Cleanup after the OPTIONS parsing was moved.
[ghc-hetmet.git] / ghc / compiler / main / DriverPipeline.hs
index 910d491..ac98eff 100644 (file)
@@ -22,14 +22,12 @@ module DriverPipeline (
         -- DLL building
    doMkDLL,
 
-   getOptionsFromStringBuffer, -- used in module GHC
-   optionsErrorMsgs,           -- ditto
   ) where
 
 #include "HsVersions.h"
 
 import Packages
-import GetImports
+import HeaderInfo
 import DriverPhases
 import SysTools                ( newTempName, addFilesToClean, getSysMan, copy )
 import qualified SysTools      
@@ -42,18 +40,14 @@ import ErrUtils
 import DynFlags
 import StaticFlags     ( v_Ld_inputs, opt_Static, WayName(..) )
 import Config
-import RdrName         ( GlobalRdrEnv )
 import Panic
 import Util
 import StringBuffer    ( hGetStringBuffer )
 import BasicTypes      ( SuccessFlag(..) )
 import Maybes          ( expectJust )
-import Ctype           ( is_ident )
-import StringBuffer    ( StringBuffer(..), lexemeToString )
 import ParserCoreUtils ( getCoreModuleName )
-import SrcLoc          ( srcLocSpan, mkSrcLoc )
-import FastString      ( mkFastString )
-import Bag             ( listToBag, emptyBag )
+import SrcLoc          ( unLoc )
+import SrcLoc          ( Located(..) )
 
 import EXCEPTION
 import DATA_IOREF      ( readIORef, writeIORef, IORef )
@@ -63,6 +57,7 @@ import Directory
 import System
 import IO
 import Monad
+import Data.List       ( isSuffixOf )
 import Maybe
 
 
@@ -93,7 +88,6 @@ preprocess dflags (filename, mb_phase) =
 -- NB.  No old interface can also mean that the source has changed.
 
 compile :: HscEnv
-       -> (Messages -> IO ())  -- error message callback
        -> ModSummary
        -> Maybe Linkable       -- Just linkable <=> source unchanged
         -> Maybe ModIface       -- Old interface, if available
@@ -108,9 +102,9 @@ data CompResult
    | CompErrs 
 
 
-compile hsc_env msg_act mod_summary maybe_old_linkable old_iface mod_index nmods = do 
+compile hsc_env mod_summary maybe_old_linkable old_iface mod_index nmods = do 
 
-   let dflags0     = hsc_dflags hsc_env
+   let dflags0     = ms_hspp_opts mod_summary
        this_mod    = ms_mod mod_summary
        src_flavour = ms_hsc_src mod_summary
 
@@ -122,20 +116,9 @@ compile hsc_env msg_act mod_summary maybe_old_linkable old_iface mod_index nmods
 
    let location          = ms_location mod_summary
    let input_fn   = expectJust "compile:hs" (ml_hs_file location) 
-   let input_fnpp = expectJust "compile:hspp" (ms_hspp_file mod_summary)
-
-   debugTraceMsg dflags0 2 ("compile: input file " ++ input_fnpp)
-
-   -- Add in the OPTIONS from the source file
-   -- This is nasty: we've done this once already, in the compilation manager
-   -- It might be better to cache the flags in the ml_hspp_file field,say
-   let hspp_buf = expectJust "compile:hspp_buf" (ms_hspp_buf mod_summary)
-       opts = getOptionsFromStringBuffer hspp_buf
-   (dflags1,unhandled_flags) <- parseDynamicFlags dflags0 (map snd opts)
-   if (not (null unhandled_flags))
-       then do msg_act (optionsErrorMsgs unhandled_flags opts input_fn)
-               return CompErrs
-       else do
+   let input_fnpp = ms_hspp_file mod_summary
+
+   debugTraceMsg dflags0 2 (text "compile: input file" <+> text input_fnpp)
 
    let (basename, _) = splitFilename input_fn
 
