Makefile的依赖管理
1、示例程序
(1)a.c文件
#include <stdio.h>void func_b(void);
void func_c(void);int main(void)
{func_b();func_c();
}(2)b.c文件
#include <stdio.h>void func_b(void)
{printf("This is func_b\n");
}(3)c.c文件
#include <stdio.h>
#include "c.h"void func_c(void)
{printf("This is c = %d\n", C);
}(4)c.h文件
#define C 1
(5)Makefile文件
test: a.o b.o c.ogcc -o test $^%.o : %.cgcc -c -o $@ $<2、Makefile存在bug
(1)make编译后,执行./test.exe 打印出:
This is func_b
This is c = 1(2)然后修改c.h:
#define C 2(3)重新编译运行,结果不变,说明现在的Makefile存在问题。
- 为什么会出现这个问题呢, 首先test依赖c.o,c.o依赖c.c, 也依赖c.h。
- 更新了c.h,并没有在Makefile上体现出来,导致c.h的更新,Makefile无法检测到。
- 因此需要添加:
c.o : c.c c.h(4)现在每次修改c.h,Makefile都能识别到更新操作,从而更新最后输出文件。每个.c文件编译都要依赖其.h文件,对于内核,有几万个文件,不可能为每个C文件依次写出其头文件。 因此需要做出改进,让其自动生成头文件依赖。
3、依赖相关指令
gcc -M c.c // 打印出依赖gcc -M -MF c.d c.c // 把依赖写入文件c.dgcc -c -o c.o c.c -MD -MF c.d // 编译c.c, 同事把依赖写入文件c.d3.1、打印出依赖

3.2、把依赖写入文件

3.3、编译且把依赖写入文件
gcc -c -o c.o c.c -MD -MF c.d| 部分 | 含义 |
|---|---|
gcc | 调用 GNU C 编译器。 |
-c | 只编译,不链接。生成目标文件(.o),不会生成可执行文件。 |
-o c.o | 指定输出的目标文件名为 c.o(默认是 c.o,但这里显式指定)。 |
c.c | 输入的 C 源文件。 |
-MD | 自动生成依赖信息(用于 make),并默认写入 .d 文件(这里是 c.d)。 |
-MF c.d | 显式指定依赖文件的输出名为 c.d(覆盖 -MD 的默认行为)。 |
4、修改Makefile
objs = a.o b.o c.odep_files := $(patsubst %,.%.d, $(objs)) # 把obj里所有文件都变为.%.d格式,并用变量dep_files表示
dep_files := $(wildcard $(dep_files)) # 利用wildcard函数,判断dep_files是否存在test: $(objs)gcc -o test $^ifneq ($(dep_files),) # 如果dep_files变量不为空,就将其包含进来
include $(dep_files)
endif%.o : %.cgcc -c -o $@ $< -MD -MF .$@.d clean:del *.o test.exe distclean:del $(dep_files) .PHONY: clean distclean5、编译参数
(1)添加CFLAGS,即编译参数。比如加上编译参数-Werror,把所有的警告当成错误。
CFLAGS = -Werror…………%.o : %.cgcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d(2)除了编译参数-Werror,还可以加上-I参数,指定头文件路径,-Iinclude表示当前的inclue文件夹下。
CFLAGS = -Werror -Iinclude …………%.o : %.cgcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d