bashmacosmakefilegnu-makepwd

How do get the working directory after a cd in a makefile?


I just need to be able to assign the value of pwd after cd to a variable so I can open a file in my web browser, but I can't seem to figure out how to do that in a Makefile. Interestingly, when searching other answers about people who want to get the directory of the currently-running Makefile after a cd (as opposed to what I want to do, which is get the actual current working directory regardless of where the Makefile is), doing things that they said don't work after a cd still seem to point to the Makefile, not the directory I cd'd into.

I'm running GNU Make 3.81 on Mac OS 10.15, if that matters.

This is my directory setup:

whatever/
|
├── foo/
│    ├── Makefile
│    └── make_a_file.py
└── bar/
     └── Makefile

make_a_file.py generates output.txt. make_a_file.py can be run from /foo/Makefile via make bizz, resulting in:

whatever/
|
├── foo/
│    ├── Makefile
│    ├── make_a_file.py
│    └── output.txt
└── bar/
     └── Makefile

If I manually copy output.txt to the bar directory, and run /bar/Makefile's make html, I end up with an html file in bar, i.e.,

whatever/
|
├── foo/
│    ├── Makefile
│    ├── make_a_file.py
│    └── output.txt
└── bar/
     ├── Makefile
     ├── output.txt
     └── output.html

My problem is that I want to open output.html in my web browser using /foo/Makefile, but it seems that I cannot get the absolute path of /bar/output.html, so I can't call something like python -mwebbrowser file:///$(WHATEVER)/bar/output.html or python -mwebbrowser file:///$(FULLPATH)/output.html. I do not want to hardcode the absolute path; I can only count on bar/ and foo/ not changing their names, not necessarily anything above them.

This is what /foo/Makefile currently looks like.

bizz:
    python make_a_file.py

compile:
    cp outputs/outfile.txt ../bar/output.txt
    cd ../bar/; \
    echo "$(PWD)"; \
    echo "$(shell pwd)"; \
    echo "$(CURDIR)"; \
    make html; \
    python -mwebbrowser file:///$(CURDIR)/_build/html/output.html

Which results this when I run it from foo/:

(venv) foo user$ make compile
cp output.txt ../bar/output.txt
cd ../bar/; \
    echo "/whatever/foo"; \
    echo "/whatever/foo"; \
    echo "/whatever/foo"; \
    make html; \
    python -mwebbrowser file:////whatever/foo/output.html
/whatever/foo
/whatever/foo
/whatever/foo
Running Sphinx v4.4.0
[and other miscellaneous output from the makefile in bar]
build succeeded.

0:85: execution error: File some object wasn’t found. (-43)

I know that the cd must have worked, and that the make html must be executed in the same subshell as the cd because make html does not work without cd'ing into bar first. And yet, all of the echos would you have believe that you are still in foo.

What's going on here? Is there a way around this without hardcoding the absolute path?


Solution

  • The methods you've tried are all evaluated by make before the shell command is ever executed. You need to write a shell command that outputs the current directory, one that executes after the cd.

    The simplest option is pwd:

    compile:
        cp outputs/outfile.txt ../bar/output.txt
        cd ../bar/; \
        pwd; \
        make html; \
        python -mwebbrowser file:///$$(pwd)/_build/html/output.html
    

    Alternatively, you could delay the evaluation of $PWD by escaping the $ so that the shell evaluates it rather than make:

    compile:
        cp outputs/outfile.txt ../bar/output.txt
        cd ../bar/; \
        echo $$PWD; \
        make html; \
        python -mwebbrowser file:///$$PWD/_build/html/output.html