我已经使用Linux内核已有一段时间了,我对适应在那里使用的Makefile结构很感兴趣。我想通过在每个子目录中创建一组Makefile来实现类似的目的,这些Makefile只包含我在构建项目时真正想要编译的文件的名称。在Linux内核中实现的一个典型的类似示例如下所示:
obj-y += file1.o
obj-y += file2.o
obj-y += file3.o
obj-y += file4.o
# ...
obj-d += somesubdir
现在,在构建项目时,我使用根目录中的Makefile将每个Makefile递归地包含在各个子目录中,并将其附加到obj-y
变量的列表中。我目前的方法是定义一个递归函数,该函数处理包括Makefile在内的文件,并自动遍历每个子目录:
OBJS :=
objtree := .
srctree := .
# ...
define build_subdir
objtree := $$(objtree)/$(1)
srctree := $$(srctree)/$(1)
obj-y :=
obj-d :=
include $$(srctree)/Makefile
OBJS += $$(patsubst %,$$(objtree)/%,$$(obj-y))
$$(foreach subdir,$$(obj-d),$$(eval $$(call build_subdir,$$(subdir))))
srctree := $$(patsubst %/$(1),%,$$(srctree))
objtree := $$(patsubst %/$(1),%,$$(objtree))
endef
# ...
$(eval $(call build_subdir,src))
$(eval $(call build_subdir,src/subdir))
遍历所有子目录时,我将各个文件添加到OBJS
变量中,然后使用该变量来编译该文件。
但是,OBJS
变量仅包含目标文件(即目标)的名称,而不包含实际源文件的名称。这是有问题的,因为我项目中的源文件不仅由.c
组成,还包括某些程序集文件(.S
)。因此,我无法定义如下所示的配方:
define compile_file
$(1): $$(patsubst %.o,%.c,$(1))
$(CC) $< -o $@ $(CFLAGS)
endef
就我而言,编译器始终是相同的,因此将$(CC)
变量保持不变没有任何问题。 $(CFLAGS)
变量也是如此。
有没有一种类似于Linux内核的方法?
这是我的Makefile的当前相关内容:
objtree := .
srctree := .
.PHONY: all
all: real-all
OBJS :=
define build_subdir
objtree := $$(objtree)/$(1)
srctree := $$(srctree)/$(1)
obj-y :=
obj-d :=
include $$(srctree)/Makefile
OBJS += $$(patsubst %,$$(objtree)/%,$$(obj-y))
$$(foreach subdir,$$(obj-d),$$(eval $$(call build_subdir,$$(subdir))))
srctree := $$(patsubst %/$(1),%,$$(srctree))
objtree := $$(patsubst %/$(1),%,$$(objtree))
endef
# $(eval $(call build_subdir, src))
$(eval $(call build_subdir,src/arch/$(ARCH)))
define compile_file
$(1): $$(patsubst %.o,%.S,$(1))
@echo "Compiling file $$< to file $$@"
endef
$(foreach file,$(OBJS),$(eval $(call compile_file,$(file))))
.PHONY: real-all
real-all: $(OBJS)
@echo "real-all"
当前输出:
Compiling file src/arch/x86/a20.S to file src/arch/x86/a20.o
make: *** No rule to make target 'src/arch/x86/acpi.S', needed by 'src/arch/x86/acpi.o'. Stop.
最后一行显然失败了,因为没有src/arch/x86/acpi.S
文件。相反,实际文件为src/arch/x86/acpi.c
。那就是我之前针对源文件问题而解决的问题,可以是.c
或.S
文件。
答案 0 :(得分:0)
我通过以下方式使用$(wildcard)
函数解决了这个问题:
define compile_file
srcbase := $$(basename $(1))
srcfile := $$(wildcard $$(srcbase).*)
$(1): $$(srcfile)
@echo "[ CC ] $$@"
endef
由于$(1)
包含文件的路径,因此srcfile
通过使用$(wildcard $$(basename $(1)).*)
查找文件来匹配文件。
现在,我可以轻松地编译所有文件了。