[project @ 1997-03-28 16:28:25 by simonm]
[ghc-hetmet.git] / ghc / driver / ghc.lprl
index 9b2d9f1..b499b8a 100644 (file)
@@ -1,8 +1,5 @@
 %
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
-%
-% *** MSUB does some substitutions here ***
-% *** grep for $( ***
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1997
 %
 
 This is the driver script for the Glasgow Haskell compilation system.
@@ -31,13 +28,13 @@ possible phases of a compilation:
     - hscpp:   run code through the C pre-processor (if -cpp flag given)
     - hsc:     run the Haskell compiler proper
     - gcc:     run the C compiler (if compiling via C)
-    - as:      run the Unix assembler
-    - ld:      run the Unix linker
+    - as:      run the assembler
+    - ld:      run the linker
 
 For each input file, the phase to START with is determined by the
 file's suffix:
-    - .lhs     literate Haskell: lit2pgm
-    - .hs      illiterate Haskell: hsp
+    - .lhs     literate Haskell: unlit
+    - .hs      illiterate Haskell: hsc
     - .hc      C from the Haskell compiler: gcc
     - .c       C not from the Haskell compiler: gcc
     - .s       assembly language: as
@@ -56,7 +53,7 @@ option:
 
 Other commonly-used options are:
 
-    -O         An `optimising' package of options, to produce faster code
+    -O         An `optimising' package of compiler flags, for faster code
 
     -prof      Compile for cost-centre profiling
                (add -auto for automagic cost-centres on top-level functions)
@@ -65,18 +62,24 @@ Other commonly-used options are:
 
     -H14m      Increase compiler's heap size
 
+    -M          Output the Makefile rules recording the
+                dependencies of a list of Haskell files.
+               (ghc driver just calls upon the help of a
+                 compatible mkdependHS script to do the
+                 actual processing)
+
 The User's Guide has more information about GHC's *many* options.
 
 Given the above, here are some TYPICAL invocations of $Pgm:
 
     # compile a Haskell module to a .o file, optimising:
     % $Pgm -c -O Foo.hs
+    # link three .o files into an executable called "test":
+    % $Pgm -o test Foo.o Bar.o Baz.o
     # compile a Haskell module to C (a .hc file), using a bigger heap:
     % $Pgm -C -H16m Foo.hs
     # compile Haskell-produced C (.hc) to assembly language:
     % $Pgm -S Foo.hc
-    # link three .o files into an executable called "test":
-    % $Pgm -o test Foo.o Bar.o Baz.o
 ------------------------------------------------------------------------
 EOUSAGE
 \end{code}
@@ -87,49 +90,55 @@ EOUSAGE
 %*                                                                     *
 %************************************************************************
 
-Establish what executables to run for the various phases (all the
-\tr{$(FOO)} make-variables are \tr{msub}bed for from the
-\tr{Makefile}), what the default options are for those phases, and
-other similar boring stuff.
-\begin{code}
-select(STDERR); $| = 1; select(STDOUT); # no STDERR buffering, please.
+The driver script need to be told where to find these executables, so
+in the course of building the driver `executable', make-variables holding
+these are prepended to the de-litted version of this file. The variables are:
 
-$HostPlatform   = '$(HOSTPLATFORM)';
-$TargetPlatform = '$(TARGETPLATFORM)';
+\begin{verbatim}
+INSTALLING
 
-#------------------------------------------------------------------------
-# If you are adjusting paths by hand for a binary GHC distribution,
-# de-commenting the line to set GLASGOW_HASKELL_ROOT should do.
-# Or you can leave it as is, and set the environment variable externally.
-#------------------------------------------------------------------------
-# $ENV{'GLASGOW_HASKELL_ROOT'} = '/some/absolute/path/name';
+HOSTPLATFORM TARGETPLATFORM
 
-if (! $ENV{'GLASGOW_HASKELL_ROOT'}) { # good -- death to environment variables
-    $TopPwd        = '$(TOP_PWD)';
-    $InstLibDirGhc  = '$(INSTLIBDIR_GHC)';
-    $InstDataDirGhc = '$(INSTDATADIR_GHC)';
-} else {
-    $TopPwd = $ENV{'GLASGOW_HASKELL_ROOT'};
+PROJECTNAME PROJECTVERSION PROJECTPATCHLEVEL
 
-    if ( '$(INSTLIBDIR_GHC)' =~ /^\/(local\/fp|usr\/local)(\/.*)/ ) {
-       $InstLibDirGhc  = $ENV{'GLASGOW_HASKELL_ROOT'} . $2;
-    } else {
-       print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTLIBDIR_GHC).\n(Installation error)\n";
-       exit(1);
-    }
+TOP_PWD
 
-    if ( '$(INSTDATADIR_GHC)' =~ /\/(local\/fp|usr\/local)(\/.*)/ ) {
-       $InstDataDirGhc = $ENV{'GLASGOW_HASKELL_ROOT'} . $2;
-    } else {
-       print STDERR "GLASGOW_HASKELL_ROOT environment variable is set;\nBut can't untangle $(INSTDATADIR_GHC).\n(Installation error)\n";
-       exit(1);
-    }
-}
+bindir libdir datadir
+
+CURRENT_DIR TMPDIR
+
+GHC_LIB_DIR GHC_RUNTIME_DIR GHC_UTILS_DIR GHC_INCLUDE_DIR
+
+GHC_OPT_HILEV_ASM GhcWithNativeCodeGen
+
+GHC_UNLIT GHC_HSCPP GHC_HSC GHC_SYSMAN
+
+CP RM CONTEXT_DIFF
+
+WAY_*_NAME WAY_*_HC_OPTS
+
+LeadingUnderscore
+
+\end{verbatim}
+
+Establish what executables to run for the various phases, what the
+default options are for those phases, and other similar boring stuff.
+
+\begin{code}
+select(STDERR); $| = 1; select(STDOUT); # no STDERR buffering, please.
+
+$TargetPlatform = $TARGETPLATFORM;
+
+$TopPwd                   = "${TOP_PWD}";
+$InstBinDirGhc     = "${bindir}";
+$InstLibDirGhc     = "${libdir}";
+$InstLibexecDirGhc = "${libexecdir}";
+$InstDataDirGhc    = "${datadir}";
+$InstSysLibDir     = ( $INSTALLING ) ? "${InstLibDirGhc}/hslibs" : 
+                       "$TopPwd/hslibs";
 
 $Status  = 0; # just used for exit() status
 $Verbose = '';
-$CoreLint = '';
-$Time = '';    # ToDo: mkworld-ize the timing command
 
 # set up signal handler
 sub quit_upon_signal { &tidy_up_and_die(1, ''); }
@@ -138,102 +147,98 @@ $SIG{'QUIT'} = 'quit_upon_signal';
 
 # where to get "require"d .prl files at runtime (poor man's dynamic loading)
 #   (use LIB, not DATA, because we can't be sure of arch-independence)
-@INC = ( ( $(INSTALLING) ) ? "$InstLibDirGhc"
-                          : "$TopPwd/$(CURRENT_DIR)" );
+@INC = ( ( $INSTALLING ) ? $InstLibDirGhc
+                          : "$TopPwd/${CURRENT_DIR}" );
 
 if ( $ENV{'TMPDIR'} ) { # where to make tmp file names
     $Tmp_prefix = ($ENV{'TMPDIR'} . "/ghc$$");
 } else {
-    $Tmp_prefix ="$(TMPDIR)/ghc$$";
-    $ENV{'TMPDIR'} = '$(TMPDIR)'; # set the env var as well
+    print STDERR "TMPDIR has not been set to anything useful!\n" if (${TMPDIR} eq '');
+    $Tmp_prefix ="${TMPDIR}/ghc$$"; # TMPDIR set via Makefile when booting..
+    $ENV{'TMPDIR'} = ${TMPDIR}; # set the env var as well
 }
 
 @Files_to_tidy = (); # files we nuke in the case of abnormal termination
 
-$Unlit = ( $(INSTALLING) ) ? "$InstLibDirGhc/unlit"
-                            : "$TopPwd/$(CURRENT_DIR)/$(GHC_UNLIT)";
-@Unlit_flags   = ();
+$Unlit = ( $INSTALLING ) ? "$InstLibexecDirGhc/unlit"
+                        : "$TopPwd/${CURRENT_DIR}/${GHC_UNLIT}";
 
-$Cat    = "cat";
+$Cp   = $CP;
+$Rm   = $RM;
+$Diff = $CONTEXT_DIFF;
+$Cat  = 'cat';
+$Cmp  = 'cmp';
+$Time = '';
 
 $HsCpp  = # but this is re-set to "cat" (after options) if -cpp not seen
-          ( $(INSTALLING) ) ? "$InstLibDirGhc/hscpp"
-                            : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSCPP)";
-@HsCpp_flags   = ();
+          ( $INSTALLING ) ? "$InstLibexecDirGhc/hscpp"
+                          : "$TopPwd/${CURRENT_DIR}/${GHC_HSCPP}";
 
-$HsP    = ( $(INSTALLING) ) ? "$InstLibDirGhc/hsp"
-                            : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSP)";
-@HsP_flags = ();
+@HsCpp_flags   = ();
+$genSPECS_flag = '';           # See ../utils/hscpp/hscpp.prl
+$HsC    = ( $INSTALLING ) ? "$InstLibexecDirGhc/hsc"
+                          : "$TopPwd/${CURRENT_DIR}/${GHC_HSC}";
 
-$HsC    = ( $(INSTALLING) ) ? "$InstLibDirGhc/hsc"
-                            : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSC)";
+# For PVM fiends only
+$SysMan         = ( $INSTALLING ) ? "$InstLibexecDirGhc/SysMan"
+                          : "$TopPwd/${CURRENT_DIR}/${GHC_SYSMAN}";
 
-$SysMan         = ( $(INSTALLING) ) ? "$InstLibDirGhc/SysMan"
-                            : "$TopPwd/$(CURRENT_DIR)/$(GHC_SYSMAN)";
+@Unlit_flags   = ();
 
+#
 # HsC_rts_flags: if we want to talk to the LML runtime system
 # NB: we don't use powers-of-2 sizes, because this may do
 #   terrible things to cache behavior.
+#
 $Specific_heap_size = 6 * 1000 * 1000;
 $Specific_stk_size  = 1000 * 1000;
-$Scale_sizes_by = 1.0;
-$RTS_style = $(GHC_RTS_STYLE);
-@HsC_rts_flags = ();
-
-@HsC_flags     = ();
-@HsC_antiflags  = ();
-\end{code}
-
-The optimisations/etc to be done by the compiler are {\em normally}
-expressed with a \tr{-O} (or \tr{-O2}) flag, or by its absence.
+$Scale_sizes_by     = 1.0;
 
-\begin{code}
-$OptLevel = 0;     # no -O == 0; -O == 1; -O2 == 2; -Ofile == 3
-$MinusO2ForC = 0;   # set to 1 if -O2 should be given to C compiler
-$StolenX86Regs = 4; # **HACK*** of the very worst sort
 \end{code}
 
-These variables represent parts of the -O/-O2/etc ``templates,''
-which are filled in later, using these.
+The variables set by @setupOptFlags@ represent parts of the
+-O/-O2/etc ``templates,'' which are filled in later, using these.
 These are the default values, which may be changed by user flags.
+
 \begin{code}
-$Oopt_UnfoldingUseThreshold    = '-fsimpl-uf-use-threshold3';
-$Oopt_MaxSimplifierIterations  = '-fmax-simplifier-iterations4';
-$Oopt_PedanticBottoms          = '-fpedantic-bottoms'; # ON by default
-$Oopt_MonadEtaExpansion                = '';
-#OLD:$Oopt_LambdaLift          = '';
-$Oopt_AddAutoSccs              = '';
-$Oopt_FinalStgProfilingMassage = '';
-$Oopt_StgStats                 = '';
-$Oopt_SpecialiseUnboxed                = '';
-$Oopt_FoldrBuild               = 1; # On by default!
-$Oopt_FB_Support               = '-fdo-new-occur-anal -fdo-arity-expand';
-#$Oopt_FoldrBuildWW            = 0; # Off by default
+sub setupOptFlags {
+   $Oopt_UnfoldingUseThreshold   = '-fsimpl-uf-use-threshold3';
+   $Oopt_MaxSimplifierIterations  = '-fmax-simplifier-iterations4';
+   $Oopt_PedanticBottoms         = '-fpedantic-bottoms'; # ON by default
+   $Oopt_MonadEtaExpansion       = '';
+   $Oopt_FinalStgProfilingMassage = '';
+   $Oopt_StgStats                = '';
+   $Oopt_SpecialiseUnboxed       = '';
+   $Oopt_DoSpecialise            = ''; # ToDo:LATER: '-fspecialise';
+   $Oopt_FoldrBuild              = 0; # *Off* by default!
+   $Oopt_FB_Support              = ''; # was '-fdo-arity-expand';
+#  $Oopt_FoldrBuildWW            = 0; # Off by default
+   $Oopt_FoldrBuildInline        = ''; # was '-fdo-inline-foldr-build';
+} # end of setupOptFlags
+
+# Assign defaults to these right away.
+&setupOptFlags();
 \end{code}
 
 Things to do with C compilers/etc:
 \begin{code}
-$CcUnregd      = '$(GHC_DEBUG_HILEV_ASM)'; # our high-level assembler (non-optimising)
-$CcRegd                = '$(GHC_OPT_HILEV_ASM)';   # our high-level assembler (optimising)
-$GccAvailable  = $(GHC_GCC_IS_AVAILABLE);  # whether GCC avail or not for optimising
-
+$CcRegd                = $GHC_OPT_HILEV_ASM;
 @CcBoth_flags  = ('-S');   # flags for *any* C compilation
 @CcInjects     = ();
 
-# non-registerizing flags: those for all files, those only for .c files; those only for .hc files
-@CcUnregd_flags   = ( $GccAvailable ) ? ('-ansi', '-pedantic') : ();
-@CcUnregd_flags_c = ();
-@CcUnregd_flags_hc= ();
+# GCC flags: 
+#    those for all files, 
+#    those only for .c files;
+#    those only for .hc files
 
-# ditto; but for registerizing (we must have GCC for this)
 @CcRegd_flags    = ('-ansi', '-D__STG_GCC_REGS__', '-D__STG_TAILJUMPS__');
 @CcRegd_flags_c        = ();
 @CcRegd_flags_hc = ();
 
-$As            = ''; # assembler is normally the same pgm as used for C compilation
+$As            = ''; # "assembler" is normally GCC
 @As_flags      = ();
 
-$Lnkr          = ''; # linker is normally the same pgm as used for C compilation
+$Lnkr          = ''; # "linker" is normally GCC
 @Ld_flags      = ();
 
 # 'nm' is used for consistency checking (ToDo: mk-world-ify)
@@ -247,186 +252,233 @@ Prelude ({\em including} its interface file(s)).
 \begin{code}
 $BuildTag      = ''; # default is sequential build w/ Appel-style GC
 
-%BuildAvail    = ('',      '$(GHC_BUILD_FLAG_normal)',
-                  '_p',    '$(GHC_BUILD_FLAG_p)',
-                  '_t',    '$(GHC_BUILD_FLAG_t)',
-                  '_u',    '$(GHC_BUILD_FLAG_u)',
-                  '_mc',   '$(GHC_BUILD_FLAG_mc)',
-                  '_mr',   '$(GHC_BUILD_FLAG_mr)',
-                  '_mt',   '$(GHC_BUILD_FLAG_mt)',
-                  '_mp',   '$(GHC_BUILD_FLAG_mp)',
-                  '_mg',   '$(GHC_BUILD_FLAG_mg)',
-                  '_2s',   '$(GHC_BUILD_FLAG_2s)',
-                  '_1s',   '$(GHC_BUILD_FLAG_1s)',
-                  '_du',   '$(GHC_BUILD_FLAG_du)',
-                  '_a',    '$(GHC_BUILD_FLAG_a)',
-                  '_b',    '$(GHC_BUILD_FLAG_b)',
-                  '_c',    '$(GHC_BUILD_FLAG_c)',
-                  '_d',    '$(GHC_BUILD_FLAG_d)',
-                  '_e',    '$(GHC_BUILD_FLAG_e)',
-                  '_f',    '$(GHC_BUILD_FLAG_f)',
-                  '_g',    '$(GHC_BUILD_FLAG_g)',
-                  '_h',    '$(GHC_BUILD_FLAG_h)',
-                  '_i',    '$(GHC_BUILD_FLAG_i)',
-                  '_j',    '$(GHC_BUILD_FLAG_j)',
-                  '_k',    '$(GHC_BUILD_FLAG_k)',
-                  '_l',    '$(GHC_BUILD_FLAG_l)',
-                  '_m',    '$(GHC_BUILD_FLAG_m)',
-                  '_n',    '$(GHC_BUILD_FLAG_n)',
-                  '_o',    '$(GHC_BUILD_FLAG_o)',
-                  '_A',    '$(GHC_BUILD_FLAG_A)',
-                  '_B',    '$(GHC_BUILD_FLAG_B)' );
-
-%BuildDescr    = ('',      'normal sequential',
-                  '_p',    'profiling',
-                  '_t',    'ticky-ticky profiling',
-                  '_t',    'unregisterized (using portable C only)',
-                  '_mc',   'concurrent',
-                  '_mr',   'profiled concurrent',
-                  '_mt',   'ticky concurrent',
-                  '_mp',   'parallel',
-                  '_mg',   'GranSim',
-                  '_2s',   '2-space GC',
-                  '_1s',   '1-space GC',
-                  '_du',   'dual-mode GC',
-                  '_a',    'user way a',
-                  '_b',    'user way b',
-                  '_c',    'user way c',
-                  '_d',    'user way d',
-                  '_e',    'user way e',
-                  '_f',    'user way f',
-                  '_g',    'user way g',
-                  '_h',    'user way h',
-                  '_i',    'user way i',
-                  '_j',    'user way j',
-                  '_k',    'user way k',
-                  '_l',    'user way l',
-                  '_m',    'user way m',
-                  '_n',    'user way n',
-                  '_o',    'user way o',
-                  '_A',    'user way A',
-                  '_B',    'user way B' );
+%BuildDescr    = (# system ways begin
+                   '',     'normal sequential',
+                  '_p',    "$WAY_p_NAME",
+                  '_t',    "$WAY_t_NAME",
+                  '_u',    "$WAY_u_NAME",
+                  '_mc',   "$WAY_mc_NAME",
+                  '_mr',   "$WAY_mr_NAME",
+                  '_mt',   "$WAY_mt_NAME",
+                  '_mp',   "$WAY_mp_NAME",
+                  '_mg',   "$WAY_mg_NAME",
+                  '_2s',   "$WAY_2s_NAME",
+                  '_1s',   "$WAY_1s_NAME",
+                  '_du',   "$WAY_du_NAME",
+                  # system ways end
+                  '_a',    "$WAY_a_NAME",
+                  '_b',    "$WAY_b_NAME",
+                  '_c',    "$WAY_c_NAME",
+                  '_d',    "$WAY_d_NAME",
+                  '_e',    "$WAY_e_NAME",
+                  '_f',    "$WAY_f_NAME",
+                  '_g',    "$WAY_g_NAME",
+                  '_h',    "$WAY_h_NAME",
+                  '_i',    "$WAY_i_NAME",
+                  '_j',    "$WAY_j_NAME",
+                  '_k',    "$WAY_k_NAME",
+                  '_l',    "$WAY_l_NAME",
+                  '_m',    "$WAY_m_NAME",
+                  '_n',    "$WAY_n_NAME",
+                  '_o',    "$WAY_o_NAME",
+                  '_A',    "$WAY_A_NAME",
+                  '_B',    "$WAY_B_NAME" );
 
 # these are options that are "fed back" through the option processing loop
-%UserSetupOpts = ('_a', '$(GHC_BUILD_OPTS_a)',
-                  '_b', '$(GHC_BUILD_OPTS_b)',
-                  '_c', '$(GHC_BUILD_OPTS_c)',
-                  '_d', '$(GHC_BUILD_OPTS_d)',
-                  '_e', '$(GHC_BUILD_OPTS_e)',
-                  '_f', '$(GHC_BUILD_OPTS_f)',
-                  '_g', '$(GHC_BUILD_OPTS_g)',
-                  '_h', '$(GHC_BUILD_OPTS_h)',
-                  '_i', '$(GHC_BUILD_OPTS_i)',
-                  '_j', '$(GHC_BUILD_OPTS_j)',
-                  '_k', '$(GHC_BUILD_OPTS_k)',
-                  '_l', '$(GHC_BUILD_OPTS_l)',
-                  '_m', '$(GHC_BUILD_OPTS_m)',
-                  '_n', '$(GHC_BUILD_OPTS_n)',
-                  '_o', '$(GHC_BUILD_OPTS_o)',
-                  '_A', '$(GHC_BUILD_OPTS_A)',
-                  '_B', '$(GHC_BUILD_OPTS_B)',
-
-                  # the GC ones don't have any "fed back" options
-                  '_2s', '',
-                  '_1s', '',
-                  '_du', '' );
+#
+%SetupOpts = 
+       (
+       '_a', "$WAY_a_HC_OPTS",
+       '_b', "$WAY_b_HC_OPTS",
+       '_c', "$WAY_c_HC_OPTS",
+       '_d', "$WAY_d_HC_OPTS",
+       '_e', "$WAY_e_HC_OPTS",
+       '_f', "$WAY_f_HC_OPTS",
+       '_g', "$WAY_g_HC_OPTS",
+       '_h', "$WAY_h_HC_OPTS",
+       '_i', "$WAY_i_HC_OPTS",
+       '_j', "$WAY_j_HC_OPTS",
+       '_k', "$WAY_k_HC_OPTS",
+       '_l', "$WAY_l_HC_OPTS",
+       '_m', "$WAY_m_HC_OPTS",
+       '_n', "$WAY_n_HC_OPTS",
+       '_o', "$WAY_o_HC_OPTS",
+       '_A', "$WAY_A_HC_OPTS",
+       '_B', "$WAY_B_HC_OPTS",
+
+       # system ways
+       '_p',  "$WAY_p_HC_OPTS",
+       '_t',  "$WAY_t_HC_OPTS",
+       '_u',  "$WAY_u_HC_OPTS",
+       '_mc', "$WAY_mc_HC_OPTS",
+       '_mr', "$WAY_mr_HC_OPTS",
+       '_mt', "$WAY_mt_HC_OPTS",
+       '_mp', "$WAY_mp_HC_OPTS",
+       '_mg', "$WAY_mg_HC_OPTS",
+       '_2s', "$WAY_2s_HC_OPTS",
+       '_1s', "$WAY_1s_HC_OPTS",
+       '_du', "$WAY_B_HC_OPTS" );
 
 # per-build code fragments which are eval'd
-%EvaldSetupOpts        = ('',      '', # this one must *not* be set!
-
-                           # profiled sequential
-                  '_p',    'push(@HsC_flags,  \'-fscc-profiling\');
-                            push(@CcBoth_flags, \'-DPROFILING\');',
-
-                           # ticky-ticky sequential
-                  '_t',    'push(@HsC_flags, \'-fticky-ticky\');
-                            push(@CcBoth_flags, \'-DTICKY_TICKY\');',
-
-                           # unregisterized (ToDo????)
-                  '_u',    '',
-
-                           # concurrent
-                  '_mc',   '$StkChkByPageFaultOK = 0;
-                            push(@HsC_flags,  \'-fconcurrent\');
-                            push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
-                            push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');',
-
-                           # profiled concurrent
-                  '_mr',   '$StkChkByPageFaultOK = 0;
-                            push(@HsC_flags,  \'-fconcurrent\', \'-fscc-profiling\');
-                            push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
-                            push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DPROFILING\');',
-
-                           # ticky-ticky concurrent
-                  '_mt',   '$StkChkByPageFaultOK = 0;
-                            push(@HsC_flags,  \'-fconcurrent\', \'-fticky-ticky\');
-                            push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
-                            push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DTICKY_TICKY\');',
-
-                           # parallel
-                  '_mp',   '$StkChkByPageFaultOK = 0;
-                            push(@HsC_flags,  \'-fconcurrent\');
-                            push(@HsCpp_flags,\'-D__PARALLEL_HASKELL__\',   \'-DPAR\');
-                            push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DPAR\');',
-
-                           # GranSim
-                  '_mg',   '$StkChkByPageFaultOK = 0;
-                            push(@HsC_flags,  \'-fconcurrent\');
-#????????????               push(@HsCpp_flags,\'-D__PARALLEL_HASKELL__\',   \'-DPAR\');
-                            push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DGRAN\');',
-
-                  '_2s',   'push (@CcBoth_flags, \'-DGC2s\');',
-                  '_1s',   'push (@CcBoth_flags, \'-DGC1s\');',
-                  '_du',   'push (@CcBoth_flags, \'-DGCdu\');',
-
-                  '_a',    '', # these user-way guys should not be set!
-                  '_b',    '',
-                  '_c',    '',
-                  '_d',    '',
-                  '_e',    '',
-                  '_f',    '',
-                  '_g',    '',
-                  '_h',    '',
-                  '_i',    '',
-                  '_j',    '',
-                  '_k',    '',
-                  '_l',    '',
-                  '_m',    '',
-                  '_n',    '',
-                  '_o',    '',
-                  '_A',    '',
-                  '_B',    '' );
+#%EvaldSetupOpts       = ('',      '', # this one must *not* be set!
+
+#                          # profiled sequential
+#                 '_p',    'push(@HsC_flags,  \'-fscc-profiling\');
+#                           push(@CcBoth_flags, \'-DPROFILING\');',
+
+#                          #and maybe ...
+#                          #push(@CcBoth_flags, '-DPROFILING_DETAIL_COUNTS');
+
+#                          # ticky-ticky sequential
+#                 '_t',    'push(@HsC_flags, \'-fticky-ticky\');
+#                           push(@CcBoth_flags, \'-DTICKY_TICKY\');',
+
+##OLD:                     # unregisterized (ToDo????)
+##                '_u',    '',
+
+#                          # concurrent
+#                 '_mc',   '$StkChkByPageFaultOK = 0;
+#                           push(@HsC_flags,  \'-fconcurrent\');
+#                           push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
+#                           push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');',
+
+#                          # profiled concurrent
+#                 '_mr',   '$StkChkByPageFaultOK = 0;
+#                           push(@HsC_flags,  \'-fconcurrent\', \'-fscc-profiling\');
+#                           push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
+#                           push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DPROFILING\');',
+
+#                          # ticky-ticky concurrent
+#                 '_mt',   '$StkChkByPageFaultOK = 0;
+#                           push(@HsC_flags,  \'-fconcurrent\', \'-fticky-ticky\');
+#                           push(@HsCpp_flags,\'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\');
+#                           push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DTICKY_TICKY\');',
+
+#                          # parallel
+#                 '_mp',   '$StkChkByPageFaultOK = 0;
+#                           push(@HsC_flags,  \'-fconcurrent\');
+#                           push(@HsCpp_flags,\'-D__PARALLEL_HASKELL__\',   \'-DPAR\');
+#                           push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DPAR\');',
+
+#                          # GranSim
+#                 '_mg',   '$StkChkByPageFaultOK = 0;
+#                           push(@HsC_flags,  \'-fconcurrent\', \'-fgransim\');
+#                           push(@HsCpp_flags,\'-D__GRANSIM__\',   \'-DGRAN\');
+#                           push(@Cpp_define, \'-D__CONCURRENT_HASKELL__\', \'-DCONCURRENT\', \'-DGRAN\');',
+
+#                 '_2s',   'push (@CcBoth_flags, \'-DGC2s\');',
+#                 '_1s',   'push (@CcBoth_flags, \'-DGC1s\');',
+#                 '_du',   'push (@CcBoth_flags, \'-DGCdu\');',
+
+#                 '_a',    '', # these user-way guys should not be set!
+#                 '_b',    '',
+#                 '_c',    '',
+#                 '_d',    '',
+#                 '_e',    '',
+#                 '_f',    '',
+#                 '_g',    '',
+#                 '_h',    '',
+#                 '_i',    '',
+#                 '_j',    '',
+#                 '_k',    '',
+#                 '_l',    '',
+#                 '_m',    '',
+#                 '_n',    '',
+#                 '_o',    '',
+#                 '_A',    '',
+#                 '_B',    '' );
+
 \end{code}
 
 Import/include directories (\tr{-I} options) are sufficiently weird to
 require special handling.
+
 \begin{code}
 @Import_dir    = ('.'); #-i things
 @Include_dir   = ('.'); #-I things; other default(s) stuck on AFTER option processing
 
-@SysImport_dir = ( $(INSTALLING) )
-                   ? ( "$InstDataDirGhc/imports" )
-                   : ( "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/prelude"
-                     );
+# where to look for interface files (system hi's, i.e., prelude and hslibs)
+@SysImport_dir = ( $INSTALLING )
+                   ? ( "$InstLibDirGhc/imports" )
+                   : ( "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/required"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/ghc"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/glaExts"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/concurrent" );
 
-$ghc_version_info = $(PROJECTVERSION) * 100;
-$haskell1_version = 2; # i.e., Haskell 1.2
-@Cpp_define    = ();
+# We need to look in ghc/ and glaExts/ when searching for implicitly needed .hi files, but 
+# we should really *not* look there for explicitly imported modules.
+
+$GhcVersionInfo  = int ($PROJECTVERSION * 100);
+$Haskell1Version = 4; # i.e., Haskell 1.4
+@Cpp_define     = ();
 
 @UserLibrary_dir= ();  #-L things;...
 @UserLibrary           = ();   #-l things asked for by the user
 
-@SysLibrary_dir = ( ( $(INSTALLING) )  #-syslib things supplied by the system
-                   ? "$InstLibDirGhc"
-                   : ("$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)",
-                      "$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)/gmp",
-                      "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)")
+@SysLibrary_dir = ( ( $INSTALLING )    #-syslib things supplied by the system
+                   ? $InstLibDirGhc
+                   : ( "$TopPwd/$CURRENT_DIR/$GHC_RUNTIME_DIR"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_RUNTIME_DIR/gmp"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR"
+                     , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/cbits"
+                     )
                  );
-@SysLibrary = ( '-lHS' );      # basic I/O and prelude stuff
+@SysLibrary = (); # will be built up as we go along
 
 $TopClosureFile # defaults to 1.2 one; will be mangled later
-       = ( $(INSTALLING) ) ? "$InstLibDirGhc/TopClosureXXXX.o"
-                           : "$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)/main/TopClosureXXXX.o";
+       = ( $INSTALLING)  ? "$InstLibDirGhc/TopClosureXXXX.o"
+                         : "$TopPwd/$CURRENT_DIR/$GHC_RUNTIME_DIR/main/TopClosureXXXX.o";
+
+# make depend for Haskell
+$MkDependHS
+       = ( $INSTALLING ) ? "$InstBinDirGhc/mkdependHS"
+                         : "$TopPwd/$CURRENT_DIR/$GHC_UTILS_DIR/mkdependHS/mkdependHS";
+# Fill in later
+@MkDependHS_flags = ( );
+
+# do_link flag should not be reset while rescanning the cmd-line.
+$Do_lnkr    = 1;
+$Specific_output_dir = '';     # set by -odir <dir>
+$Specific_output_file = '';    # set by -o <file>; "-" for stdout
+\end{code}
+
+Function to initialise the per-compilation-unit globals that
+are used to guide and control the invocation of the different phases.
+
+\begin{code} 
+sub initDriverGlobals {
+
+# reset the following options:
+# RTS flags to use while compiling
+@HsC_rts_flags      = ();
+@HsP_flags     = (); # these are the flags destined solely for
+                     # the flex/yacc parser
+@HsC_flags     = ();
+@HsC_antiflags  = ();
+\end{code}
+
+The optimisations/etc to be done by the compiler are {\em normally}
+expressed with a \tr{-O} (or \tr{-O2}) flag, or by its absence.
+
+\begin{code}
+$OptLevel      = 0; # no -O == 0; -O == 1; -O2 == 2; -Ofile == 3
+$MinusO2ForC   = 0; # set to 1 if -O2 should be given to C compiler
+$StolenX86Regs = 4; # **HACK*** of the very worst sort
+$CoreLint      = '';
+$StgLint       = '';
+
+@CcBoth_flags  = ('-S');   # flags for *any* C compilation
+@CcInjects     = ();
+
+# GCC flags: those for all files, those only for .c files; those only for .hc files
+@CcRegd_flags    = ('-ansi', '-D__STG_GCC_REGS__', '-D__STG_TAILJUMPS__');
+@CcRegd_flags_c        = ();
+@CcRegd_flags_hc = ();
+
+@Import_dir    = ('.'); #-i things
+@Include_dir   = ('.'); #-I things; other default(s) stuck on AFTER option processing
+
+
 \end{code}
 
 We are given a list of files with various presumably-known suffixes
@@ -438,68 +490,70 @@ start with.  Linking is weird and kept track of separately.
 
 Here are the initial defaults applied to all files:
 \begin{code}
-$Do_lit2pgm = 1;
-$Do_hscpp   = 1;       # but we run 'cat' by default (see after arg check)
-$Cpp_flag_set = 0;     # (hack)
-$Only_preprocess_C = 0;        # pretty hackish
-$ProduceHi  = 1;       # but beware magical value "2"! (hack)
+$Cpp_flag_set = 0;       # (hack)
+$Only_preprocess_C = 0;          # pretty hackish
+$Only_generate_deps = 0;  #
 $PostprocessCcOutput = 0;
-$HiDiff_flag= 0;
 
 # native code-gen or via C?
-$HaveNativeCodeGen = $(GHC_WITH_NATIVE_CODEGEN);
-$ProduceS = '';
-if ($HaveNativeCodeGen) {
-    if ($TargetPlatform =~ /^(alpha|sparc)-/) {
-       $ProduceS = $TargetPlatform;
-    }
-}
-$ProduceC = ($ProduceS) ? 0 : 1;
+$HaveNativeCodeGen = $GhcWithNativeCodeGen;
+$HscOut = '-C='; # '-C=' ==> .hc output; '-S=' ==> .s output; '-N=' ==> neither
+$HscOut = '-S='
+    if $HaveNativeCodeGen && $TargetPlatform =~ /^(alpha|sparc)-/;
+# TEMP: disable x86  if $HaveNativeCodeGen && $TargetPlatform =~ /^(i386|alpha|sparc)-/;
+$ProduceHi   = '-hifile=';
+$HiOnStdout  = 0;
+$HiDiff_flag = '';
 
 $CollectingGCstats = 0;
 $CollectGhcTimings = 0;
-$RegisteriseC  = '';    # set to 'o', if using optimised C code (only if avail)
-                       #   or if generating equiv asm code
 $DEBUGging = '';       # -DDEBUG and all that it entails (um... not really)
 $PROFing = '';         # set to p or e if profiling
 $PROFgroup = '';       # set to group if an explicit -Ggroup specified
 $PROFauto = '';                # set to relevant hsc flag if -auto or -auto-all
 $PROFcaf  = '';                # set to relevant hsc flag if -caf-all
-#UNUSED:$PROFdict  = '';        # set to relevant hsc flag if -dict-all
 $PROFignore_scc = '';  # set to relevant parser flag if explicit sccs ignored
+$UNPROFscc_auto = '';  # set to relevant hsc flag if forcing auto sccs without profiling
 $TICKYing = '';        # set to t if compiling for ticky-ticky profiling
 $PARing = '';          # set to p if compiling for PAR
 $CONCURing = '';       # set to c if compiling for CONCURRENT
 $GRANing = '';         # set to g if compiling for GRAN
 $StkChkByPageFaultOK = 1; # may be set to 0 (false) for some builds
-$Specific_output_dir = '';     # set by -odir <dir>
-$Specific_output_file = '';    # set by -o <file>; "-" for stdout
 $Specific_hi_file = '';                # set by -ohi <file>; "-" for stdout
 $Specific_dump_file = '';      # set by -odump <file>; "-" for stdout
 $Using_dump_file = 0;
-$Osuffix    = '.o';
-$HiSuffix   = '.hi';
-$Do_hsp            = 2;    # 1 for "old" parser; 2 for "new" parser (in hsc)
-$Do_hsc            = 1;
+$Isuffix    = '';
+$Osuffix    = '';      # default: use the normal suffix for that kind of output
+$HiSuffix   = 'hi';
+$HiSuffix_prelude = '';
+$Do_recomp_chkr = 0;   # don't use the recompilatio checker unless asked
 $Do_cc     = -1;   # a MAGIC indeterminate value; will be set to 1 or 0.
 $Do_as     = 1;
-$Do_lnkr    = 1;
+
 $Keep_hc_file_too = 0;
 $Keep_s_file_too = 0;
-$CompilingPrelude = 0;
+$UseGhcInternals = 0; # if 1, may use GHC* modules
 $SplitObjFiles = 0;
 $NoOfSplitFiles = 0;
 $Dump_parser_output = 0;
 $Dump_raw_asm = 0;
-$Dump_asm_insn_counts = 0;
-$Dump_asm_globals_info = 0;
 $Dump_asm_splitting_info = 0;
+$NoImplicitPrelude = 0;
+
+
+} # end of initDriverGlobals (Sigh)
+
+# we split the argv passed to the driver into three:
 
-# and the list of files
+# the list of files
 @Input_file = ();
 
 # and files to be linked...
 @Link_file  = ();
+
+# and whatever else
+@Cmd_opts  = ();
+
 \end{code}
 
 We inject consistency-checking information into \tr{.hc} files (both
@@ -514,16 +568,16 @@ $LinkChk = 1;     # set to 0 if the link check should *not* be done
 
 # major & minor version numbers; major numbers must always agree;
 # minor disagreements yield a warning.
-$HsC_major_version = 29;
+$HsC_major_version = 31;
 $HsC_minor_version = 0;
-$Cc_major_version  = 33;
+$Cc_major_version  = 36;
 $Cc_minor_version  = 0;
 
 # options: these must always agree
 $HsC_consist_options = '';    # we record, in this order:
                              #     Build tag; debugging?
 $Cc_consist_options  = '';    # we record, in this order:
-                             #     Build tag; debugging? registerised?
+                             #     Build tag; debugging?
 \end{code}
 
 %************************************************************************
@@ -534,1919 +588,1603 @@ $Cc_consist_options  = '';    # we record, in this order:
 
 Now slurp through the arguments.
 \begin{code}
-# can't use getopt(s); what we want is too complicated
-arg: while($_ = $ARGV[0]) {
-    shift(@ARGV);
 
-    #---------- help -------------------------------------------------------
-    if (/^-\?$/ || /^-help$/) { print $LongUsage; exit $Status; }
+#---------- user defined prelude ---------------------------------------
 
-    #---------- verbosity and such -----------------------------------------
-    /^-v$/         && do { $Verbose = '-v'; $Time = 'time'; next arg; };
+if (grep(/^-user-prelude$/, @ARGV)) {
 
-    #---------- what phases are to be run ----------------------------------
-    /^-cpp$/       && do { $Cpp_flag_set = 1; next arg; };
-    # change the global default:
-    # we won't run cat; we'll run the real thing
-       
-    /^-C$/         && do { $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0;
-                           $ProduceC = 1; $ProduceS = '';
-                           next arg; };
-    # stop after generating C
-       
-    /^-noC$/       && do { $ProduceC = 0; $ProduceS = ''; $ProduceHi = 0;
-                           $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0;
-                           next arg; };
-    # leave out actual C generation (debugging) [also turns off interface gen]
+    # If ARGV contains -user-prelude we are compiling a piece of 
+    # prelude for the user, probably with additional specialise pragmas
 
-    /^-hi$/        && do { $ProduceHi = 2; next arg; };
-    # _do_ generate an interface; usually used as: -noC -hi
-    # NB: magic value "2" for $ProduceHi (hack)
+    # We strip out the -O -f and -user-prelude flags provided on
+    # the command line and add the ones used to compile the prelude
+    # ToDo: get these options from a common definition in mkworld
 
-    /^-nohi$/      && do { $ProduceHi = 0; next arg; };
-    # don't generate an interface (even if generating C)
+    # We also enable any options forced through with -user-prelude-force
 
-    /^-hi-diffs$/   && do { $HiDiff_flag = 1; next arg; };
-    # show diffs if the interface file changes
+    # Hey, Check out this grep statement ;-)  (PS)
 
-    /^-E$/         && do { push(@CcBoth_flags, '-E');
-                           $Only_preprocess_C = 1;
-                           $Do_as = 0; $Do_lnkr = 0; next arg; };
-    # stop after preprocessing C
+    @ARGV = grep((!/^-O/ && !/^-f/ && !/^-user-prelude$/) || s/^-user-prelude-force//,
+                @ARGV);
 
-    /^-S$/         && do { $Do_as = 0; $Do_lnkr = 0; next arg; };
-    # stop after generating assembler
-       
-    /^-c$/         && do { $Do_lnkr = 0; next arg; };
-    # stop after generating .o files
-       
-    /^-link-chk$/    && do { $LinkChk = 1; next arg; };
-    /^-no-link-chk$/ && do { $LinkChk = 0; next arg; };
-    # don't do consistency-checking after a link
+    unshift(@ARGV,
+       '-fcompiling-ghc-internals=???', # ToDo!!!!
+        '-O',
+        '-fshow-pragma-name-errs',
+        '-fshow-import-specs',
+        '-fglasgow-exts',
+        '-genSPECS',
+        '-DUSE_FOLDR_BUILD',
+       '-dcore-lint');
 
-    # generate code for a different target architecture; e.g., m68k
-    # ToDo: de-Glasgow-ize & probably more...
-# OLD:
-#    /^-target$/ && do { $TargetPlatform = &grab_arg_arg('-target', ''); 
-#                        if ($TargetPlatform ne $HostPlatform) {
-#                          if ( $TargetPlatform =~ /^m68k-/ ) {
-#                              $CcUnregd = $CcRegd = 'gcc-m68k';
-#                          } else {
-#                              print STDERR "$Pgm: Can't handle -target $TargetPlatform\n";
-#                              $Status++;
-#                          }
-#                      }
-#                      next arg; };
-
-    /^-unregisteri[sz]ed$/ && do { $RegisteriseC = 'no';
-                                  $ProduceC = 1; $ProduceS = ''; # via C, definitely
-                                  next arg; };
-
-    /^-tmpdir$/ && do { $Tmp_prefix = &grab_arg_arg('-tmpdir', '');
-                       $Tmp_prefix = "$Tmp_prefix/ghc$$";
-                       $ENV{'TMPDIR'} = $Tmp_prefix; # for those who use it...
-                       next arg; };
-    # use an alternate directory for temp files
+    print STDERR "ghc: -user-prelude options:\n", "@ARGV", "\n";
+}
 
-    #---------- redirect output --------------------------------------------
+&initDriverGlobals();
+&splitCmdLine(@ARGV);
+# Run through the cmd-line first time.
+&processArgs(@Cmd_opts);
 
-    # -o <file>; applies to the last phase, whatever it is
-    # "-o -" sends it to stdout
-    # if <file> has a directory component, that dir must already exist
+# Check to see if driver is only in the business
+# to generate dependencies
+if (  $Status == 0 && $Only_generate_deps ) {
 
-    /^-o$/         && do { $Specific_output_file = &grab_arg_arg('-o', '');
-                           if ($Specific_output_file ne '-'
-                            && $Specific_output_file =~ /(.*)\/[^\/]*$/) {
-                               local($dir_part) = $1;
-                               if (! -d $dir_part) {
-                                   print STDERR "$Pgm: no such directory: $dir_part\n";
-                                   $Status++;
-                               }
-                           }
-                           next arg; };
+    push (@MkDependHS_flags, "-o$Osuffix") if $Osuffix;
+    push (@MkDependHS_flags, "-s$BuildTag") if $BuildTag;
+    local($to_do) = "$MkDependHS @MkDependHS_flags -- @Cmd_opts -- @Input_file" ;
+    &run_something($to_do, 'Haskell dependencies');
+    exit $Status;
+}
 
-    # -ohi <file>; send the interface to <file>; "-ohi -" to send to stdout
-    /^-ohi$/       && do { $Specific_hi_file = &grab_arg_arg('-ohi', '');
-                           if ($Specific_hi_file ne '-'
-                            && $Specific_hi_file =~ /(.*)\/[^\/]*$/) {
-                               local($dir_part) = $1;
-                               if (! -d $dir_part) {
-                                   print STDERR "$Pgm: no such directory: $dir_part\n";
-                                   $Status++;
-                               }
-                           }
-                           next arg; };
+# if there are several input files,
+# we don't allow \tr{-o <file>} or \tr{-ohi <file>} options...
+# (except if linking, of course)
 
-    /^-odump$/     && do { $Specific_dump_file = &grab_arg_arg('-odump', '');
-                           if ($Specific_dump_file =~ /(.*)\/[^\/]*$/) {
-                               local($dir_part) = $1;
-                               if (! -d $dir_part) {
-                                   print STDERR "$Pgm: no such directory: $dir_part\n";
-                                   $Status++;
-                               }
-                           }
-                           next arg; };
+if ($#Input_file > 0 && ( ! $Do_lnkr )) {
+    if ( ($Specific_output_file ne '' && $Specific_output_file ne '-')
+      || ($Specific_hi_file ne ''     && $Specific_hi_file ne '-') ) {
+       print STDERR "$Pgm: You can't use -o or -ohi options if you have multiple input files.\n";
+       print STDERR "\tPerhaps the -odir option will do what you want.\n";
+       $Status++;
+    }
+}
 
-    /^-odir$/      && do { $Specific_output_dir = &grab_arg_arg('-odir', '');
-                           if (! -d $Specific_output_dir) {
-                               print STDERR "$Pgm: -odir: no such directory: $Specific_output_dir\n";
-                               $Status++;
-                           }
-                           next arg; };
+# check for various pathological -o and -odir combinations...
+if ($Specific_output_dir ne '' && $Specific_output_file ne '') {
+    if ($Specific_output_file eq '-') {
+       print STDERR "$Pgm: can't set output directory with -ohi AND have output to stdout\n";
+       $Status++;
+    } else { # amalgamate...
+       $Specific_output_file = "$Specific_output_dir/$Specific_output_file";
+       # ToDo: check we haven't got a junk name now...
+       $Specific_output_dir  = ''; # reset
+    }
+}
 
-    /^-osuf$/      && do { $Osuffix  = &grab_arg_arg('-osuf', ''); next arg; };
-    /^-hisuf$/     && do { $HiSuffix = &grab_arg_arg('-hisuf', '');
-                           push(@HsP_flags, "-h$HiSuffix");
-                           next arg; };
+# crash and burn if there were errors
+if ( $Status > 0 ) {
+    print STDERR $ShortUsage;
+    exit $Status;
+}
+\end{code}
 
-    /^-hisuf-prelude$/ && do { # as esoteric as they come...
-                           local($suffix) = &grab_arg_arg('-hisuf-prelude', '');
-                           push(@HsP_flags, "-g$suffix");
-                           next arg; };
+%************************************************************************
+%*                                                                     *
+\section[Driver-post-argv-mangling]{Setup after reading options}
+%*                                                                     *
+%************************************************************************
 
-    #-------------- scc & Profiling Stuff ----------------------------------
+%************************************************************************
+%*                                                                     *
+\subsection{Set up for optimisation level (\tr{-O} or whatever)}
+%*                                                                     *
+%************************************************************************
 
-    /^-prof$/ && do { $PROFing = 'p'; next arg; }; # profiling -- details later!
+We come now to the default ``wads of options'' that are turned on by
+\tr{-O0} (do min optimisation), \tr{-O} (ordinary optimisation),
+\tr{-O2} (aggressive optimisation), or no O-ish flag (compile speed is
+more important).
 
-    /^-auto/ && do {
-               # generate auto SCCs on top level bindings
-               # -auto-all = all top level bindings
-               # -auto     = only top level exported bindings
-               $PROFauto = ( /-all/ )
-                           ? '-fauto-sccs-on-all-toplevs'
-                           : '-fauto-sccs-on-exported-toplevs';
-               next arg; };
+The user can also specify his/her own list of options in a file; in
+that case, the work is already done (see stuff about @minusO3@,
+earlier...).
 
-    /^-caf-all/ && do { # generate individual CAF SCC annotations
-               $PROFcaf = '-fauto-sccs-on-individual-cafs';
-               next arg; };
+GHC allows very precise control of what happens during a compilation.
+Core-to-Core and STG-to-STG passes can be run in any order, as many
+times as you like.  Individual transformations can be turned on or
+disabled.
 
-# UNUSED:
-#    /^-dict-all/ && do { # generate individual SCC annotations on dictionaries
-#              $PROFdict = '-fauto-sccs-on-individual-dicts';
-#              next arg; };
+Sadly, however, there are some interdependencies \& Things You Must
+Not Do.  Here is the list.
 
-    /^-ignore-scc$/ && do {
-               # forces ignore of scc annotations even if profiling
-               $PROFignore_scc = '-W';
-               next arg; };
+CORE-TO-CORE PASSES:
+\begin{description}
+\item[\tr{-fspecialise}:]
+The specialiser must have dependency-analysed input; but if you run
+the simplifier to do this, you must not let it toss away unused
+bindings!  (The typechecker conveys some specialisation info via
+``unused'' bindings...)
 
-    /^-G(.*)$/ && do { push(@HsC_flags, $_);   # set group for cost centres
-                       next arg; };
+\item[\tr{-ffloat-inwards}:]
+Floating inwards should be done before strictness analysis, because
+the latter will give better results.
 
-    #--------- ticky/concurrent/parallel -----------------------------------
-    # we sort out the details a bit later on
+\item[\tr{-fstatic-args}:]
+The static-arguments-transformation pass {\em must} have the
+simplifier run right after it.
 
-    /^-concurrent$/ && do { $CONCURing = 'c'; next arg; }; # concurrent Haskell
-    /^-gransim$/    && do { $GRANing   = 'g'; next arg; }; # GranSim
-    /^-ticky$/     && do { $TICKYing  = 't'; next arg; }; # ticky-ticky
-    /^-parallel$/   && do { $PARing    = 'p'; next arg; } ; # parallel Haskell
+\item[\tr{-fcalc-inlinings[12]}:]
+Not required, but there may be slight gains by re-simplifying after
+this is done.  (You could then \tr{-fcalc-inlinings} again, just for
+fun.)
 
-    #-------------- "user ways" --------------------------------------------
+\item[\tr{-ffull-laziness}:]
+The (outwards-)let-floater should be the {\em last} Core-to-Core pass
+that's run.  (Um, well, howzabout the simplifier just once more...)
+\end{description}
 
-    (/^-user-setup-([a-oA-Z])$/
-    || /^$(GHC_BUILD_FLAG_a)$/
-    || /^$(GHC_BUILD_FLAG_b)$/
-    || /^$(GHC_BUILD_FLAG_c)$/
-    || /^$(GHC_BUILD_FLAG_d)$/
-    || /^$(GHC_BUILD_FLAG_e)$/
-    || /^$(GHC_BUILD_FLAG_f)$/
-    || /^$(GHC_BUILD_FLAG_g)$/
-    || /^$(GHC_BUILD_FLAG_h)$/
-    || /^$(GHC_BUILD_FLAG_i)$/
-    || /^$(GHC_BUILD_FLAG_j)$/
-    || /^$(GHC_BUILD_FLAG_k)$/
-    || /^$(GHC_BUILD_FLAG_l)$/
-    || /^$(GHC_BUILD_FLAG_m)$/
-    || /^$(GHC_BUILD_FLAG_n)$/
-    || /^$(GHC_BUILD_FLAG_o)$/
-    || /^$(GHC_BUILD_FLAG_A)$/
-    || /^$(GHC_BUILD_FLAG_B)$/
-
-    || /^$(GHC_BUILD_FLAG_2s)$/ # GC ones...
-    || /^$(GHC_BUILD_FLAG_1s)$/
-    || /^$(GHC_BUILD_FLAG_du)$/
-    ) && do {
-               /^-user-setup-([a-oA-Z])$/  && do { $BuildTag = "_$1"; };
+STG-TO-STG PASSES:
+\begin{description}
+\item[\tr{-fupdate-analysis}:]
+It really really wants to be the last STG-to-STG pass that is run.
+\end{description}
 
-               /^$(GHC_BUILD_FLAG_a)$/  && do { $BuildTag = '_a';  };
-               /^$(GHC_BUILD_FLAG_b)$/  && do { $BuildTag = '_b';  };
-               /^$(GHC_BUILD_FLAG_c)$/  && do { $BuildTag = '_c';  };
-               /^$(GHC_BUILD_FLAG_d)$/  && do { $BuildTag = '_d';  };
-               /^$(GHC_BUILD_FLAG_e)$/  && do { $BuildTag = '_e';  };
-               /^$(GHC_BUILD_FLAG_f)$/  && do { $BuildTag = '_f';  };
-               /^$(GHC_BUILD_FLAG_g)$/  && do { $BuildTag = '_g';  };
-               /^$(GHC_BUILD_FLAG_h)$/  && do { $BuildTag = '_h';  };
-               /^$(GHC_BUILD_FLAG_i)$/  && do { $BuildTag = '_i';  };
-               /^$(GHC_BUILD_FLAG_j)$/  && do { $BuildTag = '_j';  };
-               /^$(GHC_BUILD_FLAG_k)$/  && do { $BuildTag = '_k';  };
-               /^$(GHC_BUILD_FLAG_l)$/  && do { $BuildTag = '_l';  };
-               /^$(GHC_BUILD_FLAG_m)$/  && do { $BuildTag = '_m';  };
-               /^$(GHC_BUILD_FLAG_n)$/  && do { $BuildTag = '_n';  };
-               /^$(GHC_BUILD_FLAG_o)$/  && do { $BuildTag = '_o';  };
-               /^$(GHC_BUILD_FLAG_A)$/  && do { $BuildTag = '_A';  };
-               /^$(GHC_BUILD_FLAG_B)$/  && do { $BuildTag = '_B';  };
-
-               /^$(GHC_BUILD_FLAG_2s)$/ && do { $BuildTag = '_2s'; };
-               /^$(GHC_BUILD_FLAG_1s)$/ && do { $BuildTag = '_1s'; };
-               /^$(GHC_BUILD_FLAG_du)$/ && do { $BuildTag = '_du'; };
+\begin{code}
 
-               local($stuff) = $UserSetupOpts{$BuildTag};
-               local(@opts)  = split(/\s+/, $stuff);
-               
-               # feed relevant ops into the arg-processing loop (if any)
-               unshift(@ARGV, @opts) if $#opts >= 0;
+sub setupOptimiseFlags {
 
-               next arg; };
+   @HsC_minusNoO_flags 
+    = (        '-fsimplify',
+         '\(',
+         $Oopt_FB_Support,
+#        '-falways-float-lets-from-lets',      # no idea why this was here (WDP 95/09)
+         '-ffloat-lets-exposing-whnf',
+         '-ffloat-primops-ok',
+         '-fcase-of-case',
+#        '-fdo-lambda-eta-expansion',  # too complicated
+         '-freuse-con',
+#        '-flet-to-case',      # no strictness analysis, so...
+         $Oopt_PedanticBottoms,
+#        $Oopt_MonadEtaExpansion,      # no thanks
+         '-fsimpl-uf-use-threshold0',
+         '-fessential-unfoldings-only',
+#        $Oopt_UnfoldingUseThreshold,  # no thanks
+         $Oopt_MaxSimplifierIterations,
+         '\)',
+       $Oopt_AddAutoSccs,
+#      '-ffull-laziness',      # removed 95/04 WDP following Andr\'e's lead
+       
+       $Oopt_FinalStgProfilingMassage
+      );
 
-    #---------- set search paths for libraries and things ------------------
+   @HsC_minusO_flags # NOTE: used for *both* -O and -O2 (some conditional bits)
+    = (
+        '-fdo-eta-reduction',
 
-    # we do -i just like HBC (-i clears the list; -i<colon-separated-items>
-    # prepends the items to the list); -I is for including C .h files.
+       # initial simplify: mk specialiser happy: minimum effort please
+       '-fsimplify',
+         '\(', 
+         $Oopt_FB_Support,
+         '-fkeep-spec-pragma-ids',     # required before specialisation
+         '-fsimpl-uf-use-threshold0',
+         '-fessential-unfoldings-only',
+         '-fmax-simplifier-iterations1',
+         $Oopt_PedanticBottoms,
+         '\)',
 
-    /^-i$/         && do { @Import_dir = ();  # import path cleared!
-                           @SysImport_dir = ();
-                           print STDERR "WARNING: import paths cleared by `-i'\n";
-                           next arg; };
+       ($Oopt_DoSpecialise) ? (
+         '-fspecialise-overloaded',
+         $Oopt_SpecialiseUnboxed,
+         $Oopt_DoSpecialise,
+       ) : (),
 
