Как добавить шаблонную зависимость - PullRequest
0 голосов
/ 27 июня 2018

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

file1.out:
    cat source.txt | grep "hello,world" > file1.out

file2.out:
   cat source.txt > file2.out

%.out: source.txt

Моя цель - добавить source.txt в качестве зависимости к file1.out и file2.out (а также ко всем другим * .out файлам, которые я могу добавить позже). Буду признателен за любой совет (извиняюсь, если это основной вопрос, но я не смог найти ничего связанного с инструкциями по сборке.

1 Ответ

0 голосов
/ 27 июня 2018

Я предполагаю, что вы используете GNU make. Ваша проблема связана с тем, как GNU make обрабатывают шаблонные (неявные) правила. Из введения в раздел Алгоритм поиска неявных правил из GNU make manual :

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

Итак, ваше шаблонное правило не учитывается для целей file1.out и file2.out, поскольку они являются целями обычных правил с рецептом .

Решение: вы можете перечислить цели *.out в переменной и использовать ее, чтобы объявить, что все они зависят от source.txt:

OUTFILES := $(wildcard *.out)

$(OUTFILES): source.txt

file1.out:
    cat source.txt | grep "hello,world" > file1.out

file2.out:
    cat source.txt > file2.out

Если цели могут находиться в подкаталогах, вы можете использовать функцию shell make для вызова find вместо использования функции wildcard make:

OUTFILES := $(shell find . -type f -name '*.out')

Примечания:

  1. Это будет работать только для существующих *.out файлов. Make не может придумать список целевых файлов, если они еще не существуют (и, следовательно, их можно найти по make), и если вы сами не предоставили список в make-файле.

  2. Ваш рецепт cat source.txt | grep "hello,world" > file1.out потерпит неудачу с ненулевым статусом выхода, если файл source.txt не содержит строку hello,world. И если это произойдет, make завершит работу с сообщением об ошибке. Вы можете избежать этого с помощью:

    cat source.txt | grep "hello,world" > file1.out || true
    
  3. Автоматические переменные могут быть очень полезны. Если source.txt является единственной предпосылкой ваших целей, вы можете упростить все это с помощью таких рецептов, как:

    file1.out:
        cat "$<" | grep "hello,world" > "$@" || true
    
    file2.out:
        cat "$<" > "$@"
    

    ($@ расширяется как цель правила, а $< расширяется как первая предпосылка). Это позволяет избежать опечаток и делает рецепты более общими. Иногда вы можете даже иметь один и тот же рецепт для нескольких целей:

    file1.out file3.out:
        cat "$<" | grep "hello,world" > "$@" || true
    
...