makefile几点基础知识
1. 赋值符号的区别
=最基本的赋值
:=是覆盖之前的值
?=是如果没有被赋值过的就赋予等号后面的值
+=是添加等号后面的值
2.自动变量
$<第一个依赖文件的名称。
$?所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚。
$@目标的完整名称。
$^所有的依赖文件,以空格分开,不包含重复的依赖文件。
3.常用函数
$(patsubst %.c, %.o, aaaa.c) 返回结果是: aaaa.o
$(filter <pattern...>,<text>) 以<pattern>模式过滤<text>字符串中的单词,保留符合模式<pattern>的单词。可以有多个模式。
$(filter-out <pattern...>,<text>)
$(foreach <var>,<list>,<text>)把参数<list>中的单词逐一取出放到参数<var>所指定的变量中, 然后再执行<text>所包含的表达式。每一次<text>会返回一个字符串,循环这个过程
shell函数 files:=$(shell echo *.c)
顶级Makefile:
CROSS_COMPILE =
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
CPP = $(CC) -E
AR = $(CROSS_COMPILE)ar
NM = $(CROSS_COMPILE)nm
STRIP = $(CROSS_COMPILE)strip
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
export AS LD CC CPP AR NM
export STRIP OBJCOPY OBJDUMP
CFLAGS := -Wall -O2 -g
LDFLAGS :=
export CFLAGS LDFLAGS
TOPDIR := $(shell pwd)
export TOPDIR
TARGET := test
obj-y += main.o
obj-y += a/
obj-y += b/
obj-y += c/
all :
make -C ./ -f $(TOPDIR)/Makefile.build
$(CC) $(LDFLAGS) -o $(TARGET) built-in.o
clean:
rm -f $(shell find -name "*.o")
rm -f $(shell find -name "*.d")
rm -f $(TARGET)
.PHONY:all clean
这里前面就是定义一些变量,all是工程默认的目标,它是一个伪目标,进入伪目标后执行的命令就是执行Makefile.build,这里就会引起递归调用,在Makefile.build中又会调用Makefile.build.一直到Makefile.build返回以后,会使用Makefile.build最后生成的built-in.o生成最终的目标文件。
Makefile.build:
PHONY := build
build :
obj-y :=
subdir-y :=
include Makefile
__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y)))
subdir-y += $(__subdir-y)
subdir_objs := $(foreach f,$(subdir-y),$(f)/built-in.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 : $(cur_objs) $(subdir_objs)
$(LD) -r -o $@ $^
dep_file = .$@.d
%.o : %.c
$(CC) $(CFLAGS) -Wp,-MD,$(dep_file) -c -o $@ $<
.PHONY : $(PHONY)
Makefile.build会加载顶级目录下的Makefile,在顶级目录下的Makefile中已经给obj-y添加了一些条目,subdir-y就是获取子目录,然后对每一个子目录又调用Makefile.build。
当递归到没有子目录的目录时,Makefile.build开始返回,并使用$(CC)对源文件进行编译,将所有的.c生成.o文件,并将当前目录下的.o和子目录下的build-in.o连接成当前目录下的build-in.o,并回返上级目录,一次往复,最终返回到顶级目录,在顶级目录下生成build-in.o。返回到顶级目录后,Makefile.build返回到了Makefile中,Makefile在使用build-in.o生成指定的目标文件。至此,递归结束,整个系统编译完成。
这里的-MD选
项和.$@.d的作用是 生成头文件的依赖关系时,把依赖关系写入到这个文件中去。
make之后的目录:
顶级:
a目录:
d目录: