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

Popular posts from this blog

sequelize.js - Sequelize group by with association includes id -

android - Robolectric "INTERNET permission is required" -

java - Android raising EPERM (Operation not permitted) when attempting to send UDP packet after network connection -