-%
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
-%
-% *** 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.
%************************************************************************
\begin{code}
+use 5; # require Perl version 5 or later.
+
($Pgm = $0) =~ s|.*/||;
$ShortUsage = "\nUsage: For basic information, try the `-help' option.\n";
$LongUsage = "\n" . <<EOUSAGE;
- 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
The phase at which to STOP processing is determined by a command-line
option:
+ -E stop after generating preprocessed, de-litted Haskell (used in conjunction with -cpp)
-C stop after generating C (.hc output)
- -E stop after generating preprocessed C (.i output)
-S stop after generating assembler (.s output)
-c stop after generating object files (.o output)
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)
-H14m Increase compiler's heap size
+ -M Output the Makefile rules recording the
+ dependencies of a list of Haskell files.
+ (ghc driver script 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}
%* *
%************************************************************************
-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 ProjectVersionInt
- 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);
- }
+HscMajorVersion HscMinorVersion CcMajorVersion CcMinorVersion
- 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);
- }
-}
+TOP_PWD
+
+bindir libdir libexecdir datadir
+
+CURRENT_DIR TMPDIR
+
+GHC_LIB_DIR GHC_RUNTIME_DIR GHC_INCLUDE_DIR
+
+GHC_OPT_HILEV_ASM GhcWithNativeCodeGen
+
+GHC_UNLIT GHC_HSCPP GHC_MKDEPENDHS GHC_HSC GHC_SYSMAN
+
+CP RM CONTEXT_DIFF
+
+WAY_*_NAME WAY_*_REAL_OPTS
+
+LeadingUnderscore
+
+GhcWithRegisterised
+
+\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}";
+#
+# Normally the same as InstLibDirGhc, but we accommodate
+# for it being separate.
+#
+$InstLibExecDirGhc = "${libexecdir}";
+$InstDataDirGhc = "${datadir}";
$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, ''); }
# 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$$");
+ # Try to find a $Tmp_prefix which isn't being used...
+ $tmp = $$;
+ do {
+ $Tmp_prefix = ($ENV{'TMPDIR'} . "/ghc$tmp");
+ $tmp++;
+ } while ( -e "$Tmp_prefix.hc" ||
+ -e "$Tmp_Prefix.s" ||
+ -e "$Tmp_Prefix.hi" );
} 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
+}
+
+# Some shells run into real trouble when command line and environment
+# gets big (e.g., cmd lines of >4K to /bin/sh causes havoc on our
+# Solaris-2.5.1 boxes - even though sysconf(_SC_ARG_MAX) reports 1M ...).
+# To work around any such */bin/sh* problems, we will scribble such
+# awfully long command lines into a temp file and exec that temp file
+# with $(REAL_SHELL) (don't use the SHELL variable directly as this
+# will normally get you the wrong thing when the driver is invoked
+# from within `make'). If the REAL_SHELL variable isn't set, you'll
+# get SHELL. This is all a terrible hack. (in case you hadn't reached
+# the same conclusion by now :-)
+#
+# TBC..
+#
+if ( ! $ENV{'REAL_SHELL'} ) {
+ $ENV{'REAL_SHELL'} = $ENV{'SHELL'};
}
@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 = ();
-$genSPECS_flag = ''; # See ../utils/hscpp/hscpp.prl
+ ( $INSTALLING ) ? "$InstLibExecDirGhc/hscpp"
+ : "$TopPwd/${CURRENT_DIR}/${GHC_HSCPP}";
-$HsP = ( $(INSTALLING) ) ? "$InstLibDirGhc/hsp"
- : "$TopPwd/$(CURRENT_DIR)/$(GHC_HSP)";
-@HsP_flags = ();
+@HsCpp_flags = ();
+$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}
+$Scale_sizes_by = 1.0;
-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
\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_DoSpecialise = '-fspecialise';
-$Oopt_FoldrBuild = 1; # On by default!
-$Oopt_FB_Support = '-fdo-new-occur-anal -fdo-arity-expand';
-#$Oopt_FoldrBuildWW = 0; # Off by default
-$Oopt_FoldrBuildInline = '-fdo-inline-foldr-build';
+sub setupOptFlags {
+ $Oopt_MaxSimplifierIterations = '-fmax-simplifier-iterations4';
+ $Oopt_PedanticBottoms = '-fpedantic-bottoms'; # ON by default
+ $Oopt_FinalStgProfilingMassage = '';
+ $Oopt_StgStats = '';
+ $Oopt_DoSpecialise = '-fspecialise';
+ $Oopt_FoldrBuild = 0; # *Off* by default!
+ $Oopt_UsageSPInf = ''; # Off by default
+} # 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
-@CcBoth_flags = ('-S'); # flags for *any* C compilation
+(added -Wimplicit: implicit prototypes cause very hard-to-find
+problems, so I'm turing on the warnings -- SDM 4/5/98)
+
+\begin{code}
+$CcRegd = $GHC_OPT_HILEV_ASM;
+@CcBoth_flags = ('-S','-Wimplicit'); # 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 = ();
+@CcRegd_flags_c = ();
@CcRegd_flags_hc = ();
-$As = ''; # assembler is normally the same pgm as used for C compilation
-@As_flags = ();
+$As = ''; # "assembler" is normally GCC
+@As_flags = ();
-$Lnkr = ''; # linker is normally the same pgm as used for C compilation
-@Ld_flags = ();
+$Lnkr = ''; # "linker" is normally GCC
+@Ld_flags = ();
+@Dll_flags = ();
# 'nm' is used for consistency checking (ToDo: mk-world-ify)
# ToDo: check the OS or something ("alpha" is surely not the crucial question)
$Nm = ($TargetPlatform =~ /^alpha-/) ? 'nm -B' : 'nm';
\end{code}
+Warning packages that are controlled by -W and -Wall. The 'standard'
+warnings that you get all the time are
+
+ -fwarn-overlapping-patterns
+ -fwarn-missing-methods
+ -fwarn-missing-fields
+ -fwarn-deprecations
+ -fwarn-duplicate-exports
+
+these are turned off by -Wnot.
+
+\begin{code}
+@StandardWarnings = ('-fwarn-overlapping-patterns',
+ '-fwarn-missing-methods',
+ '-fwarn-missing-fields',
+ '-fwarn-deprecations',
+ '-fwarn-duplicate-exports');
+@MinusWOpts = (@StandardWarnings,
+ '-fwarn-unused-binds',
+ '-fwarn-unused-matches',
+ '-fwarn-incomplete-patterns',
+ '-fwarn-unused-imports');
+@MinusWallOpts = (@MinusWOpts,
+ '-fwarn-type-defaults',
+ '-fwarn-name-shadowing',
+ '-fwarn-missing-signatures');
+\end{code}
+
What options \tr{-user-setup-a} turn into (user-defined ``packages''
+
of options). Note that a particular user-setup implies a particular
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',
- '_u', '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', "Profiling",
+ '_t', "Ticky-ticky Profiling",
+ '_u', "Unregisterised",
+ '_s', "SMP",
+ '_mp', "Parallel",
+ '_mg', "Gransim",
+ # 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', '' );
-
-# 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(@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', '' );
+#
+%SetupOpts =
+ (
+ '_a', "$WAY_a_REAL_OPTS",
+ '_b', "$WAY_b_REAL_OPTS",
+ '_c', "$WAY_c_REAL_OPTS",
+ '_d', "$WAY_d_REAL_OPTS",
+ '_e', "$WAY_e_REAL_OPTS",
+ '_f', "$WAY_f_REAL_OPTS",
+ '_g', "$WAY_g_REAL_OPTS",
+ '_h', "$WAY_h_REAL_OPTS",
+ '_i', "$WAY_i_REAL_OPTS",
+ '_j', "$WAY_j_REAL_OPTS",
+ '_k', "$WAY_k_REAL_OPTS",
+ '_l', "$WAY_l_REAL_OPTS",
+ '_m', "$WAY_m_REAL_OPTS",
+ '_n', "$WAY_n_REAL_OPTS",
+ '_o', "$WAY_o_REAL_OPTS",
+ '_A', "$WAY_A_REAL_OPTS",
+ '_B', "$WAY_B_REAL_OPTS",
+
+ # system ways
+ '_p', "-fscc-profiling -DPROFILING -optc-DPROFILING",
+ '_t', "-fticky-ticky -DTICKY_TICKY -optc-DTICKY_TICKY",
+ '_u', "-optc-DNO_REGS -optc-DUSE_MINIINTERPRETER -fno-asm-mangling -funregisterised",
+ '_s', "-fsmp -optc-pthread -optl-pthread -optc-DSMP",
+ '_mp', "-fparallel -D__PARALLEL_HASKELL__ -optc-DPAR",
+ '_mg', "-fgransim -D__GRANSIM__ -optc-DGRAN");
+
+# where to look for interface files (system hi's, i.e., prelude and syslibs)
+@SysImport_dir = ( $INSTALLING )
+ ? ( "$InstLibDirGhc/imports/std" )
+ : ( "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/std" );
+
+# 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.
+
+$Haskell1Version = 5; # i.e., Haskell 1.4
+@Cpp_define = ();
+
+# Cpp symbols defined when we're processing Haskell source.
+
+@HsSourceCppOpts =
+ ( "-D__HASKELL__=98"
+ , "-D__HASKELL1__=$Haskell1Version"
+ , "-D__GLASGOW_HASKELL__=$ProjectVersionInt"
+ , "-D__HASKELL98__"
+ , "-D__CONCURRENT_HASKELL__"
+ );
+
+
+@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/std"
+ , "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/std/cbits"
+ )
+ );
+
+# make depend for Haskell
+$MkDependHS
+ = ( $INSTALLING ) ? "$InstLibExecDirGhc/mkdependHS"
+ : "$TopPwd/$CURRENT_DIR/$GHC_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 = ();
+@HsC_flags = ();
+@HsC_antiflags = ();
\end{code}
-Import/include directories (\tr{-I} options) are sufficiently weird to
-require special handling.
+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 = '';
+$USPLint = '';
+$StgLint = '';
+
+# The SplitMarker is the string/character used to mark end of element
+# in import lists.
+$SplitMarker = ':';
@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"
- );
-
-$ghc_version_info = $(PROJECTVERSION) * 100;
-$haskell1_version = 2; # i.e., Haskell 1.2
-@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 = ( '-lHS' ); # basic I/O and prelude stuff
-
-$TopClosureFile # defaults to 1.2 one; will be mangled later
- = ( $(INSTALLING) ) ? "$InstLibDirGhc/TopClosureXXXX.o"
- : "$TopPwd/$(CURRENT_DIR)/$(GHC_RUNTIMESRC)/main/TopClosureXXXX.o";
+@SysLibrary = (); # will be built up as we go along
\end{code}
We are given a list of files with various presumably-known suffixes
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_preprocess_hc = 0; # ditto
+$Only_generate_deps = 0; # ""
+$Only_generate_dll = 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;
+
+# Win32 only:
+# static = 0 => produce code for DLLs (when compiling & linking.)
+$Static = 1;
+$Static = 0 if ($EnableWin32DLLs eq 'YES');
+
+# Output language
+$HaveNativeCodeGen = $GhcWithNativeCodeGen;
+$HscLang = 'C'; # 'C' ==> .hc output;
+ # 'asm' ==> .s output;
+ # 'java' ==> .java output
+ # 'none' ==> no code output
+$HscLang = 'asm'
+ if ($HaveNativeCodeGen eq 'YES') && $TargetPlatform =~ /^(i386)-/;
+
+$ProduceHi = '-hifile=';
+$HiOnStdout = 0;
+$HiWith = '';
+$HiDiff_flag = '';
+$Keep_HiDiffs = 0;
$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
+$PROFdict = ''; # set to relevant hsc flag if -auto-dicts
$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
+$UNREGing = ($GhcWithRegisterised eq 'YES') ? '' : 'u';
$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 = '';
+$CompilingPrelude=0;
+$Do_recomp_chkr = 1; # Use the recompilation checker by default
$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;
+$DoAsmMangling = 1; # on by default, off by -fno-asm-mangling
$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;
+# 1 => don't tell the linker to hoist in PrelMain.Main, as an
+# external main is provided instead.
+$NoHaskellMain=0;
+
+} # end of initDriverGlobals (Sigh)
-# and the list of files
+# we split the argv passed to the driver into three:
+
+# the list of files
@Input_file = ();
# and files to be linked...
@Link_file = ();
+
+# and whatever else
+@Cmd_opts = ();
+
+# cmd line options prefixing the unit we're compiling
+@File_options = ();
+
\end{code}
We inject consistency-checking information into \tr{.hc} files (both
\tr{what(1)}-style strings. Anyway, here are the relevant global
variables and their defaults:
\begin{code}
-$LinkChk = 1; # set to 0 if the link check should *not* be done
+$LinkChk = 0; # 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_minor_version = 0;
-$Cc_major_version = 33;
-$Cc_minor_version = 0;
+$HsC_major_version = $HscMajorVersion;
+$HsC_minor_version = $HscMinorVersion;
+$Cc_major_version = $CcMajorVersion;
+$Cc_minor_version = $CcMinorVersion;
# 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}
%************************************************************************
Now slurp through the arguments.
\begin{code}
-#---------- user defined prelude ---------------------------------------
-
-if (grep(/^-user-prelude$/, @ARGV)) {
-
- # If ARGV contains -user-prelude we are compiling a piece of
- # prelude for the user, probably with additional specialise pragmas
+&initDriverGlobals();
+&splitCmdLine(@ARGV);
+# Run through the cmd-line first time.
+&processArgs(@Cmd_opts);
+
+# Check to see if driver is only in the business
+# to generate dependencies
+if ( $Status == 0 && $Only_generate_deps ) {
+
+ push (@MkDependHS_flags, "-o$Osuffix") if $Osuffix;
+ # They're not (currently) needed, but we need to quote any -#include options
+ foreach (@Cmd_opts) {
+ s/-#include.*$/'$&'/g;
+ };
+ local($to_do) = "$MkDependHS @MkDependHS_flags @HsSourceCppOpts -- @Cmd_opts -- @Input_file" ;
+ &run_something($to_do, 'Haskell dependencies');
+ exit $Status;
+}
- # 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
+# ..or just to construct a (Haskell) DLL.
+if ( $Status == 0 && $Only_generate_dll && $EnableWin32DLLs ) {
- # We also enable any options forced through with -user-prelude-force
+ &createWin32DLL();
+ exit $Status;
+}
- # Hey, Check out this grep statement ;-) (PS)
+# if there are several input files,
+# we don't allow \tr{-o <file>} or \tr{-ohi <file>} options...
+# (except if linking, of course)
- @ARGV = grep((!/^-O/ && !/^-f/ && !/^-user-prelude$/) || s/^-user-prelude-force//,
- @ARGV);
+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++;
+ }
+}
- unshift(@ARGV,
- '-prelude',
- '-O',
- '-fshow-pragma-name-errs',
- '-fshow-import-specs',
- '-fomit-reexported-instances',
- '-fglasgow-exts',
- '-genSPECS',
- '-DUSE_FOLDR_BUILD',
- '-dcore-lint');
+# 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
+ }
+}
- print STDERR "ghc: -user-prelude options:\n", "@ARGV", "\n";
+# crash and burn if there were errors
+if ( $Status > 0 ) {
+ print STDERR $ShortUsage;
+ exit $Status;
}
+\end{code}
-# can't use getopt(s); what we want is too complicated
-arg: while($_ = $ARGV[0]) {
- shift(@ARGV);
+%************************************************************************
+%* *
+\section[Driver-post-argv-mangling]{Setup after reading options}
+%* *
+%************************************************************************
- #---------- help -------------------------------------------------------
- if (/^-\?$/ || /^-help$/) { print $LongUsage; exit $Status; }
+%************************************************************************
+%* *
+\subsection{Set up for optimisation level (\tr{-O} or whatever)}
+%* *
+%************************************************************************
- #---------- verbosity and such -----------------------------------------
- /^-v$/ && do { $Verbose = '-v'; $Time = 'time'; next arg; };
+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).
- #---------- 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]
+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...).
- /^-hi$/ && do { $ProduceHi = 2; next arg; };
- # _do_ generate an interface; usually used as: -noC -hi
- # NB: magic value "2" for $ProduceHi (hack)
+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.
- /^-nohi$/ && do { $ProduceHi = 0; next arg; };
- # don't generate an interface (even if generating C)
+Sadly, however, there are some interdependencies \& Things You Must
+Not Do. Here is the list.
- /^-hi-diffs$/ && do { $HiDiff_flag = 1; next arg; };
- /^-no-hi-diffs$/ && do { $HiDiff_flag = 0; next arg; };
- # show/disable diffs if the interface file changes
+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...)
- /^-E$/ && do { push(@CcBoth_flags, '-E');
- $Only_preprocess_C = 1;
- $Do_as = 0; $Do_lnkr = 0; next arg; };
- # stop after preprocessing C
+\item[\tr{-ffloat-inwards}:]
+Floating inwards should be done before strictness analysis, because
+the latter will give better results.
- /^-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
+\item[\tr{-fstatic-args}:]
+The static-arguments-transformation pass {\em must} have the
+simplifier run right after it.
- # 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
+\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.)
- #---------- redirect output --------------------------------------------
+\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}
- # -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
+\begin{code}
- /^-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; };
+sub setupOptimiseFlags {
- # -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; };
+ # this pass-ordering sequence was agreed by Simon and Andr\'e
+ # (WDP 94/07, 94/11).
- /^-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; };
+ @HsC_minusNoO_flags
+ = (
+ '-fsimplify',
+ '[',
+ $Oopt_MaxSimplifierIterations,
+ ']',
- /^-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; };
+ $Oopt_AddAutoSccs,
+ $Oopt_FinalStgProfilingMassage
+ );
- /^-osuf$/ && do { $Osuffix = &grab_arg_arg('-osuf', ''); next arg; };
- /^-hisuf$/ && do { $HiSuffix = &grab_arg_arg('-hisuf', '');
- push(@HsP_flags, "-h$HiSuffix");
- next arg; };
+ @HsC_minusO_flags # NOTE: used for *both* -O and -O2 (some conditional bits)
+ = (
+ '-ffoldr-build-on',
- /^-hisuf-prelude$/ && do { # as esoteric as they come...
- local($suffix) = &grab_arg_arg('-hisuf-prelude', '');
- push(@HsP_flags, "-g$suffix");
- next arg; };
+ '-fdo-eta-reduction',
+ '-fdo-lambda-eta-expansion',
+ '-fcase-of-case',
+ '-fcase-merge',
+ '-flet-to-case',
+ $Oopt_PedanticBottoms,
- #-------------- scc & Profiling Stuff ----------------------------------
+ # initial simplify: mk specialiser happy: minimum effort please
- /^-prof$/ && do { $PROFing = 'p'; next arg; }; # profiling -- details later!
+ '-fsimplify',
+ '[',
+ '-finline-phase0', # Don't inline anything till full laziness has bitten
+ # In particular, inlining wrappers inhibits floating
+ # e.g. ...(case f x of ...)...
+ # ==> ...(case (case x of I# x# -> fw x#) of ...)...
+ # ==> ...(case x of I# x# -> case fw x# of ...)...
+ # and now the redex (f x) isn't floatable any more
+
+ '-fno-rules', # Similarly, don't apply any rules until after full laziness
+ # Notably, list fusion can prevent floating.
+
+ '-fno-case-of-case', # Don't do case-of-case transformations.
+ # This makes full laziness work better
+
+ '-fmax-simplifier-iterations2',
+ ']',
+
+ # Specialisation is best done before full laziness
+ # so that overloaded functions have all their dictionary lambdas manifest
+ ($Oopt_DoSpecialise) ? ( $Oopt_DoSpecialise, ) : (),
+ '-ffloat-outwards',
+ '-ffloat-inwards',
- /^-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; };
+ '-fsimplify',
+ '[',
+ '-finline-phase1',
+ # Want to run with inline phase 1 after the specialiser to give
+ # maximum chance for fusion to work before we inline build/augment
+ # in phase 2. This made a difference in 'ansi' where an overloaded
+ # function wasn't inlined till too late.
+ $Oopt_MaxSimplifierIterations,
+ ']',
+
+ $Oopt_UsageSPInf, # infer usage information here in case we need it later.
+ # (add more of these where you need them --KSW 1999-04)
- /^-caf-all/ && do { # generate individual CAF SCC annotations
- $PROFcaf = '-fauto-sccs-on-individual-cafs';
- next arg; };
+ '-fsimplify',
+ '[',
+ # Need inline-phase2 here so that build/augment get
+ # inlined. I found that spectral/hartel/genfft lost some useful
+ # strictness in the function sumcode' if augment is not inlined
+ # before strictness analysis runs
-# UNUSED:
-# /^-dict-all/ && do { # generate individual SCC annotations on dictionaries
-# $PROFdict = '-fauto-sccs-on-individual-dicts';
-# next arg; };
+ '-finline-phase2',
+ '-fmax-simplifier-iterations2',
+ ']',
- /^-ignore-scc$/ && do {
- # forces ignore of scc annotations even if profiling
- $PROFignore_scc = '-W';
- next arg; };
- /^-G(.*)$/ && do { push(@HsC_flags, $_); # set group for cost centres
- next arg; };
+ '-fsimplify',
+ '[',
+ '-fmax-simplifier-iterations2',
+ # No -finline-phase: allow all Ids to be inlined now
+ # This gets foldr inlined before strictness analysis
+ ']',
- #--------- ticky/concurrent/parallel -----------------------------------
- # we sort out the details a bit later on
+ '-fstrictness',
+ '-fcpr-analyse',
+ '-fworker-wrapper',
- /^-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
+ '-fsimplify',
+ '[',
+ $Oopt_MaxSimplifierIterations,
+ # No -finline-phase: allow all Ids to be inlined now
+ ']',
+
+ '-ffloat-outwards', # nofib/spectral/hartel/wang doubles in speed if you
+ # do full laziness late in the day. It only happens
+ # after fusion and other stuff, so the early pass doesn't
+ # catch it. For the record, the redex is
+ # f_el22 (f_el21 r_midblock)
+
+# Leave out lambda lifting for now
+# '-fsimplify', # Tidy up results of full laziness
+# '[',
+# '-fmax-simplifier-iterations2',
+# ']',
+# '-ffloat-outwards-full',
+
+ # We want CSE to follow the final full-laziness pass, because it may
+ # succeed in commoning up things floated out by full laziness.
+ #
+ # CSE must immediately follow a simplification pass, because it relies
+ # on the no-shadowing invariant. See comments at the top of CSE.lhs
+ # So it must NOT follow float-inwards, which can give rise to shadowing,
+ # even if its input doesn't have shadows. Hence putting it between
+ # the two passes.
+ '-fcse',
+
- #-------------- "user ways" --------------------------------------------
+ '-ffloat-inwards',
- (/^-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"; };
+# Case-liberation for -O2. This should be after
+# strictness analysis and the simplification which follows it.
- /^$(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'; };
+# ( ($OptLevel != 2)
+# ? ''
+# : "-fliberate-case -fsimplify [ $Oopt_FB_Support -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fcase-merge -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MaxSimplifierIterations $Oopt_ShowSimplifierProgress ]" ),
- 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;
+# '-fliberate-case',
- next arg; };
+# Final clean-up simplification:
- #---------- set search paths for libraries and things ------------------
+ '-fsimplify',
+ '[',
+ $Oopt_MaxSimplifierIterations,
+ # No -finline-phase: allow all Ids to be inlined now
+ ']',
- # 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.
+ # '-fstatic-args',
- /^-i$/ && do { @Import_dir = (); # import path cleared!
- @SysImport_dir = ();
- print STDERR "WARNING: import paths cleared by `-i'\n";
- next arg; };
+ # stg2stg passes
+# '-flambda-lift',
+ $Oopt_FinalStgProfilingMassage,
+ $Oopt_StgStats,
- /^-i(.*)/ && do { local(@new_items)
- = split( /:/, &grab_arg_arg('-i', $1));
- unshift(@Import_dir, @new_items);
- next arg; };
+ # flags for stg2stg
+ '-flet-no-escape',
- /^-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; };
+ # SPECIAL FLAGS for -O2
+ ($OptLevel == 2) ? (
+ # none at the present time
+ ) : (),
+ );
- /^-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)$/;
+\end{code}
- unshift(@SysImport_dir,
- $(INSTALLING)
- ? "$InstDataDirGhc/imports/$syslib"
- : "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/$syslib");
+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 ) {
- unshift(@SysLibrary, ('-lHS' . $syslib ));
+ # 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');
- next arg; };
+ &add_Hsc_flags( @HsC_minusNoO_flags );
+ push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O'); # not optional!
- #=======================================================================
- # 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)
- #=======================================================================
+} elsif ( $OptLevel == 1 || $OptLevel == 2 ) {
- #---------- 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; };
+ &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 collector.
- #---------- 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; };
+} else { # -Ofile, then...
- #---------- 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; };
+ &add_Hsc_flags( @HsC_minusO3_flags );
+ push(@HsC_flags, $Oopt_FinalStgProfilingMassage) if $Oopt_FinalStgProfilingMassage;
- /^-genSPECS/ && do { $Cpp_flag_set = 1;
- $genSPECS_flag = $_;
- next arg; };
+ push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O'); # possibly to be elaborated...
+}
- #---------- Haskell parser (hsp) ---------------------------------------
- /^-ddump-parser$/ && do { $Dump_parser_output = 1; next arg; };
+} # setupOptimiseFlags
- #---------- 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; };
+\end{code}
- /^-ddump-asm-splitting-info$/ && do { $Dump_asm_splitting_info = 1; next arg; };
+%************************************************************************
+%* *
+\subsection{Check for consistency, etc.}
+%* *
+%************************************************************************
- #---------- Haskell compiler (hsc) -------------------------------------
+Sort out @$BuildTag@, @$PROFing@, @$PARing@,
+@$GRANing@, @$TICKYing@, @UNREGing@:
+\begin{code}
+sub setupBuildFlags {
+
+ # PROFILING stuff after argv mangling:
+ if ( ! $PROFing ) {
+ # 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';
+
+ # Ignore user sccs when auto annotating, but warn when doing so.
+ $PROFignore_scc = '-W' if $PROFauto;
+ }
+ #if ( $BuildTag ne '' ) {
+ # local($b) = $BuildDescr{$BuildTag};
+ # 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 = '_p' ;
+
+ } 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 ( $SMPing eq 's') {
+ $BuildTag = '_s';
+
+ } 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';
+
+ } elsif ( $UNREGing eq 'u' ) {
+ if ($GhcWithRegisterised eq 'YES') {
+ $BuildTag = '_u';
+ }
+ }
+\end{code}
-# 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; };
+After the sanity checks, add flags to the necessary parts of the driver pipeline:
- /^-keep-hc-files?-too$/ && do { $Keep_hc_file_too = 1; next arg; };
- /^-keep-s-files?-too$/ && do { $Keep_s_file_too = 1; next arg; };
+\begin{code}
+ if ( $BuildTag ne '' ) { # something other than normal sequential...
- /^-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");
+ local($Tag) = "${BuildTag}";
+ $Tag =~ s/_//; # move the underscore to the back
- unshift(@SysLibrary, '-lHS13');
+ $HscLang = 'C'; # must go via C
+ &processArgs(split(' ', $SetupOpts{$BuildTag}));
+# eval($EvaldSetupOpts{$BuildTag});
+ }
+\end{code}
- next arg; };
+Decide what the consistency-checking options are in force for this run:
+\begin{code}
- /^-fno-implicit-prelude$/ && do { push(@HsP_flags, '-P'); next arg; };
- /^-fignore-interface-pragmas$/ && do { push(@HsP_flags, '-p'); next arg; };
+ $HsC_consist_options = "${BuildTag},${DEBUGging}";
+ $Cc_consist_options = "${BuildTag},${DEBUGging}";
+
+ #
+ # Funny place to put it, but why not.
+ #
+ if ( $HiSuffix_prelude eq '' ) {
+
+ if ($CompilingPrelude) {
+ $HiSuffix_prelude = "$HiSuffix" if $CompilingPrelude;
+ } else {
+ local($Tag) = "${BuildTag}";
+
+ $Tag =~ s/_//;
+ $Tag = "${Tag}_" if $Tag ne '';
+ $HiSuffix_prelude="${Tag}hi";
+ }
+ }
+} # setupBuildFlags
+\end{code}
- /^-prelude$/ && do { $CompilingPrelude = 1;
- push(@HsC_flags, $_); next arg; };
+%************************************************************************
+%* *
+\subsection{Add on machine-specific C-compiler flags}
+%* *
+%************************************************************************
- /^-user-prelude-force/ && do { # ignore if not -user-prelude
- 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__}).
- /^-split-objs(.*)/ && do {
- local($sname) = &grab_arg_arg('-split-objs', $1);
- $sname =~ s/ //g; # no spaces
+Note: a few ``always apply'' flags were set at the very beginning.
- if ( $TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/ ) {
- $SplitObjFiles = 1;
- $ProduceS = '';
- $ProduceC = 1;
+\begin{code}
+sub setupMachOpts {
+
+ if ($TargetPlatform =~ /^alpha-/) {
+ unshift(@CcBoth_flags, ('-static'));
+
+ } elsif ($TargetPlatform =~ /^hppa/) {
+ 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.)
- push(@HsC_flags, "-fglobalise-toplev-names$sname");
- push(@CcBoth_flags, '-DUSE_SPLIT_MARKERS');
+ } elsif ($TargetPlatform =~ /^i386-/) {
+ # -fno-defer-pop : basically the same game as for m68k
+ #
+ # -fomit-frame-pointer : *must* in .hc files; because we're stealing
+ # the fp (%ebp) for our register maps.
+
+ unshift(@CcRegd_flags_hc, '-fno-defer-pop');
+ unshift(@CcRegd_flags_hc, '-fomit-frame-pointer');
+ unshift(@CcRegd_flags, "-DSTOLEN_X86_REGS=$StolenX86Regs");
+
+ unshift(@CcBoth_flags, ('-DDONT_WANT_WIN32_DLL_SUPPORT')) if ($Static);
+
+ } elsif ($TargetPlatform =~ /^m68k-/) {
+ # -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
- 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; };
+ } elsif ($TargetPlatform =~ /^mips-/) {
+ unshift(@CcBoth_flags, ('-static'));
- /^-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');
+ } elsif ($TargetPlatform =~ /^powerpc-|^rs6000-/) {
+ unshift(@CcBoth_flags, ('-static')); # always easier to start with
+ unshift(@CcRegd_flags, ('-finhibit-size-directive')); # avoids traceback tables
+ } elsif ($TargetPlatform =~ /^sparc-/) {
+ }
+} # end of setupMachOpts
+\end{code}
-# push(@HsC_flags, '-fshow-import-specs');
+%************************************************************************
+%* *
+\subsection{Set up for warnings}
+%* *
+%************************************************************************
- if ( ! $(INSTALLING) ) {
- unshift(@SysImport_dir,
- "$TopPwd/$(CURRENT_DIR)/$(GHC_LIBSRC)/glaExts");
- }
- next arg; };
+Several warnings are turned on by default. These are supposed to be
+the 'I'm pretty sure you've made a mistake here' kind of warnings.
+The rest are turned on by the -W and -Wall options, or individually
+via their -fwarn and -fno-warn flags.
- /^-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; };
+\begin{code}
+sub setupWarningFlags {
+&add_Hsc_flags( @StandardWarnings );
+}
+\end{code}
+Same unshifting magic, but for special linker flags.
-# Now the foldr/build options, which are *on* by default (for -O).
+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).
- /^-ffoldr-build$/
- && do { $Oopt_FoldrBuild = 1;
- $Oopt_FB_Support = '-fdo-new-occur-anal -fdo-arity-expand';
- #print "Yes F/B\n";
- next arg; };
+\begin{code}
+sub setupLinkOpts {
+ local($uscore) = ( ${LeadingUnderscore} eq 'YES' ) ? '_' : '';
+
+ unshift(@Ld_flags,
+ (($Ld_main) ? ( '-u', "${uscore}Main_" . $Ld_main . '_closure' ) : ()));
+
+ # things that are referenced by the RTS - make sure that we pull 'em in
+ unshift(@Ld_flags,
+ ( '-u', "${uscore}PrelBase_Izh_static_info"
+ ,'-u', "${uscore}PrelBase_Czh_static_info"
+ ,'-u', "${uscore}PrelFloat_Fzh_static_info"
+ ,'-u', "${uscore}PrelFloat_Dzh_static_info"
+ ,'-u', "${uscore}PrelAddr_Azh_static_info"
+ ,'-u', "${uscore}PrelAddr_Wzh_static_info"
+ ,'-u', "${uscore}PrelAddr_I64zh_static_info"
+ ,'-u', "${uscore}PrelAddr_W64zh_static_info"
+ ,'-u', "${uscore}PrelStable_StablePtr_static_info"
+ ,'-u', "${uscore}PrelBase_Izh_con_info"
+ ,'-u', "${uscore}PrelBase_Czh_con_info"
+ ,'-u', "${uscore}PrelFloat_Fzh_con_info"
+ ,'-u', "${uscore}PrelFloat_Dzh_con_info"
+ ,'-u', "${uscore}PrelAddr_Azh_con_info"
+ ,'-u', "${uscore}PrelAddr_Wzh_con_info"
+ ,'-u', "${uscore}PrelAddr_I64zh_con_info"
+ ,'-u', "${uscore}PrelAddr_W64zh_con_info"
+ ,'-u', "${uscore}PrelStable_StablePtr_con_info"
+ ,'-u', "${uscore}PrelBase_False_closure"
+ ,'-u', "${uscore}PrelBase_True_closure"
+ ,'-u', "${uscore}PrelPack_unpackCString_closure"
+ ,'-u', "${uscore}PrelException_stackOverflow_closure"
+ ,'-u', "${uscore}PrelException_heapOverflow_closure"
+ ,'-u', "${uscore}PrelException_NonTermination_closure"
+ ,'-u', "${uscore}PrelException_PutFullMVar_closure"
+ ,'-u', "${uscore}PrelException_BlockedOnDeadMVar_closure"
+ ,'-u', "${uscore}__init_Prelude"
+ ,'-u', "${uscore}__init_PrelMain"
+ ));
+ if (!$NoHaskellMain) {
+ unshift (@Ld_flags,'-u', "${uscore}PrelMain_mainIO_closure");
+ }
+ if ($TargetPlatform =~ /^powerpc-|^rs6000-/) {
+ # sometimes we have lots of toc entries...
+ # unshift(@Ld_flags, ('-Xlinker -bbigtoc -Xlinker -bnoquiet'));
+ unshift(@Ld_flags, ('-Xlinker -bbigtoc'));
+ }
+ if ($TargetPlatform =~ /^hppa/) {
+ unshift(@Ld_flags, ('-Xlinker +vnocompatwarnings'));
+ }
+
+} # end of setupLinkOpts
- /^-fno-foldr-build$/
- && do { $Oopt_FoldrBuild = 0;
- $Oopt_FB_Support = '';
- next arg; };
+\end{code}
- /^-fno-foldr-build-rule$/
- && do { $Oopt_FoldrBuild = 0;
- next arg; };
+%************************************************************************
+%* *
+\subsection{Set up include paths and system-library enslurpment}
+%* *
+%************************************************************************
- /^-fno-enable-tech$/
- && do { $Oopt_FB_Support = '';
- 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.
- /^-fno-snapback-to-append$/
- && do { $Oopt_FoldrBuildInline .= ' -fdo-not-fold-back-append ';
- #print "No Foldback of append\n";
- 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");
+ }
+} # end of setupIncPaths
+\end{code}
-# /^-ffoldr-build-ww$/
-# && do { $Oopt_FoldrBuildWW = 1; next arg; };
+\begin{code}
+sub setupSyslibs {
+ push(@SysLibrary, ( '-lHSstd', '-lHSstd_cbits' )); # basic I/O and prelude stuff
+
+ local($f);
+ foreach $f (@SysLibrary) {
+ next if $f =~ /_cbits/;
+ $f .= $BuildTag if $f =~ /^-lHS/;
+ }
+
+ # Push library HSrts, plus boring clib bit
+ push(@SysLibrary, "-lHSrts${BuildTag}");
+
+ #
+ # 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 ($TargetPlatform =~ /-(mingw32|cygwin32)$/);
+ # Note: currently only tested with mingw, may cause conflicts when linking
+ # with libcygwin.a
+ push(@SysLibrary, '-lwsock32') if ($TargetPlatform =~ /-(mingw32|cygwin32)$/);
+
+ # Push the pvm libraries
+ if ($BuildTag eq '_mp') {
+ $pvmlib = "$ENV{'PVM_ROOT'}/lib/$ENV{'PVM_ARCH'}";
+ push(@SysLibrary, "-L$pvmlib", '-lgpvm3', '-lpvm3');
+ if ( $ENV{'PVM_ARCH'} eq 'SUNMP' ) {
+ push(@SysLibrary, '-lthread', '-lsocket', '-lnsl');
+ } elsif ( $ENV{'PVM_ARCH'} eq 'SUN4SOL2' ) {
+ push(@SysLibrary, '-lsocket', '-lnsl');
+ }
+ }
+# Push the GNU multi-precision arith lib; and the math library
- /^-fasm-(.*)$/ && do { $ProduceS = $1; $ProduceC = 0; # force using nativeGen
- push(@HsC_flags, $_); # if from the command line
- next arg; };
+# If this machine has GMP already installed, then we'll get the installed
+# lib here, because presumably the one in the tree won't have been built.
- /^-fvia-C$/ && do { $ProduceS = ''; $ProduceC = 1; # force using C compiler
- next arg; };
+if ($LibGmp eq 'not-installed') {
+ push(@SysLibrary, "-lgmp");
+} else {
+ push(@SysLibrary, "-l$LibGmp");
+}
- /^-f(no-)?omit-frame-pointer$/ && do {
- unshift(@CcBoth_flags, ( $_ ));
- next arg; };
+push(@SysLibrary, '-lm') if !( $TargetPlatform =~ /^.*(cygwin32|mingw32)$/ );
+\end{code}
- # ---------------
+%************************************************************************
+%* *
+\subsection{Check that this system was built to do what we are asking}
+%* *
+%************************************************************************
- /^(-fsimpl-uf-use-threshold)(.*)$/
- && do { $Oopt_UnfoldingUseThreshold = $1 . &grab_arg_arg($1, $2);
- next arg; };
+Before continuing we check that the appropriate build is available.
- /^(-fmax-simplifier-iterations)(.*)$/
- && do { $Oopt_MaxSimplifierIterations = $1 . &grab_arg_arg($1, $2);
- next arg; };
+\begin{code}
+#die "$Pgm: no BuildAvail?? $BuildTag\n" if $BuildDescr{$BuildTag} eq '' ; # sanity
- /^-fno-pedantic-bottoms$/
- && do { $Oopt_PedanticBottoms = ''; 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;
+}
- /^-fdo-monad-eta-expansion$/
- && do { $Oopt_MonadEtaExpansion = $_; next arg; };
+} # end of setupSyslibs
- /^-fno-let-from-(case|app|strict-let)$/ # experimental, really (WDP 95/10)
- && do { push(@HsC_flags, $_); next arg; };
+\end{code}
- /^(-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; };
+%************************************************************************
+%* *
+\subsection{Final miscellaneous setup bits before we start going}
+%* *
+%************************************************************************
-# /^-flambda-lift$/ # so Simon can do some testing; ToDo:rm
-# && do { $Oopt_LambdaLift = $_; 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}
- # ---------------
+If no input or link files seen, then we let 'em feed in stdin; this is
+mainly for debugging.
- /^-fno-(.*)$/ && do { push(@HsC_antiflags, "-f$1");
- &squashHscFlag("-f$1");
- next arg; };
+\begin{code}
- /^-f/ && do { push(@HsC_flags, $_); next arg; };
+if ($#Input_file < 0 && $#Link_file < 0) {
+ @Input_file = ( '-' );
- # ---------------
+ 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" if -t;
+ while (<STDIN>) { print INF $_; }
+ close(INF) || &tidy_up_and_die(1,"Failed writing to $Tmp_prefix.hs\n");
+}
- /^-mlong-calls$/ && do { # for GCC for HP-PA boxes
- unshift(@CcBoth_flags, ( $_ ));
- next arg; };
+\end{code}
- /^-m(v8|sparclite|cypress|supersparc|cpu=(cypress|supersparc))$/
- && do { # for GCC for SPARCs
- unshift(@CcBoth_flags, ( $_ ));
- next arg; };
+Tell the world who we are, if they asked.
+\begin{code}
+print STDERR "${ProjectName}, version ${ProjectVersion}\n" if $Verbose;
+\end{code}
- /^-monly-([432])-regs/ && do { # for iX86 boxes only; no effect otherwise
- $StolenX86Regs = $1;
- next arg; };
+%************************************************************************
+%* *
+\section[Driver-main-loop]{Main loop: Process input files, and link if required}
+%* *
+%************************************************************************
- /^-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; };
+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);
+}
- #*************** ... and lots of debugging ones (form: -d* )
+# don't link if there were errors...
+if ( $Status > 0 ) {
+ print STDERR $ShortUsage;
+ &tidy_up();
+ exit $Status;
+}
- /^-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; };
+# Link if appropriate.
+&runLinker() if $Do_lnkr;
- # -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; };
+# that... that's all, folks!
+&tidy_up();
+exit $Status; # will still be 0 if all went well
+\end{code}
- /^-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; };
- /^-dsource-stats/ && do { push(@HsC_flags, $_); next arg; };
- /^-dsimplifier-stats/ && do { push(@HsC_flags, $_); next arg; };
- /^-dstg-stats/ && do { $Oopt_StgStats = $_; next arg; };
+%************************************************************************
+%* *
+\section[Driver-do-one-file]{How to process a single input file}
+%* *
+%************************************************************************
- #*************** ... and now all these -R* ones for its runtime system...
+\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)
+ local($ofile_c_stub_target);
+ local($ofile_h_stub_target);
+\end{code}
- /^-Rhbc$/ && do { $RTS_style = 'hbc'; next arg; };
- /^-Rghc$/ && do { $RTS_style = 'ghc'; next arg; };
+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 (??)
+ ($ofile_c_stub_target = $ifile) =~s/\.[^\.\/]+$/_stub.c/;
+ ($ofile_h_stub_target = $ifile) =~s/\.[^\.\/]+$/_stub.h/;
+ } 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}
- /^-Rscale-sizes?(.*)/ && do {
- $Scale_sizes_by = &grab_arg_arg('-Rscale-sizes', $1);
- next arg; };
+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.)
- /^(-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; };
+We do the pre-recompilation-checker phases here; the rest later.
+\begin{code}
+\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; };
+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.
- /^-Rgc-stats$/ && do { $CollectingGCstats++;
- # the two RTSs do this diff ways; we will try to compensate
- next arg; };
+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;
- /^-Rghc-timing/ && do { $CollectGhcTimings = 1; next arg; };
+ # 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;
- #---------- 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; };
+ local($is_hc_file) = 1; #Is the C code .hc or .c? Assume .hc for now
- /^-(Wall|ansi|pedantic)$/ && do { push(@CcBoth_flags, $_); next arg; };
+ # OK, let's strip off some literate junk..
+ if ($do_lit2pgm) {
+ &runLit2pgm($in_lit2pgm, $lit2pgm_hscpp)
+ } else {
+ $lit2pgm_hscpp = $ifile;
+ }
- # -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
+ #
+ @File_options = ();
- # inject "#include <wurble>" into the compiler's C output!
+ # Scan the top of the de-litted file for {-# OPTIONS #-} pragmas
+ &check_for_source_options($lit2pgm_hscpp,$ifile);
- /^-#include(.*)/ && do {
- local($to_include) = &grab_arg_arg('-#include', $1);
- push(@CcInjects, "#include $to_include\n");
- next arg; };
+ # 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);
+
+ # Now process the command line
+ &initDriverGlobals();
+ &processArgs((@File_options,@Cmd_opts));
+ print STDERR "\nEffective command line: " .
+ join(' ',(@File_options,@Cmd_opts)) . "\n" if $Verbose;
+ }
+ #
+ # 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();
+ &setupWarningFlags();
+ &setupHeapStackSize();
- #---------- Linker (gcc, really) ---------------------------------------
+ #
+ # 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
+ : ( ($HscLang eq 'C') ? 1 : 0 );
+ local($do_as) = $Do_as;
- /^-static$/ && do { push(@Ld_flags, $_); next arg; };
+ local($hsc_out_suffix) = ( $HscLang eq 'C' ) ? "hc" :
+ ( $HscLang eq 'asm' ) ? "s" :
+ ( $HscLang eq 'java' ) ? "java" :
+ "" ;
+
+ local($hsc_out) = "$Tmp_prefix.$hsc_out_suffix" ;
+ local($hsc_out_c_stub) = "${Tmp_prefix}_stb.c";
+ local($hsc_out_h_stub) = "${Tmp_prefix}_stb.h";
- #---------- mixed cc and linker magic ----------------------------------
- # this optimisation stuff is finally sorted out later on...
+ if ($Only_preprocess_hc) { # stop after having run $Cc -E
+ $do_as=0;
+ }
+ if ($Only_preprocess_C) { # stop after having run $hscpp
+ $do_hsc=0; $do_cc = 0; $do_as=0;
+ } elsif ($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;
+ $hsc_out_c_stub = '';
+ $hsc_out_h_stub = '';
+ } elsif ($ifile =~ /\.c$/) {
+ $do_hscpp = 0; $do_hsc = 0; $do_cc = 1;
+ $hsc_out = $ifile; $is_hc_file = 0;
+ $hsc_out_c_stub = '';
+ $hsc_out_h_stub = '';
+ } elsif ($ifile =~ /\.[sS]$/) {
+ $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;
+ }
-# /^-O0$/ && do { # turn all optimisation *OFF*
-# $OptLevel = -1;
-# $ProduceS = ''; $ProduceC = 1; # force use of C compiler
-# next arg; };
+ # hack to avoid running hscpp
+ $HsCpp = $Cat if ! $Cpp_flag_set;
- /^-O2-for-C$/ && do { $MinusO2ForC = 1; next arg; };
+ &runHscpp($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc) if $do_hscpp;
- /^-O[1-2]?$/ && do {
- local($opt_lev) = ( /^-O2$/ ) ? 2 : 1; # max 'em
- $OptLevel = ( $opt_lev > $OptLevel ) ? $opt_lev : $OptLevel;
+\end{code}
- if ( $OptLevel == 2 ) { # force use of C compiler
- $ProduceS = ''; $ProduceC = 1;
- }
- next arg; };
+We now think about whether to run hsc/cc or not (when hsc produces .s
+stuff, it effectively takes the place of both phases).
+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>"@.
- /^-Onot$/ && do { $OptLevel = 0; next arg; }; # # set it to <no opt>
+\begin{code}
+ local($going_interactive) = $HscLang eq 'none' || $ifile_root eq '_stdin';
- /^-Ofile(.*)/ && do {
- $OptLevel = 3;
- local($ofile) = &grab_arg_arg('-Ofile', $1);
- @HsC_minusO3_flags = ();
+ #
+ # Warning issued if -keep-hc-file-too is used without
+ # -fvia-C (or the equivalent)
+ #
+ if ( $HscLang ne 'C' && $Keep_hc_file_too ) {
+ print STDERR "$Pgm: warning: Native code generator to be used, -keep-hc-file-too will be ignored\n";
+ }
- 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; };
+ if (! $do_cc && ! $do_as) { # stopping after hsc
+ $hsc_out = ($Specific_output_file ne '')
+ ? $Specific_output_file
+ : &odir_ify($ifile_root, $hsc_out_suffix);
- /^-debug$/ && do { # all this does is mark a .hc/.o as "debugging"
- # in the consistency info
- $DEBUGging = 'd';
- next arg; };
+ $ofile_target = $hsc_out; # reset
+ }
- #---------- linking .a file --------------------------------------------
+ if (! $do_as) { # stopping after gcc (or hsc)
+ $cc_as = ($Specific_output_file ne '')
+ ? $Specific_output_file
+ : &odir_ify($ifile_root, ( $Only_preprocess_hc ) ? 'i' : 's');
- /^-Main(.*)/ && do {
- # specifies main or mainPrimIO to be linked
- $Ld_main = $1;
- next arg; };
+ $ofile_target = $cc_as; # reset
+ }
- #---------- catch unrecognized flags -----------------------------------
+\end{code}
- /^-./ && do {
- print STDERR "$Pgm: unrecognised option: $_\n";
- $Status++;
- next arg; };
- #---------- anything else is considered an input file ------------------
- # (well, .o and .a files are immediately queued up as linker fodder..)
- if (/\.[oa]$/) {
- push(@Link_file, $_);
- } else {
- push(@Input_file, $_);
- }
+Now the Haskell compiler, C compiler, and assembler
- # input files must exist:
- if (! -f $_) {
- print STDERR "$Pgm: input file doesn't exist: $_\n";
- $Status++;
+\begin{code}
+ if ($do_hsc) {
+ &runHscAndProcessInterfaces( $ifile, $hscpp_hsc, $ifile_root,
+ $ofile_target, $hifile_target,
+ $going_interactive);
}
-}
-# if there are several input files,
-# we don't allow \tr{-o <file>} or \tr{-ohi <file>} options...
-# (except if linking, of course)
+ if (-f $hsc_out_h_stub) {
+ &run_something("cp $hsc_out_h_stub $ofile_h_stub_target", 'Copy foreign export header file');
+ }
-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++;
+ if (-f $hsc_out_c_stub) {
+ &run_something("rm -f $ofile_c_stub_target && echo '#include \"${ofile_h_stub_target}\"' > $ofile_c_stub_target && cat $hsc_out_c_stub >> $ofile_c_stub_target", 'Copy foreign export C stubs');
+ local ($hsc_out_s_stub);
+ local ($hsc_out_o_stub);
+ ($ofile_s_stub_target = $ofile_c_stub_target) =~ s/\.(.*)$/\.s/;
+ ($ofile_o_stub_target = $ofile_c_stub_target) =~ s/\.(.*)$//;
+
+ $ofile_o_stub_target = &osuf_ify($ofile_o_stub_target, "o");
+ if ($do_cc) {
+ &runGcc (0, $ofile_c_stub_target, $ofile_s_stub_target);
+ &runAs ($ofile_o_stub_target, $ofile_s_stub_target);
+ }
+ #
+ # Bring the C stub protos into scope when compiling the .hc file.
+ #
+ push (@CcInjects, "#include \"${hsc_out_h_stub}\"\n");
+ # Hack - ensure that the stub .h file is included in the OPTIONS section
+ # if the .hc file is saved.
+ push (@File_options, "-#include \"${ofile_h_stub_target}\"\n");
+
}
-}
-# 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
+ if ($do_cc) {
+ &runGcc ($is_hc_file, $hsc_out, $cc_as_o);
+ &runMangler($is_hc_file, $cc_as_o, $cc_as, $ifile_root) if ! $Only_preprocess_hc;
}
-}
-# 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';
+ &split_asm_file($cc_as) if $do_as && $SplitObjFiles;
+
+ # save a copy of the .s file..
+ &saveIntermediate($ifile_root , "s" , $cc_as) if ($do_as && $Keep_s_file_too);
+ &runAs($as_out, $ifile_root) if $do_as;
+\end{code}
- push(@HsC_flags, $PROFauto) if $PROFauto;
- push(@HsC_flags, $PROFcaf) if $PROFcaf;
-#UNUSED: push(@HsC_flags, $PROFdict) if $PROFdict;
+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'));
- push(@HsP_flags, (($PROFignore_scc) ? $PROFignore_scc : '-S'));
+#ToDo: local($or_isuf) = ($Isuffix eq '') ? '' : "|$Isuffix";
- 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++;
+ if ( $ifile !~ /\.(lhs|hs|hc|c|s|a|S)$/ && $ifile !~ /_hc$/ ) {
+ # There's sometimes confusion regarding .hi files; users
+ # supplying them on the command line.
+ if ( $ifile =~ /\.hi$/ ) {
+ print STDERR "$Pgm: warning: found `$ifile' on command line; interface files should not be supplied here - ignoring it.\n";
+ } else {
+ print STDERR "$Pgm: don't recognise suffix on `$ifile'; passing it through to linker\n";
+ }
+ # oops; we tentatively pushed the wrong thing; fix & do the right thing
+ pop(@Link_file); push(@Link_file, $ifile);
}
-}
-# crash and burn if there were errors
-if ( $Status > 0 ) {
- print STDERR $ShortUsage;
- exit $Status;
-}
-\end{code}
-%************************************************************************
-%* *
-\section[Driver-post-argv-mangling]{Setup after reading options}
-%* *
-%************************************************************************
+} # end of ProcessInputFile
+\end{code}
%************************************************************************
%* *
-\subsection{Set up for optimisation level (\tr{-O} or whatever)}
+\section[Driver-run-phases]{Routines to run the various phases}
%* *
%************************************************************************
-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).
+\begin{code}
+sub runLit2pgm {
+ local($in_lit2pgm, $lit2pgm_hscpp) = @_;
-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...).
+ local($to_do) = "";
-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.
+ # Only add #line pragma if we're going to need it.
+ $to_do = "echo '#line 1 \"$in_lit2pgm\"' > $lit2pgm_hscpp && " if ($Cpp_flag_set);
+ $to_do .= "$Unlit @Unlit_flags $in_lit2pgm - >> $lit2pgm_hscpp";
+
+ push(@Files_to_tidy, $lit2pgm_hscpp );
-Sadly, however, there are some interdependencies \& Things You Must
-Not Do. Here is the list.
+ &run_something($to_do, 'literate pre-processor');
+}
+\end{code}
-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...)
+\begin{code}
+sub runHscpp {
+ local($in_lit2pgm, $lit2pgm_hscpp, $hscpp_hsc) = @_;
-\item[\tr{-ffloat-inwards}:]
-Floating inwards should be done before strictness analysis, because
-the latter will give better results.
+ local($to_do) = "";
-\item[\tr{-fstatic-args}:]
-The static-arguments-transformation pass {\em must} have the
-simplifier run right after it.
+ # Strictly speaking, echoing of the following line pragma is only required
+ # on non-delit'ed input, as we've already added it during de-lit. However,
+ # hscpp will then add a {-# LINE 1 "$lit2pgm_hsc" -} to the top of the file,
+ # which is not very informative (but harmless). Hence, we uniformly have
+ # {-# LINE 1 "$in_lit2pgm" #-} as the first line to all cpp'ed hsc input.
+ #
+ $to_do = "echo '{-# LINE 1 \"$in_lit2pgm\" -}' > $hscpp_hsc && ";
-\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.)
+ if ($HsCpp eq $Cat) {
+ $to_do .= "$HsCpp $lit2pgm_hscpp >> $hscpp_hsc";
+ push(@Files_to_tidy, $hscpp_hsc );
+ &run_something($to_do, 'Ineffective C pre-processor');
+ } else {
+ local($includes) = '-I' . join(' -I',@Include_dir);
+ $to_do .= "$HsCpp $Verbose @HsCpp_flags @HsSourceCppOpts $includes $lit2pgm_hscpp >> $hscpp_hsc";
+ push(@Files_to_tidy, $hscpp_hsc );
+ &run_something($to_do, 'Haskellised C pre-processor');
+ }
+
+ if ( $Only_preprocess_C ) {
+ $to_do = "$Cat $hscpp_hsc";
+ &run_something($to_do, '');
+ }
-\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}
+}
+\end{code}
-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}
\begin{code}
-# OLD:
-#@HsC_minusO0_flags
-# = ( $Oopt_AddAutoSccs,
-# '-fsimplify', # would rather *not* run the simplifier (ToDo)
-# '\(', '\)', # nothing special at all ????
-#
-# $Oopt_FinalStgProfilingMassage
-# );
-
-@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
+sub runHscAndProcessInterfaces {
+ local($ifile, $hscpp_hsc, $ifile_root,
+ $ofile_target, $hifile_target,
+ $going_interactive) = @_;
+
+ # $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)
- $Oopt_FinalStgProfilingMassage
- );
+ local($source_unchanged) = 1;
-@HsC_minusO_flags # NOTE: used for *both* -O and -O2 (some conditional bits)
- = (
- # initial simplify: mk specialiser and autoscc 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",
- '\)',
-
- $Oopt_AddAutoSccs, # need some basic simplification first
-
- ($Oopt_DoSpecialise) ? (
- '-fspecialise-overloaded',
- $Oopt_SpecialiseUnboxed,
- $Oopt_DoSpecialise,
- ) : (),
+ # 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.
- '-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',
- '-fdo-eta-reduction',
- '-fdo-lambda-eta-expansion',
- '-freuse-con',
- "$Oopt_PedanticBottoms",
- "$Oopt_MonadEtaExpansion",
- "$Oopt_UnfoldingUseThreshold",
- "$Oopt_MaxSimplifierIterations",
- '\)',
-
- '-fcalc-inlinings1',
-
-# ($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',
-# "$Oopt_PedanticBottoms",
-# "$Oopt_MonadEtaExpansion",
-# "$Oopt_UnfoldingUseThreshold",
-# "$Oopt_MaxSimplifierIterations",
-# '\)',
-# ) : (),
+ ($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);
- # this pass-ordering sequence was agreed by Simon and Andr\'e
- # (WDP 94/07, 94/11).
- '-ffull-laziness',
-
- ($Oopt_FoldrBuild) ? (
- '-ffoldr-build-on', # desugar list comprehensions for foldr/build
-
- '-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',
- "$Oopt_PedanticBottoms",
- "$Oopt_MonadEtaExpansion",
- "$Oopt_UnfoldingUseThreshold",
- "$Oopt_MaxSimplifierIterations",
- '\)',
- ) : (),
-
- '-ffloat-inwards',
-
- '-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',
- ($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",
- '\)',
-
- '-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! Only done after strictness analysis
- "$Oopt_PedanticBottoms",
- "$Oopt_MonadEtaExpansion",
- "$Oopt_UnfoldingUseThreshold",
- "$Oopt_MaxSimplifierIterations",
- '\)',
-
- '-ffloat-inwards',
-
-# Case-liberation for -O2. This should be after
-# strictness analysis and the simplification which follows it.
-
-# ( ($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 \\)" ),
-
-# Final clean-up simplification:
-
- '-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!
- $Oopt_FoldrBuildInline,
- ($Oopt_FoldrBuild) ? ('-fdo-foldr-build') : (),
- # but still do reductions if you see them!
- "$Oopt_PedanticBottoms",
- "$Oopt_MonadEtaExpansion",
- "$Oopt_UnfoldingUseThreshold",
- "$Oopt_MaxSimplifierIterations",
- '\)',
+ # The informational messages below are now conditional on -v being set -- SOF
+ if ( $ofile_target ne "_stdin.s" && ! -f $ofile_target ) {
+ print STDERR "$Pgm:compile:Output file $ofile_target doesn't exist\n" if $Verbose;
+ $source_unchanged = 0;
+ }
- # '-fstatic-args',
+ ($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
- '-fcalc-inlinings2',
+ if ( $hifile_target ne "_stdout" && ! -f $hifile_target ) {
+ print STDERR "$Pgm:compile:Interface file $hifile_target doesn't exist\n" if $Verbose;
+ $source_unchanged = 0;
+ }
- # stg2stg passes
- '-fupdate-analysis',
- '-flambda-lift',
- $Oopt_FinalStgProfilingMassage,
- $Oopt_StgStats,
+ ($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
- # flags for stg2stg
- '-flet-no-escape',
+ if ( $ofile_target ne "_stdin.s" && $i_mtime > $o_mtime) {
+ print STDERR "$Pgm:recompile:Input file $ifile newer than $ofile_target\n" if $Verbose;
+ $source_unchanged = 0;
+ }
- # SPECIAL FLAGS for -O2
- ($OptLevel == 2) ? (
- '-fsemi-tagging',
- ) : (),
- );
-\end{code}
+ # Tell the compiler which version we're using
+ push(@HsC_flags, "-fhi-version=${ProjectVersionInt}");
-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 ) {
+ # 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');
+ }
-# &add_Hsc_flags( @HsC_minusO0_flags );
+ # Indicate whether we're static or not.
+ # This will only ever
+ push(@HsC_flags, '-static') if $Static;
-if ( $OptLevel <= 0 ) {
+ # Run the compiler
- # 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');
+ &runHsc($ifile_root, $hsc_out, $hsc_hi, $hsc_out_c_stub, $hsc_out_h_stub, $going_interactive);
- &add_Hsc_flags( @HsC_minusNoO_flags );
- push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O'); # not optional!
+ # See if it bailed out early, saying nothing needed doing.
+ # We work this out by seeing if it created an output .hi file
-} elsif ( $OptLevel == 1 || $OptLevel == 2 ) {
+ if ( ! -f $hsc_hi && $ProduceHi !~ /-nohifile=/ ) {
+ # Doesn't exist, so we bailed out early.
+ # Tell the C compiler and assembler not to run
+ $do_cc = 0; $do_as = 0;
- &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...).
+ # Update dependency info, by touching the object file
+ # This records in the file system that the work of
+ # recompiling this module has been done
+ #
+ &run_something("touch $ofile_target",
+ "Touch $ofile_target, to propagate dependencies") if $HscLang ne 'none';
-} else { # -Ofile, then...
+ } else {
- &add_Hsc_flags( @HsC_minusO3_flags );
- push(@CcBoth_flags, ($MinusO2ForC) ? '-O2' : '-O'); # possibly to be elaborated...
-}
-\end{code}
+ # 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 ( $HscLang eq 'C' ) {
+ $to_do = "echo 'static char ghc_hsc_ID[] = \"\@(#)hsc $ifile\t$HsC_major_version.$HsC_minor_version,$HsC_consist_options\";' >> $hsc_out";
+
+ &run_something($to_do, 'Pin on Haskell consistency info');
+ } elsif ( $HscLang eq 'asm' ) {
+ 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');
+ }
+ # no consistency info for Java output files
+ }
-%************************************************************************
-%* *
-\subsection{Check for registerising, consistency, etc.}
-%* *
-%************************************************************************
-Are we capable of generating ``registerisable'' C (either using
-C or via equivalent native code)?
+ # Interface-handling is important enough to live off by itself
+ if ( $ProduceHi !~ /-nohifile=/ ) { # If we've produced one, process it.
+ 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);
+ }
+ # if we're going to split up object files,
+ # we inject split markers into the .hc file now
+ if ( $HscLang eq 'C' && $SplitObjFiles ) {
+ &inject_split_markers ( $hsc_out );
+ }
-\begin{code}
-$RegisteriseC = ( $GccAvailable
- && $RegisteriseC ne 'no' # not explicitly *un*set...
- && ($TargetPlatform =~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|sparc)-/)
- ) ? 'o' : '';
-\end{code}
+ # save a copy of the .hc file, even if we are carrying on...
+ if ($HscLang eq 'C' && $do_cc && $Keep_hc_file_too) {
+ &saveIntermediate($ifile_root , "hc" , $hsc_out);
+ }
-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);
}
-
-} 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';
}
\end{code}
-\begin{code}
-if ( $BuildTag ne '' ) { # something other than normal sequential...
-
- push(@HsP_flags, "-g$BuildTag.hi"); # use appropriate Prelude .hi files
-
- $ProduceC = 1; $ProduceS = ''; # must go via C
-# print STDERR "eval...",$EvaldSetupOpts{$BuildTag},"\n";
-
- eval($EvaldSetupOpts{$BuildTag});
-}
-\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__}).
+sub runHsc {
+ local($ifile_root, $hsc_out, $hsc_hi, $hsc_out_c_stub, $hsc_out_h_stub, $going_interactive) = @_;
-Note: a few ``always apply'' flags were set at the very beginning.
-
-\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;
+ push(@HsC_flags, "\"-himap=$HiIncludeString\"");
+ push(@HsC_flags, "\"-himap-sep=${SplitMarker}\"");
-} 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 we're going to show it on stdout:
+ $ProduceHi = '-nohifile=' if ! ($HiOnStdout || $Specific_hi_file ne '' );
+ $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:
+ $oflags = ( $HscLang eq 'none' ? "" : "-olang=$HscLang -ofile=$hsc_out" ) ;
+ $output = "$ProduceHi$hsc_hi $oflags -F=$hsc_out_c_stub -FH=$hsc_out_h_stub";
+ push(@Files_to_tidy, $hsc_hi, $hsc_out, $hsc_out_c_stub, $hsc_out_h_stub );
- 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
+ print STDERR "warning: both -Rgc-stats and -Rghc-timing used, -Rghc-timing wins." if $CollectingGCstats;
+ 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!
+ local($to_do);
+ # Win32 only: If the command processor used by system()
+ # exec()s the application as an ordinary Win32 executable,
+ # we're in trouble here, since the command line is likely
+ # to be > 255 chars long. To work around this situation,
+ # $HsC also understands `at-files', i.e., `@file' on the
+ # command line will cause $HsC to add the contents of `file'
+ # to the command line.
#
- # -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
-
-} 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;
-}
-\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)
+ # [ Note: support for `at-files' is not compiled in by default ]
+ $cmd_line_opts_via_at_file=0;
+ if ($cmd_line_opts_via_at_file) {
-\begin{code}
-unshift(@Ld_flags,
- ( $TargetPlatform =~ /^alpha-/
- || $TargetPlatform =~ /^hppa/
- || $TargetPlatform =~ /^mips-sgi-irix/
- || $TargetPlatform =~ /^powerpc-/
- || $TargetPlatform =~ /-solaris/
- )
- ? (($Ld_main) ? (
- '-u', 'Main_' . $Ld_main . '_closure',
- ) : (),
- '-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...
- : (($Ld_main) ? (
- '-u', '_Main_' . $Ld_main . '_closure',
- ) : (),
- '-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}
+ local($to_do_opts) = "$Tmp_prefix.opts";
+ open(OPTS, "> $Tmp_prefix.opts") || &tidy_up_and_die(1,"Can't open $Tmp_prefix.opts\n");
+ print OPTS "$dump @HsC_flags $CoreLint $USPLint $StgLint $Verbose";
+ close(OPTS);
+ $to_do = "$HsC $hscpp_hsc \@$Tmp_prefix.opts $output +RTS @HsC_rts_flags";
-%************************************************************************
-%* *
-\subsection{Set up include paths and system-library enslurpment}
-%* *
-%************************************************************************
+ } else {
-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.
+ $to_do = "$HsC $hscpp_hsc $dump @HsC_flags $CoreLint $USPLint $StgLint $Verbose $output +RTS @HsC_rts_flags";
+ }
+ &run_something($to_do, 'Haskell compiler');
-\begin{code}
-# default includes must be added AFTER option processing
-if ( $(INSTALLING) ) {
- push (@Include_dir, "$InstLibDirGhc/includes");
- push (@Include_dir, "$InstDataDirGhc/includes");
-
-} else {
- push (@Include_dir, "$TopPwd/$(CURRENT_DIR)/$(GHC_INCLUDESRC)");
+ # finish business w/ nofibbish time/bytes-alloc stats
+ &process_ghc_timings() if $CollectGhcTimings;
}
\end{code}
+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}
-local($f);
-foreach $f (@SysLibrary) {
- $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');
-
-# 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');
- }
-}
-
-# Push the GNU multi-precision arith lib; and the math library
-push(@SysLibrary, '-lgmp');
-push(@SysLibrary, '-lm');
-\end{code}
-
-%************************************************************************
-%* *
-\subsection{Check that this system was built to do what we are asking}
-%* *
-%************************************************************************
+$HiMapDone = 0;
+$HiIncludeString = (); # dir1:dir2:dir3, to pass to GHC
-Before continuing we check that the appropriate build is available.
+sub makeHiMap {
-\begin{code}
-die "$Pgm: no BuildAvail?? $BuildTag\n" if ! $BuildAvail{$BuildTag}; # sanity
+ # collect in %HiMap; write later; also used elsewhere in driver
-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;
-}
-\end{code}
+ local($mod, $path, $d, $e);
-%************************************************************************
-%* *
-\subsection{Final miscellaneous setup bits before we start going}
-%* *
-%************************************************************************
+ # reset the global variables:
+ $HiMapDone = 0;
+ $HiIncludeString = (); # dir1:dir2:dir3, to pass to GHC
+
+ foreach $d ( @Import_dir ) {
+ if ($HiIncludeString) {
+ $HiIncludeString = "$HiIncludeString${SplitMarker}${d}%.${HiSuffix}";
+ } else {
+ $HiIncludeString = "$d%.${HiSuffix}";
+ }
-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}
+ foreach $d ( @SysImport_dir ) {
+ if ($HiIncludeString) {
+ $HiIncludeString = "$HiIncludeString${SplitMarker}${d}%.${HiSuffix_prelude}";
+ } else {
+ $HiIncludeString = "${d}%.${HiSuffix_prelude}";
+ }
+ }
-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, '-');
+ $HiMapDone = 1;
}
-\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}
-%* *
-%************************************************************************
+Invoke the 'linker' - either the standard linker or the one used to build
+a (Win32) DLL.
-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 runLinker
+{
+ local($libdirs) = '';
-if ( $Status > 0 ) { # don't link if there were errors...
- print STDERR $ShortUsage;
- &tidy_up();
- exit $Status;
-}
-\end{code}
+ # append last minute flags linker and consistency flags
+ &setupBuildFlags();
+ &setupSyslibs();
+ &setupLinkOpts();
-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);
- }
+
+ $libdirs = '-L' . join(' -L',@UserLibrary_dir) if $#UserLibrary_dir >= 0;
+
# for a linker, use an explicitly given one, or the going C compiler ...
- local($lnkr) = ( $Lnkr ) ? $Lnkr : ($RegisteriseC ? $CcRegd : $CcUnregd );
+ local($lnkr) = ( $Lnkr ) ? $Lnkr : $CcRegd;
+
+ if ( ($Specific_output_file eq '') &&
+ ( ($TargetPlatform eq 'i386-unknown-cygwin32') ||
+ ($TargetPlatform eq 'i386-unknown-mingw32')) ) {
+ $Specific_output_file = 'main.exe';
+ print STDERR "Output file not specified, defaulting to \"main.exe\"\n";
+ }
+
+ local($output) = ($Specific_output_file ne '') ? "-o $Specific_output_file" : '';
+ @Files_to_tidy = ($Specific_output_file ne '') ? $Specific_output_file : 'a.out';
- local($output)= ($Specific_output_file ne '') ? "-o $Specific_output_file" : '';
- @Files_to_tidy = ($Specific_output_file ne '') ? "$Specific_output_file" : 'a.out';
+ &prepareWin32DllLink(1);
- local($to_do) = "$lnkr $Verbose @Ld_flags $output @Link_file $TopClosureFile $libdirs @UserLibrary @SysLibrary";
+ local($to_do) = "$lnkr $Verbose @Ld_flags $output @Link_file $libdirs @UserLibrary @SysLibrary";
&run_something($to_do, 'Linker');
# finally, check the consistency info in the binary
$pvm_executable = $ENV{'PVM_ROOT'} . '/bin/' . $ENV{'PVM_ARCH'}
. "/$pvm_executable";
- &run_something("rm -f $pvm_executable; cp -p $executable $pvm_executable && rm -f $executable", 'Moving binary to PVM land');
+ &run_something("$Rm -f $pvm_executable; $Cp -p $executable $pvm_executable && $Rm -f $executable", 'Moving binary to PVM land');
# 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)
+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)
+# Generated by Glasgow Haskell, version ${ProjectVersion}
+# ngoqvam choHbogh vaj' vIHoHnISbej !!!!
#
\$pvm_executable = '$pvm_executable';
\$pvm_executable_base = '$pvm_executable_base';
}
if ( $a eq '-d' && $in_RTS_args ) {
$debug = '-';
- } elsif ( $a =~ /^-N(\d+)/ && $in_RTS_args ) {
+ } elsif ( $a =~ /^-qN(\d+)/ && $in_RTS_args ) {
+ $nprocessors = $1;
+ } elsif ( $a =~ /^-qp(\d+)/ && $in_RTS_args ) {
$nprocessors = $1;
} else {
push(@nonPVM_args, $a);
}
}
-exec "$SysMan $debug $pvm_executable $nprocessors @nonPVM_args";
-print STDERR "Exec failed!!!: $SysMan $debug $nprocessors @nonPVM_args\n";
-exit(1);
+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";
+ chmod 0755, $executable;
}
}
-# that... that's all, folks!
-&tidy_up();
-exit $Status; # will still be 0 if all went well
+sub createWin32DLL
+{
+ local ($libdirs);
+
+ # append last minute flags linker and consistency flags
+ &setupBuildFlags();
+ &setupSyslibs();
+ &setupLinkOpts();
+
+ # glue them together:
+ push(@UserLibrary_dir, @SysLibrary_dir);
+
+ $libdirs = '-L' . join(' -L',@UserLibrary_dir) if $#UserLibrary_dir >= 0;
+
+ &prepareWin32DllLink(0);
+
+ local ($bld_dll) = "dllwrap";
+
+ local ($output) = ($Specific_output_file ne '') ? "$Specific_output_file" : 'HSdll.dll';
+ local ($output_dir);
+ local ($output_file);
+ local ($output_lib, $output_def);
+
+ ($output_dir = $output) =~ s|(.*/)[^/]+$|$1|;
+ $output_dir = "" if ($output_dir eq $output);
+ ($output_file = $output) =~ s|.*/([^/]+)$|$1|;
+
+ ($output_lib = $output_file) =~ s|(.+)\.[^\.]*$|${output_dir}lib$1_imp.a|;
+ ($output_def = $output_file) =~ s|(.+)\.[^\.]*$|${output_dir}$1.def|;
+
+ push (@Dll_flags, "-mno-cygwin --target=i386-mingw32") if ($TargetPlatform =~ /^.*mingw32$/);
+ push (@Dll_flags, "--output-lib $output_lib");
+ # If the "--def " option hasn't been supplied, assume everything
+ # is going to be exported via the DLL.."
+ if (!grep(/--def/, @Dll_flags)) {
+ push (@Dll_flags, "--export-all --output-def $output_def");
+ }
+
+ local($to_do) = "$bld_dll @Dll_flags -o $output @Link_file $libdirs @UserLibrary @SysLibrary";
+ # Make sure the user sees this piece of magic.
+ print STDERR "$to_do\n" if (!$Verbose);
+ &run_something($to_do, 'DLL creator');
+}
+
+sub prepareWin32DllLink
+{
+ local($linking_main) = @_;
+
+ #
+ # Win32 DLLs - link with import libraries, not the real archives.
+ #
+ if ( $TargetPlatform =~ /-mingw32$/ ) {
+ if (!$Static) {
+ #
+ # If the libraries have the form libHSfoo.a, we
+ # transform that into libHSfoo_imp.a - the import
+ # library of the DLL.
+ #
+ foreach $a ( @SysLibrary ) {
+ $a = "${a}_imp" if ($a =~ /^-lHS/);
+ }
+ foreach $a ( @UserLibrary ) {
+ $a = "${a}_imp" if ($a =~ /^-lHS/);
+ }
+ push(@Link_file, ( $INSTALLING ) ? "$InstLibDirGhc/Main.dll_o"
+ : "$TopPwd/$CURRENT_DIR/$GHC_RUNTIME_DIR/Main.dll_o") if $linking_main;
+ push(@Link_file, ( $INSTALLING ) ? "$InstLibDirGhc/PrelMain.dll_o"
+ : "$TopPwd/$CURRENT_DIR/$GHC_LIB_DIR/std/PrelMain.dll_o") if $linking_main;
+ }
+ push(@Ld_flags, "-mno-cygwin");
+ }
+}
\end{code}
+
%************************************************************************
%* *
-\section[Driver-do-one-file]{How to process a single input file}
+\section[Driver-misc-utils]{Miscellaneous utilities}
%* *
%************************************************************************
-\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}
+%************************************************************************
+%* *
+\subsection[Driver-odir-ify]{@odir_ify@: Mangle filename if \tr{-odir} set}
+%* *
+%************************************************************************
-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;
+sub osuf_ify {
+ local($ofile,$def_suffix) = @_;
+
+ return(($Osuffix eq '') ? "$ofile.$def_suffix" : "$ofile.$Osuffix" );
+}
+
+sub odir_ify {
+ local($orig_file, $def_suffix) = @_;
+ if ($Specific_output_dir eq '') { # do nothing
+ &osuf_ify($orig_file, $def_suffix);
} else {
- ($ifile_root = $ifile) =~ s/\.[^\.\/]+$//;
- ($ifile_root_file = $ifile_root) =~ s|.*/||;
+ local ($orig_file_only);
+ ($orig_file_only = $orig_file) =~ s|.*/||;
+ &osuf_ify("$Specific_output_dir/$orig_file_only",$def_suffix);
}
+}
\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}
+sub runGcc {
+ local($is_hc_file, $hsc_out, $cc_as_o) = @_;
-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";
+ local($includes) = '-I' . join(' -I', @Include_dir);
+ local($cc);
+ local($s_output);
+ local($c_flags) = "@CcBoth_flags";
+ local($ddebug_flag) = ( $DEBUGging ) ? '-DDEBUG' : '';
+ $c_flags .= " -mno-cygwin" if ( $TargetPlatform =~ /-mingw32$/ );
+
+ # "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";
+ local($cc_help) = "ghc$$.c";
+ local($cc_help_s) = "ghc$$.s";
+
+ $cc = $CcRegd;
+ $s_output = (($is_hc_file && $DoAsmMangling) || $TargetPlatform =~ /^(powerpc|rs6000|hppa)/) ? $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;
+#include "Stg.h"
+EOINCL
+ # user may have asked for #includes to be injected...
+ print TMP @CcInjects if $#CcInjects >= 0;
+ } else {
+ # Straight .c files may want to know that they're being used
+ # with a particular version of GHC, so we define __GLASGOW_HASKELL__ for their benefit.
+ print TMP "#define __GLASGOW_HASKELL__ ${ProjectVersionInt}\n";
+ }
+ # 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($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}
+ print TMP "#include \"$hsc_out\"\n";
+ close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n");
-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");
+ # Don't redirect stderr into intermediate file if slamming output onto stdout (e.g., with -E)
+ local($fuse_stderr) = "2>&1" if ! $Only_preprocess_hc;
+ local($to_do) = "$cc $Verbose $ddebug_flag $c_flags @Cpp_define $includes $cc_help > $Tmp_prefix.ccout $fuse_stderr && ( if [ $cc_help_s != $s_output ] ; then mv $cc_help_s $s_output ; else exit 0 ; fi )";
+
+ if ( $Only_preprocess_hc ) { # HACK ALERT!
+ $to_do =~ s/ -S\b//g;
}
- 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");
- }
+ push(@Files_to_tidy, $cc_help, $cc_help_s, $s_output );
+ $PostprocessCcOutput = 1 if ! $Only_preprocess_hc; # hack, dear hack...
+ &run_something($to_do, 'C compiler');
+ $PostprocessCcOutput = 0;
+ if ( $Only_preprocess_hc ) {
+ system("$Cat $Tmp_prefix.ccout");
}
+ unlink($cc_help, $cc_help_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 $genSPECS_flag @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!
+sub runMangler {
+ local($is_hc_file, $cc_as_o, $cc_as, $ifile_root) = @_;
+
+ print STDERR `cat $cc_as_o` if $Dump_raw_asm; # to stderr, before mangling
+
+ if ($is_hc_file && $DoAsmMangling) {
+ # 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");
+ # 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.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 =~ /^powerpc|^rs6000/) {
+ # minor mangling of non-threaded files for powerpcs and rs6000s
+ require('ghc-asm.prl')
+ || &tidy_up_and_die(1,"$Pgm: panic: can't load ghc-asm-powerpc.prl!\n");
+ &mini_mangle_asm_powerpc($cc_as_o, $cc_as);
}
- 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 ($do_as && $Keep_s_file_too) {
+ # &saveIntermediate($ifile_root , "s" , $cc_as);
+ #}
+}
+\end{code}
- # 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');
- }
+\begin{code}
+sub runAs {
+ local($as_out, $ifile_root) = @_;
- # 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";
+ local($asmblr) = ( $As ) ? $As : $CcRegd;
- # and #include the real source
- print TMP "#include \"$hsc_cc\"\n";
- close(TMP) || &tidy_up_and_die(1,"Failed writing to $cc_help\n");
+ # need to add the -I flags in case the file is going through cpp (.S files)
+ local($includes) = '-I' . join(' -I', @Include_dir);
- 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 ( ! $SplitObjFiles || $ifile_root =~ /_stub\.s$/ ) {
+ local($to_do) = "$asmblr -o $as_out -c @As_flags $includes $cc_as";
+ push(@Files_to_tidy, $as_out );
+ &run_something($to_do, 'Unix assembler');
- 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);
- }
- }
+ } else { # more complicated split-ification...
- # 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;
+ # must assemble files $Tmp_prefix__[1 .. $NoOfSplitFiles].s
- # 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 -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.
+ #
+ #
- if ($do_as) {
- # if we're splitting .o files...
- if ( $SplitObjFiles ) {
- &split_asm_file ( $cc_as );
- }
+ if ( $Specific_output_dir eq '' ) {
+ $Specific_output_dir = ${ifile_root};
+ }
- local($asmblr) = ( $As ) ? $As : ($RegisteriseC ? $CcRegd : $CcUnregd );
+ 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";
+ push(@Files_to_tidy, $split_out );
- 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");
- }
}
\end{code}
}
local($return_val) = 0;
- system("$Time $str_to_do");
- $return_val = $?;
+
+ if ( length($str_to_do) > 4000) {
+ # 4000 - on the random side, just like the *real* ARG_MAX
+ # for some shells.
+
+ # With some shells, command lines of this length may
+ # very well cause trouble. To safeguard against this, we squirrel the
+ # command into a file and exec that.
+ local ($sh) = $ENV{'REAL_SHELL'};
+ print STDERR "Backup plan A: saving cmd line in ${Tmp_prefix}.sh and executing that with $sh\n" if $Verbose;
+ open (TEMP, "> ${Tmp_prefix}.sh") ||
+ &tidy_up_and_die(1,"$Pgm: failed to open `$Tmp_prefix.sh'\n");
+ print TEMP "$Time $str_to_do\n";
+ close (TEMP) ||
+ &tidy_up_and_die(1,"$Pgm: failed closing `$Tmp_prefix.sh'\n");
+ system("$sh $Tmp_prefix.sh");
+ $return_val = $?;
+
+ unlink "${Tmp_prefix}.sh";
+ } else {
+ system("$Time $str_to_do");
+ $return_val = $?;
+ }
if ( $PostprocessCcOutput ) { # hack, continued
open(CCOUT, "< $Tmp_prefix.ccout")
|| &tidy_up_and_die(1,"$Pgm: failed to open `$Tmp_prefix.ccout'\n");
while ( <CCOUT> ) {
- next if /attribute directive ignored/;
next if /call-clobbered/;
- next if /from .*COptRegs\.lh/;
- next if /from .*(stg|rts)defs\.h:/;
+ next if /control reaches end/;
+ next if /from .*Stg\.h:/;
next if /from ghc\d+.c:\d+:/;
- next if /from .*\.lc/;
- next if /from .*SMinternal\.lh/;
- 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/;
next if /: At top level:$/;
next if /: In function \`.*\':$/;
next if /\`ghc_cc_ID\' defined but not used/;
close(CCOUT) || &tidy_up_and_die(1,"$Pgm: failed closing `$Tmp_prefix.ccout'\n");
}
+ local($signal_num) = $? & 127;
+ local($dumped_core) = $? & 128;
+
+ if ($signal_num != 0) {
+ print STDERR "$tidy_name received signal $signal_num";
+ if ($dumped_core != 0) {
+ print STDERR " (core dumped)";
+ }
+ print STDERR "\n";
+ }
+
if ($return_val != 0) {
if ($Using_dump_file) {
print STDERR "Compilation Errors dumped in $Specific_dump_file\n";
}
-
&tidy_up_and_die($return_val, '');
}
- $Using_dump_file = 0;
-}
-\end{code}
-
-%************************************************************************
-%* *
-\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");
- }
+ $Using_dump_file = 0;
}
\end{code}
%************************************************************************
%* *
-\subsection[Driver-ghctiming]{Emit nofibbish GHC timings}
+\subsection[Driver-ghc-timing]{Emit nofibbish GHC timings}
%* *
%************************************************************************
local($SysSpecificTiming) = 'ghc';
open(STATS, $StatsFile) || die "Failed when opening $StatsFile\n";
- local($tot_live) = 0; # for calculating avg residency
+ local($max_live) = 0;
+ local($tot_live) = 0; # for calculating residency stuff
+ local($tot_samples) = 0;
while (<STATS>) {
- $tot_live += $1 if /^\s*\d+\s+\d+\s+\d+\.\d+\%\s+(\d+)\s+\d+\.\d+\%/;
-
- $BytesAlloc = $1 if /^\s*([0-9,]+) bytes allocated in the heap/;
+ if (! /Gen:\s+0/ && ! /Minor/ && /^\s*\d+\s+\d+\s+(\d+)\s+\d+\.\d+/ ) {
+ $max_live = $1 if $max_live < $1;
+ $tot_live += $1;
+ $tot_samples += 1;
+ }
+ $BytesAlloc = $1 if /^\s*([0-9,]+) bytes allocated in the heap/;
if ( /^\s*([0-9,]+) bytes maximum residency .* (\d+) sample/ ) {
$MaxResidency = $1; $ResidencySamples = $2;
}
- $GCs = $1 if /^\s*([0-9,]+) garbage collections? performed/;
+ $GCs = $1 if /^\s*([0-9,]+) (collections? in generation 0|garbage collections? performed)/;
+
+ if ( /^\s+([0-9]+)\s+Mb total memory/ ) {
+ $TotMem = $1;
+ }
- if ( /^\s*INIT\s+time\s*(\d+\.\d\d)s\s*\(\s*(\d+\.\d\d)s elapsed\)/ ) {
+ # The presence of -? in the following pattern is only there to
+ # accommodate 0.29 && <= 2.05 RTS'
+ if ( /^\s*INIT\s+time\s*(\d+\.\d\d)s\s*\(\s*-?(\d+\.\d\d)s elapsed\)/ ) {
$InitTime = $1; $InitElapsed = $2;
} elsif ( /^\s*MUT\s+time\s*(\d+\.\d\d)s\s*\(\s*(\d+\.\d\d)s elapsed\)/ ) {
$MutTime = $1; $MutElapsed = $2;
}
}
close(STATS) || die "Failed when closing $StatsFile\n";
- if ( defined($ResidencySamples) && $ResidencySamples > 0 ) {
- $AvgResidency = int ($tot_live / $ResidencySamples) ;
+ if ( $tot_samples > 0 ) {
+ $ResidencySamples = $tot_samples;
+ $MaxResidency = $max_live;
+ $AvgResidency = int ($tot_live / $tot_samples) ;
}
# warn about what we didn't find
# print out what we found
print STDERR "<<$SysSpecificTiming: ",
- "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed)",
+ "$BytesAlloc bytes, $GCs GCs, $AvgResidency/$MaxResidency avg/max bytes residency ($ResidencySamples samples), ${TotMem}M in use, $InitTime INIT ($InitElapsed elapsed), $MutTime MUT ($MutElapsed elapsed), $GcTime GC ($GcElapsed elapsed)",
" :$SysSpecificTiming>>\n";
# OK, party over
\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);
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) {
+ if ($rest_of_arg ne '') {
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";
}
}
\end{code}
+
+To add another system library, you'll need to augment the
+Supported_syslibs variable with name and info on your addition
+to the syslib family. The info bit consist of the following:
+
+ - interface file directory
+ see the misc or posix entry for how to distinguish
+ between using installed and build tree directories.
+
+ - directory location of archives
+
+ - location of (way-independent) C support libs.
+ not all libraries need this - if you don't, just
+ give the empty string.
+ - list of syslibs you depend on.
+
+ - additional ghc command line flags that should be used.
+ - additional C compiler command line flags that should be used.
+ - link
+
+
+\begin{code}
+
+# Hash to keep track of
+%Syslibs_added = ();
+
+sub add_syslib {
+ local($syslib) = @_;
+
+ # Lifting this out of this sub brings it out of scope - why??
+ %Supported_syslibs =
+ ( lang,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/lang"
+ : "$TopPwd/hslibs/lang:$TopPwd/hslibs/lang/monads"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/lang"
+ )
+ , # where to find the cbits archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/lang/cbits"
+ )
+ , '' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '' # extra ld opts
+ ],
+
+ concurrent,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/concurrent"
+ : "$TopPwd/hslibs/concurrent"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/concurrent"
+ )
+ , '' # where to find the cbits archive to use when linking
+ , '' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '' # extra ld opts
+ ],
+
+ data,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/data"
+ : "$TopPwd/hslibs/data:$TopPwd/hslibs/data/edison:$TopPwd/hslibs/data/edison/Assoc:$TopPwd/hslibs/data/edison/Coll:$TopPwd/hslibs/data/edison/Seq"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/data"
+ )
+ , '' # where to find the cbits archive to use when linking
+ , 'lang' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '' # extra ld opts
+ ],
+
+ net,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/net"
+ : "$TopPwd/hslibs/net"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/net"
+ )
+ , # where to find the cbits archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/net/cbits"
+ )
+ , 'lang text' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , ( $TargetPlatform =~ /-solaris2$/ ? '-lnsl -lsocket' : '')
+ ],
+
+ posix,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/posix"
+ : "$TopPwd/hslibs/posix"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/posix"
+ )
+ , # where to find the cbits archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/posix/cbits"
+ )
+ , 'lang' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '' # extra ld opts
+ ],
+
+ text,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/text"
+ : "$TopPwd/hslibs/text:$TopPwd/hslibs/text/html:$TopPwd/hslibs/text/haxml/lib"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/text"
+ )
+ , # where to find the cbits archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/text/cbits"
+ )
+ , 'lang data' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '' # extra ld opts
+ ],
+
+ util,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/util"
+ : "$TopPwd/hslibs/util:$TopPwd/hslibs/util/check"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/util"
+ )
+ , # where to find the cbits archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/util/cbits"
+ )
+ , 'lang concurrent posix' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , "$LibsReadline" # extra ld opts
+ ],
+
+ win32,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/win32"
+ : "$TopPwd/hslibs/win32/src"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hslibs/win32/src"
+ )
+ , ''
+ , 'lang' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '-luser32 -lgdi32' # extra ld opts
+ ],
+
+ com,
+ [ # where to slurp interface files from
+ ( $INSTALLING
+ ? "$InstLibDirGhc/imports/com"
+ : "$TopPwd/hdirect/lib"
+ )
+ , # where to find the archive to use when linking
+ ( $INSTALLING
+ ? "$InstLibDirGhc"
+ : "$TopPwd/hdirect/lib"
+ )
+ , ''
+ , 'lang' # Syslib dependencies
+ , '' # extra ghc opts
+ , '' # extra cc opts
+ , '-luser32 -lole32 -loleaut32 -ladvapi32'
+ # extra ld opts
+ ]
+ );
+
+ # check if it's supported..
+
+ if ( !exists $Supported_syslibs{$syslib} ) {
+ print STDERR "$Pgm: no such system library (-syslib): $syslib\n";
+ $Status++;
+ return;
+ }
+
+ # This check is here to avoid syslib loops from
+ # spoiling the party. A side-effect of it is that
+ # it disallows multiple mentions of a syslib on a command-line,
+ # explicit *and* implicit ones (i.e., "-syslib lang -syslib misc"
+ # is not equal to "-syslib lang -syslib misc -syslib lang",
+ # which it needs to be)
+ #
+ # Since our current collection of syslibs don't have any
+ # loops, this test is disabled.
+ #
+ # ToDo: loop avoidance scheme when the need arises
+ #
+ #return if ( exists $Syslibs_added{$syslib} );
+
+ $Syslibs_added{$syslib} = 1;
+
+ local ($hi_dirs, $lib_dir, $lib_cbits_dir,
+ $syslib_deps, $syslib_ghc_opts,
+ $syslib_cc_opts, $syslib_ld_opts) = @{ $Supported_syslibs{$syslib} };
+
+ foreach(split(':',$hi_dirs)) {
+ unshift(@SysImport_dir, $_);
+ }
+ push(@SysLibrary_dir, $lib_dir);
+ push(@SysLibrary_dir, $lib_cbits_dir) if ( $lib_cbits_dir ne '');
+
+ push(@SysLibrary, "-lHS$syslib");
+ push(@SysLibrary, "-lHS${syslib}_cbits") if ( $lib_cbits_dir ne '');
+ push(@SysLibrary, $syslib_ld_opts) if ($syslib_ld_opts ne '');
+
+ # Add on any extra dependencies.
+ foreach $lib (split(' ',$syslib_deps)) {
+ &add_syslib($lib);
+ }
+}
+\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,$ifile) = @_;
+ local($comment_start,$comment_end);
+
+ if ($ifile =~ /\.hc$/ ||
+ $ifile =~ /_hc$/ ||
+ $ifile =~ /\.s$/ ||
+ $ifile =~ /_s$/ ) { # `Real' C intermediate
+ $comment_start = "/\\*";
+ $comment_end = "\\*/";
+ } else { # Assume it is a file containing Haskell source
+ $comment_start = "{-#";
+ $comment_end = "#-}";
+ }
+
+ open(FILE,$file) || return(1); # No big loss
+
+ while (<FILE>) {
+ if ( /^${comment_start} OPTIONS (.*)${comment_end}/ ) {
+ # add the options found at the back of the command line.
+ local(@entries) = split(/\s+/,$1);
+ print STDERR "Found OPTIONS " . join(' ',@entries) . " in $file\n" if $Verbose;
+ push(@File_options, @entries);
+ }
+ elsif ( /^$/ ) { # ignore empty lines
+ ;
+ }
+ elsif ( /^#line.+$/ ) { # ignore comment lines (unused..ToDo: rm )
+ ;
+ }
+ elsif ( /^{-# LINE.+$/ ) { # ignore line pragmas
+ ;
+ }
+ else { # stop looking, something non-empty / not
+ # ${comment_start} OPTIONS .. ${comment_end} encountered.
+ close(FILE);return(0);
+ }
+ }
+ 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|ohi|o|isuf|osuf|hisuf|odump|syslib|package|package-name)$/ &&
+ 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}
+
+When saving an intermediate file (.hc or .s) away, we
+have to prefix any OPTIONS found in the original source file.
+
+\begin{code}
+sub saveIntermediate {
+ local ($final,$suffix,$tmp)= @_ ;
+ local ($to_do);
+
+ local ($new_suffix);
+
+ # $final -- root of where to park ${final}.${suffix}
+ # $tmp -- temporary file where hsc put the intermediate file.
+
+ # HWL: use -odir for .hc and .s files, too
+ if ( $Specific_output_dir ne '' ) {
+ $final = "${Specific_output_dir}/${final}";
+ }
+ # HWL: use the same suffix as for $Osuffix in generating intermediate file,
+ # replacing o with hc or s, respectively.
+ if ( $Osuffix ne '' ) {
+ ($new_suffix = $Osuffix) =~ s/o$/hc/ if $suffix eq "hc";
+ ($new_suffix = $Osuffix) =~ s/o$/s/ if $suffix eq "s";
+ $suffix = $new_suffix;
+ print stderr "HWL says: suffix for intermediate file is $suffix; ${final}.${suffix} overall\n" if $Verbose;
+ }
+
+ # Delete the old file
+ $to_do = "$Rm ${final}.${suffix}"; &run_something($to_do, "Removing old .${suffix} file");
+
+ if ( $#File_options >= 0 ) { # OPTIONS found in Haskell source unit
+ # Add OPTION comment to the top of the generated .${suffix} file
+ open(TEMP, "> ${final}.${suffix}") || &tidy_up_and_die(1,"Can't open ${final}.${suffix}\n");
+ print TEMP "/* OPTIONS " . join(' ',@File_options) . " */\n";
+ close(TEMP);
+ print STDERR "Prepending OPTIONS: " . join(' ',@File_options) . " to ${final}.${suffix}\n" if $Verbose;
+ }
+ $to_do = "$Cat $tmp >> ${final}.${suffix}";
+ &run_something($to_do, "Saving copy of .${suffix} file");
+
+}
+
+\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}\n"; exit $Status; };
+
+ #---------- verbosity and such -----------------------------------------
+ /^-v$/ && do { $Verbose = '-v'; $Time = 'time'; next arg; };
+
+ #---------- what phases are to be run ----------------------------------
+ /^-(no-)?recomp/ && do { $Do_recomp_chkr = ($1 eq '') ? 1 : 0; 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; $HscLang = 'C';
+ next arg; };
+ # stop after generating C
+
+ /^-J$/ && do { $Do_cc = 0; $Do_as = 0; $Do_lnkr = 0; $HscLang = 'java';
+ next arg; };
+ # stop after generating Java
+
+ /^-noC$/ && do { $HscLang = 'none'; $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
+ /^-hi-with-(.*)$/ && do { $HiOnStdout = 1; $HiWith .= " $1" ; $ProduceHi = '-hifile='; next arg; };
+ # limit ourselves to outputting a particular section.
+
+ /^-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; };
+ /^-keep-hi-diffs$/ && do { $Keep_HiDiffs = 1; 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.
+ /^--mk-dll$/ && do { $Only_generate_dll = 1; $Do_as = 0; $Do_lnkr = 0; next arg; };
+ # Build a Win32 DLL (where supported).
+ /^-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; };
+ # don't do consistency-checking after a link
+ /^-no-link-chk$/ && do { $LinkChk = 0; next arg; };
+
+ /^-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++;
+ }
+ }
+ $ProduceHi='-hifile=';
+ 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; };
+ /^-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-dicts$/ && do {
+ $PROFdicts = '-fauto-sccs-on-dicts';
+ next arg; };
+ /^-auto-all$/ && do {
+ $PROFauto = '-fauto-sccs-on-all-toplevs';
+ next arg; };
+ /^-auto$/ && do {
+ $PROFauto = '-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; };
+
+ /^-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/parallel ----------------------------------------------
+ # we sort out the details a bit later on
+
+ /^-gransim$/ && do { $GRANing = 'g'; &add_syslib('concurrent'); next arg; }; # GranSim
+ /^-ticky$/ && do { $TICKYing = 't'; next arg; }; # ticky-ticky
+ /^-parallel$/ && do { $PARing = 'p'; &add_syslib('concurrent'); next arg; }; # parallel Haskell
+ /^-smp$/ && do { $SMPing = 's'; &add_syslib('concurrent'); 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);
+ local($arg) = $1;
+
+ #
+ if ( $arg =~ /;/ ) {
+ $SplitMarker=";";
+ @new_items = split( /;/, &grab_arg_arg(*Args,'-i', $arg));
+ } else {
+ @new_items = split( /:/, &grab_arg_arg(*Args,'-i', $arg));
+ }
+ 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; };
+
+ # DEPRECATED: use -package instead
+ /^-syslib(.*)/ && do { local($syslib) = &grab_arg_arg(*Args,'-syslib',$1);
+ &add_syslib($syslib);
+ next arg; };
+
+ /^-package-name(.*)/ && do
+ { local($package) = &grab_arg_arg(*Args,'-package-name',$1);
+ push(@HsC_flags,"-inpackage=$package");
+ next arg;
+ };
+
+ /^-package(.*)/ && do { local($package) = &grab_arg_arg(*Args,'-package',$1);
+ &add_syslib($package);
+ 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); $Only_preprocess_hc = ($1 eq "-E"); 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; };
+ /^-optdll(.*)$/ && do { push(@Dll_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; };
+
+ #---------- 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; };
+
+ /^-fignore-interface-pragmas$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fignore-asserts$/ && do { push(@HsC_flags, $_); next arg; };
+
+ /^-fno-implicit-prelude$/ && do { $NoImplicitPrelude= 1; push(@HsC_flags, $_); next arg; };
+
+ #
+ # have the compiler proper generate concurrent code,
+ # really only used when you want to configure your own
+ # special user compilation way.
+ #
+ # (ditto for -fgransim, fscc-profiling, -fparallel and -fticky-ticky)
+ #
+ /^-fscc-profiling$/ && do { push(@HsC_flags,$_); next arg; };
+ /^-fticky-ticky$/ && do { push(@HsC_flags,$_); next arg; };
+ /^-fgransim$/ && do { push(@HsC_flags,$_); next arg; };
+ /^-fparallel$/ && do { push(@HsC_flags,$_); next arg; };
+ /^-fsmp$/ && do { push(@HsC_flags,$_); next arg; };
+
+ /^-split-objs$/ && do {
+ if ( $TargetPlatform !~ /^(alpha|hppa1\.1|i386|m68k|mips|powerpc|rs6000|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;
+ $HscLang = '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; };
+
+ /^-unreg$/ && do { $UNREGing = 'u'; next arg; };
+ /^-funregisterised$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fno-asm-mangling$/ && do { $DoAsmMangling = 0; next arg; };
+
+ /^-fallow-overlapping-instances$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fallow-undecidable-instances$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fhistory-size.*$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fdicts-strict$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fglasgow-exts$/
+ && do { push(@HsC_flags, $_);
+
+ # -fglasgow-exts implies -syslib lang
+ &add_syslib('lang');
+
+ next arg; };
+
+ /^-fspeciali[sz]e$/
+ && do { $Oopt_DoSpecialise = '-fspecialise'; next arg; };
+ /^-fno-speciali[sz]e$/
+ && do { $Oopt_DoSpecialise = ''; next arg; };
+
+ /^-fusagesp$/
+ && do { $Oopt_UsageSPInf = '-fusagesp';
+ push (@HsC_flags, '-fusagesp-on'); next arg; };
+
+ /^-fcompiling-prelude$/ && do { $CompilingPrelude=1; push(@HsC_flags, $_); next arg; };
+
+# Now the foldr/build options, which are *on* by default (for -O).
+
+ /^-ffoldr-build$/
+ && do { $Oopt_FoldrBuild = 1;
+ #print "Yes F/B\n";
+ next arg; };
+
+ /^-fno-foldr-build$/
+ && do { $Oopt_FoldrBuild = 0;
+ next arg; };
+
+ # --------------- Renamer -------------
+
+
+ /^-fno-prune-tydecls$/ && do { push(@HsC_flags, $_); next arg; };
+ /^-fno-prune-instdecls$/ && do { push(@HsC_flags, $_); next arg; };
+
+ # ---------------
+
+ /^-fasm-(.*)$/ && do { $HscLang = 'asm'; next arg; }; # force using nativeGen
+ /^-fvia-[cC]$/ && do { $HscLang = 'C'; next arg; }; # force using C compiler
+
+ # ---------------
+
+ /^-funfolding-.*$/
+ && do { push(@HsC_flags, $_); next arg };
+
+ /^-fliberate-case-.*$/
+ && do { push(@HsC_flags, $_); next arg };
+
+ /^-funfold-casms-in-hi-file$/
+ && do { push(@HsC_flags, $_); 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; };
+
+ /^-fno-pre-inlining$/
+ && do { push(@HsC_flags, $_); next arg };
+
+ /^-fno-let-from-(case|app|strict-let)$/ # experimental, really (WDP 95/10)
+ && do { push(@HsC_flags, $_); next arg; };
+
+ /^-funbox-strict-fields$/
+ && do { push(@HsC_flags, $_); next arg; };
+
+ # --------------- Warnings etc. ------
+
+ /^-fwarn-(.*)$/ && do { push(@HsC_flags, $_); next arg; };
+
+ /^-fno-(.*)$/ && do { push(@HsC_antiflags, "-f$1");
+ &squashHscFlag("-f$1");
+ next arg; };
+
+ /^-W$/ && do { push(@HsC_flags, @MinusWOpts); next arg; };
+ /^-Wall$/ && do { push(@HsC_flags, @MinusWallOpts); next arg; };
+ /^(-Wnot|w)$/ && do { foreach (@Hsc_flags) {
+ /^-fwarn-(.*)$/ && do { $_=''; };
+ };
+ push(@HsC_antiflags, @StandardWarnings);
+ next arg; };
+
+ # --------------- fun stuff ----------------
+
+ /^-freport-compile$/ && do { push(@HsC_flags, $_); 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 USP lint
+ /^-dusagesp-lint/ && do { $USPLint = '-dusagesp-lint'; next arg; };
+ /^-dno-usagesp-lint/ && do { $USPLint = ''; 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-stats/ && 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" if $Verbose;
+ }
+ 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" if $Verbose;
+ }
+ 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 { $Static=1; push(@Ld_flags, $_); next arg; };
+ /^-no-hs-main$/ && do { $NoHaskellMain=1; 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;
+
+ $HscLang = 'C'; # 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}