Fix SPARC build, missing #include
[ghc-hetmet.git] / mk / target.mk
index 1ce8239..37a72bc 100644 (file)
@@ -2,24 +2,24 @@
 #
 #                      target.mk
 #
-#              Standard targets for fptools
+#              Standard targets for GHC
 #
 #################################################################################
 
 #
 # This file contain three groups of target rules:
 #
-# 1.  FPtools targets
+# 1.  GHC targets
 #      depend*
 #      runtests*
 #
 # 2.  GNU standard targets
 #      all*
-#      install* uninstall installcheck installdirs
+#      install* installcheck installdirs
+#       install-docs*
 #      clean* distclean* mostlyclean* maintainer-clean*
 #      tags*
-#      info dvi ps
-#      dist binary-dist
+#      dvi ps (no info) GHC adds: pdf rtf html chm HxS
 #      check
 #
 # 3. Some of the above targets have a version that
 # 
 #
 
+##################################################################
+# Pre-compute the list of sources so we don't have to do this 
+# multiple times.  See paths.mk.
+
+PRE_SRCS := $(ALL_SRCS)
+
+##################################################################
+# Include package building machinery
+# NB. needs to be after PRE_SRCS setting above, because otherwise the
+# rule dependencies won't be set correctly.
+
+include $(TOP)/mk/package.mk
+
+###################################################################
+# Suffix rules for Haskell, C and literate 
+
+include $(TOP)/mk/suffix.mk
 
 ##################################################################
-#              FPtools standard targets
+#              GHC standard targets
 #
 # depend:
 #
 # Compiler produced files that are targets of the source's imports.
 MKDEPENDHS_OBJ_SUFFICES=o
 
-# HC_OPTS sometimes contains $*, which will expand to nothing in the depend
-# rule below.  So we replace $* with a dummy value for passing to mkdependHS
-# and hope it works.  
-#
-# This crops up with GhcLibHcOpts which ends in '-split_objs -odir $*'
+ifneq "$(BootingFromHc)" "YES"
+PKGCONF_DEP = $(STAMP_PKG_CONF)
+endif
 
-MKDEPENDHS_HC_OPTS = $(patsubst $*,dollar_star,$(HC_OPTS))
+ifeq "$(USE_NEW_MKDEPEND_FLAGS)" "YES"
+MKDEPENDHS_FLAGS = -dep-makefile .depend $(foreach way,$(WAYS),-dep-suffix $(way))
+else
+MKDEPENDHS_FLAGS = -optdep-f -optdep.depend $(foreach way,$(WAYS),-optdep-s -optdep$(way))
+endif
 
-depend :: $(MKDEPENDHS_SRCS) $(MKDEPENDC_SRCS)
+depend :: $(MKDEPENDHS_SRCS) $(MKDEPENDC_SRCS) $(PKGCONF_DEP)
        @$(RM) .depend
        @touch .depend
 ifneq "$(DOC_SRCS)" ""
        $(MKDEPENDLIT) -o .depend $(MKDEPENDLIT_OPTS) $(filter %.lit,$(DOC_SRCS))
 endif
 ifneq "$(MKDEPENDC_SRCS)" ""
-       $(MKDEPENDC) -f .depend $(MKDEPENDC_OPTS) -- $(CC_OPTS) -- $(MKDEPENDC_SRCS)
+       $(MKDEPENDC) -f .depend $(MKDEPENDC_OPTS) $(foreach way,$(WAYS),-s $(way)) -- $(CC_OPTS) -- $(MKDEPENDC_SRCS) 
 endif
 ifneq "$(MKDEPENDHS_SRCS)" ""
-       $(MKDEPENDHS) -M -optdep-f -optdep.depend $(foreach way,$(WAYS),-optdep-s -optdep$(way)) $(foreach obj,$(MKDEPENDHS_OBJ_SUFFICES),-optdep-o -optdep$(obj)) $(MKDEPENDHS_OPTS) $(MKDEPENDHS_HC_OPTS) $(MKDEPENDHS_SRCS)
+       $(MKDEPENDHS) -M $(MKDEPENDHS_FLAGS) $(foreach obj,$(MKDEPENDHS_OBJ_SUFFICES),-osuf $(obj)) $(MKDEPENDHS_OPTS) $(filter-out -split-objs, $(HC_OPTS)) $(MKDEPENDHS_SRCS)
 endif
 
+
 ##################################################################
 #                      boot
 #
 #  The boot target, at a minimum generates dependency information
 
 .PHONY: boot
-boot :: depend
 
+ifeq "$(NO_BOOT_TARGET)" "YES"
+boot ::
+else
+boot :: depend
+endif
 
 ##################################################################
 #              GNU Standard targets
@@ -99,9 +123,7 @@ boot :: depend
 # 
 # `all'
 #      Compile the entire program. This should be the default target.
-#      This target need not rebuild any documentation files; Info files
-#      should normally be included in the distribution, and DVI files
-#      should be made only when explicitly asked for.
+#      This target need not rebuild any documentation files
 # 
 # `install'
 #      Compile the program and copy the executables, libraries, and so on
@@ -120,32 +142,6 @@ boot :: depend
 #      will ignore any errors.  This is in case there are systems that
 #      don't have the Unix man page documentation system installed.
 # 
-#      The way to install Info files is to copy them into `$(infodir)'
-#      with $(INSTALL_DATA) (see Command Variables), and then run the
-#      install-info program if it is present.  install-info is a script
-#      that edits the Info `dir' file to add or update the menu entry for
-#      the given Info file; it will be part of the Texinfo package. Here
-#      is a sample rule to install an Info file:
-# 
-#           $(infodir)/foo.info: foo.info # There may be a newer info
-#           file in . than in srcdir.
-#                   -if test -f foo.info; then d=.; \
-#                    else d=$(srcdir); fi; \ $(INSTALL_DATA)
-#                   $$d/foo.info $@; \ # Run install-info only if it
-#           exists.  # Use `if' instead of just prepending `-' to the
-#           # line so we notice real errors from install-info.  # We
-#           use `$(SHELL) -c' because some shells do not # fail
-#           gracefully when there is an unknown command.
-#                   if $(SHELL) -c 'install-info --version' \
-#                      >/dev/null 2>&1; then \ install-info
-#                     --infodir=$(infodir) $$d/foo.info; \ else true;
-#                   fi
-# 
-# `uninstall'
-#      Delete all the installed files that the `install' target would
-#      create (but not the noninstalled files such as `make all' would
-#      create).
-# 
 # `clean'
 # 
 #      Delete all files from the current directory that are normally
@@ -174,7 +170,7 @@ boot :: depend
 #      Delete everything from the current directory that can be
 #      reconstructed with this Makefile.  This typically includes
 #      everything deleted by distclean , plus more: C source files
-#      produced by Bison, tags tables, Info files, and so on.
+#      produced by Bison, tags tables, and so on.
 # 
 #      One exception, however: `make maintainer-clean' should not delete
 #      `configure' even if `configure' can be remade using a rule in the
@@ -185,53 +181,11 @@ boot :: depend
 # `TAGS'
 #      Update a tags table for this program.
 # 
