make和Makefile

在windows上面用VS等工具的时候,编译链接都是一键就成的,在linux下使用gcc编译链接感觉很麻烦,特别是文件多的时候。编译链接的过程,以C/C++为例,源文件(.c/.cpp)和头文件(.h)经过编译器,生成目标文件(.o文件),然后目标文件和库函数文件经过链接器,最后生成可执行文件。(dia画成这样了,左边被覆盖的地方分别是Makefile工程文件和make工具

013957_D5S2_1427523.png

今天学习了陈浩的《跟我一起写Makefile》,感觉很强大。

一、make工具:

make [option] [目标]

在不指定目标文件时,则创建第一目标,即make在当前目录下搜索到的第一个makefile文件。make使用的默认的规则定义文件是:GUNmakefile(不建议使用)、makefile或Makefile。要指定目标文件时使用 -f选项。

202613_N0o0_1427523.png

在默认情况下也就是直接输入make命令的时候

1、make会在当前目录下寻找名字为“Makefile”或“makefile”的文件;

2、如果找到,它会找到第一目标文件(target),举个栗子如example文件,并把这个example文件作为最终的目标文件;

3、如果没有找到example文件或者它的依赖文件(如:example.o)的修改时间比example的新,则执行后面的定义的命令来生成example文件;

4、如果example依赖的.o文件也存在,那么make会在当前目录下寻找目标为.o文件的依赖性,如果找到则再根据哪一个规则生成.o文件,递归的运行下去;

5、在C文件和H文件都是存在的情况下,make生成.o文件,然后再用.o文件完成make的终极任务,也就是可执行文件example。

注:对于所定义的命令错误,或是编译不成功,make不会理会,make只管文件的依赖性。make会一层一层的去找文件的依赖性,直到最终编译出第一个目标文件。如果在搜寻过程中被依赖的文件不存在,则make会直接退出并报错!

二、Makefile

0、Makefile的规则语法

target : Prerequisites
    command
....
....

或是

target : Prerequisites ; command
    command
 ....
 ....

规则包含两部分:一个是依赖关系(Prerequisites),和生成目标的方法(command)。

target是一个目标文件,也就是Makefile要最终生成的文件,Prerequisites是target的依赖文件,command也就是make要执行的命令(任意的shell命令)。依赖文件列白哦中的对象可为文件,也可为另一执行规则的目标。

在makefile文件中规则顺序很重要,因为makefile文件中只应该有一个最终目标,其他目标都是被这个目标所连带进来的。

注:独自一行的命令都要用Tab键开头

例 1:

calculator : main.o add.o subtract.o multiply.o divide.o calculate.o
	cc -o main.o add.o subtract.o multiply.o divide.o calculate.o
main.o : main.c calculate.h
	cc -c main.c
calculate.o : calculate.c add.h subtract.h divide.h multiply.h
	cc -c calculate.c
add.o : add.c
	cc -c add.c
subtract.o : subtract.c
	cc -c subtract.c
divide.o : divide.c
	cc -c divide.c
clean:
	rm calculator *.o

1、Makefile中的变量

这个Makefile 通过make可生成可执行文件calculator(所有.c和.h文件都存在),感觉很方便哦,无论修改了那个文件,要重新生成时只要make一下就好了,而不用每次都gcc -o....都重新编译一遍。但是上面的Makefile有个缺点,当增加新的文件或者删除文件的时候都要修改好几处地方,非常的不方便,而且那么长一行,看得眼都花了。好在makefile是可以使用变量的,用变量来保存所有的文件,使用变量的时候就像shell的一样$(var)。而当要增加或者删除的时候只要修改一处地方就可以了,就像C语言里的宏一样。

make工具支持4种类型的变量:自定义变量、环境变量、预定义变量、自动变量。

1)自定义变量

变量的命名规则与shell中本地变量的一样,使用方法也差不多,变量名=字符串

对利用自定义变量上例进行改进

例 2:

objects = main.o calculate.o add.o subtract.o divide.o multiply.o 
calculator : $(objects) 
	cc -o calculator $(objects)
main.o : main.c calculate.h
	cc -c main.c
calculate.o : calculate.c add.h subtract.h divide.h multiply.h 
	cc -c calculate.c
add.o : add.c
	cc -c add.c
subtract.o : subtract.c
	cc -c subtract.c
divide.o : divide.c
	cc -c divide.c
multiply.o : multiply.c
	cc -c multiply.c
clean:
	rm calculator $(objetcs)

2)环境变量

make在运行过程中,将环境变量转化为同名同值的make变量,用户也可在Makefile中对这些变量进行重新定义(不建议这样做,当make其他的文件的时候有可能出错)

