summaryrefslogtreecommitdiff
path: root/rules
diff options
context:
space:
mode:
Diffstat (limited to 'rules')
-rw-r--r--rules/all-target.mk7
-rw-r--r--rules/bindist.mk16
-rw-r--r--rules/build-dependencies.mk48
-rw-r--r--rules/build-package-data.mk16
-rw-r--r--rules/build-package-way.mk52
-rw-r--r--rules/build-package.mk135
-rw-r--r--rules/build-perl.mk45
-rw-r--r--rules/build-prog.mk139
-rw-r--r--rules/c-objs.mk5
-rw-r--r--rules/c-sources.mk4
-rw-r--r--rules/c-suffix-rules.mk60
-rw-r--r--rules/clean-target.mk9
-rw-r--r--rules/distdir-opts.mk60
-rw-r--r--rules/distdir-way-opts.mk78
-rw-r--r--rules/docbook.mk24
-rw-r--r--rules/haddock.mk27
-rw-r--r--rules/hi-rule.mk25
-rw-r--r--rules/hs-objs.mk5
-rw-r--r--rules/hs-sources.mk46
-rw-r--r--rules/hs-suffix-rules-srcdir.mk70
-rw-r--r--rules/hs-suffix-rules.mk17
-rw-r--r--rules/includes-sources.mk14
-rw-r--r--rules/manual-package-config.mk33
-rw-r--r--rules/package-config.mk41
-rw-r--r--rules/shell-wrapper.mk63
-rw-r--r--rules/way-prelims.mk13
26 files changed, 1052 insertions, 0 deletions
diff --git a/rules/all-target.mk b/rules/all-target.mk
new file mode 100644
index 0000000000..976ff1debe
--- /dev/null
+++ b/rules/all-target.mk
@@ -0,0 +1,7 @@
+
+define all-target # args: $1 = dir, $2 = deps
+all : all_$1
+.PHONY: all_$1
+all_$1 : $2
+endef
+
diff --git a/rules/bindist.mk b/rules/bindist.mk
new file mode 100644
index 0000000000..b9e093c56e
--- /dev/null
+++ b/rules/bindist.mk
@@ -0,0 +1,16 @@
+
+# Add files to the bindist. Invoke like this:
+#
+# $(eval $(call bindist,utils/genapply,ghc.mk))
+
+define bindist
+# $1 = dir
+# $2 = files
+
+.PHONY: bindist_$1
+bindist: bindist_$1
+
+bindist_$1:
+ for f in $$(addprefix $1/,$2); do echo $(BIN_DIST_NAME)/$$$$f >> $(BIN_DIST_LIST); done
+endef
+
diff --git a/rules/build-dependencies.mk b/rules/build-dependencies.mk
new file mode 100644
index 0000000000..860a2f6ff3
--- /dev/null
+++ b/rules/build-dependencies.mk
@@ -0,0 +1,48 @@
+
+define build-dependencies # args: $1 = dir, $2 = distdir
+
+ifeq "$$($1_$2_ghc_ge_609)" "YES"
+$1_$2_MKDEPENDHS_FLAGS = -include-pkg-deps -dep-makefile $$($1_$2_depfile) $$(foreach way,$$(filter-out v,$$($1_$2_WAYS)),-dep-suffix $$(way))
+else
+$1_$2_MKDEPENDHS_FLAGS = -optdep--include-pkg-deps -optdep-f -optdep$$($1_$2_depfile) $$(foreach way,$$(filter-out v,$$($1_$2_WAYS)),-optdep-s -optdep$$(way))
+endif
+
+ifneq "$$($1_$2_NO_BUILD_DEPS)" "YES"
+
+$$($1_$2_depfile) : $$(MKDIRHIER) $$(MKDEPENDC) $$($1_$2_HS_SRCS) $$($1_$2_HS_BOOT_SRCS) $$($1_$2_HC_MK_DEPEND_DEP) $$($1_$2_C_FILES) $$($1_$2_S_FILES)
+ $$(MKDIRHIER) $1/$2/build
+ $(RM) $$@ $$@.tmp
+ touch $$@.tmp
+ifneq "$$($1_$2_C_SRCS)$$($1_$2_S_SRCS)" ""
+ $$(MKDEPENDC) -f $$($1_$2_depfile).tmp $$($1_MKDEPENDC_OPTS) $$(foreach way,$$($1_WAYS),-s $$(way)) -- $$($1_$2_v_ALL_CC_OPTS) -- $$($1_$2_C_FILES) $$($1_$2_S_FILES) || ( $$(RM) $$@; exit 1 )
+ sed -e "s|$1/\([^ :]*o[ :]\)|$1/$2/build/\1|g" -e "s|$(TOP)/||" <$$($1_$2_depfile).tmp >$$($1_$2_depfile)
+endif
+ifneq "$$($1_$2_HS_SRCS)" ""
+ $$($1_$2_HC_MK_DEPEND) -M $$($1_$2_MKDEPENDHS_FLAGS) \
+ $$(filter-out -split-objs, $$($1_$2_v_ALL_HC_OPTS)) \
+ $$($1_$2_HS_SRCS) || ( $$(RM) $$@; exit 1 )
+endif
+ echo "$1_$2_depfile_EXISTS = YES" >> $$@
+ifneq "$$($1_$2_SLASH_MODS)" ""
+ for dir in $$(sort $$(foreach mod,$$($1_$2_SLASH_MODS),$1/$2/build/$$(dir $$(mod)))); do \
+ if test ! -d $$$$dir; then mkdir -p $$$$dir; fi \
+ done
+endif
+
+endif # $1_$2_NO_BUILD_DEPS
+
+# Note sed magic above: mkdependC can't do -odir stuff, so we have to
+# munge the dependencies it generates to refer to the correct targets.
+
+# Seems as good a place as any to attach the unlit dependency
+$$($1_$2_depfile) : $$(UNLIT)
+
+ifneq "$$(NO_INCLUDE_DEPS)" "YES"
+include $$($1_$2_depfile)
+else
+ifeq "$$(DEBUG)" "YES"
+$$(warning not building dependencies in $1)
+endif
+endif
+
+endef
diff --git a/rules/build-package-data.mk b/rules/build-package-data.mk
new file mode 100644
index 0000000000..206a6591f9
--- /dev/null
+++ b/rules/build-package-data.mk
@@ -0,0 +1,16 @@
+define build-package-data # args: $1 = dir, $2 = distdir
+
+ifeq "$(HSCOLOUR_SRCS)" "YES"
+$1_$2_CONFIGURE_FLAGS += --with-hscolour="$$(HSCOLOUR)"
+endif
+
+# This rule configures the package, generates the package-data.mk file
+# for our build system, and registers the package for use in-place in
+# the build tree.
+$1/$2/package-data.mk $1/$2/inplace-pkg-config $1/$2/build/autogen/cabal_macros.h : $$(GHC_CABAL_INPLACE) $$($1_$2_GHC_PKG_DEP) $1/$$($1_PACKAGE).cabal $$(wildcard $1/configure) $$($1_$2_HC_CONFIG_DEP)
+ $$(GHC_CABAL_INPLACE) configure --with-ghc=$$($1_$2_HC_CONFIG) --with-ghc-pkg=$$($1_$2_GHC_PKG) --with-gcc=$$(WhatGccIsCalled) --configure-option=--with-cc=$$(WhatGccIsCalled) $$($1_$2_CONFIGURE_FLAGS) $$($1_CONFIGURE_OPTS) $$($1_$2_CONFIGURE_OPTS) -- $2 $1
+ if [ "$$($1_$2_PROG)" = "" ]; then \
+ $$($1_$2_GHC_PKG) update --force $$($1_$2_GHC_PKG_OPTS) $1/$2/inplace-pkg-config; \
+ fi
+
+endef
diff --git a/rules/build-package-way.mk b/rules/build-package-way.mk
new file mode 100644
index 0000000000..086c231b43
--- /dev/null
+++ b/rules/build-package-way.mk
@@ -0,0 +1,52 @@
+
+define build-package-way # $1 = dir, $2 = distdir, $3 = way, $4 = stage
+
+$(call distdir-way-opts,$1,$2,$3)
+$(call hs-suffix-rules,$1,$2,$3)
+$$(foreach dir,$$($1_$2_HS_SRC_DIRS),\
+ $$(eval $$(call hs-suffix-rules-srcdir,$1,$2,$3,$$(dir))))
+
+$(call hs-objs,$1,$2,$3)
+
+$1_$2_$3_LIB = $1/$2/build/libHS$$($1_PACKAGE)-$$($1_$2_VERSION)$$($3__way).a
+
+$1_$2_$3_MKSTUBOBJS = find $1/$2/build -name "*_stub.$$($3_osuf)" -print
+# HACK ^^^ we tried to use $(wildcard), but apparently it fails due to
+# make using cached directory contents, or something.
+
+# Build the ordinary .a library
+ifeq "$$($1_$2_SplitObjs)" "YES"
+$$($1_$2_$3_LIB) : $$($1_$2_$3_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS)
+ $$(RM) $$@
+ (echo $$($1_$2_C_OBJS) $$($1_$2_S_OBJS) `$$($1_$2_$3_MKSTUBOBJS)`; find $$(patsubst %.$$($3_osuf),%_split,$$($1_$2_$3_HS_OBJS)) -name '*.$$($3_osuf)' -print) | xargs $$(AR) $$(EXTRA_AR_ARGS) $$@
+else
+$$($1_$2_$3_LIB) : $$($1_$2_$3_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS)
+ $$(RM) $$@
+ echo $$($1_$2_C_OBJS) $$($1_$2_S_OBJS) $$($1_$2_$3_HS_OBJS) `$$($1_$2_$3_MKSTUBOBJS)` | xargs $$(AR) $$(EXTRA_AR_ARGS) $$@
+endif
+
+$(call all-target,$1_$2,all_$1_$2_$3)
+$(call all-target,$1_$2_$3,$$($1_$2_$3_LIB))
+
+# Don't put bootstrapping packages in the bindist
+ifneq "$4" "0"
+BINDIST_HI += $$($1_$2_$3_HI)
+BINDIST_LIBS += $$($1_$2_$3_LIB)
+endif
+
+# Build the GHCi library
+ifeq "$3" "v"
+$1_$2_GHCI_LIB = $1/$2/build/HS$$($1_PACKAGE)-$$($1_$2_VERSION).$$($3_osuf)
+# Don't put bootstrapping packages in the bindist
+ifneq "$4" "0"
+BINDIST_LIBS += $$($1_$2_GHCI_LIB)
+endif
+$$($1_$2_GHCI_LIB) : $$($1_$2_$3_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS)
+ $$(RM) $$@
+ $$(LD) -r -o $$@ $$(EXTRA_LD_OPTS) $$($1_$2_$3_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS) `$$($1_$2_$3_MKSTUBOBJS)`
+
+$(call all-target,$1_$2,$$($1_$2_GHCI_LIB))
+endif
+
+endef
+
diff --git a/rules/build-package.mk b/rules/build-package.mk
new file mode 100644
index 0000000000..4ca3c6e66f
--- /dev/null
+++ b/rules/build-package.mk
@@ -0,0 +1,135 @@
+
+# Build a package with the stage-1 compiler, multiple ways. A typical
+# libraries/foo/ghc.mk will look like this:
+#
+# $(eval $(call build-package,libraries/base,dist-install))
+#
+# The package metadata is generated from the .cabal file and placed in
+# package-data.mk. It will look something like this:
+#
+# libraries/base_dist_MODULES = GHC.Base Data.Tuple ...
+# libraries/base_dist_PACKAGE = base
+# libraries/base_dist_VERSION = 4.0.0.0
+# libraries/base_dist_HC_OPTS = -package ghc-prim-0.1.0.0 -XRank2Types ...
+# libraries/base_dist_C_SRCS = cbits/PrelIOUtils.c ...
+# libraries/base_dist_S_SRCS = cbits/foo.S ...
+# libraries/base_dist_CC_OPTS = -Iinclude ...
+# libraries/base_dist_LD_OPTS = -package ghc-prim-0.1.0.0
+
+# TODO: soext
+
+define build-package
+# $1 = dir
+# $2 = distdir
+# $3 = GHC stage to use (0 == bootstrapping compiler)
+
+ifeq "$$(findstring $3,0 1 2)" ""
+$$(error $1/$2: stage argument to build-package should be 0, 1, or 2)
+endif
+
+# We don't install things compiled by stage 0, so no need to put them
+# in the bindist.
+ifneq "$(BINDIST) $3" "YES 0"
+
+$(call all-target,$1,all_$1_$2)
+
+$(call clean-target,$1,$2,$1/$2)
+
+distclean : clean_$1_$2_config
+
+.PHONY: clean_$1_$2_config
+clean_$1_$2_config:
+ $(RM) $1/config.log $1/config.status $1/include/Hs*Config.h
+ $(RM) -r $1/autom4te.cache
+
+# --- CONFIGURATION
+
+$1_$2_USE_BOOT_LIBS = YES
+$(call package-config,$1,$2,$3)
+
+ifneq "$$(NO_INCLUDE_PKGDATA)" "YES"
+include $1/$2/package-data.mk
+endif
+
+ifeq "$$($1_$2_DISABLE)" "YES"
+
+ifeq "$$(DEBUG)" "YES"
+$$(warning $1/$2 disabled)
+endif
+
+# A package is disabled when we want to bring its package-data.mk file
+# up-to-date first, or due to other build dependencies.
+
+$(call all-target,$1_$2,$1/$2/package-data.mk)
+
+ifneq "$(BINDIST)" "YES"
+# We have a rule for package-data.mk only when the package is
+# disabled, because we want the build to fail if we haven't run phase 0.
+$(call build-package-data,$1,$2)
+endif
+
+else
+
+ifneq "$$(NO_INCLUDE_PKGDATA)" "YES"
+ifeq "$$($1_$2_VERSION)" ""
+$$(error phase ordering error: $1/$2 is enabled, but $1/$2/package-data.mk does not exist)
+endif
+endif
+
+# Sometimes we need to modify the automatically-generated package-data.mk
+# bindings in a special way for the GHC build system, so allow that here:
+$($1_PACKAGE_MAGIC)
+
+# Bootstrapping libs are only built one way
+ifeq "$3" "0"
+$1_$2_WAYS = v
+else
+$1_$2_WAYS = $$(GhcLibWays)
+endif
+
+$(call hs-sources,$1,$2)
+$(call c-sources,$1,$2)
+$(call includes-sources,$1,$2)
+
+# --- DEPENDENCIES
+
+# We must use a different dependency file if $(GhcLibWays) changes, so
+# encode the ways into the name of the file.
+$1_$2_WAYS_DASHED = $$(subst $$(space),,$$(patsubst %,-%,$$(strip $$($1_$2_WAYS))))
+$1_$2_depfile = $1/$2/build/.depend$$($1_$2_WAYS_DASHED)
+
+$(call build-dependencies,$1,$2)
+
+# --- BUILDING
+
+# We don't bother splitting the bootstrap packages (built with stage 0)
+ifeq "$$($1_$2_SplitObjs)" ""
+ifeq "$$(SplitObjs) $3" "YES 1"
+$1_$2_SplitObjs = YES
+else
+$1_$2_SplitObjs = NO
+endif
+endif
+
+# C and S files are built only once, not once per way
+$(call c-objs,$1,$2)
+$(call distdir-opts,$1,$2,$3)
+$(call c-suffix-rules,$1,$2,v,YES)
+
+# Now generate all the build rules for each way in this directory:
+$$(foreach way,$$($1_$2_WAYS),$$(eval $$(call build-package-way,$1,$2,$$(way),$3)))
+
+$(call haddock,$1,$2)
+
+endif # package-data.mk exists
+
+# Don't put bootstrapping packages in the bindist
+ifeq "$3" "1"
+BINDIST_EXTRAS += $1/*.cabal $1/$2/setup-config $1/LICENSE
+BINDIST_EXTRAS += $$($1_$2_INSTALL_INCLUDES_SRCS)
+endif
+
+endif
+
+endef
+
diff --git a/rules/build-perl.mk b/rules/build-perl.mk
new file mode 100644
index 0000000000..48694e460e
--- /dev/null
+++ b/rules/build-perl.mk
@@ -0,0 +1,45 @@
+
+# Build a perl script. Invoke like this:
+#
+# driver/mangler_PERL_SRC = ghc-asm.lprl
+# driver/mangler_dist_PROG = ghc-asm
+#
+# $(eval $(call build-perl,driver/mangler,dist))
+
+define build-perl
+# $1 = dir
+# $2 = distdir
+
+ifeq "$$($1_$2_LIBEXEC)" "YES"
+$1_$2_INPLACE = $(INPLACE_LIB)/$$($1_$2_PROG)
+else
+$1_$2_INPLACE = $(INPLACE_BIN)/$$($1_$2_PROG)
+endif
+
+$(call all-target,$$($1_$2_INPLACE))
+
+$(call clean-target,$1,$2,$1/$2 $$($1_$2_INPLACE))
+.PHONY: clean_$1
+clean_$1 : clean_$1_$2
+
+ifneq "$$(BINDIST)" "YES"
+$1/$2/$$($1_$2_PROG).prl: $1/$$($1_PERL_SRC) $$(UNLIT)
+ $$(MKDIRHIER) $1/$2
+ $$(RM) -f $$@
+ $$(UNLIT) $$(UNLIT_OPTS) $$< $$@
+
+$1/$2/$$($1_$2_PROG): $1/$2/$$($1_$2_PROG).prl
+ $$(RM) -f $$@
+ echo '#!$$(PERL)' >> $$@
+ echo '$$$$TARGETPLATFORM = "$$(TARGETPLATFORM)";' >> $$@
+ cat $$< >> $$@
+ $$(EXECUTABLE_FILE) $$@
+
+$$($1_$2_INPLACE): $1/$2/$$($1_$2_PROG)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(RM) -f $$@
+ $$(CP) $$< $$@
+ $$(EXECUTABLE_FILE) $$@
+endif
+
+endef
diff --git a/rules/build-prog.mk b/rules/build-prog.mk
new file mode 100644
index 0000000000..46dd5af273
--- /dev/null
+++ b/rules/build-prog.mk
@@ -0,0 +1,139 @@
+
+# Build a program with the stage-1 compiler. Invoke like this:
+#
+# utils/genapply_MODULES = Main
+# utils/genapply_HC_OPTS = -package Cabal
+# utils/genapply_dist_PROG = genapply
+#
+# $(eval $(call build-prog,utils/genapply,dist-install))
+
+define build-prog
+# $1 = dir
+# $2 = distdir
+# $3 = GHC stage to use (0 == bootstrapping compiler)
+
+ifeq "$$($1_$2_PROG)" ""
+$$(error $1_$2_PROG is not set)
+endif
+
+ifeq "$$(findstring $3,0 1 2)" ""
+$$(error $1/$2: stage argument to build-prog should be 0, 1, or 2)
+endif
+
+$(call all-target,$1,all_$1_$2)
+
+$(call clean-target,$1,$2,$1/$2)
+
+$(call package-config,$1,$2,$3)
+
+ifeq "$$($1_USES_CABAL)" "YES"
+ifneq "$$(NO_INCLUDE_PKGDATA)" "YES"
+include $1/$2/package-data.mk
+endif
+endif
+
+ifeq "$$($1_USES_CABAL)$$($1_$2_VERSION)" "YES"
+$1_$2_DISABLE = YES
+endif
+
+ifeq "$$($1_$2_DISABLE)" "YES"
+
+ifeq "$$(DEBUG)" "YES"
+$$(warning $1/$2 disabled)
+endif
+
+# The following code to build the package all depends on settings
+# obtained from package-data.mk. If we don't have package-data.mk
+# yet, then don't try to do anything else with this package. Make will
+# try to build package-data.mk, then restart itself and we'll be in business.
+
+$(call all-target,$1_$2,$1/$2/package-data.mk)
+
+# We have a rule for package-data.mk only when the package is
+# disabled, because we want the build to fail if we haven't run phase 0.
+ifneq "$(BINDIST)" "YES"
+$(call build-package-data,$1,$2)
+endif
+
+else
+
+ifneq "$(BINDIST)" "YES"
+$(call hs-sources,$1,$2)
+$(call c-sources,$1,$2)
+
+# --- DEPENDENCIES
+
+$1_$2_depfile = $1/$2/build/.depend
+
+$(call build-dependencies,$1,$2)
+
+# --- IMPLICIT RULES
+
+$(call distdir-opts,$1,$2,$3)
+
+# Just the 'v' way for programs
+$(call distdir-way-opts,$1,$2,v)
+
+$(call c-suffix-rules,$1,$2,v,YES)
+
+$(call hs-suffix-rules,$1,$2,v)
+$$(foreach dir,$$($1_$2_HS_SRC_DIRS),\
+ $$(eval $$(call hs-suffix-rules-srcdir,$1,$2,v,$$(dir))))
+
+$(call c-objs,$1,$2)
+$(call hs-objs,$1,$2,v)
+
+$1/$2/build/tmp/$$($1_$2_PROG) : $$($1_$2_v_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS) $$($1_$2_OTHER_OBJS)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$($1_$2_HC) -o $$@ $$($1_$2_v_ALL_HC_OPTS) $$(LD_OPTS) $$($1_$2_v_HS_OBJS) $$($1_$2_C_OBJS) $$($1_$2_S_OBJS) $$($1_$2_OTHER_OBJS)
+
+# Note [lib-depends] if this program is built with stage1 or greater, we
+# need to depend on the libraries too. NB. since $(ALL_LIBS) and
+# $(ALL_RTS_LIBS) are not defined until after libraries/*/ghc.mk have
+# been included, this introduces an ordering dependency.
+ifneq "$3" "0"
+ifeq "$$(ALL_LIBS)" ""
+$$(error ordering failure in $1: $$(ALL_LIBS) is empty)
+endif
+$1/$2/build/tmp/$($1_$2_PROG) : $$(ALL_LIBS) $$(ALL_RTS_LIBS) $$(OTHER_LIBS)
+endif
+endif
+
+ifeq "$$($1_$2_INSTALL_INPLACE)" "NO"
+$(call all-target,$1_$2,$1/$2/build/tmp/$$($1_$2_PROG))
+else
+# Where do we install the inplace version?
+ifeq "$$($1_$2_SHELL_WRAPPER) $$(Windows)" "YES NO"
+$1_$2_INPLACE = $$(INPLACE_LIB)/$$($1_$2_PROG)
+else
+ifeq "$$($1_$2_LIBEXEC)" "YES"
+$1_$2_INPLACE = $$(INPLACE_LIB)/$$($1_$2_PROG)
+else
+$1_$2_INPLACE = $$(INPLACE_BIN)/$$($1_$2_PROG)
+endif
+endif
+
+$(call all-target,$1_$2,$$($1_$2_INPLACE))
+$(call clean-target,$1,$2_inplace,$$($1_$2_INPLACE))
+
+$$($1_$2_INPLACE) : $1/$2/build/tmp/$$($1_$2_PROG) $$(MKDIRHIER)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(CP) -p $$< $$@
+ touch $$@
+
+# touch is necessary; cp doesn't update the file time.
+endif
+
+$(call shell-wrapper,$1,$2)
+
+ifeq "$$($1_$2_INSTALL)" "YES"
+ifeq "$$($1_$2_LIBEXEC)" "YES"
+INSTALL_LIBEXECS += $1/$2/build/tmp/$$($1_$2_PROG)
+else
+INSTALL_BINS += $1/$2/build/tmp/$$($1_$2_PROG)
+endif
+endif
+
+endif # package-data.mk exists
+
+endef
diff --git a/rules/c-objs.mk b/rules/c-objs.mk
new file mode 100644
index 0000000000..b8514b6d60
--- /dev/null
+++ b/rules/c-objs.mk
@@ -0,0 +1,5 @@
+define c-objs # args: $1 = dir, $2 = distdir
+# C and S files are built only once, not once per way
+$1_$2_C_OBJS = $$(patsubst %.c,$1/$2/build/%.$$(v_osuf),$$($1_$2_C_SRCS))
+$1_$2_S_OBJS = $$(patsubst %.S,$1/$2/build/%.$$(v_osuf),$$($1_$2_S_SRCS))
+endef
diff --git a/rules/c-sources.mk b/rules/c-sources.mk
new file mode 100644
index 0000000000..8e90c702aa
--- /dev/null
+++ b/rules/c-sources.mk
@@ -0,0 +1,4 @@
+define c-sources # args: $1 = dir, $2 = distdir
+$1_$2_C_FILES = $$(patsubst %,$1/%,$$($1_$2_C_SRCS))
+$1_$2_S_FILES = $$(patsubst %,$1/%,$$($1_$2_S_SRCS))
+endef
diff --git a/rules/c-suffix-rules.mk b/rules/c-suffix-rules.mk
new file mode 100644
index 0000000000..6dfed87680
--- /dev/null
+++ b/rules/c-suffix-rules.mk
@@ -0,0 +1,60 @@
+
+define c-suffix-rules
+# $1 = dir
+# $2 = distdir
+# $3 = way
+# $4 = use GHC (YES/NO)
+
+# UseGhcForCc is only relevant when not booting from HC files.
+ifeq "$4" "YES"
+
+$1/$2/build/%.$$($3_osuf) : $1/%.c $$(MKDIRHIER) $$($1_$2_HC_DEP)
+ $$(RM) $$@
+ $$(MKDIRHIER) $$(dir $$@)
+ $$($1_$2_HC) $$($1_$2_$3_GHC_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/%.c $$($1_$2_HC_DEP)
+ $$(RM) $$@
+ $$($1_$2_HC) $$($1_$2_$3_GHC_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/%.$$($3_way_)s $$($1_$2_HC_DEP)
+ $$(RM) $$@
+ $$($1_$2_HC) $$($1_$2_$3_GHC_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/%.S $$(MKDIRHIER) $$($1_$2_HC_DEP)
+ $$(RM) $$@
+ $$(MKDIRHIER) $$(dir $$@)
+ $$($1_$2_HC) $$($1_$2_$3_GHC_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_way_)s : $1/$2/build/%.c $$($1_$2_HC_DEP)
+ $$(RM) $$@
+ $$($1_$2_HC) $$($1_$2_$3_GHC_CC_OPTS) -S $$< -o $$@
+
+else
+
+$1/$2/build/%.$$($3_osuf) : $1/%.c $$(MKDIRHIER)
+ $$(RM) $$@
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(CC) $$($1_$2_$3_ALL_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/%.c
+ $$(RM) $$@
+ $$(CC) $$($1_$2_$3_ALL_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/%.$$($3_way_)s
+ $$(RM) $$@
+ $$(AS) $$($1_$2_$3_ALL_AS_OPTS) -o $$@ $$<
+
+$1/$2/build/%.$$($3_osuf) : $1/%.S $$(MKDIRHIER)
+ $$(RM) $$@
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(CC) $$($1_$2_$3_ALL_CC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_way_)s : $1/$2/build/%.c
+ $$(RM) $$@
+ $$(CC) $$($1_$2_$3_ALL_CC_OPTS) -S $$< -o $$@
+
+endif
+
+endef
+
diff --git a/rules/clean-target.mk b/rules/clean-target.mk
new file mode 100644
index 0000000000..12c7528573
--- /dev/null
+++ b/rules/clean-target.mk
@@ -0,0 +1,9 @@
+
+define clean-target # args: $1 = dir, $2 = key, $3 = files/dirs to clean
+clean : clean_$1
+.PHONY: clean_$1
+clean_$1 : clean_$1_$2
+.PHONY: clean_$1_$2
+clean_$1_$2:
+ $(RM) -rf $3
+endef
diff --git a/rules/distdir-opts.mk b/rules/distdir-opts.mk
new file mode 100644
index 0000000000..5394adfc78
--- /dev/null
+++ b/rules/distdir-opts.mk
@@ -0,0 +1,60 @@
+
+# Set compilation flags that depend on a particular directory/distdir
+
+define distdir-opts # args: $1 = dir, $2 = distdir
+# $3 = GHC stage to use (0 == bootstrapping compiler)
+
+ifeq "$3" "0"
+# This is a bit of a hack.
+# If we are compiling something with the bootstrapping compiler on
+# cygwin, and it uses an include file from the rts (say), then we
+# need to stop mkdependC from generating a dependincy on
+# c:/ghc/rts/include/Rts.h
+# as that confuses make. So we use -isystem instead of -I, which stops
+# these dependencies from being generated. Technically this is wrong if
+# we depend on a library that is built inside the build tree, and we
+# use headers from that library, but currently I don't think that's the
+# case.
+$1_$2_DEP_INCLUDE_DIRS_FLAG = -isystem
+else
+$1_$2_DEP_INCLUDE_DIRS_FLAG = -I
+endif
+
+$1_$2_BUILD_CC_OPTS = \
+ $$(SRC_CC_OPTS) \
+ $$($1_CC_OPTS) \
+ $$(foreach dir,$$($1_$2_INCLUDE_DIRS),-I$1/$$(dir)) \
+ $$($1_$2_CC_OPTS) \
+ $$($1_$2_CPP_OPTS) \
+ $$(foreach dir,$$($1_$2_DEP_INCLUDE_DIRS),$$($1_$2_DEP_INCLUDE_DIRS_FLAG)$$(dir)) \
+ $$($1_$2_DEP_CC_OPTS)
+
+$1_$2_BUILD_LD_OPTS = \
+ $$(SRC_LD_OPTS) \
+ $$($1_LD_OPTS) \
+ $$($1_$2_LD_OPTS) \
+ $$(foreach opt,$$($1_$2_DEP_LIB_DIRS),-L$$(opt)) \
+ $$(foreach opt,$$($1_$2_DEP_EXTRA_LIBS),-l$$(opt)) \
+ $$($1_$2_DEP_LD_OPTS)
+
+# c.f. Cabal's Distribution.Simple.GHC.ghcOptions
+$1_$2_BUILD_HC_OPTS = \
+ $$(SRC_HC_OPTS) \
+ $$($1_HC_OPTS) \
+ $$($1_$2_HC_PKGCONF) \
+ $$(if $$($1_$2_PROG),, \
+ $$(if $$($1_PACKAGE),-package-name $$($1_PACKAGE)-$$($1_$2_VERSION))) \
+ $$(if $$($1_PACKAGE),-hide-all-packages) \
+ -i $$(if $$($1_$2_HS_SRC_DIRS),$$(foreach dir,$$($1_$2_HS_SRC_DIRS),-i$1/$$(dir)),-i$1) \
+ -i$1/$2/build -i$1/$2/build/autogen \
+ -I$1/$2/build -I$1/$2/build/autogen \
+ $$(foreach dir,$$($1_$2_INCLUDE_DIRS),-I$1/$$(dir)) \
+ $$(foreach inc,$$($1_$2_INCLUDE),-\#include "$$(inc)") \
+ $$(foreach opt,$$($1_$2_CPP_OPTS),-optP$$(opt)) \
+ $$(if $$($1_PACKAGE),-optP-include -optP$1/$2/build/autogen/cabal_macros.h) \
+ $$(foreach pkg,$$($1_$2_DEPS),-package $$(pkg)) \
+ $$(if $$(findstring YES,$$($1_$2_SplitObjs)),-split-objs,) \
+ $$($1_$2_HC_OPTS)
+
+endef
+
diff --git a/rules/distdir-way-opts.mk b/rules/distdir-way-opts.mk
new file mode 100644
index 0000000000..2248e2986f
--- /dev/null
+++ b/rules/distdir-way-opts.mk
@@ -0,0 +1,78 @@
+
+# Set compilation flags that additionally depend on a particular way
+
+define distdir-way-opts # args: $1 = dir, $2 = distdir, $3 = way
+
+# Options for a Haskell compilation:
+# - SRC_HC_OPTS source-tree-wide options
+# - WAY_v_HC_OPTS options for this way
+# - libraries/base_BUILD_HC_OPTS options from the build system for this dir
+# - -Idir1 -Idir2 ... include-dirs from this package
+# - -odir/-hidir/-stubdir put the output files under $3/build
+# - -osuf/-hisuf/-hcsuf suffixes for the output files in this way
+# - EXTRA_HC_OPTS options from the command-line
+
+$1_$2_$3_MOST_HC_OPTS = \
+ $$(WAY_$3_HC_OPTS) \
+ $$($1_$2_BUILD_HC_OPTS) \
+ $$($1_$2_$3_HC_OPTS) \
+ $$($$*_HC_OPTS) \
+ $$(EXTRA_HC_OPTS)
+
+# For real Haskell compilations we add -hidir etc.
+$1_$2_$3_ALL_HC_OPTS = \
+ $$($1_$2_$3_MOST_HC_OPTS) \
+ -odir $1/$2/build -hidir $1/$2/build -stubdir $1/$2/build \
+ -hisuf $$($3_hisuf) -osuf $$($3_osuf) -hcsuf $$($3_hcsuf)
+
+# c.f. Cabal's Distribution.Simple.PreProcess.ppHsc2hs
+# We use '' around cflags and lflags to handle paths with backslashes in
+# on Windows
+$1_$2_$3_ALL_HSC2HS_OPTS = \
+ --cc=$$(WhatGccIsCalled) \
+ --ld=$$(WhatGccIsCalled) \
+ $$(SRC_HSC2HS_OPTS) \
+ $$(WAY_$3_HSC2HS_OPTS) \
+ --cflag=-D__GLASGOW_HASKELL__=$$(ProjectVersionInt) \
+ $$(foreach opt,$$($1_$2_BUILD_CC_OPTS),'--cflag=$$(opt)') \
+ $$(foreach opt,$$($1_$2_BUILD_LD_OPTS),'--lflag=$$(opt)') \
+ $$($$*_HSC2HS_OPTS) \
+ $$(EXTRA_HSC2HS_OPTS)
+
+$1_$2_$3_ALL_CC_OPTS = \
+ $$(WAY_$3_CC_OPTS) \
+ $$($1_$2_BUILD_CC_OPTS) \
+ $$($1_$2_$3_CC_OPTS) \
+ $$($$*_CC_OPTS) \
+ $$(EXTRA_CC_OPTS)
+
+$1_$2_$3_GHC_CC_OPTS = \
+ $$(addprefix -optc, $$($1_$2_$3_ALL_CC_OPTS)) \
+ $$($1_$2_$3_MOST_HC_OPTS)
+
+$1_$2_$3_ALL_AS_OPTS = \
+ $$(SRC_AS_OPTS)
+ $$(WAY_$3_AS_OPTS) \
+ $$($1_AS_OPTS) \
+ $$($1_$2_AS_OPTS) \
+ $$($1_$2_$3_AS_OPTS) \
+ $$(EXTRA_AS_OPTS)
+
+$1_$2_$3_ALL_ALEX_OPTS = \
+ $$(SRC_ALEX_OPTS)
+ $$(WAY_$3_ALEX_OPTS) \
+ $$($1_ALEX_OPTS) \
+ $$($1_$2_ALEX_OPTS) \
+ $$($1_$2_$3_ALEX_OPTS) \
+ $$(EXTRA_ALEX_OPTS)
+
+$1_$2_$3_ALL_HAPPY_OPTS = \
+ $$(SRC_HAPPY_OPTS) \
+ $$(WAY_$3_HAPPY_OPTS) \
+ $$($1_HAPPY_OPTS) \
+ $$($1_$2_HAPPY_OPTS) \
+ $$($1_$2_$3_HAPPY_OPTS) \
+ $$(EXTRA_HAPPY_OPTS)
+
+endef
+
diff --git a/rules/docbook.mk b/rules/docbook.mk
new file mode 100644
index 0000000000..2f86363d4c
--- /dev/null
+++ b/rules/docbook.mk
@@ -0,0 +1,24 @@
+
+# Build docbook docs
+
+define docbook
+# $1 = dir
+# $2 = docname
+
+$(call clean-target,$1,docbook,$1/$2)
+
+ifneq "$$(XSLTPROC)" ""
+$(call all-target,$1,$1/$2/index.html)
+
+$1/$2/index.html: $$($1_DOCBOOK_SOURCES)
+ $$(RM) -r $$(dir $$@)
+ $$(XSLTPROC) --stringparam base.dir $$(dir $$@) \
+ --stringparam use.id.as.filename 1 \
+ --stringparam html.stylesheet fptools.css \
+ $$(XSLTPROC_LABEL_OPTS) $$(XSLTPROC_OPTS) \
+ $$(DIR_DOCBOOK_XSL)/html/chunk.xsl $1/$2.xml
+ cp mk/fptools.css $$(dir $$@)
+endif
+
+endef
+
diff --git a/rules/haddock.mk b/rules/haddock.mk
new file mode 100644
index 0000000000..74cb20713f
--- /dev/null
+++ b/rules/haddock.mk
@@ -0,0 +1,27 @@
+
+define haddock # args: $1 = dir, $2 = distdir, $3 = way
+
+ifneq "$$($1_$2_DO_HADDOCK)" "NO"
+
+ifeq "$$($$($1_PACKAGE)_HADDOCK_FILE)" ""
+$$($1_PACKAGE)_HADDOCK_FILE = $1/$2/doc/html/$$($1_PACKAGE)/$$($1_PACKAGE).haddock
+else
+$$(error Already got a haddock file for $$($1_PACKAGE))
+endif
+
+$(call all-target,$1_$2_haddock,$$($$($1_PACKAGE)_HADDOCK_FILE))
+
+$$($1_PACKAGE)_HADDOCK_DEPS = $$(foreach n,$$($1_$2_DEP_NAMES),$$($$n_HADDOCK_FILE))
+
+ifeq "$$(HSCOLOUR_SRCS)" "YES"
+$1_$2_HADDOCK_FLAGS += --hyperlink-source
+endif
+
+$$($$($1_PACKAGE)_HADDOCK_FILE) : $$(MKDIRHIER) $(INPLACE_BIN)/haddock$(exeext) $$(GHC_CABAL_INPLACE) $$($1_$2_HS_SRCS) $$($$($1_PACKAGE)_HADDOCK_DEPS)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(GHC_CABAL_INPLACE) haddock $2 $1 --with-haddock=$$(TOP)/$(INPLACE_BIN)/haddock --with-ghc=$$(TOP)/$(INPLACE_BIN)/ghc-stage2 $$($1_$2_HADDOCK_FLAGS) $$($1_$2_HADDOCK_OPTS)
+
+endif
+
+endef
+
diff --git a/rules/hi-rule.mk b/rules/hi-rule.mk
new file mode 100644
index 0000000000..07b65ed8e1
--- /dev/null
+++ b/rules/hi-rule.mk
@@ -0,0 +1,25 @@
+
+# Here's an interesting rule!
+# The .hi file depends on the .o file,
+# so if the .hi file is dated earlier than the .o file (commonly the case,
+# when interfaces are stable) this rule just makes sure that the .o file,
+# is up to date. Then it does nothing to generate the .hi file from the
+# .o file, because the act of making sure the .o file is up to date also
+# updates the .hi file (if necessary).
+
+define hi-rule # $1 = way
+%.$$($1_hisuf) : %.$$($1_osuf)
+ @if [ ! -f $$@ ] ; then \
+ echo Panic! $$< exists, but $$@ does not.; \
+ exit 1; \
+ else exit 0 ; \
+ fi
+
+%.$$($1_way_)hi-boot : %.$$($1_way_)o-boot
+ @if [ ! -f $$@ ] ; then \
+ echo Panic! $$< exists, but $$@ does not.; \
+ exit 1; \
+ else exit 0 ; \
+ fi
+endef
+
diff --git a/rules/hs-objs.mk b/rules/hs-objs.mk
new file mode 100644
index 0000000000..dac0bc540c
--- /dev/null
+++ b/rules/hs-objs.mk
@@ -0,0 +1,5 @@
+
+define hs-objs # args: $1 = dir, $2 = distdir, $3 = way
+$1_$2_$3_HS_OBJS = $$(patsubst %,$1/$2/build/%.$$($3_osuf),$$($1_$2_SLASH_MODS))
+$1_$2_$3_HI = $$(patsubst %,$1/$2/build/%.$$($3_hisuf),$$($1_$2_SLASH_MODS))
+endef
diff --git a/rules/hs-sources.mk b/rules/hs-sources.mk
new file mode 100644
index 0000000000..d8e6b4224a
--- /dev/null
+++ b/rules/hs-sources.mk
@@ -0,0 +1,46 @@
+
+define hs-sources # args: $1 = dir, $2 = distdir
+
+ifeq "$$($1_$2_HS_SRC_DIRS)" ""
+$1_$2_HS_SRC_DIRS = .
+endif
+
+# Here we collect all the .hs/.lhs source files that we can find. If
+# we can't find a Haskell source file for a given module, then presumably
+# it can be generated by preprocessing something (.hsc, .y, .x etc.), so
+# we depend on dist/build/Foo.hs in anticipation that the implicit rules
+# will put the preprocessed source file there.
+#
+# NB. use :=, we only want this thing evaluated once.
+#
+$1_$2_HS_SRCS := $$(foreach file,$$($1_$2_SLASH_MODS),\
+ $$(firstword \
+ $$(wildcard \
+ $$(foreach dir,$$($1_$2_HS_SRC_DIRS),\
+ $1/$$(dir)/$$(file).hs $1/$$(dir)/$$(file).lhs)) \
+ $1/$2/build/$$(file).hs))
+
+# .hs-boot files must be in the same place as the .hs file they go
+# with (GHC assumes this). When we preprocess a source file, and
+# that module has a .hs-boot or .lhs-boot file, we must arrange to
+# copy the file into the distdir so that it ends up alongside the
+# preprocessed .hs file. This complicated macro figures out for which
+# files we need to do this, so we can add them as dependencies of the
+# .depend file rule.
+#
+# for each .hs file in the build dir,
+# if there is a .hs-boot or .lhs-boot file for it in a source dir,
+# we want that file in the build dir.
+#
+# NB. use :=, we only want this thing evaluated once.
+#
+$1_$2_HS_BOOT_SRCS := $$(foreach dir,$$($1_$2_HS_SRC_DIRS),\
+ $$(subst $1/$$(dir),$1/$2/build,\
+ $$(wildcard \
+ $$(subst $1/$2/build,$1/$$(dir),\
+ $$(foreach file,\
+ $$(filter $1/$2/build%,$$($1_$2_HS_SRCS)),\
+ $$(patsubst %.hs,%.hs-boot,$$(file)) \
+ $$(patsubst %.hs,%.lhs-boot,$$(file)))))))
+
+endef
diff --git a/rules/hs-suffix-rules-srcdir.mk b/rules/hs-suffix-rules-srcdir.mk
new file mode 100644
index 0000000000..276d28b264
--- /dev/null
+++ b/rules/hs-suffix-rules-srcdir.mk
@@ -0,0 +1,70 @@
+
+define hs-suffix-rules-srcdir
+# args: $1 = dir, $2 = distdir, $3 = way, $4 = srcdir
+
+# Preprocessing Haskell source
+
+$1/$2/build/%.hs : $1/$4/%.ly $$(MKDIRHIER)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(HAPPY) $$($1_$2_$3_ALL_HAPPY_OPTS) $$< -o $$@
+
+$1/$2/build/%.hs : $1/$4/%.y $$(MKDIRHIER)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(HAPPY) $$($1_$2_$3_ALL_HAPPY_OPTS) $$< -o $$@
+
+$1/$2/build/%.hs : $1/$4/%.x $$(MKDIRHIER)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(ALEX) $$($1_$2_$3_ALL_ALEX_OPTS) $$< -o $$@
+
+$1/$2/build/%_hsc.c $1/$2/build/%_hsc.h $1/$2/build/%.hs : $1/$4/%.hsc $$(HSC2HS_INPLACE)
+ $$(MKDIRHIER) $$(dir $$@)
+ $$(HSC2HS_INPLACE) $$($1_$2_$3_ALL_HSC2HS_OPTS) $$< -o $$@
+ touch $$(patsubst %.hsc,%_hsc.c,$$<)
+
+# Compiling Haskell source
+
+$1/$2/build/%.$$($3_osuf) : $1/$4/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$4/%.lhs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_hcsuf) : $1/$4/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -C $$< -o $$@
+
+$1/$2/build/%.$$($3_hcsuf) : $1/$4/%.lhs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -C $$< -o $$@
+
+# XXX: for some reason these get used in preference to the direct
+# .hs->.o rule, I don't know why --SDM
+
+# $1/$2/build/%.$$($3_osuf) : $1/$2/build/%.$$($3_way_)hc
+# $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+#
+# $1/$2/build/%.$$($3_osuf) : $1/$2/build/%.hc
+# $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+#
+# $1/$2/build/%.$$($3_way_)s : $1/$2/build/%.$$($3_way_)hc
+# $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -S $$< -o $$@
+
+# Now the rules for hs-boot files.
+
+$1/$2/build/%.hs-boot : $1/$4/%.hs-boot
+ $$(CP) $$< $$@
+
+$1/$2/build/%.lhs-boot : $1/$4/%.lhs-boot
+ $$(CP) $$< $$@
+
+$1/$2/build/%.$$($3_way_)o-boot : $1/$4/%.hs-boot $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_way_)o-boot : $1/$4/%.lhs-boot $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+# stubs are automatically generated and compiled by GHC
+
+$1/$2/build/%_stub.$$($3_osuf): $1/$2/build/%.$$($3_osuf)
+ @:
+
+endef
+
diff --git a/rules/hs-suffix-rules.mk b/rules/hs-suffix-rules.mk
new file mode 100644
index 0000000000..62022bcec4
--- /dev/null
+++ b/rules/hs-suffix-rules.mk
@@ -0,0 +1,17 @@
+
+define hs-suffix-rules # args: $1 = dir, $2 = distdir, $3 = way
+
+$1/$2/build/%.$$($3_hcsuf) : $1/$2/build/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -C $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+$1/$2/build/%.$$($3_hcsuf) : $1/$2/build/autogen/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -C $$< -o $$@
+
+$1/$2/build/%.$$($3_osuf) : $1/$2/build/autogen/%.hs $$($1_$2_HC_DEP)
+ $$($1_$2_HC) $$($1_$2_$3_ALL_HC_OPTS) -c $$< -o $$@
+
+endef # hs-suffix-rules
+
diff --git a/rules/includes-sources.mk b/rules/includes-sources.mk
new file mode 100644
index 0000000000..de66b39305
--- /dev/null
+++ b/rules/includes-sources.mk
@@ -0,0 +1,14 @@
+
+define includes-sources # args: $1 = dir, $2 = distdir
+
+ifeq "$$($1_$2_INCLUDE_DIRS)" ""
+$1_$2_INCLUDE_DIRS = .
+endif
+
+$1_$2_INSTALL_INCLUDES_SRCS :=\
+ $$(foreach file,$$($1_$2_INSTALL_INCLUDES),\
+ $$(firstword \
+ $$(wildcard \
+ $$(foreach dir,$$($1_$2_INCLUDE_DIRS),\
+ $1/$$(dir)/$$(file)))))
+endef
diff --git a/rules/manual-package-config.mk b/rules/manual-package-config.mk
new file mode 100644
index 0000000000..2eb33b787a
--- /dev/null
+++ b/rules/manual-package-config.mk
@@ -0,0 +1,33 @@
+
+define manual-package-config # args: $1 = dir
+
+$1/package.conf.inplace : $1/package.conf.in $(GHC_PKG_INPLACE)
+ $(CPP) $(RAWCPP_FLAGS) -P \
+ -DTOP='"$$(TOP)"' \
+ $$($1_PACKAGE_CPP_OPTS) \
+ -x c -I$$(GHC_INCLUDE_DIR) $$< | \
+ grep -v '^#pragma GCC' | \
+ sed -e 's/""//g' -e 's/:[ ]*,/: /g' >$$@
+
+ $(GHC_PKG_INPLACE) update --force $$@
+
+# This is actually a real file, but we need to recreate it on every
+# "make install", so we declare it as phony
+.PHONY: $1/package.conf.install
+$1/package.conf.install:
+ $(CPP) $(RAWCPP_FLAGS) -P \
+ -DINSTALLING \
+ -DLIB_DIR='"$$(libdir)"' \
+ -DINCLUDE_DIR='"$$(libdir)/include"' \
+ $$($1_PACKAGE_CPP_OPTS) \
+ -x c -I$$(GHC_INCLUDE_DIR) $1/package.conf.in | \
+ grep -v '^#pragma GCC' | \
+ sed -e 's/""//g' -e 's/:[ ]*,/: /g' >$$@
+
+clean : clean_$1
+.PHONY: clean_$1
+clean_$1 : clean_$1_package.conf
+.PHONY: clean_$1_package.conf
+clean_$1_package.conf :
+ $(RM) $1/package.conf.install $1/package.conf.inplace
+endef
diff --git a/rules/package-config.mk b/rules/package-config.mk
new file mode 100644
index 0000000000..111386e115
--- /dev/null
+++ b/rules/package-config.mk
@@ -0,0 +1,41 @@
+
+define package-config # args: $1 = dir, $2 = distdir, $3 = GHC stage
+
+$1_$2_HC = $$(GHC_STAGE$3)
+
+# configuration stuff that depends on which GHC we're building with
+ifeq "$3" "0"
+$1_$2_ghc_ge_609 = $(ghc_ge_609)
+$1_$2_HC_CONFIG = $$(GHC_STAGE0)
+$1_$2_HC_CONFIG_DEP =
+$1_$2_GHC_PKG = $$(GHC_PKG)
+$1_$2_GHC_PKG_DEP =
+$1_$2_HC_MK_DEPEND = $$($1_$2_HC)
+# We can't make rules depend on the bootstrapping compiler, as then
+# on cygwin we get a dep on c:/ghc/..., and make gets confused by the :
+$1_$2_HC_MK_DEPEND_DEP =
+$1_$2_HC_DEP =
+ifeq "$$($1_$2_USE_BOOT_LIBS)" "YES"
+$1_$2_HC_PKGCONF = -package-conf $(BOOTSTRAPPING_CONF)
+$1_$2_GHC_PKG_OPTS = --package-conf=$$(BOOTSTRAPPING_CONF)
+$1_$2_CONFIGURE_OPTS += --package-db=$$(TOP)/$$(BOOTSTRAPPING_CONF)
+endif
+else
+$1_$2_ghc_ge_609 = YES
+$1_$2_HC_PKGCONF =
+$1_$2_HC_CONFIG = $$(TOP)/$$(DUMMY_GHC_INPLACE)
+$1_$2_HC_CONFIG_DEP = $$(DUMMY_GHC_INPLACE)
+$1_$2_GHC_PKG = $$(TOP)/$$(GHC_PKG_INPLACE)
+$1_$2_GHC_PKG_DEP = $$(GHC_PKG_INPLACE)
+$1_$2_GHC_PKG_OPTS =
+# If stage is not 0 then we always use stage1 for making .depend, as later
+# stages aren't available early enough
+$1_$2_HC_MK_DEPEND = $$(GHC_STAGE1)
+$1_$2_HC_MK_DEPEND_DEP = $$($1_$2_HC_MK_DEPEND)
+$1_$2_HC_DEP = $$($1_$2_HC)
+$1_$2_HC_OPTS += -no-user-package-conf
+endif
+
+# Useful later
+$1_$2_SLASH_MODS = $$(subst .,/,$$($1_$2_MODULES))
+endef
diff --git a/rules/shell-wrapper.mk b/rules/shell-wrapper.mk
new file mode 100644
index 0000000000..a2aca45e36
--- /dev/null
+++ b/rules/shell-wrapper.mk
@@ -0,0 +1,63 @@
+define shell-wrapper
+# $1 = dir
+# $2 = distdir
+
+ifeq "$$($1_$2_SHELL_WRAPPER)" "YES"
+
+ifeq "$(Windows)" "YES"
+
+ifeq "$$($1_$2_INSTALL_SHELL_WRAPPER)" "YES"
+# Just install the binary on Windows
+$1_$2_INSTALL = YES
+endif
+
+else
+
+ifeq "$$($1_$2_SHELL_WRAPPER_NAME)" ""
+$1_$2_SHELL_WRAPPER_NAME = $1/$$($1_$2_PROG).wrapper
+endif
+
+ifneq "$$($1_$2_INSTALL_INPLACE)" "NO"
+all_$1_$2 : $$(INPLACE_BIN)/$$($1_$2_PROG)
+
+$$(INPLACE_BIN)/$$($1_$2_PROG): $$($1_$2_INPLACE)
+ $$(RM) -f $$@
+ echo '#!$$(SHELL)' >> $$@
+ echo 'executablename=$$(TOP)/$$<' >> $$@
+ echo 'datadir=$$(TOP)/$$(INPLACE_LIB)' >> $$@
+ echo 'bindir=$$(TOP)/$$(INPLACE_BIN)' >> $$@
+ cat $$($1_$2_SHELL_WRAPPER_NAME) >> $$@
+ $$(EXECUTABLE_FILE) $$@
+endif
+
+ifeq "$$($1_$2_INSTALL_SHELL_WRAPPER)" "YES"
+
+ifeq "$$($1_$2_INSTALL_SHELL_WRAPPER_NAME)" ""
+$1_$2_INSTALL_SHELL_WRAPPER_NAME = $$($1_$2_PROG)
+endif
+
+# Install the binary in $(libexecdir), and install a shell wrapper in $(bindir)
+INSTALL_LIBEXECS += $1/$2/build/tmp/$$($1_$2_PROG)
+BINDIST_WRAPPERS += $$($1_$2_SHELL_WRAPPER_NAME)
+
+install: install_$1_$2_wrapper
+
+.PHONY: install_$1_$2_wrapper
+install_$1_$2_wrapper: WRAPPER=$$(DESTDIR)$$(bindir)/$$($1_$2_INSTALL_SHELL_WRAPPER_NAME)
+install_$1_$2_wrapper:
+ $$(MKDIRHIER) $$(DESTDIR)$$(bindir)
+ $$(RM) -f $$(WRAPPER)
+ echo '#!$$(SHELL)' >> $$(WRAPPER)
+ echo 'executablename=$$(libexecdir)/$$($1_$2_PROG)' >> $$(WRAPPER)
+ echo 'datadir=$$(datadir)' >> $$(WRAPPER)
+ echo 'bindir=$$(bindir)' >> $$(WRAPPER)
+ cat $$($1_$2_SHELL_WRAPPER_NAME) >> $$(WRAPPER)
+ $$(EXECUTABLE_FILE) $$(WRAPPER)
+
+endif # $1_$2_INSTALL_SHELL_WRAPPER
+
+endif
+
+endif # $1_$2_SHELL_WRAPPER
+
+endef
diff --git a/rules/way-prelims.mk b/rules/way-prelims.mk
new file mode 100644
index 0000000000..9df9a5bc69
--- /dev/null
+++ b/rules/way-prelims.mk
@@ -0,0 +1,13 @@
+
+define way-prelims # $1 = way
+ifeq "$1" "v"
+$1__way =
+$1_way_ =
+else
+$1__way = _$1
+$1_way_ = $1_
+endif
+$1_osuf = $$($1_way_)o
+$1_hisuf = $$($1_way_)hi
+$1_hcsuf = $$($1_way_)hc
+endef