07_05_GuyT
07_05_GuyT

Reputation: 2887

Create folder for the parent name dynamically

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

Answers (1)

Renaud Pacalet
Renaud Pacalet

Reputation: 29335

I assume:

  1. That you are using GNU make.
  2. That you have only "reasonable" file and directory names without spaces, special characters or even worse. If you name your makefile "my favorite make file", what follows will not work.
  3. That you want to create your sub-directory in the directory that contains your Makefile.

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:

  1. 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.

  2. $(dir <some-path>) keeps only the directory part, removing the file part. Example: /home/john/project1/.

  3. $(patsubst %/,%,<some-path>) removes the trailing /, if any. Example: /home/john/project1.

  4. $(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

Related Questions