@@ -143,8 +126,8 @@ compile hsc_env msg_act mod_summary maybe_old_linkable old_iface mod_index nmods
   -- This is needed when we try to compile the .hc file later, if it
   -- imports a _stub.h file that we created here.
    let current_dir = directoryOf basename
-       old_paths   = includePaths dflags1
-       dflags      = dflags1 { includePaths = current_dir : old_paths }
+       old_paths   = includePaths dflags0
+       dflags      = dflags0 { includePaths = current_dir : old_paths }
 
    -- Figure out what lang we're generating
    let hsc_lang = hscMaybeAdjustTarget dflags StopLn src_flavour (hscTarget dflags)
@@ -156,8 +139,6 @@ compile hsc_env msg_act mod_summary maybe_old_linkable old_iface mod_index nmods
 
    let dflags' = dflags { hscTarget = hsc_lang,
                                hscOutName = output_fn,
-                               hscStubCOutName = basename ++ "_stub.c",
-                               hscStubHOutName = basename ++ "_stub.h",
                                extCoreName = basename ++ ".hcr" }
 
    -- -no-recomp should also work with --make
@@ -166,77 +147,98 @@ compile hsc_env msg_act mod_summary maybe_old_linkable old_iface mod_index nmods
        hsc_env' = hsc_env { hsc_dflags = dflags' }
        object_filename = ml_obj_file location
 
+   let getStubLinkable False = return []
+       getStubLinkable True
+           = do stub_o <- compileStub dflags' this_mod location
+                return [ DotO stub_o ]
+
+       handleBatch (HscNoRecomp, iface, details)
+           = ASSERT (isJust maybe_old_linkable)
+             return (CompOK details iface maybe_old_linkable)
+       handleBatch (HscRecomp hasStub, iface, details)
+           | isHsBoot src_flavour
+               = return (CompOK details iface Nothing)
+           | otherwise
+               = do stub_unlinked <- getStubLinkable hasStub
+                    (hs_unlinked, unlinked_time) <-
+                        case hsc_lang of
+                          HscNothing
+                            -> return ([], ms_hs_date mod_summary)
+                          -- We're in --make mode: finish the compilation pipeline.
+                          _other
+                            -> do runPipeline StopLn dflags (output_fn,Nothing) Persistent
+                                              (Just location)
+                                  -- The object filename comes from the ModLocation
+                                  o_time <- getModificationTime object_filename
+                                  return ([DotO object_filename], o_time)
+                    let linkable = LM unlinked_time this_mod
+                                  (hs_unlinked ++ stub_unlinked)
+                    return (CompOK details iface (Just linkable))
+
+       handleInterpreted (InteractiveNoRecomp, iface, details)
+           = ASSERT (isJust maybe_old_linkable)
+             return (CompOK details iface maybe_old_linkable)
+       handleInterpreted (InteractiveRecomp hasStub comp_bc, iface, details)
+           = do stub_unlinked <- getStubLinkable hasStub
+                let hs_unlinked = [BCOs comp_bc]
+                    unlinked_time = ms_hs_date mod_summary
+                  -- Why do we use the timestamp of the source file here,
+                  -- rather than the current time?  This works better in
+                  -- the case where the local clock is out of sync
+                  -- with the filesystem's clock.  It's just as accurate:
+                  -- if the source is modified, then the linkable will
+                  -- be out of date.
+                let linkable = LM unlinked_time this_mod
+                               (hs_unlinked ++ stub_unlinked)
+                return (CompOK details iface (Just linkable))
+
+   let runCompiler compiler handle
+           = do mbResult <- compiler hsc_env' mod_summary
+                                     source_unchanged old_iface
+                                     (Just (mod_index, nmods))
+                case mbResult of
+                  Nothing     -> return CompErrs
+                  Just result -> handle result
    -- run the compiler
