Используйте правило статического шаблона, чтобы избежать повторения кода и динамически генерируемых зависимостей.Что-то вроде этого должно сделать это:
.DEFAULT_GOAL := all
FOO_DIR := Foo
FOO_SRCS := a
BAR_DIR := Bar
BAR_SRCS := b
# Macros to dynamically generate dependencies
OBJS :=
DIRS :=
# $(1): directory path
# $(2): source directory path relative to $(1)
# (will also be the relative path in build directory)
# $(3): source/object file base name
# NOTE: the empty line at the end of the macro is on purpose!
define obj_dependencies
_dir := $(BUILD_DIR)/$(1)
_obj := $$(_dir)/$(3).o
$$(_obj): $(1)/$(2)/$(3).c | $$(_dir)
DIRS += $$(_dir)
OBJS += $$(_obj)
_dir :=
_obj :=
endef
# $(1): directory path
# $(2): source directory path relative to $(1)
# $(3): list of file base names
objs_for_dir = $(eval $(foreach _o,$(3),$(call obj_dependencies,$(strip $(1)),$(strip $(2)),$(_o))))
# Generate dependencies for given directories & sources
$(call objs_for_dir,$(FOO_DIR),src,$(FOO_SRCS))
$(call objs_for_dir,$(BAR_DIR),Source,$(BAR_SRCS))
# build all object files
all: $(OBJS)
# Sources -> objects
$(OBJS): %.o:
$(CC) -c $< -o $@
# Utils
$(DIRS): | $(BUILD_DIR)
$(BUILD_DIR) $(DIRS):
mkdir -p $@
Имейте в виду, я напечатал это прямо с моей головы, так что могут быть опечатки.Но, по крайней мере, это должно дать вам представление о том, как добиться того, чего вы хотите.
Это можно оптимизировать, чтобы вызывать $(eval)
только один раз, например
objs_for_dir = $(foreach _o,$(3),$(call obj_dependencies,$(strip $(1)),$(strip $(2)),$(_o)))
# Generate dependencies for given directories & sources
$(eval \
$(call objs_for_dir,$(FOO_DIR),src,$(FOO_SRCS)) \
$(call objs_for_dir,$(BAR_DIR),Source,$(BAR_SRCS)) \
)