GNU Makefile: несколько выходов из одного правила + предотвращение удаления промежуточных файлов
Это вопрос продолжения вопроса здесь. Проблема в том, что существует правило, генерирующее несколько выходов из одного входа, и команда требует много времени, поэтому мы предпочли бы избежать перерасчета. Теперь есть дополнительный поворот, который мы хотим, чтобы файлы не удалялись в качестве промежуточных файлов, а правила включают в себя подстановочные знаки, позволяющие использовать параметры.
Предлагаемое решение состояло в том, что мы установили следующее правило:
file-a.out: program file.in
./program file.in file-a.out file-b.out file-c.out
file-b.out: file-a.out
@
file-c.out: file-b.out
@
Затем вызов make file-c.out
создает оба, и мы избегаем проблем с запуском make
параллельно с переключателем -j
. Пока все хорошо.
Проблема заключается в следующем. Поскольку вышеупомянутое решение устанавливает цепочку в DAG, make
считает это по-другому; файлы file-a.out
и file-b.out
рассматриваются как промежуточные файлы, и по умолчанию они удаляются как ненужные, как только file-c.out
готов.
Способ избежать этого упоминался где-то здесь и состоит из добавления file-a.out
и file-b.out
в качестве зависимостей целевой .SECONDARY
, которая не позволяет им удаляться. К сожалению, это не решает мое дело, потому что мои правила используют шаблоны подстановочных знаков; в частности, мои правила выглядят примерно так:
file-a-%.out: program file.in
./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out
file-b-%.out: file-a-%.out
@
file-c-%.out: file-b-%.out
@
чтобы можно было передать параметр, который включается в имя файла, например, запустив
make file-c-12.out
Решение, предлагаемое в документации make
, заключается в том, чтобы добавить эти как неявные правила в список зависимостей .PRECIOUS
, тем самым не удаляя эти файлы.
Решение с .PRECIOUS
работает, но также предотвращает удаление этих файлов, когда правило выходит из строя, а файлы неполны. Есть ли другой способ сделать эту работу?
Чтобы решить эту проблему, нужно определить цель .SECONDARY
без каких-либо предварительных условий, т.е.
.SECONDARY:
который сообщает make
, что все файлы должны рассматриваться как вторичные и, следовательно, не удаляться, если только когда make
не будет прервано или не будет выполнено правило. К сожалению, это не позволяет выбрать подмножество правил с подстановочными знаками, чтобы работать таким образом, поэтому я считаю это всего лишь взломом (хотя это и полезно).
Ответы
Ответ 1
Простейшая вещь
file-a-%.out file-b-%.out file-c-%.out: program file.in
./program $* file.in file-a-$*.out file-b-$*.out file-c-$*.out
сделает именно то, что вы хотите.
(Правила шаблонов с несколькими целями отличаются от обычного правила с несколькими целями, о которых вы просили здесь. См. пример бизона в сделать руководство.)
Ответ 2
Если вместо одного файла file.in ваши выходы были сгенерированы из файла предварительных условий, включающего в себя стержень, т.е.
file-a.out: program file-%.in
./program file-$*.in file-a-$*.out file-b-$*.out file-c-$*.out
вы можете создать список всех возможных целевых совпадений:
inputs = $(wildcard file-*.in)
secondaries = $(patsubst file-%.in,file-a-%.out,$(inputs)) \
$(patsubst file-%.in,file-b-%.out,$(inputs))
Аналогично, если стержень исходит из конечного множества:
batchnos = 17 18 19 20
batchnos = $(shell seq 17 20)
secondaries = $(patsubst %,file-a-%.out,$(batchnos)) $(patsubst %,file-b-%.out,$(batchnos))
Затем просто добавьте их как prereqs в цель .SECONDARY
.SECONDARY: $(secondaries)