使用带有libs/headers的gcc编译的正确方法是什么?

0 linker gcc compilation

我的第一个例子不起作用,但我的第二个例子确实有效.所以这让我想问一下链接时编译的正确方法是什么?是否有关于正确链接的更多信息?

非工作: gcc $(curl-config --libs --cflags) prog.c -o prog

工作: gcc prog.c $(curl-config --libs --cflags) -o prog

Jon*_*ler 5

C编译器 - 它是GCC还是任何其他编译器并不重要 - 是一个复杂的生物.它实际上调用单独的进程来完成工作的不同部分.有解析器,可能(现在通常会这样)包括预处理器部分,然后是代码生成,通常是汇编程序,然后是汇编程序生成对象,最后是程序链接(通常由程序调用ld,用于加载程序).详细的组织可以是不同的; 这里的关键点是加载器对早期阶段创建的目标文件以及它被告知要使用的库进行操作.

当您编写调用以链接可执行文件时,您可能也可能不会将代码编译到目标文件.在您的示例中,您编译prog.cprog.o; 通常,link命令仅列出目标文件而不列出任何源文件.

使用C编译器添加的选项(以及可能的目标文件)调用链接器,然后是目标文件和库,并按照您在命令行上列出的顺序链接相关选项,以及它自己添加的任何库.

有两种类型的链接 - 静态和动态.使用静态链接,可执行文件包含它将在运行时使用的所有对象代码,除了在运行时动态加载的任何内容.链接器在遇到目标文件和库时处理它们.通常,第一个目标文件被称为类似的crt0.o并由编译器提供; 它包含对的引用main().链接器通过记录它定义的符号和它引用的未定义的符号来处理目标文件.

对于静态链接,它会在库遇到它们时对其进行扫描; 如果库提供了当前未定义的符号,则它会从库中提取相关代码,并根据需要重新扫描以查找已引用但尚未定义的其他符号.如果唯一未定义的符号是main()并且库不包含main()(这是正常的),则跳过库有效.

对于动态链接(使用共享对象或动态链接库,也就是DLL),过去情况(在某些机器上),如果您在链接行上提到了一个库,则所有符号都会自动处理为已定义,无论它们是使用与否.最近,如果编译器在扫描它的链接过程中不包含任何相关符号,则忽略库.

您的工作示例显示了正确的链接顺序 - 目标文件之后的库.当然,在您的示例命令行中,列出了源文件,但编译器将命令转换为引用它刚刚从源创建的目标文件,并在命令行中列出序列中的库和其他链接器标志.如果您有一个旧式链接器记录了共享对象的使用,无论它是否满足任何未定义的引用,"非工作"行也会链接OK.然而,它永远不可靠; 如果任何库是一个静态库,你运行通常会遇到问题.

所以,规则很简单:

  • 链接程序时列出库之前的目标文件.

它始终有效 - 新旧连接器,静态和动态库.在某些平台上,迟早会以任何其他方式执行此操作.