propset - enables svn keywords
[build.git] / Makefile
index 9787b6e..175b617 100644 (file)
--- a/Makefile
+++ b/Makefile
 #
-# PlanetLab RPM generation
+# Thierry Parmentelat - INRIA Sophia Antipolis 
 #
-# Copyright (c) 2003  The Trustees of Princeton University (Trustees).
-# All Rights Reserved.
+### $Id$
 # 
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: 
-# 
-#     * Redistributions of source code must retain the above copyright
-#       notice, this list of conditions and the following disclaimer.
-# 
-#     * Redistributions in binary form must reproduce the above
-#       copyright notice, this list of conditions and the following
-#       disclaimer in the documentation and/or other materials provided
-#       with the distribution.
-# 
-#     * Neither the name of the copyright holder nor the names of its
-#       contributors may be used to endorse or promote products derived
-#       from this software without specific prior written permission.
-# 
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE TRUSTEES OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# $Id: Makefile,v 1.41 2004/08/25 19:09:42 mlh-pl_rpm Exp $
-#
+# run 'make help' for more info
 
+#################### Makefile
 # Default target
 all:
+.PHONY:all
 
-#
-# CVSROOT: CVSROOT to use
-# INITIAL: CVS tag to use for Source0 tarball
-# TAG: CVS tag to patch to
-# MODULE: CVS module name to use
-# SPEC: RPM spec file template
-# RPMFLAGS: Miscellaneous RPM flags
-# CVS_RSH: If not ssh
-# ALL: default targets
-#
-# If INITIAL is different than TAG, PatchSets will be generated
-# automatically with cvsps(1) to bring Source0 up to TAG. If TAG is
-# HEAD, a %{date} variable will be defined in the generated spec
-# file. If a Patch: tag in the spec file matches a generated PatchSet
-# number, the name of the patch will be as specified. Otherwise, the
-# name of the patch will be the PatchSet number. %patch tags in the
-# spec file are generated automatically.
-#
-
-#
-# kernel
-#
-
-kernel-CVSROOT := :pserver:anon@build.planet-lab.org:/cvs
-kernel-INITIAL := HEAD
-kernel-TAG := HEAD
-kernel-MODULE := linux-2.6
-kernel-SPEC := linux-2.6/scripts/kernel-planetlab.spec
-ALL += kernel
-
-#
-# vnet
-#
-
-vnet-CVSROOT := :pserver:anon@build.planet-lab.org:/cvs
-vnet-INITIAL := HEAD
-vnet-TAG := HEAD
-vnet-MODULE := vnet
-vnet-SPEC := vnet/vnet.spec
-vnet-RPMFLAGS := --define "kernelver $(shell rpmquery --queryformat '%{VERSION}-%{RELEASE}\n' --specfile SPECS/$(notdir $(kernel-SPEC)) | head -1)"
-ALL += vnet
-
-# Build kernel first so we can bootstrap off of its build
-vnet: kernel
-
-#
-# vsh
-#
-
-vsh-CVSROOT := :pserver:anon@build.planet-lab.org:/cvs
-vsh-INITIAL := HEAD
-vsh-TAG := HEAD
-vsh-MODULE := trampoline
-vsh-SPEC := trampoline/vsh.spec
-ALL += vsh
-
-# Build kernel first so we can bootstrap off of its build
-vsh: kernel
-
-#
-# util-vserver
-#
-
-util-vserver-CVSROOT := pup-pl_kernel@cvs.planet-lab.org:/cvs
-util-vserver-INITIAL := HEAD
-util-vserver-TAG := HEAD
-util-vserver-MODULE := util-vserver
-util-vserver-SPEC := util-vserver/util-vserver.spec
-ALL += util-vserver
-
-# Build kernel first so we can bootstrap off of its build
-util-vserver: kernel
-
-#
-# lkcdutils
-#
-
-lkcdutils-CVSROOT := :pserver:anon@build.planet-lab.org:/cvs
-lkcdutils-INITIAL := HEAD
-lkcdutils-TAG := HEAD
-lkcdutils-MODULE := lkcdutils
-lkcdutils-SPEC := lkcdutils/spec/lkcdutils.spec
-ALL += lkcdutils
-
-# Build kernel first so we can bootstrap off of its build
-lkcdutils: kernel
-
-#
-# yum
-#
-
-yum-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-yum-INITIAL := HEAD
-yum-TAG := HEAD
-yum-MODULE := yum
-yum-SPEC := yum/yum.spec
-ALL += yum
-
-#
-# ksymoops
-#
-
-ksymoops-CVSROOT := pup-pl_kernel@cvs.planet-lab.org:/cvs
-ksymoops-INITIAL := ksymoops-2_4_9
-ksymoops-TAG := HEAD
-ksymoops-MODULE := ksymoops
-ksymoops-SPEC := ksymoops/ksymoops.spec
-ALL += ksymoops
-
-#
-# PlanetLabAccounts
-#
-
-PlanetLabAccounts-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-PlanetLabAccounts-INITIAL := HEAD
-PlanetLabAccounts-TAG := HEAD
-PlanetLabAccounts-MODULE := PlanetLabAccounts
-PlanetLabAccounts-SPEC := PlanetLabAccounts/PlanetLabAccounts.spec
-ALL += PlanetLabAccounts
-
-#
-# NodeUpdate
-#
-
-NodeUpdate-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-NodeUpdate-INITIAL := HEAD
-NodeUpdate-TAG := HEAD
-NodeUpdate-MODULE := NodeUpdate
-NodeUpdate-SPEC := NodeUpdate/NodeUpdate.spec
-ALL += NodeUpdate
-
-#
-# PlanetLabConf
-#
+### default values
+PLDISTRO := onelab
+RPMBUILD := rpmbuild
+export CVS_RSH := ssh
 
