Вопрос по makefile, gnu-make – говоря 'make', чтобы игнорировать зависимости, когда верхняя цель была создана

19

Я использую трубопровод следующего типа:

digestA: hugefileB hugefileC
    cat $^ > [email protected]
    rm $^

hugefileB:
    touch [email protected]

hugefileC:
    touch [email protected]

ЦелиhugefileB а такжеhugefileC очень большие и требуют много времени для вычислений (и нуждаются в силе Make). Но однаждыdigestA был создан, нет необходимости сохранять его зависимости: он удаляет эти зависимости, чтобы освободить место на диске.

Теперь, если я призову «сделать» снова,hugefileB а такжеhugefileC будет восстановлен, тогда какdigestA уже в порядке.

Есть ли способ сказать "сделать"? чтобы избежать перекомпиляции зависимостей?

ПРИМЕЧАНИЕ. Я не хочу строить две зависимости внутри правил для "digestA".

@Beta & quot; Вы хотите перестроить digestA только тогда, когда он еще не существует & quot ;: да Pierre
Вы хотите восстановитьdigestA только когда он еще не существует, верно? Beta

Ваш Ответ

4   ответа
25

использование& quot; промежуточные файлы & quot; Особенность GNU Make:

Intermediate files are remade using their rules just like all other files. But intermediate files are treated differently in two ways.

The first difference is what happens if the intermediate file does not exist. If an ordinary file b does not exist, and make considers a target that depends on b, it invariably creates b and then updates the target from b. But if b is an intermediate file, then make can leave well enough alone. It won't bother updating b, or the ultimate target, unless some prerequisite of b is newer than that target or there is some other reason to update that target.

The second difference is that if make does create b in order to update something else, it deletes b later on after it is no longer needed. Therefore, an intermediate file which did not exist before make also does not exist after make. make reports the deletion to you by printing a rm -f command showing which file it is deleting.

Ordinarily, a file cannot be intermediate if it is mentioned in the makefile as a target or prerequisite. However, you can explicitly mark a file as intermediate by listing it as a prerequisite of the special target .INTERMEDIATE. This takes effect even if the file is mentioned explicitly in some other way.

You can prevent automatic deletion of an intermediate file by marking it as a secondary file. To do this, list it as a prerequisite of the special target .SECONDARY. When a file is secondary, make will not create the file merely because it does not already exist, but make does not automatically delete the file. Marking a file as secondary also marks it as intermediate.

Итак, добавление следующей строки в Makefile должно быть достаточно:

.INTERMEDIATE : hugefileB hugefileC

Вызов make в первый раз:

$ make
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC

И в следующий раз:

$ make
make: `digestA' is up to date.
большое спасибо. Это очень полезно. Ваше решение было приведено здесь:plindenbaum.blogspot.com/2012/08/… Pierre
Есть ли у вас понимание того, почему .secondary не является поведением по умолчанию для всех целей?
@Pierre, добро пожаловать. Спасибо за цитату!
@Pierre, хм, звучит интересно, но, подумав, я не смог ответить на ваш вопрос. Единственная слегка связанная часть руководстваsays: & quot;.SECONDARY без предварительных условий приводит к тому, что все цели рассматриваются как второстепенные (то есть ни одна цель не удаляется, поскольку она считается промежуточной). Но это ничего не говорит о причинах поведения по умолчанию.
3

Если вы отметитеhugefileB а такжеhugefileC какпромежуточные файлы, вы получите поведение, которое вы хотите:

digestA: hugefileB hugefileC
        cat $^ > [email protected]

hugefileB:
        touch [email protected]

hugefileC:
        touch [email protected]

.INTERMEDIATE: hugefileB hugefileC

Например:

$ gmake
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC
$ gmake
gmake: `digestA' is up to date.
$ rm -f digestA
$ gmake
touch hugefileB
touch hugefileC
cat hugefileB hugefileC > digestA
rm hugefileB hugefileC

Обратите внимание, что вам не нужно явноеrm $^ команда больше - gmake автоматически удаляет промежуточные файлы в конце сборки.

1

Я бы порекомендовал вам создавать файлы псевдокеша, которые создаютсяhugefileB а такжеhugeFileC цели.

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

-1

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

Воссоздание их как пустых не помогает, потому чтоmake Затем предположим, что пустые файлы полностью собраны.

Если есть способ объединить дайджесты, то вы можете создать по одному из каждого из огромных файлов, которые затем сохраняются, и огромный файл автоматически удаляется, поскольку он является промежуточным.

В Вопросе конкретно говорится, что автор не хочет удалять файлы из-за их огромного размера. (P.S., я думаю из того факта, что спрашивающий говорит «я запускаю следующий тип конвейера», это означает, что предоставленный код является просто примером кода, и спрашивающий фактически не просто создает пустые файлы.)

Похожие вопросы