0

I searched over the internet for a command to create a folder if it doesn't exist. I found it and put in my makefile

.DEFAULT_GOAL := all
folder := "myfolder"

createfolder:
    [ ! -d ${folder} ] && mkdir -p ${folder}

nextstep:
    echo "Got here!"

all: createfolder nextstep

When the folder doesn't exist it's created correctly. But I get an error if the folder already exists.

$ ls
makefile
$ make
[ ! -d "myfolder" ] && mkdir -p "myfolder"
echo "Got here!"
Got here!
$ ls
makefile  myfolder
$ make
[ ! -d "myfolder" ] && mkdir -p "myfolder"
make: *** [makefile:5: createfolder] Error 1

I don't get why the command would give an error if the condition [ ! -d "myfolder" ] is before the mkdir and it shouldn't even execute the second command.

How can I solve it?

Carlos Adir
  • 452
  • 3
  • 9
  • Why not use if then fi syntax ? – Ôrel Jul 03 '22 at 13:25
  • `nextstep` should be dependent on `createfolder`. If the above is run with `-j`, you could get a race condition with `nextstep` running before `createfolder` completes. Plus, `createfolder` should be declared as `.PHONY`, or better yet, renamed to the name of the folder (and then put as an _order-only_ dependency to whatever requires it) – HardcoreHenry Jul 04 '22 at 18:33

3 Answers3

2

this is what make is for.

${folder}: 
        mkdir -p ${folder}
stark
  • 12,615
  • 3
  • 33
  • 50
  • Also note, that `${folder}` in this case should be an [order-only](https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html) dependency (a folder's modification date is updated anytime anything in the folder is changed, which could make this target seem out of date when it's not). – HardcoreHenry Jul 04 '22 at 18:36
  • @HardcoreHenry Out of date with respect to what? There are no dependencies in the rule. – stark Jul 04 '22 at 19:27
  • if you had, for example, `${folder}/foo.o ${folder}/bar.o: ${folder}`, and then you did a build, the creation of `bar.o` would update the timestamp of `${folder}`. If you then did a subsequent build without modifying anything, `${folder}` would (likely) be newer than `${folder}/foo.o` and therefore it would rebuild `foo.o` and all its dependencies, even though nothing changed. Therefore the proper way to do this would be `${folder}/foo.o : | ${folder}`. – HardcoreHenry Jul 04 '22 at 20:30
1

I think the best way to create folders is to use order-only prerequisites:

%/.:
    mkdir -p "$@"

With that, you can reliably create directories for any rule:

nextstep: | $(folder)/.
    ...

If you enable secondary expansion, you can use the same trick for arbitrary compilation rules:

$(OBJDIR)/%.o : $(SRCDIR)/%.c | $$(@D)/.
    ...

so just tack | $$(@D)/. at the end of the rule and you're all set.

Idelic
  • 14,976
  • 5
  • 35
  • 40
0

You can use if then fi syntax

.DEFAULT_GOAL := all
folder := "myfolder"

createfolder:
        if [ ! -d ${folder} ]; then mkdir -p ${folder}; fi

nextstep:
        echo "Got here!"

all: createfolder nextstep
Ôrel
  • 7,044
  • 3
  • 27
  • 46
  • Thank you! When I tried dividing it in lines, I was receiving an syntax error like in [this question](https://stackoverflow.com/questions/18155852/syntax-error-end-of-file-unexpected-expecting-then). The one line command solved my problem. – Carlos Adir Jul 03 '22 at 13:36
  • 3
    Just run `mkdir -p`. That's what the `-p` is for. You don't have to check if the directory exists first: if you use `-p` then `mkdir` will create the directory if it doesn't exist, or silently succeed if it does exist. – MadScientist Jul 03 '22 at 21:55
  • 1
    And so, stark's answer should be accepted instead. – tripleee Jul 04 '22 at 18:11