我应该如何在 Makefile 中嵌入 python 脚本?

How should I embed a python script in a Makefile?

我想在 Makefile

中嵌入 python 脚本

我构建了一个 python -c 脚本(如下),它在我的 MacBook 中运行良好 Hyper terminal:

% python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'

由于我还不明白的原因,如果我用它构建一个 Makefile,这似乎会失败(注意:一个制表符是四个空格......我在 Makefile 中使用了制表符缩进)。

all:
    $(shell python -c $'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))')

运行 make all 目标...

% make all
/bin/sh: -c: line 0: syntax error near unexpected token `('
/bin/sh: -c: line 0: `python -c from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))''
make: `all' is up to date.
%

我为此苦恼了一段时间...

有人可以帮助解释 make all 失败的原因以及修复此 python -c 命令的最佳方法吗?我的 shell CLI python -c ... 命令在我的 MacBook 上成功启动 Docker 桌面。

我知道有非 python 方法可以解决这个特定问题...我需要一个通用的 python Makefile 解决方案。

由于 Python 的缩进要求,在 Makefile 中使用 python -c 很棘手。如果您想使用 Bash“C 风格”字符串,一个简单的解决方案是使用 SHELL=/bin/bash

SHELL=/bin/bash
all:
    # python command must be wrapped in single quotes _and_ have double dollar sign in front
    python -c $$'from subprocess import getstatusoutput\noutput=getstatusoutput("open --background -a Docker")\nif int(output[0])>0:\n    print("Docker desktop failed to launch: exit-code:{}".format(output[0]))'

(注意美元符号需要加倍才能转义它。显然,这限制了 Makefile 到 Bash 可用的系统的可移植性。$'...'语法允许您在字符串中使用 \n\t 等转义码,并将它们分别扩展为换行符和制表符。此构造特别需要前导美元符号和字符串周围的单引号 - 只是 '...' 做的事情略有不同,而 $"..." 做的事情 完全 不同。)

您还可以 define 一个 make 多行变量。但在这个孤立的案例中,Python 无论如何都没有发挥任何作用。

all:
    open --background -a Docker
如果 open 失败,

make 将终止并显示错误消息;从 Python 打印本质上相同的消息似乎是多余的。如果你想在错误的情况下继续,你可以这样做

all:
    open --background -a Docker || \
    echo "Docker desktop failed to launch: exit-code: $$?"

...尽管我认为 Python 脚本失败(原文如此)只是一个错误。

我找到了一种相当简单的方法来将多行 python 脚本嵌入 Makefile...

  1. 另存为Makefile...
define MULTILINE_PYTHON_SCRIPT
###########################################
# Start multiline python string here...
###########################################
from subprocess import getstatusoutput as gso

print("Here we go:")
for hello_int in [1, 2, 3,]:
    print('    Hello World %i' % hello_int)

retval, _ = gso("ls -la")
assert retval==0, "ls command execution failed"

###########################################
# End of multiline python string...
###########################################
endef
export MULTILINE_PYTHON_SCRIPT
EMBEDDED_PY := python -c "$$MULTILINE_PYTHON_SCRIPT"

.PHONY: nothing
nothing:
    echo "raw makefile command"

.PHONY: test
test:
    $(EMBEDDED_PY)

.PHONY: all
all:
    open --background -a Docker
  1. 测试输出:
% make nothing
echo "raw makefile command"
raw makefile command
%
% make test
python -c "$MULTILINE_PYTHON_SCRIPT"
Here we go:
    Hello World 1
    Hello World 2
    Hello World 3
%
%