如何定义 makefile 条件并在多个构建规则中重用它?
How define a makefile condition and reuse it in several build rules?
这可能是也可能不是 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.
我用这个做到了:
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
参考文献:
- How can I use Bash syntax in Makefile targets?
- How to use ifeq inside of a define in GNU Make?
您的代码的问题是 $(error ...)
也是一个 文本替换 。所以 $(copy_resulting_pdf)
的任何扩展也会导致所有嵌入变量和函数的递归扩展,包括 $(error ...)
。通常,$(error ...)
由 make 条件(例如 ifeq
)或其他替换(例如 $(if ...)
)保护。但在你的情况下,它是 "guarded" by shell 有条件的,这意味着没有什么可做的。
但下面的工作与预期的一样:
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 和一些花哨的转义符。
只需添加一个注释:恕我直言,在配方中编写 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 标志。
你好性能。
这可能是也可能不是 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.
我用这个做到了:
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
参考文献:
- How can I use Bash syntax in Makefile targets?
- How to use ifeq inside of a define in GNU Make?
您的代码的问题是 $(error ...)
也是一个 文本替换 。所以 $(copy_resulting_pdf)
的任何扩展也会导致所有嵌入变量和函数的递归扩展,包括 $(error ...)
。通常,$(error ...)
由 make 条件(例如 ifeq
)或其他替换(例如 $(if ...)
)保护。但在你的情况下,它是 "guarded" by shell 有条件的,这意味着没有什么可做的。
但下面的工作与预期的一样:
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 和一些花哨的转义符。
只需添加一个注释:恕我直言,在配方中编写 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
- 先决条件:make 构建
- 食谱:
all Success
打印
- 先决条件:make 需要构建
main
的存在由 make 而不是 bash 检查。
这样做的一个好处是,如果您有创建 main
的编程方式,则可以轻松添加另一个配方。
另一个是如果 main.pdf
已经是最新的,则不会发生复制。
既然你不再对 make撒谎,
这个 makefile 是并行安全的,
允许您使用 -j
n 标志。
你好性能。