X-Git-Url: https://mattmccutchen.net/mgear/mgear.git/blobdiff_plain/ac64c802d8c1d6bfe58ffd2584e3b3ef37aa4d89..8d481cf58a5338e6ba62a2e9b4c3b2776071cac0:/src/mage.mk diff --git a/src/mage.mk b/src/mage.mk index 47650b3..22e33aa 100644 --- a/src/mage.mk +++ b/src/mage.mk @@ -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. @@ -85,8 +109,8 @@ endef # - bar doesn't exist or is managed and out of date => generate # - bar is unmanaged => warn about override MG-FORCE: -MG-FORCE-TARGET-DNE: -.PHONY: MG-FORCE MG-FORCE-TARGET-DNE +.PHONY: MG-FORCE +scout-oid:=$(newoid) define mg-define-rule $(eval @@ -118,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) @@ -153,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:=)\ ,\