- 1. Make简介
- 2. Makefile基本结构
- 3. 创建和使用变量
- 4. Make使用
- 5. Makefile的VPATH
- 6. Makefile综合实战
- 工程管理器,顾名思义,是指管理较多的文件
- Make工程管理器也就是个“自动编译管理器”,这里的“自动”是指他能根据文件时间戳自动发现更新过的文件而减少编译工作量,同时,他通过读入Makefile文件的内容来执行大量的编译工作
- Make将只编译改动的代码,而不是完全编译
- Makefile是Make读入的唯一配置文件
- 由make工具创建的目标体(target),通常是目标文件或可执行文件
- 要创建的目标体所依赖的文件(dependency_file)
- 创建每个目标体时需要运行的命令(command)
- 注意:命令行前面必须是一个TAB键,否则编译错误
- 用法:新建一个Makefile文档,完成后在终端make一下就编译好了
target: dependency_files command
- 例1:
hello.o: hello.c hello.h gcc -c hello.c -o hello.o
- 例2:
test: f1.o f2.o main.o gcc f1.o f2.o main.o -o test f1.o: f1.c gcc -c f1.c -o f1.o f2.o: f2.c gcc -c f2.o -o f2.o main.o: main.c -o main.o gcc -c main.c -o main.o
- 如果想要删除生成相关的*.o文件可以用clear,见下面这个例子,在终端输入make clear就好了
test: f1.o f2.o main.o gcc f1.o f2.o main.o -o test f1.o: f1.c gcc -c f1.c -o f1.o f2.o: f2.c gcc -c f2.o -o f2.o main.o: main.c -o main.o gcc -c main.c -o main.o PHONY: clean rm *.o test3. 创建和使用变量
-
定义变量的两种方式
- :=:直接赋值,常规赋值方式,一赋值马上有效。在没赋值是为空字符。
- ?=:仅仅在变量还没赋值的情况下才有效,所有一般用在第一次赋值
- +=:在变量后加上字符
- VAR=var:递归展开方式,赋值后并不马上生效,等到使用时才真正的赋值,此时通过递归找出当前的值,所有在使用是很有可并不是开始赋的值
-
使用变量:$(VAR),如果要用$符号则需要$$来表示
-
举例
OBJS = kang.o yul.o CC = gcc CFLAGS = -Wall -O -g sunq: $(OBJS) $(CC) $(OBJS) -o sunq kang.o: kang.c kang.h $(CC) $(CFLAGS) -c kang.c -o kang.o yul.o: yul.c yul.h $(CC) $(CFLAGS) -c yul.c -o yul.o
- 注意:不能CFLAGS = $(CFLAGS) -O进行扩展,会造成死循环
- 预定义变量
| 预定义变量 | 解释 |
|---|---|
| AR | 库文件维护程序的名称,默认值为ar |
| AS | 汇编程序的名称,默认值为as |
| CC | C编译器的名称,默认值为cc |
| CPP | C预编译器的名称,默认值为$(CC) -E |
| CXX | C++编译器的名称,默认值为g++ |
| FC | FORTRAN编译器的名称,默认值为f77 |
| RM | 文件删除程序的名称,默认值为rm -f |
| ARFLAGS | 库文件维护程序的选项,无默认值 |
| ASFLAGS | 汇编程序的选项,无默认值 |
| CFLAGS | C编译器的选项,无默认值 |
| CPPFLAGS | C预编译的选项,无默认值 |
| CXXFLAGS | C++编译器的选项,无默认值 |
| FFLAGS | FORTRAN编译器的选项,无默认值 |
- 举例
Hello: main.c main.h $(CC) -o hello main.c clean $(RM) hello
- 自动变量
| 自动变量 | 解释 | 举例 test: f1.o f2.o main.o |
|---|---|---|
| $* | 不包括扩展名的目标文件名称 | hello.c->hello.o,我们可以用$*.o |
| $+ | 所有的依赖文件,以空格分开,并以出现的先后为序,可能包含重复的依赖文件 | |
| $< | 第一个依赖文件的名称 | f1.0 |
| $? | 所有时间戳比目标文件晚的依赖文件,并以空格分开 | |
| $@ | 目标文件的完整名称 | test |
| $^ | 所有不重复的目标依赖文件,以空格分开 | f1.o f2.o main.o |
| $% | 如果目标是归档成员,则该变量表示目标归档成员名称 |
- 举例
OBJS = f1.o f2.o OBJS += main.o CC = gcc CFLAGS = -Wall -O -g test: $(OBJS) gcc $(CFLAGS) $(OBJS) -o $@ f1.o: f1.c gcc -c $^ -o $@ f2.o: f2.c gcc -c $< -o $@ main.o: main.c gcc -c main.c -o main.o .PHONY: clean clean: $(RM) *.o test
- 环境变量
- make在启动时会自动读取系统当前已经定义了的环境变量,并且会创建与之具有相同名称和数值的变量
- 如果用户在Makefile中定义了相同名称的变量,那么用户自定义变量会覆盖同名的环境变量
- 用法:make [option] [param]
- 选项
| 选项 | 解释 |
|---|---|
| -C dir | 读入指定目录下的Makefile |
| -f file | 读入当前目录下的file文件作为Makefile |
| -i | 忽略所有的命令执行错误 |
| -l dir | 指定被包含的Makefile所在目录 |
| -n | 只打印要执行的命令,但不执行这些命令 |
| -p | 显示make变量数据库和隐含规则 |
| -s | 在执行命令时不显示命令 |
| -w | 如果make在执行过程中改变目录,打印当前目录名 |
- 隐含规则1:
.o的目标的依赖目标会自动推导为 .c,并且其生成命令是$(CC) -c $(CPPFLAGS) $(CFLAGS),下面的代码运用了隐含规则,因此也可以正常执行
OBJS = f1.o f2.o OBJS += main.o CC = gcc CFLAGS = -Wall -O -g test: $(OBJS) gcc $(CFLAGS) $(OBJS) -o $@ f1.o: f1.c f2.o: f2.c main.o: main.c .PHONY: clean clean: $(RM) *.o test
- 隐含规则2:链接Object文件的隐含规则 ,通过运行C的编译器来运行链接程序生成(一般是ld),其生成命令是:$(CC) $(LDFLAGS)
.o $(LOADLIBES) $(LDLIBS),这个规则对一个或多个Object文件都生效。
用法: 文件*: 文件1.o 文件2.o 文件3.o ...,需要注意生成文件名必须是文件1、文件2或文件3中的一个
举例:最终我们的Makefile可以简化成下面的代码
f1: f1.o f2.o main.o .PHONY: clean clean: $(RM) *.o main5. Makefile的VPATH
- 通常在项目中会把文件放在不同的目录下进行分类。我们可以告诉make我们文件的路径,让make自己找
- VPATH完成了这个功能,如果没有指明这个变量,make只会在当前目录下找,如果定义里VPATH,make会在当前目录找不到的情况下,到指定目录下寻找。
- 用法:VPATH = 路径1: 路径2: ...
- 举例:VPATH = src: ../headers,make会按照这个顺序进行搜索
- 举例:
首先,先介绍下我们现在文件的位置├── makefile │ ├── include │ │ └── head.h │ ├── main │ │ └── main.c │ ├── Makefile │ ├── src1 │ │ └── f1.c │ └── src2 │ └── f2.c
如果不用VPATH,我们的Makefile如下所示CC = gcc CFLAGS = -Wall -I include f1: src1/f1.o src2/f2.o main/main.o $(CC) $(CFLAGS) $^ -o $@ .PHONY: clean clean: find ./ -name "*.o" -exec rm {} ;;rm f1如果用VPATH,我们的代码如下所示CC = gcc CFLAGS = -Wall -I include VPATH = src1:src2:main f1: f1.o f2.o main.o $(CC) $(CFLAGS) $^ -o $@ .PHONY: clean clean: find ./ -name "*.o" -exec rm {} ;;rm f1
- 文件结构如下图所示
- ./f1目录下的Makefile代码如下所示
../$(OBJS_DIR)/f1.o: f1.c $(CC) -c $^ -o $@
- ./f2目录下的Makefile代码如下所示
../$(OBJS_DIR)/f2.o: f2.c $(CC) -c $^ -o $@
- ./main目录下的Makefile代码如下所示
../$(OBJS_DIR)/main.o: main.c $(CC) -c $^ -o $@
- 主目录下的Makefile
CC = gcc SUBDIRS = f1 f2 main obj OBJS = f1.o f2.o main.o BIN = myapp OBJS_DIR = obj BIN_DIR = bin export CC OBJS BIN OBJS_DIR BIN_DIR #把变量传给子目录makefile all: CHECK_DIR $(SUBDIRS) CHECK_DIR: mkdir -p $(BIN_DIR) #生成一个bin目录 $(SUBDIRS): ECHO #ECHO是打印 make -C $@ ECHO: @echo $(SUBDIRS) #加@是打印不提示 @echo begin compile clean: @$(RM) $(OBJS_DIR)/*.o @rm -rf $(BIN_DIR)



