X-Git-Url: https://mattmccutchen.net/mgear/mgear.git/blobdiff_plain/59ba5775171ada02731636b6ec3877f493085153..0382f3351db8ba1e76ce006859783b7d49622892:/mgear.mk diff --git a/mgear.mk b/mgear.mk index d456fd5..cccdbc2 100644 --- a/mgear.mk +++ b/mgear.mk @@ -10,11 +10,16 @@ mg-orig-default-goal:=$(.DEFAULT_GOAL) # instead of trying to anticipate which prerequisites it will need in advance. .SECONDEXPANSION: +# Deletion of intermediate files messes everything up. +# TODO: See if we can relax this requirement. +.SECONDARY: + # TEXT UTILITIES empty:= bs:=\$(empty) hash:=\# +comma:=, pct:=% define nl @@ -25,6 +30,9 @@ sq='$(subst ','\'',$1)' # Make-quote: a$\nb => a$$$(nl)b # This is enough to assign the value, *but not to use it as an argument!* mqas=$(subst $(hash),$$(hash),$(subst $(nl),$$(nl),$(subst $$,$$$$,$1))) +# Make the value safe to use as an argument without doubling $. +# *The implementation is incomplete*; I will improve it as needed. +msarg=$(subst $(comma),$$(comma),$1) # Return nonempty if the strings are equal, empty otherwise. # If the strings have only nice characters, you can do $(filter x$1,x$2). streq=$(findstring x$1,$(findstring x$2,x$1)) @@ -105,20 +113,21 @@ $(opfx)%: $$(empty) $$($$(oid)@opr) # prerequisite change, etc. and acts accordingly. # # Target metadata variables for bar: (* means stored in bar.g) +# Now some variables are reused instead of remembered for every target. +# +# @name:=bar +# Name of the target to which @cmd, @warnings, @deps refer. # -# bar@cmd:=cat foo >bar.tmp +# @cmd:=cat foo >bar.tmp # Generation command as given to the shell.* # -# bar@warnings:=$(empty)yikes! +# @warnings:=$(empty)yikes! # Data that the command printed to stdout or stderr, presumably warnings.* # -# bar@deps:=included@x oops@ +# @deps:=included@x oops@ # If dependency-logging, list of filename@revision used. Revision is x for # exists and empty for doesn't exist. Later perhaps x will be the mtime.* # -# bar@gloaded:=1 -# Set if mgear has loaded bar.g and hasn't changed it since then. -# # bar@gdeps:=foo # Static dependencies of bar, for checking by bar.g. # @@ -145,28 +154,33 @@ $(opfx)%: $$(empty) $$($$(oid)@opr) # - Vpath # $(call gload,foo.o) -# Make sure foo.o's genfile, if any, has been loaded. +# Load foo.o's genfile, if any, into $(@cmd), etc. define gload -$(if $($1@gloaded),,$(eval -$1@cmd:= -$1@warnings:= -$1@deps:= +$(if $(filter $(@name),$1),,$(eval +# TODO: Store and check the version of mgear that wrote the genfile. +#@mgear-version:= +@cmd:= +@warnings:= +@deps:= -include $1.g -$1@gloaded:=1 +@name:=$1 )) endef +@name:= # bar.g: scout bar and its dependencies and store $?. When implicit rules # compete for bar, we depend on the rule make uses being the last one it # second-expands so that $(bar@gdeps) is still correct. mg-genfile-oid:=$(newoid) mg-scout-oid:=$(newoid) -$(mg-genfile-oid)@opr=$($(otgt:.g=)@gdeps) $(if $(wildcard $(otgt:.g=)),$(mg-scout-oid)$(aname)$(otgt:.g=),) -$(mg-genfile-oid)@ocmd=$(eval $(otgt:.g=)@gq:=$?) +$(mg-genfile-oid)@opr=$($(otgt:.g=)@gdeps) $(if $(wildcard $(otgt:.g=)),$(mg-scout-oid)$(aname)$(otgt:.g=),) MG-FORCE +$(mg-genfile-oid)@ocmd=$(eval $(otgt:.g=)@gq:=$(filter-out MG-%,$?)) +$(mg-scout-oid)@opr:= +$(mg-scout-oid)@ocmd:= # Mgear-ized automatic variables. -# $@: needs no translation -# NOTE: $(mg@) is *eventual* target. Commands must write to temp file, $t . +# For now, if you really want the eventual target, write $$(@). +mg@ = $@.tmp # $%: haven't thought about it much, but probably needs no translation mg< = $(firstword $(mg^)) mg? = $(filter-out $(opfx)%,$($@@gq)) @@ -175,11 +189,11 @@ mg+ = $(filter-out MG-% $(opfx)%,$+) # $|: needs no translation # $*: needs no translation -# $(call mg-translate-cmd,cat $$< >$$t) +# $(call mg-translate-cmd,cat $$< >$$@) # Replaces references to automatic variables with references to their mgear-ized # counterparts. There might be false matches, e.g., $$@ => $$(mg@) ; # to prevent that, write $$$(empty)@ instead. (c.f. autoconf empty quadrigraph) -mg-translate-cmd=$(subst $$t,$$@.tmp,$(subst $$?,$$(mg?),$(subst $$<,$$(mg<),$(subst $$^,$$(mg^),$(subst $$+,$$(mg+),$1))))) +mg-translate-cmd=$(subst $$@,$$(mg@),$(subst $$?,$$(mg?),$(subst $$<,$$(mg<),$(subst $$^,$$(mg^),$(subst $$+,$$(mg+),$1))))) # $(call mg-prereq-predict,target,prerequisites) # Expands to code that does the following at second-expansion time: @@ -198,9 +212,10 @@ mg-prereq-predict=$$$$(call mg-set-gdeps,$$$$+ $(if $(findstring /,$1),$$$$(subs MG-FORCE: .PHONY: MG-FORCE -# $(call mg-define-rule,target,prerequisites,cmd) -# Defines a rule. cmd is expanded again when it is run, at which time -# Mgear-ized automatic variables are available. +# $(call mg-define-rule,target,prerequisites,cmdvar) +# Defines a rule. cmdvar is *the name of a variable* containing the command. +# The variable is read immediately with $(value) and then expanded in the scope +# of mgear-ized automatic variables each time the rule is run. # # I eradicated the target-specific variables because they fail when there are # multiple implicit rules with the same target pattern. @@ -210,7 +225,7 @@ MG-FORCE: # $(bar@gq). define mg-define-rule $(eval $1: $(call mg-prereq-predict,$1,$2) $2 MG-FORCE $(mg-genfile-oid)$(aname)$$$$@.g - $$(call mg-rule-cmd,$(call mg-translate-cmd,$3))) + $$(call mg-rule-cmd,$(call msarg,$(call mg-translate-cmd,$(value $3))))) endef # TODO Provide a way to define static pattern rules. @@ -249,18 +264,20 @@ define mg-rule-cmd $(mg-assign-cmd) >&3 &&\ $(mg-maybe-move-target) &&\ mv -f $@.g.tmp $@.g\ - ,$(if $($@@warnings),\ - $(info $($@@cmd) # mgear warning replay$(nl)$($@@warnings))\ + ,$(if $(@warnings),\ + $(info $1 # mgear warning replay$(nl)$(@warnings))\ ))) endef # If the command changed, we must regenerate. -mg-check-cmd=$(if $(call streq,$1,$($@@cmd)),,COMMAND-CHANGED) +# HMMM What if the working directory changes? Most likely, the command will +# also change and mgear will do the right thing. +mg-check-cmd=$(if $(call streq,$1,$(@cmd)),,COMMAND-CHANGED) # Pieces of mg-generate that I factored out to make mg-generate more readable. -mg-assign-cmd=echo $(call sq,$(call fmt-make-assignment,$@@cmd,$1)) +mg-assign-cmd=echo $(call sq,$(call fmt-make-assignment,@cmd,$1)) mg-run-cmd={ ($1) 2>&1 && { [ -r $@.tmp ] || { echo 'mgear: error: Command for $@ succeeded without creating it!'; false; }; }; } -mg-wrap-warnings=sed -re '1s/^/$@@warnings:=$$(empty)/; 1!s/^/$@@warnings+=$$(nl)/' +mg-wrap-warnings=sed -re '1s/^/@warnings:=$$(empty)/; 1!s/^/@warnings+=$$(nl)/' # Drat bash's lack of precedence between || and &&. Extra braces necessary. mg-maybe-move-target={ cmp -s $@ $@.tmp || { echo >$@.g && mv -f $@.tmp $@; }; }