是否可以使用共享对象构造函数来设置库搜索路径?
Is it possible to use a shared object constructor for setting the library search path?
我将共享对象存储在分层文件夹结构中。共享库可以相互依赖。在运行的时候,共享库X可能需要加载共享库Y。我不确定我可以使用什么机制让库X找到Y。
我不想使用 -rpath,因为它不能很好地跨平台翻译:
- How to set the runtime path (-rpath) of an executable with gcc under Mac OSX?
- Is there a Windows/MSVC equivalent to the -rpath linker flag?
我无法将共享对象放在一个目录中,因为可能存在名称冲突。 LD_LIBRARY_PATH 和 PATH 不可用,因为我要添加 很多 路径。
这让我想知道我是否可以修改共享对象的 constructor 中的 LD_LIBRARY_PATH(使用 -Wl,-init)。这将要求构造函数在 运行 时间链接发生之前为 运行。我找不到是否是这种情况。
本质上,我正在考虑执行以下操作(尚未尝试过此代码):
将此函数添加到库源代码中:
extern char *searchPath;
void construct() {
char *libPath = getenv("LD_LIBRARY_PATH");
char *new_libPath = malloc(1 + snprintf(NULL, 0, "%s:%s", libPath, searchPath);
sprintf(new_libPath, "%s:%s", libPath, searchPath);
setenv("LD_LIBRARY_PATH", new_libPath, 0);
}
并编译:
gcc foo.c --shared -o foo -Wl,-init,construct
没有,一般不能。一些链接器可能支持它,但其他链接器肯定不会。许多动态链接器将在加载主可执行文件后忽略对 LD_LIBRARY_PATH
或等效项的更改,因此您甚至可能根本无法在运行时影响加载路径。在链接所有库之前,其他链接器甚至可能不会尝试调用初始化程序或构造函数(例如,Mac OS X dyld
似乎以这种方式运行)。
此外,某些链接器甚至不会加载具有相同 soname
的两个库,因为它们将被视为同一个库。因此,考虑到您的库中可能存在名称冲突,这甚至会首先阻止自动加载它们。
对于库的运行时加载,POSIX 提供了dlopen
和dlsym
。 dlopen
允许您通过文件路径加载任意库,dlsym
允许您获取指向该库中定义的符号的指针考虑使用这些而不是一些动态路径更改 hack - dlopen
和 dlsym
是便携的并且相当容易使用。是的,你没有得到 "automatic" 符号解析(因为你必须自己 dlsym
一切),但是有一些方法可以设计你的库来使这更容易(或使用宏来使解析更容易) .
在 Windows 上,您可以类似地使用 LoadLibrary
和 GetProcAddress
。如果你想要一个很好的跨平台库来消除平台差异,请考虑像 libltdl.
这样的东西
我将共享对象存储在分层文件夹结构中。共享库可以相互依赖。在运行的时候,共享库X可能需要加载共享库Y。我不确定我可以使用什么机制让库X找到Y。
我不想使用 -rpath,因为它不能很好地跨平台翻译:
- How to set the runtime path (-rpath) of an executable with gcc under Mac OSX?
- Is there a Windows/MSVC equivalent to the -rpath linker flag?
我无法将共享对象放在一个目录中,因为可能存在名称冲突。 LD_LIBRARY_PATH 和 PATH 不可用,因为我要添加 很多 路径。
这让我想知道我是否可以修改共享对象的 constructor 中的 LD_LIBRARY_PATH(使用 -Wl,-init)。这将要求构造函数在 运行 时间链接发生之前为 运行。我找不到是否是这种情况。
本质上,我正在考虑执行以下操作(尚未尝试过此代码):
将此函数添加到库源代码中:
extern char *searchPath;
void construct() {
char *libPath = getenv("LD_LIBRARY_PATH");
char *new_libPath = malloc(1 + snprintf(NULL, 0, "%s:%s", libPath, searchPath);
sprintf(new_libPath, "%s:%s", libPath, searchPath);
setenv("LD_LIBRARY_PATH", new_libPath, 0);
}
并编译:
gcc foo.c --shared -o foo -Wl,-init,construct
没有,一般不能。一些链接器可能支持它,但其他链接器肯定不会。许多动态链接器将在加载主可执行文件后忽略对 LD_LIBRARY_PATH
或等效项的更改,因此您甚至可能根本无法在运行时影响加载路径。在链接所有库之前,其他链接器甚至可能不会尝试调用初始化程序或构造函数(例如,Mac OS X dyld
似乎以这种方式运行)。
此外,某些链接器甚至不会加载具有相同 soname
的两个库,因为它们将被视为同一个库。因此,考虑到您的库中可能存在名称冲突,这甚至会首先阻止自动加载它们。
对于库的运行时加载,POSIX 提供了dlopen
和dlsym
。 dlopen
允许您通过文件路径加载任意库,dlsym
允许您获取指向该库中定义的符号的指针考虑使用这些而不是一些动态路径更改 hack - dlopen
和 dlsym
是便携的并且相当容易使用。是的,你没有得到 "automatic" 符号解析(因为你必须自己 dlsym
一切),但是有一些方法可以设计你的库来使这更容易(或使用宏来使解析更容易) .
在 Windows 上,您可以类似地使用 LoadLibrary
和 GetProcAddress
。如果你想要一个很好的跨平台库来消除平台差异,请考虑像 libltdl.