★★★★★ 是小夏啊!
我们知道,当我们用像VS等这样的编译器写完代码后,会通过快捷键操作或是编译器上相应的选项来编译运行,紧接着我们一般通过控制面板来观察程序运行的结果,从而判断自己写的程序代码是否满足要求,进而对其进行Debug,修改代码直至输出达到预期目标。
那么有这么几个值得我们思考的问题:VS等编译器是如何将程序代码转换成可执行程序的?在企业中广受喜爱的Linux操作系统下又是怎样的?对于Linux操作系统中gcc/g++是如何使用的?
目录
一、背景知识
1、预处理(头文件展开、去注释、条件编译、进行宏替换等)
2、编译(生成汇编,汇编语言也需要编译,也有汇编编译器)
3、汇编(生成机器可识别代码)
4、链接(生成可执行文件或库文件)
函数库 :(链接时涉及的重要概念)
函数库的分类 :
二、gcc实际操作中如何将.c文件转化成可执行程序
三、g++实际操作中如何将.cpp文件转化成可执行程序
四、Linux项目自动化构建工具-make/Makefile
★ 依赖关系
★ 依赖方法
★ 原理
★ 项目清理
★ 测试
[xxp@VM-24-3-centos lesson1]$ gcc -E test.c -o test.i
[xxp@VM-24-3-centos lesson1]$ ls
install.sh test.c test.i
★ 预处理功能主要包括宏定义,文件包含,条件编译,去注释等。
★ 实例: gcc –E test.c –o test.i。
★ 选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。
★ 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。
[xxp@VM-24-3-centos lesson1]$ gcc -S test.i -o test.s
[xxp@VM-24-3-centos lesson1]$ ls
install.sh test.c test.i test.s
★ 在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作, 在检查无误后,gcc 把代码翻译成汇编语言。
★ 用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。
★ 实例: gcc –S test.i –o test.s。
[xxp@VM-24-3-centos lesson1]$ gcc -c test.s -o test.o
[xxp@VM-24-3-centos lesson1]$ ls
install.sh test.c test.i test.o test.s
★ 汇编阶段是把编译阶段生成的“.s”文件转成目标文件。
★ 读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了。
★ 实例: gcc –c test.s –o test.o。
[xxp@VM-24-3-centos lesson1]$ gcc test.o -o test
[xxp@VM-24-3-centos lesson1]$ ls
install.sh test test.c test.i test.o test.s
★ 在成功编译之后,就进入了链接阶段。
★ 实例: gcc hello.o –o hello。
我们的C程序中,并没有定义“printf”的函数实现,且在预编译中包含的“stdio.h”中也只有该函数的声明,而没有定义函数的实现,那么,是在哪里实“printf”函数的呢?
最后的答案是:系统把这些函数实现都被做到名为 libc.so.6 的库文件中去了,在没有特别指定时,gcc 会到系统默认的搜索路径“/usr/lib”下进行查找,也就是链接到 libc.so.6 库函数中去,这样就能实现函数“printf”了,而这也就是链接的作用。
链接如何理解:自己写的C程序和第三方库提供的方法关联起来。
函数库一般分为静态库和动态库两种。这里我们通过一个形象的例子来讲解:
如图所示,一名学生学习过程中需要通过电脑来查找资料;一种方案是到学校外面的网吧的资料库(动态库)查找 ,这种方法叫做动态链接(需要链接第三方库);另一种方案是在学校建立起等同于校外网吧的机房,相当于将函数库的内容拷贝到我自己的可执行程序当中,叫做静态链接。(不需要任何库)。
如图所示:gcc默认采用动态链接的方式生成可执行程序。
在第一部分,细述了gcc将.c文件转化成可执行程序的整个过程,但在实际使用过程当中不必如此麻烦。只需要一条指令即可:
[xxp@VM-24-3-centos lesson1]$ gcc test.c -o test
[xxp@VM-24-3-centos lesson1]$ ls
install.sh test test.c
[xxp@VM-24-3-centos lesson1]$ ./test
hello world
基本上和gcc使用一致,与vs的不同点是gcc和g++编译时的指令不同,而在vs中只需关注文件类型即可。g++也可当作gcc来编译.c文件。
[xxp@VM-24-3-centos lesson1]$ touch myfile.cpp
[xxp@VM-24-3-centos lesson1]$ vim myfile.cpp
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile myfile.cpp test test.c
[xxp@VM-24-3-centos lesson1]$ rm test
[xxp@VM-24-3-centos lesson1]$ g++ test.c -o test
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile myfile.cpp test test.c
[xxp@VM-24-3-centos lesson1]$ ./test
hello world
[xxp@VM-24-3-centos lesson1]$ g++ myfile.cpp -o myfile
[xxp@VM-24-3-centos lesson1]$ ./myfile
hello linux
首先,需要声明的一点是make是指令,Makefile是文件。在Makefile文件中存储的是相应的依赖关系和依赖方法。那么什么是依赖关系?什么是依赖方法?下面举个例子来说明:
一名学生来到月末后,需要家里边给生活费,他与父母之间就具有一种依赖关系;当他给家里边人打电话索要生活费的这种行为称作是依赖方法。但并不是所有的依赖方法都是成立的,例如:他和室友也具有某种依赖关系,但这种依赖关系并不足以其索要生活费这种依赖方法成立。
下面我们通过具体实例代码指令来实现:
[xxp@VM-24-3-centos lesson1]$ touch Makefile
[xxp@VM-24-3-centos lesson1]$ vim Makefile
[xxp@VM-24-3-centos lesson1]$ make
gcc test.c -o test -std=c99
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile test test.c
[xxp@VM-24-3-centos lesson1]$ make clean
rm -f test
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile test.c
例子在上面
上面的文件 test ,它依赖 test.o
test.o , 它依赖 test.s
test.s , 它依赖 test.i
test.i , 它依赖 test.c
例子在上面
gcc hello.* -option hello.* ,就是与之对应的依赖关系
make是如何工作的,在默认的方式下,也就是我们只输入make命令。那么
1. make会在当前目录下找名字叫“Makefile”或“makefile”的文件。
2. 如果找到,它会找文件中的第一个目标文件(target),在上面的例子中,他会找到“test” 这个文件,并把这个文件作为最终的目标文件。
3. 如果test文件不存在,或是hello所依赖的后面的hello.o文件的文件修改时间要比hello这个 文件新(可以用 touch 测试),那么,他就会执行后面所定义的命令来生成test这个件。
4. 如果test所依赖的test.o文件不存在,那么make会在当前文件中找目标为test.o文件的依赖 性,如果找到则再根据那一个规则生成test.o文件。(这有点像一个堆栈的过程)
5. 当然,你的C文件和H文件是存在的啦,于是make会生成 test.o 文件,然后再用 test.o 文 件声明make的终极任务,也就是执行文件test了。
6. 这就是整个make的依赖性,make会一层又一层地去找文件的依赖关系,直到最终编译出 第一个目标文件。
7. 在找寻的过程中,如果出现错误,比如最后被依赖的文件找不到,那么make就会直接退 出,并报错,而对于所定义的命令的错误,或是编译不成功,make根本不理。
8. make只管文件的依赖性,即,如果在我找了依赖关系之后,冒号后面的文件还是不在, 那么对不起,我就不工作啦。
1、工程是需要被清理的
2、像clean这种,没有被第一个目标文件直接或间接关联,那么它后面所定义的命令将不会被自动执行,不过,我们可以显示要make执行。即命令——“make clean”,以此来清除所有的目标文件,以便重编译。
3、但是一般我们这种clean的目标文件,我们将它设置为伪目标,用 .PHONY 修饰,伪目标的特性是,总是被执行的。
4、可以将我们的 test 目标文件声明成伪目标,测试一下。
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile test.c
[xxp@VM-24-3-centos lesson1]$ make
gcc test.c -o test -std=c99
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile test test.c
[xxp@VM-24-3-centos lesson1]$ make
make: `test' is up to date.
[xxp@VM-24-3-centos lesson1]$ make clean
rm -f test
[xxp@VM-24-3-centos lesson1]$ ls
install.sh Makefile test.c
[xxp@VM-24-3-centos lesson1]$ make clean
rm -f test
如上述测试,当执行完make指令后未对项目进行清理时,无法再次执行make指令;但是对于make clean 指令却总是被执行的。
★ makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率
★★★★★ 感谢阅读!!!