在构建期间覆盖使用 automake/libtool 构建的共享库中的安装路径,以便在无法使用 DYLD_LIBRARY_PATH 时进行测试
Posted
技术标签:
【中文标题】在构建期间覆盖使用 automake/libtool 构建的共享库中的安装路径,以便在无法使用 DYLD_LIBRARY_PATH 时进行测试【英文标题】:Overriding installation path in shared libraries built with automake/libtool during build for testing when DYLD_LIBRARY_PATH cannot be used 【发布时间】:2017-07-07 20:52:01 【问题描述】:概要:
从 OS X 10.11 开始,当系统完整性保护开启时,动态链接器环境变量不会传递给子进程。在一个产生两个库的项目中,一个依赖于另一个库,链接到库的测试代码(可执行文件的外壳包装器)无法运行,因为安装路径硬连线到库中,库尚未安装,并且动态链接器将尝试使用库中的硬连线路径找到它们。因为DYLD_LIBRARY_PATH
没有传递给子进程(例如,由测试包装脚本运行的可执行文件),所以不可能指示链接器到别处查找。
详情:
该项目由两个库组成,一个是共享库,另一个是加载共享库的dlopen
'able 模块。
这是automake
sn-p:
#-------------------
# shared library
lib_LTLIBRARIES += %D%/liblua_udunits2.la
%C%_liblua_udunits2_la_CFLAGS = $(UDUNITS2_CFLAGS) $(LUA_INCLUDE)
%C%_liblua_udunits2_la_SOURCES = %D%/lua_udunits2.c
#-------------------
# dlopen'able module
luaexec_LTLIBRARIES = %D%/udunits2.la
%C%_udunits2_la_CFLAGS = $(UDUNITS2_CFLAGS) $(LUA_INCLUDE)
%C%_udunits2_la_LIBADD = $(UDUNITS2_LIBS) %D%/liblua_udunits2.la
%C%_udunits2_la_SOURCES = %D%/udunits2.c
%C%_udunits2_la_LDFLAGS = -L%D% -module
这会产生
liblua_udunits2.dylib
udunits2.so
链接器在构建udunits2.so
时,会记录在liblua_udunits2.dylib
中找到的安装名称,
% otool -D lua_udunits2/.libs/liblua_udunits2.dylib
lua_udunits2/.libs/liblua_udunits2.dylib:
/usr/local/lib/liblua_udunits2.0.dylib
转入udunits2.so
。
% otool -L lua_udunits2/.libs/udunits2.0.so
lua_udunits2/.libs/udunits2.0.so:
/usr/local/lib/libudunits2.0.dylib (compatibility version 2.0.0, current version 2.0.0)
/usr/lib/libexpat.1.dylib (compatibility version 7.0.0, current version 8.0.0)
/usr/local/lib/liblua_udunits2.0.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1238.60.2)
测试代码是一个shell脚本,它调用一个可执行文件,该可执行文件加载udunits2.so
,然后尝试加载liblua_udunits2.dylib
。这会失败,因为它使用的是 liblua_udunits2.dylib
的安装名称,并且尚未安装。
我已经通过添加解决了以前版本的 OSX 的问题
TESTS_ENVIRONMENT += DYLD_LIBRARY_PATH="$(top_builddir)/$(PACKAGE_NAME)/.libs"
用于测试代码。
但是,从 OS X 10.11 (El Capitan) 开始,如果系统完整性保护已开启,在某些情况下dynamic linker environment variables are not passed to subprocesses。在我的情况下,测试代码是一个调用可执行文件的脚本,因此 DYLD_LIBRARY_PATH 没有传递给可执行文件,我无法覆盖库加载路径。 (该脚本是我的代码外部的第三方测试框架的一部分,因此不能将其修改为显式设置 DYLD_LIBRARY_PATH)。
问题:
有没有办法让 automake/libtool 使用构建目录路径来创建库以便继续测试,然后在安装过程中使用安装路径重新链接它们?
【问题讨论】:
使用install_name_tool
更改路径...
这可行,但必须小心地将其插入到生成的 Makefile 中,并且我更愿意尽可能将 automake
输出视为一个黑盒子,以保持向前兼容。
【参考方案1】:
这样做的最少侵入性方法似乎是使用 install_name_tool
(正如 I'L'I 在问题的 cmets 中提到的那样),希望对 automake 如何实现事物的依赖很少。
我的解决方案是创建一个依赖于dlopen
'able 模块的目标,并将动态库依赖项的路径从安装目录更改为构建目录。这允许链接到模块的测试成功加载动态库。安装完成后,依赖路径恢复到安装路径。
修改后的Makefile.am
如下所示:
#-------------------
# shared library
lib_LTLIBRARIES += %D%/liblua_udunits2.la
%C%_liblua_udunits2_la_VERSION_MAJOR = 0
%C%_liblua_udunits2_la_VERSION_MINOR = 0
%C%_liblua_udunits2_la_CFLAGS = $(UDUNITS2_CFLAGS) $(LUA_INCLUDE)
%C%_liblua_udunits2_la_SOURCES = %D%/lua_udunits2.c
%C%_liblua_udunits2_la_LDFLAGS = -version-info $(%C%_liblua_udunits2_la_VERSION_MAJOR):$(%C%_liblua_udunits2_la_VERSION_MINOR)
#-------------------
# dlopen'able module
luaexec_LTLIBRARIES = %D%/udunits2.la
%C%_udunits2_la_VERSION_MAJOR = 0
%C%_udunits2_la_VERSION_MINOR = 0
%C%_udunits2_la_CFLAGS = $(UDUNITS2_CFLAGS) $(LUA_INCLUDE)
%C%_udunits2_la_LIBADD = $(UDUNITS2_LIBS) %D%/liblua_udunits2.la
%C%_udunits2_la_SOURCES = %D%/udunits2.c
%C%_udunits2_la_LDFLAGS = -L%D% -module -version-info $(%C%_udunits2_la_VERSION_MAJOR):$(%C%_udunits2_la_VERSION_MINOR)
if HOST_OS_IS_DARWIN
noinst_DATA = %D%/fix_install_name
%C%_DYLIB_NAME = liblua_udunits2.$(%C%_liblua_udunits2_la_VERSION_MAJOR).dylib
%C%_MODULE_NAME = udunits2.$(%C%_udunits2_la_VERSION_MAJOR).so
%C%_LIBSDIR = $(abs_builddir)/%D%/.libs/
%D%/fix_install_name : %D%/udunits2.la
install_name_tool \
-change \
$(libdir)/$(%C%_DYLIB_NAME) \
$(%C%_LIBSDIR)/$(%C%_DYLIB_NAME) \
$(%C%_LIBSDIR)/$(%C%_MODULE_NAME)
touch $@
install-data-hook :
install_name_tool \
-change \
$(%C%_LIBSDIR)/$(%C%_DYLIB_NAME) \
$(libdir)/$(%C%_DYLIB_NAME) \
$(DESTDIR)$(luaexecdir)/$(%C%_MODULE_NAME)
endif
注意事项:
现在明确指定库版本,以便确定动态库和 dlopen'able 模块的名称 代码使用库在.libs
中暂存的事实
代码明确使用.so
和.dylib
扩展。我不相信有办法从 libtool 中获取这些信息。
【讨论】:
以上是关于在构建期间覆盖使用 automake/libtool 构建的共享库中的安装路径,以便在无法使用 DYLD_LIBRARY_PATH 时进行测试的主要内容,如果未能解决你的问题,请参考以下文章