显然 libtool 要求 .la 文件存在并正确声明其 rpath,即使它不会用于这个真正静态的二进制文件中的任何内容。
Libtool 的文档清楚地表明,您的“模块”文件应包含以下预处理器宏,以便导出所有符号。
#define SYMBOL SOURCEFILENAME_LTX_SYMBOL
在我的例子中,这导致 bromine.c 和chloro.c 分别具有以下内容。
#define chemical_name bromine_LTX_chemical_name
#define chemical_name chlorine_LTX_chemical_name
仍然假设我的问题中的代码存储库,以下命令是如何使用 libtool 自动 dlpreopen 二进制文件的示例。
libtool --mode=compile gcc -static -fPIC -fno-plt -c bromine.c
libtool --mode=compile gcc -static -fPIC -fno-plt -c chlorine.c
libtool --mode=link gcc -all-static -fPIC -fno-plt -o bromine.la -rpath $PWD -module -no-undefined -avoid-version bromine.lo
libtool --mode=link gcc -all-static -fPIC -fno-plt -o chlorine.la -rpath $PWD -module -no-undefined -avoid-version chlorine.lo
但是,对我来说,跳过每个 libtool 步骤并简单地在 main.c 本身中声明所需的结构数组要简单得多。将重新定义的函数/符号声明为 extern int,无论其类型如何,并创建一个名为 lt__PROGRAM__LTX_preloaded_symbols 的 lt_dlsymlist 数组。第一个元素是程序本身,最后一个元素是 {0, (void *) 0}。在这两者之间,一个结构行将声明 dlpreopened 对象/静态存档的基本名称,文件后缀为“.a”。
无论它是 .a、.o、.c 还是任何其他文件,它都会有 .a 后缀。下一个结构将是您希望使用的从中导出的所有符号,然后,如果您愿意,还有另一个文件名、它的符号等等。符号名称将使用 (void *) &SYMBOL 而不是 (void *) 0 ,就像所有其他字段一样。
extern int bromine_LTX_chemical_name();
extern int chlorine_LTX_chemical_name();
const lt_dlsymlist lt__PROGRAM__LTX_preloaded_symbols[] ={
{"@PROGRAM@", (void *) 0},
{"chlorine.a", (void *) 0},
{"chlorine_LTX_chemical_name", (void *) &chlorine_LTX_chemical_name},
{"bromine.a", (void *) 0},
{"bromine_LTX_chemical_name", (void *) &bromine_LTX_chemical_name},
{0, (void *) 0}
};
最后,lt_dlopen 不反映 lt_dlsymlist 声明——理想情况下,您将只调用文件的基本名称,而不调用它的扩展名。例如
handle = lt_dlopen("chlorine");
不是
handle = lt_dlopen("chlorine.a")
但是,我相信无论您提供什么扩展,它都会起作用,因为 lt_dlopen 函数会剥离扩展。
按照上述规定的方式进行操作可以将您的编译减少到一行并完全避免使用 libtool。例如
gcc -static -Wl,-static -fPIC -fno-plt -Wl,-z,now,--no-undefined -o main main.c bromine.c chlorine.c -lltdl -ldl
我还验证了这会生成一个真正的静态二进制文件,方法是链接到 libltdl 的调试版本,其中包含所有内容,但预先打开(没有 libdl 等)。
$./main HOBr HOCl
loaders: lt_preopen
try_dlopen (bromine, (null))
tryall_dlopen (bromine.a, lt_preopen)
Calling lt_preopen->module_open (bromine.a)
Result: Success
try_dlopen (chlorine, (null))
tryall_dlopen (chlorine.a, lt_preopen)
Calling lt_preopen->module_open (chlorine.a)
Result: Success
The IUPAC name of HOBr is hypobromous acid.
The IUPAC name of HOCl is hypochlorous acid.