-# `info'
-#      Generate any Info files needed. The best way to write the rules is
-#      as follows:
-# 
-#           info: foo.info
-# 
-#           foo.info: foo.texi chap1.texi chap2.texi
-#                   $(MAKEINFO) $(srcdir)/foo.texi
-# 
-#      You must define the variable MAKEINFO in the Makefile. It should
-#      run the makeinfo program, which is part of the Texinfo
-#      distribution.
-# 
-# `dvi' `ps'
-#      Generate DVI files for all TeXinfo documentation. For example:
-# 
-#           dvi: foo.dvi
-# 
-#           foo.dvi: foo.texi chap1.texi chap2.texi
-#                   $(TEXI2DVI) $(srcdir)/foo.texi
-# 
-#      You must define the variable TEXI2DVI in the Makefile. It should
-#      run the program texi2dvi , which is part of the Texinfo
-#      distribution. Alternatively, write just the dependencies, and
-#      allow GNU Make to provide the command.
-#
-#      ps is a FPtools addition for Postscript files
-# 
-# `dist' `binary-dist'
-#      Create a distribution tar file for this program. The tar file
-#      should be set up so that the file names in the tar file start with
-#      a subdirectory name which is the name of the package it is a
-#      distribution for. This name can include the version number.
-# 
-#      For example, the distribution tar file of GCC version 1.40 unpacks
-#      into a subdirectory named `gcc-1.40'.
-# 
-#      The easiest way to do this is to create a subdirectory
-#      appropriately named, use ln or cp to install the proper files in
-#      it, and then tar that subdirectory.
-# 
-#      The dist target should explicitly depend on all non-source files
-#      that are in the distribution, to make sure they are up to date in
-#      the distribution. See Making Releases.
+# `dvi' `ps' `pdf' `html' `chm' `HxS' `rtf' 
+#      Generate DVI/PS/PDF files for LaTeX/DocBook docs. Not everything is
+#      supported everywhere, but the intention is to standardise on DocBook
+#      producing all formats.
 #
-#      binary-dist is an FPtools addition for binary distributions
-# 
 # `check'
 #      Perform self-tests (if any). The user must build the program
 #      before running the tests, but need not install the program; you
@@ -251,7 +205,7 @@ boot :: depend
 #      directories where files are installed, and their parent
 #      directories. There is a script called `mkinstalldirs' which is
 #      convenient for this; find it in the Texinfo package.
-#      (FPTOOLS: we use a close relative of the suggested script, situated
+#      (GHC: we use a close relative of the suggested script, situated
 #       in glafp-utils/mkdirhier -- SOF)
 
 
@@ -269,7 +223,6 @@ boot :: depend
 #      HS_PROG         Haskell program
 #      C_PROG          C program
 #      LIBRARY         Library
-#      SCRIPT_PROG     Script (e.g. Perl script)
 #
 # For details of exactly what rule is generated, see the
 # relevant section below
@@ -282,8 +235,14 @@ boot :: depend
 ifneq "$(HS_PROG)" ""
 all :: $(HS_PROG)
 
-$(HS_PROG) :: $(HS_OBJS)
-       $(HC) -o $@ $(HC_OPTS) $(LD_OPTS) $(HS_OBJS) $(LIBS)
+ifneq "$(BootingFromHc)" "YES"
+$(HS_PROG) :: $(OBJS)
+       $(HC) -o $@ $(HC_OPTS) $(LD_OPTS) $(OBJS)
+else
+# see bootstrap.mk
+$(HS_PROG) :: $(OBJS)
+       $(CC) -o $@ $(HC_BOOT_CC_OPTS) $(HC_BOOT_LD_OPTS) $(OBJS) $(HC_BOOT_LIBS)
+endif
 endif
 
 #----------------------------------------
@@ -296,19 +255,33 @@ $(C_PROG) :: $(C_OBJS)
        $(CC) -o $@ $(CC_OPTS) $(LD_OPTS) $(C_OBJS) $(LIBS)
 endif
 
-
 #----------------------------------------
 #      Libraries/archives
+#
+# Build $(LIBRARY) from $(LIBOBJS)+$(STUBOBJS)
+#
+# Inputs:
+#   $(LIBOBJS)
+#   $(STUBOBJS)
+#
+# Outputs:
+#   Rule to build $(LIBRARY)
 
 ifneq "$(LIBRARY)" ""
 all :: $(LIBRARY)
 
-
-define BUILD_LIB
+ifneq "$(way)" "i"
+define BUILD_STATIC_LIB
 $(RM) $@
-$(AR) $(AR_OPTS) $@ $(LIBOBJS)
+$(AR) $(AR_OPTS) $@ $(STUBOBJS) $(LIBOBJS)
 $(RANLIB) $@
 endef
+else
+define BUILD_STATIC_LIB
+$(RM) $@
+al -out:$@ $(STUBOBJS) $(LIBOBJS)
+endef
+endif
 
 #
 # For Haskell object files, we might have chosen to split
@@ -317,459 +290,186 @@ endef
 # whether HS_SRCS is empty or not.
 #
 
-ifneq "$(HS_SRCS)" ""
-ifneq "$(filter -split-objs,$(HC_OPTS))" ""
-define BUILD_LIB
-$(RM) $@
-TMPDIR=$(TMPDIR); export TMPDIR; find $(patsubst %.$(way_)o,%,$(LIBOBJS)) -name '*.$(way_)o' -print | xargs ar q $@
-$(RANLIB) $@
-endef
-endif # $(filter...
-endif
-
-$(LIBRARY) :: $(LIBOBJS)
-       $(BUILD_LIB)
+# can't split objs in way 'u', so we disable it here
+ifeq "$(way)" "u"
+SplitObjs = NO
 endif
 
-#----------------------------------------
-#      Script programs
-
-ifneq "$(SCRIPT_PROG)" ""
-
-# To produce a fully functional script, you may
-# have to add some configuration variables at the top of 
-# the script, i.e., the compiler driver needs to know
-# the path to various utils in the build tree for instance.
-#
-# To have the build rule for the script automatically do this
-# for you, set the variable SCRIPT_SUBST_VARS to the list of
-# variables you need to put in.
-
-#
-# SCRIPT_SUBST creates a string of echo commands that
-# will when evaluated append the (perl)variable name and its value 
-# to the target it is used for, i.e.,
-#
-#    A=foo
-#    B=bar
-#    SCRIPT_SUBST_VARS = A B
-#    SCRIPT_SUBST=echo "$""A=\"foo\";" >> $@; echo "$""B=\"bar\";" >> $@
-#
-#    so if you have a rule like the following
-#    
-#     foo:
-#         @(RM) $@
-#         @(TOUCH) $@
-#         @eval $(SCRIPT_SUBST)
-#
-#    `make foo' would create a file `foo' containing the following
-#
-#    % cat foo
-#    $A=foo;
-#    $B=bar;
-#    %
-#
-# ToDo: make this work for shell scripts (drop the initial $).
-#
-ifeq "$(INTERP)" "$(SHELL)"
-SCRIPT_SUBST=$(foreach val,$(SCRIPT_SUBST_VARS),"echo \"$(val)=\\\"$($(val))\\\";\" >> $@;")
-else
-SCRIPT_SUBST=$(foreach val,$(SCRIPT_SUBST_VARS),"echo \"$$\"\"$(val)=\\\"$($(val))\\\";\" >> $@;")
-endif
-
-all :: $(SCRIPT_PROG)
+ifneq "$(HS_SRCS)" ""
+ifeq "$(SplitObjs)" "YES"
 
