Библиотеки сборки в разных папках сборки в GNU make - PullRequest
0 голосов
/ 12 февраля 2019

Я пытаюсь настроить систему сборки, которая поддерживает создание библиотек и исполняемых файлов в отдельных папках, не прибегая к рекурсивной сборке.Мое текущее дерево каталогов выглядит следующим образом:

Project
├── Foo
│   └── src
│       └── foo.c
├── Bar
|   └── Source
|       └── bar.c
├── App 
|   └── src
|       └── main.c
└── Makefile

Обратите внимание на «Source» вместо «src» в папке Bar.

Я хотел бы иметь возможность создать следующий каталог сборки:

Build
├── Foo
│   ├── foo.o
│   └── foo.a
├── Bar
│   ├── bar.o
│   └── bar.a
└── App 
    ├── main.o
    └── app.exe

Я еще не нашел способ генерировать рецепт с подстановочными знаками для создания объектов / libs / bin в правильном каталоге сборки, не повторяя себя:

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 голосов
/ 12 февраля 2019

Есть простой способ сделать это.Давайте рассмотрим это поэтапно.Мы начнем с этих правил:

.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, но в вашем make-файле написано Foo/src и Bar/Source. Настройте при необходимости.) Мы исключаем промежуточноецели и превратить правила объекта в правила статического шаблона :

.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 $@
0 голосов
/ 12 февраля 2019

Используйте правило статического шаблона, чтобы избежать повторения кода и динамически генерируемых зависимостей.Что-то вроде этого должно сделать это:

.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)) \
)
...