我试图建立一个构建系统,该系统支持在单独的文件夹中构建库和可执行文件,而不必求助于递归构造。 我当前的目录树如下:
Project
├── Foo
│ └── src
│ └── foo.c
├── Bar
| └── Source
| └── bar.c
├── App
| └── src
| └── main.c
└── Makefile
注意Bar文件夹中的“源”而不是“ src”。
我希望能够生成以下构建目录:
Build
├── Foo
│ ├── foo.o
│ └── foo.a
├── Bar
│ ├── bar.o
│ └── bar.a
└── App
├── main.o
└── app.exe
我还没有找到一种方法来生成通配符配方,以在正确的构建目录中生成对象/ libs / bins,而无需重复我自己:
BUILD_DIR := Path/To/Build
CC ?= gcc
.PHONY: all
all: Foo Bar
# Foo
FOO_DIR = Foo
FOO_SRCS = foo.c
FOO_OBJS = $(addprefix $(BUILD_DIR)/$(FOO_DIR)/,$(FOO_SRCS:.c=.o))
.PHONY: Foo
Foo: $(FOO_OBJS)
## This line has to be repeated for Bar as well
$(BUILD_DIR)/$(FOO_DIR)/%.o: $(FOO_DIR)/src/%.c | $(BUILD_DIR)/$(FOO_DIR)
$(CC) -c $< -o $@
# Bar
BAR_DIR = Bar
BAR_SRCS = bar.c
BAR_OBJS = $(addprefix $(BUILD_DIR)/$(BAR_DIR)/,$(BAR_SRCS:.c=.o))
.PHONY: Bar
Bar: $(BAR_OBJS)
## Here, I am repeating the same line as in Foo
$(BUILD_DIR)/$(BAR_DIR)/%.o: $(BAR_DIR)/Source/%.c | $(BUILD_DIR)/$(BAR_DIR)
$(CC) -c $< -o $@
# Utils
$(BUILD_DIR)/%:
mkdir -p $@
答案 0 :(得分:0)
使用静态模式规则来避免代码重复和动态生成的依赖关系。这样的事情应该做到:
.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)) \
)
答案 1 :(得分:0)
有一个简单的方法可以做到这一点。让我们分阶段进行。我们从以下规则开始:
.PHONY: all
all: Foo Bar
.PHONY: Foo
Foo: $(FOO_OBJS)
.PHONY: Bar
Bar: $(BAR_OBJS)
$(BUILD_DIR)/$(FOO_DIR)/%.o: $(FOO_DIR)/src/%.c | $(BUILD_DIR)/$(FOO_DIR)
$(CC) -c $< -o $@
$(BUILD_DIR)/$(BAR_DIR)/%.o: $(BAR_DIR)/Source/%.c | $(BUILD_DIR)/$(BAR_DIR)
$(CC) -c $< -o $@
(请注意,您的图表显示了Foo/source
和Bar/Src
,但是您的makefile显示了Foo/src
和Bar/Source
。根据需要进行调整。)
我们消除中间目标,并将对象规则转换为static pattern rules:
.PHONY: all
all: $(FOO_OBJS) $(BAR_OBJS)
$(FOO_OBJS): $(BUILD_DIR)/$(FOO_DIR)/%.o: $(FOO_DIR)/src/%.c | $(BUILD_DIR)/$(FOO_DIR)
$(CC) -c $< -o $@
$(BAR_OBJS): $(BUILD_DIR)/$(BAR_DIR)/%.o: $(BAR_DIR)/Source/%.c | $(BUILD_DIR)/$(BAR_DIR)
$(CC) -c $< -o $@
然后我们将静态模式规则分为特定的通用部分:
$(FOO_OBJS): $(BUILD_DIR)/$(FOO_DIR)/%.o: $(FOO_DIR)/src/%.c | $(BUILD_DIR)/$(FOO_DIR)
$(FOO_OBJS):
$(CC) -c $< -o $@
$(BAR_OBJS): $(BUILD_DIR)/$(BAR_DIR)/%.o: $(BAR_DIR)/Source/%.c | $(BUILD_DIR)/$(BAR_DIR)
$(BAR_OBJS):
$(CC) -c $< -o $@
最后结合通用部分:
$(FOO_OBJS): $(BUILD_DIR)/$(FOO_DIR)/%.o: $(FOO_DIR)/src/%.c | $(BUILD_DIR)/$(FOO_DIR)
$(BAR_OBJS): $(BUILD_DIR)/$(BAR_DIR)/%.o: $(BAR_DIR)/Source/%.c | $(BUILD_DIR)/$(BAR_DIR)
$(FOO_OBJS) $(BAR_OBJS):
$(CC) -c $< -o $@