-    /^-i(.*)/      && do { local(@new_items)
-                             = split( /:/, &grab_arg_arg('-i', $1));
-                           unshift(@Import_dir, @new_items);
-                           next arg; };
+       '-fsimplify',                   # need dependency anal after specialiser ...
+         '\(',                         # need tossing before calc-inlinings ...
+         $Oopt_FB_Support,
+         '-ffloat-lets-exposing-whnf',
+         '-ffloat-primops-ok',
+         '-fcase-of-case',
+         '-fdo-case-elim',
+         '-fcase-merge',
+#        '-fdo-eta-reduction',
+         '-fdo-lambda-eta-expansion',
+         '-freuse-con',
+         $Oopt_PedanticBottoms,
+         $Oopt_MonadEtaExpansion,
+         $Oopt_UnfoldingUseThreshold,
+         $Oopt_MaxSimplifierIterations,
+         '\)',
 
-    /^-I(.*)/      && do { push(@Include_dir,     &grab_arg_arg('-I', $1)); next arg; };
-    /^-L(.*)/      && do { push(@UserLibrary_dir, &grab_arg_arg('-L', $1)); next arg; };
-    /^-l(.*)/      && do { push(@UserLibrary,'-l'.&grab_arg_arg('-l', $1)); next arg; };
+#LATER:        '-fcalc-inlinings1', -- pointless for 2.01
 
