C 有没有办法让链接器从库中提取对象文件的一部分进行链接?
我有一个包含数千个C文件、许多库和数十个程序的项目要链接,为了加快编译速度,我将C文件合并到包含多个C文件的翻译单元中。这有时被称为单个编译单元、单个翻译单元或统一构建 我将多个翻译单元编译到不同的库中,这些库以前是通过单独编译每个C文件创建的 例如: old library.lib:C 有没有办法让链接器从库中提取对象文件的一部分进行链接?,c,linker,translation-unit,C,Linker,Translation Unit,我有一个包含数千个C文件、许多库和数十个程序的项目要链接,为了加快编译速度,我将C文件合并到包含多个C文件的翻译单元中。这有时被称为单个编译单元、单个翻译单元或统一构建 我将多个翻译单元编译到不同的库中,这些库以前是通过单独编译每个C文件创建的 例如: old library.lib: file1.o file2.o file3.o file4.o file5.o file6.o translation_unit_1.o translation_unit_2.o new library.li
file1.o
file2.o
file3.o
file4.o
file5.o
file6.o
translation_unit_1.o
translation_unit_2.o
new library.lib:
file1.o
file2.o
file3.o
file4.o
file5.o
file6.o
translation_unit_1.o
translation_unit_2.o
翻译单元1.c:
#include "file1.c"
#include "file2.c"
#include "file3.c"
翻译单元2.c:
#include "file4.c"
#include "file5.c"
#include "file6.c"
所以这些编译成:translation\u unit\u 1.o和translation\u unit\u 2.o。该库是上面显示的new library.lib
现在假设我有一个程序,我想链接到library.lib,它引用file2.c中的函数。但是它编译的file1.c版本不同,它复制了库中file1.c中的符号,因此它只需要library.lib中的file2.c来链接。或者我需要链接file1.c中的代码,但无法链接file2.c,因为它有一个我不想依赖的依赖项(下面的示例)
节目:
main.o
file1.o
library.lib
您知道的任何链接器有没有一种方法可以让链接器只从文件2.c中从翻译单元1.o对象代码中提取代码,并使用该代码链接main.o以生成程序
另一种方法是将翻译单元1.o拆分为file1.o、file2.o、file3.o(如果可能的话),然后将其提供给链接器
谢谢你的帮助
编辑1
这适用于为使用ARM ADS 1.2工具链编译的ELF的裸机ARM平台和使用Visual Studio工具链的Windows平台编译的单个代码库。然而,关于如何在其他平台和工具链上解决这个问题的想法是受欢迎的
下面是一个使用clang的MacOS的具体示例
下面是示例代码:
图书馆:
file1.c需要链接此文件
file2.c此文件不用于链接,并且具有未解析的依赖项,该依赖项可能位于另一个库或对象中
主要条款c:
int main( void ) {
extern int file1_a( void );
int x = file1_a();
}
文件1.c:
int file1_a(void) {
return 1;
}
文件2.c:
int file2_a( void ) {
extern int file3_a( void );
return file3_a(); // file3_a() is located somewhere else
}
单翻译单位c:
#include "file1.c"
#include "file2.c"
这将产生program1.out:
++ clang -c file1.c -o file1.o
++ clang -c file2.c -o file2.o
++ libtool -static file1.o file2.o -o library1.lib
++ clang -c main.c -o main1.o
++ clang main1.o library1.lib -o program1.out
这无法生成program2.out:
++ clang -c single_translation_unit.c -o single_translation_unit.o
++ libtool -static single_translation_unit.o -o library2.lib
++ clang -c main.c -o main2.o
++ clang main2.o library2.lib -o program2.out
Undefined symbols for architecture x86_64:
"_file3_a", referenced from:
_file2_a in library2.lib(single_translation_unit.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
更改链接顺序也不起作用:
++ clang library2.lib main2.o -o program2.out
Undefined symbols for architecture x86_64:
"_file3_a", referenced from:
_file2_a in library2.lib(single_translation_unit.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
有没有办法与clang、gcc、microsoft或任何链接器联系
clang
、gcc
或microsoft
都不是链接器(前两个是编译器,第三个是公司)
答案还取决于平台(您没有指定)
如果您是在Linux或其他ELF平台上构建,则可以使用-ffunction sections-fdata sections
编译代码,链接器将自动执行您想要的操作
有没有办法让链接器从库中提取对象文件的一部分进行链接
一般来说,链接器在分区上运行,并且不能将分区分开(您要么得到全部,要么什么也得不到)
如果没有-f函数节
,单个翻译单元中的所有函数都会在单个.text
节中结束(这是一个近似值--内联
函数的模板实例化和越位函数定义通常会在它们自己的节中结束)。因此,链接器不能选择.text
的部分,但不能选择全部
有没有办法与clang、gcc、microsoft或任何链接器联系
clang
、gcc
或microsoft
都不是链接器(前两个是编译器,第三个是公司)
答案还取决于平台(您没有指定)
如果您是在Linux或其他ELF平台上构建,则可以使用-ffunction sections-fdata sections
编译代码,链接器将自动执行您想要的操作
有没有办法让链接器从库中提取对象文件的一部分进行链接
一般来说,链接器在分区上运行,并且不能将分区分开(您要么得到全部,要么什么也得不到)
如果没有
-f函数节
,单个翻译单元中的所有函数都会在单个.text
节中结束(这是一个近似值--内联
函数的模板实例化和越位函数定义通常会在它们自己的节中结束)。因此,链接器无法使用GCC/binutils ELF工具链或适当兼容的工具选择.text
的部分(但不是全部),您可以通过以下方式完成此操作:
single\u translation\u unit.c
程序2.out
gcc
替换为clang
链接成功是因为:
- 在编译中,
指示编译器发出每个函数定义 在对象文件的不同代码段中,不包含任何其他内容,而是将它们全部合并到 默认情况下,一个-fffunction节
节.text
- 在链接中,
指示链接器丢弃未使用的节, i、 e.程序未引用符号的部分-Wl,-gc节
- 未引用函数
的定义获得了一个不同的代码段, 不包含任何其他内容,因此未使用。链接器能够丢弃这个未使用的部分,并将其一起丢弃file2\u a
定义中对file2\u a
的未解析引用file3\u a
file2\u a
或file3\u a
的引用,我们可以看到:
$ nm program2.out | egrep '(file2_a|file3_a)'; echo Done
Done
如果我们重新进行链接,请求一个映射文件:
$ gcc main2.o library2.a -Wl,-gc-sections,-Map=mapfile -o program2.out
然后,地图文件将显示:
...
...
Discarded input sections
...
...
.text.file2_a 0x0000000000000000 0xb library2.a(single_translation_unit.o)
...
...
那
$ gcc main2.o single_translation_unit.o [-Wl,-gc-sections] -o program2.out