未在 libtool 包装器脚本中添加到 LD_LIBRARY_PATH 的已构建库目录

Posted

技术标签:

【中文标题】未在 libtool 包装器脚本中添加到 LD_LIBRARY_PATH 的已构建库目录【英文标题】:built library dirs not added to LD_LIBRARY_PATH in libtool wrapper script 【发布时间】:2015-12-21 13:37:03 【问题描述】:

构建后我无法轻松测试我的程序:

$ ./src/rap/rap -h
/home/il/workspace/rap/src/rap/.libs/lt-rap: error while loading shared libraries: libpmclient.so: cannot open shared object file: No such file or directory

libpmclient.so./src/nsreclient/x86_64-unknown-linux-gnu/ 中,并且在链接期间使用了正确的-L 标志

Automake 使用 libtool 构建我的二进制文件。它创建一个包装脚本src/rap/rap

我的预期是:在生成脚本时,libtool 会忽略 LD_LIBRARY_PATH 的当前值。运行脚本时,它会将构建树中所需的目录追加LD_LIBRARY_PATH 的现有值。例如,执行:

LD_LIBRARY_PATH=/foo ./src/rap/rap

结果:

LD_LIBRARY_PATH=/foo:/home/il/workspace/rap/src/nsreclient/x86_64-unknown-linux-gnu ./src/rap/.libs/lt-rap

但 libtool 的作用恰恰相反:它将LD_LIBRARY_PATH 的当前值硬编码到生成的脚本中:

LD_LIBRARY_PATH=/opt/oracle/product/11.2.0/client_64/lib:/lib:/usr/lib:/usr/local/lib; export LD_LIBRARY_PATH;

这毫无意义。为什么不添加构建树目录?

这里是 make 命令的格式化输出:

/bin/sh ../../libtool  --tag=CC   --mode=link gcc  -Werror-implicit-function-declaration -O2 \
    -pthread   -o rap rap.o \
    librap.a \
    ../liclib/liblic.a \
    ../fget-1.3.3/lib/libfget.a \
    ../lib_mt/libppb.la \
    ../sgplib/libsgp.la \
    ../../variations/asn1lib/ebuf_lib_mt/libasn1cebuf.la \
    -L../../src/nsreclient/x86_64-unknown-linux-gnu -lpmclient \
    -L/opt/oracle/product/11.2.0/client_64/lib -lclntsh \
    -L/usr/lib -lexpat \
    -lssl \
    -lcrypto  \
    -lm


libtool: link: gcc -Werror-implicit-function-declaration -O2 -pthread -o .libs/rap rap.o  librap.a ../liclib/liblic.a ../fget-1.3.3/lib/libfget.a \
    ../lib_mt/.libs/libppb.so \
    ../sgplib/.libs/libsgp.so \
    ../../variations/asn1lib/ebuf_lib_mt/.libs/libasn1cebuf.so \
    -L../../src/nsreclient/x86_64-unknown-linux-gnu -lpmclient \
    -L/opt/oracle/product/11.2.0/client_64/lib -lclntsh \
    -L/usr/lib /usr/lib/libexpat.so \
    -lssl -lcrypto -lm -pthread -Wl,-rpath -Wl,/usr/local/lib

【问题讨论】:

您说库位于/src/nsreclient/x86_64-unknown-linux-gnu/,但是该脚本并未将该目录添加到$LD_LIBRARY_PATH。不是这个问题吗? @***foe 是的。 (./src/...) 所以你需要编辑设置$LD_LIBRARY_PATH的脚本?还是你追求别的? 我想知道为什么 libtool 还没有这样做 你是如何链接的?你能显示Makefile.am 的部分吗? 【参考方案1】:

包装脚本根本没有设置LD_LIBRARY_PATH。它假定包含所需库的子目录已添加到实际二进制文件的RPATH

-lfoo 标志传递给libtool 时,它首先尝试打开对应的文件libfoo.la。如果该文件不存在,libtool 回退到将标志不变地传递给gcc

如果.la 文件存在并指向一个共享库,libtool 告诉链接器将包含该库的目录添加到输出二进制文件的RPATH

许多软件包将其.la 文件安装到/usr/lib/。这意味着较新的libtool 将能够解析以前版本创建的文件。为预编译的.so 文件手动编写.la 文件必须是完全安全的,而不是每次都生成它们。

我创建了文件./src/nsreclient/x86_64-unknown-linux-gnu/libpmclient.la

# libpmclient.la - a libtool library file
# Generated by ltmain.sh - GNU libtool 1.5.22 (1.1220.2.365 2005/12/18 22:14:06)
#
# Please DO NOT delete this file!
# It is necessary for linking the library.

# The name that we can dlopen(3).
dlname='libpmclient.so'

# Names of this library.
library_names='libpmclient.so'

# The name of the static archive.
old_library='libpmclient.a'

# Linker flags that cannot go in dependency_libs.
inherited_linker_flags=' -pthread'

# Libraries that this one depends upon.
dependency_libs=''

# Names of additional weak libraries provided by this library
weak_library_names=''

# Version information for libpmclient.
current=0
age=0
revision=0

# Is this an already installed library?
installed=no

# Should we warn about portability when linking against -modules?
shouldnotlink=no

# Files to dlopen/dlpreopen
dlopen=''
dlpreopen=''

# Directory that this library needs to be installed in:
libdir='/usr/local/lib'

重建后,我的包装脚本不再报错。

【讨论】:

【参考方案2】:

libtool 及其包装脚本的作用存在误解。 尤其是它不会解析传递给链接器的所有标志以获取库路径 (-L),并将它们添加到某个 LD_LIBRARY_PATH 变量中。

libtool 包装脚本的目的是(cf the docs)满足运行卸载的应用程序

[any] 已卸载的 libtool 库。

现在libtool libraries 是那些奇怪的.la 文件(而不是带有.so 后缀的实际动态库)。

由于您的 libpmclient.so 不是这样的野兽,因此包装脚本在这里对您没有多大帮助。

解决方案?

如果您无法安装您的第 3 方库到运行时链接器可以找到它们的位置,我建议您将所需的路径添加到您的 LD_LIBRARY_PATH 并在您随时获取该配置文件go hacking(你也可以在你的 ~/.bashrc 中这样做,但是如果你将帐户用于与在单个项目上编码不同的事情,那么以后可能会妨碍你)

【讨论】:

我还有 2 个具有 .la 文件的其他库:../lib_mt/libppb.la../sgplib/libsgp.la。它们没有添加到 LD_LIBRARY_PATH,但我的二进制文件可以找到它们。 也许最好手动为第 3 方.so 写一个.la 文件?

以上是关于未在 libtool 包装器脚本中添加到 LD_LIBRARY_PATH 的已构建库目录的主要内容,如果未能解决你的问题,请参考以下文章

热点未在产品查看器中链接

为啥使用javascript函数包装器(在coffeescript中添加)“.call(this)”

为自定义包装器视图添加示例视图到 PreviewProvider

包装器的使用

将自定义代码添加到 SWIG 包装器

Rails 6 - Pundit“策略包装器”