[project @ 2001-01-12 11:04:45 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / DriverPipeline.hs
index 1733d63..d7bc710 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
--- $Id: DriverPipeline.hs,v 1.42 2000/12/18 12:43:04 sewardj Exp $
+-- $Id: DriverPipeline.hs,v 1.47 2001/01/09 17:16:35 rrt Exp $
 --
 -- GHC Driver
 --
@@ -7,22 +7,26 @@
 --
 -----------------------------------------------------------------------------
 
+#include "../includes/config.h"
+
 module DriverPipeline (
 
        -- interfaces for the batch-mode driver
    GhcMode(..), getGhcMode, v_GhcMode,
-   genPipeline, runPipeline,
+   genPipeline, runPipeline, pipeLoop,
 
        -- interfaces for the compilation manager (interpreted/batch-mode)
    preprocess, compile, CompResult(..),
 
        -- batch-mode linking interface
-   doLink
+   doLink,
+        -- DLL building
+   doMkDLL
   ) where
 
 #include "HsVersions.h"
 
-import CmStaticInfo ( GhciMode(..) )
+import CmStaticInfo
 import CmTypes
 import GetImports
 import DriverState
@@ -51,12 +55,15 @@ import IO
 import Monad
 import Maybe
 
+import PackedString
+import MatchPS
+
 -----------------------------------------------------------------------------
 -- GHC modes of operation
 
 data GhcMode
   = DoMkDependHS                       -- ghc -M
-  | DoMkDLL                            -- ghc -mk-dll
+  | DoMkDLL                            -- ghc --mk-dll
   | StopBefore Phase                   -- ghc -E | -C | -S | -c
   | DoMake                             -- ghc --make
   | DoInteractive                      -- ghc --interactive
@@ -67,6 +74,7 @@ GLOBAL_VAR(v_GhcMode, error "todo", GhcMode)
 
 modeFlag :: String -> Maybe GhcMode
 modeFlag "-M"           = Just $ DoMkDependHS
+modeFlag "--mk-dll"      = Just $ DoMkDLL
 modeFlag "-E"           = Just $ StopBefore Hsc
 modeFlag "-C"           = Just $ StopBefore HCc
 modeFlag "-S"           = Just $ StopBefore As
@@ -86,7 +94,7 @@ getGhcMode flags
        ([(flag,one)], rest) -> return (rest, one, flag)
        (_    , _   ) -> 
          throwDyn (OtherError 
-               "only one of the flags -M, -E, -C, -S, -c, --make, --interactive is allowed")
+               "only one of the flags -M, -E, -C, -S, -c, --make, --interactive, -mk-dll is allowed")
 
 -----------------------------------------------------------------------------
 -- genPipeline
@@ -145,12 +153,16 @@ genPipeline todo stop_flag persistent_output lang filename
    ----------- -----  ----   ---   --   --  -  -  -
     (_basename, suffix) = splitFilename filename
 
-    start_phase = startPhase suffix
+    start = startPhase suffix
+
+      -- special case for mkdependHS: .hspp files go through MkDependHS
+    start_phase | todo == DoMkDependHS && start == Hsc  = MkDependHS
+               | otherwise = start
 
     haskellish = haskellish_suffix suffix
     cish = cish_suffix suffix
 
-   -- for a .hc file we need to force lang to HscC
+       -- for a .hc file we need to force lang to HscC
     real_lang | start_phase == HCc  = HscC
              | otherwise           = lang
 
@@ -187,18 +199,6 @@ genPipeline todo stop_flag persistent_output lang filename
                                    ++ filename))
        else do
 
-       -- if we can't find the phase we're supposed to stop before,
-       -- something has gone wrong.
-   case todo of
-       StopBefore phase -> 
-          when (phase /= Ln 
-                && phase `notElem` pipeline
-                && not (phase == As && SplitAs `elem` pipeline)) $
-             throwDyn (OtherError 
-               ("flag " ++ stop_flag
-                ++ " is incompatible with source file `" ++ filename ++ "'"))
-       _ -> return ()
-
    let
    ----------- -----  ----   ---   --   --  -  -  -
       myPhaseInputExt Ln = case osuf of Nothing -> phaseInputExt Ln
@@ -230,18 +230,32 @@ genPipeline todo stop_flag persistent_output lang filename
        -- the suffix on an output file is determined by the next phase
        -- in the pipeline, so we add linking to the end of the pipeline
        -- to force the output from the final phase to be a .o file.
-      stop_phase = case todo of StopBefore phase -> phase
-                               DoMkDependHS     -> Ln
-                               DoLink           -> Ln
+      stop_phase = case todo of 
+                       StopBefore As | split -> SplitAs
+                       StopBefore phase      -> phase
+                       DoMkDependHS          -> Ln
+                       DoLink                -> Ln
       annotated_pipeline = annotatePipeline (pipeline ++ [ Ln ]) stop_phase
 
       phase_ne p (p1,_,_) = (p1 /= p)
    ----------- -----  ----   ---   --   --  -  -  -
 
