2016-12-30 2 views
2

У меня есть серия (десятки) проектов, которые состоят из большого количества контента в репозиториях git. Каждый репозиторий имеет god-подмодуль общего инструментария. Инструментарий содержит библиотеки и скрипты, необходимые для обработки репозиториев контента и создания опубликованного результата. Все репозитории помещаются на хост, который запускает CI и публикует результаты. Идея состоит в том, чтобы сохранить повторяющийся код до абсолютного минимума и в основном содержать контент в репозиториях и полагаться, а инструментарий - все это вместе для каждого проекта.Сделать переполнение¹ или «Как преодолеть цель?»

Каждый проект имеет верхний Makefile уровня, как правило, имеет только пару строк, например:

STAGE = stage 

include toolkit/Makefile 

Переменная ступень имеет некоторую информацию о том, на каком этапе это это частности, в котором определить, какие форматы получить встроенные. Практически все остальное обрабатывается 600-строчным Makefile в наборе инструментов. Для построения некоторых выходных форматов может потребоваться длинная цепочка зависимостей: прецессия источника может инициировать целевое правило, но чтобы добраться до цели, может быть 8-10 промежуточных зависимостей, когда различные файлы генерируются до того, как конечная цель может быть сделал.

Я столкнулся с несколькими ситуациями, где хочу полностью заменить (не просто расширить) целевое правило только в одном проекте. Цель запускается в середине цепочки зависимостей, но я хочу сделать что-то совершенно другое для этого шага.

Я попытался просто заменить цель в верхнем Makefile уровня:

STAGE = stage 

%-target.fmt: 
    commands 

include toolkit/Makefile 

Это специально документирован не быть поддержан, но заманчиво это работает когда-то время. Я попытался изменить порядок объявления пользовательской цели и включить, но это, похоже, не влияет на это. В случае, если это имеет значение, да, важно использовать шаблоны в целях.

Иногда полезно иметь make-файл, который в основном похож на другой файл makefile. Вы часто можете использовать директиву «include», чтобы включить ее в другую, и добавить больше целей или определений переменных. Однако для двух make-файлов недействительно давать разные рецепты для одной и той же цели.

Интересно, если я ставлю пользовательские функции в верхнем Makefile уровня ниже включаемый я могу переопределить функции из набора инструментов, такие, что $(call do_thing) будет использовать мое переопределение:

STAGE = stage 

include toolkit/Makefile 

define do_thing 
    commands 
endef 

Однако же не делает похоже, верно для целей. Я знаю о two colon syntax, но я не хочу просто продлить существующую цель с большим количеством зависимостей. Я хочу полностью заменить цель другим способом создания одного и того же файла.

Я думал об использовании рекурсивных вызовов для создания as suggested in the documentation, но тогда среда, включающая вспомогательные функции, которые широко настраиваются в инструментальном файле Makefile, не будет доступна ни одному из объектов в Makefile верхнего уровня. Это будет показательный стоппер.

Есть ли какой-либо способ сделать исключение для меня? Может ли он быть принужден к переопределению целей? Я использую исключительно последние версии GNU-Make и не слишком озабочен переносимостью.В противном случае существует еще один концептуальный способ достижения тех же целей?

¹ Моему мозгу сегодня не хватает кофе. При попытке открыть переполнения стека, чтобы задать этот вопрос, я набранный makeoverflow.com в моем браузере и был смущен, почему автозавершения не пинал в

+0

Я получаю это правильно, ваш инструментарий также содержит правило '% -target.fmt' с некоторыми командами по умолчанию, которые вы хотите переопределить? – valir

+0

@valir Да. Оба предпосылки и рецепт отличаются друг от друга, но имя правила одинаковое, и я хочу полностью переопределить тот из набора инструментов, который находится на верхнем уровне. – Caleb

ответ

1

Обновленный ответ. Если ваш рецепт имеет зависимости, то они не могут быть переопределены по умолчанию. Тогда $ (Eval) может спасти вас, как это:

