例如,我在makefile中有这样的东西:
all:
cd some_directory
但是当我输入make时,我只看到'cd some_directory',就像在echo命令中一样。
例如,我在makefile中有这样的东西:
all:
cd some_directory
但是当我输入make时,我只看到'cd some_directory',就像在echo命令中一样。
当前回答
它实际上是在执行命令,将目录更改为some_directory,但是,这是在子进程shell中执行的,它既不影响make,也不影响您正在使用的shell。
如果希望在some_directory中执行更多任务,则需要添加分号并附加其他命令。注意,你不能使用新行,因为它们被make解释为规则的结束,所以你使用的任何新行都需要用反斜杠转义。
例如:
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
还要注意,即使添加了反斜杠和换行符,每个命令之间也必须有分号。这是因为shell将整个字符串解析为一行。正如注释中所指出的,您应该使用'&&'来连接命令,这意味着只有在前面的命令成功时才会执行这些命令。
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
这在做破坏性的工作时尤其重要,比如清理,因为如果cd因为任何原因失败,您就会破坏错误的东西。
不过,一种常见的用法是在子目录中调用make,您可能想研究一下这个子目录。这里有一个命令行选项,因此您不必自己调用cd,因此您的规则将如下所示
all:
$(MAKE) -C some_dir all
它将变成some_dir并在该目录下执行Makefile,目标为“all”。作为一种最佳实践,使用$(MAKE)而不是直接调用MAKE,因为它会注意调用正确的MAKE实例(例如,如果您为构建环境使用一个特殊的MAKE版本),并且在使用某些开关(如-t)运行时提供略微不同的行为。
为了记录,make总是回显它执行的命令(除非显式抑制),即使它没有输出,这就是您所看到的。
其他回答
你希望它到达那里后做什么?每个命令都在子shell中执行,因此子shell会更改目录,但最终结果是下一个命令仍然在当前目录中。
使用GNU make,你可以做如下的事情:
BIN=/bin
foo:
$(shell cd $(BIN); ls)
它实际上是在执行命令,将目录更改为some_directory,但是,这是在子进程shell中执行的,它既不影响make,也不影响您正在使用的shell。
如果希望在some_directory中执行更多任务,则需要添加分号并附加其他命令。注意,你不能使用新行,因为它们被make解释为规则的结束,所以你使用的任何新行都需要用反斜杠转义。
例如:
all:
cd some_dir; echo "I'm in some_dir"; \
gcc -Wall -o myTest myTest.c
还要注意,即使添加了反斜杠和换行符,每个命令之间也必须有分号。这是因为shell将整个字符串解析为一行。正如注释中所指出的,您应该使用'&&'来连接命令,这意味着只有在前面的命令成功时才会执行这些命令。
all:
cd some_dir && echo "I'm in some_dir" && \
gcc -Wall -o myTest myTest.c
这在做破坏性的工作时尤其重要,比如清理,因为如果cd因为任何原因失败,您就会破坏错误的东西。
不过,一种常见的用法是在子目录中调用make,您可能想研究一下这个子目录。这里有一个命令行选项,因此您不必自己调用cd,因此您的规则将如下所示
all:
$(MAKE) -C some_dir all
它将变成some_dir并在该目录下执行Makefile,目标为“all”。作为一种最佳实践,使用$(MAKE)而不是直接调用MAKE,因为它会注意调用正确的MAKE实例(例如,如果您为构建环境使用一个特殊的MAKE版本),并且在使用某些开关(如-t)运行时提供略微不同的行为。
为了记录,make总是回显它执行的命令(除非显式抑制),即使它没有输出,这就是您所看到的。
这里有一个处理目录和制作的可爱技巧。不要在每个命令上使用多行字符串或“cd;”,而是定义一个简单的chdir函数,如下所示:
CHDIR_SHELL := $(SHELL)
define chdir
$(eval _D=$(firstword $(1) $(@D)))
$(info $(MAKE): cd $(_D)) $(eval SHELL = cd $(_D); $(CHDIR_SHELL))
endef
然后你所要做的就是在你的规则中这样调用它:
all:
$(call chdir,some_dir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
你甚至可以这样做:
some_dir/myTest:
$(call chdir)
echo "I'm now always in some_dir"
gcc -Wall -o myTest myTest.c
更改dir
foo:
$(MAKE) -C mydir
multi:
$(MAKE) -C / -C my-custom-dir ## Equivalent to /my-custom-dir
下面是我使用的模式:
.PHONY: test_py_utils
PY_UTILS_DIR = py_utils
test_py_utils:
cd $(PY_UTILS_DIR) && black .
cd $(PY_UTILS_DIR) && isort .
cd $(PY_UTILS_DIR) && mypy .
cd $(PY_UTILS_DIR) && pytest -sl .
cd $(PY_UTILS_DIR) && flake8 .
我使用这种模式的动机是:
The above solution is simple and readable (albeit verbose) I read the classic paper "Recursive Make Considered Harmful", which discouraged me from using $(MAKE) -C some_dir all I didn't want to use just one line of code (punctuated by semicolons or &&) because it is less readable, and I fear that I will make a typo when editing the make recipe. I didn't want to use the .ONESHELL special target because: that is a global option that affects all recipes in the makefile using .ONESHELL causes all lines of the recipe to be executed even if one of the earlier lines has failed with a nonzero exit status. Workarounds like calling set -e are possible, but such workarounds would have to be implemented for every recipe in the makefile.