Makefile - Function to check empty environment variables - makefile

I am trying to write a function to check if multiple environment variables are set. In this example, I've just tried to use a function which does not works probably because call opens up a subshell which does not has my exported variable.
What is a neat way to check multiple environment variables? I am trying to avoid multiple ifndef statements in my Makefile.
Makefile
define func_test
ifndef ${1}
$(error ${1} is not set - does not works)
endif
endef
test:
#$(call func_test, account_name)
ifndef account_name
$(error account_name is not set - works)
endif
Logs
~ $ export account_name=somename
~ $ make test
Makefile:8: *** account_name is not set - does not works. Stop.
~ $

Check if variable is empty
$(if $(some_var),,$(error some_var is not defined))

Related

Setting a variable in Makefiles through the command line [duplicate]

I am trying to do a simple thing:
TMPDIR ?= /tmp
test:
#echo $(TMPDIR)
This works if I run:
$ make test
/tmp
It also works if I run:
$ make test -e TMPDIR=~/tmp
/home/user/tmp
What can I do to also have it works for:
$ TMPDIR=~/tmp make test
/home/user/tmp
To follow up on my comments above, here's an example:
T ?= foo
all:
: '$(T)'
Now if I run the Makefile in various ways, it behaves as we expect (I get foo only if I don't set T either on the command line or environment):
$ make
: 'foo'
$ make T=bar
: 'bar'
$ T=bar make
: 'bar'
Variables specified on make command line override the values assigned in makefile:
TMPDIR := "/tmp"
test:
#echo $(TMPDIR)
And then:
make TMPDIR=whatever
whatever
It is generally considered a bad practice for makefiles to depend on environment variables because that may lead to non-reproducible builds. This is why passing variable overrides in make command line explicitly is recommended.
Here is a simple solution:
SHELL := env TMPDIR=$(TMPDIR) $(SHELL)
TMPDIR ?= "/tmp"
all:
#echo $(TMPDIR)
which works for both scenarios: TMPDIR=new/path make and make TMPDIR=new/path.
One of the thing you could do is:
TMPDIR := "/tmp"
ifdef $$TMPDIR
TMPDIR := $$TMPDIR
endif
test:
echo $(TMPDIR)

Unable to pass environment variables from makefile target to a bash file

I have the following Makefile:
my-file/config.json: check-envs
./my-script.sh
check-envs:
ifndef MY_VARIABLE
$(error Variable MY_VARIABLE isn't set)
endif
ifndef MY_NAME
$(error Variable MY_NAME isn't set)
endif
.PHONY: init-config
init-config: deps
init-config: export MY_VARIABLE=space-1
init-config: my-file/config.json
.PHONY: deps
deps:
# install deps here
So I tried running MY_NAME=example make init-config, but check-envs target fails with the MY_VARIABLE being not set.
I've tried to change the logic to, for example, validate environment variables in my-script.sh but unfortunately the same result happens, I can't pass the environment variable to the script from the Makefile.
What you are doing is not really how makefiles work. They work per-target, so in target init-config you can set some stuff up, but it won't persist to another target.
You have some options:
1.) Set your variable in the makefile body (variables are evaluated before the targets are executed):
# Here
MY_VARIABLE = xyz
my-file/config.json: check-envs
./my-script.sh
check-envs:
ifndef MY_VARIABLE
$(error Variable MY_VARIABLE isn't set)
endif
:
etc
:
2.) Pass the variable in:
make some_target MY_VARIABLE=xyz
3.) Parse the arguments list
# Get all the makefile parameters (or arguments)
ALL_PARAMS = $(wordlist 1,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
# Test for your argument and set a variable accordingly
ifneq (,$(findstring my_param,$(ALL_PARAMS)))
MY_VARIABLE=xzy
endif
# Empty rule so the my_param is not complained about as a missing target
my_param:;#;
my-file/config.json: check-envs
./my-script.sh
check-envs:
ifndef MY_VARIABLE
$(error Variable MY_VARIABLE isn't set)
endif
:
etc
And then call like: make my_param check-envs
The last way, is a bit messy, but the results are quite good because it gives you make tab-completion instead of the horrbile passing in a variable.

use environment variable if set otherwise use default value in makefile

I can do this:
MY_VAR:=$(myvar)
But what I want is to also define a value for MY_VAR that is used if the environment variable myvar isn't defined. Is this possible?
Something like:
# pseudo code
MY_VAR:=if not $(myvar) then someDefaultValue
Assuming make is GNU Make, all the environment variable settings inherited by make are automatically registered
as make variable settings. See 6.10 Variables from the Environment. So you can just write, e.g.
Makefile (1)
ifdef myvar
MYVAR := $(myvar)
else
MYVAR := default
endif
.PHONY: all
all:
echo $(MYVAR)
Which runs like:
$ make
echo default
default
when myvar is not defined in the environment; and when it is defined,
runs like:
$ export myvar=notDefault
$ make
echo notDefault
notDefault
And in case the environment variable and the make variable are the same - and why not? - it is simpler still.
Makefile (2)
MYVAR ?= default
.PHONY: all
all:
echo $(MYVAR)
See 6.5 Setting Variables
Then:
$ make
echo default
default
$ export MYVAR=notDefault
$ make
echo notDefault
notDefault
you can try this code below.
MY_VAR=${HOSTNAME1}
if [ "$MY_VAR" = "" ]; then
MY_VAR="DEFAULT"
fi

Makefile: macros with default parameters

Consider the following Makefile:
MAKEFLAGS += --warn-undefined-variables
define foobar
echo "$(1)"
endef
.PHONY: all
all:
$(foobar)
Is there a way to have macros with default parameters without producing undefined variable warnings?
I mean: sometimes I call "foobar" with a parameter, but sometimes not. In the latter case I'd like to have a default value for $(1).
You can't set a default value in the macro but you can easily add one when the parameter is expanded:
1:=
define foobar
echo "$(if $1,$1,default)"
endef
all:
$(foobar)
$(call foobar,biz)
$ make
echo "default"
default
echo "biz"
biz
It's a bit annoying if you use the parameter lots of times because you have to use the if for each use.
The GNU make syntax is very limited; it's not a full blown programming language, so many things are missing, like default parameters in make macros.
But the shell is a programming language! Why not implement your requirements in the commands of a target? It may be possible to use something like this:
all:
if test "$(SOMECONDITION)"; then \
do_one_thing; \
else \
do_something_else; \
fi
There is a decent solution for GNU make. Not sure how portable it is.
Use a global variable that embodies the rather messy logic, using a naming convention to avoid conflicts:
# foo.mk
MAKEFLAGS += --warn-undefined-variables
foobar_p1_default = default parameter
foobar_p1 = $(if $(filter undefined,$(origin 1)),$(foobar_p1_default),$1)
define foobar
#echo $#: "$(foobar_p1)"
endef
.PHONY: all defaulted global local
all : defaulted global local
defaulted:
$(foobar)
variable = global value
global local:
$(call foobar,parameter was $(variable))
local: variable = target specific value
The results:
$ make -f foo.mk
defaulted: default parameter
global: parameter was global value
local: parameter was target specific value

Define a Makefile variable using a ENV variable or a default value

I am trying to do a simple thing:
TMPDIR ?= /tmp
test:
#echo $(TMPDIR)
This works if I run:
$ make test
/tmp
It also works if I run:
$ make test -e TMPDIR=~/tmp
/home/user/tmp
What can I do to also have it works for:
$ TMPDIR=~/tmp make test
/home/user/tmp
To follow up on my comments above, here's an example:
T ?= foo
all:
: '$(T)'
Now if I run the Makefile in various ways, it behaves as we expect (I get foo only if I don't set T either on the command line or environment):
$ make
: 'foo'
$ make T=bar
: 'bar'
$ T=bar make
: 'bar'
Variables specified on make command line override the values assigned in makefile:
TMPDIR := "/tmp"
test:
#echo $(TMPDIR)
And then:
make TMPDIR=whatever
whatever
It is generally considered a bad practice for makefiles to depend on environment variables because that may lead to non-reproducible builds. This is why passing variable overrides in make command line explicitly is recommended.
Here is a simple solution:
SHELL := env TMPDIR=$(TMPDIR) $(SHELL)
TMPDIR ?= "/tmp"
all:
#echo $(TMPDIR)
which works for both scenarios: TMPDIR=new/path make and make TMPDIR=new/path.
One of the thing you could do is:
TMPDIR := "/tmp"
ifdef $$TMPDIR
TMPDIR := $$TMPDIR
endif
test:
echo $(TMPDIR)

Resources