假设我有三个源文件main.c,a.c和b.c.在main.c中称为一些在a.c中定义的函数(不是全部)。 b中定义的所有函数都不是由main.c调用(使用)的。在main.c中是主要功能。然后我们有一个makefile,它编译所有源文件(main.c,a.c和b.c)然后链接它们以生成可执行文件,在我的案例中是intel hex文件。我的问题是:链接器是否知道主函数所在的文件,并知道要确定要链接在一起的目标文件的哪个部分?我的意思是,如果链接器仅根据规则的配方生成exe文件来生成目标,那么无论在我们的应用程序代码中调用了多少函数,可执行文件的大小都是相同的,因为配方说要链接所有目标文件。例如,我们编译三个源文件,我们得到三个目标文件:main.o a.o和b.o(目标文件越大,exe文件越大)。我知道你会说如果你不想要b.c中的任何东西,那么不要在构建中包含它。但这意味着每次我想要更改应用程序(包括/ exclide模块)时,我都需要更改makefile。另一件事是链接器如何知道要采用的目标文件的哪一部分,它是否理解C语言?我希望你理解我的问题,原谅我的英语不好。
答案 0 :(得分:2)
1)链接器是否知道主函数所在的文件,并知道要确定要链接在一起的目标文件的哪一部分?
也许你的工具链(编译器/链接器)有选项可以实现这种优化,我的意思是从链接中删除未使用的函数,但我对全局函数有很大的疑问(对于静态函数可能是可能的) 。
2)另一件事是链接器如何知道要采用的目标文件的哪一部分,它是否理解C语言?
链接器可以检测应用程序是否未使用某个函数或变量(再次检查可用选项),但实际上并不是此工具的目标。但是,如果将某些函数编译/链接为库函数(请参阅选项),则可以生成"库"文件,然后将此库与其他目标文件链接。只有使用它们时,链接器才会包含库的功能。
我的建议:使用编译标记(#ifdef ...)在编译/链接中包含或排除部分代码。
答案 1 :(得分:1)
如果只想要最终从main
调用的可执行文件中的那些函数,请使用目标文件库。
基本上,链接器从库中提取的最小单元是目标文件。无论该目标文件中的符号是什么,也将被解析,直到所有符号都被解析。
换句话说,如果需要对象文件中符号的 none ,它将不会在结果中结束。如果需要至少一个符号,它将完整链接。
不,链接器不理解C.注意许多语言编译器创建目标文件(C ++,FORTRAN,...和汇编程序)。链接器解析符号,它们是附加到值的名称。
John Levine写了一本书“Linkers and Loaders”,可以在网上找到,它可以让你深入了解链接器,符号和目标文件。