使用lab1_result目录
执行的命令为
make mytest
代码均添加在
include tools/function.mk
后面一行。
mytest:echo $(call listf,./libs,c)
结果
./libs/string.c ./libs/printfmt.c
mytest:@echo $(call toobj,a.c,hello)
输出
obj/hello/a.o
跟toobj相似,只是借用了toobj来实现取了下巧
mytest:@echo $(call todep,a.c,hello)
输出
obj/hello/a.d
mytest:@echo $(call totarget,a.c)
结果
bin/a.c
mytest:@echo $(call packetname,hello)
输出
__objs_hello
listf
用来获取c文件,
toobj
指定obj/boot/*.o obj/kern/*.o等
todep
指定的东西与.o
在同一目录下
totarget
在bin/
下面
以前函数均是返回一个字符串,.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))
endefall: 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.oobj/test.d: test.c | objgcc -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.decho ${__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
上一篇:语法练习:left2
下一篇:关于Vue3中插槽的一些使用