Makefile 标记语言是新的,但我正在尝试创建一个目标以允许可选参数。对于给定的参数,我们期望它可以是单个或由空格分隔的多个输入。如果给出了参数,我想迭代该参数并为每个参数运行一个测试函数。
如果参数是单个输入,则运行,但如果提供多个输入,则失败。
run-test:
ifdef tests
$(foreach test_file, $(tests), $(if $(wildcard $(addprefix tests/python/test_, $(addsuffix .py, ${test_file}))), export env=preprod && pytest tests/python/test_${test_file}.py, $(info ${test_file} does not exist.)))
endif
如果我调用
make run-test tests="foo"
它运行得很好,但如果我这样做 run-test tests="foo bar"
似乎用于导出和运行 pytest 命令的测试 cli 命令会链接在一起并且不起作用。
对你的问题最直接的答案是make的函数只是文本操作操作。他们不运行命令或任何东西。
所以如果你有这样的事情:
FILES = foo.py bar.py baz.py
$(info $(foreach F,$(FILES), python $F))
你会看到输出是:
python foo.py python bar.py python baz.py
如果您将该字符串放入 shell 提示符中运行它,您将获得一个带有参数的 python 解释器
foo.py python bar.py python baz.py
。如果要运行多个命令,则必须确保函数生成的文本是有效的 shell 命令。在这种情况下,这可能意味着在它们之间添加分号:
FILES = foo.py bar.py baz.py
$(info $(foreach F,$(FILES), python $F ;))
你会看到输出是:
python foo.py ; python bar.py ; python baz.py
现在它可以工作了,但这里的问题是,如果其中任何一个(最后一个除外)失败,它将丢失错误代码。也许你并不关心这个。
但是退一步来说,你所做的整个事情并不是真正的“类似”。每当你有一个单一的配方为列表中的每个文件做一件事情时,这并不是 make 的真正设计方式。 Make 被设计为有一个规则可以做一件事。如果我是你,我会像这样重写你的 makefile:
run-test: $(tests)
.PHONY: $(tests)
$(tests): % : tests/python/test_%.py
env=preprod pytest $<
这使用静态模式规则为每个测试定义一个单独的规则,该规则将运行测试。