4

Suppose you want to have a makefile that shall generate one file named after the parent directory. One way to do that is to hard-code the target name but that's not very "generic", e.g.

TARGET := dirname.pdf

$(TARGET): $(TARGET:.pdf=.tex)
    pdflatex $(@:.pdf=.tex)

It would be much nicer to retrieve the directory name via make functions. There are various questions (and answers) on SA on how to retrieve the full path of a makefile (e.g., https://stackoverflow.com/a/18137056/1905491) but not the name of the parent directory...

What's the most efficient and portable way to do that in GNU make?

stefanct
  • 2,503
  • 1
  • 28
  • 32

4 Answers4

4

Why not just use the built-in file name functions?

TARGET := $(notdir $(CURDIR))

I guess I'm not sure what you mean by "parent directory"; it's a bit ambiguous. A specific example with a pathname and the result you wanted would make it easier to understand.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • This seems to be even more elegant than [Vroomfondel's solution] (https://stackoverflow.com/a/52784116/1905491). First I thought it would not work when using `-C` but documentation states explicitly that `CURDIR` is set after any `-C` operation has been applied and I have tested it with GNU make 4.1. Thanks! – stefanct Oct 15 '18 at 10:23
2

It depends very much on what you mean by "parent" directory. After all, make can only operate on strings and has no real notion of directories and files in terms of a datatype. You can e.g. extract the last name of a path by calling this function:

parent_name = $(lastword $(subst /, ,$(dir $(abspath $1))))
$(info $(call parent_name,/home/stefanct/myproject/foo.c))

Output:

myproject
Vroomfondel
  • 2,704
  • 1
  • 15
  • 29
  • Right, I forgot to remove the makefile's name from the path with `dir`. From there it's easy with `lastword` (cf. my [convoluted solution](https://stackoverflow.com/a/52783387/1905491) :) Thank you! – stefanct Oct 15 '18 at 09:56
2

If by parent directory you mean:

Makefile path:

/some/file/path/Makefile

Makefile directory:

/some/file/path

Parent directory (of Makefile)

/some/file

Then the following simple code is probably what you're looking for:

 MK_PATH:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
 MK_PARENT:=$(realpath $(MK_PATH)../)
Matt Conway
  • 229
  • 2
  • 8
  • I have the same understanding for OP's question. Watch out if your $(MK_PATH) variable is defined without a "/" at the end. In that case you will need to add a "/" to "MK_PARENT:=$(realpath $(MK_PATH)/../)". This got me for a while – Kiteloopdesign May 02 '22 at 20:56
0

If you have GNU make >4.0 with guile-support (output of $(info .FEATURES) contains guile) and the basename does not contain spaces the following solution works without any external dependencies or subprocesses:

MAKEFILE_PATH:=$(abspath $(lastword $(MAKEFILE_LIST)))
MAKEFILE_PATH_ELEMS:=$(subst /, ,$(MAKEFILE_PATH))
PARENT_DIR:=$(word $(guile (- $(words $(MAKEFILE_PATH_ELEMS)) 1)),$(MAKEFILE_PATH_ELEMS))

Unfortunately, guile support is not enabled by default by (all/many?) distributions and thus this requires to install a distinctive package (e.g., make-guile on Ubuntu) that provides guile support and replaces the ordinary make.

stefanct
  • 2,503
  • 1
  • 28
  • 32