I'm working on a makefile that creates multiples files in output directories. In order for those files to be created, the output directory needs to already exist or else the file creation fails.
Here's a minimal example that demonstrates the issue I'm running into:
.PHONY: default
default: dir/file.dat dir/other.dat
# In order to create these files, their parent directory must exist
dir/%.dat: | dir/
touch "$@"
# To create a directory, use mkdir -p
%/:
mkdir -p "$@"
When I run the makefile, I get an error that no rule exists to make dir. The debug run shows that make is dropping the trailing "/" from "dir/":
root@69654136a2ae:~# make -rdf dirs.mk
GNU Make 3.81
[snipped]
Considering target file `default'.
File `default' does not exist.
Considering target file `dir/file.dat'.
File `dir/file.dat' does not exist.
Considering target file `dir'.
File `dir' does not exist.
Looking for an implicit rule for `dir'.
No implicit rule found for `dir'.
Finished prerequisites of target file `dir'.
Must remake target `dir'.
make: *** No rule to make target `dir', needed by `dir/file.dat'. Stop.
Incidentally, asking for a directory target on the command line works just fine:
root@69654136a2ae:~# make -rdf dirs.mk /some/dir/
GNU Make 3.81
[snipped]
Updating goal targets....
Considering target file `/some/dir/'.
File `/some/dir/' does not exist.
Looking for an implicit rule for `/some/dir/'.
Trying pattern rule with stem `/some/dir'.
Found an implicit rule for `/some/dir/'.
Finished prerequisites of target file `/some/dir/'.
Must remake target `/some/dir/'.
mkdir -p "/some/dir/"
How can I have make do what I want?
Ideally I'm looking for a generic solution. The above example only has one subdirectory, but the actual project will have many subdirectories, so I'd like to avoid copy-pasting a solution everywhere.
Yes, the / is dropped in dir/ target (issue can be reproduced under GNU Make 3.81).
One alternative solution is to use automatic variable $(@D) to get the directory part of the file name of the target, with the trailing slash removed. And make the directory before touch the file:
.PHONY: default
default: dir/file.dat dir/other.dat
# In order to create these files, make their parent directory first
dir/%.dat:
mkdir -p $(@D)
touch "$@"
Test under GNU Make 3.81 passed:
$ make --version
GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
...
$ make
mkdir -p dir
touch "dir/file.dat"
mkdir -p dir
touch "dir/other.dat"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With