Make简介
工程管理器,顾名思义,是指管理较多的文件
Make工程管理器也就是个“”自动编译管理器”,这里的“自动”是指它能够根据文件时间戳自动发现更新过的文件而减少编译的工作量,同事,它通过读入Makefile文件的内容来执行大量的编译工作
Make将只编译改动的代码文件,而不用完全编译
Makefile基本结构
Makefile是Make读入的唯一配置文件
- 由make工具创建的目标体(target),通常是目标文件或可执行文件
- 要创建的目标体所依赖文件(dependency_file)
- 要创建每个目标体时需要运行的命令(command)
注意:命令行前面必须是一个“TAB”键,否则编译错误为:***missing separator.Stop
Makefile格式
target : dependency_files
<TAB> command
hello.o : hello.c hello.h
gcc -c hello.c -o hello.o
例子
hello.c
#include <stdio.h>
void func(void)
{
printf("hello\n");
}
hello.h
void func(void);
main.c
#include <stdio.h>
#include "hello.h"
int main(int argc, char **argv)
{
func();
return 0;
}
Makefile
test:hello.o main.o
gcc hello.o main.o -o test
hello.o:hello.c
gcc -c hello.c -o hello.o
main.o:main.c
gcc -c main.c -o main.o
.PHONY:clean
clean:
rm *.o test
创建和使用变量
创建变量的目的:用来代替一个字符文本字符串:
- 系列文件的名字
- 传递给编译器的参数
- 需要运行的程序
- 需要查找源代码的目录
- 你需要输出信息的目录
- 你想要做的其它事情
变量定义的两种方式
- 递归展开的方式VAR=var
- 简单方式 VAR:=var
变量使用$(VAR)
用“ ”和“ ” 和 “ ”和“$”来表示
类似于编程语言中的宏
eg:
OBJS = kang.o yul.o
CC = gcc
CFLAGS = -Wall -O -g
sunq: $(OBJS)
$(CC) $(OBJS) -o sunq.o
kang.o: kang.c kang.h
$(CC) $(CFLAGS) -c kang.c -o hang.o
yul.o: yul.c yul.h
$(CC) $(CFLAGS) -c yul.c -o yul.o
将上面的例子修改后:
OBJS = hello.o main.o
CC = gcc
CFLAGS = -Wall -O -g
test:$(OBJS)
$(CC) $(OBJS) -o test
hello.o:hello.c
$(CC) $(CFLAGS) -c hello.c -o hello.o
main.o:main.c
$(CC) $(CFLAGS) -c main.c -o main.o
.PHONY:clean
clean:
rm *.o test
简单方式 VAR: =var
m:=mm
x:=$(m)
y:=$(x)bar
x:=late
echo $(x) $(y)
用?=定义变量
dir:=/foo/bar
FOO?=bar
含义是,如果FOO没有被定义过,那么变量FOO的值就是"bar",如果FOO先前被定义过,那么这条语句将什么也不做,其等价于:
ifeq ($(origin FOO),undefined)
FOO = bar
endif
为变量添加值
你可以通过+=为已定义的变量添加新的值
Main=hello.o hello-1.o
Main+=hello-2.o
预定义变量
- AR:库文件维护程序的名称,默认值为ar。AS汇编程序的名称,默认值为as
- CC:C编译器的名称,默认为cc。CPP C预编译期的名称,默认值为$(CC) -E。
- CXX: C++编译器的名称,默认值为g++。
- FC:FORTRAN编译器的名称,默认值为f77
- RM:文件删除程序的名称,默认值为 rm -r
eg:
Hello: main.c main.h
$(CC) -o hello main.c
clean:
$(RM) hello
自动变量
- $* 不包含扩展名的目标文件名称
- $+ 所有的依赖文件,以空格分开,并以出现的先后为序,可能 包含重复的依赖文件
- $< 第一个依赖文件的名称
- $? 所有时间戳比目标文件晚的的依赖文件,并以空格分开
- $@ 目标文件的完整名称
- $^ 所有不重复的目标依赖文件,以空格分开
- $% 如果目标是归档成员,则该变量表示目标的归档成员名称
修改后例子:
OBJS = hello.o main.o
CC = gcc
CFLAGS = -Wall -O -g
test: $(OBJS)
$(CC) $(OBJS) -o $@
hello.o: hello.c
$(CC) $(CFLAGS) -c $< -o hello.o
main.o: main.c
$(CC) $(CFLAGS) -c $^ -o main.o
.PHONY: clean
clean:
rm *.o test
Make使用
直接运行make
选项
- -C dir读入指定目录下的Makefile
- -f file读入当前目录下的file文件作为Makefile
- -i忽略所有的命令执行错误
- -I dir指定被包含的Makefile所在目录
- -n只打印要执行的命令,但不执行这些命令
- -p显示make变量数据库和隐含规则
- -s在执行命令时不显示命令
- -w如果make在执行过程中改变目录,打印当前目录名
Makefile的VPATH
VPATH : 虚路径
在一些大的工程中,有大量的源文件,我们通常的做法是把这许多的源文件分类,并存放在不同的目录中。所以,当make需要去找寻文件的依赖关系时,你可以在文件前加上路径,但最好的方法是把一个路径告诉make,让make在自动去找。
Makefile文件中的特殊变量“VPATH”就是完成这个功能的,如果没有指明这个变量,make只会在当前的目录中去找寻依赖文件和目标文件。如果定义了这个变量,那么,make就会在当当前目录找不到的情况下,到所指定的目录中去找寻文件了。
VPATH = src:…/headers
上面的的定义指定两个目录,“src”和“…/headers”,make会按照这个顺序进行搜索。目录由“冒号”分隔。(当然,当前目录永远是最高优先搜索的地方)