Thanks for the detailed examples. Using variables to instantiate all hosts sounds overkill. I just want the pattern rule to also apply when the stem would be empty, and all but one host has a number suffix in their names.
I end up making all hosts contain the number suffix. Given the solutions provided, it feels like the cleanest one. > On Apr 25, 2020, at 1:29 PM, Kaz Kylheku (gmake) <729-670-0...@kylheku.com> > wrote: > > On 2020-04-24 21:56, Kaz Kylheku (gmake) wrote: >> And a fourth option: keep the host names inconsistent >> (they are probably hard to change) but enumerate them >> with consistently named stamp files (easy to control). >> Use computed variable names to associate the two together: >> remote-bin-host%: bin >> scp $< $(host_$*):$< >> touch $@ > > > With computed variable names, you can fake out a data > structure in which it looks like keys are matched to records > that have fields. > > Then you can specify a database of hosts records, such > that for each one you can give a stamp file name, host > name and any other property, like using a different SSH > key or whatever. > > Please study this Makefile: > > host_1.name := foo > host_1.stamp := foo.txt > > host_2.name := bar > host_2.stamp := bar.txt > > host_list := 1 2 > > define host_bin_template = > $$(host_$1.stamp): bin > echo scp $$< $$(host_$1.name):$$< > touch $$@ > endef > > $(foreach n,$(host_list),$(eval $(call host_bin_template,$n))) > > If we run "make foo.txt", this happens: > > echo scp bin foo:bin > scp bin foo:bin > touch foo.txt > > Make has deduced through the structure we set up and the generated rules that > foo.txt is a stamp file associated with host foo. > > This doesn't use pattern rules at all, but procedural rule expansion. We have > a list of hosts 1 2. > The foreach loop steps over this list, and substitutes it as parameter $1 > into the host_bin_template, which is evaluated via $(eval ...) as a piece of > Makefile syntax. That syntax creates a rule, exactly as if we had typed this > in: > > $(host_1.stamp): bin > echo scp $< $(host_1.name):$< > touch $@ > > $(host_2.stamp): bin > echo scp $< $(host_2.name):$< > touch $@ > > Of course, these variables expand, and so the effect of the for loop and eval > is that this is generated: > > foo.txt: bin > echo scp $< foo:$< > touch $@ > > bar.txt: bin > echo scp $< bar:$< > touch $@ > > > To add, a third rule, we just create new variables: > > host_3.name := saturn.localdomain > host_3.stamp := saturn.stamp > > Update the list: > > host_list = 1 2 3 > > > Done. Now we have a third rule where saturn.stamp is a target, > and updating it copies the bin file to saturn.localdomain. > > With a little more hacking, we can probably (and ironically) > re-create the "rdist" utility. :) > > The advantage of pattern rules is that they avoid instantiation bloat. > A pattern rule can potentially match just, say, one of potentially > thousands of targets, which is more efficient than generating thousands > of rules with an eval. And it can match new things in the filesystem > that don't require any new definitions in the Makefile. > > We lost some of the advantage of the pattern rule when we turned > to computed variables for assistance; manual definitions had to be made > to satisfy the computed variable references. > >