-    /^-syslib(.*)/  && do { local($syslib) = &grab_arg_arg('-syslib',$1);
-                           print STDERR "$Pgm: no such system library (-syslib): $syslib\n",
-                             $Status++ unless $syslib =~ /^(hbc|ghc|contrib)$/;
+#      ($Oopt_FoldrBuildWW) ? (
+#              '-ffoldr-build-ww-anal',
+#              '-ffoldr-build-worker-wrapper',
+#              '-fsimplify', 
+#                '\(', 
+#                $Oopt_FB_Support,
+#                '-ffloat-lets-exposing-whnf',
+#                '-ffloat-primops-ok',
+#                '-fcase-of-case',
+#                '-fdo-case-elim',
+#                '-fcase-merge',
+#                '-fdo-eta-reduction',
+#                '-fdo-lambda-eta-expansion',
+#                '-freuse-con',
+#                $Oopt_PedanticBottoms,
+#                $Oopt_MonadEtaExpansion,
+#                $Oopt_UnfoldingUseThreshold,
+#                $Oopt_MaxSimplifierIterations,
+#                '\)',
+#       ) : (),
 
-                           unshift(@SysImport_dir,
-                               $(INSTALLING)
-                               ? "$InstDataDirGhc/imports/$syslib"
-                               : "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/$syslib");
+       # this pass-ordering sequence was agreed by Simon and Andr\'e
+       # (WDP 94/07, 94/11).
+       '-ffull-laziness',
 
-                           unshift(@SysLibrary, ('-lHS' . $syslib ));
+       ($Oopt_FoldrBuild) ? (
+         '-ffoldr-build-on',           # desugar list comprehensions for foldr/build
 
-                           next arg; };
+         '-fsimplify', 
+           '\(', 
+           '-fignore-inline-pragma',   # **** NB!
+           '-fdo-foldr-build',         # NB
+           $Oopt_FB_Support,
+           '-ffloat-lets-exposing-whnf',
+           '-ffloat-primops-ok',
+           '-fcase-of-case',
+           '-fdo-case-elim',
+           '-fcase-merge',
+#          '-fdo-eta-reduction',
+           '-fdo-lambda-eta-expansion',        # After full laziness
+           '-freuse-con',
+           $Oopt_PedanticBottoms,
+           $Oopt_MonadEtaExpansion,
+           $Oopt_UnfoldingUseThreshold,
+           $Oopt_MaxSimplifierIterations,
+           '\)',
+       ) : (),
 
-    #=======================================================================
-    # various flags that we can harmlessly send to one program or another
-    # (we will later "reclaim" some of the compiler ones now sent to gcc)
-    #=======================================================================
+       '-ffloat-inwards',
 
-    #---------- this driver itself (ghc) -----------------------------------
-    # these change what executable is run for each phase:
-    /^-pgmL(.*)$/   && do { $Unlit   = $1; next arg; };
-    /^-pgmP(.*)$/   && do { $HsCpp   = $1; next arg; };
-    /^-pgmp(.*)$/   && do { $HsP     = $1; next arg; };
-    /^-pgmC(.*)$/   && do { $HsC     = $1; next arg; };
-    /^-pgmcO(.*)$/  && do { $CcRegd   = $1; next arg; };
-    /^-pgmc(.*)$/   && do { $CcUnregd  = $1; next arg; };
-    /^-pgma(.*)$/   && do { $As      = $1; next arg; };
-    /^-pgml(.*)$/   && do { $Lnkr    = $1; next arg; };
+       '-fsimplify',
+         '\(', 
+         $Oopt_FB_Support,
+         '-ffloat-lets-exposing-whnf',
+         '-ffloat-primops-ok',
+         '-fcase-of-case',
+         '-fdo-case-elim',
+         '-fcase-merge',
+         '-fdo-eta-reduction',
+         '-fdo-lambda-eta-expansion',
+         '-freuse-con',
+         ($Oopt_FoldrBuildInline),
+                       # you need to inline foldr and build
+         ($Oopt_FoldrBuild) ? ('-fdo-foldr-build') : (), 
+                       # but do reductions if you see them!
+         $Oopt_PedanticBottoms,
+         $Oopt_MonadEtaExpansion,
+         $Oopt_UnfoldingUseThreshold,
+         $Oopt_MaxSimplifierIterations,
+         '\)',
 
-    #---------- the get-anything-through opts (all pgms) -------------------
-    # these allow arbitrary option-strings to go to any phase:
-    /^-optL(.*)$/   && do { push(@Unlit_flags,   $1); next arg; };
-    /^-optP(.*)$/   && do { push(@HsCpp_flags,   $1); next arg; };
-    /^-optp(.*)$/   && do { push(@HsP_flags,     $1); next arg; };
-    /^-optCrts(.*)$/&& do { push(@HsC_rts_flags, $1); next arg; };
-    /^-optC(.*)$/   && do { push(@HsC_flags,     $1); next arg; };
-    /^-optcNhc(.*)$/ && do { push(@CcUnregd_flags_hc,$1); next arg; };
-    /^-optcNc(.*)$/  && do { push(@CcUnregd_flags_c,$1); next arg; };
-    /^-optcN(.*)$/  && do { push(@CcUnregd_flags,   $1); next arg; };
-    /^-optcOhc(.*)$/&& do { push(@CcRegd_flags_hc,$1); next arg; };
-    /^-optcOc(.*)$/ && do { push(@CcRegd_flags_c, $1); next arg; };
-    /^-optcO(.*)$/  && do { push(@CcRegd_flags,   $1); next arg; };
-    /^-optc(.*)$/   && do { push(@CcBoth_flags,  $1); next arg; };
-    /^-opta(.*)$/   && do { push(@As_flags,      $1); next arg; };
-    /^-optl(.*)$/   && do { push(@Ld_flags,      $1); next arg; };
+       '-fstrictness',
 
-    #---------- Haskell C pre-processor (hscpp) ----------------------------
-    /^-D(.*)/      && do { push(@HsCpp_flags, "'-D".&grab_arg_arg('-D',$1)."'"); next arg; };
-    /^-U(.*)/      && do { push(@HsCpp_flags, "'-U".&grab_arg_arg('-U',$1)."'"); next arg; };
+       '-fsimplify',
+         '\(', 
+         $Oopt_FB_Support,
+         '-ffloat-lets-exposing-whnf',
+         '-ffloat-primops-ok',
+         '-fcase-of-case',
+         '-fdo-case-elim',
+         '-fcase-merge',
+#        '-fdo-eta-reduction',
+         '-fdo-lambda-eta-expansion',
+         '-freuse-con',
+         '-flet-to-case',              # Aha! Only done after strictness analysis
+         $Oopt_PedanticBottoms,
+         $Oopt_MonadEtaExpansion,
+         $Oopt_UnfoldingUseThreshold,
+         $Oopt_MaxSimplifierIterations,
+         '\)',
 
-    #---------- Haskell parser (hsp) ---------------------------------------
-    /^-ddump-parser$/ && do { $Dump_parser_output = 1; next arg; };
+       '-ffloat-inwards',
 
-    #---------- post-Haskell "assembler"------------------------------------
-    /^-ddump-raw-asm$/         && do { $Dump_raw_asm          = 1; next arg; };
-    /^-ddump-asm-insn-counts$/  && do { $Dump_asm_insn_counts  = 1; next arg; };
-    /^-ddump-asm-globals-info$/ && do { $Dump_asm_globals_info = 1; next arg; };
+# Case-liberation for -O2.  This should be after
+# strictness analysis and the simplification which follows it.
 
-    /^-ddump-asm-splitting-info$/ && do { $Dump_asm_splitting_info = 1; next arg; };
+#      ( ($OptLevel != 2)
+#        ? ''
+#      : "-fliberate-case -fsimplify \\( $Oopt_FB_Support -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fcase-merge -fdo-eta-reduction -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MonadEtaExpansion $Oopt_UnfoldingUseThreshold $Oopt_MaxSimplifierIterations \\)" ),
 
-    #---------- Haskell compiler (hsc) -------------------------------------
+# Final clean-up simplification:
 
-# possibly resurrect LATER
-#   /^-fspat-profiling$/  && do { push(@HsC_flags, '-fticky-ticky');
-#                          $ProduceS = ''; $ProduceC = 1; # must use C compiler
-#                          push(@CcBoth_flags, '-DDO_SPAT_PROFILING');
-#                          push(@CcBoth_flags, '-fno-schedule-insns'); # not essential
-#                          next arg; };
+       '-fsimplify',
+         '\(', 
+         $Oopt_FB_Support,
+         '-ffloat-lets-exposing-whnf',
+         '-ffloat-primops-ok',
+         '-fcase-of-case',
+         '-fdo-case-elim',
+         '-fcase-merge',
+#        '-fdo-eta-reduction',
+         '-fdo-lambda-eta-expansion',
+         '-freuse-con',
+         '-flet-to-case',
+         '-fignore-inline-pragma',     # **** NB!
+         $Oopt_FoldrBuildInline,       
+         ($Oopt_FoldrBuild) ? ('-fdo-foldr-build') : (), 
+                       # but still do reductions if you see them!
+         $Oopt_PedanticBottoms,
+         $Oopt_MonadEtaExpansion,
+         $Oopt_UnfoldingUseThreshold,
+         $Oopt_MaxSimplifierIterations,
+         '\)',
 
-    /^-keep-hc-files?-too$/    && do { $Keep_hc_file_too = 1; next arg; };
-    /^-keep-s-files?-too$/     && do { $Keep_s_file_too = 1;  next arg; };
+      #        '-fstatic-args',
 
-    /^-fhaskell-1\.3$/         && do { $haskell1_version = 3;
-                                       push(@HsP_flags, '-3');
-                                       push(@HsC_flags, $_);
-                                       $TopClosureFile =~ s/TopClosureXXXX/TopClosure13XXXX/;
-                                       unshift(@SysImport_dir,
-                                           $(INSTALLING)
-                                           ? "$InstDataDirGhc/imports/haskell-1.3"
-                                           : "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/haskell-1.3");
+#LATER:        '-fcalc-inlinings2', -- pointless for 2.01
 
-                                       unshift(@SysLibrary, '-lHS13');
+      # stg2stg passes
+       '-fupdate-analysis',
+       '-flambda-lift',
+       $Oopt_FinalStgProfilingMassage,
+       $Oopt_StgStats,
 
-                                       next arg; };
+      # flags for stg2stg
+       '-flet-no-escape',
 
-    /^-fno-implicit-prelude$/      && do { push(@HsP_flags, '-P'); next arg; };
-    /^-fignore-interface-pragmas$/ && do { push(@HsP_flags, '-p'); next arg; };
+      # SPECIAL FLAGS for -O2
+       ($OptLevel == 2) ? (
+         '-fsemi-tagging',
+       ) : (),
+      );
 
-    /^-prelude$/               && do { $CompilingPrelude = 1;
-                                       push(@HsC_flags, $_); next arg; };
+\end{code}
 
-    /^-split-objs(.*)/ && do {
-                       local($sname) = &grab_arg_arg('-split-objs', $1);
-                       $sname =~ s/ //g; # no spaces
+Sort out what we're going to do about optimising.  First, the @hsc@
+flags and regular @cc@ flags to worry about:
+\begin{code}
+if ( $OptLevel <= 0 ) {
 
-                       if ( $TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/ ) {
-                           $SplitObjFiles = 1;
-                           push(@HsC_flags, "-fglobalise-toplev-names$sname"); 
-                           push(@CcBoth_flags, '-DUSE_SPLIT_MARKERS');
+    # for this level, we tell the parser -fignore-interface-pragmas
+    push(@HsC_flags, '-fignore-interface-pragmas');
+    # and tell the compiler not to produce them
+    push(@HsC_flags, '-fomit-interface-pragmas');
 
-                           require('ghc-split.prl')
-                            || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-split.prl!\n");
-                       } else {
-                           $SplitObjFiles = 0;
-                           print STDERR "WARNING: don't know how to split objects on this platform: $TargetPlatform\n`-split-objs' option ignored\n";
-                       }
-                       next arg; };
+    &add_Hsc_flags( @HsC_minusNoO_flags );
+    push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O');        # not optional!
 
-    /^-fglobalise-toplev-names$/&& do { push(@HsC_flags, $_); next arg; };
+} elsif ( $OptLevel == 1 || $OptLevel == 2 ) {
 
-    /^-f(hide-builtin-names|min-builtin-names)$/
-               && do { push(@HsC_flags, $_);
-                       push(@HsP_flags, '-P'); # don't read Prelude.hi
-                       push(@HsP_flags, '-N'); # allow foo# names
-                       next arg; };
-    /^-f(glasgow-exts|hide-builtin-instances)$/
-               && do { push(@HsC_flags, $_);
-                       push(@HsP_flags, '-N');
+    &add_Hsc_flags( @HsC_minusO_flags );
+    push(@CcBoth_flags, ($MinusO2ForC || $OptLevel == 2) ? '-O2' : '-O'); # not optional!
+    # -O? to GCC is not optional! -O2 probably isn't worth it generally,
+    # but it *is* useful in compiling the garbage collectors (so said
+    # Patrick many moons ago...).
 
-#                      push(@HsC_flags, '-fshow-import-specs');
+} else { # -Ofile, then...
 
-                       if ( ! $(INSTALLING) ) {
-                           unshift(@SysImport_dir,
-                               "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/glaExts");
-                       }
-                       next arg; };
+    &add_Hsc_flags( @HsC_minusO3_flags );
+    push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O');        # possibly to be elaborated...
+}
 
-    /^-fspecialise-unboxed$/
-               && do { $Oopt_SpecialiseUnboxed = '-fspecialise-unboxed';
-                       next arg; };
+} # setupOptimiseFlags
 
-# Now the foldr/build options, which are *on* by default (for -O).
+\end{code}
 
-    /^-fno-foldr-build$/
-                   && do { $Oopt_FoldrBuild = 0; 
-                           $Oopt_FB_Support = ''; 
-                           next arg; };
+%************************************************************************
+%*                                                                     *
+\subsection{Check for consistency, etc.}
+%*                                                                     *
+%************************************************************************
 
-    /^-fno-foldr-build-rule$/
-                   && do { $Oopt_FoldrBuild = 0; 
-                              next arg; };
+Sort out @$BuildTag@, @$PROFing@, @$CONCURing@, @$PARing@,
+@$GRANing@, @$TICKYing@:
+\begin{code}
+sub setupBuildFlags {
+
+
+   # PROFILING stuff after argv mangling:
+   if ( ! $PROFing ) {
+     # warn about any scc exprs found (in case scc used as identifier)
+     push(@HsP_flags, '-W');
+
+     # add -auto sccs even if not profiling !
+     push(@HsC_flags, $UNPROFscc_auto) if $UNPROFscc_auto;
+
+   } else {
+      push(@HsC_flags, $PROFauto) if $PROFauto;
+      push(@HsC_flags, $PROFcaf)  if $PROFcaf;
+      #push(@HsC_flags, $PROFdict) if $PROFdict;
+
+      $Oopt_FinalStgProfilingMassage = '-fmassage-stg-for-profiling';
+
+      push(@HsP_flags, (($PROFignore_scc) ? $PROFignore_scc : '-S'));
+
+      if ( $SplitObjFiles ) {
+        # can't split with cost centres -- would need global and externs
+        print STDERR "$Pgm: WARNING: splitting objects when profiling will *BREAK* if any _scc_s are present!\n";
+        # (but it's fine if there aren't any _scc_s around...)
+#       $SplitObjFiles = 0; # unset
+        #not an error: for now: $Status++;
+      }
+  }
+  #if ( $BuildTag ne '' ) {
+  #    local($b) = $BuildDescr{$BuildTag};
+  #    if ($CONCURing eq 'c') { print STDERR "$Pgm: Can't mix $b with -concurrent.\n"; exit 1; }
+  #    if ($PARing    eq 'p') { print STDERR "$Pgm: Can't mix $b with -parallel.\n"; exit 1; }
+  #    if ($GRANing   eq 'g') { print STDERR "$Pgm: Can't mix $b with -gransim.\n"; exit 1; }
+  #    if ($TICKYing  eq 't') { print STDERR "$Pgm: Can't mix $b with -ticky.\n"; exit 1; }
+
+  #    # ok to have a user-way profiling build
+  #    # eval the profiling opts ... but leave user-way BuildTag 
+  #    if ($PROFing   eq 'p') { &processArgs(split(' ', $SetupOpts{'_p'})); } # eval($EvaldSetupOpts{'_p'}); }
+
+  if ( $PROFing eq 'p' ) {
+      if ($PARing   eq 'p') { print STDERR "$Pgm: Can't do profiling with -parallel.\n"; exit 1; }
+      if ($GRANing  eq 'g') { print STDERR "$Pgm: Can't do profiling with -gransim.\n"; exit 1; }
+      if ($TICKYing eq 't') { print STDERR "$Pgm: Can't do profiling with -ticky.\n"; exit 1; }
+      $BuildTag = ($CONCURing eq 'c') ? '_mr' : '_p' ; # possibly "profiled concurrent"...
+
+  } elsif ( $CONCURing eq 'c' ) {
+      if ($PARing  eq 'p') { print STDERR "$Pgm: Can't mix -concurrent with -parallel.\n"; exit 1; }
+      if ($GRANing eq 'g') { print STDERR "$Pgm: Can't mix -concurrent with -gransim.\n"; exit 1; }
+      $BuildTag = ($TICKYing eq 't')  ? '_mt' : '_mc' ; # possibly "ticky concurrent"...
+      # "profiled concurrent" already acct'd for...
+
+  } elsif ( $PARing eq 'p' ) {
+      if ($GRANing  eq 'g') { print STDERR "$Pgm: Can't mix -parallel with -gransim.\n"; exit 1; }
+      if ($TICKYing eq 't') { print STDERR "$Pgm: Can't mix -parallel with -ticky.\n"; exit 1; }
+      $BuildTag = '_mp';
+
+      if ( $Do_lnkr && ( ! $ENV{'PVM_ROOT'} || ! $ENV{'PVM_ARCH'} )) {
+         print STDERR "$Pgm: both your PVM_ROOT and PVM_ARCH environment variables must be set for linking under -parallel.\n";
+         exit(1);
+      }
+
+  } elsif ( $GRANing eq 'g' ) {
+      if ($TICKYing eq 't') { print STDERR "$Pgm: Can't mix -gransim with -ticky.\n"; exit 1; }
+      $BuildTag = '_mg';
+
+  } elsif ( $TICKYing eq 't' ) {
+      $BuildTag = '_t';
+  }
 
-    /^-fno-enable-tech$/
-                   && do { $Oopt_FB_Support = ''; 
-                           next arg; };
+\end{code}
 
-#    /^-ffoldr-build-ww$/
-#                  && do { $Oopt_FoldrBuildWW = 1; next arg; };
+After the sanity checks, add flags to the necessary parts of the driver pipeline:
 
+\begin{code}
+  if ( $BuildTag ne '' ) { # something other than normal sequential...
 
-    /^-fasm-(.*)$/  && do { $ProduceS = $1; $ProduceC = 0; # force using nativeGen
-                           push(@HsC_flags, $_); # if from the command line
-                           next arg; };
+      local($Tag) = "${BuildTag}";
+      $Tag =~ s/_//;  # move the underscore to the back
 
-    /^-fvia-C$/            && do { $ProduceS = ''; $ProduceC = 1; # force using C compiler
-                           next arg; };
+      $HscOut = '-C='; # must go via C
+      &processArgs(split(' ', $SetupOpts{$BuildTag}));
+#      eval($EvaldSetupOpts{$BuildTag});
+  }
+\end{code}
 
-    /^-f(no-)?omit-frame-pointer$/ && do {
-                           unshift(@CcBoth_flags, ( $_ ));
-                           next arg; };
+Decide what the consistency-checking options are in force for this run:
+\begin{code}
 
-    # ---------------
+  $HsC_consist_options = "${BuildTag},${DEBUGging}";
+  $Cc_consist_options  = "${BuildTag},${DEBUGging}";
+
+  #
+  # Funny place to put it, but why not.
+  #
+  if ( $HiSuffix_prelude eq '' ) {
+       local($Tag) = "${BuildTag}";
+       $Tag =~ s/_//;
+       $Tag = "${Tag}_" if $Tag ne '';
+       $HiSuffix_prelude="${Tag}hi";
+  }
+  push(@HsC_flags, "-hisuf-prelude=.${HiSuffix_prelude}"); # use appropriate Prelude .hi files
+  push(@HsC_flags, "-hisuf=.${HiSuffix}");
+
+} # setupBuildFlags
+\end{code}
 
-    /^(-fsimpl-uf-use-threshold)(.*)$/
-                   && do { $Oopt_UnfoldingUseThreshold = $1 . &grab_arg_arg($1, $2);
-                           next arg; };
+%************************************************************************
+%*                                                                     *
+\subsection{Add on machine-specific C-compiler flags}
+%*                                                                     *
+%************************************************************************
 
-    /^(-fmax-simplifier-iterations)(.*)$/
-                   && do { $Oopt_MaxSimplifierIterations = $1 . &grab_arg_arg($1, $2);
-                           next arg; };
+Shove on magical machine-specific options.  We use \tr{unshift} to
+stick them on the {\em front} of the arrays, so that ``later''
+user-specified flags can clobber them (e.g., \tr{-U__STG_REV_TBLS__}).
 
-    /^-fno-pedantic-bottoms$/
-                   && do { $Oopt_PedanticBottoms = ''; next arg; };
+Note: a few ``always apply'' flags were set at the very beginning.
 
-    /^-fdo-monad-eta-expansion$/
-                   && do { $Oopt_MonadEtaExpansion = $_; next arg; };
+\begin{code}
+sub setupMachOpts {
+
+  if ($TargetPlatform =~ /^alpha-/) {
+      # we know how to *mangle* asm for alpha
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
+      unshift(@CcBoth_flags,  ('-static'));
+
+  } elsif ($TargetPlatform =~ /^hppa/) {
+      # we know how to *mangle* asm for hppa
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcBoth_flags,  ('-static'));
+      #
+      # We don't put in '-mlong-calls', because it's only
+      # needed for very big modules (sigh), and we don't want
+      # to hobble ourselves further on all the other modules
+      # (most of them).
+      #  
+      # [Dated comment (gcc-2.6.x?), -mlong-calls is no longer
+      #  a supported gcc HPPA flag]
+      unshift(@CcBoth_flags,  ('-D_HPUX_SOURCE'));
+        # ___HPUX_SOURCE, not _HPUX_SOURCE, is #defined if -ansi!
+        # (very nice, but too bad the HP /usr/include files don't agree.)
 
-    /^-fno-let-from-(case|app|strict-let)$/ # experimental, really (WDP 95/10)
-                   && do { push(@HsC_flags, $_); next arg; };
+  } elsif ($TargetPlatform =~ /^i386-/) {
+      # we know how to *mangle* asm for X86
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) 
+                       if $StkChkByPageFaultOK
+                          && $TargetPlatform !~ /nextstep/;
+      # I do not know how to do STACK_CHECK_BY_PAGE_FAULT
+      # on NeXTs (my fault, not theirs), so I don't.
+      # CaS
+
+      # -fno-defer-pop : basically the same game as for m68k
+      #
+      # -fomit-frame-pointer : *must* ; because we're stealing
+      #         the fp (%ebp) for our register maps.  *All* register
+      #         maps (in MachRegs.lh) must steal it.
+
+      unshift(@CcRegd_flags_hc, '-fno-defer-pop');
+      unshift(@CcRegd_flags,    '-fomit-frame-pointer');
+      unshift(@CcRegd_flags,    "-DSTOLEN_X86_REGS=$StolenX86Regs");
+
+  } elsif ($TargetPlatform =~ /^m68k-/) {
+      # we know how to *mangle* asm for m68k
+      unshift (@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift (@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) 
+                       if $StkChkByPageFaultOK
+                          && $TargetPlatform !~ /nextstep/;
+      # I do not know how to do STACK_CHECK_BY_PAGE_FAULT
+      # on NeXTs (my fault, not theirs), so I don't.
+      # CaS
+
+      # -fno-defer-pop : for the .hc files, we want all the pushing/
+      #    popping of args to routines to be explicit; if we let things
+      #    be deferred 'til after an STGJUMP, imminent death is certain!
+      #
+      # -fomit-frame-pointer : *don't*
+      #           It's better to have a6 completely tied up being a frame pointer
+      #           rather than let GCC pick random things to do with it.
+      #           (If we want to steal a6, then we would try to do things
+      #           as on iX86, where we *do* steal the frame pointer [%ebp].)
+
+      unshift(@CcRegd_flags_hc, '-fno-defer-pop');
+      unshift(@CcRegd_flags,    '-fno-omit-frame-pointer');
+       # maybe gives reg alloc a better time
+       # also: -fno-defer-pop is not sufficiently well-behaved without it
 
-    /^(-freturn-in-regs-threshold)(.*)$/
-                   && do { local($what) = $1;
-                           local($num)  = &grab_arg_arg($what, $2);
-                           if ($num < 2 || $num > 8) {
-                               die "Bad experimental flag: $_\n";
-                           } else {
-                               $ProduceS = ''; $ProduceC = 1; # force using C compiler
-                               push(@HsC_flags, "$what$num");
-                               push(@CcRegd_flags, "-D__STG_REGS_AVAIL__=$num");
-                           }
-                           next arg; };
+  } elsif ($TargetPlatform =~ /^mips-/) {
+      # we (hope to) know how to *mangle* asm for MIPSen
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
+      unshift(@CcBoth_flags,  ('-static'));
+
+  } elsif ($TargetPlatform =~ /^powerpc-/) {
+      # we know how to *mangle* asm for PowerPC
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
+      unshift(@CcBoth_flags,  ('-static')); # always easier to start with
+      unshift(@CcRegd_flags, ('-finhibit-size-directive')); # avoids traceback tables
+
+  } elsif ($TargetPlatform =~ /^sparc-/) {
+      # we know how to *mangle* asm for SPARC
+      unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
+      unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
+
+  }
+} # end of setupMachOpts
+\end{code}
 
