Makefile的define指令中的分号终止有什么作用?

时间:2015-05-13 16:19:40

标签: makefile openwrt

我想知道以下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))

2 个答案:

答案 0 :(得分:2)

这里的问题是如何在配方上下文中扩展多行定义(具体而言,定义的内容是什么)。

在配方上下文中,多行定义被扩展为多行,因此make手册中的示例可以正常工作。

因此,您可以假设此处讨论的场景也可以正常运行,但显然不会。有两件事情会导致这个问题。

第一个是定义的值是什么。

您可以假设给定此代码段:

PKG_BUILD_DIR := build
cp = @echo '[CP] $1'; cp '$1' '$2'

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'

最终换行符。

现在正常(并且在makefile中的示例中)无关紧要,因为define的使用方式如下:

tgt:
        $(Package/xxsim/CopyLocalFiles)

并且define的最后一个字符紧跟一个换行符(在配方行本身上)。

但这不是在这种情况下发生的事情。在这种情况下,定义正在$(foreach)循环中展开,手册说明foreach

  

连接 text 的多个扩展,并在它们之间留有空格,以生成 foreach 的结果。

所以当循环扩展两个这样的定义背靠背时:

mkdir = @echo '[MKDIR] $1'; mkdir '$1'

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

导致您看到的错误以及包括尾部分号修复的错误。

在define中包含一个额外的空行也可以解决问题(如果make只在文字定义值的末尾选择一个换行符。)

像这样:

define Package/xxsim/CopyLocalFiles
    $(call cp, files/Adapter20Sim.h, $(PKG_BUILD_DIR)/xxsim)
    $(call cp, files/Adapter20Sim.cpp, $(PKG_BUILD_DIR))

endef

答案 1 :(得分:0)

分号在define函数中没有特殊功能。 $(call MyDefine)只是扩展define函数,即call函数被define函数的内容替换。

call函数实际上做了其他一些事情,比如参数扩展,但这似乎对这个主题没有影响。)

在您的情况下,分号是必需的,因为复制命令的扩展方式是一次执行。 shell(如bash)需要在两个命令之间使用分号。

Makefile语法使用选项卡定义属于目标的命令。你的错误

  

cp:target'[MKDIR] xxsim docinfo in staging dir'不是目录`

建议您将其中一个命令(或某些东西...... ??)作为目标而不是命令处理。如果define函数的内容具有空格作为缩进,您可能希望用制表符替换它们,因此完整的内容将作为命令而不是目标插入。

另一个解决方案是在每一行之后添加反斜杠,使内容为“单行”。在这种情况下,分号是必需的,因为shell执行单行,因此所有命令都需要用它们分隔。