-   hsc_result <- hscMain hsc_env' msg_act mod_summary
-                        source_unchanged have_object old_iface
-                         (Just (mod_index, nmods))
-
-   case hsc_result of
-      HscFail -> return CompErrs
-
-      HscNoRecomp details iface -> 
-         ASSERT(isJust maybe_old_linkable)
-         return (CompOK details iface maybe_old_linkable)
-
-      HscRecomp details iface stub_h_exists stub_c_exists maybe_interpreted_code 
-
-       | isHsBoot src_flavour  -- No further compilation to do
-       -> do   case hsc_lang of
-                  HscInterpreted -> return ()
-                  _other -> SysTools.touch dflags' "Touching object file" 
-                                           object_filename
-               return (CompOK details iface Nothing)
-
-       | otherwise     -- Normal source file
-       -> do
-          maybe_stub_o <- compileStub dflags' stub_c_exists
-          let stub_unlinked = case maybe_stub_o of
-                                 Nothing -> []
-                                 Just stub_o -> [ DotO stub_o ]
-
-          (hs_unlinked, unlinked_time) <-
-            case hsc_lang of
-
-               -- in interpreted mode, just return the compiled code
-               -- as our "unlinked" object.
-               HscInterpreted
-                 -> case maybe_interpreted_code of
-#ifdef GHCI
-                      Just comp_bc -> return ([BCOs comp_bc], ms_hs_date mod_summary)
-                       -- Why do we use the timestamp of the source file here,
-                       -- rather than the current time?  This works better in
-                       -- the case where the local clock is out of sync
-                       -- with the filesystem's clock.  It's just as accurate:
-                       -- if the source is modified, then the linkable will
-                       -- be out of date.
-#endif
-                      Nothing -> panic "compile: no interpreted code"
-
-               -- We're in --make mode: finish the compilation pipeline.
-               _other
-                 -> do runPipeline StopLn dflags (output_fn,Nothing) Persistent
-                                   (Just location)
-                               -- The object filename comes from the ModLocation
-
-                       o_time <- getModificationTime object_filename
-                       return ([DotO object_filename], o_time)
-
-          let linkable = LM unlinked_time this_mod
-                            (hs_unlinked ++ stub_unlinked)
-
-          return (CompOK details iface (Just linkable))
+   case hsc_lang of
+     HscInterpreted | not (isHsBoot src_flavour) -- We can't compile boot files to
+                                                 -- bytecode so don't even try.
+         -> runCompiler hscCompileInteractive handleInterpreted
+     HscNothing
+         -> runCompiler hscCompileNothing handleBatch
+     _other
+         -> runCompiler hscCompileBatch handleBatch
 
 -----------------------------------------------------------------------------
 -- stub .h and .c files (for foreign export support)
 
-compileStub dflags stub_c_exists
-  | not stub_c_exists = return Nothing
-  | stub_c_exists = do
+-- The _stub.c file is derived from the haskell source file, possibly taking
+-- into account the -stubdir option.
+--
+-- Consequently, we derive the _stub.o filename from the haskell object
+-- filename.  
+--
+-- This isn't necessarily the same as the object filename we
+-- would get if we just compiled the _stub.c file using the pipeline.
+-- For example:
+--
+--    ghc src/A.hs -odir obj
+-- 
+-- results in obj/A.o, and src/A_stub.c.  If we compile src/A_stub.c with
+-- -odir obj, we would get obj/src/A_stub.o, which is wrong; we want
+-- obj/A_stub.o.
+
+compileStub :: DynFlags -> Module -> ModLocation -> IO FilePath
+compileStub dflags mod location = do
+       let (o_base, o_ext) = splitFilename (ml_obj_file location)
+           stub_o = o_base ++ "_stub" `joinFileExt` o_ext
+
        -- compile the _stub.c file w/ gcc
-       let stub_c = hscStubCOutName dflags
-       (_, stub_o) <- runPipeline StopLn dflags
-                           (stub_c,Nothing) Persistent Nothing{-no ModLocation-}
-       return (Just stub_o)
+       let (stub_c,_) = mkStubPaths dflags mod location
+       runPipeline StopLn dflags (stub_c,Nothing) 
+               (SpecificFile stub_o) Nothing{-no ModLocation-}
+
+       return stub_o
 
 
 -- ---------------------------------------------------------------------------
