Если вы используете GNU make и все ваши исходные файлы на C * *.c
, которые можно найти в текущем каталоге и во всех его подкаталогах (до любой глубины), это должно быть близко к тому, что вы хотите:
BUILDDIR := build
SRC := $(shell find . -type f -name '*.c')
# Convert C source file name(s) to object file name(s)
# $(1): C source file name(s)
define c2o
$(patsubst %.c,$(BUILDDIR)/%.o,$(notdir $(1)))
endef
OBJ := $(call c2o,$(SRC))
.PHONY: all
all: $(OBJ)
# Compilation rule for a C source file (use echo for testing)
# $(1): C source file name
define MY_rule
$$(call c2o,$(1)): $(1)
@echo $$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(TARGET_ARCH) -c -o $$@ $$<
endef
# Instantiate compilation rules for all C source files
$(foreach s,$(SRC),$(eval $(call MY_rule,$(s))))
Демо-версия:
host> tree .
.
├── Makefile
├── a.c
├── b
│ └── b.c
└── c
└── c
└── c.c
host> make
cc -c -o build/a.o a.c
cc -c -o build/c.o c/c/c.c
cc -c -o build/b.o b/b.c
Обратите внимание на использование $$
в определении MY_rule
. Это необходимо, потому что он раскрывается дважды: один раз при расширении параметров функции eval
и второй раз, когда make анализирует результат как обычный синтаксис make.
Как объяснено в других комментариях и ответах, это работает, только если у вас нет нескольких исходных файлов на Си с одинаковым базовым именем. Есть способ обнаружить эту ситуацию и выдать ошибку, если она встречается. Функция make sort
сортирует свой параметр списка слов, но также удаляет дубликаты. Таким образом, если количество слов до и после сортировки отличается, у вас есть дубликаты. Добавьте следующее сразу после определения OBJ
:
SOBJ := $(sort $(OBJ))
ifneq ($(words $(OBJ)),$(words $(SOBJ)))
$(error Found multiple C source files with same base name)
endif
Демо-версия:
host> touch c/c/a.c
host> make
Makefile:13: *** Found multiple C source files with same base name. Stop.