В инструментарии есть определение макроса с родовым правилом:

ifndef TARGET_FMT_COMMANDS 
define TARGET_FMT_COMMANDS 
    command1 # note this these commands should be prefixed with TAB character 
    command2 
endef 
endif 

define RULE_TEMPLATE 
%-target.fmt: $(1) 
    $$(call TARGET_FMT_COMMANDS) 

endef 

# define the default dependencies, notice the ?= assignment 
TARGET_DEPS?=list dependencies here 

# instantiate the template for the default case 
$(eval $(call RULE_TEMPLATE,$(TARGET_DEPS))) 

Затем в коде вызова, просто определить TARGET_FMT_COMMANDS и TARGET_DEPS перед включением инструментария и это должен сделать трюк.

(пожалуйста, простите имена переменных определяются /, они являются лишь примером)

Первоначальный ответ: Ну, я пишу это в инструментарии:

define TARGET_FMT_COMMANDS 
    command1 # note this these commands should be prefixed with TAB character 
    command2 
endef 

%-target.fmt: 
    $(call TARGET_FMT_COMMANDS) 

вы можете просто переопределить TARGET_FMT_COMMANDS после include toolkit/Makefile

Трюк заключается в систематическом значении символа TAB перед командами внутри определения, если вы не получите wei rd ошибок.

Вы также можете указать параметры, как обычно.

+0

Я думал. Его, но, к сожалению, на этом пути вы отказываетесь от обычных функций make. Это не позволит мне переопределить предпосылки и, следовательно, вызвать другие возможные цели, требующие вызова. Это работает, чтобы обмануть рецепт, чтобы иметь другой контент, но цель не была переопределена. – Caleb

+0

О, не было никаких упоминаний о предварительных требованиях в вопросе. Вам не повезло с ними, поскольку GNU Make расширяет их сразу же, когда сталкивается с определением правила, поэтому, если вы используете некоторые $ (DEPS), затем переопределяете DEPS позже, вы пропустите последний AFAICT. – valir

+0

Но подождите, может быть, решение для вас. Используйте расширение макроса $ (eval). Я отредактирую свой ответ, поскольку он длиннее комментария, – valir

0

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

в инструментарии/Makefile:

test: depend depend1 depend2 
    @echo test toolkit 
... 

в Makefile:

include toolkit/Makefile 

depend1 depend2: ; 

test: depend 
    @echo test 

Обратите внимание, как depend1 и depend2 теперь пустыми цели, поэтому команда испытателя цели переопределяется и зависимости эффективно переопределены как показано Что ж.

+0

. В прошлом году мое тестирование показало, что это работало некоторое время, но оно не было согласованным (см. Мой комментарий в вопросе).Что-то о том, как сделать парсинг себя несколько раз, он может или не может анализировать вещи для того, чтобы переопределить вашу цель, это может привести к противоположному. То, что срабатывает, может быть таким же простым, как расширение других переменных или функций в несвязанных целях, поэтому, хотя этот хак может получить вас за пару фиксированных целей, во что-то сложном или динамичном (особенно с .SECONDEXPANSION :), он развалится и сделает неожиданные вещи на вас. – Caleb

+0

Спасибо за головы, стыдно, что Makefiles на самом деле не предназначались для использования таким образом, так как кажется, что это будет распространенный случай использования. –

+0

Ya способ, которым производят процедуры парсера, фактически вводит несколько ненормальных поведений. Например, я обнаружил, что если я скопировал свои переопределения, как вы описали здесь и перед _and_ после включения, они имели больше шансов переубедить, потому что в зависимости от того, сколько проходов оно анализируется (возможно, определяется количеством слоев расширения переменной присутствовали?) иногда предыдущий иногда более поздний из них фактически делал переопределение случаем. Но это было слишком фруктово, чтобы использовать в производстве таким образом. – Caleb

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