Linux的项目管理器Make类似于Windows中VC里的“工程”,它是个"自动编译管理器",能根据文件的时间戳自动发现更新过的文件而减少编译量。通过读入Makefile文件的内容来执行大量的编译工作,用户只需编写一次简单的编译语句就可以了。它提高了实际项目的工作效率,几乎所有Linux下的项目编程都会用到它。
在如何写Makefile之前,我们首先看下Make工作时的流程:
1)读入所有的Makefile文件;
2)如果该Makefile文件通过include包含其他Makefile文件,则读入被包含的Makefile文件;
3)初始化文件中的变量;
4)推到隐晦规则,并分析所有规则;
5)为所有目标文件创建依赖关系链;
6)根据依赖关系,决定哪些目标要重新生成;
7)执行生成命令。
如果定义的变量被使用了,Make采用拖延战术,若变量出现在依赖关系的额规则中,仅当这条依赖被决定要使用时,变量才会在内部展开。
Makefile文件的编写
Makefile 中的第一个目标会被作为其默认目标。
目标、依赖、命令的书写格式为
targets:prerequisites
TAB command
#这种方式居多,command前用tab键对齐
或
targets:prerequisites ; command
command
没有依赖文件的目标称为“伪目标”。它只是一个标签不是一个文件。make无法生成它的依赖关系和决定它是否要执行。所以我们只能显式的指明这个“目标”才能让其生效——即通过make+ 伪目标名显示的调用让它得到执行。
为避免伪目标和文件重名的情况,可以用".PHONY"这个特殊的标记指明一个伪目标。不管有无这个文件,这个目标都是伪目标。
.PHONY:clean
clean:
rm -f *.o
//无论clean文件是否存在,clean就是一个伪目标
当然"伪目标"也可以有依赖文件,伪目标同样可以作为“默认目标”,只要将其放在第一个。一个示例就是,如果你的 Makefile 需要一口气生成若干个可执行文件,但你只想简单地敲一个 make 完事,并且,所有的目标文件都写在一个 Makefile 中,那么你可以使用“伪目标”这个特性:
all : prog1 prog2 prog3
.PHONY : all
prog1 : prog1.o
cc -o prog1 prog1.o
prog2 : prog2.o
cc -o prog2 prog2.o
prog3 : prog3.o
cc -o prog3 prog3.o
现在我以数据结构C语言实现——顺序线性表SqList这篇博文中的源文件为例,先给出它的Makefiel文件。四个源文件declaration.h、function.h、function.c、main.c
main:main.o function.o
gcc -o main main.o function.o
main.o:main.c function.h declaration.h
gcc -c main.c
function.o:function.c function.h declaration.h
gcc -c function.c
.PHONY:clean
clean:
rm *.o
这是一个很常规的写法,我们再来将他进一步优化。
使用变量
Makefile中的变量分为用户自定义变量、预定义变量、自动变量及环境变量。预定义变量及自动变量部分都默认值但也可修改。Makefile中常见的预定义变量如下:
CC——C编译器的名称,默认为cc
CPP——C编译器的名称,默认为$(CC) -E
CXX——C++编译器的名称,默认为g++
RM——文件删除程序的名称,默认为rm -f
CFLAGS——C编译器的选项无默认值
//变量在声明的时候要赋初值。使用时变量名前加"$",最后用"()"或"{}"将变量名括起来,"$$"表示真实的"$"符号。
//若规则命令中有SHELL变量,引用使用Shell的“$temp”格式
使用自动引导
让Makefile自动推导,只要看到.o文件,它就会自动的把对应的.c文件加到依赖文件中,并且gcc -c *.c也会被推导出来。简化如下
CC=gcc
OBJ=main.o function.o
RM=rm -f
make:$(OBJ)
$(CC) -o main $(OBJ)
main.o:declaration.h function.h
function.o:function.h declaration.h
.PHONY:clean
clean:
$(RM) $(OBJ)
使用自动变量
<span style="color:#333333;">$@:目标文件 $^:所有的依赖文件 $<:第一个依赖文件</span>
使用默认缺省规则
..c.o:
gcc -c $<
这个规则表示所有的.o文件都是依赖于相应的.c文件
使用函数CC=gcc
RM=rm -f
CFLAGS=-Wall -c
SRCS=$(wildcard *.c)
OBJS=$(patsubst %c,%o,$(SRCS))
TARGET=main
.PHONY:all clean
all:$(TARGET)
$(TARGET):$(OBJS)
$(CC) -o $@ $^
%.o:%.c
$(CC) $(CFLAGS) -o $@ $<
clean:
$(RM) *.o $(TARGET)
wildcard和patsubst函数的作用分别是扩展通配符和替换通配符,SRCS=$(wildcrad *.c)等于指定编译当前目录下所有.c文件。$(patsubst %.c,%.o ,$(SRCS))把$(SRCS)中的变量后缀是.c全部其换成.o
指定Makefile文件
GNU make 找寻默认的 Makefile 的规则是在当前目录下依次找三个文件——“GNUmakefile”、“makefile”和“Makefile”。其按顺序找这三个文件,一旦找到,就开始读取这个文件并执行。
我们也可以自己定义Makefile文件的名字,假如有Makefile文件名为mfile,可按一下方式执行
make -f mfile/make --file mfile