为什么 make 会停止并显示“Makefile:6: *** 多个目标模式。停止。”?

为什么 make 会停止并显示“Makefile:6: *** 多个目标模式。停止。”?

目标我将幻灯片写在 Markdown 文件中,然后对其进行编译以供显示,将其上传到我的网络服务器并执行其他操作。我想组织将 markdown 写入 makefile 后的步骤:

PROJNAME = `pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`

presentation: slides.pandoc
    pandoc --self-contained --data-dir=$(HOME)/.pandoc --template=slides/revealjs_niels_tmpl.html -V revealjs-url:$(HOME)/.pandoc/revealjs -V theme:solarized slides.pandoc -f markdown -t revealjs -o $(PROJNAME).html

onlinepresent: $(PROJNAME).html
    cp $(PROJNAME).html $(HOME)/Share/index.html

解释 PROJNAME查找项目文件夹名称并将其转换为小写。在我使用它并生成标题中显示的消息的示例文件夹中,这会导致ws-anno-ii.该presentation规则使用 将幻灯片编译为 html pandoc。宏PROJNAME用于定义输出文件的名称。如果该文件存在于已安装的外部文件系统 ( ) 中,则停止位置应复制包含项目名称 ( )onlinepresentmake文件。如果不存在,当然应该首先应用该规则。但是当我输入命令时没有任何反应,并且我收到消息ws-anno-ii.htmlSharepresentationmake

make过程停止并Makefile:6: *** multiple target patterns. Stop.引用该行onlinepresent: $(PROJNAME).html

谁能向我解释为什么会发生这种情况?

答案1

make 变量的值PROJNAME

`pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`

反引号字符在 make 中并不特殊。如果在 shell 命令中使用该变量,shell 会看到反引号并将它们解析为命令替换。但是,如果您在 make 解释变量的地方使用该变量,则反引号不会执行任何特殊操作。onlinepresent: $(PROJNAME).html变量扩展后,该行变为:

onlinepresent: `pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`.html

使解析为onlinepresent, colon, `pwd, \, grep, -oP, , , , , , , , , '(\w|-)+', , , , colon, , colon, , , colon, , colon, 。最右边冒号的左边有多个单词,因此是“多个目标模式”。|tail-n2|head-n1|tr'[upper]''[lower]'`.html

如果你想在 make 能够读取的地方使用 shell 命令的输出,你需要调用shell功能。这是一个 GNU make 功能,在其他 make 实现中不起作用。

PROJNAME = $(shell pwd | grep -oP '(\w|-)+' | tail -n 2 | head -n 1 | tr '[:upper:]' '[:lower:]'`)

这会将PROJNAME变量设置为工作目录的倒数第二个转换为小写的组件。

请注意,使用当前目录是脆弱的:这意味着如果从不同的目录作为目标调用您的 makefile 将无法工作。PROJNAME从到目标的路径进行计算会更加稳健。如果不是小写部分,您可以使用 make 函数完全完成(如果很麻烦)(我假设您拆分代码的目的实际上是提取路径名组件):

$(notdir $(patsubst %/,%,$(dir $(patsubst %/,%,$(dir $(abspath $@))))))

但 GNU make 没有大小写转换工具。如果您无论如何都要调用 shell,则可以使其变得更简单。

PROJNAME = $(shell set -x; echo '$(abspath $@)' | awk -F/ '{$$0=tolower($$0); print $$(NF-2)}')
onlinepresent: $(PROJNAME).html
        cp $< $$HOME/Share/index.html

$$请注意makefile 中的使用,它将成为$shell 命令中的内容。这是有效的,因为PROJNAME变量是在每次使用时计算的,而不是在定义时计算(如果使用 ,则 make 中的变量定义在每次使用时扩展=,如果使用 ,则在读取赋值时扩展:=)。

答案2

当你跑步时make onlinepresentmake走到目标处onlinepresent并看到它需要$(PROJNAME).html,这有点像错误的...从make的角度来看,因为没有直接提供的目标$(PROJNAME).html

我还假设您的分配PROJNAME只有一种可能结果。

尝试用

presentation: slides.pandoc
#your pandoc rule
onlinepresent: presentation
#your mv command

这说明make为了实现目标,需要onlinepresent目标。presentation然后目标表示告诉 make 这是必需的,因此如果是新的或已修改的slides.pandoc规则,它将运行该规则。slides.pandoc

或者

您还可以尝试将目标重命名presentation$(PROJNAME).html,使其看起来像

$(PROJNAME).html: slides.pandoc
#your pandoc rule
onlinepresent: $(PROJNAME).html
#your mv command

相关内容