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

18

相关但不回答问题:

在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

不想使用install_name_tool -id来更改libfoo.dylib的安装名称(绝对路径、@RPATH等)。

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

$ 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个回答

22
我已经花了一些时间努力,认为我终于想出了如何在不使用 install_name_tool 的情况下实现这一点,至少对于 Mac OS 10.9 及更高版本(据我测试)。

虽然您可能已经解决了这个问题,但我在此发布它,以防其他人需要。

基本上,您有两个选择:

  1. 在编译库时可以进行设置,将其 install_name 定义为 @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 分两步完成,然后在编译可执行文件时设置:
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)

第二种方法可能更好,因为您可以编译库一次,并让使用它的任何可执行文件使用自己的定义从哪里加载它。请在此处查看有关@executable_path@rpath@load_path的详细说明(我在此处未使用)。

1
在2021年,再次查看仍然非常有用。 - liviaerxin
你知道在编译可执行文件时是否可以更改可执行文件中动态库的名称吗? - michael_fortunato
@michael_fortunato 我相信在编译可执行文件时,-l<NAME> 标志决定了可执行文件动态链接到的库的名称。因此,如果动态库的文件名为 libXYZ.dylib,那么在编译可执行文件时,你应该将其链接为 -lXYZ - Johannes

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