在 Linux 中构建、链接进程

在 Linux 中构建、链接进程

我无法区分构建和编译之间的区别。它们相同吗?链接到底是如何工作的? .so 文件和 .o 文件到底包含什么以及我应该如何使用它们?这些文件我每天都会看到,但我不知道它们到底包含什么。谁能建议一些教程来清楚地讲述这些过程?

答案1

术语“构建”通常用于表示从一组源代码文件和其他资源开始,到一组可执行文件、共享库(可能还有其他资源)结束的整个过程。
这可能涉及很多步骤,例如特殊的预处理器(moc例如 Qt 代码)、代码生成器(flex/yaccbison例如)、编译、链接以及可能的后处理步骤(例如构建tar.gzrpm分发文件)。

对于 C 和 C++(以及相关语言),编译是将源文件(.c例如 C 代码文件)转换为目标文件 ( .o)。这些目标文件包含编译器为相应源代码生成的机器代码,但不是最终产品 - 特别是,外部函数(和数据)引用未解析。从这个意义上说,它们是“不完整的”。
目标文件有时会组合在一起形成档案(.a文件),也称为静态库。这几乎只是将它们分组在一起的一种便捷方式。

链接需要(通常是几个)目标文件(.o.a)和共享库,组合目标文件,解析(主要)目标文件本身和共享库之间的引用,并生成您可以实际使用的可执行文件或共享库(.so)可以被其他程序或共享库使用。

共享库是可以由其他可执行文件直接使用的代码/函数的存储库。针对共享库的动态链接与直接(静态)链接对象或存档文件之间的主要区别在于,可以更新共享库而无需重建使用它们的可执行文件(尽管对此有很多限制)。
例如,如果在某个时刻在 OpenSSL 共享库中发现错误,则可以在该代码中进行修复,并且可以生成和发布更新的共享库。动态链接到该共享库的程序不需要重新构建即可修复错误。更新共享库会自动修复其所有用户。
如果他们改为与目标文件链接(或一般静态链接),他们将不得不重建(或至少重新链接)以获得修复。

一个实际的例子:假设您想用 C 语言编写一个程序 - 一个精美的命令行计算器,它具有命令行历史记录/编辑支持。您将编写计算器代码,但将使用该readline库进行输入处理。
您可以将代码分为两部分:数学函数(将这些函数放入mathfuncs.c)和处理输入/输出的“主”计算器代码(放入main.c)。

你的建造包括:

  • Compile mathfuncs.c(gcc -o mathfuncs.o -c mathfuncs.c代表-c“仅编译”)
    mathfuncs.o现在包含已编译的数学函数,但不是“可执行的” - 它只是函数代码的存储库。

  • 编译你的前端(gcc -o main.o -c main.c
    main.o同样只是一堆函数,不可运行

  • 链接您的计算器可执行文件,链接为readline

    gcc -o supercalc main.o mathfuncs.o -lreadline
    #      ^ executable                    ^ dynamic link with libreadline.so
    #                  ^         ^ two .o files statically linked in
    

    现在您有了一个可以运行的真正可执行文件 ( supercalc),这取决于readline库。

  • 构建一个rpm包含所有可执行文件和共享库(和头文件)的包。 (这些.o文件是临时构建产品而不是最终产品,通常不会被发送。)

这样,如果在 中发现错误readline,您无需重建(并重新发布)可执行文件即可获得修复 -libreadline.so只需更新即可。但是,如果您发现 中的错误mathfuncs.c,则需要重新编译并重新链接supercalc(并发布新版本)。

相关内容