2016-12-16 8 views
0

Вот Makefile, который я использую в настоящее время для создания целей с различными конфигурациями, т. Е. Я создаю различные пакеты программного обеспечения с одной и той же целью, либо сразу, либо индивидуально.Соответствие различным/нескольким частям цели Makefile

.PHONY: build test %.build %.test build-all test-all 
%.build %.test: PACKAGE = $* 

%.build: 
    @echo build $(PACKAGE) 

%.test: 
    @echo test $(PACKAGE) 

build-all: a.build b.build 
test-all: a.test b.test 

build: $(PACKAGE).build 
test: $(PACKAGE).test 

теперь я могу построить все пакеты с make build-all или отдельными пакетами, например, с make build PACKAGE=a. Однако я хотел бы, чтобы переключить тело из %.build и build и т.д. цели, как в следующем:

.PHONY: build test %.build %.test build-all test-all 
build: 
    @echo build $(PACKAGE) 

test: 
    @echo test $(PACKAGE) 

build-all: a.build b.build 
test-all: a.test b.test 

%.build %.test: PACKAGE = $* 
$(PACKAGE).%: $* 

Таким образом, соответствие логической модели полностью отделена от «главных» мишеней build и test, которые должны содержат фактические команды сборки; делая важные части Makefile более читаемыми. Однако последняя строка не работает должным образом, то есть работает make a.build, и, таким образом, make build-all должен запускать цель build с PACKAGE=a. Назначение переменной во второй строке работает, сопоставление целей в последней строке не выполняется.

Вопрос: Есть ли способ выразить цель соответствия как $(PACKAGE).%: $* или померяться отдельные части мишени, как %.%: $2?

+0

Я понимаю, что это всего лишь пример, но здесь нет ничего, что требовало бы сделать. Если это действительно так, то вы используете неправильный инструмент, просто напишите сценарий оболочки. В первом предложении на странице [make homepage] (https://www.gnu.org/software/make/) «GNU Make - это инструмент, который управляет генерацией исполняемых файлов ** и другими файлами, отличными от исходного программа из исходных файлов программы. ** « – user657267

+0

Я использую этот шаблон для сборки и тестирования исполняемых файлов из кода go, например, вызывая' go build' или 'go install' и' go test' для пакетов в разных subdirs. Я также использую этот шаблон для создания исполняемых файлов внутри изображений докеров и для создания самих изображений докеров. – Juve

ответ

0

Сначала вы, вероятно, хотите:

$(PACKAGE).% : % 

не используя $*, который является автоматической переменной и поэтому не имеет никакого значения, кроме внутри рецепта; вы не можете использовать его таким образом в списках предварительных условий.

Во-вторых, вы не можете сделать это в GNU make. Правило шаблона без рецепта - это не просто создание необходимых отношений, как это делает явное правило; вместо этого он удаляет правило шаблона. Поскольку у вас еще не было правила шаблона для $(PACKAGE).%, это в основном не-op. Кроме того, целевые переменные доступны только внутри рецепта, поэтому попытка использовать $(PACKAGE) в целевом определении и ожидать, что он примет значение из ранее заданной целевой переменной, не может работать.

Вы могли бы сделать что-то вроде этого, но это не полностью динамический (вам все еще нужно список пакетов и типов):

PACKAGES = a b 
TYPES = build test 

$(foreach T,$(TYPES),$(eval $(addsuffix .$T,$(PACKAGES)): $T)) 
+0

ОК, поэтому мне нужны 'foreach' и' eval'. Я хотел избежать этого. Тем не менее, это отвечает на мой вопрос. Благодаря! – Juve

0

Как пояснил Безумный учёный, проблема не может быть легко решена в GNU сделать. Для полноты картины, я хотел бы добавить и объяснить свое окончательное и более комплексное решение:

.PHONY: all build test clean %.build %.test build-all test-all 

PACKAGES = a b c e f g 
PACKAGE = a 

all: clean build-all test-all 

%.build %.test: PACKAGE = $* 

%.build: 
    @echo build $(PACKAGE) 

%.test: 
    @echo test $(PACKAGE) 

clean: 
    @echo remove build dir 

build-all: $(addsuffix .build, $(PACKAGES)) 
test-all: $(addsuffix .test, $(PACKAGES)) 

build: $(PACKAGE).build 
test: $(PACKAGE).test 

Это решение позволяет избежать eval и foreach и основано на моем первоначальный рабочий раствор, где динамические %.build и %.test целей содержат фактические сборки команды. Я добавил переменную PACKAGES, чтобы упростить добавление новых пакетов по умолчанию PACKAGE, чтобы предотвратить выполнение неверно сконфигурированных команд сборки, а также общие цели all и clean в качестве дополнений.

из командной строки, вы просто звоните makeall, clean, build PACKAGE=x, build-all и т.д., то есть, только статические целевые показатели, которые будут затем вызвать команды сборки в динамических объектов.Статические цели и две переменные также видны в автозавершении Bash/Zsh.

Я думаю, что это самый гибкий и доступный для чтения способ создания нескольких динамических целей.

+0

Если у вас есть только два типа цели ('build' и' test'), то их выписывание определенно проще и читаемо. – MadScientist

 Смежные вопросы

  • Нет связанных вопросов^_^