@@ -274,33 +276,52 @@ link BatchCompile dflags batch_attempt_linking hpt
            pkg_deps  = concatMap (dep_pkgs . mi_deps . hm_iface) home_mod_infos
 
            -- the linkables to link
-           linkables = map (fromJust.hm_linkable) home_mod_infos
+           linkables = map (expectJust "link".hm_linkable) home_mod_infos
 
-        debugTraceMsg dflags 3 "link: linkables are ..."
-        debugTraceMsg dflags 3 (showSDoc (vcat (map ppr linkables)))
+        debugTraceMsg dflags 3 (text "link: linkables are ..." $$ vcat (map ppr linkables))
 
        -- check for the -no-link flag
        if isNoLink (ghcLink dflags)
-         then do debugTraceMsg dflags 3 "link(batch): linking omitted (-c flag given)."
+         then do debugTraceMsg dflags 3 (text "link(batch): linking omitted (-c flag given).")
                  return Succeeded
          else do
 
-       debugTraceMsg dflags 1 "Linking ..."
-
        let getOfiles (LM _ _ us) = map nameOfObject (filter isObject us)
            obj_files = concatMap getOfiles linkables
 
+           exe_file = exeFileName dflags
+
+       -- if the modification time on the executable is later than the
+       -- modification times on all of the objects, then omit linking
+       -- (unless the -no-recomp flag was given).
+       e_exe_time <- IO.try $ getModificationTime exe_file
+       let linking_needed 
+               | Left _  <- e_exe_time = True
+               | Right t <- e_exe_time = 
+                       any (t <) (map linkableTime linkables)
+
+       if dopt Opt_RecompChecking dflags && not linking_needed
+          then do debugTraceMsg dflags 1 (text exe_file <+> ptext SLIT("is up to date, linking not required."))
+                  return Succeeded
+          else do
+
+       debugTraceMsg dflags 1 (ptext SLIT("Linking") <+> text exe_file
+                                <+> text "...")
+
        -- Don't showPass in Batch mode; doLink will do that for us.
-        staticLink dflags obj_files pkg_deps
+       let link = case ghcLink dflags of
+               MkDLL       -> doMkDLL
+               StaticLink  -> staticLink
+       link dflags obj_files pkg_deps
 
-        debugTraceMsg dflags 3 "link: done"
+        debugTraceMsg dflags 3 (text "link: done")
 
        -- staticLink only returns if it succeeds
         return Succeeded
 
    | otherwise
-   = do debugTraceMsg dflags 3 "link(batch): upsweep (partially) failed OR"
-        debugTraceMsg dflags 3 "   Main.main not exported; not linking."
+   = do debugTraceMsg dflags 3 (text "link(batch): upsweep (partially) failed OR" $$
+                                text "   Main.main not exported; not linking.")
         return Succeeded
       
 
@@ -470,7 +491,7 @@ getOutputFilename dflags stop_phase output basename
  = func
  where
        hcsuf      = hcSuf dflags
-       odir       = outputDir dflags
+       odir       = objectDir dflags
        osuf       = objectSuf dflags
        keep_hc    = dopt Opt_KeepHcFiles dflags
        keep_raw_s = dopt Opt_KeepRawSFiles dflags
@@ -508,7 +529,7 @@ getOutputFilename dflags stop_phase output basename
 
                odir_persistent
                   | Just loc <- maybe_location = ml_obj_file loc
-                  | Just d <- odir = replaceFilenameDirectory persistent d
+                  | Just d <- odir = d `joinFileName` persistent
                   | otherwise      = persistent
 
 
@@ -563,8 +584,8 @@ runPhase (Unlit sf) _stop dflags _basename _suff input_fn get_output_fn maybe_lo
 --            (b) runs cpp if necessary
 
 runPhase (Cpp sf) _stop dflags0 basename suff input_fn get_output_fn maybe_loc
