Hacks to get nofib working again: copy in parts of the old GHC build system
authorSimon Marlow <marlowsd@gmail.com>
Tue, 28 Apr 2009 12:44:33 +0000 (12:44 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Tue, 28 Apr 2009 12:44:33 +0000 (12:44 +0000)
Makefile
mk/boilerplate.mk
mk/ghc-opts.mk [new file with mode: 0644]
mk/ghc-paths.mk [new file with mode: 0644]
mk/ghc-recurse.mk [new file with mode: 0644]
mk/ghc-suffix.mk [new file with mode: 0644]
mk/ghc-target.mk [new file with mode: 0644]
mk/target.mk
runstdtest/Makefile [new file with mode: 0644]
runstdtest/runstdtest.prl [new file with mode: 0644]

index 6f9a4b0..0934815 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ include $(TOP)/mk/boilerplate.mk
 # As usual,if you want to override these, create
 # $(TOP)/../mk/build.mk containing the flags and options
 # you want to use in a build tree.
-SUBDIRS = $(NoFibSubDirs)
+SUBDIRS = runstdtest $(NoFibSubDirs)
 
 
 # Include the standard targets, one of which
index 164c19f..9d9c8f8 100644 (file)
 # with standard TOP-mangling
 # Remember, TOP is the top level of the innermost level
 
+default : all
+
 NOFIB_TOP := $(TOP)
-TOP := $(TOP)/..
-include $(TOP)/mk/boilerplate.mk
-TOP:=$(NOFIB_TOP)
+include $(NOFIB_TOP)/../mk/config.mk
+GHC_TOP := $(TOP)
+TOP := $(NOFIB_TOP)
 
 # Turn off -Werror for nofib. This allows you to use nofib in a tree
 # built with validate.
@@ -30,9 +32,17 @@ WAYS=$(NoFibWays)
 
 SRC_HC_OPTS += $(NoFibHcOpts) -Rghc-timing
 
-HC        = $(WithNofibHc)
-MKDEPENDHS := $(WithNofibHc)  # ToDo: wrong, if $(WithNofibHc) isn't GHC.
-USE_NEW_MKDEPEND_FLAGS := $(shell if test `$(MKDEPENDHS) --numeric-version | sed -e "s/\./0/" -e "s/\..*//"` -ge 609; then echo YES; else echo NO; fi)
+HC        = $(GHC_TOP)/$(GHC_STAGE2)
+MKDEPENDHS := $(GHC_TOP)/$(GHC_STAGE2)  # ToDo: wrong, if $(WithNofibHc) isn't GHC.
+MKDEPENDC := $(GHC_TOP)/$(MKDEPENDC)
+RUNTEST   = $(NOFIB_TOP)/runstdtest/runstdtest
+
+USE_NEW_MKDEPEND_FLAGS = YES
+# USE_NEW_MKDEPEND_FLAGS := $(shell if test `$(MKDEPENDHS) --numeric-version | sed -e "s/\./0/" -e "s/\..*//"` -ge 609; then echo YES; else echo NO; fi)
 
+include $(NOFIB_TOP)/mk/ghc-paths.mk
+include $(NOFIB_TOP)/mk/ghc-opts.mk
 include $(NOFIB_TOP)/mk/paths.mk
 include $(NOFIB_TOP)/mk/opts.mk
+
+-include .depend
diff --git a/mk/ghc-opts.mk b/mk/ghc-opts.mk
new file mode 100644 (file)
index 0000000..08ec4b6
--- /dev/null
@@ -0,0 +1,109 @@
+#################################################################################
+#
+#                              opts.mk
+#
+#      This file defines Make variables for the
+#      option flags for each utility program
+#
+#      $Id: opts.mk,v 1.36 2004/08/26 20:08:54 panne Exp $
+#
+#################################################################################
+
+#
+# N.B. This is *NOT* the place to put extra options of ANY SORT!
+#
+
+# Exports:     Define P_OPTS for the most important utility programs, P, namely
+#
+#              AR AS CPP CTAGS C FLEX HC HSTAGS LD LINT 
+#              LIT2CHANGELOG LIT2HTML LIT2LATEX LIT2PGM
+#              MKDEPENDC MKDEPENDHS MKDEPENDLIT RUNTEST
+#              UNLIT          
+
+
+# For each such utility program P, this file defines
+#
+#      $(P)            The pathname to invoke the utility
+#      P_OPTS          Options to pass to P
+#
+# P_OPTS is always defined like this:
+#
+# P_OPTS = SRC_P_OPTS WAY$(_way)_P_OPTS EXTRA_P_OPTS
+#
+# where the variables on the right hand side are set by the user or
+# some other Makefile.  They have the following intended uses:
+#
+#      SRC_P_OPTS              Source-tree options for P
+#      WAY$(_way)_P_OPTS       Source-tree options for P specific to $(way)
+#      EXTRA_P_OPTS            Command-line options for P
+#
+# and for some programs
+#
+#      $(HcFlavour)_P_OPTS     Compiler-specific options for P
+#       $($*_P_OPTS)            Target specific options for P
+#
+# All these options should be set with
+#      thing += extra-options
+# in case someone higher up the include hierarchy has already added some
+
+# Which class of compiler are we aiming at?  (GHC, NHC or HUGS)
+ifeq "$(HcFlavour)" ""
+HcFlavour = GHC
+endif
+
+#################################################################################
+#
+#              Absolutely standard glue
+#
+#################################################################################
+
+# All the standard gluing together, as in the comment right at the front
+
+
+HC_OPTS            = $(BOOTSTRAPPING_PACKAGE_CONF_HC_OPTS) $(SRC_HC_OPTS) $(WAY$(_way)_HC_OPTS) $($*_HC_OPTS) $(EXTRA_HC_OPTS)
+HC_POST_OPTS       = $(SRC_HC_POST_OPTS) $(WAY$(_way)_HC_POST_OPTS) $($*_HC_POST_OPTS) $(EXTRA_HC_POST_OPTS)
+HC_PRE_OPTS        = $(SRC_HC_PRE_OPTS) $(WAY$(_way)_HC_PRE_OPTS) $($*_HC_PRE_OPTS) $(EXTRA_HC_PRE_OPTS)
+
+ILX2IL_OPTS        = $(SRC_ILX2IL_OPTS) $(WAY$(_way)_ILX2IL_OPTS) $($*_ILX2IL_OPTS) $(EXTRA_ILX2IL_OPTS)
+ILASM_OPTS         = $(SRC_ILASM_OPTS) $(WAY$(_way)_ILASM_OPTS) $($*_ILASM_OPTS) $(EXTRA_ILASM_OPTS)
+
+RUNTEST_OPTS       = $(SRC_RUNTEST_OPTS) $(WAY$(_way)_RUNTEST_OPTS) \
+                     $($*_RUNTEST_OPTS) $(EXTRA_RUNTEST_OPTS)
+
+ALEX_OPTS         = $(SRC_ALEX_OPTS) $($(HcFlavour)_ALEX_OPTS) $(WAY$(_way)_ALEX_OPTS) $($*_ALEX_OPTS) $(EXTRA_ALEX_OPTS)
+AR_OPTS            = $(SRC_AR_OPTS) $(WAY$(_way)_AR_OPTS) $(EXTRA_AR_OPTS)
+AS_OPTS            = $(SRC_AS_OPTS) $(WAY$(_way)_AS_OPTS) $(EXTRA_AS_OPTS)
+BLD_DLL_OPTS       = $(SRC_BLD_DLL_OPTS) $(WAY$(_way)_BLD_DLL_OPTS) $($*_HC_OPTS) $(EXTRA_BLD_DLL_OPTS)
+CPP_OPTS           = $(SRC_CPP_OPTS) $(WAY$(_way)_CPP_OPTS) $(EXTRA_CPP_OPTS)
+CTAGS_OPTS         = $(SRC_CTAGS_OPTS) $(WAY$(_way)_CTAGS_OPTS) $(EXTRA_CTAGS_OPTS)
+CC_OPTS            = $(SRC_CC_OPTS) $(WAY$(_way)_CC_OPTS) $($*_CC_OPTS) $(EXTRA_CC_OPTS)
+FLEX_OPTS          = $(SRC_FLEX_OPTS) $(WAY$(_way)_FLEX_OPTS) $(EXTRA_FLEX_OPTS)
+HADDOCK_OPTS       = $(SRC_HADDOCK_OPTS) $(WAY$(_way)_HADDOCK_OPTS) $($*_HADDOCK_OPTS) $(EXTRA_HADDOCK_OPTS)
+HAPPY_OPTS         = $(SRC_HAPPY_OPTS) $($(HcFlavour)_HAPPY_OPTS) $(WAY$(_way)_HAPPY_OPTS) $($*_HAPPY_OPTS) $(EXTRA_HAPPY_OPTS)
+GC_OPTS            = $(SRC_GC_OPTS) $(WAY$(_way)_GC_OPTS) $($*_GC_OPTS) $(EXTRA_GC_OPTS)
+HSTAGS_OPTS        = $(SRC_HSTAGS_OPTS) $(WAY$(_way)_HSTAGS_OPTS) $(EXTRA_HSTAGS_OPTS)
+HSC2HS_OPTS        = $(SRC_HSC2HS_OPTS) $($(HcFlavour)_HSC2HS_OPTS) $(WAY$(_way)_HSC2HS_OPTS) $(EXTRA_HSC2HS_OPTS)
+INSTALL_OPTS       = $(SRC_INSTALL_OPTS) $(WAY$(_way)_INSTALL_OPTS) $(EXTRA_INSTALL_OPTS)
+INSTALL_BIN_OPTS   = $(INSTALL_OPTS) $(SRC_INSTALL_BIN_OPTS)
+LD_OPTS            = $(SRC_LD_OPTS) $(WAY$(_way)_LD_OPTS) $(EXTRA_LD_OPTS)
+LINT_OPTS          = $(SRC_LINT_OPTS) $(WAY$(_way)_LINT_OPTS) $(EXTRA_LINT_OPTS)
+HEVEA_OPTS         = $(SRC_HEVEA_OPTS) $(WAY$(_way)_HEVEA_OPTS) $(EXTRA_HEVEA_OPTS)
+HACHA_OPTS         = $(SRC_HACHA_OPTS) $(WAY$(_way)_HACHA_OPTS) $(EXTRA_HACHA_OPTS)
+LIT2CHANGELOG_OPTS = $(SRC_LIT2CHANGELOG_OPTS) $(WAY$(_way)_LIT2CHANGELOG_OPTS) \
+                     $(EXTRA_LIT2CHANGELOG_OPTS)
+LIT2HTML_OPTS      = $(SRC_LIT2HTML_OPTS) $(WAY$(_way)_LIT2HTML_OPTS) $(EXTRA_LIT2HTML_OPTS)
+LIT2LATEX_OPTS     = $(SRC_LIT2LATEX_OPTS) $(WAY$(_way)_LIT2LATEX_OPTS) $(EXTRA_LIT2LATEX_OPTS)
+LIT2PGM_OPTS       = $(SRC_LIT2PGM_OPTS) $(WAY$(_way)_LIT2PGM_OPTS) $(EXTRA_LIT2PGM_OPTS)
+MKDEPENDC_OPTS     = $(SRC_MKDEPENDC_OPTS) $(WAY$(_way)_MKDEPENDC_OPTS) $(EXTRA_MKDEPENDC_OPTS)
+MKDEPENDHS_OPTS    = $(BOOTSTRAPPING_PACKAGE_CONF_MKDEPENDHS_OPTS) \
+                     $(SRC_MKDEPENDHS_OPTS) $(WAY$(_way)_MKDEPENDHS_OPTS) \
+                     $(EXTRA_MKDEPENDHS_OPTS)
+MKDEPENDLIT_OPTS   = $(SRC_MKDEPENDLIT_OPTS) $(WAY$(_way)_MKDEPENDLIT_OPTS) \
+                     $(EXTRA_MKDEPENDLIT_OPTS)
+XSLTPROC_OPTS      = $(WAY$(_way)_XSLTPROC_OPTS) $(EXTRA_XSLTPROC_OPTS)
+FOP_OPTS           = $(WAY$(_way)_FOP_OPTS) $(EXTRA_FOP_OPTS)
+UNLIT_OPTS         = $(SRC_UNLIT_OPTS) $(WAY$(_way)_UNLIT_OPTS) $(EXTRA_UNLIT_OPTS)
+ZIP_OPTS           = $(SRC_ZIP_OPTS) $(EXTRA_ZIP_OPTS)
+
+# Version of CC_OPTS to use when GHC is the C compiler
+GHC_CC_OPTS       = $(addprefix -optc, $(CC_OPTS)) $(HC_OPTS)
diff --git a/mk/ghc-paths.mk b/mk/ghc-paths.mk
new file mode 100644 (file)
index 0000000..4cb2bbf
--- /dev/null
@@ -0,0 +1,277 @@
+################################################################################
+#
+#                          paths.mk
+#
+#      This file defines Make variables for standard directories
+#      and file lists
+#
+################################################################################
+
+################################################################################
+#
+#              Standard variable names
+#
+################################################################################
+# The fptools mk setup defines a set of standard names which are used
+# by the standard targets provided by mk. One example of this is the
+# use of standard names for specifying what files to compile, their
+# intermediate/object code, and the name of the final
+# executable. Based on the settings of these variables, the standard
+# targets will generate/expand rules that automatically compile and
+# link your program.
+#
+# The general rules:
+#
+#   SRCS - sources, might be prefixed to indicate what type of source
+#          they are.
+#   OBJS - object files (possibly prefixed).
+#
+#   PROG - name of final executable
+#
+# We attempt to automatically devine the list of sources $(SRCS) to
+# compile by looking in the current directory (and possibly other
+# directories which may be specified by setting the $(ALL_DIRS)
+# variable).  This is complicated by the fact that some files are
+# derived from other files: eg. .hsc files give rise to -hsc.c and
+# -hsc.h files, .ly files give rise to .hs files, and .hs files give
+# rise to .hc files sometimes.
+
+# So we figure out the sources in three stages: first figure out what
+# sources we can find (this is $(ALL_SRCS)).  Then figure out all the
+# "derived" sources (eg. A.hsc generates A.hs and A_hsc.c), and
+# finally put all these together and remove duplicates (GNU make's
+# handy sort function does the duplicate removing).
+
+# HS_SRCS:   list of Haskell modules you want to compile.
+#             (also use by depend rule).
+# HS_OBJS:   list of corresponding object files
+# HS_PROG:   program that is ultimately linked.
+# HS_IFACES: list of interface files generated
+#             (caveat: assuming no funny use of -hisuf and that
+#               file name and module name match)
+
+ALL_SRCS    = $(wildcard $(patsubst ./%, %,  \
+                  $(patsubst %,%/*.hs,   . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.lhs,  . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.hs-boot,  . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.lhs-boot, . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.y,    . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.ly,   . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.x,    . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.c,    . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.hc,   . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.S,    . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.prl,  . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.lprl, . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.lit,  . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.verb, . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.hsc,  . $(ALL_DIRS)) \
+                  $(patsubst %,%/*.gc,   . $(ALL_DIRS)) \
+              )) $(EXTRA_SRCS)
+
+# ALL_SRCS is computed once and for all into PRE_SRCS at the top of
+# target.mk.  Otherwise, we end up re-computing ALL_SRCS every time it
+# is expanded (it is used in several variables below, and these
+# variables are used in several others, etc.), which can really slow
+# down make.
+
+PRE_HS_SRCS  = $(filter %.hs,  $(PRE_SRCS))
+PRE_LHS_SRCS = $(filter %.lhs, $(PRE_SRCS))
+
+PRE_HS_BOOT_SRCS = $(filter %.hs-boot,  $(PRE_SRCS)) \
+                  $(filter %.lhs-boot, $(PRE_SRCS))
+
+GC_SRCS       = $(filter %.gc,  $(PRE_SRCS))
+HSC_SRCS      = $(filter %.hsc, $(PRE_SRCS))
+HAPPY_Y_SRCS  = $(filter %.y,   $(PRE_SRCS))
+HAPPY_LY_SRCS = $(filter %.ly,   $(PRE_SRCS))
+HAPPY_SRCS    = $(HAPPY_Y_SRCS) $(HAPPY_LY_SRCS)
+ALEX_SRCS     = $(filter %.x,   $(PRE_SRCS))
+
+DERIVED_GC_SRCS       = $(patsubst %.gc, %.hs, $(GC_SRCS)) \
+                       $(patsubst %.gc, %_stub_ffi.c, $(GC_SRCS)) \
+                       $(patsubst %.gc, %_stub_ffi.h, $(GC_SRCS))
+
+DERIVED_HSC_SRCS      = $(patsubst %.hsc, %.hs, $(HSC_SRCS)) \
+                       $(patsubst %.hsc, %_hsc.c, $(HSC_SRCS)) \
+                       $(patsubst %.hsc, %_hsc.h, $(HSC_SRCS)) \
+                       $(patsubst %.hsc, %.hc, $(HSC_SRCS))
+
+DERIVED_HAPPY_SRCS    = $(patsubst %.y,   %.hs, $(HAPPY_Y_SRCS)) \
+                       $(patsubst %.ly,  %.hs, $(HAPPY_LY_SRCS))
+
+DERIVED_ALEX_SRCS     = $(patsubst %.x,   %.hs, $(ALEX_SRCS))
+
+DERIVED_HC_SRCS       = $(patsubst %.hs,  %.hc, $(PRE_HS_SRCS)) \
+                       $(patsubst %.lhs, %.hc, $(PRE_LHS_SRCS))
+
+DERIVED_SRCS         = $(DERIVED_GC_SRCS) \
+                       $(DERIVED_HSC_SRCS) \
+                       $(DERIVED_HAPPY_SRCS) \
+                       $(DERIVED_ALEX_SRCS) \
+                       $(DERIVED_HC_SRCS)
+
+# EXCLUDED_SRCS can be set in the Makefile, otherwise it defaults to empty.
+EXCLUDED_GC_SRCS       = $(filter %.gc,  $(EXCLUDED_SRCS))
+EXCLUDED_HSC_SRCS      = $(filter %.hsc, $(EXCLUDED_SRCS))
+EXCLUDED_HAPPY_Y_SRCS  = $(filter %.y,   $(EXCLUDED_SRCS))
+EXCLUDED_HAPPY_LY_SRCS = $(filter %.ly,  $(EXCLUDED_SRCS))
+EXCLUDED_HAPPY_SRCS   = $(EXCLUDED_HAPPY_Y_SRCS) $(EXCLUDED_HAPPY_LY_SRCS)
+EXCLUDED_ALEX_SRCS    = $(filter %.x,   $(EXCLUDED_SRCS))
+EXCLUDED_HS_SRCS      = $(filter %.hs,  $(EXCLUDED_SRCS))
+EXCLUDED_LHS_SRCS     = $(filter %.lhs, $(EXCLUDED_SRCS))
+EXCLUDED_DERIVED_SRCS = $(patsubst %.hsc, %.hs, $(EXCLUDED_HSC_SRCS)) \
+                       $(patsubst %.hsc, %_hsc.h, $(EXCLUDED_HSC_SRCS)) \
+                       $(patsubst %.hsc, %_hsc.c, $(EXCLUDED_HSC_SRCS)) \
+                       $(patsubst %.hsc, %.hc, $(EXCLUDED_HSC_SRCS)) \
+                       $(patsubst %.gc,  %_stub_ffi.c, $(EXCLUDED_GC_SRCS)) \
+                       $(patsubst %.gc,  %_stub_ffi.h, $(EXCLUDED_GC_SRCS)) \
+                        $(patsubst %.y,   %.hs, $(EXCLUDED_HAPPY_Y_SRCS)) \
+                       $(patsubst %.ly,  %.hs, $(EXCLUDED_HAPPY_LY_SRCS)) \
+                        $(patsubst %.x,   %.hs, $(EXCLUDED_ALEX_SRCS)) \
+                       $(patsubst %.hs,  %.hc, $(EXCLUDED_HS_SRCS)) \
+                       $(patsubst %.lhs, %.hc, $(EXCLUDED_LHS_SRCS)) \
+                       $(patsubst %.hs,  %_stub.c, $(EXCLUDED_HS_SRCS)) \
+                       $(patsubst %.lhs, %_stub.c, $(EXCLUDED_LHS_SRCS))
+
+# Exclude _hsc.c files; they get built as part of the cbits library,
+# not part of the main library
+
+CLOSED_EXCLUDED_SRCS  = $(sort $(EXCLUDED_SRCS) $(EXCLUDED_DERIVED_SRCS))
+
+SRCS        = $(filter-out $(CLOSED_EXCLUDED_SRCS), \
+               $(sort $(PRE_SRCS) $(DERIVED_SRCS)))
+
+HS_SRCS            = $(filter %.lhs %.hs, $(sort $(SRCS) $(BOOT_SRCS)))
+HS_OBJS     = $(addsuffix .$(way_)o,$(basename $(HS_SRCS)))
+HS_IFACES   = $(addsuffix .$(way_)hi,$(basename $(HS_SRCS)))
+
+HI_BOOTS    = $(patsubst %.hs-boot, %.$(way_)hi-boot, \
+             $(patsubst %.lhs-boot, %.$(way_)hi-boot, $(PRE_HS_BOOT_SRCS)))
+
+O_BOOTS     = $(patsubst %.hs-boot, %.$(way_)o-boot, \
+             $(patsubst %.lhs-boot, %.$(way_)o-boot, $(PRE_HS_BOOT_SRCS)))
+
+GC_C_OBJS   = $(addsuffix _stub_ffi.$(way_)o,$(basename $(filter %.gc,$(SRCS))))
+HSC_C_OBJS  = $(addsuffix _hsc.$(way_)o,$(basename $(filter %.hsc,$(SRCS))))
+
+ifeq "$(BootingFromHc)" "NO"
+# We don't want to build the _stub.c files ourselves, unless we're
+# bootstrapping from .hc files.
+EXCLUDED_C_SRCS = $(patsubst %.lhs, %_stub.c, $(HS_SRCS)) \
+                 $(patsubst %.hs,  %_stub.c, $(HS_SRCS)) \
+                 $(patsubst %.gc, %_stub_ffi.c, $(GC_SRCS)) \
+                 $(patsubst %.gc, %_stub_ffi.h, $(GC_SRCS))
+endif
+
+# These are droppings from hsc2hs - ignore them if we see them.
+EXCLUDED_C_SRCS += $(patsubst %.hsc, %_hsc_make.c, $(HSC_SRCS))
+
+C_SRCS      = $(filter-out $(EXCLUDED_C_SRCS),$(filter %.c %.S,$(SRCS)))
+C_OBJS      = $(addsuffix .$(way_)o,$(basename $(C_SRCS)))
+
+# SCRIPT_SRCS:  list of raw script files (in literate form)
+# SCRIPT_OBJS:  de-litted scripts
+SCRIPT_SRCS = $(filter %.lprl,$(SRCS))
+SCRIPT_OBJS = $(addsuffix .prl,$(basename $(SCRIPT_SRCS)))
+
+OBJS        = $(HS_OBJS) $(C_OBJS) $(GC_C_OBJS) 
+
+# The default is for $(LIBOBJS) to be the same as $(OBJS)
+LIBOBJS            = $(OBJS)
+
+#
+# Note that as long as you use the standard variables for setting
+# which C & Haskell programs you want to work on, you don't have
+# to set any of the clean variables - the default should do the Right
+# Thing.
+#
+
+#------------------------------------------------------------------
+#
+# make depend defaults
+#
+# The default set of files for the dependency generators to work on
+# is just their source equivalents.
+#
+
+ifneq "$(BootingFromHc)" "YES"
+MKDEPENDHS_SRCS=$(HS_SRCS)
+else
+MKDEPENDHS_SRCS=
+endif
+
+MKDEPENDC_SRCS=$(C_SRCS)
+
+#------------------------------------------------------------------
+#
+# make TAGS defaults
+#
+# The default set of files for the TAGS file generators to work on
+# is just their source equivalents.
+#
+TAGS_HS_SRCS=$(HS_SRCS)
+TAGS_C_SRCS=$(C_SRCS)
+
+#------------------------------------------------------------------
+# Clean file make-variables.
+#
+# The following three variables are used to control
+# what gets removed when doing `make clean'
+#
+# MOSTLYCLEAN_FILES   object code etc., but not stuff
+#                     that is slow to recompile and/or stable
+#
+# CLEAN_FILES  all files that are created by running make.
+#
+# MAINTAINER_CLEAN_FILES also clean out machine-generated files
+#                        that may require extra tools to create.
+#
+#
+# NOTE: $(SCRIPT_OBJS) is not in MOSTLY_CLEAN_FILES, because in some
+# places in the tree it appears that we have source files in $(SCRIPT_OBJS).
+# Specifically glafp-utils/mkdependC/mkdependC.prl and others in driver/ and
+# possibly others elsewhere in the tree.  ToDo: fix this properly.
+MOSTLY_CLEAN_FILES += $(HS_OBJS) $(C_OBJS) $(HSC_C_OBJS) $(GC_C_OBJS)
+CLEAN_FILES        += $(HS_PROG) $(C_PROG) $(SCRIPT_LINK) \
+                     $(PROG) $(LIBRARY) a.out \
+                     $(DERIVED_HSC_SRCS) \
+                     $(DERIVED_GC_SRCS) \
+                     $(patsubst %,%/*.$(way_)hi, . $(ALL_DIRS)) \
+                     $(HI_BOOTS) $(O_BOOTS)
+
+# we delete *all* the .hi files we can find, rather than just
+# $(HS_IFACES), because stale interfaces left around by modules which
+# don't exist any more can screw up the build.
+
+# Don't clean the .hc files if we're bootstrapping
+ifneq "$(BootingFromHc)" "YES"
+CLEAN_FILES += $(DERIVED_HC_SRCS)
+endif
+
+DIST_CLEAN_FILES       += .depend* *.hp *.prof
+
+MAINTAINER_CLEAN_FILES         += $(BOOT_SRCS) $(DERIVED_HAPPY_SRCS) $(DERIVED_ALEX_SRCS)
+
+#
+# `Standard' set of files to clean out.
+#
+MOSTLY_CLEAN_FILES += \
+ *.CKP *.ln *.BAK *.bak .*.bak *.o core a.out errs ,* *.a .emacs_*  \
+ tags TAGS *.ind *.ilg *.idx *.idx-prev *.aux *.aux-prev *.dvi *.log \
+ *.toc *.lot *.lof *.blg *.cb *_stub.c *_stub.h *.raw_s *.a.list
+
+#------------------------------------------------------------------
+
+# Directory in which DLLs are dumped so as not to get picked up by running
+# programs (e.g. ghc or hsc) that run in the build tree
+
+DLL_PEN = $(FPTOOLS_TOP)/dll
+
+#------------------------------------------------------------------
+#
+# Stylesheet for HTML generated from DocBook XML
+#
+
+FPTOOLS_CSS     = fptools.css
+FPTOOLS_CSS_ABS = $(FPTOOLS_TOP)/mk/$(FPTOOLS_CSS)
diff --git a/mk/ghc-recurse.mk b/mk/ghc-recurse.mk
new file mode 100644 (file)
index 0000000..2bb370d
--- /dev/null
@@ -0,0 +1,101 @@
+
+##################################################################
+#
+#              Recursive stuff
+#
+##################################################################
+
+# 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.
+#
+ifeq "$(way)" ""
+ifneq "$(SUBDIRS)" ""
+
+# we override the 'boot', 'all' and 'install' targets in the top
+# level Makefile. Some of the sub-projects also set 'boot' to empty.
+
+ifeq "$(NO_ALL_TARGET)" "YES"
+ALL_TARGET     =
+else
+ALL_TARGET     = all
+endif
+
+ifeq "$(NO_BOOT_TARGET)" "YES"
+BOOT_TARGET    =
+else
+BOOT_TARGET    = boot
+endif
+
+ifeq "$(NO_INSTALL_TARGET)" "YES"
+INSTALL_TARGET =
+INSTALL_DOCS_TARGET =
+else
+INSTALL_TARGET = install
+INSTALL_DOCS_TARGET = install-docs
+endif
+
+$(ALL_TARGET) docs runtests $(BOOT_TARGET) TAGS clean distclean mostlyclean maintainer-clean $(INSTALL_TARGET) $(INSTALL_DOCS_TARGET) html chm HxS ps dvi txt::
+       @echo "------------------------------------------------------------------------"
+       @echo "== Recursively making \`$@' in $(SUBDIRS) ..."
+       @echo "PWD = $(shell pwd)"
+       @echo "------------------------------------------------------------------------"
+# 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; \
+       if [ $$x_on_err -eq 0 ]; \
+           then echo "Won't exit on error due to MFLAGS: ${MFLAGS}"; \
+       fi; \
+       for i in $(SUBDIRS); do \
+         echo "------------------------------------------------------------------------"; \
+         echo "== $(MAKE) $@ $(MFLAGS);"; \
+         echo " in $(shell pwd)/$$i"; \
+         echo "------------------------------------------------------------------------"; \
+         $(MAKE) --no-print-directory -C $$i $(MFLAGS) $@ CLEAN_ALL_STAGES=YES; \
+         if [ $$? -eq 0 -o $$x_on_err -eq 0 ]; \
+             then echo "Finished making $@ in $$i": $$?; \
+             else echo "Failed making $@ in $$i": $$?; exit 1; \
+         fi; \
+       done
+       @echo "------------------------------------------------------------------------"
+       @echo "== Finished making \`$@' in $(SUBDIRS) ..."
+       @echo "PWD = $(shell pwd)"
+       @echo "------------------------------------------------------------------------"
+
+endif
+endif
+
+#
+# Selectively building subdirectories.
+#
+#
+ifneq "$(SUBDIRS)" ""
+$(SUBDIRS) ::
+         $(MAKE) -C $@ $(MFLAGS)
+endif
+
diff --git a/mk/ghc-suffix.mk b/mk/ghc-suffix.mk
new file mode 100644 (file)
index 0000000..2d34409
--- /dev/null
@@ -0,0 +1,366 @@
+#################################################################################
+#
+#                          suffix.mk
+#
+#              Suffix rules for fptools
+#
+#################################################################################
+
+# 
+# This file contain the default suffix rules for all the fptools projects.
+#
+
+
+# No need to define .SUFFIXES because we don't use any suffix rules
+# Instead we use gmake's pattern rules exlusively
+
+.SUFFIXES:
+
+# This declaration tells GNU make to delete the target if it has
+# changed and the command which created it exited with a non-zero exit
+# code.
+
+.DELETE_ON_ERROR:
+
+#-----------------------------------------------------------------------------
+# Haskell Suffix Rules
+
+# The $(odir) support is for building GHC, where we need to build three
+# different versions from the same sources.  See compiler/Makefile.
+ifneq "$(odir)" ""
+odir_ = $(odir)/
+else
+odir_ =
+endif
+
+# Turn off all the Haskell suffix rules if we're booting from .hc
+# files.  The file bootstrap.mk contains alternative suffix rules in
+# this case.
+ifneq "$(BootingFromHc)" "YES"
+
+$(odir_)%.$(way_)o : %.hs
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -c $< -o $@  -ohi $(basename $@).$(way_)hi
+       $(HC_POST_OPTS)
+
+$(odir_)%.$(way_)o : %.lhs      
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -c $< -o $@  -ohi $(basename $@).$(way_)hi
+       $(HC_POST_OPTS)
+
+# Now the rules for hs-boot files. 
+# Note that they do *not* do teh HS_PRE_OPTS / HS_POST_OPTS stuff,
+# (which concerns splitting) because they don't generate .o files
+$(odir_)%.$(way_)o-boot : %.hs-boot
+       $(HC) $(HC_OPTS) -c $< -o $@  -ohi $(basename $@).$(way_)hi-boot
+
+$(odir_)%.$(way_)o-boot : %.lhs-boot
+       $(HC) $(HC_OPTS) -c $< -o $@  -ohi $(basename $@).$(way_)hi-boot
+
+$(odir_)%.$(way_)hc : %.lhs     
+       $(RM) $@
+       $(HC) $(HC_OPTS) -C $< -o $@
+
+$(odir_)%.$(way_)hc : %.hs      
+       $(RM) $@
+       $(HC) $(HC_OPTS) -C $< -o $@
+
+$(odir_)%.$(way_)o : %.$(way_)hc
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -c $< -o $@
+       $(HC_POST_OPTS)
+
+$(odir_)%.$(way_)o : %.hc
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -c $< -o $@
+       $(HC_POST_OPTS)
+
+$(odir_)%.$(way_)s : %.$(way_)hc 
+       $(HC_PRE_OPTS)
+       $(HC) $(HC_OPTS) -S $< -o $@
+       $(HC_POST_OPTS)
+
+$(odir_)%.$(way_)hc : %.lhc
+       @$(RM) $@
+       $(UNLIT) $< $@
+       $(GENERATED_FILE) $@
+
+
+# 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).
+
+%.$(way_)hi : %.$(way_)o
+       @if [ ! -f $@ ] ; then \
+           echo Panic! $< exists, but $@ does not.; \
+           exit 1; \
+       else exit 0 ; \
+       fi                                                      
+
+%.$(way_)hi-boot : %.$(way_)o-boot
+       @if [ ! -f $@ ] ; then \
+           echo Panic! $< exists, but $@ does not.; \
+           exit 1; \
+       else exit 0 ; \
+       fi                                                      
+
+$(odir_)%.$(way_)hi : %.$(way_)hc
+       @if [ ! -f $@ ] ; then \
+           echo Panic! $< exists, but $@ does not.; \
+           exit 1; \
+       else exit 0 ; \
+       fi
+
+else # BootingFromHc
+
+# -----------------------------------------------------------------------------
+# suffix rules for building a .o from a .hc file in bootstrap mode.
+
+ifeq "$(BootingFromUnregisterisedHc)" "YES"
+
+# without mangling
+
+$(odir_)%.o : %.hc
+       $(CC) -x c $< -o $@ -c -O $(HC_BOOT_CC_OPTS) -I.  `echo $(patsubst -monly-%-regs, -DSTOLEN_X86_REGS=%, $(filter -monly-%-regs, $($*_HC_OPTS))) | sed 's/^$$/-DSTOLEN_X86_REGS=4/'`
+
+else
+
+# with mangling
+
+$(odir_)%.raw_s : %.hc
+       $(CC) -x c $< -o $@ -S -O $(HC_BOOT_CC_OPTS) -I.  `echo $(patsubst -monly-%-regs, -DSTOLEN_X86_REGS=%, $(filter -monly-%-regs, $($*_HC_OPTS))) | sed 's/^$$/-DSTOLEN_X86_REGS=4/'`
+
+$(odir_)%.s : $(odir_)%.raw_s
+       $(MANGLER) $< $@ $(patsubst -monly-%-regs, %, $(filter -monly-%-regs, $($*_HC_OPTS)))
+
+$(odir_)%.o : $(odir_)%.s
+       $(CC) -c -o $@ $<
+
+endif # not BootingFromUnregisterisedHc
+
+endif # BootingFromHc
+
+#-----------------------------------------------------------------------------
+# Happy Suffix Rules
+#
+%.hs : %.ly
+       $(HAPPY) $(HAPPY_OPTS) $<
+
+%.hs : %.y
+       $(HAPPY) $(HAPPY_OPTS) $<
+
+#-----------------------------------------------------------------------------
+# Alex Suffix Rules
+#
+
+%.hs : %.x
+       $(ALEX) $(ALEX_OPTS) $<
+
+#-----------------------------------------------------------------------------
+# hsc2hs Suffix Rules
+#
+ifneq "$(BootingFromHc)" "YES"
+%_hsc.c %_hsc.h %.hs : %.hsc
+       $(HSC2HS_INPLACE) $(HSC2HS_OPTS) $<
+       @touch $(patsubst %.hsc,%_hsc.c,$<)
+endif
+
+#-----------------------------------------------------------------------------
+# Green-card Suffix Rules
+#
+
+%.hs %_stub_ffi.c %_stub_ffi.h : %.gc
+       $(GREENCARD) $(GC_OPTS) $<
+
+%.lhs : %.gc
+       $(GREENCARD) $(GC_OPTS) $< -o $@
+
+%.gc : %.pgc
+       $(CPP) $(GC_CPP_OPTS) $< | perl -pe 's#\\n#\n#g' > $@
+
+#-----------------------------------------------------------------------------
+# C-related suffix rules
+
+# UseGhcForCc is only relevant when not booting from HC files.
+ifeq "$(UseGhcForCc) $(BootingFromHc)" "YES NO"
+
+$(odir_)%.$(way_)o : %.c
+       @$(RM) $@
+       $(HC) $(GHC_CC_OPTS) -c $< -o $@
+
+$(odir_)%.$(way_)o : %.$(way_)s
+       @$(RM) $@
+       $(HC) $(GHC_CC_OPTS) -c $< -o $@
+
+$(odir_)%.$(way_)o : %.S
+       @$(RM) $@
+       $(HC) $(GHC_CC_OPTS) -c $< -o $@
+
+$(odir_)%.$(way_)s : %.c
+       @$(RM) $@
+       $(HC) $(GHC_CC_OPTS) -S $< -o $@
+
+else
+
+$(odir_)%.$(way_)o : %.c
+       @$(RM) $@
+       $(CC) $(CC_OPTS) -c $< -o $@
+
+$(odir_)%.$(way_)o : %.$(way_)s
+       @$(RM) $@
+       $(AS) $(AS_OPTS) -o $@ $<
+
+$(odir_)%.$(way_)o : %.S
+       @$(RM) $@
+       $(CC) $(CC_OPTS) -c $< -o $@
+
+$(odir_)%.$(way_)s : %.c
+       @$(RM) $@
+       $(CC) $(CC_OPTS) -S $< -o $@
+
+endif
+
+# stubs are automatically generated and compiled by GHC
+%_stub.$(way_)o: %.o
+       @:
+
+# -----------------------------------------------------------------------------
+# Flex/lex
+
+%.c : %.flex
+       @$(RM) $@
+       $(FLEX) -t $(FLEX_OPTS) $< > $@
+%.c : %.lex
+       @$(RM) $@
+       $(FLEX) -t $(FLEX_OPTS) $< > $@
+
+#-----------------------------------------------------------------------------
+# Runtest rules for calling $(HC) on a single-file Haskell program
+
+%.runtest : %.hs
+       $(TIME) $(RUNTEST) $(HC) $(RUNTEST_OPTS) $<
+
+#-----------------------------------------------------------------------------
+# DocBook XML suffix rules
+#
+
+%.html : %.xml
+       $(XSLTPROC) --output $@ \
+                   --stringparam html.stylesheet $(FPTOOLS_CSS) \
+                   $(XSLTPROC_LABEL_OPTS) $(XSLTPROC_OPTS) \
+                   $(DIR_DOCBOOK_XSL)/html/docbook.xsl $<
+       cp $(FPTOOLS_CSS_ABS) .
+
+%/index.html : %.xml
+       $(RM) -rf $(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 $<
+       cp $(FPTOOLS_CSS_ABS) $(dir $@)
+
+# Note: Numeric labeling seems to be uncommon for HTML Help
+%-htmlhelp/index.html : %.xml
+       $(RM) -rf $(dir $@)
+       $(XSLTPROC) --stringparam base.dir $(dir $@) \
+                   --stringparam manifest.in.base.dir 1 \
+                   --stringparam htmlhelp.chm "..\\"$(basename $<).chm \
+                   $(XSLTPROC_OPTS) \
+                   $(DIR_DOCBOOK_XSL)/htmlhelp/htmlhelp.xsl $<
+
+%-htmlhelp2/collection.HxC : %.xml
+       $(RM) -rf $(dir $@)
+       $(XSLTPROC) --stringparam base.dir $(dir $@) \
+                   --stringparam use.id.as.filename 1 \
+                   --stringparam manifest.in.base.dir 1 \
+                   $(XSLTPROC_OPTS) \
+                   $(DIR_DOCBOOK_XSL)/htmlhelp2/htmlhelp2.xsl $<
+
+# TODO: Detect hhc & Hxcomp via autoconf
+#
+# Two obstacles here:
+#
+# * The reason for the strange "if" below is that hhc returns 0 on error and 1
+#   on success, the opposite of what shells and make expect.
+#
+# * There seems to be some trouble with DocBook indices, but the *.chm looks OK,
+#   anyway, therefore we pacify make by "|| true". Ugly...
+#
+%.chm : %-htmlhelp/index.html
+       ( cd $(dir $<) && if hhc htmlhelp.hhp ; then false ; else true ; fi ) || true
+
+%.HxS : %-htmlhelp2/collection.HxC
+       ( cd $(dir $<) && if Hxcomp -p collection.HxC -o ../$@ ; then false ; else true ; fi )
+
+%.ps : %.xml
+       $(DBLATEX) $(DBLATEX_OPTS) $< --ps -o $@
+
+%.pdf : %.xml
+       $(DBLATEX) $(DBLATEX_OPTS) $< --pdf -o $@
+
+%.dvi : %.xml
+       $(DBLATEX) $(DBLATEX_OPTS) $< --dvi -o $@
+
+#-----------------------------------------------------------------------------
+# Doc processing suffix rules
+#
+# ToDo: make these more robust
+#
+
+%.tex : %.tib
+       @$(RM) $*.tex $*.verb-t.tex
+       $(TIB) $*.tib
+       expand $*.tib-t.tex | $(VERBATIM) > $*.tex
+       @$(RM) $*.tib-t.tex
+
+%.ps : %.fig
+       @$(RM) $@
+       fig2dev -L ps $< $@
+
+%.tex : %.fig
+       @$(RM) $@
+       fig2dev -L latex $< $@
+
+#-----------------------------------------------------------------------------
+# Literate suffix rules
+
+%.prl : %.lprl
+       @$(RM) $@
+       $(UNLIT) $(UNLIT_OPTS) $< $@
+       $(GENERATED_FILE) $@
+
+%.c : %.lc
+       @$(RM) $@
+       $(UNLIT) $(UNLIT_OPTS) $< $@
+       $(GENERATED_FILE) $@
+
+%.h : %.lh
+       @$(RM) $@
+       $(UNLIT) $(UNLIT_OPTS) $< $@
+       $(GENERATED_FILE) $@
+
+#-----------------------------------------------------------------------------
+# Win32 resource files
+#
+# The default is to use the GNU resource compiler.
+#
+
+%.$(way_)o : %.$(way_)rc
+       @$(RM) $@
+       windres --preprocessor="$(CPP) -xc -DRC_INVOKED" $< $@
+
+#-----------------------------------------------------------------------------
+# Preprocessor suffix rule
+
+# Note use of -P option to prevent #line pragmas being left in the CPP
+# output.
+
+% : %.pp
+       @$(RM) $@
+       $(CPP) $(RAWCPP_FLAGS) -P $(CPP_OPTS) -x c $< | \
+       grep -v '^#pragma GCC' > $@
diff --git a/mk/ghc-target.mk b/mk/ghc-target.mk
new file mode 100644 (file)
index 0000000..be04669
--- /dev/null
@@ -0,0 +1,692 @@
+#################################################################################
+#
+#                      target.mk
+#
+#              Standard targets for GHC
+#
+#################################################################################
+
+#
+# This file contain three groups of target rules:
+#
+# 1.  GHC targets
+#      depend*
+#      runtests*
+#
+# 2.  GNU standard targets
+#      all*
+#      install* installcheck installdirs
+#       install-docs*
+#      clean* distclean* mostlyclean* maintainer-clean*
+#      tags*
+#      dvi ps (no info) GHC adds: pdf rtf html chm HxS
+#      check
+#
+# 3. Some of the above targets have a version that
+#    recursively invokes that target in sub-directories.
+#    This relies on the importing Makefile setting SUBDIRS
+#
+#    The recursive targets are marked with a * above
+#
+
+# 
+# 
+#
+
+##################################################################
+# Pre-compute the list of sources so we don't have to do this 
+# multiple times.  See paths.mk.
+
+PRE_SRCS := $(ALL_SRCS)
+
+###################################################################
+# Suffix rules for Haskell, C and literate 
+
+include $(TOP)/mk/ghc-suffix.mk
+
+##################################################################
+#              GHC standard targets
+#
+# depend:
+#
+#  The depend target has to cope with a set of files that may have
+#  different ways of computing their dependencies, i.e., a Haskell
+#  module's dependencies are computed differently from C files.
+#
+# Note that we don't compute dependencies automatically, i.e., have the
+# .depend file be a target that is dependent on the Haskell+C sources,
+# and then have the `depend' target depend on `.depend'. The reason for
+# this is that when GNU make is processing the `include .depend' statement
+# it records .depend as being a Makefile. Before doing any other processing,
+# `make' will try to check to see if the Makefiles are up-to-date. And,
+# surprisingly enough, .depend has a rule for it, so if any of the source
+# files change, it will be invoked, *regardless* of what target you're making.
+#
+# So, for now, the dependencies has to be re-computed manually via `make depend'
+# whenever a module changes its set of imports. Doing what was outlined above
+# is only a small optimisation anyway, it would avoid the recomputation of
+# dependencies if the .depend file was newer than any of the source modules.
+#
+.PHONY: depend
+
+# Compiler produced files that are targets of the source's imports.
+MKDEPENDHS_OBJ_SUFFICES=o
+
+ifneq "$(BootingFromHc)" "YES"
+PKGCONF_DEP = $(STAMP_PKG_CONF)
+endif
+
+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) $(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) $(foreach way,$(WAYS),-s $(way)) -- $(CC_OPTS) -- $(MKDEPENDC_SRCS) 
+endif
+ifneq "$(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
+
+ifeq "$(NO_BOOT_TARGET)" "YES"
+boot ::
+else
+boot :: depend
+endif
+
+##################################################################
+#              GNU Standard targets
+#
+#      Every Makefile should define the following targets
+# 
+# `all'
+#      Compile the entire program. This should be the default target.
+#      This target need not rebuild any documentation files
+# 
+# `install'
+#      Compile the program and copy the executables, libraries, and so on
+#      to the file names where they should reside for actual use. If
+#      there is a simple test to verify that a program is properly
+#      installed, this target should run that test.
+# 
+#      The commands should create all the directories in which files are
+#      to be installed, if they don't already exist. This includes the
+#      directories specified as the values of the variables prefix and
+#      exec_prefix , as well as all subdirectories that are needed. One
+#      way to do this is by means of an installdirs target as described
+#      below.
+# 
+#      Use `-' before any command for installing a man page, so that make
+#      will ignore any errors.  This is in case there are systems that
+#      don't have the Unix man page documentation system installed.
+# 
+# `clean'
+# 
+#      Delete all files from the current directory that are normally
+#      created by building the program.  Don't delete the files that
+#      record the configuration. Also preserve files that could be made
+#      by building, but normally aren't because the distribution comes
+#      with them.
+# 
+#      Delete `.dvi' files here if they are not part of the
+#      distribution.
+# 
+# `distclean'
+#      Delete all files from the current directory that are created by
+#      configuring or building the program. If you have unpacked the
+#      source and built the program without creating any other files,
+#      `make distclean' should leave only the files that were in the
+#      distribution.
+# 
+# `mostlyclean'
+#      Like `clean', but may refrain from deleting a few files that
+#      people normally don't want to recompile. For example, the
+#      `mostlyclean' target for GCC does not delete `libgcc.a', because
+#      recompiling it is rarely necessary and takes a lot of time.
+# 
+# `maintainer-clean'
+#      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, and so on.
+# 
+#      One exception, however: `make maintainer-clean' should not delete
+#      `configure' even if `configure' can be remade using a rule in the
+#      Makefile. More generally, `make maintainer-clean' should not delete
+#      anything that needs to exist in order to run `configure' and then
+#      begin to build the program.
+# 
+# `TAGS'
+#      Update a tags table for this program.
+# 
+# `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.
+#
+# `check'
+#      Perform self-tests (if any). The user must build the program
+#      before running the tests, but need not install the program; you
+#      should write the self-tests so that they work when the program is
+#      built but not installed.
+# 
+# The following targets are suggested as conventional names, for programs
+# in which they are useful.
+# 
+# installcheck
+#      Perform installation tests (if any). The user must build and
+#      install the program before running the tests. You should not
+#      assume that `$(bindir)' is in the search path.
+# 
+# installdirs
+#      It's useful to add a target named `installdirs' to create the
+#      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.
+#      (GHC: we use a close relative of the suggested script, situated
+#       in glafp-utils/mkdirhier -- SOF)
+
+
+
+
+###########################################
+#
+#      Targets: "all"
+#
+###########################################
+
+# For each of these variables that is defined
+# we generate one "all" rule and one rule for the variable itself:
+#
+#      HS_PROG         Haskell program
+#      C_PROG          C program
+#      LIBRARY         Library
+#
+# For details of exactly what rule is generated, see the
+# relevant section below
+
+.PHONY: all
+
+#----------------------------------------
+#      Haskell programs
+
+ifneq "$(HS_PROG)" ""
+all :: $(HS_PROG)
+
+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
+
+#----------------------------------------
+#      C programs
+
+ifneq "$(C_PROG)" ""
+all :: $(C_PROG)
+
+$(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)
+
+ifneq "$(way)" "i"
+define BUILD_STATIC_LIB
+$(RM) $@
+$(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
+# up the object files. Test for whether the library being
+# built is consisting of Haskell files by (hackily) checking
+# whether HS_SRCS is empty or not.
+#
+
+# can't split objs in way 'u', so we disable it here
+ifeq "$(way)" "u"
+SplitObjs = NO
+endif
+
+ifneq "$(HS_SRCS)" ""
+ifeq "$(SplitObjs)" "YES"
+
+SRC_HC_OPTS += -split-objs
+
+# 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
+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):
+
+#
+# If (Haskell) object files are split, cleaning up 
+# consist of descending into the directories where
+# the myriads of object files have been put.
+#
+
+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
+
+endif # $(SplitObjs)
+endif # $(HS_SRCS)
+
+#
+# Remove local symbols from library objects if requested.
+#
+
+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
+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
+ifeq "$(LIBRARY:%.dylib=YES)" "YES"
+$(LIBRARY): $(LIBOBJS) $(LIB_DEPS)
+       $(HC) -shared -dynamic -o $@ $(STUBOBJS) $(LIBOBJS) $(LIB_LD_OPTS)
+else
+ifeq "$(LIBRARY:%.dll=YES)" "YES"
+#----------------------------------------
+#      Building Win32 DLLs
+#
+$(LIBRARY): $(LIBOBJS) $(LIBRARY).o $(LIB_DEPS)
+       $(HC) -shared -dynamic -o $@ $(STUBOBJS) $(LIBOBJS) $(LIBRARY).o $(LIB_LD_OPTS)
+
+DLLTOOL=dlltool
+
+$(LIBRARY).def: $(LIBOBJS)
+       $(DLLTOOL) -D $(LIBRARY) --output-def $@ --export-all $(LIBOBJS)
+
+$(LIBRARY).o:
+       $(DLLTOOL) -D $(LIBRARY) --output-exp $(LIBRARY).o $(LIBOBJS)
+
+# 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 $@
+
+#
+# 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.)
+#
+# Note: this will not work as expected with Cygwin B20.1; you need a more recent
+#       version of binutils (to pick up windres bugfixes.)
+
+ifndef DLL_VERSION
+DLL_VERSION=$(ProjectVersion)
+endif
+
+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
+
+ifndef EXE_VERSION_NAME
+EXE_VERSION_NAME="http://www.haskell.org/ghc"
+endif
+
+ifndef EXE_DESCRIPTION
+EXE_DESCRIPTION="A GHC-compiled binary"
+endif
+
+#
+# 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
+# 
+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)))
+
+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 = ""
+
+##############################################################################
+#
+#      Targets: check tags show
+#
+##############################################################################
+
+#------------------------------------------------------------
+#                      Check
+
+.PHONY: check
+
+check:: $(TESTS)
+       @for i in $(filter-out %.lhs .hs, $(TESTS)) ''; do      \
+         if (test -f "$$i"); then              \
+           echo Running: `basename $$i` ;      \
+           cd test; `basename $$i` ;           \
+         fi;                                   \
+       done;
+
+#------------------------------------------------------------
+#                      Tags
+
+.PHONY: TAGS tags
+
+tags TAGS:: $(TAGS_HS_SRCS) $(TAGS_C_SRCS)
+       @$(RM) TAGS
+       @touch TAGS
+ifneq "$(TAGS_HS_SRCS)" ""
+       $(HSTAGS) $(HSTAGS_OPTS) $(TAGS_HS_SRCS)
+endif
+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` ) 2>/dev/null || echo TAGS file generated, perhaps copy over to source tree?
+
+################################################################################
+#
+#                      DocBook XML Documentation
+#
+################################################################################
+
+.PHONY: html html-no-chunks chm HxS fo dvi ps pdf
+
+ifneq "$(XML_DOC)" ""
+
+all :: $(XMLDocWays)
+
+# multi-file XML document: main document name is specified in $(XML_DOC),
+# sub-documents (.xml files) listed in $(XML_SRCS).
+
+ifeq "$(XML_SRCS)" ""
+XML_SRCS = $(wildcard *.xml)
+endif
+
+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))
+
+$(XML_HTML) $(XML_NO_CHUNKS_HTML) $(XML_FO) $(XML_DVI) $(XML_PS) $(XML_PDF) :: $(XML_SRCS)
+
+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 += $(XML_HTML_NO_CHUNKS) $(XML_FO) $(XML_DVI) $(XML_PS) $(XML_PDF)
+
+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
+#
+##############################################################################
+
+# 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.
+
+.PHONY: mostlyclean clean distclean maintainer-clean
+
+mostlyclean::
+       rm -f $(MOSTLY_CLEAN_FILES)
+
+# extraclean is used for adding actions to the clean target.
+extraclean::
+
+clean:: extraclean
+       rm -f $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES)
+
+distclean:: extraclean
+       rm -f $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES) $(DIST_CLEAN_FILES)
+
+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 $(MOSTLY_CLEAN_FILES) $(CLEAN_FILES) $(DIST_CLEAN_FILES) $(MAINTAINER_CLEAN_FILES)
+
+################################################################################
+#
+#                      Way management
+#
+################################################################################
+
+# Here is the ingenious jiggery pokery that allows you to build multiple versions
+# of a program in a single build tree.
+#
+# The ways setup requires the following variables to be set:
+#
+# 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.
+# When do we do this recursion?  Answer: whenever the programmer
+# asks make to make a target that involves a way suffix.
+# We must remember *not* to recurse again; but that's easy: we
+# just see if $(way) is set:
+
+ifeq "$(way)" ""
+
+# If $(WAYS) = p mc, then WAY_TARGETS expands to
+#      %.p_lhs %.p_hs %.p_o ... %.mc_lhs %.p_hs ...
+# and OTHER_WAY_TARGETS to
+#      %_p.a %_p %_mc.a %_mc
+# where the suffixes are from $(SUFFIXES)
+#
+# We have to treat libraries and "other" targets differently, 
+# because their names are of the form
+#      libHS_p.a and Foo_p
+# whereas everything else has names of the form
+#      Foo.p_o
+
+FPTOOLS_SUFFIXES := o hi hc
+
+WAY_TARGETS     = $(foreach way,$(WAYS),$(foreach suffix, $(FPTOOLS_SUFFIXES), %.$(way)_$(suffix)))
+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
+# $(subst .,.p_o)  returns p_o
+# $(subst _,.,p_o) returns p.o   (clever)
+# $(basename p.o)  returns p
+# 
+$(WAY_TARGETS) :
+       $(MAKE) way=$(basename $(subst _,.,$(subst .,,$(suffix $@)))) $@
+
+# $(@F) will be something like libHS_p.a, or Foo_p
+# $(basename $(@F)) will be libHS_p, or Foo_p
+# The sed script extracts the "p" part.
+
+$(LIB_WAY_TARGETS) :
+       $(MAKE) $(MFLAGS) $@ way=$(subst .,,$(suffix $(subst _,.,$(basename $@))))
+
+$(LIB_WAY_TARGETS_DYN) :
+       $(MAKE) $(MFLAGS) $@ way=$(patsubst _dyn,dyn,$(subst .,,$(suffix $(subst _,.,$(basename $(subst -ghc$(ProjectVersion),,$@)))))_dyn)
+
+endif  # if way
+
+# -------------------------------------------------------------------------
+# Object and interface files have suffixes tagged with their ways
+
+ifneq "$(way)" ""
+SRC_HC_OPTS += -hisuf $(way_)hi -hcsuf $(way_)hc -osuf $(way_)o
+endif
+
+# -------------------------------------------------------------------------
+# Rules to invoke the current target recursively for each way
+
+ifneq "$(strip $(WAYS))" ""
+ifeq "$(way)" ""
+
+# NB: the targets exclude 
+#      boot runtests
+# since these are way-independent
+all docs TAGS clean distclean mostlyclean maintainer-clean install ::
+       @echo "------------------------------------------------------------------------"
+       @echo "== Recursively making \`$@' for ways: $(WAYS) ..."
+       @echo "PWD = $(shell pwd)"
+       @echo "------------------------------------------------------------------------"
+# 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 "== $(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 "== Finished recursively making \`$@' for ways: $(WAYS) ..."
+       @echo "PWD = $(shell pwd)"
+       @echo "------------------------------------------------------------------------"
+
+endif
+endif
+
+include $(TOP)/mk/ghc-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)
+
index 339d0f1..50455e7 100644 (file)
@@ -115,10 +115,7 @@ endif # GHCI
 # We do this at the end for cosmetic reasons: it means that the "normal-way"
 # runtests will precede the "other-way" recursive invocations of make
 
-NOFIB_TOP := $(TOP)
-TOP := $(TOP)/..
-include $(TOP)/mk/target.mk
-TOP:=$(NOFIB_TOP)
+include $(NOFIB_TOP)/mk/ghc-target.mk
 
 # Override suffix rules
 include $(NOFIB_TOP)/mk/suffix.mk
diff --git a/runstdtest/Makefile b/runstdtest/Makefile
new file mode 100644 (file)
index 0000000..1d2ea86
--- /dev/null
@@ -0,0 +1,15 @@
+TOP=..
+include $(TOP)/mk/boilerplate.mk
+
+PROG=runstdtest
+CLEAN_FILES += $(PROG)
+all::
+       $(RM) -f $(PROG)
+       echo '#!$(PERL)'                               >> $(PROG)
+       echo '$$RM             = "$(RM)";'             >> $(PROG)
+       echo '$$DEFAULT_TMPDIR = "$(DEFAULT_TMPDIR)";' >> $(PROG)
+       echo '$$CONTEXT_DIFF   = "$(CONTEXT_DIFF)";'   >> $(PROG)
+       cat $(PROG).prl                                >> $(PROG)
+       $(EXECUTABLE_FILE) $(PROG)
+
+boot :: all
diff --git a/runstdtest/runstdtest.prl b/runstdtest/runstdtest.prl
new file mode 100644 (file)
index 0000000..039c253
--- /dev/null
@@ -0,0 +1,571 @@
+#
+# The perl script requires the following variables to be bound
+# to something meaningful before it will operate correctly:
+#   
+#   DEFAULT_TMPDIR
+#   CONTEXT_DIFF
+#   RM
+#
+# Given:
+#      * a program to run (1st arg)
+#      * some "command-line opts" ( -O<opt1> -O<opt2> ... )
+#          [default: anything on the cmd line this script doesn't recognise ]
+#        the first opt not starting w/ "-" is taken to be an input
+#        file and (if it exists) is grepped for "what's going on here"
+#        comments (^-- !!!).
+#      * a file to feed to stdin ( -i<file> ) [default: /dev/null ]
+#      * a "time" command to use (-t <cmd>).
+#
+#      * alternatively, a "-script <script>" argument says: run the
+#        named Bourne-shell script to do the test.  It's passed the
+#        pgm-to-run as the one-and-only arg.
+#
+# Run the program with those options and that input, and check:
+# if we get...
+# 
+#      * an expected exit status ( -x <val> ) [ default 0 ]
+#      * expected output on stdout ( -o1 <file> ) [ default /dev/null ]
+#              ( we'll accept one of several...)
+#      * expected output on stderr ( -o2 <file> ) [ default /dev/null ]
+#              ( we'll accept one of several...)
+#
+#      (if the expected-output files' names end in .Z, then
+#       they are uncompressed before doing the comparison)
+# 
+# (This is supposed to be a "prettier" replacement for runstdtest.)
+#
+#      Flags
+#      ~~~~~
+#      -accept-output  replace output files with the ones actually generated by running
+#                      the program
+#
+($Pgm = $0) =~ s|.*/||;
+$Verbose = 0;
+$SaveStderr = 0;
+$SaveStdout = 0;
+$StdoutBinary = 0;
+$StderrBinary = 0;
+$Status = 0;
+@PgmArgs = ();
+$PgmFail=0;
+$PgmExitStatus = 0;
+$PgmStdinFile  = '/dev/null';
+if ( $ENV{'TMPDIR'} ) { # where to make tmp file names
+    $TmpPrefix = $ENV{'TMPDIR'};
+} else {
+    $TmpPrefix ="$DEFAULT_TMPDIR";
+    $ENV{'TMPDIR'} = "$DEFAULT_TMPDIR"; # set the env var as well
+}
+# If this is Cygwin, ignore eol and CR characters.
+# Perhaps required for MSYS too, although the cygpath
+# bit is hopefully unnecessary.
+if ( `uname | grep CYGWIN` ) {
+    $CONTEXT_DIFF=$CONTEXT_DIFF . " --strip-trailing-cr" ;
+    $TmpPrefix = `cygpath -m $TmpPrefix | tr -d \\\\n`;
+}
+$ScriptFile = "$TmpPrefix/run_me$$";
+$DefaultStdoutFile = "$TmpPrefix/no_stdout$$"; # can't use /dev/null (e.g. Alphas)
+$DefaultStderrFile = "$TmpPrefix/no_stderr$$";
+@PgmStdoutFile = ();
+@PgmStderrFile = ();
+$PreScript = '';
+$PostScript = '';
+$TimeCmd = 'time';
+$StatsFile = "$TmpPrefix/stats$$";
+$CachegrindStats = "cachegrind.out.summary";
+$SysSpecificTiming = '';
+$SysCPUCounting = 0; # Use CPU counters
+$Cachegrind = 'no';
+$Counters = "";
+
+die "$Pgm: program to run not given as first argument\n" if $#ARGV < 0;
+$ToRun = $ARGV[0]; shift(@ARGV);
+# avoid picking up same-named thing from somewhere else on $PATH...
+$ToRun = "./$ToRun" if -e "./$ToRun";
+
+arg: while ($_ = $ARGV[0]) {
+    shift(@ARGV);
+    
+    /^--$/     && do { # let anything past after --
+                       push(@PgmArgs, @ARGV);
+                       last arg; };
+
+    /^-v$/            && do { $Verbose = 1; next arg; };
+    /^-accept-output-stderr$/ && do { $SaveStderr = 1; next arg; };
+    /^-accept-output-stdout$/ && do { $SaveStdout = 1; next arg; };
+    /^-accept-output$/        && do { $SaveStdout = 1; $SaveStderr = 1; next arg; };
+
+    /^-stdout-binary/ && do { $StdoutBinary=1; next arg; };
+    /^-stderr-binary/ && do { $StderrBinary=1; next arg; };
+
+    /^-O(.*)/  && do { push(@PgmArgs, &grab_arg_arg('-O',$1)); next arg; };
+    /^-i(.*)/  && do { $PgmStdinFile = &grab_arg_arg('-i',$1);
+                       $Status++,
+                       print STDERR "$Pgm: bogus -i input file: $PgmStdinFile\n"
+                           if $PgmStdinFile !~ /^\/dev\/.*$/ && ! -f $PgmStdinFile;
+                       next arg; };
+    /^-fail/    && do { $PgmFail=1; next arg; };
+    /^-x(.*)/  && do { $PgmExitStatus = &grab_arg_arg('-x',$1);
+                       $Status++ ,
+                       print STDERR "$Pgm: bogus -x expected exit status: $PgmExitStatus\n"
+                           if $PgmExitStatus !~ /^\d+$/;
+                       next arg; };
+    /^-o1(.*)/ && do { $out_file = &grab_arg_arg('-o1',$1);
+                       push(@PgmStdoutFile, $out_file);
+                       next arg; };
+    /^-o2(.*)/ && do { $out_file = &grab_arg_arg('-o2',$1);
+                       push(@PgmStderrFile, $out_file);
+                       next arg; };
+    /^-prescript(.*)/  && do { $PreScript = &grab_arg_arg('-prescript',$1);
+                               next arg; };
+    /^-postscript(.*)/ && do { $PostScript = &grab_arg_arg('-postscript',$1);
+                               next arg; };
+    /^-script/ && do { print STDERR "$Pgm: -script argument is obsolete;\nUse -prescript and -postscript instead.\n";
+                   $Status++;
+                   next arg; };
+    /^-(ghc|hbc)-timing$/ && do { $SysSpecificTiming = $1;
+                                 next arg; };
+    /^-cpu-counting-(.)$/ && do { $SysCPUCounting = "$1";
+                                 next arg; };
+    /^-cachegrind$/ && do { $SysSpecificTiming = 'ghc-instrs';
+                           $Cachegrind = 'yes'; 
+                           next arg };
+    /^-t(.*)/  && do { $TimeCmd = &grab_arg_arg('-t', $1); next arg; };
+
+    # anything else is taken to be a pgm arg
+    push(@PgmArgs, $_);
+}
+
+foreach $out_file ( @PgmStdoutFile ) {
+    if ( ! -f $out_file && !$SaveStdout ) {
+           print STDERR "$Pgm: warning: expected-stdout file missing: $out_file\n";
+           pop(@PgmStdoutFile);
+    }
+}
+
+foreach $out_file ( @PgmStderrFile ) {
+    if ( ! -f $out_file && !$SaveStderr ) {
+           print STDERR "$Pgm: warning: expected-stderr file missing: $out_file\n";
+           pop(@PgmStderrFile);
+    }
+}
+
+exit 1 if $Status;
+
+# add on defaults if none specified
+@PgmStdoutFile = ( $DefaultStdoutFile ) if $#PgmStdoutFile < 0;
+@PgmStderrFile = ( $DefaultStderrFile ) if $#PgmStderrFile < 0;
+
+# tidy up the pgm args:
+# (1) look for the "first input file"
+#     and grep it for "interesting" comments (-- !!! )
+# (2) quote any args w/ whitespace in them.
+$grep_done = 0;
+foreach $a ( @PgmArgs ) {
+    if (! $grep_done && $a !~ /^-/ && -f $a) {
+       print `egrep "^--[ ]?!!!" $a`;
+       $grep_done = 1;
+    }
+    if ($a =~ /\s/ || $a =~ /'/) {
+       $a =~ s/'/\\'/g;    # backslash the quotes;
+       $a = "\"$a\"";      # quote the arg
+    }
+}
+
+# deal with system-specific timing options
+$TimingMagic = '';
+if ( $SysSpecificTiming =~ /^ghc/ ) {
+    if ($SysCPUCounting) {
+        # Count specified CPU events
+        $cpu_counting_ghc = "-a$SysCPUCounting";
+    } else {
+        $cpu_counting_ghc = "";
+    }
+    $TimingMagic = "+RTS -S$StatsFile $cpu_counting_ghc -RTS"
+} elsif ( $SysSpecificTiming eq 'hbc' ) {
+    $TimingMagic = "-S$StatsFile";
+}
+
+if ($PreScript ne '') {
+    local($to_do);
+    $PreScriptLines = `cat $PreScript`;
+    $PreScriptLines =~ s/\r//g;
+} else {
+    $PreScriptLines = '';
+}
+
+if ($PostScript ne '') {
+    local($to_do);
+    $PostScriptLines = `cat $PostScript`;
+    $PostScriptLines =~ s/\r//g;
+    $PostScriptLines =~ s#\$o1#$TmpPrefix/runtest$$.1#gm;
+    $PostScriptLines =~ s#\$o2#$TmpPrefix/runtest$$.2#gm;
+# The postfix 'm' deals with recent versions of 
+# Perl that removed the $* feature
+} else {
+    $PostScriptLines = '';
+}
+
+# OK, so we're gonna do the normal thing...
+
+if ($Cachegrind eq 'yes') {
+  $CachegrindPrefix = "valgrind --tool=cachegrind --log-fd=9 9>$CachegrindStats";
+} else {
+  $CachegrindPrefix = '';
+}
+
+$Script = <<EOSCRIPT;
+#! /bin/sh
+myexit=0
+diffsShown=0
+rm -f $DefaultStdoutFile $DefaultStderrFile
+cat /dev/null > $DefaultStdoutFile
+cat /dev/null > $DefaultStderrFile
+$PreScriptLines
+$SpixifyLine1
+$TimeCmd /bin/sh -c \'$CachegrindPrefix $ToRun $TimingMagic @PgmArgs < $PgmStdinFile 1> $TmpPrefix/runtest$$.1.raw 2> $TmpPrefix/runtest$$.2.raw 3> $TmpPrefix/runtest$$.3.raw\'
+progexit=\$?
+if [ "$StdoutBinary" = "0" ]; then
+    dos2unix < $TmpPrefix/runtest$$.1.raw > $TmpPrefix/runtest$$.1
+else
+    cp $TmpPrefix/runtest$$.1.raw $TmpPrefix/runtest$$.1
+fi
+if [ "$StderrBinary" = "0" ]; then
+    dos2unix < $TmpPrefix/runtest$$.2.raw > $TmpPrefix/runtest$$.2
+else
+    cp $TmpPrefix/runtest$$.2.raw $TmpPrefix/runtest$$.2
+fi
+dos2unix < $TmpPrefix/runtest$$.3.raw > $TmpPrefix/runtest$$.3
+if [ \$progexit -eq 0 ] && [ $PgmFail -ne 0 ]; then
+    echo $ToRun @PgmArgs \\< $PgmStdinFile
+    echo "****" expected a failure, but was successful
+    myexit=1
+fi
+if [ \$progexit -ne $PgmExitStatus ] && [ $PgmFail -eq 0 ]; then
+    echo $ToRun @PgmArgs \\< $PgmStdinFile
+    echo "****" expected exit status $PgmExitStatus not seen \\; got \$progexit
+    myexit=1
+else
+    $PostScriptLines
+    hit='NO'
+    for out_file in @PgmStdoutFile ; do
+       if sed "s/\r\$//" $TmpPrefix/runtest$$.1 | cmp -s \$out_file - ; then
+           hit='YES'
+       fi
+    done
+    if [ \$hit = 'NO' ] ; then
+       echo $ToRun @PgmArgs \\< $PgmStdinFile
+       echo expected stdout not matched by reality
+       orig_file="$PgmStdoutFile[0]";
+       [ ! -f \$orig_file ] && orig_file="/dev/null"
+       ${CONTEXT_DIFF} \$orig_file $TmpPrefix/runtest$$.1
+       myexit=\$?
+       diffsShown=1
+    fi
+    if [ $SaveStdout = 1 ] && 
+       [ $PgmStdoutFile[0] != $DefaultStdoutFile ] && [ -s $TmpPrefix/runtest$$.1 ]; then
+       echo Saving away stdout output in $PgmStdoutFile[0] ...
+       if [ -f $PgmStdoutFile[0] ]; then
+            rm -f $PgmStdoutFile[0].bak
+            cp $PgmStdoutFile[0] $PgmStdoutFile[0].bak
+       fi;
+       cp $TmpPrefix/runtest$$.1 $PgmStdoutFile[0]
+    fi
+fi
+
+hit='NO'
+for out_file in @PgmStderrFile ; do
+    if sed "s/\r\$//" $TmpPrefix/runtest$$.2 | cmp -s \$out_file - ; then
+       hit='YES'
+    fi
+done
+if [ \$hit = 'NO' ] ; then
+    echo $ToRun @PgmArgs \\< $PgmStdinFile
+    echo expected stderr not matched by reality
+    orig_file="$PgmStderrFile[0]"
+    [ ! -f \$orig_file ] && orig_file="/dev/null"
+    ${CONTEXT_DIFF} \$orig_file $TmpPrefix/runtest$$.2
+    myexit=\$?
+    diffsShown=1
+fi
+if [ $SaveStderr = 1 ] &&
+   [ $PgmStderrFile[0] != $DefaultStderrFile ] && [ -s $TmpPrefix/runtest$$.2 ]; then
+       echo Saving away stderr output in $PgmStderrFile[0] ...
+       if [ -f $PgmStderrFile[0] ]; then
+          rm -f $PgmStderrFile[0].bak
+          cp $PgmStderrFile[0] $PgmStderrFile[0].bak
+       fi;
+       cp $TmpPrefix/runtest$$.2 $PgmStderrFile[0]
+fi
+
+${RM} core $ToRunOrig.spix $DefaultStdoutFile $DefaultStderrFile $TmpPrefix/runtest$$.1 $TmpPrefix/runtest$$.2 $TmpPrefix/runtest$$.3 $TmpPrefix/runtest$$.1.raw $TmpPrefix/runtest$$.2.raw $TmpPrefix/runtest$$.3.raw
+exit \$myexit
+EOSCRIPT
+
+# bung script into a file
+open(SCR, "> $ScriptFile") || die "Failed opening script file $ScriptFile!\n";
+print SCR $Script;
+close(SCR) || die "Failed closing script file!\n";
+chmod 0755, $ScriptFile;
+
+print STDERR $Script if $Verbose;
+
+&run_something($ScriptFile);
+
+if ( $SysSpecificTiming eq '' ) {
+    unlink $StatsFile;
+    unlink $ScriptFile;
+    exit 0;
+}
+
+&process_stats_file();
+&process_cachegrind_files() if $Cachegrind eq 'yes';
+
+# print out what we found
+print STDERR "<<$SysSpecificTiming: ";
+if ( $Cachegrind ne 'yes') {
+       print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed), $Gc0Time GC(0) ($Gc0Elapsed elapsed), $Gc1Time GC(1) ($Gc1Elapsed elapsed), $Balance balance$Counters";
+} else {
+       print STDERR "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $GCWork bytes GC work, ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed), $Gc0Time GC(0) ($Gc0Elapsed elapsed), $Gc1Time GC(1) ($Gc1Elapsed elapsed), $Balance balance, $TotInstrs instructions, $TotReads memory reads, $TotWrites memory writes, $TotMisses L2 cache misses";
+};
+print STDERR " :$SysSpecificTiming>>\n";
+
+# OK, party over
+unlink $StatsFile;
+unlink $ScriptFile;
+exit 0;
+
+sub grab_arg_arg {
+    local($option, $rest_of_arg) = @_;
+    
+    if ($rest_of_arg ne "") {
+       return($rest_of_arg);
+    } elsif ($#ARGV >= 0) {
+       local($temp) = $ARGV[0]; shift(@ARGV); 
+       return($temp);
+    } else {
+       print STDERR "$Pgm: no argument following $option option\n";
+       $Status++;
+    }
+}
+
+sub run_something {
+    local($str_to_do) = @_;
+
+#   print STDERR "$str_to_do\n" if $Verbose;
+
+    local($return_val) = 0;
+    system($str_to_do);
+    $return_val = $?;
+
+    if ($return_val != 0) {
+#ToDo: this return-value mangling is wrong
+#      local($die_msg) = "$Pgm: execution of the $tidy_name had trouble";
+#      $die_msg .= " (program not found)" if $return_val == 255;
+#      $die_msg .= " ($!)" if $Verbose && $! != 0;
+#      $die_msg .= "\n";
+       unlink $ScriptFile;
+       unlink $StatsFile;
+
+       exit (($return_val == 0) ? 0 : 1);
+    }
+}
+
+sub process_stats_file {
+
+    # OK, process system-specific stats file
+    if ( $SysSpecificTiming =~ /^ghc/ ) {
+
+       #NB: nearly the same as in GHC driver's -ghc-timing stuff
+
+       open(STATS, $StatsFile) || die "Failed when opening $StatsFile\n";
+
+       local($max_live)    = 0; 
+       local($tot_live)    = 0; # for calculating residency stuff
+       local($tot_samples) = 0;
+       local($into_gc_counters) = 0; # once we reach into the GC counters part
+       local($counters) = "";
+       local($counter) = "";
+       local($count) = 0;
+
+       $GCWork = 0;
+        $GCs = 0;
+        $Balance = 1;
+       while (<STATS>) {
+           if (! /Gen:\s+0/ && /^\s*\d+\s+\d+\s+(\d+)\s+\d+\.\d+/ ) {
+               $max_live = $1 if $max_live < $1;
+               $tot_live += $1;
+               $tot_samples += 1;
+           }
+
+           $BytesAlloc = $1 if /^\s*([0-9,]+) bytes allocated in the heap/;
+           
+           if (/^\s*([0-9,]+) bytes copied during GC/) {
+              $tmp = $1;
+              $tmp =~ s/,//g;
+              $GCWork += $tmp;
+            }
+
+#          if ( /^\s*([0-9,]+) bytes maximum residency .* (\d+) sample/ ) {
+#              $MaxResidency = $1; $ResidencySamples = $2;
+#          }
+
+           $GCs += $1 if /^\s*Generation\s*\d+:\s*([0-9,]+) collections/;
+
+           if ( /^\s+([0-9]+)\s+M[Bb] total memory/ ) {
+               $TotMem = $1;
+           }
+
+           if ( /^\s*INIT\s+time\s*(-*\d+\.\d\d)s\s*\(\s*(-*\d+\.\d\d)s elapsed\)/ ) {
+               $InitTime = $1; $InitElapsed = $2;
+           } elsif ( /^\s*MUT\s+time\s*(-*\d+\.\d\d)s\s*\(\s*(-*\d+\.\d\d)s elapsed\)/ ) {
+               $MutTime = $1; $MutElapsed = $2;
+           } elsif ( /^\s*GC\s+time\s*(-*\d+\.\d\d)s\s*\(\s*(-*\d+\.\d\d)s elapsed\)/ ) {
+               $GcTime = $1; $GcElapsed = $2;
+           }
+
+            if (/Generation (\d+):\s*\d+ collections,\s*\d+ parallel,\s*(-*\d+\.\d\d)s\s*,\s*(-*\d+\.\d\d)s elapsed/) {
+                if ($1 == 0) {
+                    $Gc0Time = $2; $Gc0Elapsed = $3;
+                } elsif ($1 == 1) {
+                    $Gc1Time = $2; $Gc1Elapsed = $3;
+                }
+            }
+
+            if (/work balance: ([0-9.]+)/) {
+                $Balance = $1;
+            }
+
+
+           if ( /CPU GC counters/ ) {
+               # Counters that follow correspond to GC
+               $into_gc_counters = 1;
+           }
+
+           if ( /^\s+\(([A-Z_0-9]+)\)\s+:\s+([0-9,]+)/ ) {
+               $counter = $1;
+               $count   = $2;
+               $count =~ s/,//g; # Remove commas in numbers
+               # Pretty printing elements of a list with type [(String,[Float])]
+                # It's a bit lame for passing values but it works.
+               if($into_gc_counters) {
+                   $counters = "$counters(\"GC:$counter\",[$count]),";
+               } else {
+                   $counters = "$counters(\"$counter\",[$count]),";
+               }
+           }
+
+           if ( /^\s+\(([A-Z_0-9]+)\)\s+\%\s+of\s+\(([A-Z_0-9]+)\)\s+:\s+([0-9.]+)/ ) {
+               $counter = "$1/$2"; # Relative quantity
+               $count   = $3;
+               # Pretty printing elements of a list with type [(String,[Float])]
+                # It's a bit lame for passing values but it works.
+               if($into_gc_counters) {
+                   $counters = "$counters(\"GC:$counter\",[$count]),";
+               } else {
+                   $counters = "$counters(\"$counter\",[$count]),";
+               }
+           }
+
+       }
+       close(STATS) || die "Failed when closing $StatsFile\n";
+       if ( $tot_samples > 0 ) {
+           $ResidencySamples = $tot_samples;
+           $MaxResidency = $max_live;
+           $AvgResidency = int ($tot_live / $tot_samples) ;
+       }
+
+       if ( length($counters) == 0 ) {
+           $Counters = "";
+       } else {
+           chop($counters); # remove trailing comma from the last entry
+           $Counters = " [$counters]";
+       }
+
+    } elsif ( $SysSpecificTiming eq 'hbc' ) {
+
+       open(STATS, $StatsFile) || die "Failed when opening $StatsFile\n";
+       while (<STATS>) {
+           $BytesAlloc = $1 if /^\s*([0-9]+) bytes allocated from the heap/;
+
+           $GCs = $1 if /^\s*([0-9]+) GCs?,$/;
+
+           if ( /^\s*(\d+\.\d\d) \((\d+\.\d)\) seconds total time,$/ ) {
+               $MutTime = $1; $MutElapsed = $2; # will fix up later
+
+               $InitTime = 0; $InitElapsed = 0; # hbc doesn't report these
+
+           } elsif ( /^\s*(\d+\.\d\d) \((\d+\.\d)\) seconds GC time/ ) {
+               $GcTime = $1; $GcElapsed = $2;
+
+               # fix up mutator time now
+               $MutTime    = sprintf("%.2f", ($MutTime    - $GcTime));
+               $MutElapsed = sprintf("%.1f", ($MutElapsed - $GcElapsed));
+           }
+       }
+       close(STATS) || die "Failed when closing $StatsFile\n";
+    }
+
+    # warn about what we didn't find
+    print STDERR "Warning: BytesAlloc not found in stats file\n" unless defined($BytesAlloc);
+    print STDERR "Warning: GCs not found in stats file\n" unless defined($GCs);
+    print STDERR "Warning: InitTime not found in stats file\n" unless defined($InitTime);
+    print STDERR "Warning: InitElapsed not found in stats file\n" unless defined($InitElapsed);
+    print STDERR "Warning: MutTime not found in stats file\n" unless defined($MutTime);
+    print STDERR "Warning: MutElapsed not found in stats file\n" unless defined($MutElapsed);
+    print STDERR "Warning: GcTime inot found in stats file\n" unless defined($GcTime);
+    print STDERR "Warning: GcElapsed not found in stats file\n" unless defined($GcElapsed);
+    print STDERR "Warning: total memory not found in stats file\n" unless defined($TotMem);
+    print STDERR "Warning: GC work not found in stats file\n" unless defined($GCWork);
+    print STDERR "Warning: Gc0Time not found in stats file\n" unless defined($Gc0Time);
+    print STDERR "Warning: Gc0Elapsed not found in stats file\n" unless defined($Gc0Elapsed);
+    print STDERR "Warning: Gc1Time not found in stats file\n" unless defined($Gc1Time);
+    print STDERR "Warning: Gc1Elapsed not found in stats file\n" unless defined($Gc1Elapsed);
+    print STDERR "Warning: Balance not found in stats file\n" unless defined($Gc1Elapsed);
+
+    # things we didn't necessarily expect to find
+    $MaxResidency     = 0 unless defined($MaxResidency);
+    $AvgResidency     = 0 unless defined($AvgResidency);
+    $ResidencySamples = 0 unless defined($ResidencySamples);
+    $Gc0Time          = 0.0 unless defined($Gc0Time);
+    $Gc0Elapsed       = 0.0 unless defined($Gc0Elapsed);
+    $Gc1Time          = 0.0 unless defined($Gc1Time);
+    $Gc1Elapsed       = 0.0 unless defined($Gc1Elapsed);
+
+    # a bit of tidying
+    $BytesAlloc =~ s/,//g;
+    $MaxResidency =~ s/,//g;
+    $GCs =~ s/,//g;
+    $InitTime =~ s/,//g;
+    $InitElapsed =~ s/,//g;
+    $MutTime =~ s/,//g;
+    $MutElapsed =~ s/,//g;
+    $GcTime =~ s/,//g;
+    $GcElapsed =~ s/,//g;
+}
+
+sub process_cachegrind_files {
+
+    open(STATS, "< $CachegrindStats") || die("Can't open $CachegrindStats\n");
+
+    while (<STATS>) {
+       /^==\d+==\s+I\s+refs:\s+([0-9,]*)/ && do {
+          $TotInstrs = $1;
+          $TotInstrs =~ s/,//g;
+       };
+
+       /^==\d+==\s+D\s+refs:\s+[0-9,]+\s+\(([0-9,]+)\s+rd\s+\+\s+([0-9,]+)\s+wr/ && do {
+          $TotReads  = $1;
+          $TotWrites = $2;
+          $TotReads  =~ s/,//g;
+          $TotWrites =~ s/,//g;
+       };
+
+       /^==\d+==\s+L2d\s+misses:\s+([0-9,]+)/ && do {
+          $TotMisses = $1;
+          $TotMisses =~ s/,//g;
+       };
+    }
+    close(STATS);
+}
+