-   return $
-     dropWhile (phase_ne start_phase) . 
-       foldr (\p ps -> if phase_ne stop_phase p then p:ps else [])  []
-               $ annotated_pipeline
+       -- if we can't find the phase we're supposed to stop before,
+       -- something has gone wrong.  This test carefully avoids the
+       -- case where we aren't supposed to do any compilation, because the file
+       -- is already in linkable form (for example).
+   if start_phase `elem` pipeline && 
+       (stop_phase /= Ln && stop_phase `notElem` pipeline)
+      then throwDyn (OtherError 
+               ("flag " ++ stop_flag
+                ++ " is incompatible with source file `" ++ filename ++ "'"))
+      else do
+
+   return (
+     takeWhile (phase_ne stop_phase ) $
+     dropWhile (phase_ne start_phase) $
+     annotated_pipeline
+    )
 
 
 runPipeline
@@ -695,9 +709,8 @@ doLink o_files = do
 #ifdef mingw32_TARGET_OS
     let extra_os = if static || no_hs_main
                    then []
---                   else [ head (lib_paths (head rts_pkg)) ++ "/Main.dll_o",
---                          head (lib_paths (head std_pkg)) ++ "/PrelMain.dll_o" ]
-                    else []
+                   else [ head (library_dirs (head rts_pkg)) ++ "/Main.dll_o",
+                          head (library_dirs (head std_pkg)) ++ "/PrelMain.dll_o" ]
 #endif
     (md_c_flags, _) <- machdepCCOpts
     runSomething "Linker"
@@ -724,6 +737,74 @@ doLink o_files = do
        )
 
 -----------------------------------------------------------------------------
+-- Making a DLL
+
+-- only for Win32, but bits that are #ifdefed in doLn are still #ifdefed here
+-- in a vain attempt to aid future portability
+doMkDLL :: [String] -> IO ()
+doMkDLL o_files = do
+    ln <- readIORef v_Pgm_dll
+    verb <- getVerbFlag
+    static <- readIORef v_Static
+    let imp = if static then "" else "_imp"
+    no_hs_main <- readIORef v_NoHsMain
+
+    o_file <- readIORef v_Output_file
+    let output_fn = case o_file of { Just s -> s; Nothing -> "HSdll.dll"; }
+
+    pkg_lib_paths <- getPackageLibraryPath
+    let pkg_lib_path_opts = map ("-L"++) pkg_lib_paths
+
+    lib_paths <- readIORef v_Library_paths
+    let lib_path_opts = map ("-L"++) lib_paths
+
+    pkg_libs <- getPackageLibraries
+    let pkg_lib_opts = map (\lib -> "-l" ++ lib ++ imp) pkg_libs
+
+    libs <- readIORef v_Cmdline_libraries
+    let lib_opts = map ("-l"++) (reverse libs)
+        -- reverse because they're added in reverse order from the cmd line
+
+    pkg_extra_ld_opts <- getPackageExtraLdOpts
+
+       -- probably _stub.o files
+    extra_ld_inputs <- readIORef v_Ld_inputs
+
+       -- opts from -optdll-<blah>
+    extra_ld_opts <- getStaticOpts v_Opt_dll
+
+    rts_pkg <- getPackageDetails ["rts"]
+    std_pkg <- getPackageDetails ["std"]
+#ifdef mingw32_TARGET_OS
+    let extra_os = if static || no_hs_main
+                   then []
+                   else [ head (library_dirs (head rts_pkg)) ++ "/Main.dll_o",
+                          head (library_dirs (head std_pkg)) ++ "/PrelMain.dll_o" ]
+#endif
+    (md_c_flags, _) <- machdepCCOpts
+    runSomething "DLL creator"
+       (unwords
+        ([ ln, verb, "-o", output_fn ]
+        ++ md_c_flags
+        ++ o_files
+#ifdef mingw32_TARGET_OS
+        ++ extra_os
+        ++ [ "--target=i386-mingw32" ]
+#endif
+        ++ extra_ld_inputs
+        ++ lib_path_opts
+        ++ lib_opts
+        ++ pkg_lib_path_opts
+        ++ pkg_lib_opts
+        ++ pkg_extra_ld_opts
+         ++ (case findPS (packString (concat extra_ld_opts)) (packString "--def") of
+               Nothing -> [ "--export-all" ]
+              Just _  -> [ "" ])
+        ++ extra_ld_opts
+       )
+       )
+
+-----------------------------------------------------------------------------
 -- Just preprocess a file, put the result in a temp. file (used by the
 -- compilation manager during the summary phase).