2、EXTRA_CFLAGS 和 CFLAGS_xxx.o
我们还可以给各个子目录下面的 makefile 里面添加 “EXTRA_CFLAGS” “CFLAGS_xxx.o” 这两个变量
"EXTRA_CFLAGS", 它给当前目录下的所有文件(不含其下的子目录)设置额外的编译选项, 可以不设置 "CFLAGS_xxx.o", 它给当前目录下的xxx.c设置它自己的编译选项, 可以不设置
首先查看 sub2.c 源码
#include <stdio.h> #include <sub2.h> void sub2_fun(void) { printf("Sub2 fun, B = %d!\n", B); #ifdef DEBUG printf("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); #endif }
再查看 sub3.c
#include <stdio.h> #include <sub3.h> void sub3_fun(void) { printf("Sub3 fun, C = %d!\n", C); #ifdef DEBUG printf("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__); #endif #ifdef DEBUG_SUB3 printf("It is only debug info for sub3.\n"); #endif }
可以看到 sub2.c 和 sub3.c 都含有 DEBUG 编译宏,如果定义了这个宏,就会打印对应的信息,那么我们可以通过 Makefile 里面传入这个宏
修改 a 目录下的 Makefile
EXTRA_CFLAGS := -D Debug # -D 就是 define 的意思
使用这个编译选项来编译 c 文件时,他就相当于在头文件里面定义了这个宏一样
先执行 make clean,再执行 make 查看效果
可以看到编译 sub2.c 和 sub3.c 时,传入了 -D 的编译选项, -I 选项是都有的,编译 main.c 和 sub.c 时没有 -D 选项
执行 test 文件,可以看到打印出了这些调试信息
源码 sub3.c 里面有个 DEBUG_SUB3 的编译开关,我们也可以给这个 sub3.c 单独指定这个编译选项
修改 a 目录下面的 Makefile,增加下面一句:
CFLAGS_sub3.o := -D DEBUG_SUB3
先执行 make clean,再执行 make
可以看到只有 sub3.c 用到了 DEBUG_SUB3 的编译选项
执行 test 文件,可以看到相应的调试信息
三、通用 Makefile 的解析
查看 example 目录下的文件树结构
1、Makefile.build 文件
Makefile.build
PHONY := __build __build: obj-y := subdir-y := EXTRA_CFLAGS := include Makefile # obj-y := a.o b.o c/ d/ # $(filter %/, $(obj-y)) : c/ d/ # __subdir-y : c d # subdir-y : c d __subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) subdir-y += $(__subdir-y) # c/built-in.o d/built-in.o subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.o) # a.o b.o cur_objs := $(filter-out %/, $(obj-y)) dep_files := $(foreach f,$(cur_objs),.$(f).d) dep_files := $(wildcard $(dep_files)) ifneq ($(dep_files),) include $(dep_files) endif PHONY += $(subdir-y) __build : $(subdir-y) built-in.o $(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build built-in.o : $(subdir-y) $(cur_objs) $(LD) -r -o $@ $(cur_objs) $(subdir_objs) dep_file = .$@.d %.o : %.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $< .PHONY : $(PHONY)
2、通用 Makefile 的设计思想:
每一个目录下面都有一个名为 Makefile 的文件,在 Makefile 里面指定了哪些文件,哪些目录要编译进程序里,我们使用顶层 Makefile.build 将这些文件编进程序里。
①、在 Makefile 文件中确定要编译的文件、目录,比如:
obj-y += main.o obj-y += a/
“Makefile” 文件总是被 “Makefile.build” 包含的。
②、Makefile.build 中设置编译规则,有 3 条编译规则:
A. 怎么编译子目录? 进入子目录编译:
$(subdir-y): make -C $@ -f $(TOPDIR)/Makefile.build # 进入子目录并使用顶层目录里面的 Makefile.build 来编译这个子目录,这个 Makefile.build 会包含子目录里面的 Makefile,从子目录的 Makefile 就知道了要编译哪些文件
B. 怎么编译当前目录中的文件?
%.o : %.c $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
C. 当前目录下的 .o 和子目录下的 built-in.o 要打包起来:
built-in.o : $(cur_objs) $(subdir_objs) $(LD) -r -o $@ $^
③、顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:
$(TARGET) : built-in.o $(CC) $(LDFLAGS) -o $(TARGET) built-in.o
3、情景演绎