-O2 implies -optc-O2 now
[ghc-hetmet.git] / ghc / compiler / main / DriverPipeline.hs
index 75c2661..039c18a 100644 (file)
@@ -9,7 +9,7 @@
 module DriverPipeline (
        -- Run a series of compilation steps in a pipeline, for a
        -- collection of source files.
-   oneShot,
+   oneShot, compileFile,
 
        -- Interfaces for the batch-mode driver
    staticLink,
@@ -22,7 +22,8 @@ module DriverPipeline (
         -- DLL building
    doMkDLL,
 
-   matchOptions, -- used in module GHC
+   getOptionsFromStringBuffer, -- used in module GHC
+   optionsErrorMsgs,           -- ditto
   ) where
 
 #include "HsVersions.h"
@@ -41,18 +42,24 @@ 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          ( Located(..) )
 
-import ParserCoreUtils ( getCoreModuleName )
+import Distribution.Compiler ( extensionsToGHCFlag )
 
 import EXCEPTION
 import DATA_IOREF      ( readIORef, writeIORef, IORef )
+import GLAEXTS         ( Int(..) )
 
 import Directory
 import System
@@ -70,10 +77,10 @@ import Maybe
 -- We return the augmented DynFlags, because they contain the result
 -- of slurping in the OPTIONS pragmas
 
-preprocess :: DynFlags -> FilePath -> IO (DynFlags, FilePath)
-preprocess dflags filename =
-  ASSERT2(isHaskellSrcFilename filename, text filename) 
-  runPipeline anyHsc dflags filename Temporary Nothing{-no ModLocation-}
+preprocess :: DynFlags -> (FilePath, Maybe Phase) -> IO (DynFlags, FilePath)
+preprocess dflags (filename, mb_phase) =
+  ASSERT2(isJust mb_phase || isHaskellSrcFilename filename, text filename) 
+  runPipeline anyHsc dflags (filename, mb_phase) Temporary Nothing{-no ModLocation-}
 
 -- ---------------------------------------------------------------------------
 -- Compile
@@ -91,6 +98,7 @@ compile :: HscEnv
        -> ModSummary
        -> Maybe Linkable       -- Just linkable <=> source unchanged
         -> Maybe ModIface       -- Old interface, if available
+        -> Int -> Int
         -> IO CompResult
 
 data CompResult
@@ -101,7 +109,7 @@ data CompResult
    | CompErrs 
 
 
-compile hsc_env mod_summary maybe_old_linkable old_iface = do 
+compile hsc_env mod_summary maybe_old_linkable old_iface mod_index nmods = do 
 
    let dflags0     = hsc_dflags hsc_env
        this_mod    = ms_mod mod_summary
@@ -113,19 +121,22 @@ compile hsc_env mod_summary maybe_old_linkable old_iface = do
 
    showPass dflags0 ("Compiling " ++ showModMsg have_object mod_summary)
 
-   let verb      = verbosity dflags0
    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)
 
-   when (verb >= 2) (hPutStrLn stderr ("compile: input file " ++ input_fnpp))
+   debugTraceMsg dflags0 2 (text "compile: input file" <+> text 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
-   opts <- getOptionsFromSource input_fnpp
-   (dflags1,unhandled_flags) <- parseDynamicFlags dflags0 opts
-   checkProcessArgsResult unhandled_flags input_fn
+   let hspp_buf = expectJust "compile:hspp_buf" (ms_hspp_buf mod_summary)
+       opts = getOptionsFromStringBuffer hspp_buf input_fn
+   (dflags1,unhandled_flags) <- parseDynamicFlags dflags0 (map snd opts)
+   if (not (null unhandled_flags))
+       then do printErrorsAndWarnings dflags1 (optionsErrorMsgs unhandled_flags opts input_fn)
+               return CompErrs
+       else do
 
    let (basename, _) = splitFilename input_fn
 
@@ -146,18 +157,18 @@ compile hsc_env mod_summary maybe_old_linkable old_iface = do
 
    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
    let do_recomp = dopt Opt_RecompChecking dflags
        source_unchanged = isJust maybe_old_linkable && do_recomp
        hsc_env' = hsc_env { hsc_dflags = dflags' }
+       object_filename = ml_obj_file location
 
    -- run the compiler
-   hsc_result <- hscMain hsc_env' printErrorsAndWarnings mod_summary
+   hsc_result <- hscMain hsc_env' mod_summary
                         source_unchanged have_object old_iface
+                         (Just (mod_index, nmods))
 
    case hsc_result of
       HscFail -> return CompErrs
