GNU make中不同构建文件夹中的构建库

时间:2019-02-12 00:24:12

标签: makefile gnu-make

我试图建立一个构建系统,该系统支持在单独的文件夹中构建库和可执行文件,而不必求助于递归构造。 我当前的目录树如下:

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 $@

2 个答案:

答案 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/sourceBar/Src,但是您的makefile显示了Foo/srcBar/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 $@