Я уже некоторое время работаю с ядром Linux, и я заинтересован в адаптации используемых там структур Makefile.Я хочу добиться чего-то похожего, создав набор Make-файлов в каждом подкаталоге, который состоит только из имен файлов, которые я действительно хочу скомпилировать при сборке моего проекта.Типичный аналогичный пример, достигнутый в ядре Linux, выглядит следующим образом:
obj-y += file1.o
obj-y += file2.o
obj-y += file3.o
obj-y += file4.o
# ...
obj-d += somesubdir
Теперь, когда я создаю свой проект, я использую Makefile в своем корневом каталоге, чтобы рекурсивно включить каждый Makefile в отдельные подкаталоги и добавить его всписок переменной obj-y
.Мой текущий подход заключается в определении рекурсивной функции, которая обрабатывает включая Make-файлы и автоматически выполняет итерацию по каждому подкаталогу:
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
.