-#
-# #! support under cygwin32 is not quite there yet, 
-# so we rely on the eval `trick' instead. On all other
-# platforms, we prepend #!$(INTERP)  -- SOF 6/97
-# 
+SRC_HC_OPTS += -split-objs
 
-$(SCRIPT_PROG) :: $(SCRIPT_OBJS)
-       $(RM) $@
-       @echo Creating $@...
-ifeq "$(INTERP)" "perl"
-ifneq "$(BIN_DIST)" "1"
-       echo "#! "$(PERL) > $@
-else
-       @touch $@
-endif
-else
-ifneq "$(INTERP)" ""
-       @echo "#!"$(INTERP) > $@
+# We generate the archive into a temporary file libfoo.a.tmp, then
+# rename it at the end.  This avoids the problem that ar may sometimes
+# fail, leaving a partially built archive behind.
+ifeq "$(ArSupportsInput)" ""
+define BUILD_STATIC_LIB
+$(RM) $@ $@.tmp
+(echo $(STUBOBJS) $(C_OBJS) $(GC_C_OBJS); $(FIND) $(patsubst %.$(way_)o,%_split,$(HS_OBJS)) -name '*.$(way_)o' -print) | xargs $(AR) $@
+$(RANLIB) $@
+endef
 else
-       @touch $@
-endif
-endif
-ifneq "$(SCRIPT_PREFIX_FILES)" ""
-       @cat $(SCRIPT_PREFIX_FILES) >> $@
-endif
-       @eval $(SCRIPT_SUBST) 
-       @cat $(SCRIPT_OBJS) >> $@
-       @chmod a+x $@
-       @echo Done.
+define BUILD_STATIC_LIB
+$(RM) $@ $@.tmp
+echo $(STUBOBJS) > $@.list
+echo $(C_OBJS) >> $@.list
+echo $(GC_C_OBJS) >> $@.list
+$(FIND) $(patsubst %.$(way_)o,%_split,$(HS_OBJS)) -name '*.$(way_)o' -print >> $@.list
+$(AR) $(AR_OPTS) $@ $(ArSupportsInput) $@.list
+$(RM) $@.list
+$(RANLIB) $@
+endef
 endif
 
+# Extra stuff for compiling Haskell files with $(SplitObjs):
 
-###########################################
 #
-#      Targets: install install-strip uninstall
+# If (Haskell) object files are split, cleaning up 
+# consist of descending into the directories where
+# the myriads of object files have been put.
 #
-###########################################
 
-# For each of these variables that is defined, you
-# get one install rule
-#
-#      INSTALL_PROGS     executable programs in $(bindir)
-#      INSTALL_SCRIPTS   executable scripts in $(bindir)
-#      INSTALL_LIBS      platform-dependent libraries in $(libdir) (ranlib'ed)
-#      INSTALL_LIBEXECS  platform-dependent execs in $(libdir)
-#      INSTALL_DATAS     platform-independent files in $(datadir)
-#
-# If the installation directory variable is undefined, the install rule simply
-# emits a suitable error message.
-#
-# Remember, too, that the installation directory variables ($(bindir) and
-# friends can be overridden from their original settings in mk/config.mk.in
-# || mk/build.mk
-#
-.PHONY: install installdirs install-strip install-dirs uninstall install-docs show-install
+extraclean ::
+       $(FIND) $(patsubst %.$(way_)o,%_split,$(HS_OBJS)) -name '*.$(way_)o' -print -o -name ld.script -print | xargs $(RM) __rm_food
+       -rmdir $(patsubst %.$(way_)o,%_split,$(HS_OBJS)) > /dev/null 2>&1
 
-show-install :
-       @echo "bindir = $(bindir)"
-       @echo "libdir = $(libdir)"
-       @echo "libexecdir = $(libexecdir)  # by default, same as libdir"
-       @echo "datadir = $(datadir)  # unused for ghc project"
+endif # $(SplitObjs)
+endif # $(HS_SRCS)
 
 #
-# Sometimes useful to separate out the creation of install directories 
-# from the installation itself.
+# Remove local symbols from library objects if requested.
 #
-install-dirs ::
-       @$(INSTALL_DIR) $(bindir)
-       @$(INSTALL_DIR) $(libdir)
-       @$(INSTALL_DIR) $(libexecdir)
-       @$(INSTALL_DIR) $(datadir)
-
-# Better do this first...
-# but we won't for the moment, do it on-demand from
-# within the various install targets instead.
-#install:: install-dirs
-
-ifneq "$(INSTALL_PROGS)" ""
-install:: $(INSTALL_PROGS)
-       @$(INSTALL_DIR) $(bindir)
-       for i in $(INSTALL_PROGS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_BIN_OPTS) $$i$(exeext) $(bindir); \
-       done
-endif
 
