+## Java and Scala source files turn into multiple `.class' files with
+## unpredictable names. Rather than try to guess stable outputs for these
+## sources, we make artificial `timestamp' files and uses these in our
+## dependencies.
+CLASSDIR = $(OUTDIR)/cls
+stamps = $(patsubst %,$(OUTDIR)/%.$1-stamp,$2)
+
+clean::; rm -rf $(CLASSDIR)
+CLEANFILES += $(OUTDIR)/*.class-stamp
+
+## Compiling actual Java code. Note that this confuses the resident Scala
+## compiler, so we have to reset it here.
+CLSISH += java
+$(OUTDIR)/%.class-stamp: %.java
+ $(call v_tag,JAVAC)mkdir -p $(CLASSDIR)/ && \
+ $(JAVAC) -d $(CLASSDIR) -cp $(CLASSDIR) $(JAVAFLAGS) $< && \
+ echo built >$@
+ $(V_AT)$(SCALAC_RESET)
+
+## Compiling Scala code.
+CLSEXT += scala
+$(OUTDIR)/%.class-stamp: %.scala
+ $(call v_tag,SCALAC)mkdir -p $(CLASSDIR)/ && \
+ $(SCALAC) -d $(CLASSDIR) -cp $(CLASSDIR) $(SCALAFLAGS) $< && \
+ echo built >$@
+
+###--------------------------------------------------------------------------
+### Native-code libraries.
+
+SHLIBS += tripe
+tripe_SOURCES = jni.c
+
+shlibfile = $(patsubst %,$(OUTDIR)/lib%.so,$1)
+SHLIBFILES = $(call shlibfile,$(SHLIBS))
+TARGETS += $(SHLIBFILES)
+ALL_SOURCES += $(foreach l,$(SHLIBS),$($l_SOURCES))
+
+$(call objects,$(tripe_SOURCES),.o): $(call stamps,ext,tripe)
+
+$(SHLIBFILES): $(OUTDIR)/lib%.so: $$(call objects,$$($$*_SOURCES),.o)
+ $(call v_tag,LD)$(LD) $(LDFLAGS.so) -o$@ $^ $(LIBS)
+
+###--------------------------------------------------------------------------
+### Java classes.
+
+## Writing things out longhand is tedious. `CLASSES' is a list of entries of
+## the form `SRC[:DEP,...]', saying that `SRC.ext', being a source file
+## capable of being built into `.class' files and setting `SRC.stamp', should
+## be so built, and that it depends on other similar sources named DEP having
+## been so built.
+CLASSES += util
+CLASSES += sys:util
+CLASSES += admin:sys,util
+CLASSES += tar:util
+CLASSES += progress:sys,util
+CLASSES += keys:progress,tar,sys,util
+CLASSES += terminal:progress,sys,util
+
+## Machinery for parsing the `CLASSES' list.
+COMMA = ,
+class-name = $(firstword $(subst :, ,$1))
+class-deps = $(subst $(COMMA), ,$(word 2,$(subst :, ,$1)))
+
+CLASS_NAMES = $(foreach c,$(CLASSES),$(call class-name,$c))
+
+all:: $(call stamps,class,$(CLASS_NAMES))
+
+$(foreach c,$(CLASSES),$(eval $(call stamps,class,$(call class-name,$c)): \
+ $(call stamps,class,$(call class-deps,$c))))
+
+DISTFILES += $(foreach c,$(CLASSES),\
+ $(foreach e,$(CLSEXT),\
+ $(wildcard $(call class-name,$c).$e)))
+
+###--------------------------------------------------------------------------
+### External packages.
+
+EXTERNALS += adns
+adns_CONFIG = --disable-dynamic
+
+EXTERNALS += mLib
+mLib_DEPS = adns
+mLib_CONFIG = --enable-static --disable-shared --with-adns
+
+EXTERNALS += catacomb
+catacomb_DEPS = mLib
+catacomb_CONFIG = --enable-static --disable-shared
+
+EXTERNALS += tripe
+tripe_DEPS = mLib catacomb
+tripe_CONFIG = --without-wireshark --with-adns --with-tunnel=slip
+
+all:: $(call stamps,ext,$(EXTERNALS))
+CLEANFILES += $(OUTDIR)/*.ext-stamp
+clean::; rm -rf $(OUTDIR)/inst $(OUTDIR)/build
+
+$(call stamps,ext,$(EXTERNALS)): \
+ $(OUTDIR)/%.ext-stamp: $$(call stamps,ext,$$($$*_DEPS))
+ $(V_AT)rm -rf $(OUTDIR)/build/$*/
+ $(V_AT)mkdir -p $(OUTDIR)/build/$*/
+ cd $(OUTDIR)/build/$*/ && \
+ $(call join-paths,../../..,$(call ext-srcdir,$*))/configure \
+ --prefix=$(EXTPREFIX) \
+ $($*_CONFIG) \
+ CFLAGS="-O2 -g -fPIC -Wall -I$(EXTPREFIX)/include" \
+ LDFLAGS="-L$(EXTPREFIX)/lib" \
+ PKG_CONFIG="pkg-config --static" \
+ PKG_CONFIG_LIBDIR=$(EXTPREFIX)/lib/pkgconfig
+ $(MAKE) -C$(OUTDIR)/build/$*/
+ $(MAKE) -C$(OUTDIR)/build/$*/ -s install
+ $(V_AT)echo done >$@
+
+###--------------------------------------------------------------------------
+### Distribution arrangements.
+
+DISTFILES += COPYING
+DISTFILES += Makefile
+DISTFILES += auto-version
+
+distdir = $(PACKAGE)-$(VERSION)
+DISTTAR = $(distdir).tar.gz
+
+distdir:
+ rm -rf $(OUTDIR)/$(distdir)
+ mkdir $(OUTDIR)/$(distdir)/
+ echo $(VERSION) >$(OUTDIR)/$(distdir)/RELEASE
+ set -e; for i in $(DISTFILES); do \
+ case $$i in */*) mkdir -p $(OUTDIR)/$(distdir)/$${i%/*}/ ;; esac; \
+ cp $$i $(OUTDIR)/$(distdir)/; \
+ done
+.PHONY: distdir
+
+dist: distdir
+ set -e; cd $(OUTDIR)/; tar chozf ../$(DISTTAR) $(distdir)
+ rm -rf $(distdir)
+.PHONY: dist
+
+###--------------------------------------------------------------------------
+### Finishing touches.