How to get make dependancies working when one rule builds several files


# This entire HTML file is a single makefile that shows how to do this.
#
# Here is how to set up dependancies for a build step that generates a bunch of
# files from one or more source files.
#
# Example:
#    We start with these source files: 
#       x.c
#       y.c
#       src1
#       src2
#       src3
#    We want to build obj
#
#    obj depends on x,c y.c gen1 gen2 and gen3
#
#    gen1 gen2 and gen3 are generated by the stamp: rule
#    src1 arc2 and src3 are required to generate gen1 gen2 and gen3
#
# Solution:
#
#    obj depends on what it needs - this is straightforward
#    obj must also depend on stamp
#
#    stamp is the rule that generates everything
#      - stamp generates its own dep.d file with generated dependancies:
#        - dep.d depends on all src files
#        - each gen file depends on dep.d
#        - stamp depends on all gen files
#        - the dep.d file must be removed and generated with a different name
#             (dep2.d) and copied as the 2nd to last step of the stamp rule
#        - the last step of stamp must touch all the gen files and stamp to
#             ensure they are newer than dep.d
#
# How it works:
#    
#    When dep.d does not exist:
#      stamp must be built because dep.d does not exist
#
#    When dep.d exists:
#      changes to src force dep.d to build
#      changes to dep.d (incl src) force gen to build
#      changes to any gen (incl dep.d and src) force stamp to build
#    So basically any change forces stamp to rebuild
#
#
#    Note: if a generated program runs as part of stamp then consider that a
#    src and also add it as a dependancy of stamp so it gets built initially.

obj: x.c y.c stamp gen1 gen2 gen3
	@echo "Do obj"
	grep s1 gen1 || exit 1
	grep s1 gen2 || exit 1
	grep s1 gen3 || exit 1
	cat x.c y.c gen1 gen2 gen3 > $@
	sleep 2

# You can optionally make dep.d depend on the Makefile if you want.
dep.d:
	@echo "Do abc for $@"
	\rm -f stamp

stamp: dep.d
	@echo "Do stamp"
	\rm -f dep.d
	@echo "EXPENSIVE OPERATION - ONLY DO ONCE"
	cat src1 src2 src3 | tee gen1 | tee gen2 > gen3
	echo "dep.d: src1 src2 src3" > dep2.d
	echo "gen1 gen2 gen3: dep.d" >> dep2.d
	echo "stamp: gen1 gen2 gen3" >> dep2.d
	mv dep2.d dep.d
	sleep 2
	touch gen1 gen2 gen3 stamp


clean:
	\rm -f gen* stamp* obj dep.d

-include dep.d

ifeq (0,1)
# Tests: copy & paste to command line to test.
# Each test should only run the EXPENSIVE OPERATION exactly once.
# The 2nd make on each line should be up to date (nothing to do).
  make clean ; make ; echo "===" ; make	; echo "============="
  \rm -f stamp ; make ; echo "===" ; make	; echo "============="
  \rm -f gen1   ; make ; echo "===" ; make	; echo "============="
  \rm -f gen1 gen2  ; make ; echo "===" ; make	; echo "============="
  \rm -f dep.d  ; make ; echo "===" ; make	; echo "============="
  \rm -f dep.d  gen1  ; make ; echo "===" ; make	; echo "============="
  \rm -f stamp gen1  ; make ; echo "===" ; make	; echo "============="
  \rm -f stamp dep.d ; make ; echo "===" ; make	; echo "============="
  \rm -f stamp dep.d gen3 ; make ; echo "===" ; make	; echo "============="
  touch src1    ; make ; echo "===" ; make	; echo "============="
  touch dep.d   ; make ; echo "===" ; make	; echo "============="
  echo "" > gen1 ; make ; echo "===" ; make	; echo "============="
  touch src1 src2 ; \rm gen1 gen2 ; make ; echo "===" ; make ; echo "========"
  touch gen1    ; make ; echo "===" ; make	; echo "============="
  touch stamp  ; make ; echo "===" ; make	; echo "============="
# The following do not require EXPENSIVE OPERATION at all.
  touch x.c     ; make ; echo "===" ; make	; echo "============="
#



endif