文章目录
- 1.gcc编译过程
- 1.1预处理
- 1.2编译
- 1.3汇编
- 1.4链接
- 2.自动化构建工具-make和makefile
- 2.1使用背景
- 2.2两者的概念和区别
- 2.3项目清理
- 3.Linux简单进度条的实现
1.gcc编译过程
1. 预处理(进行宏替换)
2. 编译(生成汇编)
3. 汇编(生成机器可识别代码)
4. 连接(生成可执行文件或库文件)
1.1预处理
预处理(Preprocessing):在这个阶段,gcc会对源代码进行预处理,主要包括处理宏定义、头文件包含、条件编译等操作。预处理器会根据预处理指令(以#开头)对源代码进行处理,并生成一个经过预处理的中间文件。
格式 gcc [选项] 要编译的文件 [选项] [目标文件]
实例: gcc –E test.c –o test.i
选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
1.2编译
编译(Compilation):在这个阶段,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查无误后,gcc会将预处理后的中间文件转换为汇编代码。它会进行词法分析、语法分析、语义分析等操作,生成相应的汇编代码文件(通常以.s或.asm为扩展名)。
用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
实例: gcc –S test.i –o test.s
1.3汇编
汇编(Assembly):在这个阶段,gcc会将汇编代码转换为机器码或可执行的二进制文件。它会调用系统上的汇编器(如gas)将汇编代码转化为目标文件(通常以.o为扩展名)。
实例: gcc –c test.s –o test.o
1.4链接
链接(Linking):在这个阶段,gcc会将目标文件和其他必要的库文件进行链接,生成最终的可执行文件。链接器(如ld)会解析目标文件中的符号引用,将它们与其他目标文件或库文件中的符号定义进行匹配,并生成最终的可执行文件。
实例: gcc test.o –o test
代码即可编译成功。
2.自动化构建工具-make和makefile
2.1使用背景
当然一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,每个文件多有相对应的规则去执行,一些文件需要先编译,一些文件需要后编译,也可能一些文件需要重新编译,甚至于进行更复杂的功能操作。
对此引入了makefile来定义了一系列的规则来指定文件所对应的编译需求。
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。而make是一个命令工具,是一个解释makefile中指令的命令工具。
2.2两者的概念和区别
在Linux中,make是一个构建工具,而makefile是用于描述和指导make工具进行构建过程的文件。
(1)make的概念:make是一个命令行工具,旨在自动化构建软件的过程。 它根据指定的构建规则和依赖关系,判断哪些文件需要重新编译,并执行相应的构建命令进行编译和链接。make会读取makefile文件来获取构建规则和命令。
(2)makefile的概念:makefile是一个文本文件,包含了构建软件的规则、依赖关系和构建命令。 它告诉make工具如何进行构建,定义了目标、依赖关系和构建命令之间的关联。通过编写合适的makefile文件,可以实现对项目的自动化构建。
(3)两者的区别:make是一个构建工具,提供了命令行接口来执行构建操作,而makefile则是一个文本文件,用于描述构建规则和命令。 make工具根据makefile文件中的规则和依赖关系,进行自动化构建,而makefile文件本身并不具备执行构建的能力。
make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。
1.什么是依赖规则
依赖规则(Dependency rules)是在makefile中定义的规则,用于描述一个目标和其所依赖的文件之间的关系。依赖规则告诉make工具,在构建目标之前,需要先检查并更新相关的依赖文件。
一个简单的依赖规则通常包括三个部分:目标、依赖和命令。
target: dependency1 dependency2
command1
command2
在这个例子中,我们定义了两个依赖规则:
对于目标hello,它依赖于hello.o目标文件。如果hello.o不存在或者比hello的生成时间要早,那么make工具会执行后续的构建命令将hello.o编译链接成可执行文件hello。
对于目标hello.o,它依赖于hello.c源文件。如果hello.c不存在或者比hello.o的生成时间要晚,那么make工具会执行后续的构建命令将hello.c编译成目标文件hello.o。
hello: hello.o
gcc hello.o -o hello
hello.o: hello.c
gcc -c hello.c -o hello.o
2.什么是依赖关系
依赖关系(Dependency relationships)是指一个软件系统或项目中,各个组件或模块之间的相互依赖关系。在软件开发中,依赖关系描述了一个组件或模块在实现或运行过程中所依赖的其他组件或模块。
hello: hello.o //文件 hello ,它依赖 hell.o
gcc hello.o -o hello
hello.o: hello.s //hello.o , 它依赖 hello.s
gcc -c hello.s -o hello.o
hello.s: hello.i //hello.s , 它依赖 hello.i
gcc -S hello.i -o hello.s
hello.i: hello.c //hello.i , 它依赖 hello.c
gcc -E hello.c -o hello.i
对于第一条目标hello,它依赖于hello.o目标文件。如果hello.o不存在或者比hello的生成时间要早,那么make工具会执行后续的构建命令将hello.o链接成可执行文件hello。后面三条同理。
2.3项目清理
工程是需要被清理的,对于使用使用构建系统提供的清理目标(makefile):通常会提供清理目标以辅助清理工作。Makefile中可以定义一个名为clean的目标,其命令中包含删除生成文件的操作。通过运行make clean命令,将执行所定义的清理任务。
但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
用make和makefile实现hello world!
makefile
$@指前一项文件hello $^指后一项文件hello.c
hello world!
执行成功
删除成功
3.Linux简单进度条的实现
#include <stdio.h>
#include <unistd.h>
#include <string.h>
int main()
{
int i = 0;
char bar[102];
memset(bar, 0 ,sizeof(bar));
const char *lable="|/-\\";
while(i <= 100 )
{
printf("[%-100s][%d%%][%c]\r", bar, i, lable[i%4]);
fflush(stdout);
bar[i++] = '#';
usleep(10000);
}
printf("\n");
return 0;
}
这些就是Linux中gcc编译、make和makefile的简单介绍了😉
如有错误❌望指正,最后祝大家学习进步✊天天开心✨🎉