Makefile在Linux环境下非常有用,它规定了整个工程的编译规则,即哪些文件先编译、哪些文件后编译、相互之间依赖关系是什么,是编写大型工程必不可少的工具。 而了解了Makefile的规则,你会发现其实它能做的不仅仅是C/C++的编译,它更是提供了一个强大的批处理工具。 下面的叙述以GNU的make为主。
由于网上给出makefile的教程都比较冗长,可能看完自己都不会写。 而本文主要以我自己的实操体验为主,想到什么就补充什么。
make的语法规则如下,注意每个recipe前面都需要有tab键。 意思是,要完成target,需要先完成prerequisites;如果prerequisites都满足,则执行recipe指令(对由于这里是一系列指令,所以只要是Linux的指令,什么都可以,因而makefile不仅仅可以用来做编译,用来做其他批处理也是可以的)。
target ... : prerequisites ...
recipe
...
...
每次执行make,程序都会自动检测prerequisites中的内容有无变化(即文件是否比原来的新),如果有则重新执行prerequisites中的目标;否则就直接跳过。
常见的C编译命令写成makefile见下,代表的是要生成test
文件,首先要有test.c
文件,然后通过gcc test.c -o test
指令就能生成。
test : test.c
gcc test.c -o test
但上面的方法显然太过麻烦了,当文件一多起来就manage不住了。 因而可以通过以下方式进行编写,使得makefile更加易写。
首先是声明变量,如
CC = gcc
FLAGS = -O3
下文要用到时就可以直接用$(CC)
、$(FLAGS)
等等调用了。
然后是自动变量(automatic variables),以下面的语句为例
all: library.cpp main.cpp
$@
代表目标文件,上例中$@
等价于all
$^
代表所有的依赖文件,上例中$^
等价于library.cpp main.cpp
$<
代表第一个依赖文件,上例中$<
等价于library.cpp
自动变量结合通配符%
就能写出下面的这种指令了
% : %.c
$(CC) $(FLAGS) $< -o $@
代表的是文件夹中要通过某一.c
文件(这里不妨设它就是X.c
了)生成对应的执行文件X
,需要取出第一个依赖文件($<
),即X.c
,通过编译指令gcc -O3
生成对应的目标文件($@
),即X
(%
)。
这里要注意通配符%
与*
的区别,后者代表任意文件,在删除文件时常用。
.PHONY
为伪目标文件,-
代表执行时出了问题也不要管
.PHONY : clean
clean :
-rm edit $(objects)
上面已经将makefile的基本操作讲完了,已经差不多能满足日常需求,至于其他进阶操作则以后再补充。
下面是计网套接字编程生成服务器端和客户端的makefile文件,原文件夹中含有server.c
和client.c
文件。
CC = gcc
FLAGS = -pthread
ALL = server client
all: $(ALL)
% : %.c
$(CC) $(FLAGS) $< -o $@
.PHONY : clean
clean :
-rm -f *.o $(ALL)
执行流程都是从上往下,要完成all
目标,需要先完成server
和client
两个子目标。
这两个子目标都包含在% : %.c
中,因而可以直接执行。
#
用来注释/
换行,prerequisites不能换行,但可以通过下面添加变量的方法解决过长问题LONGPRE := pre1
LONGPRE += pre2 pre3
all : $(LONGPRE)