+####################
+# gather build information for the 'About' page
+SOURCES/myplc-release:
+ @echo 'Creating myplc-release'
+ mkdir -p SOURCES
+ rm -f $@
+ (echo -n 'Build bdate: ' ; date '+%Y.%m.%d') >> $@
+ (echo -n 'Build btime: ' ; date '+%H:%M') >> $@
+ (echo -n 'Build hostname: ' ; hostname) >> $@
+ (echo -n 'Build location: ' ; pwd) >> $@
+ (echo -n 'Build tags file: ' ; fgrep '$$''Id' $(PLDISTROTAGS)) >> $@
+ echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx modules versions info" >> $@
+ $(MAKE) --no-print-directory versions >> $@
+
+####################
+# notes:
+# * to make configuration easier, we always use the first module's
+# definitions (CVSROOT,TAG, or SVNPATH) to extract the spec file
+# * for the same reason, in case cvs is used, the first module name is added to
+# $(package)-SPEC - otherwise the cvs modules have to define spec as
+# <module>/<module>.spec while svn modules just define it as <module>.spec
+#
+define stage1_variables
+$(1)_spec = $(notdir $($(1)-SPEC))
+$(1)_specpath = SPECS/$(notdir $($(1)-SPEC))
+$(1)_module = $(firstword $($(1)-MODULES))
+endef
+
+$(foreach package, $(ALL), $(eval $(call stage1_variables,$(package))))
+
+#
+# for each package, compute whether we need to set date (i.e. whether we use the trunk)
+# the myplc package is forced to have a date, because it is more convenient
+# (we cannot bump its number everytime something changes in the system)
+#
+define package_hasdate
+$(1)_hasdate = $(if $(subst myplc,,$(1)), \
+ $(if $($(1)-SVNPATH),\
+ $(if $(findstring /trunk,$($(1)-SVNPATH)),yes,),\
+ $(if $(findstring HEAD,$($(1)-TAG)),yes,)), \
+ yes)
+endef
+
+$(foreach package, $(ALL), $(eval $(call package_hasdate,$(package))))
+
+### extract spec file from scm
+# usage: extract_spec_file package
+# see early releases for comments on other possible implementations
+# cannot use variables in such rules, we need to inline everything, sigh
+define target_spec
+$($(1)_specpath):
+ mkdir -p SPECS
+ (echo -n "# Generated by planetlab build from $($(1)-SPEC) on " ; date) > $($(1)_specpath)
+ echo "%define distroname $(DISTRO)" >> $($(1)_specpath)
+ echo "%define distrorelease $(RELEASE)" >> $($(1)_specpath)
+ echo "%define pldistro $(PLDISTRO)" >> $($(1)_specpath)
+ $(if $($(1)_hasdate),echo "%define date $(shell date +%Y.%m.%d)" >> $($(1)_specpath),)
+ echo "# included from codebase specfile" >> $($(1)_specpath)
+ $(if $($(1)-SPECVARS), \
+ $(foreach line,$($(1)-SPECVARS), \
+ echo "%define" $(word 1,$(subst =, ,$(line))) "$(word 2,$(subst =, ,$(line)))" >> $($(1)_specpath) ;))
+ $(if $($($(1)_module)-SVNPATH),\
+ svn cat $($($(1)_module)-SVNPATH)/$($(1)-SPEC) >> $($(1)_specpath),\
+ cvs -d $($($(1)_module)-CVSROOT) checkout \
+ -r $($($(1)_module)-TAG) \
+ -p $($(1)_module)/$($(1)-SPEC) >> $($(1)_specpath))
+ @if [ -z $($(1)_specpath) ] ; then rm $($(1)_specpath) ; exit 1 ; fi
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_spec,$(package))))
+
+### this utility allows to extract various info from a spec file
+### and to define them in makefiles
+spec2make: spec2make.c
+ $(CC) -g -Wall $< -o $@ -lrpm -lrpmbuild
+
+# Base rpmbuild in the current directory
+export HOME := $(shell pwd)
+.rpmmacros:
+ echo "%_topdir $(HOME)" > $@
+ echo "%_tmppath $(HOME)/tmp" >> $@
+
+### run spec2make on the spec file and include the result
+# usage: spec2make package
+define target_mk
+MAKE/$(1).mk: $($(1)_specpath) spec2make .rpmmacros
+ mkdir -p MAKE
+ ./spec2make $($(1)-RPMFLAGS) $($(1)_specpath) $(1) > MAKE/$(1).mk
+ @if [ -z MAKE/$(1).mk ] ; then rm MAKE/$(1).mk ; exit 1 ; fi
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_mk,$(package))))
+
+# stores PLDISTRO in a file
+# this is done at stage1. later run wont get confused
+pldistro.mk:
+ echo "PLDISTRO:=$(PLDISTRO)" > $@
+ echo "PLDISTROTAGS:=$(PLDISTROTAGS)" >> $@
+
+savepldistro: pldistro.mk
+.PHONY: savepldistro
+
+# always refresh this
+all: savepldistro
+
+####################
+### pack sources into tarballs
+ALLTARBALLS:= $(foreach package, $(ALL), $($(package)-TARBALL))
+tarballs: $(ALLTARBALLS)
+ @echo $(words $(ALLTARBALLS)) source tarballs OK
+.PHONY: tarballs
+
+SOURCES/%.tar.bz2: SOURCES/%
+ tar chpjf $@ -C SOURCES $*
+
+SOURCES/%.tar.gz: SOURCES/%
+ tar chpzf $@ -C SOURCES $*
+
+SOURCES/%.tgz: SOURCES/%
+ tar chpzf $@ -C SOURCES $*
+
+### the directory SOURCES/<package>-<version> is made
+# with a copy -rl from CODEBASES/<package>
+# the former is $(package-SOURCE) and the latter is $(package-CODEBASE)
+ALLSOURCES:=$(foreach package, $(ALL), $($(package)-SOURCE))
+# so that make does not use the rule below directly for creating the tarball files
+.SECONDARY: $(ALLSOURCES)
+
+sources: $(ALLSOURCES)
+ @echo $(words $(ALLSOURCES)) versioned source trees OK
+.PHONY: sources
+
+define target_link_codebase_sources
+$($(1)-SOURCE): $($(1)-CODEBASE) ; mkdir -p SOURCES ; cp -rl $($(1)-CODEBASE) $($(1)-SOURCE)
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_link_codebase_sources,$(package))))
+
+### codebase extraction
+ALLCODEBASES:=$(foreach package, $(ALL), $($(package)-CODEBASE))
+# so that make does not use the rule below directly for creating the tarball files
+.SECONDARY: $(ALLCODEBASES)
+
+codebases : $(ALLCODEBASES)
+ @echo $(words $(ALLCODEBASES)) codebase OK
+.PHONY: codebases
+
+### extract codebase
+# usage: extract_single_module package
+define extract_single_module
+ mkdir -p CODEBASES
+ $(if $($($(1)_module)-SVNPATH), cd CODEBASES && svn export $($($(1)_module)-SVNPATH) $(1), cd CODEBASES && cvs -d $($($(1)_module)-CVSROOT) export -r $($($(1)_module)-TAG) -d $(1) $($(1)_module))
+endef
+
+# usage: extract_multi_module package
+define extract_multi_module
+ mkdir -p CODEBASES/$(1) && cd CODEBASES/$(1) && (\
+ $(foreach m,$($(1)-MODULES), $(if $($(m)-SVNPATH), svn export $($(m)-SVNPATH) $(m);, cvs -d $($(m)-CVSROOT) export -r $($(m)-TAG) $(m);)))
+endef
+
+CODEBASES/%: package=$(notdir $@)
+CODEBASES/%: multi_module=$(word 2,$($(package)-MODULES))
+CODEBASES/%:
+ @(echo -n "XXXXXXXXXXXXXXX -- BEG CODEBASE $(package) : $@ " ; date)
+ $(if $(multi_module),\
+ $(call extract_multi_module,$(package)),\
+ $(call extract_single_module,$(package)))
+ @(echo -n "XXXXXXXXXXXXXXX -- END CODEBASE $(package) : $@ " ; date)
+
+### rpmbuild invokation
+ALLRPMS:=$(foreach package,$(ALL),$($(package)-RPM))
+# same as above, mention $(ALL) and not $(ALLRPMS)
+rpms: $(ALL)
+ @echo $(words $(ALLRPMS)) binary rpms OK
+.PHONY: rpms
+
+# usage: build_binary_rpm package
+# xxx hacky - invoke createrepo if DEPENDFILES mentions RPMS/yumgroups.xml
+define target_binary_rpm
+$($(1)-RPM): $($(1)_specpath) $($(1)-TARBALL) .rpmmacros
+ mkdir -p BUILD RPMS tmp
+ @(echo -n "XXXXXXXXXXXXXXX -- BEG RPM $(1) " ; date)
+ $(if $(findstring RPMS/yumgroups.xml,$($(1)-DEPENDFILES)), createrepo --quiet -g yumgroups.xml RPMS/ , )
+ $(if $($(1)-RPMBUILD),\
+ $($(1)-RPMBUILD) $($(1)-RPMFLAGS) -bb $($(1)_specpath), \
+ $(RPMBUILD) $($(1)-RPMFLAGS) -bb $($(1)_specpath))
+ @(echo -n "XXXXXXXXXXXXXXX -- END RPM $(1) " ; date)
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_binary_rpm,$(package))))
+
+### source rpms
+ALLSRPMS:=$(foreach package,$(ALL),$($(package)-SRPM))
+srpms: $(ALLSRPMS)
+ @echo $(words $(ALLSRPMS)) source rpms OK
+.PHONY: srpms
+
+# usage: build_source_rpm package
+define target_source_rpm
+$($(1)-SRPM): $($(1)_specpath) $($(1)-TARBALL) .rpmmacros
+ mkdir -p BUILD SRPMS tmp
+ @(echo -n "XXXXXXXXXXXXXXX -- BEG SRPM $(1) " ; date)
+ $(if $($(1)-RPMBUILD),\
+ $($(1)-RPMBUILD) $($(1)-RPMFLAGS) -bs $($(1)_specpath),
+ $(RPMBUILD) $($(1)-RPMFLAGS) -bs $($(1)_specpath))
+ @(echo -n "XXXXXXXXXXXXXXX -- END SRPM $(1) " ; date)
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_source_rpm,$(package))))
+
+### RPMS/yumgroups.xml
+ifndef YUMGROUPS
+YUMGROUPS := groups/$(PLDISTRO).xml
+endif
+RPMS/yumgroups.xml: $(YUMGROUPS)
+ install -D -m 644 $(YUMGROUPS) $@
+
+### shorthand target
+# e.g. make proper -> does propers rpms
+# usage shorthand_target package
+define target_shorthand
+$(1): $($(package)-RPM)
+.PHONY: $(1)
+$(1)-spec: $($(package)-SPEC)
+.PHONY: $(1)-spec
+$(1)-mk: $($(package)-MK)
+.PHONY: $(1)-mk
+$(1)-tarball: $($(package)-TARBALL)
+.PHONY: $(1)-tarball
+$(1)-codebase: $($(package)-CODEBASE)
+.PHONY: $(1)-source
+$(1)-source: $($(package)-SOURCE)
+.PHONY: $(1)-codebase
+$(1)-rpm: $($(package)-RPM)
+.PHONY: $(1)-rpm
+$(1)-srpm: $($(package)-SRPM)
+.PHONY: $(1)-srpm
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_shorthand,$(package))))
+
+### dependencies
+define package_depends_on_file
+$(1):$(2)
+$($(1)-RPM):$(2)
+endef
+
+define target_dependfiles
+$(foreach file,$($(1)-DEPENDFILES),$(eval $(call package_depends_on_file,$(1),$(file))))
+endef
+
+define package_depends_on_package
+$(1):$(2)
+$(1):$($(2)-RPM)
+$($(1)-RPM):$($(2)-RPM)
+endef
+
+define target_depends
+$(foreach package,$($(1)-DEPENDS),$(eval $(call package_depends_on_package,$(1),$(package))))
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_depends,$(package))))
+$(foreach package,$(ALL),$(eval $(call target_dependfiles,$(package))))
+
+
+### clean target
+# usage: target_clean package
+define target_clean
+$(1)-clean-codebase:
+ rm -rf $($(1)-CODEBASE)
+.PHONY: $(1)-clean-codebase
+CLEANS += $(1)-clean-codebase
+$(1)-clean-source:
+ rm -rf $($(1)-SOURCE)
+.PHONY: $(1)-clean-source
+CLEANS += $(1)-clean-source
+$(1)-clean-tarball:
+ rm -rf $($(1)-TARBALL)
+.PHONY: $(1)-clean-tarball
+CLEANS += $(1)-clean-tarball
+$(1)-clean-build:
+ rm -rf BUILD/$(notdir $($(1)-SOURCE))
+CLEANS += $(1)-clean-build
+$(1)-clean-rpm:
+ rm -rf $($(1)-RPM)
+.PHONY: $(1)-clean-rpm
+CLEANS += $(1)-clean-rpm
+$(1)-clean-srpm:
+ rm -rf $($(1)-SRPM)
+.PHONY: $(1)-clean-srpm
+CLEANS += $(1)-clean-srpm
+$(1)-clean: $(1)-clean-codebase $(1)-clean-source $(1)-clean-tarball $(1)-clean-build $(1)-clean-rpm $(1)-clean-srpm
+.PHONY: $(1)-clean
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_clean,$(package))))
+
+### clean precisely
+clean:
+ $(MAKE) $(CLEANS)
+.PHONY: clean