在实际工作中,一个项目可能有很多源文件,比如有200个源文件,那么用gcc/g++编译的时候,我们应该先编译哪一个呢?
而且,这么多源文件需要我们一个个去gcc来编译吗?
而makefifile就定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂的功能操作
makefifile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编
译,极大的提高了软件开发的效率。
makefifile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编
译,极大的提高了软件开发的效率。
make是一个命令工具,是一个解释makefifile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefifile都成为了一种在工程方面的编译方法。
所以,总结一下:
make是一条命令
makefifile是一个文件,两个搭配使用,完成项目自动化构建。
而makefile文件需要我们自己去编写(一般工作中是使用一些自动化构造makefile的工具,比如cmake)
Makefile的主要作用就是为了自动化构建项目,也就是把源代码自动编译形成可执行文件。
(makefile 或 Makefile都可以 )
Makefile中主要由两个部分构成
举个例子:
到月底了,你给你爸打电话要钱:
- 爸,我是你儿子(女儿) - - – --> 依赖关系
- 该给我钱了 -----> 依赖方法
首先创建Makefile文件,用vim打开
touch Makefile
,vim Makefile
mytest:test.c #要生成的mytest依赖test.c
gcc test.c -o mytest ##依赖方法(前面必须有tab缩进)
然后执行make
就是去调用Makefile的依赖方法,此时就会生成可执行文件mytest
注意问题
创建的文件只能是:makefile或者Makefile (不能是其他的名字)
如果出现makefile is up to date
的报错,说明此时目录中存在一个mytest的文件(以上面代码为例)
所以要更改生成的目标可执行程序的名字
项目除了构建,还需要清理
所以还需要构建一个删除的方法
mytest:test.c
gcc test.c -o mytest
.PHONY:clean #表明clean是一个伪目标
clean: #可以不依赖任何文件
rm -f mytest #删除命令
# mytest 和 clean都是一个目标文件
# 但是clean用 关键字.PHONY修饰,表明clean是一个伪目标(假的),即clean不是真实存在的.
# 可以理解成,伪目标主要就是用来执行下面的方法的
注意:在Makefile中,.PHONY后面的target表示的是一个伪造的target, 而不是真实存在的文件target,注意Makefile的target默认是文件。
然后make clean
就可以清理生成的目标文件mytest
这样,就可以利用make
和make clean
代替gcc test.c -o mytest
和 rm -f mytest
所以 make 目标名
就是去调对应的依赖方法
注意点
一个命令只会使用一对依赖关系和依赖方法,比如make
对应一对依赖关系和依赖方法,make clean
对应另一对依赖关系和依赖方法
默认make
是执行第一对依赖关系和依赖方法
除了第一对直接用make
,执行别的方法是make 目标名
就会执行对应的方法
如:clean
就是目标名,所以有make clean
执行clean方法
一般把要生成的可执行程序放在最前面
伪目标的依赖方法总是被执行的
什么意思?
我们知道,如果make生成了一个mytest,然后继续调用make
就会提示错误信息,如图
意思就是,生成的mytest已经是最新了,不需要再创建了
但是,如果执行了make clean
之后,再执行多次,仍是可以执行的,如图
所以,这就叫做:伪目标的依赖方法总是被执行的
意思就是:总是会根据依赖关系,执行依赖方法
所以,如果给我们要生成的可执行文件用.PHONY
修饰,这样要升到文件也是伪目标文件,每一次调用make
都会重新生成新的mytest
习惯:总是给clean设置.PHONY,不给要生成的可执行文件设置.PHONY
但是这里存在一个问题:
如果对文件做修改,就会成功执行make
。但是如果不做修改,就会出现上面的 is up to date的问题
(注意经过配置的vim打开文件即使不做任何修改就退出,会自动保存,也就是对文件进行了修改)
那makefile是如何得知,得到的可执行程序是最新的呢?
---- 根据文件的最近修改时间
[[acm–Linux下文件的三个时间]]
ccess time: 表示最后一次访问文件的时间(仅仅是访问如cat,没有改动)
modify time: 表示最后一次修改文件的时间(修改内容)
change time: 表示最后一次对文件属性改变的改变的时间,包括权限、大小、属性等等
解释:
因为可执行程序一定是再源文件之后生成的,如果可执行程序的最后修改时间比所有源文件都靠后,那么说明可执行程序就是最新的,不需要修改。如果存在某一个源文件的最近修改时间按是在可执行程序的最后修改时间之后,说明可执行程序不是最新的,就可以修改
所以会出现以下情形:
我在vs2019写了一个代码,然后编译不通过
我发现错误,并修改(但是没有保存)
重新编译,结果还是不通过
这是因为编译生成的还是老的那个文件,没保存意味着源文件的最新修改时间没变,所以不会生成最新的可执行程序
创建main.c
,test.c
,test.h
我们知道生成可执行程序之前.h已经被编译器自动包含,最后一步链接其实是把所有的.o文件以及libc.so(动态库)合并链接,然后生成一个可执行文件。所以利用该过程即可实现多个文件编译生成可执行文件
(只需要合并.o文件,标准库编译器会自动链接)
mytest:main.o test.o #文件列表空格隔开不同文件
gcc -o mytest test.o main.o #此时没有.o会自动向下扫描依赖关系并执行依赖方法
test.o:test.c #test.c是test.o的依赖文件
gcc -o test.o -c test.c
main.o:main.c #main.c是main.o的依赖文件
gcc -o main.o -c main.c
#清理
.PHONY:clean
clean:
rm -f *.o mytest # 把所有目标文件和 mytest都清理
上面的代码 其实就相当于VS下Debug模式中 生成解决方案 和 清理解决方案