- Add a full target obfuscation factory and rule and a comment explaining them.
[mgear/mgear.git] / src / mage.mk
index eba3c6d..22e33aa 100644 (file)
@@ -26,14 +26,42 @@ streq = $(findstring x$1,$(findstring x$2,x$1))
 # newlines appearing in bar safely.
 fmt-make-assignment = $1:=$$(empty)$(call mqas,$2)
 
-# OBFUSCATION
-
-# Coming soon.
+# We use second-expansion heavily to dynamically compute prerequisites when they
+# are needed.  Second-expansion lets us follow make's implicit rule search
+# instead of trying to anticipate which prerequisites it will need in advance.
+.SECONDEXPANSION:
 
-# High-priority implicit rule to ensure that we don't try to actually update
-# obfuscated targets.  TEMP
-/./proc/self/cwd/%:
-       
+# TARGET OBFUSCATION
+
+# Mage uses two kinds of "obfuscated targets" (those that are not the simple
+# names of real files):
+# - An always-exists target like /.//. is used as a prerequisite of an implicit
+#   rule.  Since it exists, make doesn't second-expand its own prerequisites
+#   until it is actually run.  This way, a target's prerequisites can depend on
+#   the results of previous command scripts.
+# - An alternative-name target like /.//./proc/self/cwd/bar is used to check the
+#   mtime of a file without actually building it or introducing a circular
+#   dependency.
+
+# $(newoid) allocates and returns a new obfuscation ID (oid).  Example:
+#    x:=$(newoid)
+# You can then refer to target $x or $x$(aname)bar (for any file bar).
+# Prerequisites and commands come from $($x@opr) and $($x@ocmd).
+# Target-specific variables $(oid) and $(otgt) (if alternate-name) are
+# available.
+
+opfx:=/./
+# TODO If the system doesn't support /proc/self/cwd, use something else.
+aname:=/proc/self/cwd/
+nextoid:=/./.
+newoid=$(nextoid)$(eval nextoid:=$(subst /.//////,//./,$(patsubst /.//////%,/././%,$(nextoid:.=/.))))
+
+# High-priority implicit rule for obfuscated targets.  Works for both always-
+# exists and alternate-name targets.
+$(opfx)%: oid=$(word 1,$(subst $(aname), ,$@))
+$(opfx)%: otgt=$(word 2,$(subst $(aname), ,$@))
+$(opfx)%: $$($$(oid)@opr)
+       $($(oid)@ocmd)
 
 # MAIN BUILD LOGIC
 
@@ -67,10 +95,6 @@ define mg-translate-cmd
 $(subst $$@,$$(mg@),$(subst $$<,$$(mg<),$(subst $$^,$$(mg^),$(subst $$+,$$(mg+),$1))))
 endef
 
-# OOOH!!! .SECONDEXPANSION does let us watch the implicit rule search as it
-# happens.
-.SECONDEXPANSION:
-
 # $(call mg-rule,target,prerequisite,cmd)
 # Defines a rule.
 # If cmd uses $@, quote if necessary so this function sees $@, etc.
@@ -86,6 +110,7 @@ endef
 # - bar is unmanaged => warn about override 
 MG-FORCE:
 .PHONY: MG-FORCE
+scout-oid:=$(newoid)
 define mg-define-rule
 $(eval 
 
@@ -117,7 +142,7 @@ endef
 
 # If the target is unmanaged, we must run the rule; we'll see that the
 # obfuscated target is in $? and complain.
-mg-scout-target=$(if $(wildcard $(target)),/./proc/self/cwd/$(target),)
+mg-scout-target=$(if $(wildcard $(target)),$(scout-oid)$(aname)$(target),)
 
 # If the command changed, we must regenerate.
 mg-check-cmd=$(if $(call streq,$(cmd),$($(target)@cmd)),,x)
@@ -152,7 +177,7 @@ endef
 #        from before the removal. (trap EXIT)
 define mg-generate
        $(call gload,$(target))\
-       $(if $(filter /./proc/self/cwd/$(target),$?),\
+       $(if $(filter $(scout-oid)$(aname)$(target),$?),\
                $(info mage: warning: Manually created/modified file at $(target) overrides rule.)\
                $(eval $(target)@cmd:=)$(eval $(target)@warnings:=)$(eval $(target)@deps:=)\
        ,\