-  = do src_opts <- getOptionsFromSource input_fn
-       (dflags,unhandled_flags) <- parseDynamicFlags dflags0 src_opts
+  = do src_opts <- getOptionsFromFile input_fn
+       (dflags,unhandled_flags) <- parseDynamicFlags dflags0 (map unLoc src_opts)
        checkProcessArgsResult unhandled_flags (basename `joinFileExt` suff)
 
        if not (dopt Opt_Cpp dflags) then
@@ -621,7 +642,7 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
                                  ; return (Nothing, mkModule m) }
 
                other -> do { buf <- hGetStringBuffer input_fn
-                           ; (_,_,mod_name) <- getImports dflags buf input_fn
+                           ; (_,_,L _ mod_name) <- getImports dflags buf input_fn
                            ; return (Just buf, mod_name) }
 
   -- Build a ModLocation to pass to hscMain.
@@ -662,7 +683,8 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
                -- Some fields are not looked at by hscMain
            mod_summary = ModSummary {  ms_mod       = mod_name, 
                                        ms_hsc_src   = src_flavour,
-                                       ms_hspp_file = Just input_fn,
+                                       ms_hspp_file = input_fn,
+                                        ms_hspp_opts = dflags,
                                        ms_hspp_buf  = hspp_buf,
                                        ms_location  = location4,
                                        ms_hs_date   = src_timestamp,
@@ -703,8 +725,6 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
 
         let dflags' = dflags { hscTarget = hsc_lang,
                               hscOutName = output_fn,
-                              hscStubCOutName = basename ++ "_stub.c",
-                              hscStubHOutName = basename ++ "_stub.h",
                               extCoreName = basename ++ ".hcr" }
 
        hsc_env <- newHscEnv dflags'
@@ -713,40 +733,28 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
        addHomeModuleToFinder hsc_env mod_name location4
 
   -- run the compiler!
-       result <- hscMain hsc_env printErrorsAndWarnings
+       mbResult <- hscCompileOneShot hsc_env
                          mod_summary source_unchanged 
-                         False         -- No object file
                          Nothing       -- No iface
                           Nothing       -- No "module i of n" progress info
 
