Makefile 学习笔记
Posted 皮卡丘吉尔
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Makefile 学习笔记相关的知识,希望对你有一定的参考价值。
Makefile学习笔记
1. gcc编译过程
-
预处理
gcc -E hello.c -o hello.i
-
编译
gcc -S hello.i -o hello.s
-
汇编
gcc -c hello.s -o hello.o
-
链接
gcc hello.o -o hello
2. Makefile 基本介绍
我们把编译分为两个步骤。
-
先编译
gcc -c a.c -o a.o gcc -c b.c -o b.o gcc -c c.c -o c.o ...
-
再链接
gcc a.o b.o c.o -o hello
编译的原则是 修改的才会被编译。这样增加效率。
如何判断哪个文件被修改了,哪些没修改?
我们通过文件修改时间来判断。
规则1
目标文件: 依赖文件
[Tab]命令
(当依赖比目标新 或者 目标文件不存在 执行命令)
# hello 依赖于 a.o b.o c.o
hello : a.o b.o c.o
gcc a.o b.o c.o -o hello
# a.o 依赖于 a.c
a.o : a.c
gcc -c a.c -o a.o
# b.o 依赖于 b.c
b.o : b.c
gcc -c b.c -o b.o
# c.o 依赖于 c.c
c.o : c.c
gcc -c c.c -o c.o
规则2
Makefile 语法
-
- 通配符:
%.o
- 通配符:
-
- 假想目标:
.PHONY
- 假想目标:
-
- 即时变量、延时变量 export
# hello 依赖于 a.o b.o c.o 文件
hello : a.o b.o c.o
gcc $^ -o hello
# %.o 依赖于 %.c 文件
%.o : %.c
gcc -c $< -o $@
$<
: 第一个依赖文件$@
: 目标文件$^
: 所有的依赖文件
3. Makefile 使用
# hello 依赖于 a.o b.o c.o 文件
hello : a.o b.o c.o
gcc $^ -o hello
# %.o 依赖于 %.c 文件
%.o : %.c
gcc -c $< -o $@
clean:
rm *.o hello
.PHONY: clean
make [目标]
-
目标可以不写、则默认是 第一个目标
-
make
是执行 第一个目标文件 -
当执行
make clean
则可以删除 所有文件 -
.PHONY: clean
是防止你执行make clean
时刚好你 有clean
文件。
即时变量 和 延时变量
A := xxx
A的值即刻确定B = xxx
B的值使用到的时候才确定
A := $(C)
B = $(C)
#C = abc
all:
@echo A = $(A)
@echo B = $(B)
C = abc
pikaqiu@ubuntu:~/linux_c/makefile/2$ make
A =
B = abc
:=
: 即时变量=
: 延时变量?=
: 延时变量, 如果是第一次定义才起效,如果再前面该变量已定义则忽略这句+=
: 附加, 它是即时变量还是延时变量取决于前面的定义
A := $(C)
B = $(C)
#C = abc
D = hello
D ?= world
all:
@echo A = $(A)
@echo B = $(B)
@echo D = $(D)
C = abc
pikaqiu@ubuntu:~/linux_c/makefile/2$ make
A =
B = abc
D = hello
pikaqiu@ubuntu:~/linux_c/makefile/2$ make D=ddd
A =
B = abc
D = ddd
4. Makefile 函数
1. $(foreach var, list, text) # 在 list 挨个取出值 然后给到 var, 然后 变成 text 对应意思
2. $(filter pattern..., text) # 在 text 中取出符合 patten 格式的值
$(filter-out pattern..., text) # 在 text 中取除不符合 patten 格式的值
3. $(wildcard pattern) # pattern 定义了文件名的格式
# wildcard 取出其中存在的文件
4. $(patsubst pattern, replacement, $(var)) # 从 val 中取 寻找符合 pattern 格式 的 替换成 replacement 的值
示例1
$(foreach var, list, text)
# 在 list 挨个取出值 然后 变成 text对应意思
A = a b c
B = $(foreach f, $(A), $(f).o)
all:
@echo B = $(B)
pikaqiu@ubuntu:~/linux_c/makefile/3$ make
B = a.o b.o c.o
pikaqiu@ubuntu:~/linux_c/makefile/3$
示例2
$(filter pattern..., text)
# 在 text 中取出符合 patten 格式的值
C = a b c d/
D = $(filter %/, $(C)) # 获取 C中 符合 %/ 格式的内容
E = $(filter-out %/, $(C)) # 获取 C中 不符合 %/ 格式的内容
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
pikaqiu@ubuntu:~/linux_c/makefile/3$ make
D = d/
E = a b c
pikaqiu@ubuntu:~/linux_c/makefile/3$
示例3
$(wildcard pattern)
# pattern 定义了文件名的格式 wildcard 取出其中存在的文件
files = $(wildcard *.c) # 获取当前路径 .c 的文件
file1 = a.c b.c c.c e.c
file2 = $(wildcard $(file1)) # 获取当前路径文件 有存在 file1的文件
all:
@echo files = $(files)
@echo files = $(file2)
pikaqiu@ubuntu:~/linux_c/makefile/3$ ls
a.c b.c c.c d.c Makefile
pikaqiu@ubuntu:~/linux_c/makefile/3$ make
files = d.c a.c c.c b.c
files = a.c b.c c.c
pikaqiu@ubuntu:~/linux_c/makefile/3$
示例4
$(patsubst pattern, replacement, $(var))
# 从 val 中取 寻找符合 pattern 格式 的 替换成 replacement 的值
files = a.c b.c c.c ddd
dep_files = $(patsubst %.c, %.d, $(files)) # 从 files变量中 取出每一个值 把 符合.c 替换成.d
all:
@echo dep_files = $(dep_files)
pikaqiu@ubuntu:~/linux_c/makefile/3$ make
dep_file: a.d b.d c.d ddd
pikaqiu@ubuntu:~/linux_c/makefile/3$
实例5
我们这边做一个简单的 Makefile
-
main.c
#include <stdio.h> #include "add.h" int main() printf("%d\\n", add(X, Y)); return 0;
-
add.c
#include "add.h" int add(int x, int y) return x + y;
-
add.h
#ifndef ADD_H #define ADD_H #define X 1 #define Y 2 int add(int x, int y); #endif
-
Makefile (有bug 当宏被修改 再执行 make 并没有更新数据)
main: main.o add.o
gcc $^ -o main
%.o : %.c %.h
gcc -c $< -o $@
clean:
rm *.o main
.PHONY: clean
我们可以通过 gcc -M add.c
来查看 add.c 依赖于啥.h文件
pikaqiu@ubuntu:~/linux_c/makefile/4$ gcc -M add.c
add.o: add.c /usr/include/stdc-predef.h add.h
我们如果想保存下来 这些依赖 可以执行 gcc -M add.c -MF add.d
将依赖存放到 add.d文件中
pikaqiu@ubuntu:~/linux_c/makefile/4$ gcc -M add.c -MF add.d
pikaqiu@ubuntu:~/linux_c/makefile/4$ ls
add.c add.d add.h add.o main main.c main.o Makefile
pikaqiu@ubuntu:~/linux_c/makefile/4$ cat add.d
add.o: add.c /usr/include/stdc-predef.h add.h
如果我们既要生成 .o
文件 还要生成依赖文件 .d
.
gcc -c add.c -o add.o -MD -MF add.d
- Makefile (比较完善写法)
objs = main.o add.o
dep_files := $(patsubst %, .%.d, $(objs)) # 将objs 所有内容 变成 .%.d 存放在 dep_files 中
dep_files := $(wildcard $(dep_files)) # 判断 dep_files 文件是否真实存在 真实存在才 存放到 dep_files
CFLASS = -Werror # 把警告当成错误
#CFLASS = -Werror -I. # 把警告当成错误 并且 把 当前路径 设置为头文件默认路径
#CFLASS = -Werror -Iinclude # 把警告当成错误 并且 把 名为 include 的文件夹 设置为头文件默认路径
main : $(objs)
gcc $^ -o main
@echo dep_files = $(dep_files)
# 如果这些依赖存在 则包含进来
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -c $< -o $@ -MD -MF .$@.d # 自动生成依赖文件 然后加载进来
clean:
rm *.o main
distclean:
rm $(dep_files)
.PHONY: clean
目前只是写了一点点,更多的资料可以 访问 网址 跟我一起写Makefile
以上是关于Makefile 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章