Создайте файл с именем KV.mk со следующими определениями функций:
# 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
Затем создайте клиентский Makefile со следующим содержимым:
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)
Скопируйте эти два файла в пустой каталог и запустите «make».
Этот метод предлагает большую свободу в использовании нескольких словарей с несколькими парами ключ / значение для каждого словаря. Один словарь может использоваться для всего Makefile. Другой словарь может быть использован для всех правил, имеющих общие потребности. Для каждого правила могут использоваться отдельные словари.
Еще один шаг, упрощающий, вот сценарий оболочки, воплощающий идею KV.
#!/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
и тот же Makefile, демонстрирующий это упрощение.
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