Сделать цель, содержащую подкаталог, на основе целевых зависимостей

Скажем, у меня есть список исходных файлов, и каждый из них должен быть скомпилирован в отдельные двоичные файлы:

SRCS = abcd.c efgh.c ijkl.c

И я хочу, чтобы выходные файлы находились в отдельных подкаталогах на основе таких имен файлов:

  • построить/abcd/abcd
  • сборка/efgh/efgh
  • построить/ijkl/ijkl

Я думаю, что правило статического шаблона - это путь. Псевдо-правило make может выглядеть примерно так:

$(TARGETS): build/%/%: %.c
    # stuff ...

Я начал с составления списка подкаталогов на основе имен файлов:

DIRS = $(SRCS:%.c=build/%)

Итак, теперь у нас есть DIRS = build/abcd build/efgh build/ijkl. Я подумал, что теперь могу составить список целей примерно так:

BLDS = $(DIRS:%=%/$(basename %))

Но, конечно, это не работает, поскольку подстановочный знак нельзя использовать несколько раз в шаблоне. Поэтому я сейчас застрял на BLDS = build/abcd/% build/efgh/% build/ijkl/%.

Очевидно, я совершенно неправильно об этом говорю. Как бы вы это сделали?

На данный момент я пишу каждое правило явно, что начинает становиться немного утомительным:

compile = # command to do stuff
BD = build

all: $(BD)/abcd/abcd $(BD)/efgh/efgh $(BD)/ijkl/ijkl

$(BD)/abcd/abcd: abcd.c
    $(call compile)

$(BD)/efgh/efgh: efgh.c
    $(call compile)

$(BD)/ijkl/ijkl: ijkl.c
    $(call compile)

clean:
    rm -rf build/*

.PHONY: all

person James    schedule 22.12.2013    source источник


Ответы (1)


Я считаю, что это делает то, что вы хотите:

SRCS:=abcd.c efgh.c ijkl.c

# We could fold NAMES into BLDS's definition if NAMES is not used elsewhere.
NAMES:=$(SRCS:%.c=%)

BLDS:=$(foreach name,$(NAMES),$(subst foo,$(name),build/foo/foo))

# We don't use DIRS below but the question had this variable.
DIRS:=$(dir $(BLDS))

TARGETS:=$(BLDS)

.PHONY: all
all: $(TARGETS)

.SECONDEXPANSION:
$(TARGETS): $$(notdir $$@).c
    @echo Build $@ from $^
    mkdir -p $(dir $@)
    touch $@

Есть два важных изменения. Во-первых, изменить порядок создания переменных и использовать subst, что позволяет многократно заменять совпадающую строку. Второй — использовать дополнительное расширение, чтобы правила для каждой из ваших целей. Изначально вы используете шаблон с двумя %, но в документации говорится:

Шаблонное правило выглядит как обычное правило, за исключением того, что его цель содержит символ `%' (ровно один из них).

(Выделение добавлено.)

Я проверил это с поддельными файлами abcd.c efgh.c и ijkl.c и получил следующий результат:

$ make
Build build/abcd/abcd from abcd.c
mkdir -p build/abcd/
touch build/abcd/abcd
Build build/efgh/efgh from efgh.c
mkdir -p build/efgh/
touch build/efgh/efgh
Build build/ijkl/ijkl from ijkl.c
mkdir -p build/ijkl/
touch build/ijkl/ijkl
person Louis    schedule 27.12.2013
comment
Эй, большое спасибо за это. На самом деле я никогда раньше не слышал о вторичном расширении в make, так что это было действительно поучительно. - person James; 31.12.2013