-PlanetLabConf-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-PlanetLabConf-INITIAL := HEAD
-PlanetLabConf-TAG := HEAD
-PlanetLabConf-MODULE := PlanetLabConf
-PlanetLabConf-SPEC := PlanetLabConf/PlanetLabConf.spec
-ALL += PlanetLabConf
-
-#
-# PlanetLabKeys
-#
-
-PlanetLabKeys-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-PlanetLabKeys-INITIAL := HEAD
-PlanetLabKeys-TAG := HEAD
-PlanetLabKeys-MODULE := PlanetLabKeys
-PlanetLabKeys-SPEC := PlanetLabKeys/PlanetLabKeys.spec
-ALL += PlanetLabKeys
-
-#
-# BWLimit
-#
-
-BWLimit-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-BWLimit-INITIAL := HEAD
-BWLimit-TAG := HEAD
-BWLimit-MODULE := BWLimit
-BWLimit-SPEC := BWLimit/BWLimit.spec
-ALL += BWLimit
-
-#
-# ipod
-#
-
-ipod-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-ipod-INITIAL := HEAD
-ipod-TAG := HEAD
-ipod-MODULE := ipod
-ipod-SPEC := ipod/ipod.spec
-ALL += ipod
-
-#
-# sudo
-#
-
-sudo-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-sudo-INITIAL := HEAD
-sudo-TAG := HEAD
-sudo-MODULE := sudo
-sudo-SPEC := sudo/planetlab_sudo.spec
-ALL += sudo
-
-#
-# pycurl
-#
-
-pycurl-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-pycurl-INITIAL := HEAD
-pycurl-TAG := HEAD
-pycurl-MODULE := pycurl
-pycurl-SPEC := pycurl/pycurl.spec
-ALL += pycurl
-
-#
-# BootServerRequest
-#
-
-BootServerRequest-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-BootServerRequest-INITIAL := HEAD
-BootServerRequest-TAG := HEAD
-BootServerRequest-MODULE := BootServerRequest
-BootServerRequest-SPEC := BootServerRequest/PLBootServerRequest.spec
-ALL += BootServerRequest
-
-#
-# PlanetLabID
-#
-
-PlanetLabID-CVSROOT := pup-node_pkgs@cvs.planet-lab.org:/cvs
-PlanetLabID-INITIAL := HEAD
-PlanetLabID-TAG := HEAD
-PlanetLabID-MODULE := PlanetLabID
-PlanetLabID-SPEC := PlanetLabID/PlanetLabID.spec
-ALL += PlanetLabID
-
-#
-# Node Manager
-#
-
-sidewinder-CVSROOT := pup-sidewinder@cvs.planet-lab.org:/cvs
-sidewinder-INITIAL := HEAD
-sidewinder-TAG := HEAD
-sidewinder-MODULE := sidewinder
-sidewinder-SPEC := sidewinder/sidewinder.spec
-ALL += sidewinder
-
-#
-# pl_sshd
-#
-
-pl_sshd-CVSROOT := pup-pl_sshd@cvs.planet-lab.org:/cvs
-pl_sshd-INITIAL := HEAD
-pl_sshd-TAG := HEAD
-pl_sshd-MODULE := pl_sshd
-pl_sshd-SPEC := pl_sshd/pl_sshd.spec
-ALL += pl_sshd
-
-ifeq ($(findstring $(package),$(ALL)),)
+########## pldistro.mk holds PLDISTRO - it is generated at stage1 (see below)
+ifeq "$(stage1)" ""
+include pldistro.mk
+endif
 