@@ -166,27 +177,31 @@ compile hsc_env mod_summary maybe_old_linkable old_iface = do
          ASSERT(isJust maybe_old_linkable)
          return (CompOK details iface maybe_old_linkable)
 
-      HscRecomp details iface
-               stub_h_exists stub_c_exists maybe_interpreted_code 
+      HscRecomp details iface stub_h_exists stub_c_exists maybe_interpreted_code 
 
        | isHsBoot src_flavour  -- No further compilation to do
-       -> return (CompOK details iface Nothing)
+       -> do   case hsc_lang of
+                  HscInterpreted -> return ()
+                  _other -> SysTools.touch dflags' "Touching object file" 
+                                           object_filename
+               return (CompOK details iface Nothing)
 
-       | otherwise             -- Normal Haskell source files
+       | otherwise     -- Normal source file
        -> do
-          let 
-          maybe_stub_o <- compileStub dflags' stub_c_exists
-          let stub_unlinked = case maybe_stub_o of
-                                 Nothing -> []
-                                 Just stub_o -> [ DotO stub_o ]
+          stub_unlinked <-
+            if stub_c_exists then do
+               stub_o <- compileStub dflags' this_mod location
+               return [ DotO stub_o ]
+            else
+               return []
 
           (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
+               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,
@@ -198,16 +213,17 @@ compile hsc_env mod_summary maybe_old_linkable old_iface = do
 #endif
                       Nothing -> panic "compile: no interpreted code"
 
-               -- we're in batch mode: finish the compilation pipeline.
-               _other -> do
-                  let object_filename = ml_obj_file location
+               HscNothing
+                 -> return ([], ms_hs_date mod_summary)
 
-                  runPipeline StopLn dflags output_fn Persistent
-                              (Just location)
-                       -- the object filename comes from the ModLocation
+               -- 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)
+                       o_time <- getModificationTime object_filename
+                       return ([DotO object_filename], o_time)
 
           let linkable = LM unlinked_time this_mod
                             (hs_unlinked ++ stub_unlinked)
@@ -217,14 +233,33 @@ compile hsc_env mod_summary maybe_old_linkable old_iface = do
 -----------------------------------------------------------------------------
 -- 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 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
 
 
 -- ---------------------------------------------------------------------------
@@ -249,6 +284,9 @@ link Interactive dflags batch_attempt_linking hpt
         return Succeeded
 #endif
 
+link JustTypecheck dflags batch_attempt_linking hpt
+   = return Succeeded
+
 link BatchCompile dflags batch_attempt_linking hpt
    | batch_attempt_linking
    = do 
@@ -261,50 +299,63 @@ link BatchCompile dflags batch_attempt_linking hpt
            -- the linkables to link
            linkables = map (fromJust.hm_linkable) home_mod_infos
 
