如何在makefile中写入“ cd”命令?


354

例如,我的makefile文件中包含以下内容:

all:
     cd some_directory

但是当我键入命令时make,仅看到“ cd some_directory”,如echo命令中所示。


5
目前尚不清楚您要做什么,但是,根据我的经验make,我从来没有想像这样更改目录。也许您应该尝试另一种解决方案?
P Shved

2
相信目录很重要是一个新手常见的错误。在大多数情况下不是这样;cd dir; cmd file几乎总是可以更有用地表示为cmd dir/file
2012年

34
认为您当前的工作目录无关紧要是一个新手常见的错误。许多程序(尤其是Shell脚本)在编写时都考虑了特定的价值.。的确,大多数工具的设计方式都不需要更改其密码。但这并非总是如此,我认为将其称为“错误”以认为您的目录可能很重要不是一个好主意。
伊芙琳·科莫

提示:如果cd命令说“没有这样的文件或目录”,即使(相对)目录确实存在,请检查CDPATH环境变量是否为空或包含“。”。Make使用“ sh”执行命令,如果已设置,则只能通过CDPATH找到相对路径。这与bash相反,后者会尝试。在咨询CDPATH之前。
丹尼斯·豪

Answers:


620

它实际上是在执行命令,将目录更改为some_directory,但是,这是在子进程外壳程序中执行的,不会影响make或您正在使用的外壳程序。

如果您希望在中执行更多任务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

它将更改为目标“ all” some_dirMakefile在其中执行。最佳做法是使用$(MAKE)而不是make直接调用,因为它将注意调用正确的make实例(例如,如果您为构建环境使用特殊的make版本),并且在运行时提供略有不同的行为使用某些开关,例如-t

为了记录起见,make 总是回显它执行的命令(除非明确禁止),即使它没有输出,这也是您所看到的。


8
好吧,并非总是如此。要抑制回声,只需在行首添加@。
Beta

2
@Beta:是的,破折号也忽略了错误状态。也许我有点被带走了,我想指出一个事实,make确实会回显该命令,而不管它是哪种命令。在这种情况下,这是一个没有输出的命令,这使回显对于不熟悉make的人来说显得更加陌生。
falstro

46
有两个要点:1.这些命令应该真正由来连接&&,因为;如果目录不存在且cd失败,则shell将在当前目录中继续运行其余命令,这可能导致诸如“找到”消息进行编译,调用make时发生无限循环,或诸如之类的规则造成灾难clean:: cd dir; rm -rf *。2.调用sub-make时,请调用$(MAKE)而不是,make以便可以正确传递选项
2012年

2
@perreal,我通常使用如下方式定义一个模式规则:%-recursive:body :(@T="$@";$(MAKE) -C some_dir $${T%-*}我通常也有一个for循环,循环遍历子目录列表,这$${T%-*}是一个bash扩展,它删除-recursive了目标名称的一部分),然后定义明确的短手(和.PHONY)目标的每个,如all: all-recursivecheck: check-recursiveclean: clean-recursive
falstro 2013年

1
@ChristianStewart,真实,如在注释2和3中提到
falstro

94

GNU make 3.82(2010年7月)开始,您可以使用.ONESHELL特殊目标在shell的单个实例中运行所有配方行(加粗强调我的):

  • 新的特殊目标:.ONESHELL指示make调用该shell的单个实例并向其提供整个配方,而不管其包含多少行。[...]
.ONESHELL: # Only applies to all target
all:
    cd ~/some_dir
    pwd # Prints ~/some_dir if cd succeeded

6
不过请注意pwd本身的工作原理,以及`pwd`(与反引号),但$(shell pwd)$(PWD)做之前仍然会返回目录cd命令,所以你不能直接使用它们。
酒精2016年

3
是的,因为变量和函数扩展是在通过make执行命令之前完成的,而pwd`pwd`是由shell本身执行的。
Chnossos

2
并非每个人都在旧版makefile上工作,即使如此,这个答案也要知道是否存在这种可能性。
Chnossos

1
这可能是一个烦人/危险的选择,因为只有目标的最后一个命令才可能导致失败(任何先前的命令失败都将被忽略),可能没有人愿意与您合作。
tobii

1
设置SHELLFLAGS-e -c,shell将在第一个失败的命令退出。
蒂莫西·鲍德温

21

这是处理目录和目录的一个可爱技巧。而不是使用多行字符串或“ 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

41
“可爱”?更像是足够的绳索将自己拍到脚上。
2013年

1
然后为该规则中的命令或所有随后执行的规则设置当前目录吗?另外,在Windows下这项工作会有所变化吗?
user117529 2014年

8
当然-jn,这对于并行执行()来说是很困难的,这实际上是make的全部要点。
bobbogo 2014年

5
这是一个糟糕的技巧。如果您不得不求助于此类事情,则无需使用Makefile。
gatopeich 2014年

4
我不会不同意它肯定是一个糟糕的hack。但是确实显示了您可以做的一些邪恶的事情。
JoeS 2014年

9

一旦到达目的地,您希望它做什么?每个命令都在子外壳程序中执行,因此该子外壳程序会更改目录,但最终结果是下一个命令仍在当前目录中。

使用GNU make,您可以执行以下操作:

BIN=/bin
foo:
    $(shell cd $(BIN); ls)

5
为什么$(shell ...)when cd $(BIN); lscd $(BIN) && ls(如@andrewdotn指出的)就足够了。
vapace 2013年

1

更改目录

foo: 
    $(MAKE) -C mydir

multi:
    $(MAKE) -C / -C my-custom-dir   ## Equivalent to /my-custom-dir

-6

像这样:

target:
    $(shell cd ....); \
    # ... commands execution in this directory
    # ... no need to go back (using "cd -" or so)
    # ... next target will be automatically in prev dir

祝好运!


1
不,这是错误的。具体来说,会在$(shell cd ....)最初分析Makefile时执行,而不是在运行此特定配方时执行。
Tripleee '18

@triplee不太完全- $(shell)仅在make决定建立target时才扩展。如果make不需要配方,则不会扩展它。
bobbogo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.