0

Let's say I have a directory ~/dir1/dir2/dir3/ and a file Makefile in that directory with the contents

include ../Makefile

~/dir1/dir2/Makefile has the same contents as ~/dir1/dir2/dir3/Makefile

If I am allowed to control the contents of ~/dir1/Makefile, and make was invoked in ~/dir1/dir2/dir3/, How do I get the string ~/dir1/dir2/dir3/Makefile(The first include file) for use as a variable in ~/dir1/Makefile?

Reproducible Example (as requested by MadScientist) :

  1. Any unix system
  2. mkdir -p ~/dir1/dir2/dir3
  3. cd ~/dir1/dir2/dir3
  4. echo 'include ../Makefile' > Makefile
  5. cp ./Makefile ../Makefile

Now we have a Makefile in ~/dir1/dir2/dir3/ and ~/dir1/dir2/ with the same declaration, i.e. an include declaration that includes the Makefile in the parent directory.

If make is invoked in ~/dir1/dir2/dir3, then the include chains finally stop at ~/dir1/Makefile

How do I find the path of the first file in this chain of includes, i.e. ~/dir1/dir2/dir3/Makefile for use as a variable in ~/dir1/Makefile?

Monke
  • 93
  • 6
  • It would be easier to understand the question if the names of the directories weren't all the same. I'm not sure how you get from `~/test/test/test/Makefile` to `~/test/Makefile`... is there another include? In any event, I think you can get what you are looking for by appropriate use of `MAKEFILE_LIST` https://www.gnu.org/software/make/manual/html_node/Special-Variables.html#index-MAKEFILE_005fLIST-_0028list-of-parsed-makefiles_0029 but if not maybe you can clarify the question, hopefully with a MCVE https://stackoverflow.com/help/minimal-reproducible-example – MadScientist Jan 18 '21 at 15:51
  • I would suggest that you use `include` only to incorporate makefile fragments that are specifically designed for and used exclusively for that purpose. Otherwise, use recursive `make` if you want to use rules defined in other makefiles. This will save you a lot of headaches. Among those is being uncertain of whether any given file is the root of the inclusion tree. – John Bollinger Jan 18 '21 at 16:16
  • @MadScientist I have refactored the post as per your proposal. `MAKEFILE_LIST` indeed does the job for me, but after refactoring the post I have discovered another error. Somehow, including an Makefile from a parent directory means that you cannot include another Makefile present in the parent directory of the included Makefile(in the included Makefile), the example I've cooked up returns a Bad Address error in make due to the dir2 makefile including ```../Makefile``` – Monke Jan 18 '21 at 16:23
  • Your newly discovered error is a bug in the lower two makefiles; you can fix it, but not from within the top makefile. As for the primary problem, do you want the tilde ('~')? An absolute path (e.g. `/users/monke/dir1/dir2/dir3/Makefile`) is much easier to construct. – Beta Jan 18 '21 at 17:40

1 Answers1

1

To get the full path of the first make file invoked from the CLI:

make_path_called_from_cli:=$(firstword $(foreach mk,${MAKEFILE_LIST},$(abspath ${mk})))

To get the full path of the make file which included the current make file:

$(info Using GNUmake Special variable to obtain Every make file used...)

$(info ${MAKEFILE_LIST})

$(info Compute the full path for all of those make files...)
all_make_file_full_path:=$(foreach mk,${MAKEFILE_LIST},$(abspath ${mk}))

$(info ${all_make_file_full_path})

$(info The last one from the list is the current make file...)

current_make_file_path:=$(lastword ${all_make_file_full_path})
$(info ${current_make_file_path})

$(info Now we remove the current make file from the list of make...)
all_make_file_path_except_current:=$(filter-out ${current_make_file_path}, ${all_make_file_full_path})

$(info ${all_make_file_path_except_current})

# Now the last one from the list is the make file which included the current one
parent_make_file_path:=$(lastword ${all_make_file_path_except_current})

$(info We finally have the answer...)
$(info ${parent_make_file_path})
elarivie
  • 175
  • 3
  • 7
  • I believe OP was asking for the first makefile invoked (the one from the command line), which would simply be `$(firstword $(MAKEFILE_LIST))` – HardcoreHenry Jan 18 '21 at 18:52