-#
-# Just like INSTALL_PROGS, but prefix with install sites bin/lib/data and
-# install without stripping.
-#
-ifneq "$(INSTALL_SCRIPTS)" ""
-install:: $(INSTALL_SCRIPTS)
-       @$(INSTALL_DIR) $(bindir)
-ifeq "$(INTERP)" "perl"
-ifneq "$(BIN_DIST)" "1"
-       @for i in $(INSTALL_SCRIPTS); do \
-          $(RM) $$i.tmp; \
-          echo "#! $(PERL)" > $$i.tmp ; \
-          echo '$$'"bindir='$(bindir)';"                            >> $$i.tmp ; \
-          echo '$$'"libdir='$(libdir)';"                            >> $$i.tmp ; \
-          echo '$$'"libexecdir='$(libexecdir)';"                    >> $$i.tmp ; \
-          echo '$$'"datadir='$(datadir)';"                          >> $$i.tmp ; \
-          cat  $$i                                                >> $$i.tmp ; \
-          echo $(INSTALL_PROGRAM) $(filter-out -s,$(INSTALL_OPTS)) $$i.tmp $(bindir)/$$i ;    \
-          $(INSTALL_PROGRAM) $(filter-out -s,$(INSTALL_BIN_OPTS)) $$i.tmp $(bindir)/$$i ; \
-          $(RM) $$i.tmp; \
-       done
-else
-       for i in $(INSTALL_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(bindir); \
-       done
-endif
+ifeq "$(StripLibraries)" "YES"
+ifeq "$(SplitObjs)" "YES"
+SRC_HC_POST_OPTS += \
+  for i in $(basename $@)_split/*.$(way_)o; do \
+       $(LD) -r $(LD_X) -o $$i.tmp $$i; \
+       $(MV) $$i.tmp $$i; \
+  done
 else
-       for i in $(INSTALL_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(bindir); \
-       done
-endif
-endif
-
-ifneq "$(INSTALL_LIB_SCRIPTS)" ""
-install:: $(INSTALL_LIB_SCRIPTS)
-       @$(INSTALL_DIR) $(libdir)
-ifeq "$(INTERP)" "perl"
-ifneq "$(BIN_DIST)" "1"
-       @for i in $(INSTALL_LIB_SCRIPTS); do \
-          $(RM) $$i.tmp; \
-          echo "#! $(PERL)" > $$i.tmp ; \
-          echo '$$'"bindir='$(bindir)';"                            >> $$i.tmp ; \
-          echo '$$'"libdir='$(libdir)';"                            >> $$i.tmp ; \
-          echo '$$'"libexecdir='$(libexecdir)';"                    >> $$i.tmp ; \
-          echo '$$'"datadir='$(datadir)';"                          >> $$i.tmp ; \
-          cat  $$i                                                >> $$i.tmp ; \
-          echo $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libdir) ;    \
-          $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i.tmp $(libdir)/$$i ; \
-          $(RM) $$i.tmp; \
-       done
-else
-       for i in $(INSTALL_LIB_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libdir); \
-       done
-endif
+SRC_HC_POST_OPTS += \
+  $(LD) -r $(LD_X) -o $@.tmp $@; $(MV) $@.tmp $@
+endif # SplitObjs
+endif # StripLibraries
+
+# Note: $(STUBOBJS) isn't depended on here, but included when building the lib.
+#       (i.e., the assumption is that $(STUBOBJS) are created as a side-effect
+#       of building $(LIBOBJS)).
+
+ifeq "$(LIBRARY:%.so=YES)" "YES"
+# ELF styled DSO
+$(LIBRARY): $(LIBOBJS) $(LIB_DEPS)
+       $(RM) $@
+       $(HC) -shared -dynamic -o $@ $(STUBOBJS) $(LIBOBJS) $(LIB_LD_OPTS)
 else
-       for i in $(INSTALL_LIB_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libdir); \
-       done
-endif
-endif
-
-ifneq "$(INSTALL_LIBEXEC_SCRIPTS)" ""
-install:: $(INSTALL_LIBEXEC_SCRIPTS)
-       @$(INSTALL_DIR) $(libexecdir)
-ifeq "$(INTERP)" "perl"
-ifneq "$(BIN_DIST)" "1"
-       @for i in $(INSTALL_LIBEXEC_SCRIPTS); do \
-          $(RM) $$i.tmp; \
-          echo "#! $(PERL)" > $$i.tmp ; \
-          echo '$$'"bindir='$(bindir)';"                            >> $$i.tmp ; \
-          echo '$$'"libdir='$(libdir)';"                            >> $$i.tmp ; \
-          echo '$$'"libexecdir='$(libexecdir)';"                    >> $$i.tmp ; \
-          echo '$$'"datadir='$(datadir)';"                          >> $$i.tmp ; \
-          cat  $$i                                                >> $$i.tmp ; \
-          echo $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libexecdir) ;    \
-          $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i.tmp $(libexecdir)/$$i ; \
-          $(RM) $$i.tmp; \
-       done
+ifeq "$(LIBRARY:%.dylib=YES)" "YES"
+$(LIBRARY): $(LIBOBJS) $(LIB_DEPS)
+       $(HC) -shared -dynamic -o $@ $(STUBOBJS) $(LIBOBJS) $(LIB_LD_OPTS)
 else
-       for i in $(INSTALL_LIBEXEC_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libexecdir); \
-       done
-endif
-else
-       for i in $(INSTALL_LIBEXEC_SCRIPTS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_OPTS) $$i $(libexecdir); \
-       done
-endif
-endif
-
-ifneq "$(INSTALL_LIBS)" ""
-install:: $(INSTALL_LIBS)
-       @$(INSTALL_DIR) $(libdir)
-       for i in $(INSTALL_LIBS); do \
-               case $$i in \
-                 *.a) \
-                   $(INSTALL_DATA) $(INSTALL_OPTS) $$i $(libdir); \
-                   $(RANLIB) $(libdir)/`basename $$i` ;; \
-                 *) \
-                   $(INSTALL_DATA) $(INSTALL_OPTS) $$i $(libdir); \
-               esac; \
-       done
-endif
-
-ifneq "$(INSTALL_LIBEXECS)" ""
-install:: $(INSTALL_LIBEXECS)
-       @$(INSTALL_DIR) $(libexecdir)
-       -for i in $(INSTALL_LIBEXECS); do \
-               $(INSTALL_PROGRAM) $(INSTALL_BIN_OPTS) $$i$(exeext) $(libexecdir); \
-       done
-endif
-
-ifneq "$(INSTALL_DATAS)" ""
-install:: $(INSTALL_DATAS)
-       @$(INSTALL_DIR) $(datadir)
-       for i in $(INSTALL_DATAS); do \
-               $(INSTALL_DATA) $(INSTALL_OPTS) $$i $(datadir); \
-       done
-endif
-
-#
-# Use with care..
+ifeq "$(LIBRARY:%.dll=YES)" "YES"
+#----------------------------------------
+#      Building Win32 DLLs
 #
-uninstall:: 
-ifeq ($(INSTALL_PROGS),)
-       @for i in $(INSTALL_PROGS) ; do                         \
-               echo rm -f $(bindir)/`basename $$i`;            \
-               rm -f $(bindir)/`basename $$i`;                 \
-       done
-endif
-ifeq ($(INSTALL_LIBS),)
-       @for i in $(INSTALL_LIBS); do                           \
-               echo rm -f $(libdir)/`basename $$i`;            \
-               rm -f $(libdir)/`basename $$i`;                 \
-       done
-endif
-ifeq ($(INSTALL_LIBEXECS),)
-       @for i in $(INSTALL_LIBEXECS); do                       \
-               echo rm -f $(libexecdir)/`basename $$i`;        \
-               rm -f $(libexecdir)/`basename $$i`;             \
-       done
-endif
-ifeq ($(INSTALL_DATAS),)
-       @for i in $(INSTALL_DATAS); do                          \
-               echo rm -f $(datadir)/`basename $$i`;           \
-               rm -f $(datadir)/`basename $$i`;                \
-       done
-endif
+$(LIBRARY): $(LIBOBJS) $(LIBRARY).o $(LIB_DEPS)
+       $(HC) -shared -dynamic -o $@ $(STUBOBJS) $(LIBOBJS) $(LIBRARY).o $(LIB_LD_OPTS)
 
-#
-# install-strip is from the GNU Makefile standard.
-#
-ifneq "$(way)" ""
-install-strip::
-       @$(MAKE) EXTRA_INSTALL_OPTS='-s' install                                        
-endif
+DLLTOOL=dlltool
 
-###########################################
-#
-#      Targets: dist binary-dist
-#
-###########################################
+$(LIBRARY).def: $(LIBOBJS)
+       $(DLLTOOL) -D $(LIBRARY) --output-def $@ --export-all $(LIBOBJS)
 
+$(LIBRARY).o:
+       $(DLLTOOL) -D $(LIBRARY) --output-exp $(LIBRARY).o $(LIBOBJS)
 
-#
-# dist-pre is a canned rule the toplevel of your source tree
-# would use as follows, 
-#
-#  dist :: dist-pre
-#
-# it performs two tasks, first creating the distribution directory
-# tree and it then decorates the new tree with symbolic links pointing
-# to the symbolic links in the build tree.
-#
-# The dist-pre relies on (at least) the `find' in GNU findutils
-# (only tested with version 4.1). All non-GNU `find's I have
-# laid on my hands locally, has a restrictive treatment of {} in
-# -exec commands, i.e.,
-#
-#   find . -print echo a{} \;
-#   
-# does not expand the {}, it has to be a separate argument (i.e. `a {}').
-# GNU find is (IMHO) more sensible here, expanding any {} it comes across
-# inside an -exec, whether it is a separate arg or part of a word:
-#
-#  $ touch yes
-#  $ find --version
-#    GNU find version 4.1
-#  $ find yes -exec echo oh,{}! \;
-#    oh,yes!
-#
-# Of course, the above is not impossible to achieve with other finds,
-# just that GNU find does the Patently Right Thing here :)
-#
-# ====> if you're using these dist rules, get hold of GNU findutils.
-#
-#  --SOF 2/97
-#
-.PHONY: dist dist-pre dist-post
+# Generates library.dll.a; by MinGW conventions, this is the dll's import library
+$(LIBRARY).a: $(LIBOBJS) $(LIBRARY).def
+       $(DLLTOOL) -D $(LIBRARY) --def $(LIBRARY).def --output-lib $@
 
 #
-# The dist rules leaves out CVS, SRC (from mkshadowdir) and tests
-# directories when creating shadow source distrib tree
+# Version information is baked into a DLL by having the DLL include DllVersionInfo.o.
+# The version info contains two user tweakables: DLL_VERSION and DLL_VERSION_NAME.
+# (both are given sensible defaults though.)
 #
-dist-pre::
-       -rm -rf $(SRC_DIST_DIR)
-       -rm -f $(SRC_DIST_NAME).tar.gz
-       (cd $(FPTOOLS_TOP_ABS); find $(SRC_DIST_DIRS) -type d \( -name CVS -prune -o -name SRC -prune -o -name tests -prune -o -exec $(MKDIRHIER) $(SRC_DIST_DIR)/{} \; \) ; )
-       (cd $(FPTOOLS_TOP_ABS); find $(SRC_DIST_DIRS) -name CVS -prune -o -name SRC -prune -o -name tests -prune -o -name "*~" -prune -o -name ".cvsignore" -prune -o -name "\#*" -prune -o -name ".\#*" -prune -o -type l -exec $(LN_S) $(FPTOOLS_TOP_ABS)/{} $(SRC_DIST_DIR)/{} \; )
+# Note: this will not work as expected with Cygwin B20.1; you need a more recent
+#       version of binutils (to pick up windres bugfixes.)
 
-#
-# After having created a shadow distribution tree and copied/linked
-# all the necessary files to it, `dist-post' makes sure the permissions
-# are set right and then package up the tree. Empty directories are also removed.
-#
-# For now, we make the packaging a separate rule, so as to allow
-# the inspection of the dist tree before eventually packaging it up.
-#
-dist-post::
-       @echo Deleting the following empty directories..
-       ( cd $(SRC_DIST_DIR) ; cd .. ; find $(SRC_DIST_NAME) -type d -exec sh -c 'test x`ls $$0 | wc -l | sed -e "s/ //g"` = x0' {} \; -print -exec rm -rf {} \; -prune )
-       ( cd $(SRC_DIST_DIR) ; cd .. ; chmod -R a+rw $(SRC_DIST_NAME) ) 
+ifndef DLL_VERSION
+DLL_VERSION=$(ProjectVersion)
+endif
 
-dist-package::
-       cd $(SRC_DIST_DIR); cd ..; $(TAR) chzf $(SRC_DIST_NAME).tar.gz $(SRC_DIST_NAME)
+ifndef DLL_VERSION_NAME
+DLL_VERSION_NAME="http://www.haskell.org/ghc"
+endif
 
-#
+ifndef DLL_DESCRIPTION
+DLL_DESCRIPTION="A GHC-compiled DLL"
+endif
 
+ifndef EXE_VERSION
+EXE_VERSION=$(ProjectVersion)
+endif
 
-# The default dist rule:
-#
-# copy/link the contents of $(SRC_DIST_FILES) into the
-# shadow distribution tree. SRC_DIST_FILES contain the
-# build-generated files that you want to include in
-# a source distribution.
-#
-#
-ifneq "$(SRC_DIST_FILES)" ""
-dist::
-       @for i in $(SRC_DIST_FILES); do                  \
-         if (test -f "$$i"); then                       \
-           echo $(LN_S) `pwd`/$$i $(SRC_DIST_DIR)/$$i ; \
-           $(LN_S) `pwd`/$$i $(SRC_DIST_DIR)/$$i ;      \
-         fi;                                            \
-       done;
+ifndef EXE_VERSION_NAME
+EXE_VERSION_NAME="http://www.haskell.org/ghc"
 endif
 
-#
-# binary-dist creates a binary bundle, set BIN_DIST_NAME
-# to package name and do `make binary-dist' (normally this
-# just a thing you would do from the toplevel of fptools or)
-# from the top of a project.
-#
-.PHONY: binary-dist-pre binary-dist binary-pack
-
-binary-dist-pre::
-       -rm -rf $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)
-       -rm -f $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME).tar.gz
-       @for i in $(BIN_DIST_DIRS); do                   \
-         if test -d "$$i"; then                         \
-          echo $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/bin/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion); \
-          $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/bin/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion); \
-          echo $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion); \
-          $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion); \
-          echo $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/share/$(ProjectNameShort)-$(ProjectVersion); \
-          $(MKDIRHIER) $(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/share/$(ProjectNameShort)-$(ProjectVersion); \
-          echo $(MAKE) -C $$i $(MFLAGS) install BIN_DIST=1 BIN_DIST_NAME=$(BIN_DIST_NAME) \
-                       prefix=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME) \
-                       exec_prefix=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME) \
-                       bindir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/bin/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       libdir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       libexecdir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       datadir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/share/$(ProjectNameShort)-$(ProjectVersion) ; \
-          $(MAKE) -C $$i $(MFLAGS) install BIN_DIST=1 BIN_DIST_NAME=$(BIN_DIST_NAME) \
-                       prefix=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME) \
-                       exec_prefix=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME) \
-                       bindir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/bin/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       libdir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       libexecdir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/lib/$(TARGETPLATFORM)/$(ProjectNameShort)-$(ProjectVersion) \
-                       datadir=$(BIN_DIST_TMPDIR)/$(BIN_DIST_NAME)/share/$(ProjectNameShort)-$(ProjectVersion) ; \
-         fi; \
-       done
+ifndef EXE_DESCRIPTION
+EXE_DESCRIPTION="A GHC-compiled binary"
+endif
 
 #
-# Do this separately for now
+# Little bit of lo-fi mangling to get at the right set of settings depending
+# on whether we're generating the VERSIONINFO for a DLL or EXE
 # 
-binary-pack::
-       ( cd $(BIN_DIST_TMPDIR); $(TAR) chzf $(BIN_DIST_NAME).tar.gz $(BIN_DIST_NAME); rm -rf $(BIN_DIST_NAME) )
+DLL_OR_EXE=$(subst VersionInfo.$(way_)rc,,$@)
+VERSION_FT=$(subst Dll, 0x2L, $(subst Exe, 0x1L, $(DLL_OR_EXE)))
+VERSION_RES_NAME=$(subst Exe,$(EXE_VERSION_NAME), $(subst Dll, $(DLL_VERSION_NAME),$(DLL_OR_EXE)))
+VERSION_RES=$(subst Exe,$(EXE_VERSION), $(subst Dll, $(DLL_VERSION),$(DLL_OR_EXE)))
+VERSION_DESC=$(subst Exe,$(EXE_DESCRIPTION), $(subst Dll, $(DLL_DESCRIPTION),$(DLL_OR_EXE)))
 
-ifneq "$(way)" ""
-package-way-dist::
-       ( cd $(BIN_DIST_TMPDIR); find $(BIN_DIST_NAME)/ \( -name "*$(_way).a" -o -name "*.$(way_)hi" \) -print | xargs tar cvf $(BIN_DIST_TMPDIR)/ghc-$(ProjectVersion)-$(way)-$(TARGETPLATFORM).tar )
-       gzip $(BIN_DIST_TMPDIR)/ghc-$(ProjectVersion)-$(way)-$(TARGETPLATFORM).tar
-endif
+DllVersionInfo.$(way_)rc ExeVersionInfo.$(way_)rc:
+       $(RM) DllVersionInfo.$(way_)rc
+       echo "1 VERSIONINFO"                > $@
+       echo "FILEVERSION 1,0,0,1"         >> $@
+       echo "PRODUCTVERSION 1,0,0,1"      >> $@
+       echo "FILEFLAGSMASK 0x3fL"         >> $@
+       echo "FILEOS 0x4L"                 >> $@
+       echo "FILETYPE $(VERSION_FT)"      >> $@
+       echo "FILESUBTYPE 0x0L"            >> $@
+       echo "BEGIN"                       >> $@
+       echo " BLOCK \"StringFileInfo\""   >> $@
+       echo " BEGIN"                      >> $@
+       echo "  BLOCK \"040904B0\""        >> $@
+       echo "  BEGIN"                     >> $@
+       echo "   VALUE \"CompanyName\", \"$(VERSION_RES_NAME)\\0\"" >> $@
+       echo "   VALUE \"FileVersion\", \"$(VERSION_RES)\\0\"" >> $@
+       echo "   VALUE \"ProductVersion\", \"$(VERSION_RES)\\0\"" >> $@
+       echo "   VALUE \"FileDescription\", \"$(VERSION_DESC)\\0\"" >> $@
+       echo "  END" >> $@
+       echo " END" >> $@
+       echo " BLOCK \"VarFileInfo\""  >> $@
+       echo " BEGIN" >> $@
+       echo "  VALUE \"Translation\", 0x0409, 1200" >> $@
+       echo " END" >> $@
+       echo "END" >> $@
+else
+# Regular static library
+$(LIBRARY): $(LIBOBJS)
+       $(BUILD_STATIC_LIB)
+endif # %.dll
+endif # %.dylib
+endif # %.so
+endif # LIBRARY = ""
 
-ifneq "$(way)" ""
-remove-way-dist::
-       ( cd $(BIN_DIST_TMPDIR); find $(BIN_DIST_NAME)/ \( -name "*$(_way).a" -o -name "*.$(way_)hi" \) -print -exec rm -f {} \; )
-endif
+include $(TOP)/mk/install.mk
 
-###########################################
+##############################################################################
 #
-#      Targets: check tags show info
+#      Targets: check tags show
 #
-###########################################
+##############################################################################
 
 #------------------------------------------------------------
 #                      Check
@@ -787,165 +487,101 @@ check:: $(TESTS)
 #------------------------------------------------------------
 #                      Tags
 
-.PHONY: TAGS
+.PHONY: TAGS tags
 
-TAGS:: $(SOURCES)
+tags TAGS:: $(TAGS_HS_SRCS) $(TAGS_C_SRCS)
        @$(RM) TAGS
        @touch TAGS
-ifneq "$(HS_SRCS)" ""
-       $(HSTAGS) $(HSTAGS_OPTS) -- $(TAGS_HS_SRCS)
+ifneq "$(TAGS_HS_SRCS)" ""
+       $(HSTAGS) $(HSTAGS_OPTS) $(TAGS_HS_SRCS)
 endif
-ifneq "$(C_SRCS)" ""
+ifneq "$(TAGS_C_SRCS)" ""
        etags -a $(TAGS_C_SRCS)
 endif
-       @( DEREFFED=`ls -l Makefile | sed -e 's/.*-> \(.*\)/\1/g'` && $(RM) `dirname $$DEREFFED`/TAGS && $(CP) TAGS `dirname $$DEREFFED` ) || echo TAGS file generated, perhaps copy over to source tree?
+       @( DEREFFED=`ls -l Makefile | sed -e 's/.*-> \(.*\)/\1/g'` && $(RM) `dirname $$DEREFFED`/TAGS && $(CP) TAGS `dirname $$DEREFFED` ) 2>/dev/null || echo TAGS file generated, perhaps copy over to source tree?
 
-#------------------------------------------------------------
-#                      Makefile debugging
-# to see the effective value used for a Makefile variable, do
-#  make show VALUE=MY_VALUE
+################################################################################
 #
+#                      DocBook XML Documentation
+#
+################################################################################
 
-show:
-       @echo '$(VALUE)=$($(VALUE))'
+.PHONY: html html-no-chunks chm HxS fo dvi ps pdf
 
-#------------------------------------------------------------
-#                      Documentation
+ifneq "$(XML_DOC)" ""
 
-.PHONY: dvi ps html info txt
+all :: $(XMLDocWays)
 
-info:: $(DOC_INFO)
-dvi:: $(DOC_DVI)
-ps::  $(DOC_PS)
-html:: $(DOC_HTML)
-texi:: $(DOC_TEXI)
-txt:: $(DOC_TEXT)
+# multi-file XML document: main document name is specified in $(XML_DOC),
+# sub-documents (.xml files) listed in $(XML_SRCS).
 
-#
-# Building literate root documents requires extra treatment,
-# as the root files need to be processed different from other
-# literate files (`compile' them into .itex with the -S (standalone)
-# option) and then link together a master TeX document with
-# a -S option.
-#
-$(filter %.tex,$(patsubst %.lit,%.tex,$(DOC_SRCS))) :
-       @$(RM) $@
-       $(LIT2LATEX) -S -c $(LIT2LATEX_OPTS) -o $(patsubst %.tex,%.itex,$@) $(addsuffix .lit,$(basename $@))
-       $(LIT2LATEX) -S $(LIT2LATEX_OPTS) -o $@ $(addsuffix .itex,$(basename $@))
-       @chmod 444 $@
-#
-# Ditto for texi and html
-#
-$(filter %.texi,$(patsubst %.lit,%.texi,$(DOC_SRCS))) :
-       @$(RM) $@
-       $(LIT2TEXI) -S -c $(LIT2TEXI_OPTS) -o $(patsubst %.texi,%.itxi,$@) $(addsuffix .lit,$(basename $@))
-       $(LIT2TEXI) -S $(LIT2TEXI_OPTS) -o $@ $(addsuffix .itxi,$(basename $@))
-       @chmod 444 $@
-#
-# Rather than using lit2html, we opt for the lit-texi-html route,
-# and use texi2html as our HTML backend.
-# (Note: we need to change mkdependlit to get this really off the ground)
-#
-# If the generated html representation is split up into a myriad of files,
-# put the files in a subdirectory html/, if a monolith is created, park
-# the generated file in the same dir as the .lit file.
-#
-$(filter %.html,$(patsubst %.lit,%.html,$(DOC_SRCS))) : $(filter %.lit,$(DOC_SRCS))
-       $(RM) $@ $(patsubst %.html,%.texi,$@) $(patsubst %.html,%.itxi,$@)
-ifneq "$(filter -monolithic,$(TEXI2HTML_OPTS))" ""
-       $(LIT2TEXI) -S -c $(LIT2TEXI_OPTS) -o $(patsubst %.html,%.itxi,$@) $(addsuffix .lit,$(basename $@))
-       $(LIT2TEXI) -S $(LIT2TEXI_OPTS) -o $(patsubst %.html,%.texi,$@) $(addsuffix .itxi,$(basename $@))
-       $(TEXI2HTML) $(TEXI2HTML_OPTS) $(patsubst %.html,%.texi,$@)
-       cp $(TEXI2HTML_PREFIX)invisible.xbm .
-else
-       $(RM) html/$(basename $@)*
-       $(MKDIRHIER) html
-       $(LIT2TEXI) -S -c $(LIT2TEXI_OPTS) -o $(patsubst %.html,%.itxi,$@) $(addsuffix .lit,$(basename $@))
-       $(LIT2TEXI) -S $(LIT2TEXI_OPTS) -o html/$(patsubst %.html,%.texi,$@) $(addsuffix .itxi,$(basename $@))
-       (cd html; ../$(TEXI2HTML) $(TEXI2HTML_OPTS) $(patsubst %.html,%.texi,$@); cd ..)
-       cp $(TEXI2HTML_PREFIX)invisible.xbm html/
-       @touch $@
+ifeq "$(XML_SRCS)" ""
+XML_SRCS = $(wildcard *.xml)
 endif
 
-#--------------------------------------------------------------------------
-# SGML Documentation
-#
-# This will eventually replace the literate stuff for documentation
+XML_HTML           = $(addsuffix /index.html,$(basename $(XML_DOC)))
+XML_HTML_NO_CHUNKS = $(addsuffix .html,$(XML_DOC))
+XML_CHM            = $(addsuffix .chm,$(XML_DOC))
+XML_HxS            = $(addsuffix .HxS,$(XML_DOC))
+XML_FO             = $(addsuffix .fo,$(XML_DOC))
+XML_DVI            = $(addsuffix .dvi,$(XML_DOC))
+XML_PS             = $(addsuffix .ps,$(XML_DOC))
+XML_PDF            = $(addsuffix .pdf,$(XML_DOC))
 
-SGML_SRCS = $(wildcard    *.sgml *.vsgml)
-SGML_DVI  = $(addsuffix  .dvi, $(basename $(SGML_SRCS)))
-SGML_PS   = $(addsuffix   .ps, $(basename $(SGML_SRCS)))
-SGML_TEXI = $(addsuffix .texi, $(basename $(SGML_SRCS)))
-SGML_INFO = $(addsuffix .info, $(basename $(SGML_SRCS)))
-SGML_HTML = $(addsuffix .html, $(basename $(SGML_SRCS)))
-SGML_TEXT = $(addsuffix  .txt, $(basename $(SGML_SRCS)))
+$(XML_HTML) $(XML_NO_CHUNKS_HTML) $(XML_FO) $(XML_DVI) $(XML_PS) $(XML_PDF) :: $(XML_SRCS)
 
-dvi  :: $(SGML_DVI)
-info :: $(SGML_INFO)
-html :: $(SGML_HTML)
-txt  :: $(SGML_TXT)
-ps   :: $(SGML_PS)
+html           :: $(XML_HTML)
+html-no-chunks :: $(XML_HTML_NO_CHUNKS)
+chm            :: $(XML_CHM)
+HxS            :: $(XML_HxS)
+fo             :: $(XML_FO)
+dvi            :: $(XML_DVI)
+ps             :: $(XML_PS)
+pdf            :: $(XML_PDF)
 
-CLEAN_FILES += $(SGML_TEXT) $(SGML_HTML) $(SGML_TEXI) $(SGML_PS) $(SGML_DVI)
+CLEAN_FILES += $(XML_HTML_NO_CHUNKS) $(XML_FO) $(XML_DVI) $(XML_PS) $(XML_PDF)
 
-# suffix rules should handle the rest (for single-file docs at least).
+extraclean ::
+       $(RM) -rf $(XML_DOC).out $(FPTOOLS_CSS) $(basename $(XML_DOC)) $(basename $(XML_DOC))-htmlhelp
 
-###########################################
+validate ::
+       $(XMLLINT) --valid --noout $(XMLLINT_OPTS) $(XML_DOC).xml
+endif
+
+##############################################################################
 #
 #      Targets: clean
 #
-###########################################
+##############################################################################
 
-.PHONY: realclean mostlyclean clean distclean maintainer-clean
+# we have to be careful about recursion here; since all the clean
+# targets are recursive, we don't want to make eg. distclean depend on
+# clean because that would result in far too many recursive calls.
 
-# realclean is just a synonym for maintainer-clean
-realclean: maintainer-clean
+.PHONY: mostlyclean clean distclean maintainer-clean
 
-
-ifneq "$(MOSTLY_CLEAN_FILES)" ""
 mostlyclean::
        rm -f $(MOSTLY_CLEAN_FILES)
-endif
-
-ifneq "$(CLEAN_FILES)" ""
-clean:: mostlyclean
-       rm -f $(CLEAN_FILES)
-endif
 
+# extraclean is used for adding actions to the clean target.
+extraclean::
 
-ifneq "$(DIST_CLEAN_FILES)" ""
-distclean:: mostlyclean clean
-       rm -f $(DIST_CLEAN_FILES)
-endif
+clean:: extraclean
+       rm -f $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES)
 
+distclean:: extraclean
+       rm -f $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES) $(DIST_CLEAN_FILES)
 
-ifneq "$(MAINTAINER_CLEAN_FILES)" ""
-maintainer-clean:: mostlyclean clean distclean
+maintainer-clean:: extraclean
        @echo 'This command is intended for maintainers to use; it'
        @echo 'deletes files that may need special tools to rebuild.'
-       rm -f $(MAINTAINER_CLEAN_FILES)
-endif
-
-#
-# If (Haskell) object files are split, cleaning up 
-# consist of descending into the directories where
-# the myriads of object files have been put.
-#
+       rm -f $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES) $(DIST_CLEAN_FILES) $(MAINTAINER_CLEAN_FILES)
 
-ifneq "$(HS_OBJS)" ""
-ifneq "$(filter -split-objs,$(HC_OPTS))" ""
-clean ::
-       find $(patsubst %.$(way_)o,%,$(HS_OBJS)) -name '*.$(way_)o' -print | xargs $(RM) __rm_food
-       -rmdir $(patsubst %.$(way_)o,%,$(HS_OBJS))
-endif
-endif
-
-
-#################################################################################
+################################################################################
 #
 #                      Way management
 #
-#################################################################################
+################################################################################
 
 # Here is the ingenious jiggery pokery that allows you to build multiple versions
 # of a program in a single build tree.
@@ -955,6 +591,11 @@ endif
 # Expects:     $(WAYS)                 the possible "way" strings to one of 
 #                                      which $(way) will be set
 
+ifneq "$(way)" ""
+ifeq "$(findstring $(way), $(WAYS))" ""
+$(error Unknown way $(way) of $(WAYS))
+endif
+endif
 
 # So how does $(way) ever get set to anything?  Answer, we recursively
 # invoke make, setting $(way) on the command line.
@@ -980,7 +621,8 @@ ifeq "$(way)" ""
 FPTOOLS_SUFFIXES := o hi hc
 
 WAY_TARGETS     = $(foreach way,$(WAYS),$(foreach suffix, $(FPTOOLS_SUFFIXES), %.$(way)_$(suffix)))
-LIB_WAY_TARGETS = $(foreach way,$(WAYS),%_$(way).a %_$(way))
+LIB_WAY_TARGETS = $(foreach way,$(filter-out %dyn,$(WAYS)), %_$(way).a)
+LIB_WAY_TARGETS_DYN =  $(foreach way,$(filter %dyn,$(WAYS)), %$(subst dyn,-ghc$(ProjectVersion),$(subst _dyn,dyn,$(way)))$(soext))
 
 # $@ will be something like Foo.p_o
 # $(suffix $@)     returns .p_o
@@ -998,108 +640,62 @@ $(WAY_TARGETS) :
 $(LIB_WAY_TARGETS) :
        $(MAKE) $(MFLAGS) $@ way=$(subst .,,$(suffix $(subst _,.,$(basename $@))))
 
-endif  # if way
-
-
-##################################################################
-#
-#              Recursive stuff
-#
-##################################################################
+$(LIB_WAY_TARGETS_DYN) :
+       $(MAKE) $(MFLAGS) $@ way=$(patsubst _dyn,dyn,$(subst .,,$(suffix $(subst _,.,$(basename $(subst -ghc$(ProjectVersion),,$@)))))_dyn)
 
-# Here are the diabolically clever rules that
-# 
-# (a) for each "recursive target" <t>
-#     propagates "make <t>" to directories in SUBDIRS
-#
-# (b) when SUBDIRS is empty,
-#     for each "multi-way-target" <t>
-#     calls "make -way=w <t>" for each w in $(WAYS)
-#
-#     This has the effect of making the standard target
-#     in each of the specified ways (as well as in the normal way
-
-# Controlling variables
-#      WAYS    = extra (beyond the normal way) ways to build things in
-#      SUBDIRS = subdirectories to recurse into
-
-# No ways, so iterate over the SUBDIRS
-
-# note about recursively invoking make: we'd like make to drop all the
-# way back to the top level if it fails in any of the
-# sub(sub-...)directories.  This is done by setting the -e flag to the
-# shell during the loop, which causes an immediate failure if any of
-# the shell commands fail.
-
-# One exception: if the user gave the -i or -k flag to make in the
-# first place, we'd like to reverse this behaviour.  So we check for
-# these flags, and set the -e flag appropriately.  NOTE: watch out for
-# the --no-print-directory flag which is passed to recursive
-# invocations of make.
+endif  # if way
 
-ifeq "$(way)" ""
-ifneq "$(SUBDIRS)" ""
+# -------------------------------------------------------------------------
+# Object and interface files have suffixes tagged with their ways
 
-all docs runtests boot TAGS clean veryclean maintainer-clean install info ::
-       @echo "------------------------------------------------------------------------"
-       @echo "===fptools== Recursively making \`$@' in $(SUBDIRS) ..."
-       @echo "PWD = $(shell pwd)"
-       @echo "------------------------------------------------------------------------"
-       @case '${MFLAGS}' in *-[ik]*) set +e;; *-r*[ik]*) set +e;; *) set -e;; esac; \
-       for i in $(SUBDIRS) ; do \
-         echo "------------------------------------------------------------------------"; \
-         echo "==fptools== $(MAKE) $@ $(MFLAGS);"; \
-         echo " in $(shell pwd)/$$i"; \
-         echo "------------------------------------------------------------------------"; \
-         $(MAKE) --no-print-directory -C $$i $(MFLAGS) $@; \
-       done
-       @echo "------------------------------------------------------------------------"
-       @echo "===fptools== Finished making \`$@' in $(SUBDIRS) ..."
-       @echo "PWD = $(shell pwd)"
-       @echo "------------------------------------------------------------------------"
-
-dist ::
-       @case '${MFLAGS}' in *-[ik]*) set +e;; *-r*[ik]*) set +e;; *) set -e;; esac; \
-       for i in $(SUBDIRS) ; do \
-         $(MKDIRHIER_PREFIX)mkdirhier $(SRC_DIST_DIR)/$$i; \
-         $(MAKE) -C $$i $(MFLAGS) $@ SRC_DIST_DIR=$(SRC_DIST_DIR)/$$i; \
-       done
-endif
+ifneq "$(way)" ""
+SRC_HC_OPTS += -hisuf $(way_)hi -hcsuf $(way_)hc -osuf $(way_)o
 endif
 
-#
-# Selectively building subdirectories.
-#
-#
-ifneq "$(SUBDIRS)" ""
-$(SUBDIRS) ::
-         $(MAKE) -C $@ $(MFLAGS)
-endif
+# -------------------------------------------------------------------------
+# Rules to invoke the current target recursively for each way
 
-ifneq "$(WAYS)" ""
+ifneq "$(strip $(WAYS))" ""
 ifeq "$(way)" ""
 
 # NB: the targets exclude 
-#      boot info TAGS
+#      boot runtests
 # since these are way-independent
-all docs runtests TAGS clean veryclean maintainer-clean install ::
+all docs TAGS clean distclean mostlyclean maintainer-clean install ::
        @echo "------------------------------------------------------------------------"
-       @echo "===fptools== Recursively making \`$@' for ways: $(WAYS) ..."
+       @echo "== Recursively making \`$@' for ways: $(WAYS) ..."
        @echo "PWD = $(shell pwd)"
        @echo "------------------------------------------------------------------------"
-       @case '${MFLAGS}' in *-[ik]*) set +e;; *-r*[ik]*) set +e;; *) set -e;; esac; \
+# Don't rely on -e working, instead we check exit return codes from sub-makes.
+       case '${MFLAGS}' in *-[ik]*) x_on_err=0;; *-r*[ik]*) x_on_err=0;; *) x_on_err=1;; esac; \
        for i in $(WAYS) ; do \
          echo "------------------------------------------------------------------------"; \
-         echo "==fptools== $(MAKE) way=$$i $@;"; \
+         echo "== $(MAKE) way=$$i $@;"; \
          echo "PWD = $(shell pwd)"; \
          echo "------------------------------------------------------------------------"; \
          $(MAKE) way=$$i --no-print-directory $(MFLAGS) $@ ; \
+         if [ $$? -eq 0 ] ; then true; else exit $$x_on_err; fi; \
        done
        @echo "------------------------------------------------------------------------"
-       @echo "===fptools== Finished recursively making \`$@' for ways: $(WAYS) ..."
+       @echo "== Finished recursively making \`$@' for ways: $(WAYS) ..."
        @echo "PWD = $(shell pwd)"
        @echo "------------------------------------------------------------------------"
 
 endif
 endif
 
+include $(TOP)/mk/recurse.mk
+
+# -----------------------------------------------------------------------------
+# Further cleaning
+
+# Sometimes we want to clean things only after the recursve cleaning
+# has heppened (eg. if the files we're about to remove would affect
+# the recursive traversal).
+
+distclean::
+       rm -f $(LATE_DIST_CLEAN_FILES)
+
+maintainer-clean::
+       rm -f $(LATE_DIST_CLEAN_FILES)
+