-       case result of
-
-           HscFail -> throwDyn (PhaseFailed "hsc" (ExitFailure 1))
-
-            HscNoRecomp details iface -> do
-               SysTools.touch dflags' "Touching object file" o_file
-                       -- The .o file must have a later modification date
-                       -- than the source file (else we wouldn't be in HscNoRecomp)
-                       -- but we touch it anyway, to keep 'make' happy (we think).
-               return (StopLn, dflags', Just location4, o_file)
-
-           HscRecomp _details _iface 
-                     stub_h_exists stub_c_exists
-                     _maybe_interpreted_code -> do
-
-               -- Deal with stubs 
-               maybe_stub_o <- compileStub dflags' stub_c_exists
-               case maybe_stub_o of
-                     Nothing     -> return ()
-                     Just stub_o -> consIORef v_Ld_inputs stub_o
-
-               -- In the case of hs-boot files, generate a dummy .o-boot 
-               -- stamp file for the benefit of Make
-               case src_flavour of
-                 HsBootFile -> SysTools.touch dflags' "Touching object file" o_file
-                 other      -> return ()
-
-               return (next_phase, dflags', Just location4, output_fn)
+       case mbResult of
+          Nothing -> throwDyn (PhaseFailed "hsc" (ExitFailure 1))
+          Just HscNoRecomp
+              -> do SysTools.touch dflags' "Touching object file" o_file
+                    -- The .o file must have a later modification date
+                    -- than the source file (else we wouldn't be in HscNoRecomp)
+                    -- but we touch it anyway, to keep 'make' happy (we think).
+                    return (StopLn, dflags', Just location4, o_file)
+          Just (HscRecomp hasStub)
+              -> do when hasStub $
+                         do stub_o <- compileStub dflags' mod_name location4
+                            consIORef v_Ld_inputs stub_o
+                    -- In the case of hs-boot files, generate a dummy .o-boot 
+                    -- stamp file for the benefit of Make
+                    when (isHsBoot src_flavour) $
+                      SysTools.touch dflags' "Touching object file" o_file
+                    return (next_phase, dflags', Just location4, output_fn)
 
 -----------------------------------------------------------------------------
 -- Cmm phase
@@ -765,8 +773,6 @@ runPhase Cmm stop dflags basename suff input_fn get_output_fn maybe_loc
 
         let dflags' = dflags { hscTarget = hsc_lang,
                               hscOutName = output_fn,
-                              hscStubCOutName = basename ++ "_stub.c",
-                              hscStubHOutName = basename ++ "_stub.h",
                               extCoreName = basename ++ ".hcr" }
 
        ok <- hscCmmFile dflags' input_fn
@@ -811,6 +817,9 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
 
        let excessPrecision = dopt Opt_ExcessPrecision dflags
 
+       let cc_opt | optLevel dflags >= 2 = "-O2"
+                  | otherwise            = "-O"
+
        -- Decide next phase
        
         let mangle = dopt Opt_DoAsmMangling dflags
@@ -819,6 +828,23 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
                | otherwise         = As
        output_fn <- get_output_fn next_phase maybe_loc
 
+       let
+         more_hcc_opts =
+#if i386_TARGET_ARCH
+               -- on x86 the floating point regs have greater precision
+               -- than a double, which leads to unpredictable results.
+               -- By default, we turn this off with -ffloat-store unless
+               -- the user specified -fexcess-precision.
+               (if excessPrecision then [] else [ "-ffloat-store" ]) ++
+#endif
+               -- gcc's -fstrict-aliasing allows two accesses to memory
+               -- to be considered non-aliasing if they have different types.
+               -- This interacts badly with the C code we generate, which is
+               -- very weakly typed, being derived from C--.
+               ["-fno-strict-aliasing"]
+
+
+
        SysTools.runCc dflags (
                -- force the C compiler to interpret this file as C when
                -- compiling .hc files, by adding the -x c option.
@@ -835,11 +861,13 @@ runPhase cc_phase stop dflags basename suff input_fn get_output_fn maybe_loc
                       ++ (if hcc && mangle
                             then md_regd_c_flags
                             else [])
-                      ++ [ verb, "-S", "-Wimplicit", "-O" ]
+                      ++ (if hcc 
+                            then more_hcc_opts
+                            else [])
+                      ++ [ verb, "-S", "-Wimplicit", cc_opt ]
                       ++ [ "-D__GLASGOW_HASKELL__="++cProjectVersionInt ]
                       ++ cc_opts
                       ++ split_opt
-                      ++ (if excessPrecision then [] else [ "-ffloat-store" ])
                       ++ include_paths
                       ++ pkg_extra_cc_opts
                       ))
@@ -927,34 +955,64 @@ runPhase As stop dflags _basename _suff input_fn get_output_fn maybe_loc
 
 
 runPhase SplitAs stop dflags basename _suff _input_fn get_output_fn maybe_loc
-  = do  let as_opts = getOpts dflags opt_a
+  = do  
+       output_fn <- get_output_fn StopLn maybe_loc
+
+       let (base_o, _) = splitFilename output_fn
+           split_odir  = base_o ++ "_split"
+           osuf = objectSuf dflags
+
+       createDirectoryHierarchy split_odir
+
+       -- remove M_split/ *.o, because we're going to archive M_split/ *.o
+       -- later and we don't want to pick up any old objects.
+       fs <- getDirectoryContents split_odir 
+       mapM_ removeFile $ map (split_odir `joinFileName`)
+                        $ filter (osuf `isSuffixOf`) fs
+
+       let as_opts = getOpts dflags opt_a
 
        (split_s_prefix, n) <- readIORef v_Split_info
 
-       let real_odir
-               | Just d <- outputDir dflags = d
-               | otherwise                  = basename ++ "_split"
+       let split_s   n = split_s_prefix ++ "__" ++ show n `joinFileExt` "s"
+           split_obj n = split_odir `joinFileName`
+                               filenameOf base_o ++ "__" ++ show n
+                                       `joinFileExt` osuf
 
        let assemble_file n
-             = do  let input_s  = split_s_prefix ++ "__" ++ show n ++ ".s"
-                   let output_o = replaceFilenameDirectory
-                                       (basename ++ "__" ++ show n ++ ".o")
-                                        real_odir
-                   let osuf = objectSuf dflags
-                   let real_o = replaceFilenameSuffix output_o osuf
-                   SysTools.runAs dflags
-                                (map SysTools.Option as_opts ++
-                                   [ SysTools.Option "-c"
-                                   , SysTools.Option "-o"
-                                   , SysTools.FileOption "" real_o
-                                   , SysTools.FileOption "" input_s
-                                   ])
+             = SysTools.runAs dflags
+                        (map SysTools.Option as_opts ++
+                        [ SysTools.Option "-c"
+                        , SysTools.Option "-o"
+                        , SysTools.FileOption "" (split_obj n)
+                        , SysTools.FileOption "" (split_s n)
+                        ])
        
        mapM_ assemble_file [1..n]
 
-       output_fn <- get_output_fn StopLn maybe_loc
+       -- and join the split objects into a single object file:
+       let ld_r args = SysTools.runLink dflags ([ 
+                               SysTools.Option "-nostdlib",
+                               SysTools.Option "-nodefaultlibs",
+                               SysTools.Option "-Wl,-r", 
+                               SysTools.Option ld_x_flag, 
+                               SysTools.Option "-o", 
+                               SysTools.FileOption "" output_fn ] ++ args)
+            ld_x_flag | null cLD_X = ""
+                     | otherwise  = "-Wl,-x"     
+
+       if cLdIsGNULd == "YES"
+           then do 
+                 let script = split_odir `joinFileName` "ld.script"
+                 writeFile script $
+                     "INPUT(" ++ unwords (map split_obj [1..n]) ++ ")"
+                 ld_r [SysTools.FileOption "" script]
+           else do
+                 ld_r (map (SysTools.FileOption "" . split_obj) [1..n])
+
        return (StopLn, dflags, maybe_loc, output_fn)
 
+
 -----------------------------------------------------------------------------
 -- MoveBinary sort-of-phase
 -- After having produced a binary, move it somewhere else and generate a
@@ -1078,18 +1136,12 @@ getHCFilePackages filename =
 staticLink :: DynFlags -> [FilePath] -> [PackageId] -> IO ()
 staticLink dflags o_files dep_packages = do
     let verb = getVerbFlag dflags
+        output_fn = exeFileName dflags
 
     -- get the full list of packages to link with, by combining the
     -- explicit packages with the auto packages and all of their
     -- dependencies, and eliminating duplicates.
 
-    let o_file = outputFile dflags
-#if defined(mingw32_HOST_OS)
-    let output_fn = case o_file of { Just s -> s; Nothing -> "main.exe"; }
-#else
-    let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }
-#endif
-
     pkg_lib_paths <- getPackageLibraryPath dflags dep_packages
     let pkg_lib_path_opts = map ("-L"++) pkg_lib_paths
 
@@ -1175,6 +1227,24 @@ staticLink dflags o_files dep_packages = do
              if success then return ()
                         else throwDyn (InstallationError ("cannot move binary to PVM dir")))
 
+
+exeFileName :: DynFlags -> FilePath
+exeFileName dflags
+  | Just s <- outputFile dflags = 
+#if defined(mingw32_HOST_OS)
+      if null (suffixOf s)
+        then s `joinFileExt` "exe"
+        else s
+#else
+      s
+#endif
+  | otherwise = 
+#if defined(mingw32_HOST_OS)
+       "main.exe"
+#else
+       "a.out"
+#endif
+
 -----------------------------------------------------------------------------
 -- Making a DLL (only for Win32)
 
@@ -1297,88 +1367,6 @@ hsSourceCppOpts =
        , "-D__CONCURRENT_HASKELL__"
        ]
 
------------------------------------------------------------------------------
--- Reading OPTIONS pragmas
-
-getOptionsFromSource 
-       :: String               -- input file
-       -> IO [String]          -- options, if any
-getOptionsFromSource file
-  = do h <- openFile file ReadMode
-       look h `finally` hClose h
-  where
-       look h = do
-           r <- tryJust ioErrors (hGetLine h)
-           case r of
-             Left e | isEOFError e -> return []
-                    | otherwise    -> ioError e
-             Right l' -> do
-               let l = removeSpaces l'
-               case () of
-                   () | null l -> look h
-                      | prefixMatch "#" l -> look h
-                      | prefixMatch "{-# LINE" l -> look h   -- -}
-                      | Just opts <- matchOptions l
-                       -> do rest <- look h
-                              return (opts ++ rest)
-                      | otherwise -> return []
-
-getOptionsFromStringBuffer :: StringBuffer -> [(Int,String)]
-getOptionsFromStringBuffer buffer@(StringBuffer _ len# _) = 
-  let 
-       ls = lines (lexemeToString buffer (I# len#))  -- lazy, so it's ok
-  in
-  look 1 ls
-  where
-       look i [] = []
-       look i (l':ls) = do
-           let l = removeSpaces l'
-           case () of
-               () | null l -> look (i+1) ls
-                  | prefixMatch "#" l -> look (i+1) ls
-                  | prefixMatch "{-# LINE" l -> look (i+1) ls   -- -}
-                  | Just opts <- matchOptions l
-                       -> zip (repeat i) opts ++ look (i+1) ls
-                  | otherwise -> []
-
--- detect {-# OPTIONS_GHC ... #-}.  For the time being, we accept OPTIONS
--- instead of OPTIONS_GHC, but that is deprecated.
-matchOptions s
-  | Just s1 <- maybePrefixMatch "{-#" s -- -} 
-  = matchOptions1 (removeSpaces s1)
-  | otherwise
-  = Nothing
- where
-  matchOptions1 s
-    | Just s2 <- maybePrefixMatch "OPTIONS" s
-    = case () of
-       _ | Just s3 <- maybePrefixMatch "_GHC" s2, not (is_ident (head s3))
-         -> matchOptions2 s3
-         | not (is_ident (head s2))
-         -> matchOptions2 s2
-         | otherwise
-         -> Just []  -- OPTIONS_anything is ignored, not treated as start of source
-    | Just s2 <- maybePrefixMatch "INCLUDE" s, not (is_ident (head s2)),
-      Just s3 <- maybePrefixMatch "}-#" (reverse s2)
-    = Just ["-#include", removeSpaces (reverse s3)]
-    | otherwise = Nothing
-  matchOptions2 s
-    | Just s3 <- maybePrefixMatch "}-#" (reverse s) = Just (words (reverse s3))
-    | otherwise = Nothing
-
-
-optionsErrorMsgs :: [String] -> [(Int,String)] -> FilePath -> Messages
-optionsErrorMsgs unhandled_flags flags_lines filename
-  = (emptyBag, listToBag (map mkMsg unhandled_flags_lines))
-  where
-       unhandled_flags_lines = [ (l,f) | f <- unhandled_flags, 
-                                         (l,f') <- flags_lines, f == f' ]
-       mkMsg (line,flag) = 
-           ErrUtils.mkPlainErrMsg (srcLocSpan loc) $
-               text "unknown flag in  {-# OPTIONS #-} pragma:" <+> text flag
-         where
-               loc = mkSrcLoc (mkFastString filename) line 0
-               -- ToDo: we need a better SrcSpan here
 
 -- -----------------------------------------------------------------------------
 -- Misc.