In summary, I process a .uml file to extract the .norm files implied by its contents, and then process the .norm files to create .gen files. Most of this can be standardised, but there's no way for standard processing to determine beforehand which .norm files are "contained" in a .uml file.
I created a .norm-stamp file whenever I've processed a .uml file,
%.norm-stamp: %.uml ... processing ... touch $@
and then added a rule to say that many.uml "contains" a.norm and b.norm:
a.norm b.norm: many.norm-stamp
The first time I say make a.gen, all is well. If I then touch many.uml and say make a.gen again, make only gets as far as creating many.norm-stamp (and a.norm, b.norm); I have to run make again to regenerate a.gen.
I found that I can get the behaviour I need by adding an empty recipe: the red semicolon at the end of
a.norm b.norm: many.norm-stamp ;This is an "empty recipe" Make rule. That documentation says "The only reason this is useful is to prevent a target from getting implicit recipes (from implicit rules or the .DEFAULT special target[...]", so - in the hope that I've found another valid use for the construct - I've posted a Make bug, which includes a sample Makefile.