make和makefile以及程序的编译和链接过程

一, Linux 下程序运行过程 
1,在一个目录下新建三个文件:main.c hello.c hello.h分别编写他们如下图: 
小程序学习编译链接执行过程  
2,想要让这个程序执行起来,就必须对上面的三个文件分别进行编译链接执行,如下图: 
目标文件的编译,生成.o文件  
链接生成可执行文件mian,并执行main  
通过上面这个过程。我们可以大致总结一下gcc编译器把目标文件经过预处理,编译,汇编,链接生成可执行文件的过程和命令: 
(1)预处理(宏替换,删除注释和多余的空白字符,条件编译,文件包含):  
预处理过程  
其中选项-E进行查看,这个选项的作用是让gcc在预处理结束后停止编译 
过程。 
选项-o是指目标文件,.i文件为已将完成预处理过程的C原始程序。 
(2)编译(gcc检查代码规范性,是否有语法错误,生成汇编):  
编译  
其中选项-S进行查看,这个选项只进行编译而不进行汇编,生成.s文件。 
(3)汇编(生成机器可识别代码,将编译生成的.s文件转成.o二进制目标代码):  
汇编  
(4)链接(生成可执行文件或库文件):  
在成功编译后,就进入了链接的阶段,这里涉及到一个重要的概念: 函数库 查看上面的小程序会发现里面并没有定义printf函数的实现,并且在预编译阶段包含进去的“stdio.h”里面也只有它的声明,而没有定义函数的实现。那么printf实在哪里实现的呢? 
其实系统把对这些函数的实现都做到名字为 libc.so.6 的库文件中去了,在没有特别指定时,gcc会到系统默认的路径 “/user/lib” 下面进行查找,并且链接到 lib.so.6 库函数中去,这样就能实现printf函数了,这也就是链接的作用。 
函数库分为两种: 静态库和动态库 。静态库是指在编译链接时将库文件的代码全部加入到可执行文件里,因此生成的文件比较大,但在执行过程中就不会再用到库文件了,后缀名一般为.a;动态库和它相反,在编译链接过程中并没有将库文件加入到可执行文件里面去,而是在程序执行时由运行时链接文件加载库,这样可以节省系统的开销,后缀名一般为.so。上面提到的libc.so.6就是动态库,所以也就可以得到gcc在编译时默认使用动态库。完成链接过程,gcc就可以生成可执行文件main了。 
链接  
(5)执行:  
”./可执行文件名“就可以执行这个程序啦,输出结果如下图: 
执行  
二,make和makefile 
1,对make和makefile的理解 
像上面提到的那样,要把一个程序执行起来首先要经过编译生成中间文件(.o文件)( 在编译时编译器只检查程序语法,函数,变量是否被声明,如果函数没有被声明,编译器会给出警告,但还是会生成.o文件。在链接时链接器会在所有的.o文件里寻找函数的实现,如果没有找到,那就会报链接错误码,就类似与这种:Link2001错误 )再经过链接生成可执行文件,这样在小程序里看起来没什么,但在大型的工程里这却是非常艰难烦躁的过程,你必须记住所有中间文件的文件名,才能方便在链接时用到它们,但如果程序里出现了一点小bug,那么上面的过程都要重新来过。这样效率实在太低了,所以就出现了makefile和make。 
一个工程中的源文件不计其数,其按类型,功能,模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件要先编译,哪些后编译,哪些需要重新编译,甚至进行更复杂的功能操作。makefile就像一个shell脚本一样,其中也可以执行 操作系统 的命令。makefile带来的好处就是“ 自动化编译 ”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。 
make和makefile的区别:  
make:是一个命令工具。 
makefile:是一个存放编译方法的文件。 
2,书写makefile的格式和规则 
make命令执行时,需要一个Makefile文件,告诉make需要怎样去编译和链接程序。下面是makefile的书写规则: 
(1)如果这个工程没有被编译过,那么我们的所有C文件都要编译并被链接。 
(2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。 
(3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。 
Makefile文件(形式1)  
Makefile文件(形式2)  
注意: 
在定义好依赖关系后,后续的那一行定义了如何生成目标文件的操作系统命令,一定要以一个Tab键作为开头。记住,make并不管命令是怎么工作的,他只管执行所定义的命令。 
clean不是文件,是一个动作名词,make clean用它来清除所有的目标文件,以便于进行重编译。 
clean的两种写法  
加@和不加@的对比  
3,make是怎么工作的? 
(1)make会在当前目录下找名字叫“Makefile”或“makefile”的文件。 
(2)如果找到,它会找文件中的第一个目标文件,在上面的例子中,他会找到“hello”这个文件,并把这个文件作为最终的目标文件。 
(3)如果hello文件不存在,或是hello所依赖的后面的 .o 文件的文件修改时间要比hello这个文件新,那么,他就会执行后面所定义的命令来生 
成hello这个文件,这个也就是重编译。 
(4)如果hello所依赖的.o文件也存在,那么make会在当前文件中找目标为.o文件的依赖性,如果找到则再根据那一个规则生成.o文件。(这 
有点像一个堆栈的过程) 
(5)当然,你的.c文件和.h文件是存在的啦,于是make会生成 .o 文件, 
然后再用 .o 文件声明make的终极任务,也就是执行文件hello了。 
make会一层一层去找文件的依赖关系,直到最终编译出第一个目标文件,如果过程中出现了错误(被依赖的文件找不到等),make会直接退出并报错。而对于所定义的命令的错误,或是编译不成功,make根本不理。make只管文件的依赖性,即如果在我找了依赖关系之后,冒号后面的文件还是不在,那么对不起,make就不工作啦。 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值