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

原创 2016年06月02日 12:00:18

一,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的其他内容后面会继续完善的,有很多不足的地方希望小伙伴们帮忙指正。

版权声明:

相关文章推荐

c++ 编译链接,makefile思路整理

长虹剑自己的一些经验总结,具体请自行根据实际情况决定。 (未完且待细节补充 ) - 2016-10-25 补充了一个makefile模板 - 2016-10-27 补充了cmake及cmake...

Makefile经典教程(掌握这些足够)

makefile很重要       什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professio...
  • ruglcc
  • ruglcc
  • 2012-07-31 15:28
  • 400381

make:一个非常重要的编译命令

无论是在Linux还是在Unix环境中,make都是一个非常重要的编译命令。不管是自己进行项目开发还是安装应用软件,我们都经常要用到make或make install。利用make工具,我们可以将大型...

GUN make学习笔记之make显示规则

在上一篇GUN make 学习笔记之make初探中,我们编写了一些规则用于编译和链接我们的程序。每个规则都定义了目标(即被更新的文件)。每个目标文件都依赖一组前提条件(同样也是文件)。当要求更新目标...

Linux下通过源码编译安装程序(configure/make/make install的作用 )

一、程序的组成部分 Linux下程序大都是由以下几部分组成: 二进制文件:也就是可以运行的程序文件 库文件:就是通常我们见到的lib目录下的文件 配置文件:这个不必多说,都知道 帮助文档:通...

linux下用CMake、make工具手动编译程序的步骤、方法

使用CMake可以方便的创建makefile文件,再配合make软件就可以实现不用IDE手动编译软件的功能。 使用的CMake版本为V3,4,0,make版本为3.81。 1、创建好项目的...

多模块编译链接 Makefile文件的编写

一、概述 现在,免费的操作系统Linux的使用者越来越多。Linux的爱好者们也许要在Linux软件开发上一展身手,不过很遗憾,Linux平台上还没有一个像Visual C++或Borland Del...

make: *** No rule to make target解决办法

今天在公司编译cocos2.2.6源码时出现这个错误:make: * No rule to make target /home/hxl/bin/cocos2d-x-2.2.6/projects/Hel...

【Linux】make的工作原理和makefile文件

● makefile文件      make是一个命令,makefile是一个文件。make命令执行时,需要一个 Makefile 文件,以告诉make命令需要怎么样的去编译和链接程序。一个工程中的源...

使用make命令编译项目文件入门

使用make命令编译项目文件入门 目录: 一、make命令的运行过程 二、基本gcc编译命令 三、简单Makefile文件的编写 四、实例 一、make命令的运行过程    ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)