I'm trying to understand why I get a linking error while compiling a project generated with CMake.
The CMakeFiles.txt builds a static library for each folder of the project and then link all of them together in the following way:
# root CMakeLists.txt
add_subdirectory(subfolder1)
add_subdirectory(subfolder2)
add_subdirectory(...)
add_executable(target ${SOURCES})
set(LIBRARIES
LIB_FOO
LIB_BAR
...
)
target_link_libraries(target
${LIBRARIES}
)
then in each subfolder I have a simple CMakeLists.txt like
file(GLOB FOO_SOURCE *.cpp)
add_library(LIB_FOO ${FOO_SOURCE})
Now this works and compiles everything fine but I get an undefined reference while linking, so I tried to investigate if everything was available at the end and it looks like so. The actual error is the following:
libLIB_WORLD.a(World.cpp.o): In function `World::generate(WorldGenOptions)':
World.cpp:(.text+0x803): undefined reference to `MapGenerator::MapGenerator(BlockMap*)'
World.cpp:(.text+0x837): undefined reference to `MapGenerator::generate(bool, WorldGenOptions)'
Now, MapGenerator.cpp is part of LIB_MAP
, so I checked if the file exists and contains the symbols:
:~$ nm libLIB_MAP.a | grep generate
....
00000000000044dc T _ZN12MapGenerator8generateEb15WorldGenOptions
:~$ nm CMakeFiles/LIB_MAP.dir/MapGenerator.cpp.o | grep generate
....
00000000000044dc T _ZN12MapGenerator8generateEb15WorldGenOptions
So the symbol is present, at this point I checked if it was correctly linked by ld:
:~$ make VERBOSE=1
/usr/bin/g++ ... libLIB_MAP.a libLIB_WORLD.a ...
So it is actually present in linking phase together with the other library that is not able to find the symbol.
Is there something trivial I'm missing? I'm quite new to CMake so I'm out of ideas.
This is a problem of a library dependency that was not modeled correctly in CMake.
Your
LIB_WORLD
references methods fromLIB_MAP
. This dependency is not modeled in your CMake scripts. As both of those are static libraries, they will still build fine on their own. (Remember that static libraries are essentially a bunch of object files packed together, but they never pass through the linker.)However, as soon as you link them to an executable or a shared library, you will get the problem. Even though your executable links against both
LIB_WORLD
andLIB_MAP
, it does so in the wrong order. So when the linker is trying to resolve the missing symbols forLIB_WORLD
, it does not know yet about the symbols exported byLIB_MAP
, hence the error message you experienced.The proper fix is to introduce the dependency on
LIB_WORLD
:Now whenever you link something against
LIB_WORLD
you will always also link againstLIB_MAP
and CMake will take care that the order is right. (In particular, if your executable does not make direct use of methods fromLIB_MAP
you might want to remove it from itstarget_link_libraries
altogether.)As an additional benefit, it now allows you to build
LIB_WORLD
as a shared library, which would have failed with a linker error before.