makefile讲解
初识Makefile
- makefile的意义
什么是makefile?或许C或C++程序员中很多人都不知道这个东西,因为IDE(集成开发环境:如VS,QtCreator,CLoin, Keil)已经为你做了全面工作,包括编译规则和工程管理。但是要作一个优秀的职业C++程序员,makefile还是要懂一些。因为,makefile关系到了整个工程的编译规则,这对于你理解程序、管理项目、查找错误都有一定的帮助。
- Makefile的作用
一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,链接的依赖如何处理,甚至于进行更复杂的功能操作,因为makefile就像一个shell脚本一样,其中也可以执行操作系统的命令。注意: 怎么编译是编译器的事,如何链接是链接器的事,要分工明确,各司其职。
- Makefile的好处
makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。可见,makefile是一种编译依赖管理和工程管理的文件。借助于make工具,轻松实现编译管理。
既然Makefile这么强大离不开make工具,那我们就来了解一下make吧!
什么是make
- make是一个解释makefile中指令的命令工具。
- 大多数的编译器厂商都会提供自己的Make工具,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make
make工具最主要也是最基本的功能就是通过makefile文件描述的源程序之间的相互关系来执行makefile命令以完成编译工作。
既然是一个命令工具,那它的命令格式和执行规则是什么呢?
1、make命令格式
make命令格式:make [-f Makefile] [option] [target]
- -f Makefile:指定makefile文件;若不指定,默认为当前文件夹的makefile或Makefile
- option:见make手册,如-debug等
- target:指定生成目标
举例:make all
2、编译和链接规则
1)如果这个工程没有编译过,那么我们的所有C文件都要编译并被链接。
2)如果这个工程的某几个C文件被修改,那么我们只编译被修改的C文件,并链接目标程序。
3)如果这个工程的头文件被改变了,那么我们需要编译引用了这几个头文件的C文件,并链接目标程序。
3、make的工作方式
make 工作时的执行步骤如下:
- 读入所有的 Makefile。
- 读入被 include 的其它 Makefile。
- 初始化文件中的变量。
- 推导隐晦规则,并分析所有规则。
- 为所有的目标文件创建依赖关系链。
- 根据依赖关系,决定哪些目标要重新生成。
- 执行生成命令。
这里的include,变量、隐晦规则的含义可能我们现在不懂,不着急,慢慢看。
编译器命令(gcc)
makefile既然和编译链接有极大的关系,我们简单了解一下编译器的命令(以gcc为例),具体命令请查看gcc手册或者自己使用的编译器命令。
gcc 的常用参数:
-
-o 指定目标文件
gcc sources/main.c -o bin/main
-
-c 编译的时候只生产目标文件不链接
gcc -c sources/main.c -o obj/main.o
-
-I 主要指定头文件的搜索路径
gcc -I headers -c main.c -o main.o
-
-l 指定静态库
gcc -l pthread
makefile
1、经典结构
(1)需要由make工具创建的目标体(target),通常是目标文件或可执行文件。
(2)要创建的目标体所依赖的文件(dependency_file)。
(3)创建每个目标体时需要运行的命令(command)。
由上格式如下:
target:dependency_files;[command]
command
...
target这个目标文件需要 dependency_files中的文件才能够生成,生成命令为 command 。
例子:
2、伪目标
上面make命令的make all命令里的all目标,很可能就是一个为目标,一个例子如下:
.PHONY: all
all: exe1.o static.a shared.so
这样以来,make all 就会一次性把我们需要的可执行文件,静态库,动态库即所有目标全部构建出来。
常见伪目标:
- all: 这个伪目标是所有目标的目标,其功能一般是编译所有的目标。
- clean: 这个伪目标功能是删除所有被 make 创建的文件。
- install: 这个伪目标功能是安装已编译好的程序,其实就是把目标执行文件拷贝到指定的目标中去。
- print: 这个伪目标的功能是例出改变过的源文件。
- tar: 这个伪目标功能是把源程序打包备份。也就是一个 tar 文件。
- dist: 这个伪目标功能是创建一个压缩文件,一般是把 tar 文件压成 Z 文件。或是 gz 文件。
- TAGS: 这个伪目标功能是更新所有的目标,以备完整地重编译使用。
- check 和 test: 这两个伪目标一般用来测试 makefile 的流程。
3.变量
变量就是存储一些值共下次使用,以简化代码。在Makefile里面如下:
objects = main.o test.o
clean :
rm $(objects)
很简单,我们用=定义一个变量,用$()引用一个变量。
4.隐晦规则
如果一个.o出现在了其他依赖文件中,但是却没有指出.o的以来和生成过程,那么make就会自己隐晦推导,即:把 .o 的目标的依赖文件置成 .c ,并使用 C 的编译命令 cc –c .o .c 来生成.o 的目标,如果没有指出的是a.o,则相当于增加以下语句:
a.o : a.c
cc –c a.c -o a.o
OK,学到这里你就理解了Makefile的工作原理和生成规则,可以应对一般的项目。如果你不手撕大型项目的Makefile,学到这里你就完全够用了!!!(不手撕就是用IDE或者CMake,或者其他构造工具,一般真没必要写Makefile)
但是你想写手撕大型项目的Makefile,你还需要进一步了解makefile,请移步另一篇文章。
如果文章有用,欢迎点赞、打赏、转发。最重要的还是要谢谢大家的支持,我会一如既往地推送深度好文…
![]() | ![]() |