-        when (verb >= 3) $ do
-            hPutStrLn stderr "link: linkables are ..."
-             hPutStrLn stderr (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 when (verb >= 3) $
-                   hPutStrLn stderr "link(batch): linking omitted (-c flag given)."
+         then do debugTraceMsg dflags 3 (text "link(batch): linking omitted (-c flag given).")
                  return Succeeded
          else do
 
-       when (verb >= 1) $
-             hPutStrLn stderr "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
 
-        when (verb >= 3) (hPutStrLn stderr "link: done")
+        debugTraceMsg dflags 3 (text "link: done")
 
        -- staticLink only returns if it succeeds
         return Succeeded
 
    | otherwise
-   = do when (verb >= 3) $ do
-           hPutStrLn stderr "link(batch): upsweep (partially) failed OR"
-            hPutStrLn stderr "   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
-   where
-      verb = verbosity dflags
       
 
 -- -----------------------------------------------------------------------------
 -- Compile files in one-shot mode.
 
-oneShot :: DynFlags -> Phase -> [String] -> IO ()
+oneShot :: DynFlags -> Phase -> [(String, Maybe Phase)] -> IO ()
 oneShot dflags stop_phase srcs = do
   o_files <- mapM (compileFile dflags stop_phase) srcs
   doLink dflags stop_phase o_files
 
-compileFile :: DynFlags -> Phase -> FilePath -> IO FilePath
-compileFile dflags stop_phase src = do
+compileFile :: DynFlags -> Phase -> (FilePath, Maybe Phase) -> IO FilePath
+compileFile dflags stop_phase (src, mb_phase) = do
    exists <- doesFileExist src
    when (not exists) $ 
        throwDyn (CmdLineError ("does not exist: " ++ src))
@@ -328,7 +379,7 @@ compileFile dflags stop_phase src = do
                        other      -> stop_phase
 
    (_, out_file) <- runPipeline stop_phase' dflags
-                         src output Nothing{-no ModLocation-}
+                         (src, mb_phase) output Nothing{-no ModLocation-}
    return out_file
 
 
@@ -373,17 +424,21 @@ data PipelineOutput
        -- the output must go into the specified file.
 
 runPipeline
-  :: Phase             -- When to stop
-  -> DynFlags          -- Dynamic flags
-  -> FilePath          -- Input filename
-  -> PipelineOutput    -- Output filename
-  -> Maybe ModLocation  -- A ModLocation, if this is a Haskell module
+  :: Phase                     -- When to stop
+  -> DynFlags                  -- Dynamic flags
+  -> (FilePath,Maybe Phase)     -- Input filename (and maybe -x suffix)
+  -> PipelineOutput            -- Output filename
+  -> Maybe ModLocation          -- A ModLocation, if this is a Haskell module
   -> IO (DynFlags, FilePath)   -- (final flags, output filename)
 
-runPipeline stop_phase dflags input_fn output maybe_loc
+runPipeline stop_phase dflags (input_fn, mb_phase) output maybe_loc
   = do
   let (basename, suffix) = splitFilename input_fn
-      start_phase = startPhase suffix
+
+       -- If we were given a -x flag, then use that phase to start from
+      start_phase
+       | Just x_phase <- mb_phase = x_phase
+       | otherwise                = startPhase suffix
 
   -- We want to catch cases of "you can't get there from here" before
   -- we start the pipeline, because otherwise it will just run off the
@@ -457,7 +512,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
@@ -491,11 +546,11 @@ getOutputFilename dflags stop_phase output basename
                   | StopLn <- next_phase = return odir_persistent
                   | otherwise            = return persistent
 
-               persistent = basename ++ '.':suffix
+               persistent = basename `joinFileExt` suffix
 
                odir_persistent
                   | Just loc <- maybe_location = ml_obj_file loc
-                  | Just d <- odir = replaceFilenameDirectory persistent d
+                  | Just d <- odir = d `joinFileName` persistent
                   | otherwise      = persistent
 
 
@@ -552,7 +607,7 @@ runPhase (Unlit sf) _stop dflags _basename _suff input_fn get_output_fn maybe_lo
 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
-       checkProcessArgsResult unhandled_flags (basename++'.':suff)
+       checkProcessArgsResult unhandled_flags (basename `joinFileExt` suff)
 
        if not (dopt Opt_Cpp dflags) then
            -- no need to preprocess CPP, just pass input file along
@@ -573,7 +628,7 @@ runPhase (HsPp sf) _stop dflags basename suff input_fn get_output_fn maybe_loc
           return (Hsc sf, dflags, maybe_loc, input_fn)
        else do
            let hspp_opts = getOpts dflags opt_F
-           let orig_fn = basename ++ '.':suff
+           let orig_fn = basename `joinFileExt` suff
            output_fn <- get_output_fn (Hsc sf) maybe_loc
            SysTools.runPp dflags
                           ( [ SysTools.Option     orig_fn
@@ -608,7 +663,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.
@@ -643,7 +698,7 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
                      | otherwise = location3
 
   -- Make the ModSummary to hand to hscMain
-       src_timestamp <- getModificationTime (basename ++ '.':suff)
+       src_timestamp <- getModificationTime (basename `joinFileExt` suff)
        let
            unused_field = panic "runPhase:ModSummary field"
                -- Some fields are not looked at by hscMain
@@ -690,8 +745,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'
@@ -700,10 +753,11 @@ 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
+       result <- hscMain hsc_env
                          mod_summary source_unchanged 
                          False         -- No object file
                          Nothing       -- No iface
+                          Nothing       -- No "module i of n" progress info
 
        case result of
 
@@ -711,17 +765,18 @@ runPhase (Hsc src_flavour) stop dflags0 basename suff input_fn get_output_fn _ma
 
             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
+               when stub_c_exists $ 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
@@ -748,8 +803,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
@@ -794,6 +847,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
@@ -802,12 +858,29 @@ 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
 
-       -- force the C compiler to interpret this file as C when
-       -- compiling .hc files, by adding the -x c option.
-       let langopt | hcc = [ SysTools.Option "-x", SysTools.Option "c"]
-                   | otherwise = [ ]
+       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 (langopt ++
+       SysTools.runCc dflags (
+               -- force the C compiler to interpret this file as C when
+               -- compiling .hc files, by adding the -x c option.
+               -- Also useful for plain .c files, just in case GHC saw a 
+               -- -x c option.
+                       [ SysTools.Option "-x", SysTools.Option "c"] ++
                        [ SysTools.FileOption "" input_fn
                        , SysTools.Option "-o"
                        , SysTools.FileOption "" output_fn
@@ -818,11 +891,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
                       ))
@@ -915,7 +990,7 @@ runPhase SplitAs stop dflags basename _suff _input_fn get_output_fn maybe_loc
        (split_s_prefix, n) <- readIORef v_Split_info
 
        let real_odir
-               | Just d <- outputDir dflags = d
+               | Just d <- objectDir dflags = d
                | otherwise                  = basename ++ "_split"
 
        let assemble_file n
@@ -1061,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
 
@@ -1158,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)
 
@@ -1283,14 +1370,19 @@ hsSourceCppOpts =
 -----------------------------------------------------------------------------
 -- Reading OPTIONS pragmas
 
+-- This is really very ugly and should be rewritten.
+--   - some error messages are thrown as exceptions (should return)
+--   - we ignore LINE pragmas
+--   - parsing is horrible, combination of prefixMatch and 'read'.
+
 getOptionsFromSource 
        :: String               -- input file
        -> IO [String]          -- options, if any
 getOptionsFromSource file
   = do h <- openFile file ReadMode
-       look h `finally` hClose h
+       look h 1 `finally` hClose h
   where
-       look h = do
+       look h i = do
            r <- tryJust ioErrors (hGetLine h)
            case r of
              Left e | isEOFError e -> return []
@@ -1298,40 +1390,91 @@ getOptionsFromSource file
              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
+                   () | null l -> look h (i+1)
+                      | prefixMatch "#" l -> look h (i+1)
+                      | prefixMatch "{-# LINE" l -> look h (i+1)  -- -} wrong!
+                      | Just opts <- matchOptions i file l
+                       -> do rest <- look h (i+1)
                               return (opts ++ rest)
                       | otherwise -> return []
 
+getOptionsFromStringBuffer :: StringBuffer -> FilePath -> [(Int,String)]
+getOptionsFromStringBuffer buffer@(StringBuffer _ len _) fn = 
+  let 
+       ls = lines (lexemeToString buffer 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   -- -} wrong!
+                  | Just opts <- matchOptions i fn 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
+matchOptions i fn s
   | Just s1 <- maybePrefixMatch "{-#" s -- -} 
-  = matchOptions1 (removeSpaces s1)
+  = matchOptions1 i fn (removeSpaces s1)
   | otherwise
   = Nothing
  where
-  matchOptions1 s
+  matchOptions1 i fn s
     | Just s2 <- maybePrefixMatch "OPTIONS" s
     = case () of
        _ | Just s3 <- maybePrefixMatch "_GHC" s2, not (is_ident (head s3))
-         -> matchOptions2 s3
+         -> matchOptions2 i fn s3
          | not (is_ident (head s2))
-         -> matchOptions2 s2
+         -> matchOptions2 i fn 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)]
+
+    | Just s2 <- maybePrefixMatch "LANGUAGE" s, not (is_ident (head s2)),
+      Just s3 <- maybePrefixMatch "}-#" (reverse s2)
+    = case [ exts | (exts,"") <- reads ('[' : reverse (']':s3))] of
+       [] -> languagePragParseError i fn
+       exts:_ -> case extensionsToGHCFlag exts of
+                       ([], opts) -> Just opts
+                       (unsup,_) -> unsupportedExtnError i fn unsup
     | otherwise = Nothing
-  matchOptions2 s
+  matchOptions2 i fn s
     | Just s3 <- maybePrefixMatch "}-#" (reverse s) = Just (words (reverse s3))
     | otherwise = Nothing
 
 
+languagePragParseError i fn = 
+  pgmError (showSDoc (mkLocMessage loc (
+               text "cannot parse LANGUAGE pragma")))
+  where loc = srcLocSpan (mkSrcLoc (mkFastString fn) i 0)
+
+unsupportedExtnError i fn unsup = 
+  pgmError (showSDoc (mkLocMessage loc (
+               text "unsupported extensions: " <>
+               hcat (punctuate comma (map (text.show) unsup)))))
+  where loc = srcLocSpan (mkSrcLoc (mkFastString fn) i 0)
+
+
+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.