【问题标题】:Embed Python in Makefile to set make variables在 Makefile 中嵌入 Python 以设置 make 变量
【发布时间】:2013-06-15 15:38:09
【问题描述】:

我有一个复杂的逻辑来检测 Makefile 变量的路径。我放弃了用make语言做这件事,所以我用Python编写了代码,并希望将代码嵌入到Makefile中来设置变量。但是,这不起作用:

define DETECT_SDK
import os
locations = [
  "../google_appengine",
  "/usr/local/google_appengine",
  "../.locally/google_appengine",
]
for path in locations:
  if os.path.exists(path):
    print(path)
    break
else:
  print(".")
endef

SDK_PATH ?= $(shell python -c $(DETECT_SDK))

default:
        python -c 'import sys; print(sys.argv)' $(SDK_PATH)

更新:从Is it possible to create a multi-line string variable in a Makefile 更新了多行定义 以前它因Makefile:2: *** missing separator. Stop. 而失败。现在它失败并出现另一个错误:

/bin/sh: 1: Syntax error: "(" unexpected
python -c 'import sys; print(sys.argv)' 
['-c']

【问题讨论】:

    标签: python variables makefile


    【解决方案1】:

    你必须引用你传递给 Python 的字符串:

    SDK_PATH ?= $(shell python -c '$(DETECT_SDK)')
    

    否则 shell 会在解析 Python 脚本时感到困惑。

    编辑:

    不过,我不明白你的 Python 脚本。要么你的缩进是错误的,所以 else 应该附加到 if (grrr...) 或者你错过了 break 语句......或者 else 可能只是没用。正如它所写的那样,它将生成一个以换行符分隔的存在路径列表,加上“.”。如果您描述您真正想做的事情,而不是说您放弃了,我们可以提供帮助。

    例如,如果您想要打印该列表中的第一个现有路径或“.”如果不存在(也就是说,您的 Python 循环在 print 之后缺少 break),那么您可以在 GNU make 中轻松做到这一点:

    SDK_PATH_LIST = ../google/appengine /usr/local/google_appengine ../.locally/google_appengine
    SDK_PATH ?= $(firstword $(wildcard $(SDK_PATH_LIST:%=%/.)) .)
    

    【讨论】:

    • for .. else 是 feature of Python,但你是对的 - 我的代码丢失了 break
    • 我不确定这个魔术字符串是不是 $(firstword $(wildcard $(SDK_PATH_LIST:%=%/.)) .),但我知道我的 Python 代码可以工作。
    • 我知道 for-else 是 Python 的一个特性。如果缩进错误所以 else 附加到 if 上,那么它将打印“。”对于每条不存在的路径。由于您没有说出您期望代码做什么,因此这是一个可能的解决方案。 make 代码说:获取 SDK_PATH_LIST 中的每个路径并将/. 附加到它,因此它被视为一个目录,然后在其上运行wildcard,它将返回存在的路径而不是不存在的路径,然后取返回列表的第一个单词。我们在末尾添加.,这样如果不存在,那将是第一个单词。
    • 不错的技巧。无论如何,我发现 Python 代码更具可读性,所以我更喜欢 Pythonic 方法。
    • 没关系。按照我的建议添加引号,它应该可以工作。如果不是这样,您可能必须在分隔语句中添加分号:Python 依赖空格作为语句分隔符和块定义是(IMO)在编写这样的内联脚本时的一个严重缺陷,但无论您的工作如何完成......跨度>
    【解决方案2】:

    由于一些 make 错误,它试图执行多行字符串,以下对我有用:

    define NEWLINE
    
    
    endef
    
    define DETECT_SDK
    import os
    locations = [
      "../google_appengine",
      "/usr/local/google_appengine",
      "../.locally/google_appengine",
    ]
    for path in locations:
      if os.path.exists(path):
        print(path)
        break
    endef
    
    SDK_PATH ?= $(shell echo '$(subst $(NEWLINE),@NEWLINE@,${DETECT_SDK})' | sed 's/@NEWLINE@/\n/g' | python -)
    
    default:
            @echo 'SDK Path Detected: $(SDK_PATH)'
    

    【讨论】:

    • 如何通过管道将参数传递给 python 标准输入?即echo arguments | python -c 'import sys; print(sys.stdin.read())'我在这里提出了一个新问题:stackoverflow.com/questions/55681576/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 2012-07-22
    • 2015-02-01
    • 2013-10-28
    • 1970-01-01
    相关资源
    最近更新 更多