Makefile 的 define 指令中的分号终止有什么作用?
What does semicolon-termination inside a Makefile's define directive do?
我想知道以下 makefile 片段中的分号有什么作用:
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim);
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR));
endef
Hooks/Prepare/Post+=Package/xxsim/CopyLocalFiles
以防万一,makefile 用于 OpenWRT 构建系统中的自定义组件 (xxsim)。
我希望分号是不必要的,例如,这个例子 (source):
define two-lines =
echo foo
echo $(bar)
endef
但是,如果我们在没有这些分号的情况下构建,对 cp
的第二次调用将失败(对 cp
的第一次调用隐式成功):
[CP] files/Adapter20Sim.h
[CP] files/Adapter20Sim.cpp
cp: target ' [MKDIR] xxsim docinfo in staging dir' is not a directory
很明显,cp接收到了错误的输入参数。那么,添加分号的实际作用是什么?为什么在存在分号的情况下组件可以正确构建?
更新: 在下面添加了构建系统上下文,这源于 Etan 在评论中的帮助:
Hooks/Prepare/Post
用在 foreach 语句中,其中它的每个值都用在调用函数中:
$(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
foreach
的上下文:
$(STAMP_PREPARED) : export PATH=$$(TARGET_PATH_PKG)
$(STAMP_PREPARED):| $(PKG_BUILD_DIR) $(STAGING_DIR)/include $(STAGING_DIR)/lib$(LIB_SUFFIX)
$(foreach hook,$(Hooks/Prepare/Pre),$(call $(hook))$(sep))
$(Build/Prepare)
$(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
$(call touch,$$@,Prepared $(PKG_NAME))
分号在定义函数中没有特殊功能。 $(call MyDefine)
只是扩展定义函数,即 call
函数被 define
函数的内容替换。
(call
函数实际上还做了一些其他的事情,比如参数扩展,但这似乎对这个主题没有影响。)
在您的情况下,分号是必需的,因为复制命令以同时执行的方式展开。 shell(如 bash)两个命令之间需要分号。
Makefile 语法使用制表符来定义属于目标的命令。你的错误
cp: target ' [MKDIR] xxsim docinfo in staging dir' is not a directory`
建议将您的命令之一(或其他东西..??)作为目标而不是命令处理。如果 define
函数的内容以空格作为缩进,您可能希望用制表符替换它们,因此完整的内容将作为命令而不是目标插入。
另一种解决方案是在每行后添加反斜杠,使内容成为'single-line'。在这种情况下,由于shell单行执行,因此需要分号,因此所有命令都需要用分号分隔。
这里的问题是如何在配方上下文中扩展多行定义(特别是定义的内容)。
在配方上下文中,多行定义被扩展为多行,因此 make 手册中的示例可以正常工作。
因此,您会假设此处讨论的方案也适用,但显然不适用。有两件事共同导致了这个问题。
第一个是定义的值。
你可能会假设给定这个片段:
PKG_BUILD_DIR := build
cp = @echo '[CP] '; cp '' ''
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef
Package/xxsim/CopyLocalFiles
的值将是:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'
它是...除了。
你 可能 假设那是两行和两个换行符,所以实际上是这样的:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'\n
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'\n
但事实并非如此。它实际上是这样的:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'\n
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'
with no final newline.
现在通常(以及在 makefile 中的示例中)这无关紧要,因为 define 是这样使用的:
tgt:
$(Package/xxsim/CopyLocalFiles)
定义的最后一个字符紧跟一个换行符(在配方行本身)。
但这不是本例中发生的情况。在这种情况下,定义在 $(foreach)
循环中展开,手册中说的是 foreach
:
The multiple expansions of text are concatenated, with spaces between them, to make the result of foreach.
所以当循环展开两个这样的背靠背定义时:
mkdir = @echo '[MKDIR] '; mkdir ''
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef
HOOKS += Package/xxsim/CopyLocalFiles
define Package/xxsim/MkdirStaging
$(call mkdir, $(PKG_BUILD_DIR)/xxsim/staging)
endef
HOOKS += Package/xxsim/MkdirStaging
tgt:
$(foreach hook,$(HOOKS),$(call $(hook)))
你得到的扩展输出是这样的:
tgt:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build' @echo '[MKDIR] build/xxsim/staging'; mkdir build/xxsim/staging
导致您看到的错误的原因,包括尾随分号在内的错误得到修复。
在定义中包含一个额外的空行也可以解决问题(如果 make 只在文字定义值的末尾截断一个换行符)。
像这样:
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef
我想知道以下 makefile 片段中的分号有什么作用:
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim);
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR));
endef
Hooks/Prepare/Post+=Package/xxsim/CopyLocalFiles
以防万一,makefile 用于 OpenWRT 构建系统中的自定义组件 (xxsim)。
我希望分号是不必要的,例如,这个例子 (source):
define two-lines =
echo foo
echo $(bar)
endef
但是,如果我们在没有这些分号的情况下构建,对 cp
的第二次调用将失败(对 cp
的第一次调用隐式成功):
[CP] files/Adapter20Sim.h
[CP] files/Adapter20Sim.cpp
cp: target ' [MKDIR] xxsim docinfo in staging dir' is not a directory
很明显,cp接收到了错误的输入参数。那么,添加分号的实际作用是什么?为什么在存在分号的情况下组件可以正确构建?
更新: 在下面添加了构建系统上下文,这源于 Etan 在评论中的帮助:
Hooks/Prepare/Post
用在 foreach 语句中,其中它的每个值都用在调用函数中:
$(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
foreach
的上下文:
$(STAMP_PREPARED) : export PATH=$$(TARGET_PATH_PKG)
$(STAMP_PREPARED):| $(PKG_BUILD_DIR) $(STAGING_DIR)/include $(STAGING_DIR)/lib$(LIB_SUFFIX)
$(foreach hook,$(Hooks/Prepare/Pre),$(call $(hook))$(sep))
$(Build/Prepare)
$(foreach hook,$(Hooks/Prepare/Post),$(call $(hook))$(sep))
$(call touch,$$@,Prepared $(PKG_NAME))
分号在定义函数中没有特殊功能。 $(call MyDefine)
只是扩展定义函数,即 call
函数被 define
函数的内容替换。
(call
函数实际上还做了一些其他的事情,比如参数扩展,但这似乎对这个主题没有影响。)
在您的情况下,分号是必需的,因为复制命令以同时执行的方式展开。 shell(如 bash)两个命令之间需要分号。
Makefile 语法使用制表符来定义属于目标的命令。你的错误
cp: target ' [MKDIR] xxsim docinfo in staging dir' is not a directory`
建议将您的命令之一(或其他东西..??)作为目标而不是命令处理。如果 define
函数的内容以空格作为缩进,您可能希望用制表符替换它们,因此完整的内容将作为命令而不是目标插入。
另一种解决方案是在每行后添加反斜杠,使内容成为'single-line'。在这种情况下,由于shell单行执行,因此需要分号,因此所有命令都需要用分号分隔。
这里的问题是如何在配方上下文中扩展多行定义(特别是定义的内容)。
在配方上下文中,多行定义被扩展为多行,因此 make 手册中的示例可以正常工作。
因此,您会假设此处讨论的方案也适用,但显然不适用。有两件事共同导致了这个问题。
第一个是定义的值。
你可能会假设给定这个片段:
PKG_BUILD_DIR := build
cp = @echo '[CP] '; cp '' ''
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef
Package/xxsim/CopyLocalFiles
的值将是:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'
它是...除了。
你 可能 假设那是两行和两个换行符,所以实际上是这样的:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'\n
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'\n
但事实并非如此。它实际上是这样的:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'\n
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build'
with no final newline.
现在通常(以及在 makefile 中的示例中)这无关紧要,因为 define 是这样使用的:
tgt:
$(Package/xxsim/CopyLocalFiles)
定义的最后一个字符紧跟一个换行符(在配方行本身)。
但这不是本例中发生的情况。在这种情况下,定义在 $(foreach)
循环中展开,手册中说的是 foreach
:
The multiple expansions of text are concatenated, with spaces between them, to make the result of foreach.
所以当循环展开两个这样的背靠背定义时:
mkdir = @echo '[MKDIR] '; mkdir ''
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef
HOOKS += Package/xxsim/CopyLocalFiles
define Package/xxsim/MkdirStaging
$(call mkdir, $(PKG_BUILD_DIR)/xxsim/staging)
endef
HOOKS += Package/xxsim/MkdirStaging
tgt:
$(foreach hook,$(HOOKS),$(call $(hook)))
你得到的扩展输出是这样的:
tgt:
@echo '[CP] files/Adapter20Sim.h'; cp 'files/Adapter20Sim.h' 'build/xxsim'
@echo '[CP] files/Adapter20Sim.cpp'; cp 'files/Adapter20Sim.cpp' 'build' @echo '[MKDIR] build/xxsim/staging'; mkdir build/xxsim/staging
导致您看到的错误的原因,包括尾随分号在内的错误得到修复。
在定义中包含一个额外的空行也可以解决问题(如果 make 只在文字定义值的末尾截断一个换行符)。
像这样:
define Package/xxsim/CopyLocalFiles
$(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
$(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))
endef