概要:
从OS X 10.11开始,启用系统完整性保护时,动态链接器环境变量不会传递给子进程。在一个生成两个库的项目中,一个依赖于另一个库,链接到库的测试代码(围绕可执行文件的shell包装器)无法运行,因为安装路径被硬连线到库中,库尚未安装,并且动态链接器将尝试使用库中的硬连线路径来查找它们。由于DYLD_LIBRARY_PATH
未传递给子进程(例如,由测试包装器脚本运行的可执行文件),因此无法指示链接器查找其他位置。
详情:
该项目由两个库组成,一个是共享库,另一个是dlopen
'能够加载共享库的模块。
以下是automake
摘要:
#-------------------
# 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使用构建目录路径来创建库,以便可以继续进行测试,然后在安装过程中使用安装路径重新链接它们?
答案 0 :(得分:0)
这样做最不具干扰性的方法似乎是使用install_name_tool
(正如我在问题中的评论中所提到的那样),希望只是轻微依赖于automake如何实施的东西。
我的解决方案是创建一个依赖于dlopen
能力模块的目标,并将动态库依赖关系的路径从安装目录更改为构建目录。这允许链接模块的测试成功加载动态库。安装后,依赖关系路径将恢复到安装路径。
修改后的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
注意事项:
.libs
.so
和.dylib
扩展名。我不相信有这种方法可以从libtool中获取这些信息。