-#    /^-flambda-lift$/ # so Simon can do some testing; ToDo:rm
-#                  && do { $Oopt_LambdaLift = $_; next arg; };
+Same unshifting magic, but for special linker flags.
 
-    # ---------------
+The configure script determines whether the object file symbol tables
+have a leading underscore, and sets @LeadingUnderscore@ accordingly.
+(The driver script `sees' the setting of the @LeadingUnderscore@
+by having the Makefile prepend it).
 
-    /^-fno-(.*)$/   && do { push(@HsC_antiflags, "-f$1");
-                           &squashHscFlag("-f$1");
-                           next arg; };
+\begin{code}
+sub setupLinkOpts {
+  local($uscore) = ( ${LeadingUnderscore} eq 'YES' ) ? '_' : '';
+
+  unshift(@Ld_flags,
+        (($Ld_main) ? (
+          '-u', "${uscore}Main_" . $Ld_main . '_closure',
+        ) : ()
+# What are these? -- SOF
+#         , '-u', "${uscore}STbase_unsafePerformPrimIO_fast1"
+#         , '-u', "${uscore}Prelude_Z91Z93_closure"     # i.e., []
+#         , '-u', "${uscore}Prelude_IZh_static_info"
+#         , '-u', "${uscore}Prelude_False_inregs_info"
+#         , '-u', "${uscore}Prelude_True_inregs_info"
+#         , '-u', "${uscore}Prelude_CZh_static_info"
+#         , '-u', "${uscore}DEBUG_REGS"
+       ))
+         ; # just for fun, now...
+
+} # end of setupLinkOpts
 
-    /^-f/          && do { push(@HsC_flags, $_); next arg; };
+\end{code}
 
-    # ---------------
-
-    /^-mlong-calls$/ && do { # for GCC for HP-PA boxes
-                           unshift(@CcBoth_flags, ( $_ ));
-                           next arg; };
-
-    /^-m(v8|sparclite|cypress|supersparc|cpu=(cypress|supersparc))$/
-                    && do { # for GCC for SPARCs
-                           unshift(@CcBoth_flags, ( $_ ));
-                           next arg; };
+%************************************************************************
+%*                                                                     *
+\subsection{Set up include paths and system-library enslurpment}
+%*                                                                     *
+%************************************************************************
 
-    /^-monly-([432])-regs/ && do { # for iX86 boxes only; no effect otherwise
-                           $StolenX86Regs = $1;
-                           next arg; };
+Now that we know what garbage-collector, etc., are required, we can
+finalise our list of libraries to slurp through, and generally Get
+Ready for Business.
 
-    /^-mtoggle-sp-mangling/ && do { # for iX86 boxes only; for RTS only
-                           print STDERR "$Pgm: warning: -mtoggle-sp-mangling is no longer supported\n";
-#                          $SpX86Mangling = 1 - $SpX86Mangling;
-                           next arg; };
+\begin{code}
+sub setupIncPaths {
+  # default includes must be added AFTER option processing
+  if ( ! $INSTALLING ) {
+      push (@Include_dir, "$TopPwd/${CURRENT_DIR}/${GHC_INCLUDE_DIR}");
+  } else {
+      push (@Include_dir, "$InstLibDirGhc/includes");
+      push (@Include_dir, "$InstLibDirGhc/includes");
+  }
+} # end of setupIncPaths
+\end{code}
 
-    #*************** ... and lots of debugging ones (form: -d* )
+\begin{code}
+sub setupSyslibs {
+  push(@SysLibrary, ( '-lHS', '-lHS_cbits' )); # basic I/O and prelude stuff
+
+  local($f);
+  foreach $f (@SysLibrary) {
+      next if $f =~ /_cbits/;
+      $f .= $BuildTag if $f =~ /^-lHS/;
+  }
+
+  # fiddle the TopClosure file name...
+  $TopClosureFile =~ s/XXXX//;
+
+  # Push library HSrts, plus boring clib bit
+  push(@SysLibrary, "-lHSrts${BuildTag}");
+  push(@SysLibrary, '-lHSclib');
+  #
+  # RTS compiled with cygwin32, uses the WinMM API
+  # to implement the itimers, since cygwin.dll does not
+  # support it. Only reqd. for `ways' that use itimers.
+  #
+  push(@SysLibrary, '-lwinmm') if $BuildTag ne '' && $TargetPlatform eq 'i386-unknown-cygwin32';
+
+  # Push the pvm libraries
+  if ($BuildTag eq '_mp') {
+      $pvmlib = "$ENV{'PVM_ROOT'}/lib/$ENV{'PVM_ARCH'}";
+      push(@SysLibrary, "-L$pvmlib", '-lpvm3', '-lgpvm3');
+      if ( $ENV{'PVM_ARCH'} eq 'SUNMP' ) {
+          push(@SysLibrary, '-lthread', '-lsocket', '-lnsl');
+      } elsif ( $ENV{'PVM_ARCH'} eq 'SUN4SOL2' ) {
+          push(@SysLibrary, '-lsocket', '-lnsl');
+      }
+  }
 
-    /^-darity-checks$/ && do {
-                           push(@HsC_flags, $_);
-                           push(@CcBoth_flags, '-D__DO_ARITY_CHKS__'); 
-                           next arg; };
-    /^-darity-checks-C-only$/ && do {
-                           # so we'll have arity-checkable .hc files
-                           # should we decide we need them later...
-                           push(@HsC_flags, '-darity-checks');
-                           next arg; };
-    /^-dno-stk-checks$/        && do {
-                           push(@HsC_flags, '-dno-stk-chks');
-                           push(@CcBoth_flags, '-D__OMIT_STK_CHKS__'); 
-                           next arg; };
+# Push the GNU multi-precision arith lib; and the math library
+push(@SysLibrary, '-lgmp');
+push(@SysLibrary, '-lm');
+\end{code}
 
-    # -d(no-)core-lint is done this way so it is turn-off-able.
-    /^-dcore-lint/       && do { $CoreLint = '-dcore-lint'; next arg; };
-    /^-dno-core-lint/    && do { $CoreLint = '';           next arg; };
+%************************************************************************
+%*                                                                     *
+\subsection{Check that this system was built to do what we are asking}
+%*                                                                     *
+%************************************************************************
 
-    /^-d(dump|ppr)-/         && do { push(@HsC_flags, $_); next arg; };
-    /^-dverbose-(simpl|stg)/ && do { push(@HsC_flags, $_); next arg; };
-    /^-dsimplifier-stats/    && do { push(@HsC_flags, $_); next arg; };
-    /^-dstg-stats/          && do { $Oopt_StgStats = $_; next arg; };
+Before continuing we check that the appropriate build is available.
 
-    #*************** ... and now all these -R* ones for its runtime system...
+\begin{code}
+#die "$Pgm: no BuildAvail?? $BuildTag\n" if $BuildDescr{$BuildTag} eq '' ; # sanity
 
-    /^-Rhbc$/      && do { $RTS_style = 'hbc'; next arg; };
-    /^-Rghc$/      && do { $RTS_style = 'ghc'; next arg; };
+if ( $BuildDescr{$BuildTag} eq '' ) {
+    print STDERR "$Pgm: a `", $BuildDescr{$BuildTag},
+       "' \"build\" is not available with your GHC setup.\n";
+    print STDERR "(It was not configured for it at your site.)\n";
+    print STDERR $ShortUsage;
+    exit 1;
+}
 
-    /^-Rscale-sizes?(.*)/ && do {
-       $Scale_sizes_by = &grab_arg_arg('-Rscale-sizes', $1);
-       next arg; };
+} # end of setupSyslibs
 
-    /^(-H|-Rmax-heapsize)(.*)/ && do {
-       local($heap_size) = &grab_arg_arg($1, $2);
-       if ($heap_size =~ /(\d+)[Kk]$/) {
-           $heap_size = $1 * 1000;
-       } elsif ($heap_size =~ /(\d+)[Mm]$/) {
-           $heap_size = $1 * 1000 * 1000;
-       } elsif ($heap_size =~ /(\d+)[Gg]$/) {
-           $heap_size = $1 * 1000 * 1000 * 1000;
-       }
-       if ($heap_size <= 0) {
-           print STDERR "$Pgm: resetting heap-size to zero!!!\n";
-           $Specific_heap_size = 0;
-       }
-       # if several heap sizes given, take the largest...
-       if ($heap_size >= $Specific_heap_size) {
-           $Specific_heap_size = $heap_size;
-       } else {
-           print STDERR "$Pgm: ignoring heap-size-setting option ($_)...not the largest seen\n";
-       }
-       next arg; };
+\end{code}
 
-    /^-(K|Rmax-(stk|stack)size)(.*)/ && do {
-       local($stk_size) = &grab_arg_arg('-Rmax-stksize', $3);
-       if ($stk_size =~ /(\d+)[Kk]$/) {
-           $stk_size = $1 * 1000;
-       } elsif ($stk_size =~ /(\d+)[Mm]$/) {
-           $stk_size = $1 * 1000 * 1000;
-       } elsif ($stk_size =~ /(\d+)[Gg]$/) {
-           $stk_size = $1 * 1000 * 1000 * 1000;
-       }
-       if ($stk_size <= 0) {
-           print STDERR "$Pgm: resetting stack-size to zero!!!\n";
-           $Specific_stk_size = 0;
-       }
-       # if several stack sizes given, take the largest...
-       if ($stk_size >= $Specific_stk_size) {
-           $Specific_stk_size = $stk_size;
-       } else {
-           print STDERR "$Pgm: ignoring stack-size-setting option (-Rmax-stksize $stk_size)...not the largest seen\n";
-       }
-       next arg; };
+%************************************************************************
+%*                                                                     *
+\subsection{Final miscellaneous setup bits before we start going}
+%*                                                                     *
+%************************************************************************
 
-    /^-Rgc-stats$/ && do {  $CollectingGCstats++;
-                           # the two RTSs do this diff ways; we will try to compensate
-                           next arg; };
+Record largest specific heapsize, if any.
+\begin{code}
+sub setupHeapStackSize {
+   $Specific_heap_size = $Specific_heap_size * $Scale_sizes_by;
+   push(@HsC_rts_flags, '-H'.$Specific_heap_size);
+   $Specific_stk_size = $Specific_stk_size * $Scale_sizes_by;
+   push(@HsC_rts_flags, "-K$Specific_stk_size");
+}
+\end{code}
 
-    /^-Rghc-timing/ && do { $CollectGhcTimings = 1; next arg; };
+If no input or link files seen, then we let 'em feed in stdin; this is
+mainly for debugging.
 
-    #---------- C high-level assembler (gcc) -------------------------------
-# OLD: and dangerous
-#    /^-g$/            && do { push(@CcBoth_flags, $_); next arg; };
-#    /^-(p|pg)$/               && do { push(@CcBoth_flags, $_); push(@Ld_flags, $_); next arg; };
-#    /^-(fpic|fPIC)$/  && do { push(@CcBoth_flags, $_); push(@As_flags, $_); next arg; };
+\begin{code}
 
-    /^-(Wall|ansi|pedantic)$/ && do { push(@CcBoth_flags, $_); next arg; };
+if ($#Input_file < 0 && $#Link_file < 0) {
+    @Input_file = ( '-' );
 
-    # -dgcc-lint is a useful way of making GCC very fussy.
-    # From alan@spri.levels.unisa.edu.au (Alan Modra).
-    /^-dgcc-lint$/ && do { push(@CcBoth_flags, '-Wall -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs'); next arg; };
-    # An alternate set, from mark@sgcs.com (Mark W. Snitily)
-    # -Wall -Wstrict-prototypes -Wmissing-prototypes -Wcast-align -Wshadow
+    open(INF, "> $Tmp_prefix.hs") || &tidy_up_and_die(1,"Can't open $Tmp_prefix.hs\n");
+    print STDERR "Enter your Haskell program, end with ^D (on a line of its own):\n";
+    while (<>) { print INF $_; }
+    close(INF) || &tidy_up_and_die(1,"Failed writing to $Tmp_prefix.hs\n");
+}
 
-    # inject "#include <wurble>" into the compiler's C output!
+\end{code}
 
-    /^-#include(.*)/   && do {
-       local($to_include) = &grab_arg_arg('-#include', $1);
-       push(@CcInjects, "#include $to_include\n");
-       next arg; };
+Tell the world who we are, if they asked.
+\begin{code}
+print STDERR "${PROJECTNAME}, version ${PROJECTVERSION}, patchlevel ${PROJECTPATCHLEVEL}\n"
+    if $Verbose;
+\end{code}
 
-    #---------- Linker (gcc, really) ---------------------------------------
+%************************************************************************
+%*                                                                     *
+\section[Driver-main-loop]{Main loop: Process input files, and link if required}
+%*                                                                     *
+%************************************************************************
 
-    /^-static$/                && do { push(@Ld_flags, $_); next arg; };
+Process the input files; don't continue with linking if there are
+problems (global variable @$Status@ non-zero).
+\begin{code}
+foreach $ifile (@Input_file) {
+    &ProcessInputFile($ifile);
+}
 
-    #---------- mixed cc and linker magic ----------------------------------
-    # this optimisation stuff is finally sorted out later on...
+if ( $Status > 0 ) { # don't link if there were errors...
+    print STDERR $ShortUsage;
+    &tidy_up();
+    exit $Status;
+}
 
-#    /^-O0$/   && do { # turn all optimisation *OFF*
-#              $OptLevel = -1;
-#              $ProduceS = ''; $ProduceC = 1; # force use of C compiler
-#              next arg; };
+# append last minute flags linker and consistency flags
+&setupBuildFlags();
+&setupSyslibs();
+&setupLinkOpts();
 
-    /^-O2-for-C$/ && do { $MinusO2ForC = 1; next arg; };
+\end{code}
 
