【发布时间】:2018-04-25 04:31:12
【问题描述】:
有没有办法让编译器更喜欢来自LIBRARY_PATH 的库而不是系统路径。我特别在寻找 Clang。我在写这个问题时部分解决了 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 --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后缀?
叮当
Clang 更加不合作。它在--print-search-dirs 的输出中不包括LIBRARY_PATH,如果libfoo.so 已经在/usr/lib 中找到,它甚至不包括-L/tmp/XXX/lib 来调用ld。
如何让 Clang 透明地确定我的库路径的优先级?
注意事项
- 示例来自 Archlinux,但我也在 Ubuntu 16.04 下进行了测试,其行为类似。
- GCC 的相关问题:Why does g++ look in LIBRARY_PATH/../lib64 and where is this documented? 和 g++ searches /lib/../lib/, then /lib/。
- 用
-L覆盖搜索顺序有效,但不透明。 -
gcc --print-search-dirs列出的目录比gcc -v多。后者过滤掉不存在的路径。
【问题讨论】:
-
一个特别难看但可行的解决方案是围绕
gcc、cc、g++和c++进行包装,并在那里强制使用适当的-L。 -
自定义规格文件可以解决您的问题。详情请见
https://gcc.gnu.org/onlinedocs/gcc/Spec-Files.html -
@nit 我不确定从这个文件的哪里开始。只有 4 次提到“图书馆/IES”,而且似乎都没有提到我的问题。您能否以答案的形式详细说明?
-
你找到解决办法了吗?
-
不超出问题中所写的内容。