使用mkdir时如何防止makefile中的“目录已存在错误”


109

我需要在我的makefile中生成一个目录,即使我可以轻松地忽略它,我也不想一遍又一遍地得到“目录已存在错误”。

我主要使用mingw / msys,但也希望它能在其他Shell /系统中使用。

我试过了,但是没用,有什么想法吗?

ifeq (,$(findstring $(OBJDIR),$(wildcard $(OBJDIR) )))
-mkdir $(OBJDIR)
endif

Answers:


106

在UNIX上,只需使用以下命令:

mkdir -p $(OBJDIR)

如果目录存在,则mkdir的-p选项可防止出现错误消息。


39
“通常,请遵循这些程序广泛支持的(通常是posix指定的)选项和功能。例如,不要使用'mkdir -p',那样可能会很方便,因为有些系统不支持它与所有其他方式并存
greg.kindel 2011年

8
-p在Windows上不起作用,这大概是问题所在。不知道这是怎么被接受的。
锑2014年


1
@Antimony如果您在MinGW Shell之外使用GNU Make,您可能做错了。不过,您可以选择。
yyny

“在UNIX上,只需使用此...” -是make -pUnix还是Linux?
jww

122

查看正式的make文档,这是一个很好的方法:

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,foo.o bar.o baz.o)

$(OBJDIR)/%.o : %.c
    $(COMPILE.c) $(OUTPUT_OPTION) $<

all: $(OBJS)

$(OBJS): | $(OBJDIR)

$(OBJDIR):
    mkdir -p $(OBJDIR)

您应该在这里看到|的用法。管道操作员,仅定义订单是先决条件。意味着$(OBJDIR)目标应该存在(而不是最近的),以便建立当前目标。

请注意,我用过mkdir -p-p与文档示例相比,添加了该标志。参见其他答案。


4
这绝对是解决此问题的官方方法。
lcltj 2011年

@CraigMcQueen:我的意思是$(OBJDIR)目标应该存在。检查文件的存在(和时间戳),以决定是否需要构建目标。因此在这里,如果$(OBJDIR)不存在,它将构建它,以便存在以构建当前目标$(OBJS),该目标将在内部创建。
ofavre 2012年

我想我在尝试发现此问题之前实际上已经尝试过其他所有解决此问题的组合(我正在尝试生成在Windows / Linux之间尽可能通用的makefile)-这几乎是我可以使用的唯一文件,但是效果很好!:)
code_fodder

67

您可以使用测试命令:

test -d $(OBJDIR) || mkdir $(OBJDIR)

7
如果您需要使makefile在Windows(使用gnuwin32和PowerShell)和POSIX兼容操作系统中都可以工作,则这是首选方法。
克里斯·哈迪

6
只要您具有gnuwin32 CoreUtils软件包即可提供“测试”实用程序。
davenpcj

2
在这里晚了一点,但我想指出的是,make -j由于在测试目录是否存在以及创建目录之间存在竞争状况,因此在并行构建()时此解决方案可能会中断。一个作业可以测试它是否不存在,但是在创建它之前,另一个作业可以创建目录。然后,当第一个尝试创建它时,它将失败,因为该目录已经存在。在这种情况下,最好的解决方案是仅使用@TeKa答案中提到的先决条件(应该是公认的答案)。
C0deH4cker 2014年

@MarcusJ在我的OS X El Capitan上工作。哪个版本破解了?
富兰克林于

@ C0deH4cker-原谅我的无知... TeKa哪个答案?自您发表评论以来,我认为TeKa更改了他/她的名字。
jww

18

这是我与GNU make一起使用来创建编译器输出目录的一个技巧。首先定义此规则:

  %/.d:
          mkdir -p $(@D)
          touch $@

然后,使进入该目录的所有文件都依赖于该目录中的.d文件:

 obj/%.o: %.c obj/.d
    $(CC) $(CFLAGS) -c -o $@ $<

注意使用$ <代替$ ^。

最后,防止.d文件自动删除:

 .PRECIOUS: %/.d

跳过.d文件并直接取决于目录是不起作用的,因为每次在该目录中写入文件时都会更新目录修改时间,这将在每次调用make时强制进行重建。


1
啊,谢谢,我正在尝试使类似的东西起作用。我不想在多个目标上使用“ test -d foo || mkdir foo”,因为随后使用“ make -j2”将同时对其进行测试,两个测试都给出false,然后两个进程将尝试对mkdir进行测试最后他们失败了。
锤击

13

如果目录已经存在对您来说不是问题,那么您可以重定向该命令的stderr,摆脱错误消息:

-mkdir $(OBJDIR) 2>/dev/null

这也具有在Windows上工作的优势。不要忘记命令前面的'-',这样make不会保释。
Michael Burr

11

在您的makefile中:

target:
    if test -d dir; then echo "hello world!"; else mkdir dir; fi

10

在Windows上

if not exist "$(OBJDIR)" mkdir $(OBJDIR)

在Unix上| 的Linux

if [ ! -d "$(OBJDIR)" ]; then mkdir $(OBJDIR); fi

此为Windows。
校验和

/bin/sh: 1: Syntax error: end of file unexpected (expecting "then")
wotanii '16

第一个版本适用于Windows,第二个选项适用于Linux,如@checksum所述
Edgard Leal

Windows的第一个版本不是原子版本,因此当另一个进程(例如,并行模式下的规则)在“不存在”和“ mkdir”之间创建目录时,它将无法正常工作。
PetrVepřek'18


6
$(OBJDIR):
    mkdir $@

这也适用于多个目录,例如。

OBJDIRS := $(sort $(dir $(OBJECTS)))

$(OBJDIRS):
    mkdir $@

添加$(OBJDIR)为第一个目标效果很好。


3

它在mingw32 / msys / cygwin / linux下工作

ifeq "$(wildcard .dep)" ""
-include $(shell mkdir .dep) $(wildcard .dep/*)
endif

0

如果您显式忽略返回代码并转储错误流,那么在发生错误时,make将忽略该错误:

mkdir 2>/dev/null || true

这不会在并行模式中引起比赛危险-但我尚未进行过确定性测试。


0

比Lars的答案简单一点:

something_needs_directory_xxx : xxx/..

和通用规则:

%/.. : ;@mkdir -p $(@D)

没有触摸文件可以清理或制作.PRECIOUS :-)

如果您想了解另一个通用的gmake技巧,或者对使用最少脚手架的非递归make感兴趣,则可以在该博客中查看另外两个便宜的gmake技巧和其他与make相关的文章。

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.