CMake:从ExternalProject链接共享的C++对象会产生相对路径而非绝对路径的二进制文件

13
问题:我正在使用CMake构建一个外部项目。该项目有一个Makefile,最终会生成一个共享对象。我想链接并安装这个对象到我的超级项目中,就像它是项目中的一个库一样。问题在于,ExternalProject lib被链接到我的应用程序和库中时使用的是相对路径而不是绝对路径,这会在除了CMake所放置的目录之外的任何目录中运行时出现问题。
我创建了一个简单的SSCCE示例项目来演示我的整体设置。如有需要,请随意查看和编译(git clone https://github.com/calebwherry/cmake-SO-question-main --recursive && cd cmake-SO-question-main && mkdir build && cd build && cmake .. && make && cd src/app/testApp && ldd testApp)。
每当我在可执行文件和库上运行ldd时,都会得到以下输出:
    linux-vdso.so.1 =>  (0x00007fff8b5a2000)
    libTestLib.so => /home/jwherry3/repos/cmake-superprj-main-test/build/src/lib/TestLib/libTestLib.so (0x00007f592da57000)
    ../../lib/libExtLib.so (0x00007f592d855000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f592d539000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f592d2b7000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f592d0a0000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f592cd14000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f592dc5a000)

我尝试了各种处理RPATHS的方法,但无法正确链接ExtLib。项目本地的库(libTestLib.so)链接得很好。我还尝试设置LD_LIBRARY_PATH来覆盖运行应用程序时的相对路径,但即使我这样做,它仍然找不到库。我想,因为它是相对的,所以它不遵循正常的链接顺序?结果是,除非我在它所在的目录中,否则二进制文件将无法运行。我觉得在使用ExternalProject创建依赖项方面,我正在做一些非常愚蠢的事情,这就是我的问题,但我已经头痛了3天,没有任何进展。系统设置:Debian Wheezy 64位,CMake 3.0.2,g++-4.9.2。

还没有结果,是吗?好吧,我暂时通过让外部项目构建静态库并链接它来“修复”问题。虽然不是长期解决方案,但至少可以正确运行。我已经更新了存储库,为其他人提供了这个选项,但你必须手动更改ext/CMakeLists.txt中的设置才能启用它。 - Caleb
抱歉,没有注意到答案。 - Slava
1个回答

11

经过和CMake用户邮件列表的@brad-king帮助,花了一些时间但我终于得出了答案。

主要问题是我没有正确地在我的外部项目中编译共享对象。Brad对我的问题的回答:

感谢提供完整/简单的示例。问题在于由外部项目构建的libExtLib.so文件没有由链接器设置DT_SONAME。当链接器给定一个没有soname的共享库文件路径时,则将该路径复制到使用方的DT_NEEDED字段中,因为其没有可用的soname。

有两种解决方法:

  1. 确保外部构建系统正确地设置DT_SONAME。

  2. 告诉CMake导入的库文件没有soname:

    set_property(TARGET ExtLib PROPERTY IMPORTED_NO_SONAME 1)

    CMake将通过-lExtLib进行链接,链接器将不存储文件路径到DT_NEEDED中,而只存储文件名。

这两个解决方法都应该可以解决问题。第一种更干净。

由于我可以控制外部库的Make文件,我选择了更干净的第一种解决方法,像这样编译共享对象:

$(SHARED_TARGET): $(OBJECTS) $(CXX) $(CXXFLAGS) $(OBJECTS) -o $@ $(LDFLAGS) -Wl,-soname,$@

我已经修改了原始示例,并使它更加简单:https://github.com/calebwherry/cmake-SO-question-main。我会将其保留作为以后任何人在此帖子上遇到问题的参考。

P.S.

还有一种次优的解决方法。如果我没有采取上述措施,我本可以直接将我链接的库的完整路径传递给target_link_library,而不使用导入库目标。我已经在存储库的CMake文件中注释掉了该选项。这不是一个很好的解决方案,但可以用另一种方式解决问题。


为什么CMake不总是使用“-l”链接器标志? - Johan Boulé

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接