1

I am working on a Makefile that gets executed in a Linux environment and Windows environment (through MINGW64). The script has a variable which is pointing to the shell command which should be used:

SHELL:=/usr/bin/env bash

Later on, that variable is being used to run a shell script:

${SHELL} ./utils/tests.sh

On Linux that works just fine but on Windows with MINGW64 (Git Bash) it fails because /usr/bin/env is being replaced with C:/Program Files/Git/usr/local and there is a space character in "Program Files" which breaks the path in the Makefile.

To solve the issue on Windows, I can put ${SHELL} in quotes to make sure that the space character is kept:

"${SHELL}" ./utils/tests.sh

However, this is breaking on Linux environments because it becomes a string now and "/usr/bin/env bash" is not executable.

So I came up with this solution:

ifeq ($(OS),Windows_NT)
    "${SHELL}" ./utils/tests.sh
else
    ${SHELL} ./utils/tests.sh
endif

That's now working in both environments (Linux & MINGW64) but it comes with the downside of having 5 lines of code everywhere where I want to run a script. Ideally, I would like to assign the variable just once. I tried this but it doesn't work either:

ifeq ($(OS),Windows_NT)
    SHELL:="/usr/bin/env" bash
else
    SHELL:=/usr/bin/env bash
endif

test: clean build
    ${SHELL} ./utils/tests.sh

Does anyone have a clever solution to my problem?

Benny Code
  • 51,456
  • 28
  • 233
  • 198
  • 1
    Subscribed to learn the results :) – sobolevn Oct 18 '21 at 08:26
  • 1
    Exactly at what point is `/usr/bin/env` replaced with `C:/Program Files/Git/usr/local` and by whom/what? Also, does it absolutely have to be `SHELL:=/usr/bin/env bash`? Why not set it to `/bin/bash`, `/usr/bin/bash` or whatever path it may be that Bash is run from when using `/usr/bin/env bash`? This would eliminate the space from the equation and you could use `"${SHELL}"` throughout. – Fonic Oct 18 '21 at 09:48
  • This might help: https://www.cmcrossroads.com/article/gnu-make-meets-file-names-spaces-them – Carlos Marx Oct 18 '21 at 10:39
  • @Maxxim the /usr/bin/env variable is replaced by MINGW during the execution of `"${SHELL}" ./utils/tests.sh`. The reason why to use `/usr/bin/env bash` comes from here: https://stackoverflow.com/questions/16365130/what-is-the-difference-between-usr-bin-env-bash-and-usr-bin-bash/55927235#55927235 – Benny Code Oct 18 '21 at 12:49
  • @BennyNeugebauer: I'm aware of this, in fact I always use `/usr/bin/env ...` myself whenever possible. However, it's just a recommendation, not a necessity. But I'm curious about something else: why use calls like `${SHELL} ./utils/tests.sh` at all? Why not simply run `./utils/tests.sh` directly and put `#!/usr/bin/env bash` inside that script? Why go through the shell to run the script? Any particular reason for this? – Fonic Oct 18 '21 at 13:45
  • `SHELL` is already the name of a shell builtin for make which tells it which shell to use for all operations (including `$(shell)` functions) - the `${SHELL}` part is unnecessary – Emily-TTG Oct 19 '21 at 14:08
  • I tested Maxxim's solution (replacing `/usr/bin/env bash` with `bash` and using it with quotation marks) which worked out great. @Maxxim please post that as the answer so I can accept it. Thanks to all of you! – Benny Code Oct 19 '21 at 16:36

1 Answers1

1

You could replace:

SHELL:=/usr/bin/env bash

with one of these (or with whatever path directly leads to Bash's executable):

SHELL:=/bin/bash
SHELL:=/usr/bin/bash
SHELL:=bash

which would eliminate the space from the equation.


That being said, you should also be able to run the commands directly, i.e.:

./utils/tests.sh

instead of:

${SHELL} ./utils/tests.sh

which would eliminate the need to set and use variable SHELL altogether.

Fonic
  • 2,625
  • 23
  • 20