使用共享对象和符号链接构建安装包

时间:2014-11-04 01:18:08

标签: linux installation cmake

我正在开发一个项目,我们正在开始发布二进制文件。我们使用CMake生成构建文件,使用CPack创建二进制文件。我们的二进制文件工作,但我们遇到共享对象的问题。实质上,许多问题来自系统上的符号链接,尤其是具有多个链接的共享对象。所以,假设一些可执行文件的ldd(或otool)的RPATH结果包括libmpich.so.10,并且我从cmake链接了/usr/lib/x86_64-linux-gnu/libmpich.so这些文件是相关的像这样:

/usr/lib/x86_64-linux-gnu/libmpich.so -> libmpich.so.10
/usr/lib/x86_64-linux-gnu/libmpich.so.10 -> libmpich.so.10.0.4
/usr/lib/x86_64-linux-gnu/libmpich.so.10.0.4

现在,由于某种原因,RPATH使用中间链接(so.10),但libmpich.so上的readlink(或get_filename_component(... REALPATH))返回libmpich.so.10.0.4。因此,如果我以libmpich.so或libmpich.so.10.0.4的名称安装libmpich.so.10.0.4(或者从一个到另一个创建符号链接),我仍然错过了在RPATH。

在处理这些和/或使用文件glob试图抓住中间链接时,我一直在玩打击鼹鼠,但我想做更强大的事情。有人为此使用了良好的设计模式吗?

我一直在研究使用像GET_PREREQUISITES这样的函数,但那些需要构建对象,所以我需要以某种方式将它们添加到安装脚本中......并且感觉它们应该是更好的方式。

-Jameson

P.S。我也在寻找建立二进制文件的最佳实践指南,无论是使用cmake还是通常。我们在windows,linux和mac上生成二进制文件。如果你知道一些好的链接,请发布它们。

1 个答案:

答案 0 :(得分:4)

我最近刚刚处理了这个问题。 cmake命令get_filename_component(... REALPATH)在一次调用中恢复符号链接的所有级别。

要解决单个级别的符号链接问题,您可以调用“#readlink'直接来自cmake,因为它可以在你可能构建的每个符合链接的平台上使用(Linux,Mac OS X和* BSD)。

所以,如果你想重现完整的符号链接链, 你在cmake脚本中编写了类似的代码:

#If given the following library path:
set(lib  "/usr/lib/x86_64-linux-gnu/libmpich.so")

#Make sure the initial path is absolute.
get_filename_component(lib "${lib}" ABSOLUTE)

#Store initial path as first element in list.
set(symlist "${lib}")

while(UNIX AND IS_SYMLINK "${lib}")
  #Grab path to directory containing the current symlink.
  get_filename_component(sym_path "${lib}" DIRECTORY)

  #Resolve one level of symlink, store resolved path back in lib.
  execute_process(COMMAND readlink "${lib}"
                  RESULT_VARIABLE errMsg
                  OUTPUT_VARIABLE lib
                  OUTPUT_STRIP_TRAILING_WHITESPACE)

  #Check to make sure readlink executed correctly.
  if(errMsg AND (NOT "${errMsg}" EQUAL "0"))
    message(FATAL_ERROR "Error calling readlink on library.")
  endif()

  #Convert resolved path to an absolute path, if it isn't one already.
  if(NOT IS_ABSOLUTE "${lib}")
    set(lib "${sym_path}/${lib}")
  endif()

  #Append resolved path to symlink resolution list.
  list(APPEND symlist "${lib}")
endwhile()

#Now symlist will contain the following:
# [...]/libmpich.so;[...]/libmpich.so.10;[...]/libmpich.so.10.0.4