C++ CMake:链接共享的C++;ExternalProject中的对象生成具有相对路径而非绝对路径的二进制文件

C++ CMake:链接共享的C++;ExternalProject中的对象生成具有相对路径而非绝对路径的二进制文件,c++,build,cmake,C++,Build,Cmake,问题:我正在CMake中构建一个外部项目。该项目有一个生成文件,最终生成一个共享对象。我想在超级项目中链接并安装此对象,就像它是项目中的一个库一样。问题是ExternalProject库是通过相对路径而不是绝对路径链接到我的应用程序和库中的,当从CMake放置它的目录以外的任何目录运行时,绝对路径都会导致问题 我必须演示我的整体设置。如果需要,请随意阅读和编译(git-clonehttps://github.com/calebwherry/cmake-SO-question-main --递归和

问题:我正在CMake中构建一个外部项目。该项目有一个生成文件,最终生成一个共享对象。我想在超级项目中链接并安装此对象,就像它是项目中的一个库一样。问题是ExternalProject库是通过相对路径而不是绝对路径链接到我的应用程序和库中的,当从CMake放置它的目录以外的任何目录运行时,绝对路径都会导致问题

我必须演示我的整体设置。如果需要,请随意阅读和编译(
git-clonehttps://github.com/calebwherry/cmake-SO-question-main --递归和cd cmake SO问题main和mkdir构建和cd构建和cmake..&&make和cd src/app/testApp和ldd testApp

每当我在可执行文件和libs上运行
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)
我已经尝试过处理rpath的各种方法,但无法使ExtLib正确链接。项目的本地库(
libTestLib.so
)链接很好

我还尝试在运行应用程序时设置
LD_LIBRARY_PATH
以覆盖相对路径,但即使这样做,它仍然找不到库。我想,因为它是相对的,所以它不遵循正常的链接顺序?结果是,除非我在二进制文件所在的目录中,否则二进制文件将不会运行

我觉得我在用ExternalProject创建依赖项时做了一些非常愚蠢的事情,这是我的问题,但我已经绞尽脑汁3天了,还没有想出任何办法


系统设置:Debian Wheezy 64位,CMake 3.0.2,g++-4.9.2。

花了一段时间,但在CMake用户列表服务的帮助下,我终于找到了答案,特别是@brad king

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

感谢您提供完整/简单的示例。问题是 外部项目生成的libExtLib.so文件不存在 由链接器设置DT_SONAME。当给链接器一个 没有soname的共享库文件的路径 复制到消费者的DT_NEEDED字段中,因为 没有我可以用的

有两种解决方案:

  • 确保外部构建系统正确设置DT_SONAME

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

    set_属性(导入的目标ExtLib属性_NO_SONAME 1)

    然后,CMake将通过-lExtLib链接它,而链接器不会 将文件路径存储在所需的DT_中,但仅存储文件名

  • 这两种方法都可以解决问题。1号更干净

    因为我可以控制外部库中的Make文件,所以我选择了cleaner first解决方案,通过如下方式编译共享对象:

    $(共享目标):$(对象)
    $(CXX)$(cxflags)$(对象)-o$@$(LDFLAGS)-Wl,-soname,$@

    我已经修改了我原来的示例,使其更加简单:。我将把它留作以后偶然看到这篇文章的人的参考

    p.S.


    还有另一个修复是次优的。如果我没有执行上述任何操作,我可以只给target_link_library提供指向我链接的库的完整路径,而不使用导入的库目标。我在回购协议的CMake文件中注意到了这一点,并将其注释掉。这不是一个很好的解决方案,但确实可以用另一种方式解决问题。

    仍然没有成功,是吗?我已经暂时“修复”了这个问题,让外部项目也构建一个静态库,并将其链接到其中,而不是共享库。这不是一个长期的解决方案,但至少能让它正确运行。我已经更新了回购协议,使其他人可以使用此选项,但您必须在ext/CMakeLists.txt中手动更改此选项才能将其打开。抱歉,没有注意到答案