假设您的程序由两个源文件(main.c和auxiliary.c)和两个头文件(declarations.h和auxiliary.h)组成。
然后按如下方式运行编译器:
$gcc main.c auxiliary.c -o myprogram
问题1 :编译器是否会为我的程序创建一个单个目标文件(即只缺少库)或者它会创建两个目标文件,每个源文件一个(然后链接一切都在一起)?
问题2 :是否需要单独调用链接器?因为如果您使用上面的命令,编译器会为您处理,对吧?
问题3 :为什么某些库会自动链接(例如,stdio)以及为什么有些库需要额外的工作(例如,math.h需要在编译时添加-lm)。 -lm代表什么?
问题4 :假设您有一个源文件,并且您的程序不需要任何外部库。这是否意味着您从编译器获得的目标代码已经可执行? (即编译它像$ gcc -c main.c)。
答案 0 :(得分:4)
gcc通常会为每个源文件生成一个对象。但是有一个-combine
选项可以告诉您不想这样做。
当你有几十个源文件时重新编译所有内容并不是一个好主意(当你有更多时,你将它们分成库)。
历史。曾经有一段时间 - 在共享库之前 - 当数学库相对较大并将其放入每个可执行文件中时,即使那些不需要它的人也被认为是浪费的(使用数学库涉及像printf这样的函数的替代版本,所以即使不使用你也有成本)
我正在等待一个程序不使用标准库的任何部分(逻辑上调用main作为exit(main(argc, argv))
完成,因此至少调用exit
)然后是启动和完成代码。
答案 1 :(得分:3)
gcc
为每个源文件创建一个目标文件,然后链接它们以构建可执行文件。
您的示例证明gcc
能够链接所有必需的步骤
自动链接的库是标准C库。其他需要指定。这允许在不需要atan2()
时构建较小的可执行文件。
-lm
向编译器指示它应该找到数学库,其id为m
。在Unix上,其文件名为libm.so
或libm.a
,具体取决于链接是动态的(在运行时执行并导致较小的可执行文件)还是静态的(在链接时执行并导致独立的可执行文件)。 / p>
没有。无论如何,它必须链接到标准C库。此外,目标代码的文件格式与可执行文件不同。
答案 2 :(得分:1)
问题1 :使用'-save-temps'执行你的gcc语句,你会看到编译器创建了两个目标文件。
问题2 :对链接器的调用是隐含的。 'gcc'命令实际上不是一个编译器,但是通过根据需要调用预处理器,编译器,汇编器和链接器来驱动编译过程。 在小程序中,让'gcc'处理所有事情是一个好主意,但是对于包含许多源文件的大型程序,这意味着重新编译所有源文件,即使它们没有更改。
问题3 :这是一个惯例问题。 (m库是数学库。)
问题4 :不,事实并非如此。总是需要链接一些额外的代码来处理流程启动/拆卸要求。在linux上,这些是crt1.o,crti.o,crtbegin.o和crtn.o文件。