makefile - gnu make - recipe to keep installed version of file aligned with a master version of file -
so here's makefile install foo.conf, based on master copy called foo.conf.master. installs current directory rather /etc, testing purposes:
all: foo.conf.copied foo.conf.copied: foo.conf.master foo.conf cp foo.conf.master foo.conf touch $@ # recipe tell make okay foo.conf not exist beforehand. foo.conf:
so create foo.conf.master:
$ touch foo.conf.master $
and you're ready test:
$ make cp foo.conf.master foo.conf touch foo.conf.copied $
the point if (with "trusted" sysadmin hat on) modify foo.conf.master make (possibly called cron) roll out update:
$ touch foo.conf.master $ make cp foo.conf.master foo.conf touch foo.conf.copied $
but equally important: if (with "rogue" sysadmin hat on) modify installed version make out update:
$ touch foo.conf $ make cp foo.conf.master foo.conf touch foo.conf.copied $
woohoo.
okay, problem: foo.conf isn't file want for, need change static rules pattern rules. okay, that's easy: substitute foo.conf % in targets , dependencies, substitute foo.conf $* in commands, , make minor modification last recipe (which otherwise become '%:') doesn't i'm trying cancel builtin pattern rule.
so clean , create makefile:
all: foo.conf.copied %.copied: %.master % cp $*.master $* touch $@ # recipe tell make okay foo.conf not exist beforehand. # nop tells make i'm not *cancelling* pattern rule here # (see http://stackoverflow.com/questions/34315150/make-implicit-rules-dont-work-without-command). %: ;
but doesn't work:
$ make make: *** no rule make target `foo.conf.copied', needed `all'. stop. $
the error message misleading; foo.conf doesn't know how make, can demonstrated adding following @ bottom of makefile:
foo.conf: touch $@
but that's static rule again, don't want.
there couple more requirements satisfy, above example doesn't demonstrate. these are:
- foo.conf should installable anywhere in filesystem (e.g. /etc/foo/server/foo.conf)
- foo.conf.master should in central directory, or subdirectly thereof, master versions, preferably without '.master' extension (e.g. ~/poor-mans-puppet/master-files/etc/foo/foo.conf)
- foo.conf.copied should in central directory, not in same directory foo.conf (e.g. ~/poor-mans-puppet/timestamp-files/etc/foo/foo.conf)
after googling, hair pulling, i'm asking here! ideas please? (ps: if copying makefiles here, remember change indentation tabs.)
mad scientist below suggested elegant static rule, need pattern rule. reason need hook dependencies in using rules:
all: <new-dependency>
rather hooking them in using variables:
stuff_all_should_depend_on += <new-dependency>
the reason requirement consistency how other (non-%.copied) targets handled in large makefile.
however, based on mad scientist's idea, tried following, didn't work, perhaps helps me:
all: foo.conf.copied %.copied: %.master % $(eval files_for_which_an_empty_recipe_are_needed += $$*) cp $*.master $* touch $@ define generate_static_empty_rule $(1): endef $(foreach x,$(files_for_which_an_empty_recipe_are_needed),$(eval $(call generate_static_empty_rule,$(x))))
can explain why you're using ".copied" file? why don't use:
%: %.master ; cp $< $@
?
anyway, you're running afoul of make's special rules related match-anything rules (pattern rules %
can build everything). if change pattern it's not match-anything, %.conf: ;
work. don't want assume files end in .conf
.
alternatively can use static pattern rules, this:
files_to_copy = foo.conf bar.conf biz.baz all: $(files_to_copy:%=%.copied) $(files_to_copy:%=%.copied): %.copied : %.master % cp $*.master $* touch $@
and don't need pattern rule.
Comments
Post a Comment