编译与链接

100 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第11天,点击查看活动详情

什么是编译

把程序的源代码翻译成CPU能够直接运行的机器代码,且编译永远是以一个源文件为单位,这样当我们对一个源文件修改时,只用编译该文件,则不用编译整个项目

注:常用的C/C++编译器除了gcc还有clang,msvc等。

什么是目标文件

经过编译后的二进制文件,后缀名为“.c” ,不同操作系统的目标文件类型并不相同如Windows是PE,而Linux是ELF,他们虽然互不兼容但在结构上非常相似,都是对二进制的封装。

gcc -c main.c 生成.o的文件,被称作目标文件,是一个二进制文件。文件格式是ELF,Windows上是PE。

readelf -h main.o 找到可执行文件的基本信息

readelf -S m 一系列的区块sections。.text .data等

注:目标文件虽然包含了编译之后的机器代码,但它并不能够直接执行,因为使用了尚未定义的函数如printf等,此类函数在主程序中仅是声明,编译器并不知道此类函数的定义,因此编译器只能将此类函数的跳转地址暂时先设为0随后在链接的时候再去修正它。

链接

其实是将编译之后的所有目标文件,连同用到的一些静态库、运行时库,组合拼装成一个独立的可执行文件,其中包括地址修正,此时,连接器会根据我们的目标文件或者静态库中的重定位表,找到那些需要被重定位的函数、全局变量,从而修正它们的地址,但我们在链接的时候,忘记提供必须的目标文件,那么链接器找不到声明函数的定义,于是报错“引用未定义”或者“符号未定义”。

1.jpg

makefile(make)

Makefile(make)是一个简单的构建工具,也可以用来自动生成文档,Makefile的核心是对“依赖”的管理。

makefile其实就是在构建一颗依赖树,你要构建最上方的这个目标就需要提供下面这些节点的文件,然后层层递归下去。用make指令可以根据依赖树递归的构建这个可执行文件。

2.jpg