将错误与cmake链接

时间:2015-07-24 01:50:42

标签: c++ linker cmake static-libraries

我正在尝试理解为什么在编译使用CMake生成的项目时出现链接错误。

CMakeFiles.txt为项目的每个文件夹构建一个静态库,然后按以下方式将所有文件夹链接在一起:

# 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}
)

然后在每个子文件夹中,我有一个简单的CMakeLists.txt,如

file(GLOB FOO_SOURCE *.cpp)
add_library(LIB_FOO ${FOO_SOURCE})

现在这个工作并编译好一切但我在链接时得到了一个未定义的引用,所以我试着调查一下最后是否所有内容都可用,看起来就是这样。实际错误如下:

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)'

现在,MapGenerator.cpp是LIB_MAP的一部分,所以我检查了文件是否存在并包含符号:

:~$ nm libLIB_MAP.a | grep generate
....
00000000000044dc T _ZN12MapGenerator8generateEb15WorldGenOptions

:~$ nm CMakeFiles/LIB_MAP.dir/MapGenerator.cpp.o | grep generate
....
00000000000044dc T _ZN12MapGenerator8generateEb15WorldGenOptions

所以符号存在,此时我检查了它是否被ld:

正确链接
:~$ make VERBOSE=1
/usr/bin/g++  ... libLIB_MAP.a libLIB_WORLD.a ...

因此它实际上存在于链接阶段和其他无法找到符号的库中。

我有什么微不足道的错过吗?我对CMake很陌生,所以我没有想法。

1 个答案:

答案 0 :(得分:5)

这是一个未在CMake中正确建模的库依赖项问题。

来自LIB_WORLD的{​​{1}}引用方法。此依赖关系未在CMake脚本中建模。由于这两个都是静态库,它们仍然可以自行构建。 (请记住,静态库本质上是一堆打包在一起的目标文件,但它们从不通过链接器。)

但是,只要将它们链接到可执行文件或共享库,就会出现问题。即使您的可执行文件链接到LIB_MAPLIB_WORLD,它也会以错误的顺序执行 。因此,当链接器尝试解析LIB_MAP的缺失符号时,它还不知道LIB_WORLD导出的符号,因此会出现错误消息。

正确的解决方法是引入对LIB_MAP的依赖:

LIB_WORLD

现在,每当您将某些内容与add_library(LIB_WORLD [...]) target_link_libraries(LIB_WORLD LIB_MAP) 相关联时,您始终会链接到LIB_WORLD CMake会关注订单是否正确。 (特别是,如果您的可执行文件未直接使用LIB_MAP中的方法,您可能希望将其从LIB_MAP中完全删除。)

作为一个额外的好处,它现在允许您将target_link_libraries构建为共享库,这在之前会因链接器错误而失败。