makefile工作原则
原则一
若想生成目标,检查规则中的依赖条件是否存在,如不存在,则去寻找是否有规则去生成依赖文件。如:
makefile
All:hello
hello:hello.o
gcc hello.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
编译
$ make
gcc -c hello.c -o hello.o
gcc hello.o -o hello
原则二
命名: makefile Makefile
一个规则
目标:依赖条件
[tab]命令
一个例子
单文件
$ tree
.
├── hello.c
└── makefile
编辑makefile:
hello:hello.c
gcc hello.c -o hello
使用make编译
$ make
gcc hello.c -o hello
$ ls
hello hello.c makefile
多文件
- 文件结构
$ tree
.
├── add.c
├── hello.c
├── makefile
└── sub.c
- makefile
为了提高编译效率,当修改一个源文件时,必须要重新编译其他没变的文件
# 1. 方式一
hello:hello.c add.c sub.c
gcc hello.c add.c sub.c -o hello
# 2. 方式二,当修改一个源文件,只会编译这个文件,并链接,省略了其他文件的编译和汇编
hello:hello.o add.o sub.o
gcc hello.o add.o sub.o -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
1) 第一次编译:
$ make
gcc -c hello.c -o hello.o
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
gcc hello.o add.o sub.o -o hello
2) 当修改了add.c后,再次编译
$ make
gcc -c add.c -o add.o
gcc hello.o add.o sub.o -o hello
2个函数
src = $(wildcard *.c)
找到当前目录下所有后缀为.c的文件,赋值给src,即src会被替换为hello.c, add.c..
obj = $(patsust %.c,%.o,$(src))
把src变量中所有后缀名为.c的文件替换成.o,obj为hello.o add.o ..
改写为:
# 仅仅代表字符串替换
src = $(wildcard *.c) # add.c sub.c hello.c
obj = $(patsubst %.c,%.o,$(src)) # add.o sub.o hello.o
All:hello
hello:$(obj)
gcc $(obj) -o hello
hello.o:hello.c
gcc -c hello.c -o hello.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:sub.c
gcc -c sub.c -o sub.o
clean:
-rm -rf $(obj) hello # -表示出错也执行
- clean
make clean -n # 预览要执行的操作
make clean # 执行clean操作
3个自动变量
$@
表示规则中的目标,只能出现在一组规则中的命令中
hello:$(obj)
gcc $(obj) -o $@
hello.o:hello.c
gcc -c hello.c -o $@ # $@ == hello.o
$<
表示规则中的第一个条件
hello.o:hello.c
gcc -c $< -o $@ # $@ == hello.o
如果该变量用在模式规则中,可将依赖条件中的列表依次取出,套用模式规则
$^
表示规则中的所有条件,组成一个列表,以空格隔开,如果这个列表中有重复的项则消除重复项
- 升级为:
src = $(wildcard *.c) # hello.c add.c sub.c
obj = $(patsubst %.c,%.o,$(src)) # hello.c add.o sub.o
All:hello
hello:$(obj)
gcc $^ -o $@
hello.o:hello.c
gcc -c $< -o $@
add.o:add.c
gcc -c $< -o $@
sub.o:sub.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) hello
目前已经很大的增强了项目的拓展行
当新增文件时,只需要添加如下代码:
mul.o:mul.c
gcc -c $< -o $@
模式规则
-升级为:
src = $(wildcard *.c) # hello.c add.c sub.c
obj = $(patsubst %.c,%.o,$(src)) # hello.c add.o sub.o
All:hello
hello:$(obj)
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) hello
这样,新增文件时,就不需要更改Makefile了
至此,已经可以实现单层目录的编译了。
多层目录(嵌套执行make)
目录结构
.
├── add.c
├── dir1
│ ├── makefile
│ └── mul.c
├── hello.c
├── makefile
└── sub.c
根目录下的时总控Makefile:
src = $(wildcard *.c) # hello.c add.c sub.c
obj = $(patsubst %.c,%.o,$(src)) # hello.c add.o sub.o
All:hello
hello:$(obj)
gcc $^ -o $@
%.o:%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj) hello
subsystem:
cd dir1 && $(MAKE)
通过为目标
subsystem
完成子目录的编译
- 目录结构
├── hello
├── inc
│ └── mymath.h
├── makefile
├── obj
│ ├── dir1
└── src
├── add.c
├── dir1
│ ├── makefile
│ └── mul.c
├── hello.c
└── sub.c
src目录放源码(.c),obj目录放汇编文件(.o)
src = $(wildcard ./src/*.c) # hello.c add.c sub.c
src += $(wildcard ./src/dir1/*.c)
# src = ./src/hello.c ..
obj = $(patsubst ./src/%.c, ./obj/%.o,$(src)) # hello.c add.o sub.o
# obj = ./obj/hello.o ..
All:hello
hello:$(obj)
gcc $^ -o $@
# obj = ./obj/hello.o ...
$(obj):./obj/%.o:./src/%.c
gcc -c $< -o $@
clean:
-rm -rf $(obj)
-rm -rf hello
exec:
@echo $(obj)
@echo $(src)
注意模式匹配中的
%
只能匹配文件名,不匹配路径但是在函数中的
%
可以匹配任意字符,包括路径
结果:
.
├── hello
├── inc
│ └── mymath.h
├── makefile
├── obj
│ ├── add.o
│ ├── dir1
│ │ └── mul.o
│ ├── hello.o
│ └── sub.o
└── src
├── add.c
├── dir1
│ ├── makefile
│ └── mul.c
├── hello.c
└── sub.c