【问题标题】:Linking fails with CMake, DSO-Link-ChangeCMake、DSO-Link-Change 链接失败
【发布时间】:2013-04-05 03:47:44
【问题描述】:

几个月前我在 linux 上编译良好的软件在我的新 ubuntu 上停止编译:

Linking CXX executable myApp
/usr/bin/ld: ../libMyLib/libMyLib.a(MyFile.cpp.o): undefined reference to symbol '_ZN2cv6resizeERKNS_11_InputArrayERKNS_12_OutputArrayENS_5Size_IiEEddi'
/usr/bin/ld: note: '_ZN2cv6resizeERKNS_11_InputArrayERKNS_12_OutputArrayENS_5Size_IiEEddi' is defined in DSO /usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libopencv_imgproc.so so try adding it to the linker command line
/usr/lib/gcc/x86_64-linux-gnu/4.7/../../../../lib/libopencv_imgproc.so: could not read symbols: Invalid operation
collect2: error: ld returned 1 exit status
make[2]: *** [myApp/myApp] Error 1
make[1]: *** [myApp/CMakeFiles/myApp.dir/all] Error 2
make: *** [all] Error 2

我猜它与https://fedoraproject.org/wiki/UnderstandingDSOLinkChange有关。

我的项目(所有 cmake)包含几个库和一个应用程序,这些库和应用程序都依赖于 opencv 和/或 boost(每个都依赖于一些不同的)。我自己的库构建为 .a 文件,ocv/boost 被拉入为共享库,然后应用程序的链接失败并出现上述错误。

我还尝试将自己的库构建为 SHARED,但这导致了更多错误。我的库的 CMakeLists 看起来像

FIND_PACKAGE(Boost REQUIRED)
FIND_PACKAGE(OpenCV REQUIRED core)
...stuff...
include_directories( ${OpenCV_INCLUDE_DIRS} )
include_directories( ${Boost_INCLUDE_DIRS} )
add_library( ${SUBPROJECT_NAME} ${SOURCE} ${HEADERS} )

应用程序 CMakeLists 的样子

FIND_PACKAGE( OpenCV REQUIRED core imgproc highgui)
include_directories( ${OpenCV_INCLUDE_DIRS} )
TARGET_LINK_LIBRARIES( ${SUBPROJECT_NAME} ${OpenCV_LIBS} MyLib )

这一切都是正确的,我一直认为这是这样做的方法,但现在有了这个 DSO 东西,我再也无法让它工作了。

如果相关,我尝试使用 CMake 2.8.7 和 2.8.10,以及 g++ 4.7.2 和 4.8,都产生相同的错误。

【问题讨论】:

  • 我不记得库的顺序在 CMake 中是否重要(即它是否以正确的顺序将它们提供给 GCC),但这对于 GCC 本身来说肯定很重要。也许你应该把MyLib放在${OpenCV_LIBS}之前?
  • 哦,伙计,你一定是在开玩笑吧...当 MyLib 依赖于 ${OpenCV_LIBS} 时,它必须在 cmdline 之前运行?这对我来说非常不直观,我的想法是,首先你必须链接到 ${OpenCV_LIBS} (然后它是“定义的”),然后链接到依赖于 ${OpenCV_LIBS} 并且现在能够找到它的 MyLib...但实际上你是对的,自从我使用 gcc 以来我就错了......如果你把它作为答案,我会接受...... :-) 谢谢,太愚蠢了......

标签: c++ gcc linker cmake ld


【解决方案1】:

GCC 对您在链接阶段指定库的顺序非常敏感。例如,如果libA.a 依赖于libB.a 并且一个可执行文件App 依赖于两者,那么您必须通过以下方式调用链接器:

gcc main.o object1.o ... object2.o -lA -lB -o App

注意:请注意,虽然A 依赖于B,但A 仍然在B 之前。作为结论,最独立的工件应该链接到最后一个。当然这在某种意义上是违反直觉的,但是尝试以与在 C++ 中应用 const 限定符相同的方式对待它。 :)

【讨论】:

  • 似乎在上面链接的链接行为更改之前,在我的情况下这并不重要(除了不正确),但现在链接器变得更加迂腐,这很重要。非常感谢:-)
  • @Ela782:但可能有更好的解决方案。像 CMake 这样的构建系统都是关于从编译器和平台中抽象出来的。因此,通常不鼓励修改CMakeLists 以适应特定的编译器。最好将target_link_libraries(MyLib ${OpenCV_LIBS}) 添加到CMakeLists 中对应MyLib。这样,您不仅可以显式定义工件的依赖关系,这对可读性非常有利,而且您还可以使用 CMake 的依赖关系跟踪系统。换句话说,让 CMake 巧妙地帮助您处理链接顺序。
  • 好的,但我一直认为你提出的做法是不好的做法,好的做法是只让应用程序做最后的链接。这不再是真的,还是曾经如此?大约一年前我告诉自己,我在几个主页上阅读了该建议(我想也在 SO 上)。
  • 链接仍然是最终的。由于您使用的是 CMake,因此我提出的实际上是一种更高级别的技术。所以这不是关于多次链接,而是关于指示 CMake 依赖关系图的外观,以便最终链接以正确的顺序完成。此外,您不能以这种方式破坏任何内容或引入冗余链接,因为相互依赖的静态库仅在它们链接到最终的可执行文件或动态库时才会链接在一起,而以前从未如此,即它们只是 *.o 文件的存档。
【解决方案2】:

OpenCV_LIBS 是否包含 -lopencv_imgproc? 如果没有,尝试手动添加 -lopencv_imgproc 链接命令行(运行 make V=1) 如果有效,请将其添加到 TARGET_LINK

【讨论】:

  • 是的,它当然包含它,这是链接失败的应用程序的完整命令:/usr/bin/c++ -std=c++11 -O3 -DNDEBUG CMakeFiles/myApp.dir/myApp.cpp.o -o myApp -L/home/user/MCR/v81/bin/glnxa64 -rdynamic -lboost_program_options-mt -lmx -lmat -lopencv_gpu -lopencv_contrib -lopencv_legacy -lopencv_objdetect -lopencv_calib3d -lopencv_features2d -lopencv_video -lopencv_highgui -lopencv_ml -lopencv_imgproc -lopencv_flann -lopencv_core ../MyLib/MyLib.a -Wl,-rpath,/home/user/MCR/v81/bin/glnxa64
  • 谢谢我遇到了同样的问题,包括修复它!
猜你喜欢
  • 2012-10-26
  • 2016-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-17
相关资源
最近更新 更多