如何在makefile中追加文件路径

时间:2019-11-27 10:00:54

标签: macos makefile

我在 MacOS 中的makefile中使用了以下示例代码来构造路径,但它始终不起作用。

all:
  ROOT=$(shell pwd)
  @echo $(ROOT)
  AGENT:=$(ROOT)/agent
  @echo $(AGENT)
  @mkdir -p $(AGENT)

它将输出为AGENT:=/agent,显然,AGENT变量未扩展为ROOT

1 个答案:

答案 0 :(得分:1)

这里有几个常见错误:

  1. 配方行运行在单独的外壳中,您不能期望在一个外壳中分配的外壳变量仍在另一个外壳中定义。
  2. 无需在配方中使用$(shell...) make函数:配方已经是shell脚本。
  3. 您显然混淆了shell变量并制作了变量。
    • 仅在配方中(仅几乎是)为外壳变量分配了var=xxx=周围没有空格)。它们使用$var${var}进行扩展,但从未使用$(var)进行扩展,仍然几乎仅在配方中扩展。
    • 使用var := xxxvar = xxx(在:==周围有或没有空格)分配制造变量,仅在配方之外(几乎,仅)。它们使用$(var)${var}进行扩展,而从未使用$var进行扩展。请注意,=:=不同,但这超出了范围。

如果您是初学者,请忽略以上说明中的“ 几乎”,您现在将不需要此。

Makefile用两种不同的语言编写:配方中的shell语言和其他地方的make语言。有点像网页是用HTML和CSS编写的。 Shell语言和make语言有时看起来相似,但有所不同。需要考虑的重要一点是,make首先将其扩展以替换make变量或make函数,然后将这些食谱传递给shell。因此,经常有必要保护外壳语法的某些部分免受这种make扩展的影响(请参见下面的示例)。

无论如何,尝试这样的事情,也许:

带有make变量

ROOT := $(shell pwd)
AGENT := $(ROOT)/agent

all:
    @echo $(ROOT)
    @echo $(AGENT)
    @mkdir -p $(AGENT)

ROOTAGENT是make变量,使用:=在任何配方之外分配,并且可以在任何地方使用,包括在配方中。它们用$(var)扩展。在将配方传递给外壳之前,make会将其展开为:

echo /some/where
echo /some/where/agent
mkdir -p /some/where/agent

每行将在单独的shell中执行,但这没关系,因为它们之间没有传递shell变量。

注意:如果使用的是GNU make,将定义CURDIR make变量并将其扩展为当前工作目录。无需使用pwd,只需使用$(CURDIR)而不是$(ROOT)

AGENT := $(CURDIR)/agent

all:
    @echo $(CURDIR)
    @echo $(AGENT)
    @mkdir -p $(AGENT)

注意:如果ROOT指向Makefile所在的位置,并且如果您使用-f的make选项从其他地方调用make,则$(CURDIR)不再起作用,因为它指向哪里您从而不是在Makefile所在的位置调用make。但是您也可以使用以下方法获得正确的ROOT

ROOT := $(dir $(lastword $(MAKEFILE_LIST)))

在Makefile的开头(在任何include语句之前)。

使用shell变量

仅使用shell语法和单行代码:

all:
    @ROOT="`pwd`"; AGENT="$$ROOT"/agent; echo "$$ROOT"; echo "$$AGENT"; mkdir -p "$$AGENT"

ROOTAGENT是外壳变量,在配方内部用=分配,并且仅在配方的同一行中可用。请注意,双$用于扩展shell变量。在将结果传递到外壳程序之前,需要它们先退出make性能的第一个扩展。通过make扩展后,配方以以下方式传递到外壳:

ROOT="`pwd`"; AGENT="$ROOT"/agent; echo "$ROOT"; echo "$AGENT"; mkdir -p "$AGENT"

(make将$$展开为$并停在那里)是您想要的。它在单个shell中执行,这就是为什么将shell变量从列表的一个命令传递到下一个命令的原因。

如果希望获得更好的可读性,可以使用\行继续行将配方拆分为多行,但在一个外壳程序中仍然只执行一个配方:

all:
    @ROOT="`pwd`"; \
    AGENT="$$ROOT/agent"; \
    echo "$$ROOT"; \
    echo "$$AGENT"; \
    mkdir -p "$$AGENT"

这与其他形式严格等效,只是更易于阅读。但这完全不同于:

all:
    @ROOT="`pwd`"
    @AGENT="$$ROOT/agent"
    @echo "$$ROOT"
    @echo "$$AGENT"
    @mkdir -p "$$AGENT"

因为这是最后一种形式,所以5行由5个不同的shell执行。例如,当第二个运行时,不再定义第一个外壳分配的ROOT外壳变量,其结果与以下内容相同:

AGENT="/agent"

然后,两条echo行根本没有回声,只是换行了。最后,您得到一个错误,因为:

mkdir -p

无效。