如何定义makefile条件并在几个构建规则中重复使用?

时间:2019-04-14 02:42:29

标签: makefile eval variable-assignment gnu-make

这可能是Makefile Variable Assignment Executes Early的重复

是否可以定义条件并在以后重用?

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 个答案:

答案 0 :(得分:1)

您的代码存在的问题是$(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)

注意:您不需要评估,也可以在此处进行一些花哨的逃生。

答案 1 :(得分:1)

仅需添加一个注释:在配方中编写 bash 控制结构有点像代码恕我直言。用 make 惯用语代替它们,事情总是看起来更好。

这里的另一种气味是当您撒谎 make 时:您的makefile并未说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

那么当您要求 make 制作all时会发生什么?

  • all
    • 前提条件: make 需要构建main.pdf
      • 前提条件: make 构建other_things
        • blah-dy-blah…运行
      • 食谱:main已复制到main.pdf
    • 配方:all Success已打印

main的存在是通过 make 而不是 bash 来检查的。 这样做的一个很好的特点是,如果您以编程方式创建main,则可以轻松添加其他配方。 另一个是如果main.pdf已经是最新的,则复制不会发生。

由于您不再说谎 make , 这个makefile文件是并行安全的, 允许您使用-j n 标志。 您好!

答案 2 :(得分:-1)

我设法做到这一点:

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. How can I use Bash syntax in Makefile targets?
  2. How to use ifeq inside of a define in GNU Make?