Makefile

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
posted @ 2020-02-09 16:42  fight139  阅读(222)  评论(0)    收藏  举报