clang,在链接时更改依赖的共享库安装名称

时间:2014-12-16 14:04:21

标签: macos dynamic-library install-name-tool

相关,但不回答这个问题:

在OSX上,我有一个由打包管理器提供的动态库,安装在非 标准目录,其中install_name只是文件名。例如:

$ ROOT=$PWD
$ mkdir $ROOT/foo 
$ cd $ROOT/foo
$ echo 'int foo(int a, int b){return a+b;}' > foo.c
$ clang foo.c -dynamiclib -install_name libfoo.dylib -o libfoo.dylib

不希望更改(绝对路径,@ RPATH,...)install_name libfoo.dylib使用install_name_tool -id

现在我将程序与库链接,例如:

$ mkdir $ROOT/bar
$ cd $ROOT/bar
$ echo 'int foo(int,int); int main(){return foo(2,4);}' > main.c
$ clang main.c -L../foo -lfoo   

该程序无法运行:

$ ./a.out
dyld: Library not loaded: libfoo.dylib
  Referenced from: $ROOT/bar/./a.out
  Reason: image not found
Trace/BPT trap: 5

,因为:

$ otool -L ./a.out
./a.out:
        libfoo.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

我可以更改依赖库的路径:

$ install_name_tool -change libfoo.dylib ../foo/libfoo.dylib a.out

这样:

$ otool -L ./a.out
./a.out:
        ../foo/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)

并且程序可以执行:

$ ./a.out
$ echo $?
6

我可以在命令中添加一个clang选项:

$ clang main.c -L../foo -lfoo 

以避免必须运行:

$ install_name_tool -change libfoo.dylib ../foo/libfoo.dylib a.out

注意:我不想修改DYLD_LIBRARY_PATH或其他环境变量。

1 个答案:

答案 0 :(得分:13)

一段时间以来我一直在反对这个问题,并且认为我终于想出了如何在不使用install_name_tool的情况下做到这一点,至少对于Mac OS 10.9及更高版本(据我测试过) )。

虽然您可能已经想到这一点,但我会在这里发布,以防其他人需要它。

基本上你有两个选择:

  1. 您可以在编译库时执行此操作,并根据install_name
  2. 定义其@executable_path
    ROOT=$PWD
    mkdir $ROOT/foo
    mkdir $ROOT/bar
    
    cd $ROOT/foo
    echo 'int foo(int a, int b){return a+b;}' > foo.c
    clang foo.c -dynamiclib -install_name @executable_path/../foo/libfoo.dylib -o libfoo.dylib
    
    cd $ROOT/bar
    echo 'int foo(int,int); int main(){return foo(2,4);}' > main.c
    clang main.c -L../foo -lfoo -o main
    
    ./main
    echo $?
    # output is '6'
    
    1. 或者您可以使用@rpath分两步完成,然后在编译可执行文件时设置它:
    2. ROOT=$PWD
      mkdir $ROOT/foo
      mkdir $ROOT/bar
      
      cd $ROOT/foo
      echo 'int foo(int a, int b){return a+b;}' > foo.c
      clang foo.c -dynamiclib -install_name @rpath/libfoo.dylib -o libfoo.dylib
      
      cd $ROOT/bar
      echo 'int foo(int,int); int main(){return foo(2,4);}' > main.c
      clang main.c -L../foo -lfoo -rpath @executable_path/../foo/ -o main
      
      ./main
      echo $?
      # output is '6'
      

      两种情况下的最终结果都是相同的:

      bar $ otool -L main
      main:
        @executable_path/../foo/libfoo.dylib (compatibility version 0.0.0, current version 0.0.0)
        /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
      

      第二个可能是可取的,因为那时你可以编译一次库,并且使用它的任何可执行文件定义它将使用它自己的rpath加载它的位置。

      check here详细解释@executable_path@rpath@load_path(我在此处未使用)。