[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master f93cd2f 2/4: Improve documentation
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master f93cd2f 2/4: Improve documentation |
Date: |
Fri, 24 May 2019 09:41:08 -0400 (EDT) |
branch: master
commit f93cd2fe1fc7885ecf6986aca2a8f1341369e2bf
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Improve documentation
---
gwc/parent.make | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 50 insertions(+), 6 deletions(-)
diff --git a/gwc/parent.make b/gwc/parent.make
index e835b9a..9b47722 100644
--- a/gwc/parent.make
+++ b/gwc/parent.make
@@ -39,14 +39,58 @@ all:
# single file. See this discussion:
# https://lists.nongnu.org/archive/html/lmi/2019-05/msg00052.html
+# How does this work?
+#
+# Only a few lines of code are required, and the subtlest one:
+# $(eval include $(LMI_ENV_FILE))
+# isn't very difficult: it simply expands to an appropriate 'include'
+# directive at a particular time. The real challenge is understanding
+# the implicit synchronization. It is instructive to run test cases
+# with 'make --trace', whose output is paraphrased here:
+#
+# begin reading parent.make
+# parent.make has $(LMI_ENV_FILE) as a prerequisite
+# therefore, must remake $(LMI_ENV_FILE)
+# source the script; in the same shell,
+# write 'make' variable definitions to $(LMI_ENV_FILE)
+# finished remaking $(LMI_ENV_FILE)
+# finished prerequisites of parent.make
+# resume reading parent.make
+# now $(LMI_ENV_FILE) is newer than parent.make
+# therefore, must remake parent.make
+# its recipe contains $(eval include $(LMI_ENV_FILE))
+# which expands to a make directive
+# which is executed when parent.make is reread
+# which causes the definitions to take effect
+# finished remaking parent.make
+# finished reading parent.make
+#
+# It is tempting to rearrange the code to make it simpler, but the
+# '--trace' output shows why that doesn't work--for example:
+#
+# - Can the two recipes be combined into one, sourcing the script
+# and writing the temporary file just before $(eval)? No: $(eval)
+# would take effect before the script has been sourced. 'include'
+# is a make directive, not a shell command, so its effect occurs
+# when the makefile is reread--before the recipe is executed.
+#
+# - Can $(eval include) be moved outside the recipe it occurs in,
+# and written outside any rule context (as directives typically are)?
+# No: it would take effect the first time the makefile is read, before
+# the script has been sourced, and it wouldn't be reconsidered later.
+# Functions are usually expanded when read, but not in rule contexts,
+# where expansion is deferred.
+
+# Prior art; alternatives
+#
# Obviously one could simply write a cover script to replace direct
-# invocation of 'make', but that's nasty. See:
+# invocation of 'make', but the goal here is to avoid that. See:
# https://lists.gnu.org/archive/html/help-make/2006-04/msg00142.html
# which suggests 'eval'.
#
-# This is unhelpful:
-#
https://stackoverflow.com/questions/7507810/how-to-source-a-script-in-a-makefile
-# except that it has a link to:
+# An online search for 'make "eval include"' finds few articles, and
+# fewer still that use that construct in a recipe. This one:
# https://blog.153.io/2016/04/18/source-a-shell-script-in-make/
-# which doesn't actually work in its final, simplified version;
-# but earlier in that article it uses 'eval include', which does work.
+# demonstrates the 'eval include' technique adapted here (though it
+# doesn't literally source a script). Its earlier 'eval include'
+# example works, though its final, simplified example seems not to.