3)预定义变量

GNU make预定义了一些变量,在Makefile文件中可以直接使用。

204750_KOxw_1427523.png

再次改进例子

例 3

objects = main.o calculate.o add.o subtract.o divide.o multiply.o 
calculator : $(objects) 
	$(CC) -o calculator $(objects)
main.o : main.c calculate.h
	$(CC) -c main.c
calculate.o : calculate.c add.h subtract.h divide.h multiply.h 
	$(CC) -c calculate.c
add.o : add.c
	$(CC) -c add.c
subtract.o : subtract.c
	$(CC) -c subtract.c
divide.o : divide.c
	$(CC) -c divide.c
multiply.o : multiply.c
	$(CC) -c multiply.c
clean:
	rm calculator $(objetcs)


4)自动变量

由make工具预先定义,具有特定的含义,它的值与规则中的目标和依赖对象有关。

211802_DJpJ_1427523.png

利用自定义变量改进例3

例 4

objects = main.o calculate.o add.o subtract.o divide.o multiply.o 
calculator : $(objects) 
	$(CC) -o $@ $^             #用$@表示calculator $^表示所有依赖文件
main.o : main.c calculate.h
	$(CC) -c -o $@ $<          #<第一个依赖文件的名称 这里是main.c
calculate.o : calculate.c add.h subtract.h divide.h multiply.h 
	$(CC) -c -o $@ $<
add.o : add.c
	$(CC) -c -o $@ $<
subtract.o : subtract.c
	$(CC) -c -o $@ $<
divide.o : divide.c
	$(CC) -c -o $@ $<
multiply.o : multiply.c
	$(CC) -c -o $@ $<
clean:
	rm calculator $(objetcs)

这样子感觉比例2 还麻烦了,都要加个-o 选项和$@,其实这两个可以去掉的,指示为了练习才加了。

2、Makefile的潜规则

1)隐含规则:自动推导

make强大,它可以自动推导文件及依赖文件后面的命令,我们就没必要去在每一个[.o]文件后都写上类似的命令(cc example.c),因为make 会自动识别,并自己推导命令。所以再次修改上面的例子

 例 5:

objects = main.o calculate.o add.o subtract.o divide.o multiply.o 
calculator : $(objects) 
	$(CC) -o $@ $^             #用$@表示calculator $^表示所有依赖文件
main.o : main.c calculate.h
calculate.o : calculate.c add.h subtract.h divide.h multiply.h 
add.o : add.c
subtract.o : subtract.c
divide.o : divide.c
multiply.o : multiply.c

.PHONY : clean
clean:
	-rm calculator $(objetcs)

看下make的自动推导,好爽

lean@lean-Aspire:~/workspace/hello,world/src$ make
cc    -c -o main.o main.c
cc    -c -o calculate.o calculate.c
cc    -c -o add.o add.c
cc    -c -o subtract.o subtract.c
cc    -c -o divide.o divide.c
cc    -c -o multiply.o multiply.c
cc -o calculator main.o calculate.o add.o subtract.o divide.o multiply.o

上面的.PHONY 表示clean是个伪目标,现在我也不懂伪目标是个什么东西,接着继续往后看吧!

2)后缀规则

后缀规则定义了将具有某后缀的文件(例如.c文件)转换为具有另外一后缀的文件(例如.o文件)的方法。每个后缀规则以两个成对出现的后缀名定义,例如将.c文件转换为.o文件的后缀规则可定义为:

.c.o:
    gcc -c $<


3、清空目标文件的规则

每个Makefile中都应该写一个清空目标文件(可执行文件和.o文件)的规则,这有利于重编译和保持文件的整洁

一般风格是:

clean :
    rm calculator $(objects)

更为稳健的做法是:

.PHONY : clean
clean :
    -rm calculator $(objects)

在rm前加了“-”的意思是,可能某些文件有问题不用理会,继续做后面的事就好。

更加灵活的做法:

.PHONY : cleanall
cleanall : cleanprogram cleanobj
cleanprogram :
    -rm procgram
cleanobj :
    -rm obj

想要清除不同文件的时候只需

make cleanall  #清除所有文件
make cleanobj  #清除目标文件
...

4、文件指示

①文件包含:在一个Makefile中包含另一个Makefile,就像C语言里面的#include一样

②文件的有效性:根据某些情况指示文件是否有效,就像C语言里的预编译#if

③定义多行命令:

。。。

后面的用到了再补充



转载于:https://my.oschina.net/u/1427523/blog/415710

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值