Undefined reference problems - C++

Hey there,
I’m facing some issues with undefined references in my code and I’ve come to the conclusion, that CMake must be some kind of error source - There are no compiling problems, it just fails to … do stuff whenever I am using my thread interface
Please don’t be too harsh with your comments - I am new to CMake and C++ (Is this even the right place to ask… - Stackoverflow is such a tracking hazard)

Utils.cpp: 0bin - encrypted pastebin
Utils.hpp: 0bin - encrypted pastebin
CMakeLists.txt (reached link cap):

add_executable(WS WordSearch.cpp)
add_library(U Utils/utils.cpp Utils/utils.hpp)
target_link_libraries(WS U)

Terminal output:

/sbin/ld: libU.a(utils.cpp.o): warning: relocation against `_ZN11threadUtils13ThreadManager6pausedE' in read-only section `.text._ZZN11threadUtils13ThreadManager3runEvENKUlvE_clEv[_ZZN11threadUtils13ThreadManager3runEvENKUlvE_clEv]'
/sbin/ld: libU.a(utils.cpp.o): in function `threadUtils::ThreadManager::run()::{lambda()#1}::operator()() const':
/home/maus/Cxx/WordSearch/src/Utils/utils.cpp:106: undefined reference to `threadUtils::ThreadManager::paused'
/sbin/ld: /home/maus/Cxx/WordSearch/src/Utils/utils.cpp:106: undefined reference to `threadUtils::ThreadManager::paused'
/sbin/ld: libU.a(utils.cpp.o): in function `std::thread::thread<threadUtils::ThreadManager::run()::{lambda()#1}, , void>(threadUtils::ThreadManager::run()::{lambda()#1}&&)':
/usr/include/c++/11.1.0/bits/std_thread.h:136: undefined reference to `pthread_create'
/sbin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/WS.dir/build.make:98: src/WS] Error 1
make[1]: *** [CMakeFiles/Makefile2:126: src/CMakeFiles/WS.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

What’s wrong here - Is CMake even causing this?
Thanks!

The problem seems to be you’re building a STATIC library (check https://cmake.org/cmake/help/latest/command/add_library.html to know why it’s static). This library type is by default compiled without position independent code (PIC) and, if not explicitly written in CMake, does not carry transitive linking information.
Additionally, if I remember correctly, to use C++ thread thingies on linux, you must link to a threading library by yourself (see docu for find_package() and FindThreads module).

Thanks for the answer!

Threading seems to be pretty easy on linux, as stated here.

I just marked my library as SHARED and it’s now looking better:

[ 75%] Linking CXX executable WS
/sbin/ld: libU.so: undefined reference to `pthread_create'
/sbin/ld: libU.so: undefined reference to `threadUtils::ThreadManager::paused'
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/WS.dir/build.make:98: src/WS] Error 1
make[1]: *** [CMakeFiles/Makefile2:126: src/CMakeFiles/WS.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

I am confused why it’s having problems - It doesn’t even print out any lines.
EDIT: Line 106-108 are causing the “paused” problem (if (std::count(paused.begin(), paused.end(), id)),
Commenting out the whole run() method fixes all compilation errors - Huh.

EDIT 2: Should’ve read the whole comment

Oh nice! I got it to an almost working state:

add_executable(WS WordSearch.cpp)
find_package (Threads)
add_library(U SHARED Utils/utils.cpp Utils/utils.hpp)
target_link_libraries(U pthread)
target_link_libraries(WS U)

Compiles perfectly when I comment out that paused searcher part - Why is that one still doing weird stuff…

I’ve just checked - for the threading on linux you really need to link pthreads - that will take care of the missing pthread_create.

I believe the second error comes from ODR violation you have in your code - you define threadUtils::ThreadManager class twice - once in the hpp and once in the cpp file and those two are not identical which they must be according to C++ standard or you’re in undefined behaviour teritory. In fact the same goes for progress::ActionSpinner.

Something like this I guess?


This might just be completely bogus at this point.

… I am still getting the same error regardless

EDIT again: Actually using my interface:

/sbin/ld: CMakeFiles/WS.dir/WordSearch.cpp.o: in function `main':
/home/maus/Cxx/WordSearch/src/WordSearch.cpp:214: undefined reference to `threadUtils::ThreadManager::kill()'
/sbin/ld: /home/maus/Cxx/WordSearch/src/WordSearch.cpp:262: undefined reference to `progress::ActionSpinner::~ActionSpinner()'
/sbin/ld: /home/maus/Cxx/WordSearch/src/WordSearch.cpp:262: undefined reference to `progress::ActionSpinner::~ActionSpinner()'
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/WS.dir/build.make:98: src/WS] Error 1
make[1]: *** [CMakeFiles/Makefile2:126: src/CMakeFiles/WS.dir/all] Error 2
make: *** [Makefile:91: all] Error 2

CMake is hard

This is not CMake - this is really C++. And yeah - not the easiest thing on Earth :stuck_out_tongue_winking_eye:

In any case, I think your .hpp looks OK, except you need to declare action() as pure virtual already there, but I’m not sure if the way you’ve written your .cpp is legal - I’ve never seen a class redeclared like that in the .cpp. Maybe try more standard approach, like:

namespace threadUtils {
 
  std::vector<std::time_t> ThreadManager::threads;
  std::vector<std::time_t> ThreadManager::paused;
 
  void ThreadManager::kill() { threads.erase(std::find(threads.begin(), threads.end(), id)); }
 
  void ThreadManager::pause(bool cont) {
    std::vector<std::time_t>::iterator it =
        std::find(paused.begin(), paused.end(), id);
    if (it != paused.end() && !cont) {
      paused.erase(it);
    } else if (cont) {
      paused.push_back(id);
    }
  }
 
  void ThreadManager::run() {
    thread = std::thread([this]() {
      while (true) {
        if (std::count(paused.begin(), paused.end(), id)) {
          continue;
        }
        action();
      }
    });
    thread.join();
  }
 
}; // namespace threadUtils

And the same for you ActionSpinner.
You generally seem to have a lot of learning to do regarding C++. Maybe you should start with something simpler than threading and libraries just to get a grasp of the language? Just a suggestion - don’t yell at me :stuck_out_tongue_winking_eye:

In the end, you are 100% right about this. I’ve yet got too learn a ton about C++.
This threading problem was more of an experiment as I’d like to have easy control about my threads. I really hate, that there’s no way to kill them externally without voodoo magic.
I might have to resort back to just using lambda threads the good old way.
Thanks for your efforts of trying to help me out - At least I now know, how to use SHARED libraries in CMake.
Have a great day!
:smiley: