关闭

make,makefile和程序的编译链接过程

标签: makefilelinux编译器
2841人阅读 评论(0) 收藏 举报
分类:

一,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就不工作啦。
好啦,就说这么多啦,有关make和makefile的其他内容后面会继续完善的,有很多不足的地方希望小伙伴们帮忙指正。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9229次
    • 积分:152
    • 等级:
    • 排名:千里之外
    • 原创:40篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条
    文章分类
    文章存档