如何将命令的输出分配给Makefile变量

for*_*ran 196 shell makefile

我需要有条件地执行一些make规则,只要安装的Python大于某个版本(比如2.5).

我以为我可以做一些像执行:

python -c 'import sys; print int(sys.version_info >= (2,5))'
Run Code Online (Sandbox Code Playgroud)

然后在ifeqmake语句中使用输出(如果正常则为"1",否则为"0").

在一个简单的bash shell脚本中,它只是:

MY_VAR=`python -c 'import sys; print int(sys.version_info >= (2,5))'`
Run Code Online (Sandbox Code Playgroud)

但这在Makefile中不起作用.

有什么建议?我可以使用任何其他合理的解决方法来实现这一目标.

Ark*_*nez 308

shell像使用Make builtin一样使用MY_VAR=$(shell echo whatever)

me@Zack:~$make
MY_VAR IS whatever
Run Code Online (Sandbox Code Playgroud)

me@Zack:~$ cat Makefile 
MY_VAR := $(shell echo whatever)

all:
    @echo MY_VAR IS $(MY_VAR)
Run Code Online (Sandbox Code Playgroud)

  • shell不是标准的make builtin命令.这是一个内置的GNU Make. (33认同)
  • 虽然问题有点老,但最好做MY_VAR:= $(shell ...),否则每次评估MY_VAR时,它都会再次执行$(shell ...). (25认同)
  • http://stackoverflow.com/a/2373111/12916添加了关于转义`$`的重要说明. (11认同)
  • 这个简单的例子有效.它也适用于shell命令管道.但是必须使用$$在shell命令中表示$ (5认同)
  • 将 `shell echowhatever` 替换为 `python -c 'import sys; 打印 int(sys.version_info >= (2,5))'`。您收到“意外标记附近的语法错误”。我不明白为什么有人认为这回答了问题。谁能解释一下我缺少什么吗? (3认同)

小智 25

把作业包装成一个eval对我有用.

# dependency on .PHONY prevents Make from 
# thinking there's `nothing to be done`
set_opts: .PHONY
  $(eval DOCKER_OPTS = -v $(shell mktemp -d -p /scratch):/output)
Run Code Online (Sandbox Code Playgroud)

  • _"注意:@true在这里阻止Make认为没有什么可做的."_嗯,这就是`.PHONY总是让这些目标`的目的. (6认同)

Fra*_*ula 15

这里有一个更复杂的例子,配方内有管道和变量赋值:

getpodname:
    # Getting pod name
    @eval $$(minikube docker-env) ;\
    $(eval PODNAME=$(shell sh -c "kubectl get pods | grep profile-posts-api | grep Running" | awk '{print $$1}'))
    echo $(PODNAME)
Run Code Online (Sandbox Code Playgroud)

  • 如果方便的话,我会使用一种类似的方法通过部署名称来获取PODNAME:$(eval PODNAME = $(shell sh -c“ kubectl get pod -l app = sqlproxy -o jsonpath ='{。 items [0] .metadata.name}'“))` (2认同)
  • 该语法让我困惑了一秒钟,直到我意识到您同时使用了 *shellbuiltin* eval (在 docker-env 行上)和 *make function* eval (在下一行上)。 (2认同)

Ala*_*nSE 14

我正在写一个答案,以提高解决问题的实际语法的可见性.不幸的是,对于那些寻找合理问题的简单答案的人来说,有些人可能认为琐碎的事情会成为一个非常重要的问题.

将以下内容放入文件"Makefile"中.

MY_VAR := $(shell python -c 'import sys; print int(sys.version_info >= (2,5))')

all:
    @echo MY_VAR IS $(MY_VAR)
Run Code Online (Sandbox Code Playgroud)

您希望看到的行为如下(假设您最近安装了python).

make
MY_VAR IS 1
Run Code Online (Sandbox Code Playgroud)

如果您将上述文本复制并粘贴到Makefile中,您会得到这个吗?可能不是.您可能会收到类似于此处报告的错误:

makefile:4:***缺少分隔符.停止

原因:因为虽然我个人使用了真正的标签,但Stack Overflow(试图提供帮助)会将我的标签转换为多个空格.你,沮丧的互联网公民,现在复制这个,认为你现在拥有我使用的相同文本.make命令现在读取空格并发现"all"命令格式不正确.因此,复制上面的文本,粘贴它,然后将"@echo"之前的空白转换为选项卡,这个例子最终应该为你工作.

  • 这是因为 Eclipse 通过识别 makefile 语法将这些空格转换为制表符。在SO网页中,肯定是空格。 (2认同)

Jur*_*raj 7

当心这样的食谱

target:
    MY_ID=$(GENERATE_ID);
    echo $MY_ID;
Run Code Online (Sandbox Code Playgroud)

它做错了两件事。配方中的第一行与第二行在单独的shell实例中执行。同时,该变量丢失。第二件事是错误的,$是没有逃脱。

target:
    MY_ID=$(GENERATE_ID); \
    echo $$MY_ID;
Run Code Online (Sandbox Code Playgroud)

这两个问题都已修复,并且该变量可用。反斜杠将两行结合在一起以在单个shell中运行,因此可以进行变量的设置和变量后缀的读取。

我意识到原来的帖子说过如何将shell命令的结果转换为MAKE变量,并且此答案显示了如何将其转换为shell变量。但是其他读者可能会受益。

最后一项改进是,如果消费者希望设置“环境变量”,则必须将其导出。

my_shell_script
    echo $MY_ID
Run Code Online (Sandbox Code Playgroud)

在makefile中需要这个

target:
    export MY_ID=$(GENERATE_ID); \
    ./my_shell_script;
Run Code Online (Sandbox Code Playgroud)

希望能对某人有所帮助。通常,应该避免在配方之外进行任何实际工作,因为如果有人使用带有“ --dry-run”选项的makefile,仅查看其将要做什么,就不会有任何不良影响。每次$(shell)调用都会在编译时进行评估,并且可能会意外地执行某些实际工作。最好在可能的情况下,将实际工作(如生成ID)留在配方内部。


Mit*_*acy 6

借助GNU Make,您可以使用shelleval存储,运行和分配任意命令行调用的输出。下面的示例与使用的示例之间的区别:=:=分配(一旦遇到)仅发生一次。设置的递归扩展变量=有些“懒惰”。保留对其他变量的引用,直到引用变量本身为止,并且每次引用该变量时都会进行后续递归扩展,这对于制作“一致,可调用的代码段”是理想的。有关更多信息,请参见有关设置变量的手册

# Generate a random number.
# This is not run initially.
GENERATE_ID = $(shell od -vAn -N2 -tu2 < /dev/urandom)

# Generate a random number, and assign it to MY_ID
# This is not run initially.
SET_ID = $(eval MY_ID=$(GENERATE_ID))

# You can use .PHONY to tell make that we aren't building a target output file
.PHONY: mytarget
mytarget:
# This is empty when we begin
    @echo $(MY_ID)
# This recursively expands SET_ID, which calls the shell command and sets MY_ID
    $(SET_ID)
# This will now be a random number
    @echo $(MY_ID)
# Recursively expand SET_ID again, which calls the shell command (again) and sets MY_ID (again)
    $(SET_ID)
# This will now be a different random number
    @echo $(MY_ID)
Run Code Online (Sandbox Code Playgroud)

  • 它仍然被调用,因为 if stmts 是在 makefile 编译时而不是运行时评估的。对于运行时特定指令,请将它们放入配方中。如果它们是有条件的,请添加用 bash/shell 编写的 if stmts,作为配方的一部分。 (2认同)
  • +100 简单明了的解释 (2认同)