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)