Makefile рекурсивно включает список объектных файлов - PullRequest
2 голосов
/ 06 мая 2019

Я уже некоторое время работаю с ядром 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.

1 Ответ

0 голосов
/ 06 мая 2019

Я решил это с помощью функции $(wildcard) следующим образом:

define compile_file

srcbase := $$(basename $(1))
srcfile := $$(wildcard $$(srcbase).*)

$(1): $$(srcfile)
    @echo "[ CC ] $$@"
endef

Поскольку $(1) содержит путь к файлу, srcfile сопоставляет файл путем поиска файла с $(wildcard $$(basename $(1)).*).

Теперь я могу легко скомпилировать все файлы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...