'How to check if a directory doesn't exist in make and create it

In my project's directory, I have some subdirs: code/, export/, docs/ and object/. What make does is simply compile all the files from the code dir, and put the .o files into the object dir.

The problem is, I told git to ignore all .o files, because I don't want them uploaded, so it doesn't track the object dir either. I'm actually OK with that, I don't want the object/ uploaded to my GitHub account as well, but with the current solution (which is a simple empty text file inside the object/ dir), the directory does get uploaded and needs to be present before the build (the makefile just assumes it's there).

This doesn't really seem like the best solution, so is there a way to check if a directory doesn't exist before the build in a make file, and create it if so? This would allow for the object dir not to be present when the make command is called, and created afterwards.



Solution 1:[1]

Just have a target for it:

object/%.o: code/%.cc object
    compile $< somehow...

object:
    mkdir $@

You have to be a little more careful if you want to guard against the possibility of a file called "object", but that's the basic idea.

Solution 2:[2]

The only correct way to do this is with order-only-prerequisites, see: https://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html. Note the | in the snippet.

If you don't use order-only-prerequisites each modification (e.g. coping or creating a file) in that directory will trigger the rule that depends on the directory-creation target again!

object/%.o: code/%.cc | object
    compile $< somehow...

object:
    mkdir -p $@

Solution 3:[3]

Insert a mkdir command in the target.

object/%.o : code/%.cc
    @mkdir -p object
    compile $< somehow...

The '-p' results in no error if the directory already exists.

Solution 4:[4]

You can also use the $(@D) make variable to create the directory of the target. $(@D) refers to the directory of the target. So you can use:

out/%.o: src/%.c
    mkdir -p $(@D)
    $(CC) $^ -o $@

This also works great if the folder is a variable, like:

OBJ:=objects

$(OBJ)/%.o: src/%.c
   mkdir -p $(@D)
   $(CC) $^ -o $@

With $(@D) you can change the OBJ variable and you won't need to change also the mkdir line in the recipe.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Beta
Solution 2
Solution 3 Mike F
Solution 4 Kostas Tsiligkiris