有没有办法让编译器更喜欢LIBRARY_PATH
库中的库而不是系统路径。我特别喜欢叮当。在写这个问题时,我部分解决了 GCC 的问题,但也不是很清楚。
背景
LIBRARY_PATH
是一个方便的环境变量,允许透明地链接非标准目录中的库,例如用户安装,以及在我的情况下提供不同版本库的环境模块。 这个想法是做一个module load libfoo/version
,编译器将透明地使用正确的libfoo.so
。
对于共享库,还需要为ld.so
设置LD_LIBRARY_PATH
以找到合适的库。如果在LD_LIBRARY_PATH
和/usr/lib
中有多个libfoo.so
,ld.so
指定在默认路径之前搜索LD_LIBRARY_PATH
。
问题
当库定义soname
时,我遇到了问题 - 在/usr/lib
和LIBRARY_PATH
中,两个libfoo.so
版本(分别是指向libfoo.so.1
和libfoo.so.2
的符号链接)不同。然后ld
将链接到/usr/lib
中的soname
,LD_LIBRARY_PATH
无法再优先考虑预期的库。
我第一次遇到这个 boost ,但这里有一个小例子:
echo "void foo() {}" > foo.c
# create an old libfoo version in /usr/lib
sudo gcc foo.c -fpic -shared -o /usr/lib/libfoo.so.1 -Wl,-soname,libfoo.so.1
sudo ln -s libfoo.so.1 /usr/lib/libfoo.so
# create the new libfoo that we want to transparently override
mkdir -p /tmp/XXX/lib
gcc foo.c -fpic -shared -o /tmp/XXX/lib/libfoo.so.2 -Wl,-soname,libfoo.so.2
ln -s libfoo.so.2 /tmp/XXX/lib/libfoo.so
export LIBRARY_PATH=/tmp/XXX/lib
export LD_LIBRARY_PATH=/tmp/XXX/lib
echo "void foo(); int main() { foo(); }" > main.c
gcc main.c -lfoo
ldd a.out| grep foo
# under some conditions this shows libfoo.so.1 instead of .2
libfoo.so.1 => /usr/lib/libfoo.so.1
海湾合作委员会
我最初在自定义安装GCC时遇到了此问题,而GCC正在按系统安装的预期工作。gcc --print-search-dirs
揭示了一个模式:
/tmp/XXX/lib/x86_64-pc-linux-gnu/7.2.0/
/tmp/XXX/lib/x86_64-linux-gnu/
/tmp/XXX/lib/../lib64/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/x86_64-linux-gnu/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/../lib64/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../x86_64-pc-linux-gnu/7.2.0/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../x86_64-linux-gnu/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../lib64/
/lib/x86_64-pc-linux-gnu/7.2.0/
/lib/x86_64-linux-gnu/
/lib/../lib64/
/usr/lib/x86_64-pc-linux-gnu/7.2.0/
/usr/lib/x86_64-linux-gnu/
/usr/lib/../lib64/
/tmp/XXX/lib/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../../x86_64-pc-linux-gnu/lib/
/opt/gcc/7.2.0/lib/gcc/x86_64-pc-linux-gnu/7.2.0/../../../
/lib/
/usr/lib/
除了正常的搜索优先级(LIBRARY_PATH
在系统路径之前)之外,GCC 还会优先考虑一些"前缀",包括../lib64
。这可以通过创建另一个符号链接来解决:
ln -s lib /tmp/XXX/lib64
我认为这与configure
期间的--libdir
参数有关,我省略了该参数,并且在系统安装中/usr/lib
,但即使我指定--libdir=$PREFIX/lib --libexecdir=$PREFIX/lib
,它也更喜欢../lib64
。
如何在运行时编译或控制gcc
,使其至少使用../lib
而不是后缀../lib64
?
铛
叮当更是不配合。它不包括--print-search-dirs
输出中的LIBRARY_PATH
,甚至不包括-L/tmp/XXX/lib
它调用ld
是否可以在/usr/lib
中找到libfoo.so
。
如何让 Clang 透明地确定我的库路径的优先级?
笔记
- 示例来自 Archlinux,但我也在 Ubuntu 16.04 下进行了测试,它的行为类似。
- GCC 的相关问题:为什么 g++ 看起来像 LIBRARY_PATH/../lib64 这在哪里记录?和 g++ 搜索/lib/../lib/,然后是/lib/。
- 用
-L
覆盖搜索顺序是有效的,但不是透明的。 gcc --print-search-dirs
列出的目录多于gcc -v
。后者过滤掉非退出路径。
我发现了GCC的自定义安装不同的原因。Debian 发行版修补了 GCC makefiles,这就是它获得正确优先级LIBRARY_PATH
的方式。在构建 GCC 之前,找到gcc/config/i386/t-linux64
,将所有MULTILIB_OSDIRNAMES
更改为以下行:
MULTILIB_OSDIRNAMES = m64=../lib$(call if_multiarch,:x86_64-linux-gnu)
MULTILIB_OSDIRNAMES+= m32=../lib32$(call if_multiarch,:i386-linux-gnu)
MULTILIB_OSDIRNAMES+= mx32=../libx32$(call if_multiarch,:x86_64-linux-gnux32)
同时将--libexecdir=/your/custom/path/lib --libdir=/your/custom/path/lib
添加到configure
。