现在,我们对上面的makefile进行逐步改进,改进过程如下:

改进一:使用变量

OBJ=//TAB键隔开ain.o mytool1.o mytool2.o
 
make
(OBJ) 
//TAB键隔开gcc -o main $(OBJ)
 
main.o:main.c mytool1.h mytool2.h
 
//TAB键隔开gcc -c main.c
 
mytool1.o:mytool1.c mytool1.h
 
//TAB键隔开gcc -c mytool1.c
 
mytool2.o:mytool2.c mytool2.h
 
//TAB键隔开gcc -c mytool2.c
 
clean:
 
rm -f main $(OBJ)

Makefile中的变量分为用户自定义变量、预定义变量、自动变量及环境变量。如上例中的OBJ就是用户自定义变量,自定义变量的值由用户自行设定,而预定义变量和自动变量为通常在Makefile都会出现的变量,其中部分有默认值,也就是常见的设定值,当然用户可以对其进行修改。

在Makefile中的定义的变量,就像是C/C++语言中的宏一样,他代表了一个文本字串,在Makefile中执行的时候其会自动原模原样地展开在所使用的地方。其与C/C++所不同的是,你可以在Makefile中改变其值。在Makefile中,变量可以使用在“目标”、“依赖目标”、“命令”或是Makefile的其它部分中。

预定义变量包含了常见编译器、汇编器的名称及其编译选项。Makefile中常见预定义变量及其部分默认值如表 3‑12所示。

01.jpg (78.46 KB, 下载次数: 0)

下载附件 保存到相册 设为封面

前天 09:37

变量在声明时需要给予初值,而在使用时,需要给在变量名前加上“$”符号,但最好用小括号“()”或是大括号“{}”把变量给包括起来。如果你要使用真实的“$”字符,那么你需要用“$$”来表示。

在定义变量的值时,在Makefile中有两种方式来定义变量的值。

先看第一种方式,也就是简单的使用“=”号,在“=”左侧是变量,右侧是变量的值,右侧变量的值可以定义在文件的任何一处,也就是说,右侧中的变量不一定非要是已定义好的值,其也可以使用后面定义的值。我们可以使用make中的另一种用变量来定义变量的方法。这种方法使用的是“:=”操作符。

一般在书写Makefile时,各部分变量引用的格式如下:

1.make变量(Makefile中定义的或者是make的环境变量)的引用使用“$(VAR)”格式,无论“VAR”是单字符变量名还是多字符变量名。

2.出现在规则命令行中shell变量(一般为执行命令过程中的临时变量,它不属于Makefile变量,而是一个shell变量)引用使用shell的“$tmp”格式。

3.对出现在命令行中的make变量同样使用“$(CMDVAR)”格式来引用。

改进二:使用自动推导

CC = gcc
 
OBJ = main.o mytool1.o mytool2.o
 
make: $(OBJ)
 
$(CC) -o main $(OBJ)
 
main.o: mytool1.h mytool2.h
 
mytool1.o: mytool1.h
 
mytool2.o: mytool2.h
 
.PHONY: clean
 
clean:
 
rm -f main $(OBJ)

让make自动推导,只要make看到一个.o文件,它就会自动的把对应的.c文件加到依赖文件中,并且gcc -c *.c也会被推导出来,所以Makefile就简化了。

改进三:自动变量($^ $< $@)的应用

CC = gcc
 
OBJ = main.o mytool1.o mytool2.o
 
main: $(OBJ)
 
$(CC) -o $@ $^
 
main.o: main.c mytool1.h mytool2.h
 
$(CC) -c $<
 
mytool1.o: mytool1.c mytool1.h
 
$(CC) -c $<
 
mytool2.o: mytool2.c mytool2.h
 
$(CC) -c $<
 
.PHONY: clean
 
clean:
 
rm -f main $(OBJ)

命令中的“$<”和“$@”是自动化变量,“$^”表示所有的依赖目标集,“$@”表示目标集。“$^”表示依赖文件列表中的第一个依赖文件

改进四:使用函数

CC = gcc
 
CFLAGS = -Wall -c
 
LDFLAGS = -lpthread
 
SRCS = $(wildcard *.c)
 
OBJS = $(patsubst %c,%o,$(SRCS))
 
TARGET = main
 
.PHONY: all clean //“.PHONY”表示,all 和clean 是个伪目标文件。
 
all: $(TARGET)
 
$(TARGET): $(OBJS)
 
$(CC) $(LDFLAGS) -o $@ $^
 
%.o: %.c
 
$(CC) $(CFLAGS) -o $@ $<
 
clean:
 
@rm -f *.o $(TARGET)

在这个Makefile中使用wildcard 和patsubst函数来处理变量,从而让我们的命令或是规则更为的灵活和具有智能。make所支持的函数也不算很多,不过已经足够我们的操作了。函数调用后,函数的返回值可以当做变量来使用。wildcard 和patsubst函数的作用分别是扩展通配符和替换通配符。SRCS = $(wildcard *.c)等于指定编译当前目录下所有.c文件。在$(patsubst %.c,%.o,$(SRCS) )中,patsubst把$(SRCS)中的变量符合后缀是.c的全部替换成.o。

通过上面的例子我们得到如下总结:

makefile文件保存了编译器和连接器的参数选项,还表述了所有源文件之间的关系(源代码文件需要的特定的包含文件,可执行文件要求包含的目标文件模块及库等)。创建程序(make程序)首先读取makefile文件,然后再激活编译器、汇编器、资源编译器和连接器以便产生最后的输出,最后输出并生成的通常是可执行文件。创建程序利用内置的推理规则来激活编译器,以便通过对特定cpp文件的编译来产生特定的obj文件。