I am new in makefle, I had need array in makefile then I found that I can achieve that having variable that their items separated with spaces, and then iterating over it. Now I want something like map(key,value) pair to store values with keys. Question: can I have that in makefile ? Thanks in advance..
Asked
Active
Viewed 3,854 times
1
-
1By chance did you get a chance to look at this thread? [Dictionaries/Maps/Lookup Tables in Makefiles](https://stackoverflow.com/questions/40919502/dictionaries-maps-lookup-tables-in-makefiles) – vijay v May 25 '20 at 15:46
-
Thanks, I have viewed that post, it is no helpful in my situation. I do not need many variables I need one long variable from that I get get value passing it's key. – ant_dev May 25 '20 at 15:50
2 Answers
5
You can use token pasting for that:
VAR_FOO_KEY := FOO_VAL
VAR_BAR_KEY := BAR_VAL
#example lookup:
KEY := FOO_KEY
LOOKUP_VAL := $(VAR_$(KEY))

HardcoreHenry
- 5,909
- 2
- 19
- 44
-
-
2This is common practice in larger makefile systems. It avoids unnecessary if statements / for loops. – HardcoreHenry May 25 '20 at 19:34
1
Make a file named KV.mk with the following function definitions:
# KV(3 args): in a dictionary directory record a key value pair in a file
# KV(2 args): in a dictionary directory recover value associated with a key
# KV(1 arg ): remove a dictionary directory
# KV(0 arg ): remove all dictionary directories
define KV
$(if $4,$(error K0123.mk: args>3 forbidden), \
$(if $3,mkdir -p $1.key; echo "$3" > $1.key/$2, \
$(if $2,`cat $1.key/$2`, \
$(if $1,rm -fr $1.key/*, \
rm -fr *.key \
))))
endef
Then make a client Makefile with the following contents:
include KV.mk
all: hello.cpp hello
.PHONY: hello.cpp
hello.cpp:
@echo '#include <iostream>' > $@
@echo 'int main(int argc, char** argv)' >> $@
@echo '{ std::cout << "hello" << std::endl; return 0; }' >> $@
hello: hello.cpp
@$(call KV,$@)
@$(call KV,$@,compiler,g++)
@$(call KV,$@,compiler) -o hello hello.cpp
@./$@
clean:
@rm -f hello.cpp hello
@$(call KV)
Copy these two files into an empty directory and run "make".
This method offers much liberty in having multiple dictionaries with multiple key/value pairs per dictionary. One dictionary may be used for the entire Makefile. Another dictionary may be used for all rules having common needs. Individual dictionaries may be used for each rule.
Simplifying one more step, here is a shell script encapsulating the KV idea.
#!/bin/bash
usage() {
cat <<USAGE
KV(1) -- syre(tm) user command
NAME
KV - key value store management for Makefile
SYNOPSIS
(1) KV [--help]
(2) KV [--clear]
(3) KV [OPTION]... {key}
(4) KV [OPTION]... {key}={value}
1: display usage (this text)
2: clear all dictionaries (make clean)
3: print value associated with key
4: store key value pair in the dictionary and key file
USAGE
if [ "" != "$1" ] ; then echo "KV error: $1"; fi
exit 0
}
if [ $1 = "--help" ] ; then usage;
elif [ $1 = "--clear" ] ; then rm -fr *.key;
else
case $# in
3) mkdir -p $1.key; echo "$3" > $1.key/$2;;
2) cat $1.key/$2;;
1) rm -fr $1.key;;
*) usage "KV error: 1, 2, or 3 args required";;
esac
fi
and here is the same Makefile showing that simplification.
all: hello.cpp hello
.PHONY: hello.cpp
hello.cpp:
@echo '#include <iostream>' > $@
@echo 'int main(int argc, char** argv)' >> $@
@echo '{ std::cout << "hello" << std::endl; return 0; }' >> $@
hello: hello.cpp
@./KV $@
@./KV $@ compiler g++
@`./KV $@ compiler` -o hello hello.cpp
@./$@
clean:
@rm -f hello.cpp hello
@./KV --clear

jlettvin
- 1,113
- 7
- 13