-# Build all packages
+#################### include onelab.mk
+# describes the set of components
+PLDISTROCONTENTS := $(PLDISTRO).mk
+include $(PLDISTROCONTENTS)
+
+#################### include <pldistro>-tags.mk
+# describes where to fetch components, and the related tags if using cvs
+PLDISTROTAGS := $(PLDISTRO)-tags.mk
+include $(PLDISTROTAGS)
+
+########## stage1 and stage2
+# extract specs and compute .mk files by running 
+# make stage1=true
+# entering stage1, we compute all the spec files
+# then we use stage2 to compute the .mk iteratively, 
+# ensuring that the n-1 first makefiles are loaded when creating the n-th one
+# when stage2 is set, it is supposed to be an index (starting at 1) in $(ALL)
+
+ALLMKS := $(foreach package, $(ALL), MAKE/$(package).mk)
+
+### stage2 : need some arithmetic, see
+# http://www.cmcrossroads.com/articles/ask-mr.-make/learning-gnu-make-functions-with-arithmetic.html
+ifneq "$(stage2)" ""
+# the first n packages
+packages := $(wordlist 1,$(words $(stage2)),$(ALL))
+# the n-th package
+package := $(word $(words $(packages)),$(packages))
+# the n-1 first packages
+stage2_1 := $(wordlist 2,$(words $(stage2)),$(stage2))
+previous := $(wordlist 1,$(words $(stage2_1)),$(ALL))
+previousmks := $(foreach package,$(previous),MAKE/$(package).mk)
+include $(previousmks)
+all: verbose
+verbose:
+       @echo "========== stage2 : $(package)"
+       @echo "stage2 : included .mk files : $(previousmks)"
+all: $($(package)_specpath)
+all: MAKE/$(package).mk
+else
+### stage1
+ifneq "$(stage1)" ""
+all : verbose
+verbose :
+       @echo "========== stage1"
+all : spec2make
+all : .rpmmacros
+# specs and makes are done sequentially by stage2
+all : stage2
+stage2:
+       arg=""; for n in $(ALL) ; do arg="$$arg x"; $(MAKE) --no-print-directory stage2="$$arg"; done
+### regular make
+else
+### once .mks are OK, you can run make normally
+include $(ALLMKS)
+#all : tarballs
+#all : sources
+#all : codebases
+#all : rpms
+#all : srpms
+# mention $(ALL) here rather than rpms 
+# this is because the inter-package dependencies are expressed like
+# util-vserver: util-python
 all: $(ALL)
+all: srpms
+endif
+endif
 
-# Recurse
-$(ALL):
-       $(MAKE) package=$@
-
-# Remove files generated by this package
-$(foreach package,$(ALL),$(package)-clean): %-clean:
-       $(MAKE) package=$* clean
-
-# Remove all generated files
+####################
+# 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)-MODULE))
+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 "%define pldistro $(PLDISTRO)" > $($(1)_specpath)
+       $(if $($(1)_hasdate),echo "%define date $(shell date +%Y.%m.%d)" >> $($(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)-MODULE), $(if $($(m)-SVNPATH), svn export $($(m)-SVNPATH) $(m);, cvs -d $($(m)-CVSROOT) export -r $($(m)-TAG) $(m);)))
+endef
+
+CODEBASES/%: package=$(notdir $@)
+CODEBASES/%: module=$($(package)-MODULE)
+CODEBASES/%: multi_module=$(word 2,$(module))
+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-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-rpm $(1)-clean-srpm
+.PHONY: $(1)-clean
+endef
+
+$(foreach package,$(ALL),$(eval $(call target_clean,$(package))))
+
+### clean precisely
 clean:
