ucore的makefile学习-以实际例子来展示

使用lab1_result目录
执行的命令为

make mytest

代码均添加在如下代码后面一行。

include tools/function.mk
mytest:
	echo $(call listf,./libs,c)

结果
./libs/string.c ./libs/printfmt.c

toobj

mytest:
	@echo $(call toobj,a.c,hello)

输出
obj/hello/a.o

todep

跟toobj相似,只是借用了toobj来实现取了下巧

mytest:
	@echo $(call todep,a.c,hello)

输出
obj/hello/a.d

totarget

mytest:
	@echo $(call totarget,a.c)

结果
bin/a.c

packetname

mytest:
	@echo $(call packetname,hello)

输出
__objs_hello

总结

listf用来获取c文件,
toobj指定obj/boot/*.o obj/kern/*.o等
todep指定的东西与.o在同一目录下
totargetbin/下面
以前函数均是返回一个字符串,.d文件指明其依赖的其它文件。

SLASH	:= /
OBJDIR	:= obj
BINDIR	:= bin
listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
		  $(wildcard $(addsuffix $(SLASH)*,$(1))))

# get .o obj files: (#files[, packet])
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
		$(addsuffix .o,$(basename $(1))))

# get .d dependency files: (#files[, packet])
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))

totarget = $(addprefix $(BINDIR)$(SLASH),$(1))

# change $(name) to $(OBJPREFIX)$(name): (#names)
packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))

# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@echo + cc $$<
	$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
ALLOBJS += $$(call toobj,$(1),$(4))
endef

$(info  $(call cc_template,a.c ,gcc ,-g,))
test:
	echo hello


OBJDIR	:= obj
BINDIR	:= bin
SLASH	:= /
.SECONDEXPANSION:
# -------------------- function begin --------------------

# list all files in some directories: (#directories, #types)
listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
		  $(wildcard $(addsuffix $(SLASH)*,$(1))))

# get .o obj files: (#files[, packet])
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
		$(addsuffix .o,$(basename $(1))))

# get .d dependency files: (#files[, packet])
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))

totarget = $(addprefix $(BINDIR)$(SLASH),$(1))

# change $(name) to $(OBJPREFIX)$(name): (#names)
packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))

# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@echo + cc $$<
	$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
ALLOBJS += $$(call toobj,$(1),$(4))
endef

all: obj/test.o obj/test.d
	

$(eval $(call cc_template,test.c,gcc,-g,))

其中,第一行
@gcc -I$(dir a.c ) -g -MM $< -MT "$(patsubst %.d,%.o,$@) $@"> $@
-I$(dir a.c),用于取.c所有的目录为include的查找目录,即include<...>的文件的查找目录被显示申明,不会再去查找系统默认库目录。
随便写一个test.c,可以对比如下两个的输出,这个gcc指令用来生成.d文件的。
gcc -MM test.c -MT "test.d",
gcc -MM test.c
下面一个gcc命令用于生成.o文件
注意到$$$$(dir $$$$@)行为比较怪异,这是二次展开,用法特殊
当eval执行完后
代码大概如下,

all: obj/test.d obj/test.o

obj/test.d: test.c | obj
	gcc -I. -g -MM test.c -MT "test.o test.d" > obj/test.d
obj/test.o: test.c | obj
	@echo + cc test.c
	@gcc -I . -g -c test.c -o obj/test.o
ALLOBJS+=obj/test.o

OBJDIR	:= obj
BINDIR	:= bin
SLASH	:= /
OBJPREFIX	:= __objs_
.SECONDEXPANSION:
# -------------------- function begin --------------------

# list all files in some directories: (#directories, #types)
listf = $(filter $(if $(2),$(addprefix %.,$(2)),%),\
		  $(wildcard $(addsuffix $(SLASH)*,$(1))))

# get .o obj files: (#files[, packet])
toobj = $(addprefix $(OBJDIR)$(SLASH)$(if $(2),$(2)$(SLASH)),\
		$(addsuffix .o,$(basename $(1))))

# get .d dependency files: (#files[, packet])
todep = $(patsubst %.o,%.d,$(call toobj,$(1),$(2)))

totarget = $(addprefix $(BINDIR)$(SLASH),$(1))

# change $(name) to $(OBJPREFIX)$(name): (#names)
packetname = $(if $(1),$(addprefix $(OBJPREFIX),$(1)),$(OBJPREFIX))

# cc compile template, generate rule for dep, obj: (file, cc[, flags, dir])
define cc_template
$$(call todep,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@$(2) -I$$(dir $(1)) $(3) -MM $$< -MT "$$(patsubst %.d,%.o,$$@) $$@"> $$@
$$(call toobj,$(1),$(4)): $(1) | $$$$(dir $$$$@)
	@echo + cc $$<
	$(V)$(2) -I$$(dir $(1)) $(3) -c $$< -o $$@
ALLOBJS += $$(call toobj,$(1),$(4))
endef
# add files to packet: (#files, cc[, flags, packet, dir])
define do_add_files_to_packet
__temp_packet__ := $(call packetname,$(4))
ifeq ($$(origin $$(__temp_packet__)),undefined)
$$(__temp_packet__) :=
endif
__temp_objs__ := $(call toobj,$(1),$(5))
$$(foreach f,$(1),$$(eval $$(call cc_template,$$(f),$(2),$(3),$(5))))
$$(__temp_packet__) += $$(__temp_objs__)
endef

$(eval $(call do_add_files_to_packet,test.c,gcc,-g,hello,))
$(info $(call do_add_files_to_packet,test.c,gcc,-g,hello,))
all:obj/test.o obj/test.d
	echo ${__objs_hello}

关于do_add_files_to_packet干了什么,生成target obj/.o,obj/.d,并且将所有的.o文件收集到变量packet里面带上一个__objs_前缀。

将一些.o文件收集到变量__objs_packet中。

# add objs to packet: (#objs, packet)
define do_add_objs_to_packet
__temp_packet__ := $(call packetname,$(2))
ifeq ($$(origin $$(__temp_packet__)),undefined)
$$(__temp_packet__) :=
endif
$$(__temp_packet__) += $(1)
endef

__temp_target__存放你要生成的可执行目标,
__temp_target__将__objs_packt里的.o文件和objs里的.o文件接在一起
TARGETS加上当前目标
编译当前目标

# add packets and objs to target (target, #packes, #objs[, cc, flags])
define do_create_target
__temp_target__ = $(call totarget,$(1))
__temp_objs__ = $$(foreach p,$(call packetname,$(2)),$$($$(p))) $(3)
TARGETS += $$(__temp_target__)
ifneq ($(4),)
$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
	$(V)$(4) $(5) $$^ -o $$@
else
$$(__temp_target__): $$(__temp_objs__) | $$$$(dir $$$$@)
endif
endef

之个finish是帮助生成文件夹的


# finish all
define do_finish_all
ALLDEPS = $$(ALLOBJS:.o=.d)
$$(sort $$(dir $$(ALLOBJS)) $(BINDIR)$(SLASH) $(OBJDIR)$(SLASH)):
	@$(MKDIR) $$@
endef

总结:
do_add_files_to_packet:调用了cc_template,需要一个obj目录并生成.o和.d文件
do_add_objs_to_packet:在__objs_( 2 ) 变 量 里 加 上 2)变量里加上 2)(1)变量里的.o文件
do_create_target:产生相应的target,形如bin/boot,将packes是一堆变量,每个变量里面的.o文件取出,并加上objs,得到一大堆.o文件,利用.o生成当前目标,并将目标存于TARGETS

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值