2014-11-04 78 views
2

我正在开发一个项目,并且正在启动发布二进制文件。我们使用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),但在执行的readlink libmpich.so(或get_filename_component(...真实路径))返回libmpich.so.10.0.4。因此,如果我以名称libmpich.so.10.0.4或libmpich.so.10.0.4(或创建从一个到另一个的符号链接)安装libmpich.so.10.0.4,我仍然错过了RPATH中要求的库。

我一直在玩捶打一个摩尔在处理这些和/或使用文件glob来尝试抓取中间链接,但我想做更强大的事情。任何人都使用一个好的设计模式呢?

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

-Jameson

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

回答

1

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

要解决符号链接的单一级别,您可以直接从cmake调用'readlink',因为它可用于您可能构建的每个启用了符号链接的平台(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