2015-04-02 122 views
1

我有一个libA.so,这取决于libB.so,它位于../libB/(来自libA.c)。我试图以这样的方式编译东西,我不必设置任何环境变量。我有:如何设置.so库将搜索其他.so库的路径?

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
    cc -std=c99 -shared libA.o -L../libB -lB -o libA.so 

这个编译得很好。当我运行加载力霸使用dlopen我得到一个程序:

dyld: Library not loaded: libB.so 
    Referenced from: libA/libA.so 
    Reason: image not found 
Trace/BPT trap: 5 

所以力霸不会在运行时发现libB。我发现这个解决方案来改变Mac OS X上运行时路径:

install_name_tool -change libB.so @loader_path /../ libB.so libA.so

,但我想找到一个解决方案,可以在OS X和Linux上运行。再一次,我试图让最终用户尽可能少做,所以我不希望他们必须设置环境变量,我必须使用cc(对我来说,这是我的Apple LLVM版本4.2(铿-425.0 .27)(基于LLVM 3.2svn),我也希望它能在Linux上工作,所以推测cc = gcc那里)。

编辑我的问题可能比我意识到的要复杂。我在C中创建这个动态库,但试图从python中使用它。我可以在python中使用libB.so(它没有依赖关系)没有问题,当我从python中加载libA.so时,它发现它(见上面的错误),只是在那个时候,libA.so意识到它没有问题,不知道在哪里可以找到libB.so.如果我在下面正确理解你的答案,解决方案取决于在编译可执行文件时设置链接器路径,在我的情况下这是在Python中。

当我编译它时,没有办法告诉libA.so在哪里查找libB.so吗?我之后可以在OSX上使用install_name_tool来完成它,但是编译器没有办法在OSX和Linux上工作吗?

回答

5

底线是您的最终可执行文件必须知道您的库驻留在哪里。您可以通过以下两种方式完成:(1)导出LD_LIBRARY_PATH,其中包含您的库的路径,或者(2)使用rpath,因此您的可执行文件知道在哪里可以找到您的库。导出LD_LIBRARY_PATH通常看起来是这样的:

LD_LIBRARY_PATH=/path/to/your/lib:${LD_LIBRARY_PATH} 
export LD_LIBRARY_PATH 

我更喜欢使用rpath。要使用rpath(下面的例子为我的扩展测试的函数库libetf.so)编译你的库正常

gcc -fPIC -Wall -W -Werror -Wno-unused -c -o lib_etf.o lib_etf.c 
gcc -o libetf.so.1.0 lib_etf.o -shared -Wl,-soname,libetf.so.1 

然后编译可执行利用这个库,你编译为对象,然后给出rpath链接对象一个链接器选项。您将为您的案例提供libA.solibB.so的路径。建立我的testso可执行:

gcc -O2 -Wall -W -Wno-unused -c -o testetf.o testetf.c 
gcc -o testso testetf.o -L/home/david/dev/src-c/lib/etf -Wl,-rpath=/home/david/dev/src-c/lib/etf -letf 

使用ldd,以确认该可执行文件已经正确定位您的图书馆:

$ ldd testso 
     linux-vdso.so.1 (0x00007fffd79fe000) 
     libetf.so.1 => /home/david/dev/src-c/lib/etf/libetf.so.1 (0x00007f4d1ef23000) 
     libc.so.6 => /lib64/libc.so.6 (0x00007f4d1eb75000) 
     /lib64/ld-linux-x86-64.so.2 (0x00007f4d1f126000) 

注:libetf.so.1/home/david/dev/src-c/lib/etf/libetf.so.1

1

使用-rpath链接器选项。

-rpath dir

Add a directory to the runtime library search path. This is used when linking an ELF executable with shared objects. All -rpath arguments are concatenated and passed to the runtime linker, which uses them to locate shared objects at runtime. The -rpath option is also used when locating shared objects which are needed by shared objects explicitly included in the link; see the description of the -rpath-link option. If -rpath is not used when linking an ELF executable, the contents of the environment variable LD_RUN_PATH will be used if it is defined. The -rpath option may also be used on SunOS. By default, on SunOS, the linker will form a runtime search patch out of all the -L options it is given. If a -rpath option is used, the runtime search path will be formed exclusively using the -rpath options, ignoring the -L options. This can be useful when using gcc, which adds many -L options which may be on NFS mounted filesystems. For compatibility with other ELF linkers, if the -R option is followed by a directory name, rather than a file name, it is treated as the -rpath option.

+0

感谢您的帮助。当我man cc时,我没有看到rpath的任何选项。不幸的是我不得不使用cc。有任何想法吗? – Dan 2015-04-03 19:40:04

+0

当你说“cc”时,你需要更具体。 “cc”取决于系统。在Linux上它通常只是一个“gcc”的链接。无论如何,“rpath”是一个链接器选项,不是编译器选项。因此请阅读:man ld – kaylum 2015-04-03 20:05:46

+0

如果不清楚。使用gcc(也可能是cc)选项可以通过-Wl选项传递给链接器。 – kaylum 2015-04-03 20:29:43

3

尽管你自己没有构建可执行文件,但是除了将libpath.so中的rpath设置为可执行二进制文件外,其他方法几乎相同。设置rpath时,请使用特殊的$ ORIGIN字符串,以便libB.so的位置始终与libA.so相关。

ld: Using -rpath,$ORIGIN inside a shared library (recursive)

例如:

cc -std=c99 -c -fPIC -I../libB/ -Wall libA.c 
cc -std=c99 -shared libA.o -L../libB -lB -o libA.so -Wl,-rpath,\$ORIGIN/../libB 

注意$ ORIGIN不是一个环境变量,它是由运行时加载器传递给链接时如上图所示所以逃过直接解释。

顺便说一句,如果你喜欢跟随类似的方法来你正在做的OS X的,你可以更改.so文件将rpath它已经使用chrpath命令编译后 - 见:

Can I change 'rpath' in an already compiled binary?

[编辑添加]

好吧,这很有趣!在阅读关于-rpathinstall_name的各种帖子和玩各种选项之间,我想我已经找到了适合的组合。主要伎俩似乎与力霸一个@loader_path一起被设置在libB.so的install_name的:

cc -shared -o libA.so libA.o -L../libB -lB -Wl,-rpath,@loader_path 
cc -shared -o libB.so libB.o -install_name @loader_path/../libB/libB.so 

现在libB.so总是位于相对于地方libA.so是../libB/。

+0

非常感谢您的帮助。我尝试了你的建议,但不幸的是它不起作用 - 从第一个链接开始,似乎让它工作的方式是添加-rpath-link选项,但是我的OS X编译器不支持它。第二个链接中的chrpath也很棒,但是当我检查我的Linux工作站(红帽)时,它没有安装。我希望找到一个解决方案,使最终用户不必安装任何依赖项。任何其他想法? – Dan 2015-04-07 00:48:01

+0

看起来OS X上不支持$ ORIGIN特殊字符串...因此,在OS X上构建时应该坚持自己的计划。在Linux上构建时使用上述技巧,或使用以下命令安装“chrpath”:'sudo yum install chrpath'。基本上,如果你在每个平台上以相应的方式构建它,那么最终用户不需要做任何事情,只需下载并运行即可。 – bgstech 2015-04-07 01:03:33

+0

谢谢,您的上述解决方案在OS X上适用于我,但当然不适用于Linux。我认为在两种操作系统上都必须有一种简单的方法来做到这一点,但也许答案是没有? – Dan 2015-04-07 11:21:42