Reputation: 2887
I Need to create dir based on the parent directory
For example:
If I’ve project like following
project1
-File1
-Makefile
In the make file I want to do something like the following
mkdir project1
And then it should look like
project1
-File1
-Makefile
-project1
But I want to do it dynamically i.e. mkdir parent folder
, since let's assume that in the makefile I don’t know what is the name of the parent folder. Is it possible? It should be empty folder with the name of the parent folder.
As prerequisite it should always have parent a folder
I tried the suggestion below:
update
all: build
build:
mkdir $(basename "$PWD")
This created the following:
project1
-File1
-Makefile
-WD
This created a folder under the root, which is OK ,but the name is WD
, which is wrong, it should be project1
Upvotes: 0
Views: 550
Reputation: 29335
I assume:
my favorite make file
", what follows will not work.First, you need to get the path and the base name of the directory that contains your Makefile. And this is not that simple. The following should work in all cases, except if you put your Makefile at the root /
of your filesystem or have "unreasonable" file and directory names. Put this at the beginning of your Makefile, before any include
directive:
DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
BASE := $(notdir $(patsubst %/,%,$(DIR)))
DIRNAME := $(DIR)$(BASE)
Sorry, it looks over-complicated, but all parts are here for a good reason (see at the end for the details). If you really want this to work in all cases, you need them all.
Next you need to create the sub-directory without error, even if it exists already:
$(DIRNAME):
mkdir -p $@
$@
, in the recipe, expands as the target, that is $(DIRNAME)
in this case; using these automatic variables whenever possible is highly recommended. Do not forget the -p
option, else the recipe will fail if the sub-directory exists.
Finally, you must guarantee that the command is executed before you actually need the sub-directory. Assume, for instance, that you have an all
target but you want the sub-directory to exist before building the all
target. You could write a simple dependency:
all: $(DIRNAME)
<all-recipe>
$(DIRNAME):
mkdir -p $@
But in this case, every time the content of the sub-directory is modified, you will rebuild the all
target, possibly uselessly. This is where order-only prerequisites are useful. They must exist but their last modification date is not considered by make.
All in all, the following should do what you want:
DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
BASE := $(notdir $(patsubst %/,%,$(DIR)))
DIRNAME := $(DIR)$(BASE)
all: | $(DIRNAME)
<all-recipe>
$(DIRNAME):
mkdir -p $@
Note the |
that introduces the order-only prerequisites.
Explanation about building the name of the sub-directory that you want to create:
You can invoke make from a different directory:
make -C <path-to-project>
make -f <path-to-project>/Makefile
So, $(shell basename "$$PWD")
or any variant (e.g. $(notdir $(PWD))
) will work only if you invoke make from the directory where your Makefile resides. The correct way to get the absolute path of the Makefile, even if make is invoked from elsewhere, is $(abspath $(lastword $(MAKEFILE_LIST)))
. Remember to put it before any include
directive. Example of expansion result: /home/john/project1/Makefile
.
$(dir <some-path>)
keeps only the directory part, removing the file part. Example: /home/john/project1/
.
$(patsubst %/,%,<some-path>)
removes the trailing /
, if any. Example: /home/john/project1
.
$(notdir <some-path>)
removes the directory part up to and including the last /
. Example: project1
.
So, if your Makefile is /home/john/project1/Makefile
, and even if you call make from anywhere else than /home/john/project1
with make -C
or make -f
, the DIR
, BASE
and DIRNAME
variables will expand as:
DIR: /home/john/project1/
BASE: project1
DIRNAME: /home/john/project1/project1
Upvotes: 2