top := $(shell pwd) CAT = cat CP = cp ECHO = echo EXISTS = test -e FAIL = exit 1 FIND = find GIT = git LNDIR = lndir -silent MKDIRS = mkdir -p PATCH = patch RM = rm -f SED = sed SVN = svn TAR = bsdtar TOUCH = touch WGET = wget all: package # configuration ################################################################ packages := $(filter-out _%,$(shell $(SED) "s/[\# ].*//" conf/sources.mk)) include conf/sources.mk include conf/dependencies.mk export MAVEN_LOCAL_REPO := $(shell $(CAT) conf/maven.local.repo.txt) export JAR_DIR := $(shell $(CAT) conf/jardir.txt) # download ##################################################################### download: PHONY $(foreach package,$(packages),build/download/$(shell utils/spec2file '$($(package))')) build/download/git/%: .tokens/network if [ -d '$@' ]; then \ cd '$@' && $(GIT) fetch --all -p; \ else \ $(MKDIRS) '$(@D)' && $(GIT) clone --mirror '$(shell utils/file2url 'git/$*')' '$@'; \ fi $(TOUCH) '$@' build/download/svn/%: .tokens/network if ! [ -d '$(shell utils/file2base 'svn/$*')' ]; then \ $(RM) -r '$@' && \ $(MKDIRS) build/download/svn && \ $(SVN) checkout --depth=empty \ '$(shell utils/file2url 'svn/$*')' \ build/download/'$(shell utils/file2base 'svn/$*')' && \ cd build/download/'$(shell utils/file2base 'svn/$*')'; \ else \ cd build/download/'$(shell utils/file2base 'svn/$*')' && \ $(SVN) update; \ fi && \ $(SVN) update --parents '$(shell utils/file2extra 'svn/$*')' $(EXISTS) '$@' $(TOUCH) '$@' build/download/tar/%: .tokens/network $(MKDIRS) '$(@D)' $(WGET) -c -O '$@' '$(shell utils/file2url 'tar/$*')' $(TOUCH) '$@' # extract ###################################################################### extract: PHONY $(foreach package,$(packages),build/extract/$(shell utils/spec2file '$($(package))')) # This is a little gross because to get the dependencies right for # `git` and `tar`, we need to do a bit more complex processing of # `%`/`$*`. We could do that with `.SECONDEXPANSION:`, but that is a # whole can of worms. Instead, we use a foreach loop to loop over all # possibilities. `svn` doesn't have this issue, because, unlike `git` # and `tar`, it's `extra` component is present in `build/download`. build/extract/git/%: # magic foreach loop gitref='$(shell utils/file2extra 'git/$*'|cut -d/ -f1)' && \ gitdir=build/extract/'$(shell utils/file2base 'git/$*')'/$${gitref} && \ $(RM) -r "$$gitdir" && \ { \ $(MKDIRS) "$$(dirname "$$gitdir")" && \ $(GIT) clone build/download/'$(shell utils/file2base 'git/$*')' "$$gitdir" && \ ( cd "$$gitdir" && $(GIT) checkout "$$gitref" ) && \ $(EXISTS) '$@'; \ } || { $(RM) -r "$$gitdir"; $(FAIL); } $(TOUCH) '$@' build/extract/svn/%: build/download/svn/% $(RM) -r '$@' $(MKDIRS) '$(@D)' $(CP) -a '$<' '$@' $(TOUCH) '$@' build/extract/tar/%: # magic foreach loop basedir='build/extract/$(shell utils/file2base 'tar/$*')' && \ $(RM) -r "$$basedir" && \ { \ $(MKDIRS) "$$basedir" && \ ( cd "$$basedir" && $(TAR) -m --strip-components 1 -xf '$(top)/$<' ); \ } || { $(RM) -r "$$basedir"; $(FAIL); } $(foreach package,$(packages),$(if $(filter-out svn|%,$($(package))),$(eval \ build/extract/$(shell utils/spec2file '$($(package))'): \ build/download/$(shell utils/file2base "$$(utils/spec2file '$($(package))')") \ ))) # place (patch) ################################################################ place: PHONY $(addprefix build/workdir/,$(packages)) $(addprefix build/workdir/,$(packages)): \ build/workdir/%: $(RM) -r '$@' $(MKDIRS) '$(@D)' $(CP) -a '$<' '$@' cd '$@' && \ for patch in $(sort $(wildcard $(top)/rules/$*/*.patch)); do \ $(PATCH) -p1 < $$patch || { $(RM) -r '$@'; $(FAIL); }; \ done && \ if [ -f '$(top)/rules/$*/delete.list' ]; then \ $(RM) -r -- $$(< '$(top)/rules/$*/delete.list'); \ fi $(TOUCH) '$@' # Loop over our source configuration and set up the dependencies # beteen `build/compile` and `build/extract`. $(foreach package,$(packages),$(eval \ build/workdir/$(package): \ build/extract/$(shell utils/spec2file '$($(package))') \ $(shell $(FIND) rules/$(package) 2>/dev/null) \ )) # package ###################################################################### package: PHONY $(addprefix build/packages/,$(packages)) package_specific=$(filter $(patsubst rules/%/Makefile,%,$(wildcard rules/*/Makefile)),$(packages)) package_generic =$(filter-out $(patsubst rules/%/Makefile,%,$(wildcard rules/*/Makefile)),$(packages)) dirs2jars = $(if $1,$(shell $(FIND) $1 -name '*.jar')) deps2jars = $(filter %.jar,$1) $(call dirs2jars,$(filter build/packages/%,$1)) deps2classpath = $(shell $(ECHO) $(abspath $(call deps2jars,$1)) | $(SED) 'y/ /:/') recurse = CLASSPATH='$(call deps2classpath,$^)' extra_makefiles='$(abspath $(wildcard rules/$*/*.mk))' $(MAKE) -C build/workdir/$* -f '$1' install DESTDIR='$(top)/$@' $(addprefix build/packages/,$(package_specific)): \ build/packages/%: RECURSIVE build/workdir/% rules/%/Makefile $(call recurse,$(top)/rules/$*/Makefile) $(MKDIRS) build/packages/all && $(LNDIR) '$(top)/$@' build/packages/all $(addprefix build/packages/,$(package_generic)): \ build/packages/%: RECURSIVE build/workdir/% rules/generic/Makefile $(call recurse,$(top)/rules/generic/Makefile) $(MKDIRS) build/packages/all && $(LNDIR) '$(top)/$@' build/packages/all # boilerplate ################################################################## clean: PHONY $(RM) -r build/compile build/packages distclean: PHONY $(RM) -r .tokens build .tokens/%: $(MKDIRS) '$(@D)' $(TOUCH) '$@' .PHONY: RECURSIVE PHONY .DELETE_ON_ERROR: