Search code examples
c++linuxgcccmakeld

`ld` undefined reference error, but libraries are linked to by CMake and symbols exist


I have a CMake file like this:

cmake_minimum_required(VERSION 3.12)
project(cpp-service VERSION 0.1.0)

add_compile_definitions(OPENVDB_7_ABI_COMPATIBLE)
list(APPEND CMAKE_MODULE_PATH "/usr/local/lib64/cmake/OpenVDB/")
find_package(OpenVDB REQUIRED)

### https://stackoverflow.com/a/69290761/3405291
list(APPEND CMAKE_MODULE_PATH "deps/tbb/cmake/")
find_package(TBB REQUIRED)

add_executable(${PROJECT_NAME}
    src/main.cpp
)

target_link_libraries(${PROJECT_NAME} PUBLIC
    OpenVDB::openvdb
    TBB::tbb
)

All the libraries are linked-to by CMake. The symbols are all available. But, linker cannot link find symbols at all. With many errors like this:

...
[ 92%] Building CXX object ...
[ 96%] Building CXX object ...
[100%] Linking CXX executable cpp-service
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/cpp-service.dir/src/main.cpp.o: in function `hollowing::mesh_to_grid(hollowing::Contour const&, openvdb::v7_2::math::Transform const&, float, float, int)':
/home/m3/repos/cpp-service/src/hollowing.h:268: undefined reference to `openvdb::v7_2::initialize()'
/usr/lib64/gcc/x86_64-suse-linux/7/../../../../x86_64-suse-linux/bin/ld: CMakeFiles/cpp-service.dir/src/main.cpp.o: in function `tbb::task_group_context::task_group_context(tbb::task_group_context::kind_type, unsigned long)':
/home/m3/repos/cpp-service/deps/tbb/include/tbb/task.h:499: undefined reference to `tbb::task_group_context::init()'
...

Guess

One guess is that I'm having this problem:

...It seems that gcc now send the linker flag --as-needed to ld. This has the effect of discarding any specified libraries that do not have symbols that are required for linking.

Tried

I tried this, but it had no effect. The same link errors are thrown:

target_link_options(${PROJECT_NAME} PUBLIC
    "LINKER:-no-as-needed"
)

Question

I ran out of options debugging this problem. Does anybody have any suggestion to try out?


CMake commands

export CC=/usr/bin/gcc-11
export CXX=/usr/bin/g++-11
mkdir build
cd build
cmake ..
cmake --build . --verbose >> log.txt 2>&1     # Save log to file.

Compile commands

CMake shows the compile logs are like:

[  3%] Building CXX object CMakeFiles/cpp-service.dir/src/main.cpp.o
/usr/bin/g++-11 -I/home/m3/repos/cpp-service/deps/tbb/include -I/.../more/include/paths/.../... -g -std=c++17 -MD -MT CMakeFiles/cpp-service.dir/src/main.cpp.o -MF CMakeFiles/cpp-service.dir/src/main.cpp.o.d -o CMakeFiles/cpp-service.dir/src/main.cpp.o -c /home/m3/repos/cpp-service/src/main.cpp

Link command

CMake log shows the link command is:

[100%] Linking CXX executable cpp-service
/usr/local/bin/cmake -E cmake_link_script CMakeFiles/cpp-service.dir/link.txt --verbose=1
/usr/bin/g++-11 -g CMakeFiles/cpp-service.dir/src/main.cpp.o CMakeFiles/cpp-service.dir/src/***.cpp.o CMakeFiles/cpp-service.dir/src/***more***object***files***.cpp.o -o cpp-service 

The errors are thrown exactly right after the above link command. Errors like:

undefined reference to `openvdb::v7_2::initialize()'

Symbols

Symbols are defined inside the linked libraries:

nm /usr/local/lib64/libopenvdb.so | less

The above command shows the initialize symbol is available:

Symbol


Solution

  • Fix 🔧

    The cause of the linker errors was this statement:

    if(LINUX)
    

    The fix was to replace it with this:

    if(UNIX AND NOT APPLE)
    

    This commit fixes the problem:

    Commit

    Reference: https://stackoverflow.com/a/40152725/3405291

    Strangely, CMake wasn't complaining about anything and just throwing random linker errors.