下面的内容只是个人学习Makefile的一些笔记,有什么错误大家可以以下探讨。
1、Makefile的核心–规则
-
目标:依赖1 依赖2 …
-
[TAB] 命令
当“目标文件”不存在,或者某个依赖文件比目标文件“新”,则执行“命令”
2、Makefile的语法
2.1.通配符:
- %.o
- $@ 表示目标
- $< 表示第1个依赖文件
- $^ 表示所有依赖文件
- 不想在终端看到命令输出的话,可在命令前加一个“@”
2.2.假想目标:
我们的 Makefile 中有这样的目标:
clean:
rm -f $(shell find -name "*.o")
rm -f $(TARGET)
如果当前目录下恰好有名为“clean”的文件,那么执行“make clean”时它就不会执行那些删除命令。这时我们需要把“clean”这个目标,设置为“假想目标”,这样可以确保执行“make clean”时那些删除命令肯定可以得到执行。
使用下面的语句把“clean”设置为假想目标:
.PHONY : clean
2.3.即时变量、延时变量
A := xxx # A的值即刻确定,在定义时即确定
B = xxx # B的值使用到时才确定
:= # 即时变量
= # 延时变量
?= # 延时变量,如果时第一次定义才起效,如果在前面该变量已被定义则忽略这一句
+= # 附加,它是即时还是延时变量,由前面的定义决定
3、Makefile常用函数
$(foreach var, list, text) //A = a b c B = $(foreach f, $(A), $(f).o)
//给list中的每个内容加上一个text
$(filter pattern..., text) //C = a b c d/ D = $(filter %/, $(C))
//在text中,取出符合pattern格式的内容
$(filter-out pattern..., text) //C = a b c d/ E = $(filter-out %/,$(C))
//在text中,取出不符合pattern格式的内容
$(wildcard pattern) //files = $(wildcard *.c)
//pattern定义了文件名的格式,wildcard取出其中存在的文件
$(patsubst pattern, replacement, $(var))
//file2 = a.c b.c c.c dep_files = $(patsubst %.c, %.d, $(file2))
//从text中取出每一个值,如果符合pattern,则替换成replacement
4、Makefile实例
4.1.支持头文件依赖
gcc -M c.c //打印出依赖
gcc -M -MF c.d c.c //把依赖写入文件c.d
gcc -c -o c.o c.c -MD -MF c.d //编译c.o,把依赖写入文件c.d
实例:
objs = a.o b.o c.o
dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))
test: $(objs)
gcc -o -test $^
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
4.2.添加CFLAGS
CFLAGS = -Werror -Iinclude //-Werror-->将warning视为error
//-Iinclude-->指定include文件夹作为gcc搜索头文件的目录
实例:
objs = a.o b.o c.o
dep_files := $(patsubst %,.%.d, $(objs))
dep_files := $(wildcard $(dep_files))
CFLAGS = -Werror -Iinclude ////-Iinclude-->指定include文件夹作为gcc搜索头文件的目录
test: $(objs)
gcc -o -test $^
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
5、通用Makefile的设计思想
5.1.在 Makefile 文件中确定要编译的文件、目录,比如:
obj-y += main.o
obj-y += a/
“Makefile”文件总是被“Makefile.build”包含的。
5.2.在 Makefile.build 中设置编译规则,有 3 条编译规则:
- 怎么编译子目录? 进入子目录编译:
$(subdir-y):
make -C $@ -f $(TOPDIR)/Makefile.build
- 怎么编译当前目录中的文件?
%.o : %.c
$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -Wp,-MD,$(dep_file) -c -o $@ $<
- 当前目录下的.o 和子目录下的 built-in.o 要打包起来:
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
5.3. 顶层 Makefile 中把顶层目录的 built-in.o 链接成 APP:
$(TARGET) : built-in.o
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o
6、通用Makefile的解析
6.1.Makefile
obj-y += main.o
obj-y += sub.o
obj-y += a/
all : start_recursive_build $(TARGET) //1.执行make,
@echo $(TARGET) has been built! //导致顶层Makefile的第一个目标“all”被处理
start_recursive_build: //2.使用Makefile.build处理顶层目录
make -C ./ -f $(TOPDIR/Makefile.build)
$(TARGET) : built-in.o //4.最后链接得到APP
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o
6.2.Makefile.build
obj-y :=
subdir-y := //3-1.变量清零
EXTRA_CFLAGS :=
include Makefile //3-2.包含Makefile,里面有obj-y-->确定文件以及目录
......
PHONY += $(subdir-y)
__build : $(subdir-y) built-in.o //3-3.先处理子目录-->跟处理顶层目录一样
$(subdir-y): //3-4.编译main.o、sub.o
make -C $@ -f $(TOPDIR)/Makefile.build //把mian.o,sub.o以及a/built-in.o
//一起链接得到顶层目录的built-in.o
built-in.o : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^