0

What I try to achieve:

  • making a makefile executable using a shebang
  • making it switch to a certain directory beforehands, so it is callable from any where

What I have:

/docker/images/Makefile (with executable flag):

#!/usr/bin/make -f

default: ...
...

I can do

cd /docker/images
./Makefile

However, what I would like to be able to do:

cd /somewhere/else
/docker/images/Makefile

What I tried:

man make states, that I can set a --directoy <dir> param.
However, the shebang #!/usr/bin/make --directory=/docker/images -f, does not work:

$ cd /somewhere/else
$ /docker/images/Makefile
make: *** =/docker/images -f: Datei oder Verzeichnis nicht gefunden.  Schluss.

(File or dir not found)

Any guesses?
I'm on Devuan ASCII with GNU Make 4.1

I've seen the related thread which does not address my issue.

Stephan Richter
  • 1,139
  • 11
  • 31

4 Answers4

2

Sure you can. Use /usr/bin/env with -S option, which is exactly meant for splitting parameters on the shebang line.

$ cat Makefile
#!/usr/bin/env -S make -C /docker/images -f
all:
        echo Foo

Output:

$ /docker/images/Makefile
make: Entering directory '/docker/images'
echo Foo
Foo
make: Leaving directory '/docker/images'
raspy
  • 3,995
  • 1
  • 14
  • 18
  • Heck. This would be the accepted answer, if my env would support it: `/usr/bin/env --version`: env (GNU coreutils) 8.26 Spoiler: it does not. (Only -i, -0, -u) – Stephan Richter May 18 '20 at 11:36
  • Ah, makes sense. It's a 8.30 feature, available in stock Ubuntu 20.04 LTS at least. – raspy May 18 '20 at 14:01
0

When we put #!/usr/bin/make --directory=/docker/images -f

and run /docker/images/Makefile

It's equivalent to run :

/usr/bin/make "--directory=/docker/images -f" /docker/images/Makefile

One solution is to delegate to second line :

#!/home/debian/bin/run_second_line
# /usr/bin/make --directory=/docker/images -f

default: ...
...

In /home/debian/bin/run_second_line:

#!/bin/bash
get_second_line=$(awk 'NR == 2{print}' "$1")
exec bash -c "${get_second_line#?} $1"

Update :

It should work with this shebang:

#!/usr/bin/perl -euse File::Basename;exec qq`make -C @{[dirname $ARGV[0]]} -f ` . $ARGV[0]
Philippe
  • 20,025
  • 2
  • 23
  • 32
  • Well, while it clarifies while my approach does not work, it does not provide a solution either. I want a solution that works without having to call an external program or script. – Stephan Richter May 18 '20 at 08:30
  • My solution achieves both of the requirements at the beginning of your post (You run directly `/docker/images/Makefile`). `a solution that works without having to call an external program or script` is not in your post. – Philippe May 18 '20 at 08:38
  • This is correct. I did not mention the restriction to the single file, because I did not forsee solutions calling external scripts. Sorry for that :D – Stephan Richter May 18 '20 at 09:11
0

What about just:

make -C /some/dir/where/there/is/a/makefile
code_fodder
  • 15,263
  • 17
  • 90
  • 167
  • To my understanding, this does not change to /some/dir/where/there/is/a/ before executing the makefile, does it? And neither allows it to call the makefile as script, as I demanded. – Stephan Richter May 18 '20 at 08:29
  • 2
    This is precisely what `-C` or `--directory` is for. So you won't be able to call it like `/some/dir/makefile` as an executable - but calling it like `make -C /some/dir/` (it will automatically pickup any file called `makefile` is effectively equivalent. I just re-tested this for my sanity and printed `pwd` in a rule and it printed the required directory. It is a suggested alternative, you do not have to accept this answer : ) – code_fodder May 18 '20 at 08:44
  • Yes, I know that. However I am explicitly searching for a solution, that *will* allow me to start it as an executable, while maintaining the possibility to run `make -C /somedir Makefile`. Anyway, thanks for your input! – Stephan Richter May 18 '20 at 08:46
  • Just one more question - do you need to call the makefile directly as an executable - or would it be acceptable to have an accompanying executable that lives next to your makefile (say called `makefile_exec.sh` or something). This can then determine its own location make sure that is the current directory and then just call `make`... without knowing the precise reason you want your makefile to be executable it is difficult to know, but AFAIK this is again another equivalent method - but weather it suites your specific need I do not know : ) – code_fodder May 18 '20 at 19:34
  • Yeah, as mentioned in another [comment](https://stackoverflow.com/questions/61848450/executable-makefile-that-runs-in-a-specific-directory/61850877?noredirect=1#comment109423635_61849526), I want to be able to call it as executable. And via `make -C`. A bit out of curiosity, a bit because of simpicity on the calling part. And a little bit just because I can. – Stephan Richter May 18 '20 at 21:09
0

Inspired from similar approaches, I found a solution:

My makefile now has the following head:

#!/bin/bash

# the following block will be executed by bash, but not make
define BASH_CODE 2>/dev/null
make -C $(dirname $0) -f $(basename $0) $@
exit 0
endef

# the following lines will be interpreted by make, but not bash

# Makefile starts here #
volumes = $$HOME/docker/volumes

# headings created with https://www.askapache.com/online-tools/figlet-ascii/

default: talk

talk:
    @echo Dies ist ein Test
    pwd

...

With these lines in place I can now do the following:

  1. call make -C /path/to/makefile/
  2. call /path/to/makefile/Makefile

Anybody with a better solution?

Stephan Richter
  • 1,139
  • 11
  • 31