Как определить условие make-файла и повторно использовать его в нескольких правилах сборки? - PullRequest
0 голосов
/ 14 апреля 2019

Это может быть или не быть дубликатом Назначение переменной Makefile выполняется рано

Возможно ли определить условие и использовать его позже?

MAIN_FILE_PATH := main

define copy_resulting_pdf=
if [[ -f "${MAIN_FILE_PATH}" ]] \
then \
    cp "${MAIN_FILE_PATH}" "${MAIN_FILE_PATH}.pdf"; \
else \
    $(error Error: The PDF ${MAIN_FILE_PATH} was not generated!); \
fi
endef

all:
    echo doing other things.
    $(copy_resulting_pdf)


other:
    echo doing more other things.
    $(copy_resulting_pdf)

Когдазапустите это, make даже не начнет создавать правило all.Это просто выбрасывает:

Makefile:14: *** Error: The PDF main was not generated!.  Stop.

Ответы [ 3 ]

1 голос
/ 14 апреля 2019

Проблема с вашим кодом в том, что $(error ...) также является текстовой заменой . Таким образом, любое расширение $(copy_resulting_pdf) также приводит к рекурсивному расширению всех встроенных переменных и функций, включая $(error ...). Обычно $(error ...) охраняется условными обозначениями make (такими как ifeq) или другими подстановками (такими как $(if ...)). Но в вашем случае он был «защищен» условной оболочкой, что ничего не значит сделать.

Но следующее работает так, как и ожидалось:

MAIN_FILE_PATH := main

define copy_resulting_pdf
    echo Printing results...
    if [[ -f "${MAIN_FILE_PATH}" ]]; then \
        printf 'Copying PDF...\n'; \
        cp "${MAIN_FILE_PATH}" "${MAIN_FILE_PATH}.pdf"; \
    else \
        printf "Error: The PDF \"${MAIN_FILE_PATH}\" was not generated!\n"; \
        exit 1; \
    fi
endef

.PHONY: all other
all:
    @echo doing other things.
    @$(copy_resulting_pdf)

other:
    @echo doing more other things.
    @$(copy_resulting_pdf)

Примечание: вам не нужен eval и некоторые необычные побеги здесь.

1 голос
/ 17 апреля 2019

Просто добавьте одну заметку: запись bash управляющих структур в рецепте - это немного запах кода ИМХО. Вещи всегда выглядят лучше, если заменить их на make идиом.

Другой запах здесь - когда вы врете make : ваш make-файл не говорит, что рецепт all создает main.pdf, например.

MAIN_FILE_PATH := main

.PHONY: other_things
other_things:
    blah-dy-blah…

${MAIN_FILE_PATH}.pdf: | other_things
${MAIN_FILE_PATH}.pdf: ${MAIN_FILE_PATH}
    cp $< $@

.PHONY: all
all: ${MAIN_FILE_PATH}.pdf
    echo $@ Success

Так что же происходит, когда вы просите заставить сделать all?

  • all:
    • предварительное условие: сделать необходимо построить main.pdf
      • предварительное условие: make builds other_things
        • blah-dy-blah… работает
      • рецепт: main копируется в main.pdf
    • рецепт: all Success напечатано

Наличие main проверяется make вместо bash . Хорошей характеристикой этого является то, что вы можете легко добавить другой рецепт, если у вас есть программный способ создания main. Другая причина заключается в том, что копия не выполняется, если main.pdf уже обновлен.

Так как вы больше не врете сделать , этот make-файл параллельно безопасен, позволяя вам использовать флаг -j n . Привет производительность.

0 голосов
/ 14 апреля 2019

Мне удалось сделать это с помощью:

SHELL := /bin/bash
MAIN_FILE_PATH := main

define copy_resulting_pdf=
echo Printing results...
eval "if [[ -f "${MAIN_FILE_PATH}" ]]; then \
    printf 'Coping PDF...\\n'; \
    cp "${MAIN_FILE_PATH}" "${MAIN_FILE_PATH}.pdf"; \
else \
    printf \"Error: The PDF "${MAIN_FILE_PATH}" was not generated!\\n\"; \
    exit 1; \
fi"
endef

all:
    echo doing other things.
    $(copy_resulting_pdf)

Запуск:

echo doing other things.
doing other things.
echo Printing results...
Printing results...
eval "if [[ -f "main" ]]; then printf 'Coping PDF...\\n'; cp "main" "main.pdf"; else printf \"Error: The PDF "main" was not generated!\\n\"; exit 1; fi"
Error: The PDF main was not generated!
make: *** [setup/makefile.mk:17: all] Error 1

Ссылки:

  1. Как использовать синтаксис Bash в целях Makefile?
  2. Как использовать ifeq внутри определения в GNU Make?
...