obfn1:=/./.
#obfn=$(obfn1)$(eval obfn1=$(patsubst /.//////%,/.//./%,$(subst /.//////,//./,$(obfn1)/)))
-#obfn=$(obfn1)$(eval pr$(obfn1)=$1)$(eval cmd$(obfn1)=$2)$(eval obfn1:=$(subst /.//////,//./,$(patsubst /.//////%,/././%,$(obfn1:.=/.))))
-obfn=$(obfn1)$(eval pr=$1)$(eval cmd=$2)$(eval obfn1:=$(subst /.//////,//./,$(patsubst /.//////%,/././%,$(obfn1:.=/.))))
+obfn=$(obfn1)$(eval pr$(obfn1)=$1)$(eval cmd$(obfn1)=$2)$(eval obfn1:=$(subst /.//////,//./,$(patsubst /.//////%,/././%,$(obfn1:.=/.))))
+#obfn=$(obfn1)$(eval pr=$1)$(eval cmd=$2)$(eval obfn1:=$(subst /.//////,//./,$(patsubst /.//////%,/././%,$(obfn1:.=/.))))
digits=0 1 2 3 4 5 6 7 8 9
%yx: $(foreach d,$(digits),%$dy)
-#%y: $$(call obfn,FORCE,$$$$(info Running $$@ $$$$@))
-%y: $$(call obfn,,)
+%y: $$(call obfn,FORCE,$$$$(info Running $$@ $$$$@))
+#%y: $$(call obfn,,)
-/./%: $$(pr)
- $(cmd)
+/./%: $$(pr$$@)
+ $(cmd$@)
FORCE:
# 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
$(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.
# - bar is unmanaged => warn about override
MG-FORCE:
.PHONY: MG-FORCE
+scout-oid:=$(newoid)
define mg-define-rule
$(eval
# 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)
# 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:=)\
,\