Как заставить определенные группы целей всегда запускаться последовательно?

Есть ли способ просить gmake никогда не запускать две цели из параллельного набора?

Я не хочу использовать .NOTPARALLEL, потому что он заставляет весь Makefile запускаться последовательно, а не только требуемую часть.

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


Причиной, по которой мне это нужно, является то, что (только) часть моего Makefile вызывает ghc --make, которая сама заботится о своих зависимостях. И это невозможно запустить параллельно в двух разных целях, потому что, если две цели разделяют некоторую зависимость, они могут переписывать друг друга .o. (Но ghc отлично с тем, чтобы быть вызванным последовательно.)

Обновление: Чтобы дать конкретный пример. Скажем, мне нужно скомпилировать две программы в файле Makefile:

  • prog1 зависит от prog1.hs и mylib.hs;
  • prog2 зависит от prog2.hs и mylib.hs.

Теперь, если я вызываю ghc --make prog1.hs, он проверяет свои зависимости, компилирует как prog1.hs, так и mylib.hs в свои соответствующие файлы объектов и интерфейсов, а ссылки prog1. То же самое происходит, когда я вызываю ghc --make prog2.hs. Поэтому, если две команды будут работать параллельно, одна перезапишет mylib.o другой, что приведет к ее неудаче.

Однако мне нужно, чтобы ни prog1 не зависело от prog2 и наоборот, потому что они должны компилироваться отдельно. (На самом деле они очень большие с большим количеством модулей и требуют компиляции их всех замедлений развития значительно.)

Ответ 1

Хммм, мог бы получить немного больше информации, так что это просто удар в темноте.

Make на самом деле не поддерживает это, но вы можете последовательно использовать две цели несколькими способами. Во-первых, реальное использование для рекурсивного make:

targ1: ; recipe1...
targ2: ; recipe2...

both-targets:
    ${MAKE} targ1
    ${MAKE} targ2

Итак, здесь вы можете просто make -j both-targets, и все в порядке. Хрупкий, хотя, поскольку make -j targ1 targ2 все еще работает параллельно. Вместо этого вы можете использовать зависимости:

targ1: ; recipe1...
targ2: | targ1 ; recipe2...

Теперь make -j targ1 targ2 делает то, что вы хотите. Недостаток? make targ2 всегда будет пытаться сначала построить targ1 (последовательно). Это может (или не обязательно) быть шоу-стопором для вас.

ИЗМЕНИТЬ

Еще одна неудовлетворительная стратегия - явно посмотреть на $MAKECMDGOALS, в котором перечислены цели, указанные вами в командной строке. Тем не менее хрупкое решение, так как оно нарушается, когда кто-то использует зависимости внутри Makefile для создания вещей (это не необоснованное действие).

Скажем, ваш файл makefile содержит две независимые цели targ1 и targ2. В основном они остаются независимыми, пока кто-то не укажет в командной строке, что они должны быть созданы. В этом конкретном случае вы нарушаете эту независимость. Рассмотрим этот фрагмент:

$(and $(filter targ1,${MAKECMDGOALS)),$(filter targ2,${MAKECMDGOALS}),$(eval targ1: | targ2))

Urk! Что здесь происходит?

  • Сделать оценку $(and)
  • Сначала нужно развернуть $(filter targ1,${MAKECMDGOALS})
  • Iff targ1 указан, он продолжает расширяться $(filter targ2,${MAKECMDGOALS})
  • Iff targ2 также был указан, он продолжает расширять $(eval), вызывая сериализацию targ1 и targ2.
    • Обратите внимание, что $(eval) расширяется до нуля (вся его работа была выполнена как побочный эффект), так что исходный $(and) всегда ничего не меняет, не вызывая синтаксической ошибки.

Тьфу!

[Теперь, когда я набрал это, значительно проще prog2: | $(filter prog1,${MAKECMDGOALS}) происходит со мной. О, хорошо.]

YMMV и все такое.

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

Ответ 2

Так как я застрял в той же проблеме, вот еще один указатель в том направлении, в котором make не предоставляет описываемой функции:

Из GNU Make Manual:

Важно соблюдать осторожность при параллельном выполнении (ключ -j, см. Параллельное выполнение) и архивы. Если несколько AR-команд одновременно запускаются в одном архиве, они не будут знать друг о друге и могут повредить файл.

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

То, что вы пытаетесь, и то, что я пытаюсь (используя make для вставки данных в базу данных SQLite3), страдает от одной и той же проблемы.