Target_2 is unable to get value of eval set in target_1,
The destination eval turns out empty handed, i.e no value is assigned to it
.PHONY:target_1
target_1:
ifeq ($(RQM_SETUP),ci)
$(eval efs-mount-path := $(shell mktemp -d))
else
#echo "$(VAR)"
endif
.PHONY:target_2
target_2:
$(MAKE) target_1 VAR=dags
$(eval destination := $(efs-mount-path))
Related
Looking for ways to assign a variable in a Makefile based on the existence of a directory.
Eg: (pseudo code)
if dir "src/$(project)" exists
SOURCE_DIR := src/$(project)
else
SOURCE_DIR := src/default
test.o: $SOURCE_DIR/test.c
gcc -c -o $# $<
What's the best way to achieve the above
As your source directory will contain files and a non-existing directory will not, you can utilize the GNU make internal function $(wildcard):
project := test
# returns all entries under src/$(project) directory or empty string
ifneq ($(wildcard src/$(project)/*),)
SOURCE_DIR := src/$(project)
else
SOURCE_DIR := src/default
endif
.PHONY: all
all:
#echo $(SOURCE_DIR)
Test run
$ ls src/test/
a.c
$ make
src/test
$ rm -rf src/test
$ make
src/default
BONUS: it might be more readable to rewrite the conditional like this:
SOURCE_DIR := src/$(project)
ifeq ($(wildcard $(SOURCE_DIR)/*),)
# fall back to default directory
SOURCE_DIR := src/default
endif
UPDATE 2: if you don't want to rely on the existence of any files in the directory, you can also test the directory name directly. A directory always has an entry ., because it points to itself:
SOURCE_DIR := src/$(project)
ifeq ($(wildcard $(SOURCE_DIR)/.),)
# fall back to default directory
SOURCE_DIR := src/default
endif
UPDATE 3: adding a check that $(project) is set:
SOURCE_DIR := src/$(project)
ifeq ($(strip $(project)),)
# fall back to default directory
SOURCE_DIR := src/default
else ifeq ($(wildcard $(SOURCE_DIR)/.),)
# fall back to default directory
SOURCE_DIR := src/default
endif
or if you prefer makefile Golfing (thanks #MadScientist for the suggestion)
SOURCE_DIR := $(or $(and $(project),$(wildcard src/$(project)/.)),src/default)
$(and) result
if $(project) is an empty string: empty string
if src/$(project) is not a directory: empty string
otherwise: src/$(project)/., which is equivalent to src/$(project)
$(or) result
if $(and) returns empty string: src/default
otherwise: the string returned by $(and)
CAVEAT: the above listed tests will fail if $(project) contains white space.
Try this.
SOURCE_DIR := src/$(shell test -d src/"$(project)" && echo "$(project)" || echo default)
define func1
include $(shell pwd)/test/$(strip $1)/component.mk
$(info :::::::${NAME} ::::::::::::::: )
endef
INCLUDES := a b c
$(foreach dir, $(INCLUDES), $(eval $(call func1, $(dir)) ))
all : $(objs)
Contents of each makefile:
cat test/a/component.mk
NAME := AA
cat test/b/component.mk
NAME := BB
cat test/c/component.mk
NAME := CC
Output is
::::::: :::::::::::::::
:::::::AA :::::::::::::::
:::::::BB :::::::::::::::
It looks like first time NAME is empty.
Let's look at the expansion of $(foreach dir, ${INCLUDES}, $(eval $(call func1, ${dir}) )) in painful detail.
${INCLUDES} is expanded, giving $(foreach dir,a b c,$(eval $(call func1,${dir})))
Next dir is set to a
$(call func1,a) is expanded
1 is set to a
func1 is expanded:
include $(shell pwd)/test/$(strip $1)/component.mk
$(info :::::::${NAME} ::::::::::::::: )
$(shell pwd) becomes HERE, say (N.B. Use ${CURDIR} instead)
$(strip $1) becomes $(strip a) becomes a
${NAME} expands to nothing
$(info ::::::: ::::::::::::::: ) expands to nothing
As a side effect ::::::: ::::::::::::::: appears on stdout
$(eval $(call func1,a)) expands to $(eval include HERE/test/a/component.mk), expands to nothing
As a side effect, the include is processed by make
Presumably HERE/test/a/component.mk exists and contains valid make syntax,
and the variable NAME gets a value.
1 is set to b. Lather, rinse, repeat.
Tip
To get a hint of problems in code like this, always run make with --warn:
$ make --warn -Rr
Makefile:8: warning: undefined variable 'NAME'
::::::: :::::::::::::::
⋮
Fix
To get some insight, replace the $(eval stuff) with $(error [stuff])
$ make
::::::: :::::::::::::::
Makefile:8: *** [ include /cygdrive/c/Users/somewhere/a/component.mk
]. Stop.
Here we see the $(info …) has disappeared even before it has got to the eval.
The naive fix is pretty horrible.
define func1
include $(shell pwd)/test/$(strip $1)/component.mk
$$(info :::::::$${NAME} ::::::::::::::: )
endef
Running this with the $(error …) in place gives
$ make
Makefile:8: *** [ include /cygdrive/c/Users/somewhere/a/component.mk
$(info :::::::${NAME} ::::::::::::::: )]. Stop.
That stuff between the [ and ] is valid make syntax.
Tidied up it looks like:
include /cygdrive/c/Users/somewhere/a/component.mk
$(info :::::::${NAME} ::::::::::::::: )
Job done. There are cleaner ways, but you need to understand the pain first!
I have the following makefile:
C_FILE=""
cfg:
## C to CFG ####
# echo $(C_FILE)
ifndef C_FILE
$(error variable C_FILE not set)
endif
$(eval CFG_FILE := ./outputs/temp/$(shell basename $(C_FILE) .c).cfg)
gcc -fdump-tree-cfg=$(CFG_FILE) $(C_FILE)
When I run the command make cfg C_FILE="./inputs/Fib.c" it always
terminates saying variable C_FILE not set.
Lines beginning with a tab character (by default) aren't parsed by make (other than for variable expansion), they're sent directly to the shell, get rid of the indents on the lines with the make conditionals
C_FILE=""
cfg:
## C to CFG ####
# echo $(C_FILE)
ifndef C_FILE
$(error variable C_FILE not set)
endif
$(eval CFG_FILE := ./outputs/temp/$(shell basename $(C_FILE) .c).cfg)
gcc -fdump-tree-cfg=$(CFG_FILE) $(C_FILE)
I'd like to add some comments to user657267's answer.
ifndef C_FILE is always false. C_FILE is defined on the first line, or from command line. Consider using ifeq "" "$(C_FILE)".
Quote (") is normal character in makefile. Define empty variable this way:
C_FILE=
instead of using $(shell ) function, use makefile built-ins:
$(basename $(notdir $(C_FILE)))
avoid using $(eval ) if not really needed. Extract relevant code outside recipe.
My proposal is:
C_FILE=
ifeq "" "$(C_FILE)"
$(error variable C_FILE not set)
endif
CFG_FILE=./outputs/temp/$(basename $(notdir $(C_FILE))).cfg
cfg:
## C to CFG ####
# echo $(C_FILE)
gcc -fdump-tree-cfg=$(CFG_FILE) $(C_FILE)
I have something like this in my makefile:
exit_code := $(shell some_script.py; echo $$?)
ifneq ($(exit_code),0)
$(error Error occured)
endif
and it works properly - the echo $$? returns exit code of python script
I need to put that code into define like that:
define run-python-script
exit_code := $(shell some_script.py; echo $$?)
ifneq ($(exit_code),0)
$(error Error occured)
endif
endef
$(call run-python-script)
but then exit_code does not contain the exit code. And $(error Error occured) is always executed.
How to make work the version with define?
I need to put that code into define like that:
The if()/endif are processed and evaluated when the Makefile is parsed. You can't use them inside a variable definition.
The exit_code := ... in first snippet is a definition of a make variable, while in the second it is just a string, part of the make's variable called run-python-script.
You can try this (your script is replaced with false for test purposes):
eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1)))
the-command = false; echo $$?
run-python-script = $(if $(call eq,0,$(shell $(the-command))),,$(error Error occured))
$(run-python-script)
(The $(call) is redundant in that case.)
I want to add Modules to my build system.
To keep my makefile clean when adding new modules, they all follow the same pattern, so I tried to generalize it with a function:
uc = $(shell echo $1 | tr '[a-z]' '[A-Z]')
define driver-mod
$(eval CFLAGS += -DUSE_$(call uc, $1));
$(eval include $(DRIVERS_SRC)/$1/Makefile.include);
endef
ifneq (,$(filter led,$(USEMODULE)))
$(call driver-mod, led)
endif
ifneq (,$(filter uart,$(USEMODULE)))
$(call driver-mod, uart)
endif
ifneq (,$(filter button,$(USEMODULE)))
$(call driver-mod, button)
endif
(the ifneq is going to be replaced with a $(foreach x, $(USEMODULE), $(call driver-mod, $(x))
However, it seems like $1 in driver-mod is not evaluated, I get
make: *** $(DRIVERS_SRC): Is a directory. Stop.
(doesn't actually output $(DRIVERS_SRC) but it's value, edited for clarity)
When I replace the $1 with e.g. led, it works as expected.
What am I missing?
Turns out I have to escape the $ for eval:
define driver-mod
$(eval CFLAGS += -DUSE_$(call uc, $1));
$(eval include $(DRIVERS_SRC)/\$1/Makefile.include);
endef
works!
Can be simplified as follows:
uc = $(shell echo $1 | tr '[a-z]' '[A-Z]')
define __driver-mod
CFLAGS += -DUSE_$(uc)
include $(DRIVERS_SRC)/$1/Makefile.include
endef
driver-mod = $(eval $(call __driver-mod,$(strip $1)))
$(foreach 1,$(USEMODULE),$(driver-mod))