17

I have an rule that creates a directory

bin:
    -mkdir $@

However after the first time the directory has been generated, I receive this output:

mkdir bin
mkdir: cannot create directory `bin': File exists
make: [bin] Error 1 (ignored)

Is there some way I can only run the rule if the directory doesn't exist, or suppress the output when the directory already exists?

Matt Joiner
  • 112,946
  • 110
  • 377
  • 526

6 Answers6

22

Another way to suppress the make: error ... (ignored) output is to append || true to a command that could fail. Example with grep that checks for errors in a LaTeX log file:

undefined:
  @grep -i undefined *.log || true

Without the || true, make complains when grep fails to find any matches.

This works for all commands, not just mkdir; that's why I added this answer.

daniel kullmann
  • 13,653
  • 8
  • 51
  • 67
  • daniel, the `-` prefix character to a command in a make rule does the same thing albeit without requiring the shell to handle it. This is likely faster, and less likely to backfire. – Matt Joiner Apr 16 '12 at 17:52
  • 8
    The `-` prefix causes make to output the annoying "error ignored" output, which my solution doesn't. So no, the two do not do the same thing. – daniel kullmann Apr 17 '12 at 06:33
  • 1
    This only works as ||: (pipe-pipe-colon) on my Windows build. – Engineer Jul 22 '15 at 15:55
10

The error is ignored already by the leading '-' on the command line. If you really want to lose the error messages from mkdir, use I/O redirection:

bin:
    -mkdir bin 2> /dev/null

You will still get the 'ignored' warning from make, though, so it might be better to use the option to mkdir that doesn't cause it to fail when the target already exists, which is the -p option:

MKDIR_P = mkdir -p

bin:
    ${MKDIR_P} $@

The -p option actually creates all the directories that are missing on the given paths, so it can generate a a number of directories in one invocation, but a side-effect is that it does not generate an error for already existing directories. This does assume a POSIX-ish implementation of mkdir; older machines may not support it (though it has been standard for a long time now).

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
9

The traditional way to handle directory creation is to use a stamp file that is depended on and creates the dir as a side effect. Remove the stamp file when making distclean or whatever your "really clean" target is:

bin/.dirstamp:
    mkdir -p $(DIRS)
    touch $@

bin/foo: bin/.dirstamp
    $(MKFOO) -o $@

distclean:
    rm -rf bin

The reason for this is as follows: whenever a file in bin is created/removed, the mtime of the containing directory is updated. If a target depends on bin, then the next time make runs, it will then recreate files that it doesn't need to.

Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
-1

You rule should not be executed unless its target does not exists or is out of date because of its dependencies. In other words, you should never encounter this error.

[Example Added]

[max@truth tmp]$ ls -la
total 20
drwxr-xr-x.  2 max users 4096 Aug 14 21:11 .
drwx------. 80 max max   4096 Aug 14 18:25 ..
-rw-rw-r--   1 max max     38 Aug 14 21:11 Makefile
[max@truth tmp]$ cat Makefile 
.PHONY: all
all: bin

bin:
    mkdir $@

[max@truth tmp]$ make
mkdir bin
[max@truth tmp]$ ls -la
total 24
drwxr-xr-x.  3 max users 4096 Aug 14 21:11 .
drwx------. 80 max max   4096 Aug 14 18:25 ..
drwxrwxr-x   2 max max   4096 Aug 14 21:11 bin
-rw-rw-r--   1 max max     38 Aug 14 21:11 Makefile
[max@truth tmp]$ make
make: Nothing to be done for `all'.
[max@truth tmp]$ make
make: Nothing to be done for `all'.

Does your folder depend on anything? Is your folder a phony target?

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
-1

Well I ended up with this construct, maybe someone will find it useful or can comment on it:

BINDIR = .
TMPDIR = tmp
OUTDIRS = $(BINDIR) $(TMPDIR)
$(OUTDIRS):
    @test -d $@ || mkdir $@
Matt Joiner
  • 112,946
  • 110
  • 377
  • 526
  • Make does `test` for you anyway, so it ends up stat'ing the directory twice. This just hides the problem that the default target is .(dot). – Maxim Egorushkin Aug 20 '10 at 16:27
-1

Make assumes the first target is the default target. If that is your complete makefile, then it must be always trying to remake the default target, which is bin. Insert the following lines to the top of your makefile:

all: bin
.PHONY: all
Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271