-    /^-O[1-2]?$/ && do {
-               local($opt_lev) = ( /^-O2$/ ) ? 2 : 1; # max 'em
-               $OptLevel = ( $opt_lev > $OptLevel ) ? $opt_lev : $OptLevel;
+Link if appropriate.
+\begin{code}
+if ($Do_lnkr) {
+    local($libdirs) = '';
 
-               if ( $OptLevel == 2 ) { # force use of C compiler
-                   $ProduceS = ''; $ProduceC = 1;
-               }
-               next arg; };
+    # glue them together:
+    push(@UserLibrary_dir, @SysLibrary_dir);
 
-    /^-Onot$/  && do { $OptLevel = 0; next arg; }; # # set it to <no opt>
+    $libdirs = '-L' . join(' -L',@UserLibrary_dir) if $#UserLibrary_dir >= 0;
 
-    /^-Ofile(.*)/ && do {
-               $OptLevel = 3;
-               local($ofile) = &grab_arg_arg('-Ofile', $1);
-               @HsC_minusO3_flags = ();
+    # for a linker, use an explicitly given one, or the going C compiler ...
+    local($lnkr) = ( $Lnkr ) ? $Lnkr : $CcRegd;
 
-               open(OFILE, "< $ofile") || die "Can't open $ofile!\n";
-               while (<OFILE>) {
-                   chop;
-                   s/\#.*//;       # death to comments
-                   s/[ \t]+//g;    # death to whitespace
-                   next if /^$/;   # ditto, blank lines
-                   s/([()*{}])/\\$1/g;    # protect shell metacharacters
-                   if ( /^C:(.*)/ ) {
-                       push(@CcBoth_flags, $1);
-                   } else {
-                       push(@HsC_minusO3_flags, $_);
-                   }
-               }
-               close(OFILE);
-               next arg; };
+    local($output) = ($Specific_output_file ne '') ? "-o $Specific_output_file" : '';
+    @Files_to_tidy = ($Specific_output_file ne '') ? $Specific_output_file : 'a.out';
 
-    /^-debug$/     && do { # all this does is mark a .hc/.o as "debugging"
-                           # in the consistency info
-                           $DEBUGging = 'd';
-                           next arg; };
+    local($to_do) = "$lnkr $Verbose @Ld_flags $output @Link_file $TopClosureFile $libdirs @UserLibrary @SysLibrary";
+    &run_something($to_do, 'Linker');
 
-    #---------- catch unrecognized flags -----------------------------------
+    # finally, check the consistency info in the binary
+    local($executable) = $Files_to_tidy[0];
+    @Files_to_tidy = (); # reset; we don't want to nuke it if it's inconsistent
 
-    /^-./ && do {
-       print STDERR "$Pgm: unrecognised option: $_\n";
-       $Status++;
-       next arg; };
+    if ( $LinkChk ) {
+       # dynamically load consistency-chking code; then do it.
+       require('ghc-consist.prl')
+           || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-consist.prl!\n");
 
-    #---------- anything else is considered an input file ------------------
-    # (well, .o files are immediately queued up as linker fodder..)
-    if (/\.o$/) {
-       push(@Link_file, $_);
-    } else {
-       push(@Input_file, $_);
+       &chk_consistency_info ( $executable );
     }
 
-    # input files must exist:
-    if (! -f $_) {
-       print STDERR "$Pgm: input file doesn't exist: $_\n";
-       $Status++;
-    }
-}
+    # if PVM parallel stuff, we do truly weird things.
+    # Essentially: (1) move the executable over to where PVM expects
+    # to find it.  (2) create a script in place of the executable
+    # which will cause the program to be run, via SysMan.
+    if ( $PARing eq 'p' ) {
+       local($pvm_executable) = $executable;
+       local($pvm_executable_base);
 
-# if there are several input files,
-# we don't allow \tr{-o <file>} or \tr{-ohi <file>} options...
-# (except if linking, of course)
+       if ( $pvm_executable !~ /^\// ) { # a relative path name: make absolute
+           local($pwd) = `pwd`;
+           chop($pwd);
+           $pwd =~ s/^\/tmp_mnt//;
+           $pvm_executable = "$pwd/$pvm_executable";
+       }
 
-if ($#Input_file > 0 && ( ! $Do_lnkr )) {
-    if ( ($Specific_output_file ne '' && $Specific_output_file ne '-')
-      || ($Specific_hi_file ne ''     && $Specific_hi_file ne '-') ) {
-       print STDERR "$Pgm: You can't use -o or -ohi options if you have multiple input files.\n";
-       print STDERR "\tPerhaps the -odir option will do what you want.\n";
-       $Status++;
-    }
-}
+       $pvm_executable =~ s|/|=|g; # make /s into =s
+       $pvm_executable_base = $pvm_executable;
 
-# check for various pathological -o and -odir combinations...
-if ($Specific_output_dir ne '' && $Specific_output_file ne '') {
-    if ($Specific_output_file eq '-') {
-       print STDERR "$Pgm: can't set output directory with -ohi AND have output to stdout\n";
-       $Status++;
-    } else { # amalgamate...
-       $Specific_output_file = "$Specific_output_dir/$Specific_output_file";
-       # ToDo: check we haven't got a junk name now...
-       $Specific_output_dir  = ''; # reset
-    }
-}
+       $pvm_executable = $ENV{'PVM_ROOT'} . '/bin/' . $ENV{'PVM_ARCH'}
+                       . "/$pvm_executable";
 
-# PROFILING stuff after argv mangling:
-if ( ! $PROFing ) {
-    # warn about any scc exprs found (in case scc used as identifier)
-    push(@HsP_flags, '-W');
-} else {
-    $Oopt_AddAutoSccs = '-fadd-auto-sccs' if $PROFauto;
-    $Oopt_FinalStgProfilingMassage = '-fmassage-stg-for-profiling';
+       &run_something("$Rm -f $pvm_executable; $Cp -p $executable $pvm_executable && $Rm -f $executable", 'Moving binary to PVM land');
 
-    push(@HsC_flags, $PROFauto) if $PROFauto;
-    push(@HsC_flags, $PROFcaf)  if $PROFcaf;
-#UNUSED:    push(@HsC_flags, $PROFdict) if $PROFdict;
+       # OK, now create the magic script for "$executable"
+       open(EXEC, "> $executable") || &tidy_up_and_die(1,"$Pgm: couldn't open $executable to write!\n");
+       print EXEC <<EOSCRIPT1;
+eval 'exec perl -S \$0 \${1+"\$@"}'
+  if \$running_under_some_shell;
+# =!=!=!=!=!=!=!=!=!=!=!
+# This script is automatically generated: DO NOT EDIT!!!
+# Generated by Glasgow Haskell, version ${PROJECTVERSION} ${PROJECTPATCHLEVEL}
+#
+\$pvm_executable      = '$pvm_executable';
+\$pvm_executable_base = '$pvm_executable_base';
+\$SysMan = '$SysMan';
+EOSCRIPT1
 
-    push(@HsP_flags, (($PROFignore_scc) ? $PROFignore_scc : '-S'));
+       print EXEC <<\EOSCRIPT2;
+# first, some magical shortcuts to run "commands" on the binary
+# (which is hidden)
+if ($#ARGV == 1 && $ARGV[0] eq '+RTS' && $ARGV[1] =~ /^--((size|file|strip|rm|nm).*)/ ) {
+    local($cmd) = $1;
+    system("$cmd $pvm_executable");
+    exit(0); # all done
+}
 
-    if ($SplitObjFiles && ! $CompilingPrelude) {
-       # can't split with cost centres -- would need global and externs
-       print STDERR "$Pgm: WARNING: splitting objects when profiling will *BREAK* if any _scc_s are present!\n";
-       # (but it's fine if there aren't any _scc_s around...)
-#      $SplitObjFiles = 0; # unset
-       #not an error: for now: $Status++;
+# OK, really run it; process the args first
+$ENV{'PE'} = $pvm_executable_base;
+$debug = '';
+$nprocessors = 2; # the default
+@nonPVM_args = ();
+$in_RTS_args = 0;
+
+# ToDo: handle --RTS
+args: while ($a = shift(@ARGV)) {
+    if ( $a eq '+RTS' ) {
+       $in_RTS_args = 1;
+    } elsif ( $a eq '-RTS' ) {
+       $in_RTS_args = 0;
+    }
+    if ( $a eq '-d' && $in_RTS_args ) {
+       $debug = '-';
+    } elsif ( $a =~ /^-N(\d+)/ && $in_RTS_args ) {
+       $nprocessors = $1;
+    } else {
+       push(@nonPVM_args, $a);
     }
 }
 
-# crash and burn if there were errors
-if ( $Status > 0 ) {
-    print STDERR $ShortUsage;
-    exit $Status;
+local($return_val) = 0;
+system("$SysMan $debug $pvm_executable $nprocessors @nonPVM_args");
+$return_val = $?;
+system("mv $ENV{'HOME'}/$pvm_executable_base.???.gr .") if -f "$ENV{'HOME'}/$pvm_executable_base.001.gr";
+exit($return_val);
+EOSCRIPT2
+       close(EXEC) || die "Failed closing $executable\n";
+       chmod 0755, $executable;
+    }
 }
+
+# that...  that's all, folks!
+&tidy_up();
+exit $Status; # will still be 0 if all went well
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\section[Driver-post-argv-mangling]{Setup after reading options}
+\section[Driver-do-one-file]{How to process a single input file}
 %*                                                                     *
 %************************************************************************
 
-%************************************************************************
-%*                                                                     *
-\subsection{Set up for optimisation level (\tr{-O} or whatever)}
-%*                                                                     *
-%************************************************************************
+\begin{code}
+sub ProcessInputFile {
+    local($ifile) = @_;          # input file name
+    local($ifile_root);          # root of or basename of input file
+    local($ofile_target); # ultimate output file we hope to produce
+                         # from input file (need to know for recomp
+                         # checking purposes)
+    local($hifile_target);# ditto (but .hi file)
+\end{code}
 
-We come now to the default ``wads of options'' that are turned on by
-\tr{-O0} (do min optimisation), \tr{-O} (ordinary optimisation),
-\tr{-O2} (aggressive optimisation), or no O-ish flag (compile speed is
-more important).
+Handle the weirdity of input from stdin.
+\begin{code}
+    if ($ifile ne '-') {
+       ($ifile_root  = $ifile) =~ s/\.[^\.\/]+$//;
+       $ofile_target = # may be reset later...
+                       ($Specific_output_file ne '' && ! $Do_lnkr)
+                       ? $Specific_output_file
+                       : &odir_ify($ifile_root, 'o');
+       $hifile_target= ($Specific_hi_file ne '')
+                       ? $Specific_hi_file
+                       : "$ifile_root.$HiSuffix"; # ToDo: odirify?
+                       # NB: may change if $ifile_root isn't module name (??)
+    } else {
+       $ifile = "$Tmp_prefix.hs"; # we know that's where we put the input
+       $ifile_root   = '_stdin';
+       $ofile_target = '_stdout'; # gratuitous?
+       $hifile_target= '_stdout'; # ditto?
+    }
+\end{code}
 
-The user can also specify his/her own list of options in a file; in
-that case, the work is already done (see stuff about @minusO3@,
-earlier...).
+We need to decide what phases of the compilation system we will run
+over this file.  The defaults are the ones established when processing
+flags.  (That established what the last phase run for all files is.)
 
-GHC allows very precise control of what happens during a compilation.
-Core-to-Core and STG-to-STG passes can be run in any order, as many
-times as you like.  Individual transformations can be turned on or
-disabled.
+We do the pre-recompilation-checker phases here; the rest later.
+\begin{code}
+\end{code}
 
-Sadly, however, there are some interdependencies \& Things You Must
-Not Do.  Here is the list.
+Look at the suffix and decide what initial phases of compilation may
+be dropped off for this file.  Also the rather boring business of
+which files are coming-in/going-out.
 
-CORE-TO-CORE PASSES:
-\begin{description}
-\item[\tr{-fspecialise}:]
-The specialiser must have dependency-analysed input; but if you run
-the simplifier to do this, you must not let it toss away unused
-bindings!  (The typechecker conveys some specialisation info via
-``unused'' bindings...)
+Again, we'll do the post-recompilation-checker parts of this later.
+\begin{code}
+    local($do_lit2pgm) = ($ifile =~ /\.lhs$/) ? 1 : 0;
+    local($do_hscpp)   = 1; # but "hscpp" might really be "cat"
+    local($do_hsc)     = 1;
 
-\item[\tr{-ffloat-inwards}:]
-Floating inwards should be done before strictness analysis, because
-the latter will give better results.
+    # names of the files to stuff between phases
+    # defaults are temporaries
+    local($in_lit2pgm)   = $ifile;
+    local($lit2pgm_hscpp) = "$Tmp_prefix.lpp";
+    local($hscpp_hsc)    = "$Tmp_prefix.cpp";
+    local($hsc_hi)       = "$Tmp_prefix.hi";
+    local($cc_as_o)      = "${Tmp_prefix}_o.s"; # temporary for raw .s file if opt C
+    local($cc_as)        = "$Tmp_prefix.s";     # mangled or hsc-produced .s code
+    local($as_out)       = $ofile_target;
 
-\item[\tr{-fstatic-args}:]
-The static-arguments-transformation pass {\em must} have the
-simplifier run right after it.
+    local($is_hc_file) = 1; #Is the C code .hc or .c? Assume .hc for now
 
-\item[\tr{-fcalc-inlinings[12]}:]
-Not required, but there may be slight gains by re-simplifying after
-this is done.  (You could then \tr{-fcalc-inlinings} again, just for
-fun.)
+    $lit2pgm_hscpp = $ifile if ($ifile =~ /\.hs$/);
 
-\item[\tr{-ffull-laziness}:]
-The (outwards-)let-floater should be the {\em last} Core-to-Core pass
-that's run.  (Um, well, howzabout the simplifier just once more...)
-\end{description}
+    # OK, let's strip off some literate junk:
+    &runLit2pgm($in_lit2pgm, $lit2pgm_hscpp) if ($ifile =~ /\.lhs$/);
+    #
+    @File_options = ();
+
+    # Scan the top of the de-litted file for {-# OPTIONS #-} pragmas
+    &check_for_source_options($lit2pgm_hscpp);
+    # options found in the source file take a back seat, i.e., we scan
+    # them first. Only process the command line again if source file
+    # contained anything of interest *or* there's more than one
+    # input file (we have to reset the options).
+    #
+    if ( $#Input_file >= 0 || $#File_options >= 0) {
+        @File_options = (@File_options, @Cmd_opts);
 
-STG-TO-STG PASSES:
-\begin{description}
-\item[\tr{-fupdate-analysis}:]
-It really really wants to be the last STG-to-STG pass that is run.
-\end{description}
+        # Now process the command line
+        &initDriverGlobals();
+        &processArgs(@File_options);
+    }
+    #
+    # Having got the effective command line scanned, set up
+    # the various options in prep for some real work.
+    #
+    # check the sanity of the BuildTag we're about to use,
+    # and if needs be, add some more flags and setup to
+    # the different phases.
+    #
+    &setupBuildFlags();
+    &setupOptimiseFlags();
+    &setupMachOpts();
+    &setupIncPaths();
+    &setupHeapStackSize();
 
-\begin{code}
-# OLD:
-#@HsC_minusO0_flags
-#  = (         $Oopt_AddAutoSccs,
-#      '-fsimplify', # would rather *not* run the simplifier (ToDo)
-#        '\(', '\)', # nothing special at all ????
-#
-#      $Oopt_FinalStgProfilingMassage
-#   );
+    #
+    # These two variables need to be set after the
+    # command-line has been processed and the build options
+    # have be seen set up. This is because command-line options
+    # can control whether to compile vias C or not.
+    # 
+    local($do_cc)      = ( $Do_cc != -1) # i.e., it was set explicitly
+                         ? $Do_cc
+                         : ( ($HscOut eq '-C=') ? 1 : 0 );
+    local($do_as)      = $Do_as;
+    local($hsc_out)      = ( $HscOut eq '-C=' ) ? "$Tmp_prefix.hc" : "$Tmp_prefix.s" ;
 
-@HsC_minusNoO_flags
-  = (  '-fsimplify',
-         '\(',
-         "$Oopt_FB_Support",
-#        '-falways-float-lets-from-lets',      # no idea why this was here (WDP 95/09)
-         '-ffloat-lets-exposing-whnf',
-         '-ffloat-primops-ok',
-         '-fcase-of-case',
-#        '-fdo-lambda-eta-expansion',  # too complicated
-         '-freuse-con',
-#        '-flet-to-case',      # no strictness analysis, so...
-         "$Oopt_PedanticBottoms",
-#        "$Oopt_MonadEtaExpansion",    # no thanks
-         '-fsimpl-uf-use-threshold0',
-         '-fessential-unfoldings-only',
-#        "$Oopt_UnfoldingUseThreshold",        # no thanks
-         "$Oopt_MaxSimplifierIterations",
-         '\)',
-       $Oopt_AddAutoSccs,
-#      '-ffull-laziness',      # removed 95/04 WDP following Andr\'e's lead
-       '-fuse-get-mentioned-vars', # for the renamer
-       
-       $Oopt_FinalStgProfilingMassage
-    );
+    if ($ifile =~ /.lhs$/ || $ifile =~ /.hs$/ ) {
+       ;
+    } elsif ($ifile =~ /\.hc$/ || $ifile =~ /_hc$/ ) { # || $ifile =~ /\.$Isuffix$/o) # ToDo: better
+       $do_hscpp = 0; $do_hsc = 0; $do_cc = 1;
+       $hsc_out = $ifile;
+    } elsif ($ifile =~ /\.c$/) {
+       $do_hscpp = 0; $do_hsc = 0; $do_cc = 1;
+       $hsc_out = $ifile; $is_hc_file = 0;
+    } elsif ($ifile =~ /\.s$/) {
+       $do_hscpp = 0; $do_hsc = 0; $do_cc = 0;
+       $cc_as = $ifile;    
+    } else { # don't know what it is, but nothing to do herein...
+       $do_hscpp = 0; $do_hsc = 0; $do_cc = 0; $do_as = 0;
+    }
 
-@HsC_minusO_flags # NOTE: used for *both* -O and -O2 (some conditional bits)
-  = (
-      # core2core passes
-       # initial simplify: mk specialiser happy: minimum effort please
-       '-fsimplify',
-         '\(', 
-         "$Oopt_FB_Support",
-         '-fkeep-spec-pragma-ids',
-         '-fsimpl-uf-use-threshold0',
-         '-fessential-unfoldings-only',
-         '-fmax-simplifier-iterations1',
-         "$Oopt_PedanticBottoms",
-         '\)',
+    # hack to avoid running hscpp
+    $HsCpp = $Cat if ! $Cpp_flag_set;
 
-       $Oopt_AddAutoSccs, # dangerous to do with *no* simplification...
+    &runHscpp($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc)
+       if $do_hscpp;
+\end{code}
 
-       '-fspecialise-overloaded',
-       $Oopt_SpecialiseUnboxed,
-       '-fspecialise',
+We now think about whether to run hsc/cc or not (when hsc produces .s
+stuff, it effectively takes the place of both phases).
 
-       '-fsimplify', # need tossing before calc-i...
-         '\(', 
-         "$Oopt_FB_Support",
-         '-ffloat-lets-exposing-whnf',
-         '-ffloat-primops-ok',
-         '-fcase-of-case',
-         '-fdo-case-elim',
-         '-fdo-eta-reduction',
-         '-fdo-lambda-eta-expansion',
-         '-freuse-con',
-#        '-flet-to-case',      # no point, before strictness analysis
-         "$Oopt_PedanticBottoms",
-         "$Oopt_MonadEtaExpansion",
-         "$Oopt_UnfoldingUseThreshold",
-         "$Oopt_MaxSimplifierIterations",
-         '\)',
+To get the output file name right: for each phase that we are {\em
+not} going to run, set its input (i.e., the output of its preceding
+phase) to @"$ifile_root.<suffix>"@.
+\begin{code}
+    local($going_interactive) = $HscOut eq '-N=' || $ifile_root eq '_stdin';
 
-       '-fcalc-inlinings1',
+    #
+    # Warning issued if -keep-hc-file-too is used without
+    # -fvia-C (or the equivalent)
+    #
+    if ( $HscOut ne '-C=' && $Keep_hc_file_too ) {
+       print STDERR "Warning: Native code generator to be used, -keep-hc-file-too will be ignored\n";
+    }
 
-#      ($Oopt_FoldrBuildWW) ? (
-#              '-ffoldr-build-ww-anal',
-#              '-ffoldr-build-worker-wrapper',
-#              '-fsimplify', 
-#                '\(', 
-#                "$Oopt_FB_Support",
-#                '-ffloat-lets-exposing-whnf',
-#                '-ffloat-primops-ok',
-#                '-fcase-of-case',
-#                '-fdo-case-elim',
-#                '-fdo-eta-reduction',
-#                '-fdo-lambda-eta-expansion',
-#                '-freuse-con',
-##               '-flet-to-case',      # no point, before strictness analysis
-#                "$Oopt_PedanticBottoms",
-#                "$Oopt_MonadEtaExpansion",
-#                "$Oopt_UnfoldingUseThreshold",
-#                "$Oopt_MaxSimplifierIterations",
-#                '\)',
-#       ) : (),
+    if (! $do_cc && ! $do_as) { # stopping after hsc
+       $hsc_out = ($Specific_output_file ne '')
+                ? $Specific_output_file
+                : &odir_ify($ifile_root, ($HscOut eq '-C=') ? 'hc' : 's');
 
-       # this pass-ordering sequence was agreed by Simon and Andr\'e
-       # (WDP 94/07, 94/11).
-       '-ffull-laziness',
+       $ofile_target = $hsc_out; # reset
+    }
 
-       ($Oopt_FoldrBuild) ? (
-         '-fsimplify', 
-           '\(', 
-           '-fignore-inline-pragma',   # **** NB!
-           '-fdo-foldr-build',         # NB
-           "$Oopt_FB_Support",
-           '-ffloat-lets-exposing-whnf',
-           '-ffloat-primops-ok',
-           '-fcase-of-case',
-           '-fdo-case-elim',
-           '-fdo-eta-reduction',
-           '-fdo-lambda-eta-expansion',
-           '-freuse-con',
-  #      '-flet-to-case',      # no point, before strictness analysis
-           "$Oopt_PedanticBottoms",
-           "$Oopt_MonadEtaExpansion",
-           "$Oopt_UnfoldingUseThreshold",
-           "$Oopt_MaxSimplifierIterations",
-           '\)',
-       ) : (),
+    if (! $do_as) { # stopping after gcc (or hsc)
+       $cc_as = ($Specific_output_file ne '')
+                ? $Specific_output_file
+                : &odir_ify($ifile_root, ( $Only_preprocess_C ) ? 'i' : 's');
 
-       '-ffloat-inwards',
+       $ofile_target = $cc_as; # reset
+    }
 
-       '-fsimplify',
-         '\(', 
-         "$Oopt_FB_Support",
-         '-ffloat-lets-exposing-whnf',
-         '-ffloat-primops-ok',
-         '-fcase-of-case',
-         '-fdo-case-elim',
-         '-fdo-eta-reduction',
-         '-fdo-lambda-eta-expansion',
-         '-freuse-con',
-#        '-flet-to-case',      # no point, before strictness analysis
-         '-fdo-inline-foldr-build',
-                               # you need to inline foldr!
-         "$Oopt_PedanticBottoms",
-         "$Oopt_MonadEtaExpansion",
-         "$Oopt_UnfoldingUseThreshold",
-         "$Oopt_MaxSimplifierIterations",
-         '\)',
+\end{code}
 
-       '-fstrictness',
 
-       '-fsimplify',
-         '\(', 
-         "$Oopt_FB_Support",
-         '-ffloat-lets-exposing-whnf',
-         '-ffloat-primops-ok',
-         '-fcase-of-case',
-         '-fdo-case-elim',
-         '-fdo-eta-reduction',
-         '-fdo-lambda-eta-expansion',
-         '-freuse-con',
-         '-flet-to-case',      # Aha!
-         "$Oopt_PedanticBottoms",
-         "$Oopt_MonadEtaExpansion",
-         "$Oopt_UnfoldingUseThreshold",
-         "$Oopt_MaxSimplifierIterations",
-         '\)',
+Now the Haskell compiler, C compiler, and assembler
 
-       '-ffloat-inwards',
+\begin{code}
+   if ($do_hsc) {
+       &runHscAndProcessInterfaces( $ifile, $hscpp_hsc, $ifile_root, 
+                                    $ofile_target, $hifile_target);
+    }
 
-# Case-liberation for -O2.  This should be after
-# strictness analysis and the simplification which follows it.
+    if ($do_cc) {
+       &runGcc    ($is_hc_file, $hsc_out, $cc_as_o);
+       &runMangler($is_hc_file, $cc_as_o, $cc_as, $ifile_root);
+    }
 
-#      ( ($OptLevel != 2)
-#        ? ''
-#      : "-fliberate-case -fsimplify \\( "$Oopt_FB_Support" -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fdo-eta-reduction -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MonadEtaExpansion $Oopt_UnfoldingUseThreshold $Oopt_MaxSimplifierIterations \\)" ),
+    &split_asm_file($cc_as)  if $do_as && $SplitObjFiles;
 
-# Final clean-up simplification:
+    &runAs($as_out, $ifile_root) if $do_as;
+\end{code}
 
-       '-fsimplify',
-         '\(', 
-         "$Oopt_FB_Support",
-         '-ffloat-lets-exposing-whnf',
-         '-ffloat-primops-ok',
-         '-fcase-of-case',
-         '-fdo-case-elim',
-         '-fdo-eta-reduction',
-         '-fdo-lambda-eta-expansion',
-         '-freuse-con',
-         '-flet-to-case',
-         '-fignore-inline-pragma',     # **** NB!
-         '-fdo-inline-foldr-build',    # NB
-         "$Oopt_PedanticBottoms",
-         "$Oopt_MonadEtaExpansion",
-         "$Oopt_UnfoldingUseThreshold",
-         "$Oopt_MaxSimplifierIterations",
-         '\)',
+Finally, decide what to queue up for linker input.
+\begin{code}
+    # tentatively assume we will eventually produce linker input:
+    push(@Link_file, &odir_ify($ifile_root, 'o'));
 
-#      '-fstatic-args',
-       '-fcalc-inlinings2',
+#ToDo:    local($or_isuf) = ($Isuffix eq '') ? '' : "|$Isuffix";
 
-      # stg2stg passes
-       '-fupdate-analysis',
-       '-flambda-lift',
-       $Oopt_FinalStgProfilingMassage,
-       $Oopt_StgStats,
+    if ( $ifile !~ /\.(lhs|hs|hc|c|s)$/ && $ifile !~ /_hc$/ ) {
+       print STDERR "$Pgm: don't recognise suffix on `$ifile'; passing it through to linker\n"
+           if $ifile !~ /\.a$/;
 
-      # flags for stg2stg
-       '-flet-no-escape',
+       # oops; we tentatively pushed the wrong thing; fix & do the right thing
+       pop(@Link_file); push(@Link_file, $ifile);
+    }
 
-      # how do we desugar list comprehensions ?
-       (($Oopt_FoldrBuild) ? '-ffoldr-build-on' : '' ), 
 
-      # SPECIAL FLAGS for -O2
-       (($OptLevel == 2) ? '-fsemi-tagging' : '')
-    );
+} # end of ProcessInputFile
 \end{code}
 
-Sort out what we're going to do about optimising.  First, the @hsc@
-flags and regular @cc@ flags to worry about:
-\begin{code}
-#if    ( $OptLevel < 0 ) {
+%************************************************************************
+%*                                                                     *
+\section[Driver-run-phases]{Routines to run the various phases}
+%*                                                                     *
+%************************************************************************
 
-#   &add_Hsc_flags( @HsC_minusO0_flags );
+\begin{code}
+sub runLit2pgm {
+    local($in_lit2pgm, $lit2pgm_hscpp) = @_;
 
-if ( $OptLevel <= 0 ) {
+    local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $lit2pgm_hscpp && ".
+                   "$Unlit @Unlit_flags $in_lit2pgm -  >> $lit2pgm_hscpp";
+    @Files_to_tidy = ( $lit2pgm_hscpp );
 
-    # for this level, we tell the parser -fignore-interface-pragmas
-    push(@HsP_flags, '-p');
-    # and tell the compiler not to produce them
-    push(@HsC_flags, '-fomit-interface-pragmas');
+    &run_something($to_do, 'literate pre-processor');
+}
+\end{code}
 
-    &add_Hsc_flags( @HsC_minusNoO_flags );
-    push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O');        # not optional!
+\begin{code}
+sub runHscpp {
+    local($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc) = @_;
 
-} elsif ( $OptLevel == 1 || $OptLevel == 2 ) {
+    local($to_do);
 
-    &add_Hsc_flags( @HsC_minusO_flags );
-    push(@CcBoth_flags, ($MinusO2ForC || $OptLevel == 2) ? '-O2' : '-O'); # not optional!
-    # -O? to GCC is not optional! -O2 probably isn't worth it generally,
-    # but it *is* useful in compiling the garbage collectors (so said
-    # Patrick many moons ago...).
-
-} else { # -Ofile, then...
-
-    &add_Hsc_flags( @HsC_minusO3_flags );
-    push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O');        # possibly to be elaborated...
+    if ($HsCpp eq $Cat) {
+       $to_do = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsc && ".
+                       "$HsCpp $lit2pgm_hscpp >> $hscpp_hsc";
+       @Files_to_tidy = ( $hscpp_hsc );
+       &run_something($to_do, 'Ineffective C pre-processor');
+    } else {
+       local($includes) = '-I' . join(' -I',@Include_dir);
+       $to_do = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsc && ".
+                       "$HsCpp $Verbose $genSPECS_flag @HsCpp_flags -D__HASKELL1__=$Haskell1Version -D__GLASGOW_HASKELL__=$GhcVersionInfo $includes $lit2pgm_hscpp >> $hscpp_hsc";
+       @Files_to_tidy = ( $hscpp_hsc );
+       &run_something($to_do, 'Haskellised C pre-processor');
+    }
 }
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{Check for registerising, consistency, etc.}
-%*                                                                     *
-%************************************************************************
-
-Are we capable of generating ``registerisable'' C (either using
-C or via equivalent native code)?
 
 \begin{code}
-$RegisteriseC = ( $GccAvailable
-               && $RegisteriseC ne 'no'    # not explicitly *un*set...
-               && ($TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/)
-               ) ? 'o' : '';
-\end{code}
+sub runHscAndProcessInterfaces {
+    local($ifile, $hscpp_hsc, $ifile_root, $ofile_target, $hifile_target) = @_;
+
+       # $ifile                is the original input file
+       # $hscpp_hsc            post-unlit, post-cpp, etc., input file
+       # $ifile_root           input filename minus suffix
+       # $ofile_target         the output file that we ultimately hope to produce
+       # $hifile_target        the .hi file ... (ditto)
+       
+    local($source_unchanged) = 1;
 
-Sort out @$BuildTag@, @$PROFing@, @$CONCURing@, @$PARing@,
-@$GRANing@, @$TICKYing@:
-\begin{code}
-if ( $BuildTag ne '' ) {
-    local($b) = $BuildDescr{$BuildTag};
-    if ($PROFing   eq 'p') { print STDERR "$Pgm: Can't mix $b with profiling.\n"; exit 1; }
-    if ($CONCURing eq 'c') { print STDERR "$Pgm: Can't mix $b with -concurrent.\n"; exit 1; }
-    if ($PARing    eq 'p') { print STDERR "$Pgm: Can't mix $b with -parallel.\n"; exit 1; }
-    if ($GRANing   eq 'g') { print STDERR "$Pgm: Can't mix $b with -gransim.\n"; exit 1; }
-    if ($TICKYing  eq 't') { print STDERR "$Pgm: Can't mix $b with -ticky.\n"; exit 1; }
-
-} elsif ( $PROFing eq 'p' ) {
-    if ($PARing   eq 'p') { print STDERR "$Pgm: Can't do profiling with -parallel.\n"; exit 1; }
-    if ($GRANing  eq 'g') { print STDERR "$Pgm: Can't do profiling with -gransim.\n"; exit 1; }
-    if ($TICKYing eq 't') { print STDERR "$Pgm: Can't do profiling with -ticky.\n"; exit 1; }
-    $BuildTag = ($CONCURing eq 'c') ? '_mr' : '_p' ; # possibly "profiled concurrent"...
-
-} elsif ( $CONCURing eq 'c' ) {
-    if ($PARing  eq 'p') { print STDERR "$Pgm: Can't mix -concurrent with -parallel.\n"; exit 1; }
-    if ($GRANing eq 'g') { print STDERR "$Pgm: Can't mix -concurrent with -gransim.\n"; exit 1; }
-    $BuildTag = ($TICKYing eq 't')  ? '_mt' : '_mc' ; # possibly "ticky concurrent"...
-    # "profiled concurrent" already acct'd for...
-
-} elsif ( $PARing eq 'p' ) {
-    if ($GRANing  eq 'g') { print STDERR "$Pgm: Can't mix -parallel with -gransim.\n"; exit 1; }
-    if ($TICKYing eq 't') { print STDERR "$Pgm: Can't mix -parallel with -ticky.\n"; exit 1; }
-    $BuildTag = '_mp';
-
-    if ( $Do_lnkr && ( ! $ENV{'PVM_ROOT'} || ! $ENV{'PVM_ARCH'} )) {
-       print STDERR "$Pgm: both your PVM_ROOT and PVM_ARCH environment variables must be set for linking under -parallel.\n";
-       exit(1);
+# Check if the source file is up to date relative to the target; in
+# that case we say "source is unchanged" and let the compiler bail out
+# early if the import usage information allows it.
+
+    ($i_dev,$i_ino,$i_mode,$i_nlink,$i_uid,$i_gid,$i_rdev,$i_size,
+     $i_atime,$i_mtime,$i_ctime,$i_blksize,$i_blocks) = stat($ifile);
+
+    if ( ! -f $ofile_target ) {
+#      print STDERR "$Pgm:compile:Output file $ofile_target doesn't exist\n";
+       $source_unchanged = 0;
     }
 
-} elsif ( $GRANing eq 'g' ) {
-    if ($TICKYing eq 't') { print STDERR "$Pgm: Can't mix -gransim with -ticky.\n"; exit 1; }
-    $BuildTag = '_mg';
+    ($o_dev,$o_ino,$o_mode,$o_nlink,$o_uid,$o_gid,$o_rdev,$o_size,
+     $o_atime,$o_mtime,$o_ctime,$o_blksize,$o_blocks) = stat(_); # stat info from -f test
 
-} elsif ( $TICKYing eq 't' ) {
-    $BuildTag = '_t';
-}
-\end{code}
+    if ( ! -f $hifile_target ) {
+#      print STDERR "$Pgm:compile:Interface file $hifile_target doesn't exist\n";
+       $source_unchanged = 0;
+    }
 
-\begin{code}
-if ( $BuildTag ne '' ) { # something other than normal sequential...
+    ($hi_dev,$hi_ino,$hi_mode,$hi_nlink,$hi_uid,$hi_gid,$hi_rdev,$hi_size,
+     $hi_atime,$hi_mtime,$hi_ctime,$hi_blksize,$hi_blocks) = stat(_); # stat info from -f test
 
-    push(@HsP_flags, "-g$BuildTag.hi"); # use appropriate Prelude .hi files
+    if ($i_mtime > $o_mtime) {
+#      print STDERR "$Pgm:recompile:Input file $ifile newer than $ofile_target\n";
+       $source_unchanged = 0;
+    }
 
-    $ProduceC = 1; $ProduceS = ''; # must go via C
+    # So if source_unchanged is still "1", we pass on the good news to the compiler
+    # The -recomp flag can disable this, forcing recompilation
+    if ($Do_recomp_chkr && $source_unchanged) {
+       push(@HsC_flags, '-fsource-unchanged'); 
+    }  
+
+# Run the compiler
+
+    &runHsc($ifile_root, $hsc_out, $hsc_hi, $going_interactive);
+
+# See if it bailed out early, saying nothing needed doing.  
+# We work this out by seeing if it created an output .hi file
+
+    if ( ! -f $hsc_hi ) {
+       # Doesn't exist, so we bailed out early.
+       # Tell the C compiler and assembler not to run
+       $do_cc = 0; $do_as = 0;
+
+       # Update dependency info, touch both object file and 
+       # interface file, so that the following invariant is
+        # maintained:
+       #
+       #   a dependent module's interface file should after recompilation
+        #   checking be newer than the interface files of its imports. 
+        #
+       # That is, if module A's interface file changes, then module B
+       # (which import from A) needs to be checked.
+        # If A's change does not affect B, which causes the compiler to bail
+       # out early, we still need to touch the interface file of B. The reason
+        # for this is that B may export A's interface.
+       #
+       &run_something("touch $ofile_target $hifile_target", 
+                      "Touch $ofile_target $hifile_target,  to propagate dependencies");
+
+    } else {   
+
+     # Didn't bail out early (new .hi file) so we thunder on
+    
+       # If non-interactive, heave in the consistency info at the end
+       # NB: pretty hackish (depends on how $output is set)
+       if ( ! $going_interactive ) {
+           if ( $HscOut eq '-C=' ) {
+           $to_do = "echo 'static char ghc_hsc_ID[] = \"\@(#)hsc $ifile\t$HsC_major_version.$HsC_minor_version,$HsC_consist_options\";' >> $hsc_out";
+    
+           } elsif ( $HscOut eq '-S=' ) {
+               local($consist) = "hsc.$ifile.$HsC_major_version.$HsC_minor_version.$HsC_consist_options";
+               $consist =~ s/,/./g;
+               $consist =~ s/\//./g;
+               $consist =~ s/-/_/g;
+               $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
+               $to_do = "echo '\n\t.text\n$consist:' >> $hsc_out";
+           }
+           &run_something($to_do, 'Pin on Haskell consistency info');  
+       }   
 
-#    print STDERR "eval...",$EvaldSetupOpts{$BuildTag},"\n";
 
-    eval($EvaldSetupOpts{$BuildTag});
+       # Interface-handling is important enough to live off by itself
+       require('ghc-iface.prl')
+           || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-iface.prl!\n");
+       
+       &postprocessHiFile($hsc_hi, $hifile_target, $going_interactive);
+       
+       # save a copy of the .hc file, even if we are carrying on...
+       if ($HscOut eq '-C=' && $do_cc && $Keep_hc_file_too) {
+           local($to_do) = "$Rm $ifile_root.hc; $Cp $hsc_out $ifile_root.hc";
+           &run_something($to_do, 'Saving copy of .hc file');
+       }
+       
+       # save a copy of the .s file, even if we are carrying on...
+       if ($HscOut eq '-S=' && $do_as && $Keep_s_file_too) {
+           local($to_do) = "$Rm $ifile_root.s; $Cp $hsc_out $ifile_root.s";
+           &run_something($to_do, 'Saving copy of .s file');
+       }
+       
+       # if we're going to split up object files,
+       # we inject split markers into the .hc file now
+       if ( $HscOut eq '-C=' && $SplitObjFiles ) {
+           &inject_split_markers ( $hsc_out );
+        }
+    }
 }
 \end{code}
 
-Decide what the consistency-checking options are in force for this run:
-\begin{code}
-$HsC_consist_options = "${BuildTag},${DEBUGging}";
-$Cc_consist_options  = "${BuildTag},${DEBUGging},${RegisteriseC}";
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\subsection{Add on machine-specific C-compiler flags}
-%*                                                                     *
-%************************************************************************
 
-Shove on magical machine-specific options.  We use \tr{unshift} to
-stick them on the {\em front} of the arrays, so that ``later''
-user-specified flags can clobber them (e.g., \tr{-U__STG_REV_TBLS__}).
+\begin{code}
+sub runHsc {
+    local($ifile_root, $hsc_out, $hsc_hi, $going_interactive) = @_;
 
-Note: a few ``always apply'' flags were set at the very beginning.
+    # prepend comma to HsP flags (so hsc can tell them apart...)
+    foreach $a ( @HsP_flags ) { $a = ",$a" unless $a =~ /^,/; }
 
-\begin{code}
-if ($TargetPlatform =~ /^alpha-/) {
-    # we know how to *mangle* asm for alpha
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
-    unshift(@CcBoth_flags,  ('-static')) if $GccAvailable;
-
-} elsif ($TargetPlatform =~ /^hppa/) {
-    # we know how to *mangle* asm for hppa
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcBoth_flags,  ('-static')) if $GccAvailable;
-    # We don't put in '-mlong-calls', because it's only
-    # needed for very big modules (sigh), and we don't want
-    # to hobble ourselves further on all the other modules
-    # (most of them).
-    unshift(@CcBoth_flags,  ('-D_HPUX_SOURCE')) if $GccAvailable;
-        # ___HPUX_SOURCE, not _HPUX_SOURCE, is #defined if -ansi!
-        # (very nice, but too bad the HP /usr/include files don't agree.)
+    &makeHiMap() unless $HiMapDone;
+#    print STDERR "HiIncludes: $HiIncludeString\n";
+    push(@HsC_flags, "-himap=$HiIncludeString");
+#    push(@HsC_flags, "-himap=$HiMapFile");
 
-} elsif ($TargetPlatform =~ /^i386-/) {
-    # we know how to *mangle* asm for X86
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1'))
-       if $StkChkByPageFaultOK && $TargetPlatform !~ /linux/;
-       # NB: cannot do required signal magic on Linux for such stk chks */
+    # here, we may produce .hc/.s and/or .hi files
+    local($output) = '';
+    @Files_to_tidy = ();
 
-    unshift(@CcRegd_flags, ('-m486')); # not worth not doing
+    if ( $going_interactive ) {
+       # don't need .hi unless going to show it on stdout:
+       $ProduceHi = '-nohifile=' if ! $HiOnStdout;
+       $do_cc = 0; $do_as = 0; $Do_lnkr = 0; # and we won't go any further...
+    }
 
-    # -fno-defer-pop : basically the same game as for m68k
-    #
-    # -fomit-frame-pointer : *must* ; because we're stealing
-    #  the fp (%ebp) for our register maps.  *All* register
-    #  maps (in MachRegs.lh) must steal it.
+    # set up for producing output/.hi; note that flag twiddling
+    # may mean that nothing will actually be produced:
+    $output = "$ProduceHi$hsc_hi $HscOut$hsc_out";
+    @Files_to_tidy = ( $hsc_hi, $hsc_out );
 
-    unshift(@CcRegd_flags_hc, '-fno-defer-pop');
-    unshift(@CcRegd_flags,    '-fomit-frame-pointer');
-    unshift(@CcRegd_flags,    "-DSTOLEN_X86_REGS=$StolenX86Regs");
+    # if we're compiling foo.hs, we want the GC stats to end up in foo.stat
+    if ( $CollectingGCstats ) {
+       push(@HsC_rts_flags, "-S$ifile_root.stat");
+       push(@Files_to_tidy, "$ifile_root.stat");
+    }
 
-    unshift(@CcBoth_flags,  ('-static')) if $GccAvailable; # maybe unnecessary???
+    if ( $CollectGhcTimings ) { # assume $RTS_style eq 'ghc'
+       # emit nofibbish time/bytes-alloc stats to stderr;
+       # see later .stat file post-processing
+       push(@HsC_rts_flags, "-s$Tmp_prefix.stat");
+       push(@Files_to_tidy, "$Tmp_prefix.stat");
+    }
 
-} elsif ($TargetPlatform =~ /^m68k-/) {
-    # we know how to *mangle* asm for m68k
-    unshift (@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift (@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
+    local($dump) = '';
+    if ($Specific_dump_file ne '') {
+       $dump = "2>> $Specific_dump_file";
+       $Using_dump_file = 1;
+    }
 
-    # -fno-defer-pop : for the .hc files, we want all the pushing/
-    #     popping of args to routines to be explicit; if we let things
-    #     be deferred 'til after an STGJUMP, imminent death is certain!
-    #
-    # -fomit-frame-pointer : *don't*
-    #    It's better to have a6 completely tied up being a frame pointer
-    #    rather than let GCC pick random things to do with it.
-    #    (If we want to steal a6, then we would try to do things
-    #    as on iX86, where we *do* steal the frame pointer [%ebp].)
-
-    unshift(@CcRegd_flags_hc, '-fno-defer-pop');
-    unshift(@CcRegd_flags,    '-fno-omit-frame-pointer');
-       # maybe gives reg alloc a better time
-       # also: -fno-defer-pop is not sufficiently well-behaved without it
+    local($to_do);
+    $to_do = "$HsC @HsP_flags ,$hscpp_hsc $dump @HsC_flags $CoreLint $StgLint $Verbose $output +RTS @HsC_rts_flags";
+    &run_something($to_do, 'Haskell compiler');
 
-} elsif ($TargetPlatform =~ /^powerpc-/) {
-    # we know how to *mangle* asm for PowerPC
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
-
-} elsif ($TargetPlatform =~ /^sparc-/) {
-    # we know how to *mangle* asm for SPARC
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
-
-} elsif ($TargetPlatform =~ /^mips-/) {
-    # we (hope to) know how to *mangle* asm for MIPSen
-    unshift(@CcRegd_flags, ('-D__STG_REV_TBLS__'));
-    unshift(@CcRegd_flags, ('-DSTACK_CHECK_BY_PAGE_FAULT=1')) if $StkChkByPageFaultOK;
-    unshift(@CcBoth_flags,  ('-static')) if $GccAvailable;
+    # finish business w/ nofibbish time/bytes-alloc stats
+    &process_ghc_timings() if $CollectGhcTimings;
 }
 \end{code}
 
-Same unshifting magic, but for special linker flags.
-
-Should really be whether or not we prepend underscores to global symbols,
-not an architecture test.  (JSM)
-
+Use \tr{@Import_dir} and \tr{@SysImport_dir} to make a tmp file
+of (module-name, pathname) pairs, one per line, separated by a space.
 \begin{code}
-unshift(@Ld_flags,
-    (   $TargetPlatform =~ /^alpha-/
-     || $TargetPlatform =~ /^hppa/
-     || $TargetPlatform =~ /^mips-sgi-irix/
-     || $TargetPlatform =~ /^powerpc-/
-     || $TargetPlatform =~ /-solaris/
-    )
-    ? ('-u', 'unsafePerformPrimIO_fast1',
-       '-u', 'Nil_closure',
-       '-u', 'IZh_static_info',
-       '-u', 'False_inregs_info',
-       '-u', 'True_inregs_info',
-       '-u', 'CZh_static_info',
-       '-u', 'DEBUG_REGS') # just for fun, now...
-
-    # nice friendly a.out machines...
-    : ('-u', '_unsafePerformPrimIO_fast1',
-       '-u', '_Nil_closure',
-       '-u', '_IZh_static_info',
-       '-u', '_False_inregs_info',
-       '-u', '_True_inregs_info',
-       '-u', '_CZh_static_info',
-       '-u', '_DEBUG_REGS')
-    );
-\end{code}
+#%HiMap     = ();
+$HiMapDone = 0;
+$HiMapFile = '';
+$HiIncludeString = ();         # dir1:dir2:dir3, to pass to GHC
 
-%************************************************************************
-%*                                                                     *
-\subsection{Set up include paths and system-library enslurpment}
-%*                                                                     *
-%************************************************************************
+sub makeHiMap {
 
-Now that we know what garbage-collector, etc., are required, we can
-finalise our list of libraries to slurp through, and generally Get
-Ready for Business.
+    # collect in %HiMap; write later; also used elsewhere in driver
 
-\begin{code}
-# default includes must be added AFTER option processing
-if ( $(INSTALLING) ) {
-    push (@Include_dir, "$InstLibDirGhc/includes");
-    push (@Include_dir, "$InstDataDirGhc/includes");
+    local($mod, $path, $d, $e);
+
+    # reset the global variables:
+    #%HiMap     = ();
+    $HiMapDone = 0;
+    $HiMapFile = '';
+    $HiIncludeString = ();             # dir1:dir2:dir3, to pass to GHC
     
-} else {
-    push (@Include_dir, "$TopPwd/$(CURRENT_DIR)/$(GHC_INCLUDESRC)");
-}
-\end{code}
+    foreach $d ( @Import_dir ) {
+       if ($HiIncludeString) { $HiIncludeString = "$HiIncludeString:$d";
+       } else { $HiIncludeString = $d; }
 
-\begin{code}
-local($f);
-foreach $f (@SysLibrary) {
-    $f .= "${BuildTag}" if $f =~ /^-lHS/;
-}
+# The compiler does the searching now
+#
+#      opendir(DIR, $d) || &tidy_up_and_die(1,"$Pgm: error when reading directory: $d\n");
+#      local(@entry) = readdir(DIR);
+#      foreach $e ( @entry ) {
+#          next unless $e =~ /\b([A-Z][A-Za-z0-9_]*)\.${HiSuffix_prelude}$/o;
+#          $mod  = $1;
+#          $path = "$d/$e";
+#          $path =~ s,^\./,,;
+#
+#          if ( ! defined($HiMap{$mod}) ) {
+#              $HiMap{$mod} = $path;
+#          } else {
+#              &already_mapped_err($mod, $HiMap{$mod}, $path);
+#          }
+#      }
+#      closedir(DIR); # || &tidy_up_and_die(1,"$Pgm: error when closing directory: $d\n");
+    }
+
+    foreach $d ( @SysImport_dir ) {
+       if ($HiIncludeString) { $HiIncludeString = "$HiIncludeString:$d";
+       } else { $HiIncludeString = $d; }
 
-# fiddle the TopClosure file name...
-$TopClosureFile =~ s/XXXX//;
-
-# Push library HSrts, plus boring clib bit
-push(@SysLibrary, "-lHSrts${BuildTag}");
-push(@SysLibrary, '-lHSclib');
-
-# Push the pvm libraries
-if ($BuildTag eq '_mp') {
-    $pvmlib = "$ENV{'PVM_ROOT'}/lib/$ENV{'PVM_ARCH'}";
-    push(@SysLibrary, "-L$pvmlib", '-lpvm3', '-lgpvm3');
-    if ( $ENV{'PVM_ARCH'} eq 'SUNMP' ) {
-        push(@SysLibrary, '-lthread', '-lsocket', '-lnsl');
-    } elsif ( $ENV{'PVM_ARCH'} eq 'SUN4SOL2' ) {
-        push(@SysLibrary, '-lsocket', '-lnsl');
+#      opendir(DIR, $d) || &tidy_up_and_die(1,"$Pgm: error when reading directory: $d\n");
+#      local(@entry) = readdir(DIR);
+#      foreach $e ( @entry ) {
+#          next unless $e =~ /([A-Z][A-Za-z0-9_]*)\.$HiSuffix$/o;
+#          next if $NoImplicitPrelude && $e =~ /Prelude\.$HiSuffix$/o;
+#
+#          $mod  = $1;
+#          $path = "$d/$e";
+#          $path =~ s,^\./,,;
+#
+#          if ( ! defined($HiMap{$mod}) ) {
+#              $HiMap{$mod} = $path;
+#          } elsif ( $mod ne 'Main' )  { # saves useless warnings...
+#              &already_mapped_err($mod, $HiMap{$mod}, $path);
+#          }
+#      }
+#      closedir(DIR); # || &tidy_up_and_die(1,"$Pgm: error when closing directory: $d\n");
     }
-}
 
-# Push the GNU multi-precision arith lib; and the math library
-push(@SysLibrary, '-lgmp');
-push(@SysLibrary, '-lm');
-\end{code}
+#
+# Not currently used:
+#
+#    $HiMapFile = "$Tmp_prefix.himap";
+#    unlink($HiMapFile);
+#    open(HIMAP, "> $HiMapFile") || &tidy_up_and_die(1,"$Pgm: can't open $HiMapFile\n");
+#    foreach $d (keys %HiMap) {
+#      print HIMAP $d, ' ', $HiMap{$d}, "\n";
+#    }
+#    close(HIMAP) || &tidy_up_and_die(1,"$Pgm: error when closing $HiMapFile\n");
 
-%************************************************************************
-%*                                                                     *
-\subsection{Check that this system was built to do what we are asking}
-%*                                                                     *
-%************************************************************************
+    $HiMapDone = 1;
+}
 
-Before continuing we check that the appropriate build is available.
+sub already_mapped_err {
+    local($mod, $mapped_to, $path) = @_;
 
-\begin{code}
-die "$Pgm: no BuildAvail?? $BuildTag\n" if ! $BuildAvail{$BuildTag}; # sanity
+    # OK, it isn't really an error if $mapped_to and $path turn
+    # out to be the same thing.
+    ($m_dev,$m_ino,$m_mode,$m_nlink,$m_uid,$m_gid,$m_rdev,$m_size,
+     $m_atime,$m_mtime,$m_ctime,$m_blksize,$m_blocks) = stat($mapped_to);
+    ($p_dev,$p_ino,$p_mode,$p_nlink,$p_uid,$p_gid,$p_rdev,$p_size,
+     $p_atime,$p_mtime,$p_ctime,$p_blksize,$p_blocks) = stat($path);
 
-if ( $BuildAvail{$BuildTag} =~ /^-build-.*-not-defined$/ ) {
-    print STDERR "$Pgm: a `", $BuildDescr{$BuildTag},
-       "' \"build\" is not available with your GHC setup.\n";
-    print STDERR "(It was not configured for it at your site.)\n";
-    print STDERR $ShortUsage;
-    exit 1;
+    return if $m_ino == $p_ino; # same inode number
+
+    print STDERR "$Pgm: module $mod already mapped to $mapped_to";
+    print STDERR ";\n\tignoring: $path\n";
 }
 \end{code}
 
 %************************************************************************
 %*                                                                     *
-\subsection{Final miscellaneous setup bits before we start going}
+\section[Driver-misc-utils]{Miscellaneous utilities}
 %*                                                                     *
 %************************************************************************
 
-Record largest specific heapsize, if any.
-\begin{code}
-$Specific_heap_size = $Specific_heap_size * $Scale_sizes_by;
-push(@HsC_rts_flags, '-H'.$Specific_heap_size);
-$Specific_stk_size = $Specific_stk_size * $Scale_sizes_by;
-push(@HsC_rts_flags, (($RTS_style eq 'ghc') ? '-K' : '-A').$Specific_stk_size);
-
-# hack to avoid running hscpp
-$HsCpp = $Cat if ! $Cpp_flag_set;
-\end{code}
-
-If no input or link files seen, then we let 'em feed in stdin; this is
-mainly for debugging.
-\begin{code}
-if ($#Input_file < 0 && $#Link_file < 0) {
-    push(@Input_file, '-');
-}
-\end{code}
-
-Tell the world who we are, if they asked.
-\begin{code}
-if ($Verbose) {
-    print STDERR "$(PROJECTNAME), version $(PROJECTVERSION) $(PROJECTPATCHLEVEL)\n";
-}
-\end{code}
-
 %************************************************************************
 %*                                                                     *
-\section[Driver-main-loop]{Main loop: Process input files, and link if required}
+\subsection[Driver-odir-ify]{@odir_ify@: Mangle filename if \tr{-odir} set}
 %*                                                                     *
 %************************************************************************
 
-Process the input files; don't continue with linking if there are
-problems (global variable @$Status@ non-zero).
 \begin{code}
-foreach $ifile (@Input_file) {
-    &ProcessInputFile($ifile);
+sub osuf_ify {
+    local($ofile,$def_suffix) = @_;
+
+    return(($Osuffix eq '') ? "$ofile.$def_suffix" : "$ofile.$Osuffix" );
 }
 
-if ( $Status > 0 ) { # don't link if there were errors...
-    print STDERR $ShortUsage;
-    &tidy_up();
-    exit $Status;
+sub odir_ify {
+    local($orig_file, $def_suffix) = @_;
+    if ($Specific_output_dir eq '') {   # do nothing
+       &osuf_ify($orig_file, $def_suffix);
+    } else {
+       local ($orig_file_only);
+       ($orig_file_only = $orig_file) =~ s|.*/||;
+       &osuf_ify("$Specific_output_dir/$orig_file_only",$def_suffix);
+    }
 }
 \end{code}
 
-Link if appropriate.
 \begin{code}
-if ($Do_lnkr) {
-    local($libdirs);
-    # glue them together:
-    push(@UserLibrary_dir, @SysLibrary_dir);
-    if ($#UserLibrary_dir < 0) {
-       $libdirs = '';
-    } else {
-       $libdirs = '-L' . join(' -L',@UserLibrary_dir);
+sub runGcc {
+    local($is_hc_file, $hsc_out, $cc_as_o) = @_;
+
+    local($includes) = '-I' . join(' -I', @Include_dir);
+    local($cc);
+    local($s_output);
+    local($c_flags) = "@CcBoth_flags";
+    local($ddebug_flag) = ( $DEBUGging ) ? '-DDEBUG' : '';
+
+    # "input" files to use that are not in some weird directory;
+    # to help C compilers grok .hc files [ToDo: de-hackify]
+    local($cc_help)   = "ghc$$.c";
+    local($cc_help_s) = "ghc$$.s";
+
+    $cc       = $CcRegd;
+    $s_output = ($is_hc_file || $TargetPlatform =~ /^(hppa|i386)/) ? $cc_as_o : $cc_as;
+    $c_flags .= " @CcRegd_flags";
+    $c_flags .= ($is_hc_file) ? " @CcRegd_flags_hc"  : " @CcRegd_flags_c";
+
+    # C compiler won't like the .hc extension.  So we create
+    # a tmp .c file which #include's the needful.
+    open(TMP, "> $cc_help") || &tidy_up_and_die(1,"$Pgm: failed to open `$cc_help' (to write)\n");
+    if ( $is_hc_file ) {
+       print TMP <<EOINCL;
+#ifdef __STG_GCC_REGS__
+# if ! (defined(MAIN_REG_MAP) || defined(MARK_REG_MAP) || defined(SCAN_REG_MAP) || defined(SCAV_REG_MAP) || defined(FLUSH_REG_MAP))
+#  define MAIN_REG_MAP
+# endif
+#endif
+#include "stgdefs.h"
+EOINCL
+       # user may have asked for #includes to be injected...
+       print TMP @CcInjects if $#CcInjects >= 0;
     }
-    # for a linker, use an explicitly given one, or the going C compiler ...
-    local($lnkr) = ( $Lnkr ) ? $Lnkr : ($RegisteriseC ? $CcRegd : $CcUnregd );
+    # heave in the consistency info
+    print TMP "static char ghc_cc_ID[] = \"\@(#)cc $ifile\t$Cc_major_version.$Cc_minor_version,$Cc_consist_options\";\n";
 
-    local($output)= ($Specific_output_file ne '') ? "-o $Specific_output_file" : '';
-    @Files_to_tidy = ( ($Specific_output_file ne '') ? "$Specific_output_file" : 'a.out' );
+    # and #include the real source
+    print TMP "#include \"$hsc_out\"\n";
+    close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n");
 
-    local($to_do) = "$lnkr $Verbose @Ld_flags $output @Link_file $TopClosureFile $libdirs @UserLibrary @SysLibrary";
-    &run_something($to_do, 'Linker');
+    local($to_do) = "$cc $Verbose $ddebug_flag $c_flags @Cpp_define -D__HASKELL1__=$Haskell1Version $includes $cc_help > $Tmp_prefix.ccout 2>&1 && ( if [ $cc_help_s != $s_output ] ; then mv $cc_help_s $s_output ; else exit 0 ; fi )";
+    # note: __GLASGOW_HASKELL__ is pointedly *not* #defined at the C level.
+    if ( $Only_preprocess_C ) { # HACK ALERT!
+       $to_do =~ s/ -S\b//g;
+    }
+    @Files_to_tidy = ( $cc_help, $cc_help_s, $s_output );
+    $PostprocessCcOutput = 1;  # hack, dear hack...
+    &run_something($to_do, 'C compiler');
+    $PostprocessCcOutput = 0;
+    unlink($cc_help, $cc_help_s);
+}
+\end{code}
 
-    # finally, check the consistency info in the binary
-    local($executable) = $Files_to_tidy[0];
-    @Files_to_tidy = (); # reset; we don't want to nuke it if it's inconsistent
+\begin{code}
+sub runMangler {
+    local($is_hc_file, $cc_as_o, $cc_as, $ifile_root) = @_;
 
-    if ( $LinkChk ) {
-       # dynamically load consistency-chking code; then do it.
-       require('ghc-consist.prl')
-           || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-consist.prl!\n");
+    if ( $is_hc_file ) {
+       # dynamically load assembler-fiddling code, which we are about to use:
+       require('ghc-asm.prl')
+       || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n");
+    }
 
-       &chk_consistency_info ( $executable );
+    print STDERR `cat $cc_as_o` if $Dump_raw_asm; # to stderr, before mangling
+
+    if ($is_hc_file) {
+       # post-process the assembler [.hc files only]
+       &mangle_asm($cc_as_o, $cc_as);
+
+
+#OLD: for sanity:
+#OLD:  local($target) = 'oops';
+#OLD:  $target = '-alpha'      if $TargetPlatform =~ /^alpha-/;
+#OLD:  $target = '-hppa'       if $TargetPlatform =~ /^hppa/;
+#OLD:  $target = '-old-asm'    if $TargetPlatform =~ /^i386-/;
+#OLD:  $target = '-m68k'       if $TargetPlatform =~ /^m68k-/;
+#OLD:  $target = '-mips'       if $TargetPlatform =~ /^mips-/;
+#OLD:  $target = ''            if $TargetPlatform =~ /^powerpc-/;
+#OLD:  $target = '-solaris'    if $TargetPlatform =~ /^sparc-sun-solaris2/;
+#OLD:  $target = '-sparc'      if $TargetPlatform =~ /^sparc-sun-sunos4/;
+#OLD:
+#OLD:  if ( $target ne '' ) {
+#OLD:      require("ghc-asm$target.prl")
+#OLD:      || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm$target.prl!\n");
+#OLD:      &mangle_asm($cc_as_o, "$cc_as-2"); # the OLD one!
+#OLD:      &run_something("$Cmp -s $cc_as-2 $cc_as || $Diff $cc_as-2 $cc_as 1>&2 || exit 0",
+#OLD:          "Diff'ing old and new mangled .s files"); # NB: to stderr
+#OLD:  }
+
+    } elsif ($TargetPlatform =~ /^hppa/) {
+       # minor mangling of non-threaded files for hp-pa only
+       require('ghc-asm.prl')
+       || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm-hppa.prl!\n");
+       &mini_mangle_asm_hppa($cc_as_o, $cc_as);
+
+    } elsif ($TargetPlatform =~ /^i386/) {
+       # extremely-minor OFFENSIVE mangling of non-threaded just one file
+       require('ghc-asm.prl')
+       || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n");
+       &mini_mangle_asm_i386($cc_as_o, $cc_as);
     }
 
-    # if PVM parallel stuff, we do truly weird things.
-    # Essentially: (1) move the executable over to where PVM expects
-    # to find it.  (2) create a script in place of the executable
-    # which will cause the program to be run, via SysMan.
-    if ( $PARing eq 'p' ) {
-       local($pvm_executable) = $executable;
-       local($pvm_executable_base);
+    # save a copy of the .s file, even if we are carrying on...
+    if ($do_as && $Keep_s_file_too) {
+       local($to_do) = "$Rm $ifile_root.s; $Cp $cc_as $ifile_root.s";
+       &run_something($to_do, 'Saving copy of .s file');
+    }
+}
+\end{code}
 
-       if ( $pvm_executable !~ /^\// ) { # a relative path name: make absolute
-           local($pwd) = `pwd`;
-           chop($pwd);
-           $pwd =~ s/^\/tmp_mnt//;
-           $pvm_executable = "$pwd/$pvm_executable";
-       }
+\begin{code}
+sub runAs {
+    local($as_out, $ifile_root) = @_;
 
-       $pvm_executable =~ s|/|=|g; # make /s into =s
-       $pvm_executable_base = $pvm_executable;
+    local($asmblr) = ( $As ) ? $As : $CcRegd;
 
-       $pvm_executable = $ENV{'PVM_ROOT'} . '/bin/' . $ENV{'PVM_ARCH'}
-                       . "/$pvm_executable";
+    if ( ! $SplitObjFiles ) {
+       local($to_do)  = "$asmblr -o $as_out -c @As_flags $cc_as";
+       @Files_to_tidy = ( $as_out );
+       &run_something($to_do, 'Unix assembler');
 
-       &run_something("rm -f $pvm_executable; cp -p $executable $pvm_executable && rm -f $executable", 'Moving binary to PVM land');
+    } else { # more complicated split-ification...
 
-       # OK, now create the magic script for "$executable"
-       open(EXEC, "> $executable") || &tidy_up_and_die(1,"$Pgm: couldn't open $executable to write!\n");
-       print EXEC <<EOSCRIPT1;
-#!$(PERL)
-# =!=!=!=!=!=!=!=!=!=!=!
-# This script is automatically generated: DO NOT EDIT!!!
-# Generated by Glasgow Haskell, version $(PROJECTVERSION) $(PROJECTPATCHLEVEL)
-#
-\$pvm_executable      = '$pvm_executable';
-\$pvm_executable_base = '$pvm_executable_base';
-\$SysMan = '$SysMan';
-EOSCRIPT1
+       # must assemble files $Tmp_prefix__[1 .. $NoOfSplitFiles].s
 
-       print EXEC <<\EOSCRIPT2;
-# first, some magical shortcuts to run "commands" on the binary
-# (which is hidden)
-if ($#ARGV == 1 && $ARGV[0] eq '+RTS' && $ARGV[1] =~ /^--((size|file|strip|rm|nm).*)/ ) {
-    local($cmd) = $1;
-    system("$cmd $pvm_executable");
-    exit(0); # all done
-}
+        # If -odir is used, great, just pin it in front of the
+       # generated split file names. If it hasn't been set, we
+       # snatch it from the ifile_root.
+       #
+       # 
 
-# OK, really run it; process the args first
-$ENV{'PE'} = $pvm_executable_base;
-$debug = '';
-$nprocessors = 2; # the default
-@nonPVM_args = ();
-$in_RTS_args = 0;
+        if ( $Specific_output_dir eq '' ) {
+            $Specific_output_dir = ${ifile_root};
+        }
 
-# ToDo: handle --RTS
-args: while ($a = shift(@ARGV)) {
-    if ( $a eq '+RTS' ) {
-       $in_RTS_args = 1;
-    } elsif ( $a eq '-RTS' ) {
-       $in_RTS_args = 0;
-    }
-    if ( $a eq '-d' && $in_RTS_args ) {
-       $debug = '-';
-    } elsif ( $a =~ /^-N(\d+)/ && $in_RTS_args ) {
-       $nprocessors = $1;
-    } else {
-       push(@nonPVM_args, $a);
-    }
-}
+       for ($f = 1; $f <= $NoOfSplitFiles; $f++ ) {
+           local($split_out) = &odir_ify("${ifile_root}__${f}",'o');
+           local($to_do) = "$asmblr -o $split_out -c @As_flags ${Tmp_prefix}__${f}.s";
+           @Files_to_tidy = ( $split_out );
 
-exec "$SysMan $debug $nprocessors @nonPVM_args";
-print STDERR "Exec failed!!!: $SysMan $debug $nprocessors @nonPVM_args\n";
-exit(1); 
-EOSCRIPT2
-       close(EXEC) || die "Failed closing $executable\n";
-       chmod 0755, "$executable";
-    }
-}
-
-# that...  that's all, folks!
-&tidy_up();
-exit $Status; # will still be 0 if all went well
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\section[Driver-do-one-file]{How to process a single input file}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-sub ProcessInputFile {
-    local($ifile) = @_;        # input file name
-    local($ifile_root);        # root of or basename of input file
-    local($ifile_root_file); # non-directory part of $ifile_root
-\end{code}
-
-Handle the weirdity of input from stdin.
-\begin{code}
-    if ($ifile eq '-') {
-       open(INF, "> $Tmp_prefix.hs") || &tidy_up_and_die(1,"Can't open $Tmp_prefix.hs\n");
-       print STDERR "Enter your Haskell program, end with ^D (on a line of its own):\n";
-       while (<>) { print INF $_; }
-       close(INF) || &tidy_up_and_die(1,"Failed writing to $Tmp_prefix.hs\n");
-       $ifile = "$Tmp_prefix.hs";
-       $ifile_root = '_stdin';
-       $ifile_root_file = $ifile_root;
-    } else {
-       ($ifile_root = $ifile) =~ s/\.[^\.\/]+$//;
-       ($ifile_root_file = $ifile_root) =~ s|.*/||;
-    }
-\end{code}
-
-We now decide what phases of the compilation system we will run over
-this file.  The defaults are the ones established when processing flags.
-(That established what the last phase run for all files is.)
-
-The lower-case names are the local ones (as is usual), just for this
-one file.
-\begin{code}
-    local($do_lit2pgm) = $Do_lit2pgm;
-    local($do_hscpp)   = $Do_hscpp;
-    local($do_hsp)     = $Do_hsp;
-    local($do_hsc)     = $Do_hsc;
-    local($do_as)      = $Do_as;
-    local($do_cc)      = ( $Do_cc != -1) # i.e., it was set explicitly
-                         ? $Do_cc
-                         : ( ($ProduceC) ? 1 : 0 );
-\end{code}
-
-Look at the suffix and decide what initial phases of compilation may
-be dropped off for this file.  Also the rather boring business of
-which files are coming-in/going-out.
-\begin{code}
-    # names of the files to stuff between phases
-    # defaults are temporaries
-    local($in_lit2pgm)   = $ifile;
-    local($lit2pgm_hscpp) = "$Tmp_prefix.lpp";
-    local($hscpp_hsp)    = "$Tmp_prefix.cpp";
-    local($hsp_hsc)      = "$Tmp_prefix.hsp";
-    local($hsc_cc)       = "$Tmp_prefix.hc";
-
-    # to help C compilers grok .hc files [ToDo: de-hackify]
-    local($cc_help)      = "ghc$$.c";
-    local($cc_help_s)    = "ghc$$.s";
-
-    local($hsc_hi)       = "$Tmp_prefix$HiSuffix";
-    local($cc_as_o)      = "${Tmp_prefix}_o.s"; # temporary for raw .s file if opt C
-    local($cc_as)        = "$Tmp_prefix.s";
-    local($as_out)       = ($Specific_output_file ne '' && ! $Do_lnkr)
-                               ? $Specific_output_file
-                               : &odir_ify("${ifile_root}${Osuffix}");
-
-    local($is_hc_file)   = 1; #Is the C code .hc or .c
-
-    if ($ifile =~ /\.lhs$/) {
-       push(@Link_file, &odir_ify("${ifile_root}${Osuffix}"));
-    } elsif ($ifile =~ /\.hs$/) {
-       $do_lit2pgm = 0;
-       $lit2pgm_hscpp = $ifile;
-       push(@Link_file, &odir_ify("${ifile_root}${Osuffix}"));
-    } elsif ($ifile =~ /\.hc$/) {
-       $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 1;
-       $hsc_cc = $ifile;    
-       push(@Link_file, &odir_ify("${ifile_root}${Osuffix}"));
-    } elsif ($ifile =~ /\.c$/) {
-       $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 1;
-       $hsc_cc = $ifile; $is_hc_file = 0;
-       push(@Link_file, &odir_ify("${ifile_root}${Osuffix}"));
-    } elsif ($ifile =~ /\.s$/) {
-       $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 0;
-       $cc_as = $ifile;    
-       push(@Link_file, &odir_ify("${ifile_root}${Osuffix}"));
-    } else {
-       if ($ifile !~ /\.a$/) {
-           print STDERR "$Pgm: don't recognise suffix on `$ifile'; passing it through to linker\n";
-       }
-       $do_lit2pgm = 0; $do_hscpp = 0; $do_hsp = 0; $do_hsc = 0; $do_cc = 0; $do_as = 0;
-       push(@Link_file, $ifile);
-    }
-\end{code}
-
-To get the output file name right: for each phase that we are {\em
-not} going to run, set its input (i.e., the output of its preceding phase) to
-@"$ifile_root.<suffix>"@.
-\begin{code}
-    # lit2pgm -- no preceding phase
-    if (! $do_hscpp) {
-       $lit2pgm_hscpp = "$ifile_root.lpp????"; # not done
-    }
-    if (! $do_hsp) {
-       $hscpp_hsp = "$ifile_root.cpp????"; # not done
-    }
-    if (! $do_hsc) {
-       $hsp_hsc = "$ifile_root.hsp????"; # not done
-    }
-    if (! $do_cc) {
-       $hsc_cc = &odir_ify("$ifile_root.hc");
-    }
-    if (! $do_as) {
-       if ($Specific_output_file ne '') {
-           $cc_as  = $Specific_output_file;
-       } else {
-           $cc_as  = &odir_ify(( $Only_preprocess_C ) ? "$ifile_root.i" : "$ifile_root.s");
-       }
-    }
-\end{code}
-
-OK, now do it!  Note that we don't come back from a @run_something@ if
-it fails.
-\begin{code}
-    if ($do_lit2pgm) {
-       local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $lit2pgm_hscpp; ".
-                       "$Unlit @Unlit_flags $in_lit2pgm -  >> $lit2pgm_hscpp";
-       @Files_to_tidy = ( $lit2pgm_hscpp );
-       &run_something($to_do, 'literate pre-processor');
-    }
-    if ($do_hscpp) {
-       # ToDo: specific output?
-       if ($HsCpp eq $Cat) {
-           local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsp; ".
-                           "$HsCpp $lit2pgm_hscpp >> $hscpp_hsp";
-           @Files_to_tidy = ( $hscpp_hsp );
-           &run_something($to_do, 'Ineffective C pre-processor');
-       } else {
-           local($includes) = '-I' . join(' -I',@Include_dir);
-           local($to_do) = "echo '#line 1 \"$in_lit2pgm\"' > $hscpp_hsp; ".
-                           "$HsCpp $Verbose @HsCpp_flags -D__HASKELL1__=$haskell1_version -D__GLASGOW_HASKELL__=$ghc_version_info $includes $lit2pgm_hscpp >> $hscpp_hsp";
-           @Files_to_tidy = ( $hscpp_hsp );
-           &run_something($to_do, 'Haskellised C pre-processor');
-       }
-    }
-    if ($do_hsp) {
-       # glue imports onto HsP_flags
-       # if new parser, then put a comma on the front of all of them.
-       local($hsprefix) = ($do_hsp == 2) ? ',' : '';
-
-       foreach $a   ( @HsP_flags  )    { $a = "$hsprefix$a" unless $a =~ /^,/; }
-       foreach $dir ( @Import_dir )    { push(@HsP_flags, "$hsprefix-I$dir"); }
-       foreach $dir ( @SysImport_dir ) { push(@HsP_flags, "$hsprefix-J$dir"); }
-    }
-
-    if ($do_hsp == 1) { # "old" parser
-       local($to_do) = "$HsP $Verbose @HsP_flags $hscpp_hsp > $hsp_hsc";
-       @Files_to_tidy = ( $hsp_hsc );
-       &run_something($to_do, 'Haskell parser');
-       if ($Dump_parser_output) {
-           print STDERR `$Cat $hsp_hsc`;
-       }
-       @HsP_flags = (); # reset!
-    }
-    if ($do_hsc) {
-       # here, we may produce .hc and/or .hi files
-       local($output)    = '';
-       local($c_source)  = "$ifile_root.hc";
-       local($c_output)  = $hsc_cc;         # defaults
-       local($s_output)  = $cc_as;
-       local($hi_output) = "$ifile_root$HiSuffix";
-       local($going_interactive) = 0;
-
-       if ($Specific_output_file ne '' && ! $do_cc) {
-           $c_source = $c_output = $Specific_output_file;
-           @Files_to_tidy = ( $Specific_output_file ) if $Specific_output_file ne '-';
-       }
-       if ($Specific_hi_file ne '') {
-           # we change the suffix (-hisuf) even if a specific -ohi file:
-           $Specific_hi_file =~ s/\.hi$/$HiSuffix/;
-           $hi_output = $Specific_hi_file;
-           @Files_to_tidy = ( $Specific_hi_file ) if $Specific_hi_file ne '-';
-       }
-
-       if ( ! ($ProduceC || $ProduceS)
-           || $ifile_root eq '_stdin'  # going interactive...
-           || ($c_output eq '-' && $hi_output eq '-')) {
-           $going_interactive = 1;
-#OLD:      $output = '1>&2';   # interactive/debugging, to stderr
-           @Files_to_tidy = ();
-           # don't need .hi (unless magic value "2" says we wanted it anyway):
-           if ( $ProduceHi == 2 ) {
-               $output .= " -hi$hsc_hi";
-               unlink($hsc_hi); # needs to be cleared; will be appended to
-           } else {
-               $ProduceHi = 0;
-           }
-           $do_cc = 0; $do_as = 0; $Do_lnkr = 0; # and we won't go any further...
-       }
-
-       if ( ! $going_interactive ) {
-           if ( $ProduceHi ) {
-               # we always go to a temp file for these (for later diff'ing)
-               $output = "-hi$hsc_hi";
-               unlink($hsc_hi); # needs to be cleared; will be appended to
-               @Files_to_tidy = ( $hsc_hi );
-           }
-           if ( $ProduceC ) {
-               $output .= " -C$c_output";
-               push(@Files_to_tidy, $c_output);
-
-               open(CFILE, "> $c_output") || &tidy_up_and_die(1,"$Pgm: failed to open `$c_output' (to write)\n");
-               print CFILE "#line 2 \"$c_source\"\n";
-               close(CFILE) || &tidy_up_and_die(1,"Failed writing to $c_output\n");
-               # the "real" C output will then be appended
-           }
-           if ( $ProduceS ) {
-               $output .= " -fasm-$ProduceS -S$s_output";
-               push(@Files_to_tidy, $s_output);
-
-               # ToDo: ummm,... this isn't doing anything (WDP 94/11)
-               open(SFILE, "> $s_output") || &tidy_up_and_die(1,"$Pgm: failed to open `$s_output' (to write)\n");
-               close(SFILE) || &tidy_up_and_die(1,"Failed writing to $s_output\n");
-               # the "real" assembler output will then be appended
-           }
-       }
-
-       # if we're compiling foo.hs, we want the GC stats to end up in foo.stat
-       if ( $CollectingGCstats ) {
-           if ($RTS_style eq 'hbc') {
-               push(@HsC_rts_flags, '-S'); # puts it in "STAT"
-           } else {
-               push(@HsC_rts_flags, "-S$ifile_root.stat");
-               push(@Files_to_tidy, "$ifile_root.stat");
-           }
-       }
-
-       if ( $CollectGhcTimings ) { # assume $RTS_style eq 'ghc'
-           # emit nofibbish time/bytes-alloc stats to stderr;
-           # see later .stat file post-processing
-           push(@HsC_rts_flags, "-s$Tmp_prefix.stat");
-           push(@Files_to_tidy, "$Tmp_prefix.stat");
-       }
-
-       local($dump);
-       if ($Specific_dump_file ne '') {
-           $dump = "2>> $Specific_dump_file";
-           $Using_dump_file = 1;
-        } else {
-           $dump = '';
-        }
-
-       local($to_do);
-       if ($RTS_style eq 'hbc') {
-           # NB: no parser flags
-           $to_do = "$HsC < $hsp_hsc $dump @HsC_rts_flags - @HsC_flags $CoreLint $Verbose $output";
-       } elsif ($do_hsp == 1) { # old style parser -- no HsP_flags
-           $to_do = "$HsC < $hsp_hsc $dump @HsC_flags $CoreLint $Verbose $output +RTS @HsC_rts_flags";
-       } else { # new style
-           $to_do = "$HsC ,-H @HsP_flags ,$hscpp_hsp $dump @HsC_flags $CoreLint $Verbose $output +RTS @HsC_rts_flags";
-       }
-       &run_something($to_do, 'Haskell compiler');
-
-       # compensate further for HBC's -S rts opt:
-       if ($CollectingGCstats && $RTS_style eq 'hbc') {
-           unlink("$ifile_root.stat");
-           rename('STAT', "$ifile_root.stat");
-       }
-
-       # finish business w/ nofibbish time/bytes-alloc stats
-       &process_ghc_timings() if $CollectGhcTimings;
-
-       # if non-interactive, heave in the consistency info at the end
-       # NB: pretty hackish (depends on how $output is set)
-       if ( ! $going_interactive ) {
-           if ( $ProduceC ) {
-           $to_do = "echo 'static char ghc_hsc_ID[] = \"\@(#)hsc $ifile\t$HsC_major_version.$HsC_minor_version,$HsC_consist_options\";' >> $c_output";
-           }
-           if ( $ProduceS ) {
-               local($consist) = "hsc.$ifile.$HsC_major_version.$HsC_minor_version.$HsC_consist_options";
-               $consist =~ s/,/./g;
-               $consist =~ s/\//./g;
-               $consist =~ s/-/_/g;
-               $consist =~ s/[^A-Za-z0-9_.]/ZZ/g; # ToDo: properly?
-               $to_do = "echo '\n\t.text\n$consist:' >> $s_output";
-           }
-           &run_something($to_do, 'Pin on Haskell consistency info');  
-       }
-
-       # call the special mangler to produce the .hi/.h(h?) files...
-       &diff_hi_file($hsc_hi, $hi_output)
-               if $ProduceHi == 1 && ! $going_interactive;
-#OLD:  &extract_c_and_hi_files("$Tmp_prefix.hsc", $c_output, $hi_output, $c_source)
-
-       # if we produced an interface file "no matter what",
-       # print what we got on stderr (ToDo: honor -ohi flag)
-       if ( $ProduceHi == 2 ) {
-           print STDERR `$Cat $hsc_hi`;
-       }
-
-       # save a copy of the .hc file, even if we are carrying on...
-       if ($ProduceC && $do_cc && $Keep_hc_file_too) {
-           local($to_do) = "$(RM) $ifile_root.hc; cp $c_output $ifile_root.hc";
-           &run_something($to_do, 'Saving copy of .hc file');
-       }
-
-       # save a copy of the .s file, even if we are carrying on...
-       if ($ProduceS && $do_as && $Keep_s_file_too) {
-           local($to_do) = "$(RM) $ifile_root.s; cp $cc_as $ifile_root.s";
-           &run_something($to_do, 'Saving copy of .s file');
-       }
-
-       # if we're going to split up object files,
-       # we inject split markers into the .hc file now
-       if ( $ProduceC && $SplitObjFiles ) {
-           &inject_split_markers ( $c_output );
-       }
-    }
-    if ($do_cc) {
-       local($includes) = '-I' . join(' -I',@Include_dir);
-       local($cc);
-       local($s_output);
-       local($c_flags) = "@CcBoth_flags";
-       local($ddebug_flag) = ( $DEBUGging ) ? '-DDEBUG' : '';
-       if ($RegisteriseC) {
-           $cc       = $CcRegd;
-           $s_output = ($is_hc_file || $TargetPlatform =~ /^(hppa|i386)/) ? $cc_as_o : $cc_as;
-           $c_flags .= " @CcRegd_flags";
-           $c_flags .= ($is_hc_file) ? " @CcRegd_flags_hc"  : " @CcRegd_flags_c";
-       } else {
-           $cc       = $CcUnregd;
-           $s_output = $cc_as;
-           $c_flags .= " @CcUnregd_flags";
-           $c_flags .= ($is_hc_file) ? " @CcUnregd_flags_hc" : " @CcUnregd_flags_c";
-       }
-
-       # C compiler won't like the .hc extension.  So we create
-       # a tmp .c file which #include's the needful.
-       open(TMP, "> $cc_help") || &tidy_up_and_die(1,"$Pgm: failed to open `$cc_help' (to write)\n");
-       if ( $is_hc_file ) {
-           print TMP <<EOINCL;
-#ifdef __STG_GCC_REGS__
-# if ! (defined(MAIN_REG_MAP) || defined(MARK_REG_MAP) || defined(SCAN_REG_MAP) || defined(SCAV_REG_MAP) || defined(FLUSH_REG_MAP))
-#  define MAIN_REG_MAP
-# endif
-#endif
-#include "stgdefs.h"
-EOINCL
-           # user may have asked for #includes to be injected...
-           print TMP @CcInjects if $#CcInjects >= 0;
-       }
-       # heave in the consistency info
-       print TMP "static char ghc_cc_ID[] = \"\@(#)cc $ifile\t$Cc_major_version.$Cc_minor_version,$Cc_consist_options\";\n";
-
-       # and #include the real source
-       print TMP "#include \"$hsc_cc\"\n";
-       close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n");
-
-       local($to_do) = "$cc $Verbose $ddebug_flag $c_flags @Cpp_define -D__HASKELL1__=$haskell1_version $includes $cc_help > $Tmp_prefix.ccout 2>&1 && ( if [ $cc_help_s != $s_output ] ; then mv $cc_help_s $s_output ; else exit 0 ; fi )";
-       # note: __GLASGOW_HASKELL__ is pointedly *not* #defined at the C level.
-       if ( $Only_preprocess_C ) { # HACK ALERT!
-           $to_do =~ s/ -S\b//g;
-       }
-       @Files_to_tidy = ( $cc_help, $cc_help_s, $s_output );
-       $PostprocessCcOutput = 1;       # hack, dear hack...
-       &run_something($to_do, 'C compiler');
-       $PostprocessCcOutput = 0;
-       unlink($cc_help, $cc_help_s);
-
-       if ( ($RegisteriseC && $is_hc_file)
-         || $Dump_asm_insn_counts
-         || $Dump_asm_globals_info ) {
-           # dynamically load assembler-fiddling code, which we are about to use
-           local($target) = 'oops';
-           $target = '-alpha'   if $TargetPlatform =~ /^alpha-/;
-           $target = '-hppa'    if $TargetPlatform =~ /^hppa/;
-           $target = ''         if $TargetPlatform =~ /^i386-/;
-           $target = '-m68k'    if $TargetPlatform =~ /^m68k-/;
-           $target = '-mips'    if $TargetPlatform =~ /^mips-/;
-           $target = ''         if $TargetPlatform =~ /^powerpc-/;
-           $target = '-solaris' if $TargetPlatform =~ /^sparc-sun-solaris2/;
-           $target = '-sparc'   if $TargetPlatform =~ /^sparc-sun-sunos4/;
-
-           $target ne 'oops'
-           || &tidy_up_and_die(1,"$Pgm: panic: can't decipher $TargetPlatform!\n");
-           require("ghc-asm$target.prl")
-           || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm$target.prl!\n");
-       }
-
-       if ( $Dump_raw_asm ) { # to stderr, before mangling
-           local($to_pr) = ($RegisteriseC) ? $cc_as_o : $cc_as ;
-           print STDERR `cat $to_pr`;
-       }
-
-       if ($RegisteriseC) {
-            if ($is_hc_file) {
-               # post-process the assembler [.hc files only]
-               &mangle_asm($cc_as_o, $cc_as);
-
-           } elsif ($TargetPlatform =~ /^hppa/) {
-               # minor mangling of non-threaded files for hp-pa only
-               require('ghc-asm-hppa.prl')
-               || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm-hppa.prl!\n");
-               &mini_mangle_asm($cc_as_o, $cc_as);
-
-           } elsif ($TargetPlatform =~ /^i386/) {
-               # extremely-minor OFFENSIVE mangling of non-threaded just one file
-               require('ghc-asm.prl')
-               || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm.prl!\n");
-               &mini_mangle_asm($cc_as_o, $cc_as);
-           }
-       }
-
-       # collect interesting (static-use) info
-       &dump_asm_insn_counts($cc_as)  if $Dump_asm_insn_counts;
-       &dump_asm_globals_info($cc_as) if $Dump_asm_globals_info;
-
-       # save a copy of the .s file, even if we are carrying on...
-       if ($do_as && $Keep_s_file_too) {
-           local($to_do) = "$(RM) $ifile_root.s; cp $cc_as $ifile_root.s";
-           &run_something($to_do, 'Saving copy of .s file');
-       }
-    }
-
-    if ($do_as) {
-       # if we're splitting .o files...
-       if ( $SplitObjFiles ) {
-           &split_asm_file ( $cc_as );
-       }
-
-       local($asmblr) = ( $As ) ? $As : ($RegisteriseC ? $CcRegd : $CcUnregd );
-
-       if ( ! $SplitObjFiles ) {
-           local($to_do)  = "$asmblr -o $as_out -c @As_flags $cc_as";
-           @Files_to_tidy = ( $as_out );
-           &run_something($to_do, 'Unix assembler');
-
-       } else { # more complicated split-ification...
-
-           # must assemble files $Tmp_prefix__[1 .. $NoOfSplitFiles].s
-
-           for ($f = 1; $f <= $NoOfSplitFiles; $f++ ) {
-               local($split_out) = &odir_ify("${ifile_root}__${f}${Osuffix}");
-               local($to_do) = "$asmblr -o $split_out -c @As_flags ${Tmp_prefix}__${f}.s";
-               @Files_to_tidy = ( $split_out );
-
-               &run_something($to_do, 'Unix assembler');
-           }
-       }
-    }
-} # end of ProcessInputFile
-\end{code}
-
-%************************************************************************
-%*                                                                     *
-\section[Driver-misc-utils]{Miscellaneous utilities}
-%*                                                                     *
-%************************************************************************
-
-%************************************************************************
-%*                                                                     *
-\subsection[Driver-odir-ify]{@odir_ify@: Mangle filename if \tr{-odir} set}
-%*                                                                     *
-%************************************************************************
-
-\begin{code}
-sub odir_ify {
-    local($orig_file) = @_;
-    if ($Specific_output_dir eq '') {   # do nothing
-       return($orig_file);
-    } else {
-       local ($orig_file_only);
-       ($orig_file_only = $orig_file) =~ s|.*/||;
-       return("$Specific_output_dir/$orig_file_only");
+           &run_something($to_do, 'Unix assembler');
+       }
     }
 }
 \end{code}
@@ -2486,7 +2224,7 @@ sub run_something {
            next if /from .*(stg|rts)defs\.h:/;
            next if /from ghc\d+.c:\d+:/;
            next if /from .*\.lc/;
-           next if /from .*SMinternal\.lh/;
+           next if /from .*SMinternal\.l?h/;
            next if /ANSI C does not support \`long long\'/;
            next if /warning:.*was declared \`extern\' and later \`static\'/;
            next if /warning: assignment discards \`const\' from pointer target type/;
@@ -2511,60 +2249,6 @@ sub run_something {
 
 %************************************************************************
 %*                                                                     *
-\subsection[Driver-demangle-C-and-hi]{@extract_c_and_hi_files@: Unscramble Haskell-compiler output}
-%*                                                                     *
-%************************************************************************
-
-Update interface if the tmp one is newer...
-We first have to fish the module name out of the interface.
-\begin{code}
-sub diff_hi_file {
-    local($tmp_hi_file, $hi_file) = @_;
-    local($if_modulename) = '';
-
-    # extract the module name
-
-    open(TMP,   "< $tmp_hi_file")|| &tidy_up_and_die(1,"$Pgm: failed to open `$tmp_hi_file' (to read)\n");
-    while (<TMP>) {
-       if ( /^interface ([A-Za-z0-9'_]+) / ) {
-           $if_modulename = $1;
-       }
-    }
-    close(TMP) || &tidy_up_and_die(1,"Failed reading from $tmp_hi_file\n");
-    &tidy_up_and_die(1,"No module name in $tmp_hi_file\n")
-       if ! $if_modulename;
-
-    #compare/diff with old one
-
-    if ($hi_file eq '-') {
-       &run_something("cat $tmp_hi_file", "copy interface to stdout");
-
-    } else {
-       if ($Specific_hi_file eq '' && $if_modulename ne '') {
-           if ( $hi_file =~ /\// ) {
-                $hi_file =~ s/\/[^\/]+$//;
-                $hi_file .= "/$if_modulename$HiSuffix";
-           } else {
-               $hi_file = "$if_modulename$HiSuffix";
-           }
-           print STDERR "interface really going into: $hi_file\n" if $Verbose;
-       }
-
-       if ($HiDiff_flag && -f $hi_file) {
-           local($diffcmd) = '$(CONTEXT_DIFF)';
-
-           &run_something("cmp -s $tmp_hi_file $hi_file || $(CONTEXT_DIFF) $hi_file $tmp_hi_file 1>&2 || exit 0",
-               "Diff'ing old and new $HiSuffix files"); # NB: to stderr
-       }
-
-       &run_something("cmp -s $tmp_hi_file $hi_file || ( $(RM) $hi_file && $(CP) $tmp_hi_file $hi_file )",
-                      "Comparing old and new $HiSuffix files");
-    }
-}
-\end{code}
-
-%************************************************************************
-%*                                                                     *
 \subsection[Driver-ghctiming]{Emit nofibbish GHC timings}
 %*                                                                     *
 %************************************************************************
@@ -2647,7 +2331,7 @@ sub process_ghc_timings {
 
 \begin{code}
 sub tidy_up {
-    local($to_do) = "\n$(RM) $Tmp_prefix*";
+    local($to_do) = "\n$Rm $Tmp_prefix*";
     if ( $Tmp_prefix !~ /^\s*$/ ) {
        print STDERR "$to_do\n" if $Verbose;
        system($to_do);
@@ -2680,15 +2364,15 @@ next argument (\tr{-Rmax-heapsize 8M}).  We allow both cases.
 
 Note: no error-checking; \tr{-Rmax-heapsize -Rgc-stats} will silently
 gobble the second argument (and probably set the heapsize to something
-nonsensical). (ToDo?)
+nonsensical).
 \begin{code}
 sub grab_arg_arg {
-    local($option, $rest_of_arg) = @_;
+    local(*Args, $option, $rest_of_arg) = @_;
     
     if ($rest_of_arg) {
        return($rest_of_arg);
-    } elsif ($#ARGV >= 0) {
-       local($temp) = $ARGV[0]; shift(@ARGV); 
+    } elsif ($#Args >= 0) {
+       local($temp) = $Args[0]; shift(@Args); 
        return($temp);
     } else {
        print STDERR "$Pgm: no argument following $option option\n";
@@ -2731,3 +2415,659 @@ sub add_Hsc_flags {
     }
 }
 \end{code}
+
+Source files may have {-# OPTIONS ... #-} pragmas at the top, containing
+command line options we want to append to collection of commands specified
+directly. @check_for_source_options@ looks at the top of a de-lit'ified Haskell
+file for any such pragmas:
+
+\begin{code}
+sub check_for_source_options {
+    local($file) = @_;
+
+    open(FILE,$file) || return(1); # No big loss
+
+    while (<FILE>) {
+       if ( /^{-# OPTIONS (.*)#-}/ ) {
+           # add the options found at the back of the command line.
+          local(@entries) = split(/\s+/,$1);
+          push(@File_options, @entries);
+       }
+        elsif ( /^$/ ) { # ignore empty lines
+           ;
+        }
+        else { # stop looking, something non-empty / not
+              # {-# OPTIONS .. #-} encountered.
+           break;
+        }
+    }
+    close(FILE);
+    return(0);
+}
+\end{code}
+
+
+We split the initial argv up into three arrays:
+
+  - @Cmd_opts 
+  - @Link_file
+  - @Input_file
+
+the reason for doing so is to be able to deal
+with {-# OPTIONS #-} pragma in source files properly.
+
+\begin{code}
+sub splitCmdLine {
+    local(@args) = @_;
+
+arg: while($_ = $args[0]) {
+    shift(@args);
+    # sigh, we have to deal with these -option arg specially here.
+    /^-(tmpdir|odir|o|isuf|osuf|hisuf|hisuf-prelude|odump|syslib)$/ && 
+       do { push(@Cmd_opts, $_); push(@Cmd_opts,$args[0]); shift(@args); next arg; };
+    /^-./  && do { push(@Cmd_opts, $_); next arg; };
+
+    if (/\.[oa]$/) {
+       push(@Link_file, $_);
+    } else {
+       push(@Input_file, $_);
+    }
+
+    # input files must exist:
+    if (! -f $_) {
+       print STDERR "$Pgm: input file doesn't exist: $_\n";
+       $Status++;
+    }
+  }
+}    
+
+\end{code}
+
+Command-line processor
+
+\begin{code}
+sub processArgs {
+    local(@Args) = @_;
+
+# can't use getopt(s); what we want is too complicated
+
+arg: while($_ = $Args[0]) {
+    shift(@Args);
+
+    #---------- help -------------------------------------------------------
+    if (/^-\?$/ || /^--?help$/) { print $LongUsage; exit $Status; }
+
+    #-----------version ----------------------------------------------------
+    /^--version$/   && do { print STDERR "${PROJECTNAME}, version ${PROJECTVERSION}, patchlevel ${PROJECTPATCHLEVEL}\n"; exit $Status; };
+
+    #---------- verbosity and such -----------------------------------------
+    /^-v$/         && do { $Verbose = '-v'; $Time = 'time'; next arg; };
+
+    #---------- what phases are to be run ----------------------------------
+    /^-recomp/     && do { $Do_recomp_chkr = 1; next arg; };
+
+    /^-cpp$/       && do { $Cpp_flag_set = 1; next arg; };
+    # change the global default:
+    # we won't run cat; we'll run the real thing
+       
+    /^-C$/         && do { $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0; $HscOut = '-C=';
+                           next arg; };
+    # stop after generating C
+       
+    /^-noC$/       && do { $HscOut = '-N='; $ProduceHi = '-nohifile=';
+                           $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0;
+                           next arg; };
+    # leave out actual C generation (debugging) [also turns off interface gen]
+
+    /^-hi$/        && do { $HiOnStdout = 1; $ProduceHi = '-hifile='; next arg; };
+    # _do_ generate an interface; usually used as: -noC -hi
+
+    /^-nohi$/      && do { $ProduceHi = '-nohifile='; next arg; };
+    # don't generate an interface (even if generating C)
+
+    /^-hi-diffs$/             && do { $HiDiff_flag = 'normal'; next arg; };
+    /^-hi-diffs-with-usages$/ && do { $HiDiff_flag = 'usages'; next arg; };
+    /^-no-hi-diffs$/          && do { $HiDiff_flag = '';       next arg; };
+    # show/disable diffs if the interface file changes
+
+    /^-E$/         && do { push(@CcBoth_flags, '-E');
+                           $Only_preprocess_C = 1;
+                           $Do_as = 0; $Do_lnkr = 0; next arg; };
+    # stop after preprocessing C
+    /^-M$/         && do { $Only_generate_deps = 1; $Do_as = 0; $Do_lnkr = 0; next arg; };
+    # only generate dependency information.
+    /^-S$/         && do { $Do_as = 0; $Do_lnkr = 0; next arg; };
+    # stop after generating assembler
+       
+    /^-c$/         && do { $Do_lnkr = 0; next arg; };
+    # stop after generating .o files
+
+    /^-link-chk$/    && do { $LinkChk = 1; next arg; };
+    /^-no-link-chk$/ && do { $LinkChk = 0; next arg; };
+    # don't do consistency-checking after a link
+
+    /^-tmpdir$/ && do { $Tmp_prefix = &grab_arg_arg(*Args,'-tmpdir', '');
+                       $Tmp_prefix = "$Tmp_prefix/ghc$$";
+                       $ENV{'TMPDIR'} = $Tmp_prefix; # for those who use it...
+                       next arg; };
+    # use an alternate directory for temp files
+
+    #---------- redirect output --------------------------------------------
+
+    # -o <file>; applies to the last phase, whatever it is
+    # "-o -" sends it to stdout
+    # if <file> has a directory component, that dir must already exist
+
+    /^-odir$/      && do { $Specific_output_dir = &grab_arg_arg(*Args,'-odir', '');
+                           #
+                           # Hack, of the worst sort: don't do validation of
+                           # odir argument if you're using -M (dependency generation).
+                           #
+                           if ( ! $Only_generate_deps && ! -d $Specific_output_dir) {
+                               print STDERR "$Pgm: -odir: no such directory: $Specific_output_dir\n";
+                               $Status++;
+                           }
+                           next arg; };
+
+    /^-o$/         && do { $Specific_output_file = &grab_arg_arg(*Args,'-o', '');
+                           if ($Specific_output_file ne '-'
+                            && $Specific_output_file =~ /(.*)\/[^\/]*$/) {
+                               local($dir_part) = $1;
+                               if (! -d $dir_part) {
+                                   print STDERR "$Pgm: no such directory: $dir_part\n";
+                                   $Status++;
+                               }
+                           }
+                           next arg; };
+
+    # NB: -isuf not documented yet (because it doesn't work yet)
+    /^-isuf$/      && do { $Isuffix  = &grab_arg_arg(*Args,'-isuf', '');
+                           if ($Isuffix =~ /\./ ) {
+                               print STDERR "$Pgm: -isuf suffix shouldn't contain a .\n";
+                               $Status++;
+                           }
+                           next arg; };
+
+    /^-osuf$/      && do { $Osuffix  = &grab_arg_arg(*Args,'-osuf', '');
+                           if ($Osuffix =~ /\./ ) {
+                               print STDERR "$Pgm: -osuf suffix shouldn't contain a .\n";
+                               $Status++;
+                           }
+                           next arg; };
+
+    # -ohi <file>; send the interface to <file>; "-ohi -" to send to stdout
+    /^-ohi$/       && do { $Specific_hi_file = &grab_arg_arg(*Args,'-ohi', '');
+                           if ($Specific_hi_file ne '-'
+                            && $Specific_hi_file =~ /(.*)\/[^\/]*$/) {
+                               local($dir_part) = $1;
+                               if (! -d $dir_part) {
+                                   print STDERR "$Pgm: no such directory: $dir_part\n";
+                                   $Status++;
+                               }
+                           }
+                           next arg; };
+
+    # The suffix to use when looking for interface files
+    /^-hisuf$/     && do { $HiSuffix = &grab_arg_arg(*Args,'-hisuf', '');
+                           if ($HiSuffix =~ /\./ ) {
+                               print STDERR "$Pgm: -hisuf suffix shouldn't contain a .\n";
+                               $Status++;
+                           }
+                           next arg; };
+    # ToDo: remove, not a `normal' user thing to do (should be automatic)
+    /^-hisuf-prelude$/     && do { $HiSuffix_prelude = &grab_arg_arg(*Args,'-hisuf-prelude', '');
+                           if ($HiSuffix =~ /\./ ) {
+                               print STDERR "$Pgm: -hisuf-prelude suffix shouldn't contain a .\n";
+                               $Status++;
+                           }
+                           next arg; };
+    /^-odump$/     && do { $Specific_dump_file = &grab_arg_arg(*Args,'-odump', '');
+                           if ($Specific_dump_file =~ /(.*)\/[^\/]*$/) {
+                               local($dir_part) = $1;
+                               if (! -d $dir_part) {
+                                   print STDERR "$Pgm: no such directory: $dir_part\n";
+                                   $Status++;
+                               }
+                           }
+                           next arg; };
+
+    #-------------- scc & Profiling Stuff ----------------------------------
+
+    /^-prof$/ && do { $PROFing = 'p'; next arg; }; # profiling -- details later!
+
+    /^-auto/ && do {
+               # generate auto SCCs on top level bindings
+               # -auto-all = all top level bindings
+               # -auto     = only top level exported bindings
+               $PROFauto = ( /-all/ )
+                           ? '-fauto-sccs-on-all-toplevs'
+                           : '-fauto-sccs-on-exported-toplevs';
+               next arg; };
+
+    /^-caf-all/ && do { # generate individual CAF SCC annotations
+               $PROFcaf = '-fauto-sccs-on-individual-cafs';
+               next arg; };
+
+    /^-ignore-scc$/ && do {
+               # forces ignore of scc annotations even if profiling
+               $PROFignore_scc = '-W';
+               next arg; };
+
+    /^-G(.*)$/ && do { push(@HsC_flags, "-G=$1");   # set group for cost centres
+                       next arg; };
+
+    /^-unprof-scc-auto/ && do {
+               # generate auto SCCs on top level bindings when not profiling.
+               # Used to measure optimisation effects of presence of sccs.
+               $UNPROFscc_auto = ( /-all/ )
+                           ? '-fauto-sccs-on-all-toplevs'
+                           : '-fauto-sccs-on-exported-toplevs';
+               next arg; };
+
+    #--------- ticky/concurrent/parallel -----------------------------------
+    # we sort out the details a bit later on
+
+    /^-concurrent$/ && do { $CONCURing = 'c'; next arg; }; # concurrent Haskell
+    /^-gransim$/    && do { $GRANing   = 'g'; next arg; }; # GranSim
+    /^-ticky$/     && do { $TICKYing  = 't'; next arg; }; # ticky-ticky
+    /^-parallel$/   && do { $PARing    = 'p'; next arg; }; # parallel Haskell
+
+    #-------------- "user ways" --------------------------------------------
+
+    (/^-user-setup-([a-oA-Z])$/ ) && 
+           do {
+               /^-user-setup-([a-oA-Z])$/  && do { $BuildTag = "_$1"; };
+
+               local($stuff) = $UserSetupOpts{$BuildTag};
+               local(@opts)  = split(/\s+/, $stuff);
+               
+               # feed relevant ops into the arg-processing loop (if any)
+               unshift(@Args, @opts) if $#opts >= 0;
+
+               next arg; };
+
+    #---------- set search paths for libraries and things ------------------
+
+    # we do -i just like HBC (-i clears the list; -i<colon-separated-items>
+    # prepends the items to the list); -I is for including C .h files.
+
+    /^-i$/         && do { @Import_dir = ();  # import path cleared!
+                           @SysImport_dir = ();
+                           print STDERR "WARNING: import paths cleared by `-i'\n";
+                           next arg; };
+
+    /^-i(.*)/      && do { local(@new_items)
+                             = split( /:/, &grab_arg_arg(*Args,'-i', $1));
+                           unshift(@Import_dir, @new_items);
+                           next arg; };
+
+    /^-I(.*)/      && do { push(@Include_dir,     &grab_arg_arg(*Args,'-I', $1)); next arg; };
+    /^-L(.*)/      && do { push(@UserLibrary_dir, &grab_arg_arg(*Args,'-L', $1)); next arg; };
+    /^-l(.*)/      && do { push(@UserLibrary,'-l'.&grab_arg_arg(*Args,'-l', $1)); next arg; };
+
+    /^-syslib(.*)/  && do { local($syslib) = &grab_arg_arg(*Args,'-syslib',$1);
+                           print STDERR "$Pgm: no such system library (-syslib): $syslib\n",
+                             $Status++ unless $syslib =~ /^(hbc|ghc|posix|contrib)$/;
+
+                           unshift(@SysImport_dir,
+                               ${INSTALLING}
+                               ? "$InstSysLibDir/$syslib/imports"
+                               : "$TopPwd/hslibs/$syslib/src");
+
+                           if ( ${INSTALLING} ) {
+                               push(@SysLibrary_dir,
+                                       ("$InstSysLibDir"));
+                           } else {
+                               push(@SysLibrary_dir,
+                                       ("$TopPwd/hslibs/$syslib"
+                                       ,"$TopPwd/hslibs/$syslib/cbits"));
+                           }
+
+                           push(@SysLibrary, "-lHS$syslib");
+                           push(@SysLibrary, "-lHS${syslib}_cbits")
+                             unless $syslib eq 'contrib'; #HACK! it has no cbits
+
+                           next arg; };
+
+    #=======================================================================
+    # various flags that we can harmlessly send to one program or another
+    # (we will later "reclaim" some of the compiler ones now sent to gcc)
+    #=======================================================================
+
+    #---------- this driver itself (ghc) -----------------------------------
+    # these change what executable is run for each phase:
+    /^-pgmL(.*)$/   && do { $Unlit      = $1; next arg; };
+    /^-pgmP(.*)$/   && do { $HsCpp      = $1; next arg; };
+    /^-pgmC(.*)$/   && do { $HsC        = $1; next arg; };
+    /^-pgmcO?(.*)$/ && do { $CcRegd     = $1; next arg; }; # the O? for back compat
+    /^-pgma(.*)$/   && do { $As         = $1; next arg; };
+    /^-pgml(.*)$/   && do { $Lnkr       = $1; next arg; };
+    /^-pgmdep(.*)$/ && do { $MkDependHS = $1; next arg; };
+
+    #---------- the get-anything-through opts (all pgms) -------------------
+    # these allow arbitrary option-strings to go to any phase:
+    /^-optL(.*)$/   && do { push(@Unlit_flags,      $1); next arg; };
+    /^-optP(.*)$/   && do { push(@HsCpp_flags,      $1); next arg; };
+    /^-optCrts(.*)$/&& do { push(@HsC_rts_flags,    $1); next arg; };
+    /^-optC(.*)$/   && do { push(@HsC_flags,        $1); next arg; };
+    /^-optcpp(.*)$/ && do { push(@Cpp_define,       $1); next arg; };
+    /^-optc(.*)$/   && do { push(@CcBoth_flags,     $1); next arg; };
+    /^-opta(.*)$/   && do { push(@As_flags,         $1); next arg; };
+    /^-optl(.*)$/   && do { push(@Ld_flags,         $1); next arg; };
+    /^-optdep(.*)$/ && do { push(@MkDependHS_flags, $1); next arg; };
+
+    #---------- Haskell C pre-processor (hscpp) ----------------------------
+    /^-D(.*)/      && do { push(@HsCpp_flags, "'-D".&grab_arg_arg(*Args,'-D',$1)."'"); next arg; };
+    /^-U(.*)/      && do { push(@HsCpp_flags, "'-U".&grab_arg_arg(*Args,'-U',$1)."'"); next arg; };
+
+    /^-genSPECS/   && do { $Cpp_flag_set = 1;
+                          $genSPECS_flag = $_;
+                           next arg; };
+
+    #---------- post-Haskell "assembler"------------------------------------
+    /^-ddump-raw-asm$/           && do { $Dump_raw_asm        = 1; next arg; };
+    /^-ddump-asm-splitting-info$/ && do { $Dump_asm_splitting_info = 1; next arg; };
+
+    #---------- Haskell compiler (hsc) -------------------------------------
+
+    /^-keep-hc-files?-too$/    && do { $Keep_hc_file_too = 1; next arg; };
+    /^-keep-s-files?-too$/     && do { $Keep_s_file_too = 1;  next arg; };
+
+    /^-fhaskell-1\.3$/         && do { next arg; }; # a no-op right now
+
+    /^-fignore-interface-pragmas$/ && do { push(@HsC_flags, $_); next arg; };
+
+    /^-fno-implicit-prelude$/      && do { $NoImplicitPrelude= 1; push(@HsC_flags, $_); next arg; };
+     # don't do stack checking using page fault `trick'.
+     # (esoteric).
+    /^-fstack-check$/             && do { $StkChkByPageFaultOK = 0; next arg; };
+     #
+     # have the compiler proper generate concurrent code,
+     # really only used when you want to configure your own
+     # special user compilation way. (Use -concurrent when
+     # compiling `Concurrent Haskell' programs).
+     #
+     # (ditto for -fgransim, fscc-profiling and -fticky-ticky)
+     #
+    /^-fconcurrent$/      && do { push(@HsC_flags,$_); next arg; };
+    /^-fscc-profiling$/   && do { push(@HsC_flags,$_); next arg; };
+    /^-fticky-ticky$/     && do { push(@HsC_flags,$_); next arg; };
+    /^-fgransim$/        && do { push(@HsC_flags,$_); next arg; };
+
+    /^-user-prelude-force/     && do { # ignore if not -user-prelude
+                                       next arg; };
+
+    /^-split-objs/     && do {
+                       if ( $TargetPlatform !~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/ ) {
+                           $SplitObjFiles = 0;
+                           print STDERR "WARNING: don't know how to split objects on this platform: $TargetPlatform\n`-split-objs' option ignored\n";
+                       } else {
+                           $SplitObjFiles = 1;
+                           $HscOut = '-C=';
+
+                           push(@HsC_flags, "-fglobalise-toplev-names"); 
+                           push(@CcBoth_flags, '-DUSE_SPLIT_MARKERS');
+
+                           require('ghc-split.prl')
+                            || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-split.prl!\n");
+                       }
+                       next arg; };
+
+    /^-fglasgow-exts$/
+               && do { push(@HsC_flags, $_);
+                       push(@HsP_flags, '-N');
+
+#                      push(@HsC_flags, '-fshow-import-specs');
+
+                       next arg; };
+
+    /^-fspeciali[sz]e-unboxed$/
+               && do { $Oopt_DoSpecialise      = '-fspecialise';
+                       $Oopt_SpecialiseUnboxed = '-fspecialise-unboxed';
+                       next arg; };
+    /^-fspeciali[sz]e$/
+               && do { $Oopt_DoSpecialise = '-fspecialise'; next arg; };
+    /^-fno-speciali[sz]e$/
+               && do { $Oopt_DoSpecialise = ''; next arg; };
+
+
+# Now the foldr/build options, which are *on* by default (for -O).
+
+    /^-ffoldr-build$/
+                   && do { $Oopt_FoldrBuild = 1; 
+                           $Oopt_FB_Support = '-fdo-arity-expand';
+                           #print "Yes F/B\n";
+                           next arg; };
+
+    /^-fno-foldr-build$/
+                   && do { $Oopt_FoldrBuild = 0; 
+                           $Oopt_FB_Support = ''; 
+                           next arg; };
+
+    /^-fno-foldr-build-rule$/
+                   && do { $Oopt_FoldrBuild = 0; 
+                           next arg; };
+
+    /^-fno-enable-tech$/
+                   && do { $Oopt_FB_Support = ''; 
+                           next arg; };
+
+    /^-fno-snapback-to-append$/
+                   && do { $Oopt_FoldrBuildInline .= ' -fdo-not-fold-back-append '; 
+                           next arg; };
+
+    # ---------------
+
+    /^-fasm-(.*)$/  && do { $HscOut = '-S='; next arg; }; # force using nativeGen
+    /^-fvia-C$/            && do { $HscOut = '-C='; next arg; }; # force using C compiler
+
+    # ---------------
+
+    /^(-funfolding-use-threshold)(.*)$/
+                   && do { $Oopt_UnfoldingUseThreshold = $1 . &grab_arg_arg(*Args,$1, $2);
+                           next arg; };
+
+    /^(-fmax-simplifier-iterations)(.*)$/
+                   && do { $Oopt_MaxSimplifierIterations = $1 . &grab_arg_arg(*Args,$1, $2);
+                           next arg; };
+
+    /^-fno-pedantic-bottoms$/
+                   && do { $Oopt_PedanticBottoms = ''; next arg; };
+
+    /^-fdo-monad-eta-expansion$/
+                   && do { $Oopt_MonadEtaExpansion = $_; next arg; };
+
+    /^-fno-let-from-(case|app|strict-let)$/ # experimental, really (WDP 95/10)
+                   && do { push(@HsC_flags, $_); next arg; };
+
+    /^(-freturn-in-regs-threshold)(.*)$/
+                   && do { local($what) = $1;
+                           local($num)  = &grab_arg_arg(*Args,$what, $2);
+                           if ($num < 2 || $num > 8) {
+                               die "Bad experimental flag: $_\n";
+                           } else {
+                               $HscOut = '-C='; # force using C compiler
+                               push(@HsC_flags, "$what$num");
+                               push(@CcRegd_flags, "-D__STG_REGS_AVAIL__=$num");
+                           }
+                           next arg; };
+
+    # --------------- Warnings etc. ------
+
+    /^-f(show-import-specs)/
+                   && do { push(@HsC_flags, $_); next arg; };
+
+    # for now, just -fwarn-name-shadowing
+    /^-fwarn-(.*)$/   && do { push(@HsC_flags, $_); next arg; };
+    /^-fno-(.*)$/   && do { push(@HsC_antiflags, "-f$1");
+                           &squashHscFlag("-f$1");
+                           next arg; };
+
+    # --------------- platform specific flags (for gcc mostly) ----------------
+
+    /^-mlong-calls$/ && do { # for GCC for HP-PA boxes,
+                             # for 2.6.x..?, does not apply for 2.7.2
+                            # any longer.
+                           unshift(@CcBoth_flags, ( $_ ));
+                           next arg; };
+
+    /^-m(v8|sparclite|cypress|supersparc|cpu=(cypress|supersparc))$/
+                    && do { # for GCC for SPARCs
+                           unshift(@CcBoth_flags, ( $_ ));
+                           next arg; };
+
+    /^-monly-([432])-regs/ && do { # for iX86 boxes only; no effect otherwise
+                           $StolenX86Regs = $1;
+                           next arg; };
+
+    #*************** ... and lots of debugging ones (form: -d* )
+
+    # -d(no-)core-lint is done this way so it is turn-off-able.
+    /^-dcore-lint/       && do { $CoreLint = '-dcore-lint'; next arg; };
+    /^-dno-core-lint/    && do { $CoreLint = '';           next arg; };
+    # Ditto for STG lint
+    /^-dstg-lint/       && do { $StgLint = '-dstg-lint'; next arg; };
+    /^-dno-stg-lint/    && do { $StgLint = '';           next arg; };
+
+    /^-d(dump|ppr)-/         && do { push(@HsC_flags, $_); next arg; };
+    /^-dverbose-(simpl|stg)/ && do { push(@HsC_flags, $_); next arg; };
+    /^-dshow-passes/        && do { push(@HsC_flags, $_); next arg; };
+    /^-dshow-rn-trace/      && do { push(@HsC_flags, $_); next arg; };
+    /^-dsource-stats/        && do { push(@HsC_flags, $_); next arg; };
+    /^-dsimplifier-stats/    && do { push(@HsC_flags, $_); next arg; };
+    /^-dstg-stats/          && do { $Oopt_StgStats = $_; next arg; };
+
+    #*************** ... and now all these -R* ones for its runtime system...
+
+    /^-Rscale-sizes?(.*)/ && do {
+       $Scale_sizes_by = &grab_arg_arg(*Args,'-Rscale-sizes', $1);
+       next arg; };
+
+    /^(-H|-Rmax-heapsize)(.*)/ && do {
+       local($heap_size) = &grab_arg_arg(*Args,$1, $2);
+       if ($heap_size =~ /(\d+)[Kk]$/) {
+           $heap_size = $1 * 1000;
+       } elsif ($heap_size =~ /(\d+)[Mm]$/) {
+           $heap_size = $1 * 1000 * 1000;
+       } elsif ($heap_size =~ /(\d+)[Gg]$/) {
+           $heap_size = $1 * 1000 * 1000 * 1000;
+       }
+       if ($heap_size <= 0) {
+           print STDERR "$Pgm: resetting heap-size to zero!!! $heap_size\n";
+           $Specific_heap_size = 0;
+       
+       # if several heap sizes given, take the largest...
+       } elsif ($heap_size >= $Specific_heap_size) {
+           $Specific_heap_size = $heap_size;
+       } else {
+           print STDERR "$Pgm: ignoring heap-size-setting option ($_)...not the largest seen\n";
+       }
+       next arg; };
+
+    /^-(K|Rmax-(stk|stack)size)(.*)/ && do {
+        local($flag) = $1;
+       local($stk_size) = &grab_arg_arg(*Args,'-Rmax-stksize', $3);
+       if ($stk_size =~ /(\d+)[Kk]$/) {
+           $stk_size = $1 * 1000;
+       } elsif ($stk_size =~ /(\d+)[Mm]$/) {
+           $stk_size = $1 * 1000 * 1000;
+       } elsif ($stk_size =~ /(\d+)[Gg]$/) {
+           $stk_size = $1 * 1000 * 1000 * 1000;
+       }
+       if ($stk_size <= 0) {
+           print STDERR "$Pgm: resetting stack-size to zero!!! $stk_size\n";
+           $Specific_stk_size = 0;
+
+       # if several stack sizes given, take the largest...
+       } elsif ($stk_size >= $Specific_stk_size) {
+           $Specific_stk_size = $stk_size;
+       } else {
+           print STDERR "$Pgm: ignoring stack-size-setting option ($flag $stk_size)...not the largest seen\n";
+       }
+       next arg; };
+
+    /^-Rgc-stats$/ && do {  $CollectingGCstats++;
+                           # the two RTSs do this diff ways; we will try to compensate
+                           next arg; };
+
+    /^-Rghc-timing/ && do { $CollectGhcTimings = 1; next arg; };
+
+    #---------- C high-level assembler (gcc) -------------------------------
+    /^-(Wall|ansi|pedantic)$/ && do { push(@CcBoth_flags, $_); next arg; };
+
+    # -dgcc-lint is a useful way of making GCC very fussy.
+    # From alan@spri.levels.unisa.edu.au (Alan Modra).
+    /^-dgcc-lint$/ && do { push(@CcBoth_flags, '-Wall -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wnested-externs'); next arg; };
+    # An alternate set, from mark@sgcs.com (Mark W. Snitily)
+    # -Wall -Wstrict-prototypes -Wmissing-prototypes -Wcast-align -Wshadow
+
+    # inject "#include <wurble>" into the compiler's C output!
+
+    /^-#include(.*)/   && do {
+       local($to_include) = &grab_arg_arg(*Args,'-#include', $1);
+       push(@CcInjects, "#include $to_include\n");
+       next arg; };
+
+    #---------- Linker (gcc, really) ---------------------------------------
+
+    /^-static$/                && do { push(@Ld_flags, $_); next arg; };
+
+    #---------- mixed cc and linker magic ----------------------------------
+    # this optimisation stuff is finally sorted out later on...
+
+    /^-O2-for-C$/ && do { $MinusO2ForC = 1; next arg; };
+
+    /^-O[1-2]?$/ && do {
+               local($opt_lev) = ( /^-O2$/ ) ? 2 : 1; # max 'em
+               $OptLevel = ( $opt_lev > $OptLevel ) ? $opt_lev : $OptLevel;
+
+               $HscOut = '-C=' if $OptLevel == 2; # force use of C compiler
+               next arg; };
+
+    /^-Onot$/  && do { $OptLevel = 0; next arg; }; # # set it to <no opt>
+
+    /^-Ofile(.*)/ && do {
+               $OptLevel = 3;
+               local($ofile) = &grab_arg_arg(*Args,'-Ofile', $1);
+               @HsC_minusO3_flags = ();
+
+               open(OFILE, "< $ofile") || die "Can't open $ofile!\n";
+               while (<OFILE>) {
+                   chop;
+                   s/\#.*//;       # death to comments
+                   s/[ \t]+//g;    # death to whitespace
+                   next if /^$/;   # ditto, blank lines
+                   s/([()*{}])/\\$1/g;    # protect shell metacharacters
+                   if ( /^C:(.*)/ ) {
+                       push(@CcBoth_flags, $1);
+                   } else {
+                       push(@HsC_minusO3_flags, $_);
+                   }
+               }
+               close(OFILE);
+               next arg; };
+
+    /^-debug$/ && do { # all this does is mark a .hc/.o as "debugging"
+                       # in the consistency info
+                       $DEBUGging = 'd';
+                       next arg; };
+
+    #---------- linking .a file --------------------------------------------
+
+    /^-Main(.*)/ && do {
+               # specifies main or mainPrimIO to be linked
+               $Ld_main = $1;
+               next arg; }; 
+
+    #---------- catch unrecognized flags -----------------------------------
+
+    /^-./ && do {
+       print STDERR "$Pgm: unrecognised option: $_\n";
+       $Status++;
+       next arg; };
+
+}
+
+} # end of processArgs
+
+\end{code}