【问题标题】:Linking error with cmake与 cmake 链接错误
【发布时间】:2015-07-24 01:50:42
【问题描述】:

我试图了解为什么在编译使用 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 很陌生,所以我没有想法。

【问题讨论】:

  • 您可能需要检查为链接器提供的库的顺序
  • @Steephen:顺序是问题末尾VERBOSE=1写的那个,LIB_MAP链接在LIB_WORLD之前
  • @Steephen:交换 LIB_MAP 和 LIB_WORLD 的顺序似乎已经解决了这个问题。所以世界(需要地图)在另一个之前链接。
  • @Steephen 我只是减少了调用,因为它链接了 40-50 个库 + 15 个共享库,我想专注于这个问题。
  • CMake 通常会take care of the correct order of libraries passed to the linker,但我仍然建议使用--start-group --end-group linker options for the GNU toolchain。它增加了链接时间,但是在某个地方有这么多库甚至可能是循环依赖。

标签: c++ linker cmake static-libraries


【解决方案1】:

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

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

但是,一旦您将它们链接到可执行文件或共享库,您就会遇到问题。即使您的可执行文件链接到LIB_WORLD 和LIB_MAP,它也以错误的顺序这样做。因此,当链接器尝试解决 LIB_WORLD 的缺失符号时,它还不知道 LIB_MAP 导出的符号,因此您遇到了错误消息。

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

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

现在,每当您将某些内容链接到 LIB_WORLD 时,您也将始终链接到 LIB_MAP 并且 CMake 会注意顺序是否正确。 (特别是,如果您的可执行文件不直接使用来自 LIB_MAP 的方法,您可能希望将其从其 target_link_libraries 中完全删除。)

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

【讨论】:

  • 你为我节省了很多时间。谢谢!这需要被接受为正确答案。尽管这对我来说完全违反直觉。我原以为你想先链接到 LIB_MAP,因为这些符号需要在随后的 LIB_WORLD 链接上被链接……我的大脑仍然不太想理解这一点,但现在还早,也许更多的咖啡。 .
  • 非常感谢!我花了几个小时试图自己弄清楚。
猜你喜欢
  • 1970-01-01
  • 2012-06-21
  • 2011-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多