-       rm -rf BUILD RPMS SOURCES SPECS SRPMS .rpmmacros .cvsps
-
-.PHONY: all $(ALL) $(foreach package,$(ALL),$(package)-clean) clean
-
+       $(MAKE) $(CLEANS)
+.PHONY: clean
+
+clean-help:
+       @echo Available clean targets
+       @echo $(CLEANS)
+
+### brute force clean
+distclean1:
+       rm -rf pldistro.mk .rpmmacros spec2make SPECS MAKE 
+distclean2:
+       rm -rf CODEBASES SOURCES BUILD RPMS SRPMS tmp
+distclean: distclean1 distclean2
+.PHONY: distclean1 distclean2 distclean
+
+# xxx tmp - I cannot use this on my mac for local testing
+ISMACOS=$(findstring Darwin,$(shell uname))
+ifneq "$(ISMACOS)" ""
+#################### produce reliable version information
+# for a given module
+VFORMAT="%30s := %s\n"
+define print_version
+$(1)-version:
+       @$(if $($(1)-SVNPATH),\
+          printf $(VFORMAT) $(1)-SVNPATH "$($(1)-SVNPATH)",\
+          printf $(VFORMAT) $(1)-CVSROOT "$($(1)-CVSROOT)" ; printf $(VFORMAT) $(1)-TAG "$($(1)-TAG)")
+endef
+
+# compute all modules
+ALL-MODULES :=
+$(foreach package,$(ALL), $(eval ALL-MODULES+=$($(package)-MODULE)))
+ALL-MODULES:=$(sort $(ALL-MODULES))
+
+$(foreach module,$(ALL-MODULES), $(eval $(call print_version,$(module))))
+
+versions: $(foreach module, $(ALL-MODULES), $(module)-version)
 else
+versions:
+       @echo "warning : the 'versions' target is not supported on macos"
+endif
 
-# Define variables for Makerules
-CVSROOT := $($(package)-CVSROOT)
-INITIAL := $($(package)-INITIAL)
-TAG := $($(package)-TAG)
-MODULE := $($(package)-MODULE)
-SPEC := $($(package)-SPEC)
-RPMFLAGS := $($(package)-RPMFLAGS)
-CVS_RSH := $(if $($(package)-CVS_RSH),$($(package)-CVS_RSH),ssh)
-
-include Makerules
-
+#################### include install Makefile
+# the default is to use the distro-dependent install file
+# however the main distro file can redefine PLDISTROINSTALL
+ifndef PLDISTROINSTALL
+PLDISTROINSTALL := $(PLDISTRO)-install.mk
 endif
+# only if present
+-include $(PLDISTROINSTALL)
+
+####################
+help:
+       @echo "Known pakages are"
+       @echo "  $(ALL)"
+       @echo "Run make in two stages:"
+       @echo ""
+       @echo "make stage1=true PLDISTRO=onelab"
+       @echo " -> extracts all spec files in SPECS/ and mk files in MAKE/"
+       @echo "    as well as save PLDISTRO for subsequent runs"
+       @echo ""
+       @echo "Then you can use the following targets"
+       @echo '$ make'
+       @echo "  rebuilds everything"
+       @echo '$ make util-vserver'
+       @echo "  makes the RPMS related to util-vserver"
+       @echo "  equivalent to 'make util-vserver-rpm'"
+       @echo ""
+       @echo "Or, vertically - step-by-step for a given package"
+       @echo '$ make util-vserver-codebase'
+       @echo "  performs codebase extraction in CODEBASES/util-vserver"
+       @echo '$ make util-vserver-source'
+       @echo "  creates source link in SOURCES/util-vserver-<version>"
+       @echo '$ make util-vserver-tarball'
+       @echo "  creates source tarball in SOURCES/util-vserver-<version>.<tarextension>"
+       @echo '$ make util-vserver-rpm'
+       @echo "  build rpm(s) in RPMS/"
+       @echo '$ make util-vserver-srpm'
+       @echo "  build source rpm in SRPMS/"
+       @echo ""
+       @echo "Or, horizontally, reach a step for all known packages"
+       @echo '$ make codebases'
+       @echo '$ make sources'
+       @echo '$ make tarballs'
+       @echo '$ make rpms'
+       @echo '$ make srpms'
+       @echo ""
+       @echo "Cleaning examples"
+       @echo "$ make clean"
+       @echo "  removes the files made by make"
+       @echo "$ make distclean"
+       @echo "  brute-force cleaning, removes entire directories - requires a new stage1"
+       @echo "$ make util-vserver-clean"
+       @echo "  removes codebase, source, tarball, rpm and srpm for util-vserver"
+       @echo "$ make util-vserver-clean-codebase"
+       @echo "  and so on"
+
+
+#################### convenience, for debugging only
+# make +foo : prints the value of $(foo)
+# make ++foo : idem but verbose, i.e. foo=$(foo)
+++%: varname=$(subst +,,$@)
+++%:
+       @echo "$(varname)=$($(varname))"
++%: varname=$(subst +,,$@)
++%:
+       @echo "$($(varname))"