在windows下,对多个文件进行编译链接,只需要IDE的按钮轻轻一点就可以。而在Linux并没有这种一键直达的按钮,这时我们就需要makefile来帮助我们。makefile能帮我们一次对多个文件进行编译。
make是一个命令工具,是一个解释makefile中指令的命令工具。且make命令会自动智能地根据当前的文件修改的情况来确定哪些文件需要重编译,从而自己编译所需要的文件和链接目标程序。
makefile规则:
target ... : prerequisites ...
command
...
...
target就是一个目标文件,可以是Object File,也可以是执行文件,还可以是一个标签(Label)。
prerequisites是要生成那个target所需要的文件或是目标。
command也就是make需要执行的命令。(要以tab进行文本缩进)
这是一个文件的依赖关系,也就是说,target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。说白一点就是说,prerequisites中如果有一个以上的文件更新了的话,make的时候command所定义的命令就会被执行。这就是Makefile的规则。也就是Makefile中最核心的内容。
注意:如果只有prerequisites的文件被更新了,make时command才会执行。如果是其他文件或prerequisites文件中#include的文件更新了,当进行make时,command是不会执行的。
我们可以把上述内容保存在文件为“Makefile”或“makefile”的文件中,然后在该目录下直接输入命令“make”就可以生成执行文件。如果要删除执行文件和所有的中间目标文件,那么,只要简单地执行一下"make clean"就可以了。但是如果makefile文件中并没有写clean的工作,那么make clean什么都不会干。因此我们需要在makefile文件中添加clean的工作
clean:
rm -f 文件名
比如,我有五个文件。
Func1.h,Func2.h,Func1.c,Func2.c,main.c
makefile文件如下
(1)常规方式
main:main.o Func1.o Func2.o
gcc -o main main.o Func1.o Func2.o
main.o:main.c Func1.h Func2.h
gcc -c main.c
Func1.o:Func1.h Func1.c
gcc -c Func1.c
Func2.o:Func2.h Func2.c
gcc -c Func2.c
clean:
rm -f *.o main
gcc -o output_filename file.c,确定输出文件的名称为output_filename,同时这个名称不能和源文件同名。如果不给出这个选项,gcc就给出预设的可执行文件a.out。
gcc -c 只编译生成.o文件,不链接
在makefile文件所在目录使用make指令,就生成了main文件。./main执行程序。
(2)使用自定义目标变量进行简化
OBJ=main.o Func1.o Func2.o
GCC=gcc
main:$(OBJ)
$(GCC) -o main $(OBJ)
main.o: main.c Func1.h Func2.h
$(GCC) -c main.c
Func1.o:Func1.h Func1.c
$(GCC) -c Func1.c
Func2.o:Func2.h Func2.c
$(GCC) -c Func2.c
clean:
rm -f $(OBJ) main
$(OBJ)表示引用OBJ变量
(3)make自动推导进行简化
OBJ=main.o Func1.o Func2.o
make:$(OBJ)
gcc -o main $(OBJ)
main.o: Func1.c Func2.c
Func1.o:Func1.c
Func2.o:Func2.c
clean:
rm -f $(OBJ) main
(4)使用自动变量进行简化
OBJ=main.o Func1.o Func2.o
main:$(OBJ)
gcc -o $@ $(OBJ)
main.o: main.c
gcc -c $<
Func1.o:Func1.c
gcc -c $<
Func2.o:Func2.c
gcc -c $<
clean:
rm -f $(OBJ) main
使用自动变量(依赖文件是指:prerequisites所在位置的文件,目标文件是指target所在位置的名称)
命令格式 含 义
$* 不包含扩展名的目标文件名称
$+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含 重复的依赖文件
$< 第一个依赖文件的名称
$? 所有时间戳比目标文件晚的依赖文件,并以空格分开
$@ 目标文件的完整名称
$^ 所有不重复的依赖文件,以空格分开
$% 如果目标是归档成员,则该变量表示目标的归档成员名称
make时出现"xxx is up to date"
这表示makefile的target和当前目录下的某个目录名字冲突了。
通常是因为make执行后没有执行make clean。造成再次生成target文件。
因此需要执行一次make clean,或者在makefile开始使用.PHONY(伪目标)。
.PHONY:all
all:target
.PHONY个人见解
.PHONY伪目标,告诉make目标没有实体,要生成all这个实体就生成它的依赖文件。all依赖client和server,所以会生成这两个可执行文件。
当我们用makefile生成两个或多个可执行程序时更要用.PHONY。因为makefile从头找终极目标,然后找它的依赖文件。
下面代码中,不写.PHONY则只会生成server,不会生成client,因为makefile认为已经生成目标server了。不会向下执行了。
注意,如果不写.PHONY的话,请保证文件中没有自己定义的目标名(下例中的all和clean)。因为如果有的话会认为all或clean已经是最新的了,不会执行makefile文件中的make all和clean的。
OBJ=server client
all:client server
.PHONY:all
server:server.c
gcc -o $@ $^ -lpthread
client:client.c
gcc -o $@ $^
.PHONY:clean
clean:
rm -f $(OBJ)