2015-03-02 5 views
1

Я не знаю, как определить программные цели в GNU Make. Как это возможно?Как программно определить цели в GNU Make?

Иногда можно уйти with alternate methods. Однако способность определять программные цели в Make-файлах очень важна для написания и организации сложных производственных правил с помощью make. Примеры сложных правил производства находятся в системе сборки FreeBSD или в Makefile библиотек, таких как BSD Owl

main differences между сценариями оболочки и Makefiles являются:

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

  • В Makefile, это смешно легко украсить процедуру советом или украсить ее крючками, в то время как это практически невозможно в сценариях оболочки.

Например, очень простой и полезный шаблон является следующее:

build: pre-build 
build: do-build 
build: post-build 

Это представляет build мишени в виде композита из трех мишеней, одна из которых содержит фактические инструкции do-build и два других, которые являются крюки, выполненные до и после do-build. Эта модель используется во многих системах сборки, написанных для BSD Make, которая, кстати, позволяет программное определение целей, так что можно написать в пакете:

.for _target in configure build test install 
.if !target(${_target}) 
${_target}: pre-${_target} 
${_target}: do-${_target} 
${_target}: post-${_target} 
.endif 
.endfor 

условие введено .if/.endif блока позволяет пользователю использовать его собственное определение любого ${_target}.

Каким будет перевод этого фрагмента для GNU Make?

+0

Следует отметить, что в GNU вы не ** получаете гарантию в порядке между целевыми условиями (хотя без '-j', я считаю, что это безопасно предположить, что вы это делаете), поэтому ваши« крючки » «не обязательно делать то, что вы хотите. –

+0

@ EtanReisner Конечно, но это напрямую не связано с вопросом, и я пропустил это, чтобы все было просто. В BSD Make, например, говорят: '.ЗАКАЗ: предварительная сборка «строить-строить пост-строить» для обеспечения последовательной обработки указанных целей. –

+0

С или без '-j' make всегда будет переходить список предварительных условий в том же порядке. Это просто, что с помощью '-j' make не будет ждать, пока предыдущие (не зависимые) предпосылки не закончатся, прежде чем запускать новые (это может привести к тому, что некоторые задания будут выполняться в другом порядке из-за отсутствия необходимых условий). Без '-j' make _does_ гарантирует сборку в порядке. – MadScientist

ответ

2

FWIW вот сделает эквивалентный синтаксис для

.for _target in configure build test install 
.if !target(${_target}) 
${_target}: pre-${_target} 
${_target}: do-${_target} 
${_target}: post-${_target} 
.endif 
.endfor 

В принципе, вы хотите сделать увидеть что-то вроде этого фрагмента кода:

build: pre-build 
build: do-build 
build: post-build 

и аналогично для configure, test и install. Это предполагает цикл с eval где-то:

define makerule = 
    $1: pre-$1 
    $1: do-$1 
    $1: post-$1 
endef 

targets := configure build test install 

$(foreach _,${targets},$(eval $(call makerule,$_))) 

(играть с этим, изменение eval к info). Осторожно с этими закрытиями!

FWIW, вот расширение foreach:

  • сделать расширяет список для итерироваться над
    • ${targets} становится configure, build, test и install
    • Мы $(foreach _,configure build test install,$(eval $(call makerule,$_)))
  • _ устанавливается в первое значение, configure.
  • сделать расширяет $(eval $(call makerule,configure))
  • Для оценки eval, сделать расширяет $(call makerule,configure)
    • Она делает это путем установки 1 к configure, а также расширение ${makerule}, которая производит 3 строки текста:
      configure: pre-configure
      configure: do-configure
      configure: post-configure
  • $(eval) идет на работу, читать этот текст в качестве сделать синтаксис
  • Обратите внимание, что расширение $(eval) пусто! Вся его работа выполнена как побочный эффект. Промыть, намыть, промыть, повторить.

Пожалуйста, обратите внимание: я согласен со всеми другими комментаторами: ваша картина плохо делают. Если ваш make-файл не является -j безопасным, то это сломанный (отсутствующие зависимости).

+0

Благодарим вас за полезный ответ! Как я уже говорил в некоторых других комментариях, я хорошо разбираюсь в проблемах параллелизма и опускал их из моего вопроса, потому что меня интересовали только программные аспекты. Но хорошо, что новички читают ваш баннер параллелизма! : D –

2

Сначала эта структура недействительна, если вы когда-либо хотите поддерживать параллельные сборки; если вы вызываете make с опцией -j, он будет запускать все три правила предварительного требования одновременно, потому что, хотя все они должны быть заполнены до build, ни одна из них не зависит друг от друга, поэтому нет определенного порядка (т. е. t сказать, что pre-build должен быть заполнен до do-build может работать).

Во-вторых, GNU make имеет ряд объектов для programmatically defining rules. Одна вещь, которую GNU make не имеет, в настоящее время - это способность искать цели, которые уже определены, поэтому нет прямой аналогии с .if !target(...).

Однако вы можете узнать, была ли переменная определена или нет с использованием переменной .VARIABLES. Таким образом, одним из способов было бы определить переменную, если вы хотите, чтобы ваша собственная цель, а затем проверить генератор правил.

+0

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

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