In my makefile, I need to make a variable assignment based on a command line variable value. for example, I do:
make var_1=xxx
where
There's a smooth way to do this using recursion as follows. First define a function called pos
that finds the position of an element in a list and then use $(word)
to extract the corresponding element in another list.
Here's pos
:
_pos = $(if $(findstring $1,$2),$(call _pos,$1,\
$(wordlist 2,$(words $2),$2),x $3),$3)
pos = $(words $(call _pos,$1,$2))
Read this answer to understand how it works: Makefile: find function which returns position
Now it's easy to define a function that finds an element in a list and the finds the corresponding element in another list.
lookup = $(word $(call pos,$1,$2),$3)
And then try if out like this:
ALPHA := a b c d e f g h i j k l m n o p q r s t u v w x y z
NATO := alpha beta charlie delta echo foxtrot gamma hotel india\
juliet kilo lima mike november oscar papa quebec romeo\
sierra tango uniform victor whisky yankee zulu
to-nato = $(call lookup,$1,$(ALPHA),$(NATO))
To make a to-nato
function that converts from a letter of the alphabet to the NATO alphabet.
It's a little kludgey, but if there's a symbol you know won't be in any of the values (such as "_") you could do this:
var_1_values = a b c d
var_2_values = A B C D
# This will be a_A b_B c_C d_D
LIST1 = $(join $(addsuffix _,$(var_1_values)),$(var_2_values))
var_1 := a
# The filter gives a_A, the subst turns it into A
var_2 = $(subst $(var_1)_,,$(filter $(var_1)_%, $(LIST1)))
This works in mingw gnu make 4.3 :
define get_index
$(shell \
$(eval _c = 1)\
$(eval _b = n n) \
$(foreach x,$(2), \
$(eval _b += n \
$(eval _c = $(words $(_b)) \
$(if $(filter $(1),$(x)), \
$(eval _r = $(_c)))))) \
echo $(_r) \
$(eval _c =) \
$(eval _b =) \
$(eval _r =) \
)
endef
Takes two arguments; the word to search for and the list where to search. The index is 'returned' by echoing in $(shell ...)
Example:
list = cow horse chicken
index = $(call get_index,horse,$(list))
@echo $(index)
# output: 2
FAB = macrofab
# NOTE: base starts at 1 instead of 0
none := 1
seeed := 1
oshpark := 2
macrofab := 2
pcbng := 3
#NOTE: String must end with a space for word function to work
SUFFIX_DRILLS := "txt xln drl "
.PHONY: gerber
gerber:
@echo $(FAB) drill suffix is $(word $($(FAB)), $(SUFFIX_DRILLS))
Output of make is: macrofab drill suffix is xln
This can be done quite slickly using recursion inside GNU make functions as follows:
_pos = $(if $(findstring $1,$2),$(call _pos,$1,\
$(wordlist 2,$(words $2),$2),x $3),$3)
pos = $(words $(call _pos,$1,$2))
To use it you would $(call)
the pos
function with two arguments: the item to find and the list to find it in. For example,
$(call pos,a,a b c d e f g)
$(call pos,e,a b c d e f g)
$(call pos,g,a b c d e f g)
$(call pos,h,a b c d e f g)
$(call pos,e,))
It works by recursing through the $2
argument until it can no longer find the value in $1
. Each time it recurses it lops the head off $2
using $(wordlist 2,$(words $2),$2)
. Each time is recurses it adds an x
to the returned string so that there is one x
for each position through $2
up to where $1
was found.
It then just uses $(words)
to count the length of the return from _pos
(the number of x
s).
If you use the GMSL project this can be written more slickly write this as:
_pos = $(if $(findstring $1,$2),$(call $0,$1,$(call rest,$2),x $3),$3)
pos = $(words $(call _$0,$1,$2))
Note that I used $0
here which will contain the name of the current function (that's a standard GNU make feature) and the GMSL function rest
to lop the head off the list.
One way simulate associative containers in make is to use computed variables. E.g.:
var_2.a := A
var_2.b := B
# ...
# lookup
var_2 = ${var_2.${var_1}}
# or, lookup and assign a default value if lookup fails
var_2_or_default = $(or ${var_2.${var_1}},<default-value>)