必须掌握的最基础的makefile知识
在linux下编写C++,会常使用到makefile进行编译,因为在生产环境中有大量的需要编译的文件,如果在终端里直接输入编译命令
gcc filename1.c filename2.c ... -L lib -l test Include ./include -O 3 ... -o app
有可能会因为参数过多,或需编译的文件过多、文件名过长而导致出错,所以都会使用makefile进行编译,虽然在真正的生产环境中,makefile会由一个高工进行编写,我们只需完成自己的一部分模块,但编写简单的makefile也是必备的基础能力。
注:makefile的两种命名,第一种即makefile,第二种为Makefile。
makefile的工作原理
在makefile里编写的语句可总结为
生成目标:依赖条件
(Tab键) 执行命令
即,最终是为了得到“生成目标”,而得到“生成目标”是需要依赖一些东西的,即“依赖条件”,一般是通过“执行命令”对“依赖条件”进行相关操作,然后得到“生成目标”。
其工作原理可总结如下图:
以一个 将1.c、2.c、3.c、4.c这四个文件编译成可执行文件app的makefile编写为例
makefile1:
app:1.c 2.c 3.c 4.c
gcc 1.c 2.c 3.c 4.c -o app
如果其中一个.c文件被更改,使用makefile1会将所以.c文件全部编译一次,效率低下,应该利用其更新的工作原理只编译修改了的那个.c文件,原理如下图,将makefile1改写。
makefile2:
app:1.o 2.o 3.o 4.o
gcc 1.o 2.o 3.o 4.o -o app
1.o:1.c
gcc -c 1.c
2.o:2.c
gcc -c 2.c
3.o:3.c
gcc -c 3.c
4.o:4.c
gcc -c 4.c
可使用自定义变量进行makefile的改进
注:在makefile里定义变量时是不需要标明类型的。
makefile3:
obj=1.o 2.o 3.o 4.o
target=app
#大写的变量为makefile中自己维护的变量
CC = gcc
CPPFLAGS = -I
$(target):$(obj) #$符号用于取变量的值
$(CC) $(obj) -o $(target)
#这里的%是模式匹配,当上面的依赖条件中缺乏.o文件时,便会向下寻找
#比如缺少1.o 便会调用下面的语句,将1传给%
#$< 表示传入的依赖条件,即%.c的值,如1.c
#$@ 表示生成的目标,即%.o,如1.o
%.o:%.c
$(CC) -c $< -o $@
可以通过函数使makefile更简单,前提是需要知道一些函数,可自行查找,此处使用两个函数:
wildcard:在指定目下寻找指定文件,此处用来寻找当前目录下所有的.c文件;
patsubst:匹配替换函数,将一类文件替换为另一类文件,此处用来将.c文件替换成.o文件,而用来替换的.c文件名可从src得到。
再给其加上clean,即,将生成可执行文件的过程中产生的文件进行删除。
makefile4:
tartet=app
src=$(wildcard ./*.c)
obj=$(patsubst ./%.c, ./%.o, $(src))
CC = gcc
CPPFLAGS = -I
$(target):$(obj)
$(CC) $(obj) -o $(target)
%.o:%.c
$(CC) -c $< -o $@
.PHONY:clean
clean:
-rm $(obj) $(target) -f
hello:
echo "hello"
这里编写的clean,可以在外部通过 make clean命令执行,同理如果使用make hello命令,则会执行hello下的命令,从而显示出“hello”字符串。
“.PHONY:clean”参数是为了防止,当前目录下有一个名为“clean”的文件,导致系统在执行“make clean”命令时出错。
"-rm"是为了当命令rm执行出错时忽略它,并继续执行接下来的命令,可防止因为出错而不执行后续的命令。
“-f”是为了忽略错误,强制执行,在此处即忽略是否有文件可以删除,都将执行该命令。
学习了一下简单的makefile编写,只能说有个大致的入门了解,如果只是自己编写使用,编写成makefile2这个版本即可。