TPPZ
TPPZ

Reputation: 4891

makefile variables within variables executing bash scripts

I have a makefile that I want to run against both linux (debian/Ubuntu) and Windows/Cygwin.

I need to do something slightly different according to the running environment and I came out with the following piece of code which is supposed to store in the variable a string which is foo if the OS is linux, otherwise foo.exe:

EXECUTABLE_FILENAME=bash -c 'os_type=`uname`; if [ $os_type == "Linux" ]; then echo "foo"; else echo "foo.exe"; fi'

then I would like to use that variable in another one, something like:

GODEPBUILD=$(godep go build -o $(EXECUTABLE_FILENAME))

the previous one with/without the evaluation via $(...some stuff...) (see below for all the tests I made to make this work)

finally I would like to "run" that command somewhere else in a task within the makefile, something like:

build-all:
   @echo -e "build my project"
   $(GODEPBUILD)

I have tried many different combinations

but I get all sorts of bash errors e.g.:

I am doing this chain of steps because I need to wrap many commands of the go toolchain into another tool called godep, also I need to combine this with some specific features of the Operating System (e.g. the filename thing I am stuck with). I have defined many different "commands" of the go toolchain at the beginning of the makefile e.g.:

GODEP_VERSION=godep version
GODEPRESTORE=godep restore
GODEPTEST=godep go test -v
GOCLEAN=go clean

I call these "commands" inside the makefile tasks like $(GODEP_VERSION) (or -$(GODEP_VERSION) if I need to ignore the stderr) and for me it was nice to add the "build command" in a similar fashion.

The make version is:

Is this thing possible at all?

How could I achieve this combination of different "small scripts" to build the final command that make should run inside a task?

Upvotes: 0

Views: 693

Answers (1)

Jonathan Wakely
Jonathan Wakely

Reputation: 171273

Surely you want the output of the bash command as the filename, right? You are using the bash command itself as the filename. i.e. $(EXECUTABLE_FILENAME) is a string consisting of several words. When you pass that to the godep command it gets passed as multiple arguments:

godep go build -o $(EXECUTABLE_FILENAME)

becomes:

godep go build -o bash -c 'os_type=`uname`; if [ s_type == "Linux" ]; then echo "foo"; else echo "foo.exe"; fi'

which is complete nonsense (note that $o gets expanded as a make variable, but that's the least of your problems).

Surely you want to run the bash command to decide the filename. You can run a shell command with make's $(shell ...) function:

EXECUTABLE_FILENAME = $(shell os_type=`uname` ; if [ $$os_type == Linux ]; then echo foo ; else echo foo.exe ; fi)

Note I used $$os_type to refer to a shell variable, so make doesn't try to expand $os_type before invoking the shell.

But I would simplify that to something like:

EXECUTABLE_FILENAME = foo$(shell [ `uname` == Linux ] || echo .exe)

Or maybe:

EXECUTABLE_SUFFIX = $(shell [ `uname` == Linux ] || echo .exe)
EXECUTABLE_FILENAME = foo$(EXECUTABLE_SUFFIX)

Now the make variable $(EXECUTABLE_FILENAME) will expand to the filename.

The next problem is here:

GODEPBUILD=$(godep go build -o $(EXECUTABLE_FILENAME))

What is this supposed to mean? Why have you enclosed it in $(...)? That tries to run a make function called godep, surely you just want:

GODEPBUILD = godep go build -o $(EXECUTABLE_FILENAME)

Then when you use it in the recipe it will expand to either:

build-all:
   @echo -e "build my project"
   godep go build -o foo

Or:

build-all:
   @echo -e "build my project"
   godep go build -o foo.exe

N.B. as an optional (but recommended) improvement you should use := to set make variables, because otherwise they get expanded every time they are used. This would mean that every time you refer to a variable that uses $(EXECUTABLE_SUFFIX) the shell command is run again. Changing it to use := will mean it gets evaluated once:

EXECUTABLE_SUFFIX := $(shell [ `uname` == Linux ] || echo .exe)

Similarly, you can use := for the other variables too:

EXECUTABLE_FILENAME := foo$(EXECUTABLE_SUFFIX)
GODEPBUILD := godep go build -o $(EXECUTABLE_FILENAME)

(These ones don't really matter, as long as EXECUTABLE_SUFFIX used := and so already contains the filename).

Upvotes: 1

Related Questions