Linking error with cmake

10,271

This is a problem of a library dependency that was not modeled correctly in CMake.

Your LIB_WORLD references methods from LIB_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 and LIB_MAP, it does so in the wrong order. So when the linker is trying to resolve the missing symbols for LIB_WORLD, it does not know yet about the symbols exported by LIB_MAP, hence the error message you experienced.

The proper fix is to introduce the dependency on LIB_WORLD:

add_library(LIB_WORLD [...])
target_link_libraries(LIB_WORLD LIB_MAP)

Now whenever you link something against LIB_WORLD you will always also link against LIB_MAP and CMake will take care that the order is right. (In particular, if your executable does not make direct use of methods from LIB_MAP you might want to remove it from its target_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.

Share:
10,271
Jack
Author by

Jack

Busy developing games. jack(at)pixbits.com

Updated on June 04, 2022

Comments

  • Jack
    Jack about 1 year

    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.