From 75081c63ee8b204a239572a232d50455556882f4 Mon Sep 17 00:00:00 2001 From: Luke Shumaker Date: Mon, 21 Mar 2016 01:55:24 -0400 Subject: Go ahead and add the generated files. So I know about regressions. --- public/make-memoize.html | 64 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 public/make-memoize.html (limited to 'public/make-memoize.html') diff --git a/public/make-memoize.html b/public/make-memoize.html new file mode 100644 index 0000000..f67c5c5 --- /dev/null +++ b/public/make-memoize.html @@ -0,0 +1,64 @@ + + + + + A memoization routine for GNU Make functions — Luke Shumaker + + + +
Luke Shumaker » blog » make-memoize
+
+

A memoization routine for GNU Make functions

+

I'm a big fan of GNU Make. I'm pretty knowledgeable about it, and was pretty active on the help-make mailing list for a while. Something that many experienced make-ers know of is John Graham-Cumming's "GNU Make Standard Library", or GMSL.

+

I don't like to use it, as I'm capable of defining macros myself as I need them instead of pulling in a 3rd party dependency (and generally like to stay away from the kind of Makefile that would lean heavily on something like GMSL).

+

However, one really neat thing that GMSL offers is a way to memoize expensive functions (such as those that shell out). I was considering pulling in GMSL for one of my projects, almost just for the memoize function.

+

However, John's memoize has a couple short-comings that made it unsuitable for my needs.

+ +

So, I implemented my own, more flexible memoization routine for Make.

+
# This definition of `rest` is equivalent to that in GMSL
+rest = $(wordlist 2,$(words $1),$1)
+
+# How to use: Define 2 variables (the type you would pass to $(call):
+# `_<var>NAME</var>_main` and `_<var>NAME</var>_hash`.  Now, `_<var>NAME</var>_main` is the function getting
+# memoized, and _<var>NAME</var>_hash is a function that hashes the function arguments
+# into a string suitable for a variable name.
+#
+# Then, define the final function like:
+#
+#     <var>NAME</var> = $(foreach func,<var>NAME</var>,$(memoized))
+
+_main = $(_$(func)_main)
+_hash = __memoized_$(_$(func)_hash)
+memoized = $(if $($(_hash)),,$(eval $(_hash) := _ $(_main)))$(call rest,$($(_hash)))
+

However, I later removed it from the Makefile, as I re-implemented the bits that it memoized in a more efficient way, such that memoization was no longer needed, and the whole thing was faster.

+

Later, I realized that my memoized routine could have been improved by replacing func with $0, which would simplify how the final function is declared:

+
# This definition of `rest` is equivalent to that in GMSL
+rest = $(wordlist 2,$(words $1),$1)
+
+# How to use:
+#
+#     _<var>NAME</var>_main = <var>your main function to be memoized</var>
+#     _<var>NAME</var>_hash = <var>your hash function for parameters</var>
+#     <var>NAME</var> = $(memoized)
+#
+# The output of your hash function should be a string following
+# the same rules that variable names follow.
+
+_main = $(_$0_main)
+_hash = __memoized_$(_$0_hash)
+memoized = $(if $($(_hash)),,$(eval $(_hash) := _ $(_main)))$(call rest,$($(_hash)))
+

Now, I'm pretty sure that should work, but I have only actually tested the first version.

+

TL;DR

+

Avoid doing things in Make that would make you lean on complex solutions like an external memoize function.

+

However, if you do end up needing a more flexible memoize routine, I wrote one that you can use.

+ +
+ + + -- cgit v1.2.3