[project @ 2004-08-13 13:04:50 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / SysTools.lhs
index 48fcd4f..fcd62de 100644 (file)
@@ -1,6 +1,6 @@
 -----------------------------------------------------------------------------
 --
--- (c) The University of Glasgow 2001
+-- (c) The University of Glasgow 2001-2003
 --
 -- Access to system tools: gcc, cp, rm etc
 --
@@ -19,6 +19,7 @@ module SysTools (
        setPgms,
        setPgma,
        setPgml,
+       setPgmDLL,
 #ifdef ILX
        setPgmI,
        setPgmi,
@@ -28,6 +29,7 @@ module SysTools (
 
        getTopDir,              -- IO String    -- The value of $libdir
        getPackageConfigPath,   -- IO String    -- Where package.conf is
+        getUsageMsgPaths,       -- IO (String,String)
 
        -- Interface to system tools
        runUnlit, runCpp, runCc, -- [Option] -> IO ()
@@ -47,15 +49,13 @@ module SysTools (
        -- Temporary-file management
        setTmpDir,
        newTempName,
-       cleanTempFiles, cleanTempFilesExcept, removeTmpFiles,
+       cleanTempFiles, cleanTempFilesExcept,
        addFilesToClean,
 
        -- System interface
-       getProcessID,           -- IO Int
        system,                 -- String -> IO ExitCode
 
        -- Misc
-       showGhcUsage,           -- IO ()        Shows usage message and exits
        getSysMan,              -- IO String    Parallel system only
        
        Option(..)
@@ -68,8 +68,8 @@ import DriverUtil
 import DriverPhases     ( isHaskellUserSrcFilename )
 import Config
 import Outputable
-import Panic           ( progName, GhcException(..) )
-import Util            ( global, notNull )
+import Panic           ( GhcException(..) )
+import Util            ( global, notNull, toArgs )
 import CmdLineOpts     ( dynFlag, verbosity )
 
 import EXCEPTION       ( throwDyn )
@@ -77,14 +77,14 @@ import DATA_IOREF   ( IORef, readIORef, writeIORef )
 import DATA_INT
     
 import Monad           ( when, unless )
-import System          ( ExitCode(..), exitWith, getEnv, system )
+import System          ( ExitCode(..), getEnv, system )
 import IO              ( try, catch,
-                         openFile, hPutChar, hPutStrLn, hPutStr, hClose, hFlush, IOMode(..),
+                         openFile, hPutStrLn, hPutStr, hClose, hFlush, IOMode(..),
                          stderr )
 import Directory       ( doesFileExist, removeFile )
-import List             ( intersperse, partition )
+import List             ( partition )
 
-#include "../includes/config.h"
+#include "../includes/ghcconfig.h"
 
 -- GHC <= 4.08 didn't have rawSystem, and runs into problems with long command
 -- lines on mingw32, so we disallow it now.
@@ -105,7 +105,7 @@ import Foreign
 import CString         ( CString, peekCString )
 #endif
 
-#if __GLASGOW_HASKELL__ < 601
+#if __GLASGOW_HASKELL__ < 603
 import Foreign         ( withMany, withArray0, nullPtr, Ptr )
 import CForeign                ( CString, withCString, throwErrnoIfMinus1 )
 #else
@@ -189,22 +189,22 @@ All these pathnames are maintained IN THE NATIVE FORMAT OF THE HOST MACHINE.
 GLOBAL_VAR(v_Pgm_L,    error "pgm_L",   String)        -- unlit
 GLOBAL_VAR(v_Pgm_P,    error "pgm_P",   (String,[Option]))     -- cpp
 GLOBAL_VAR(v_Pgm_F,    error "pgm_F",   String)        -- pp
-GLOBAL_VAR(v_Pgm_c,    error "pgm_c",   String)        -- gcc
-GLOBAL_VAR(v_Pgm_m,    error "pgm_m",   String)        -- asm code mangler
-GLOBAL_VAR(v_Pgm_s,    error "pgm_s",   String)        -- asm code splitter
-GLOBAL_VAR(v_Pgm_a,    error "pgm_a",   String)        -- as
+GLOBAL_VAR(v_Pgm_c,    error "pgm_c",   (String,[Option])) -- gcc
+GLOBAL_VAR(v_Pgm_m,    error "pgm_m",   (String,[Option])) -- asm code mangler
+GLOBAL_VAR(v_Pgm_s,    error "pgm_s",   (String,[Option])) -- asm code splitter
+GLOBAL_VAR(v_Pgm_a,    error "pgm_a",   (String,[Option])) -- as
 #ifdef ILX
 GLOBAL_VAR(v_Pgm_I,     error "pgm_I",   String)        -- ilx2il
 GLOBAL_VAR(v_Pgm_i,     error "pgm_i",   String)        -- ilasm
 #endif
-GLOBAL_VAR(v_Pgm_l,    error "pgm_l",   String)        -- ld
-GLOBAL_VAR(v_Pgm_MkDLL, error "pgm_dll", String)       -- mkdll
+GLOBAL_VAR(v_Pgm_l,    error "pgm_l",   (String,[Option])) -- ld
+GLOBAL_VAR(v_Pgm_MkDLL, error "pgm_dll", (String,[Option])) -- mkdll
 
 GLOBAL_VAR(v_Pgm_T,    error "pgm_T",    String)       -- touch
 GLOBAL_VAR(v_Pgm_CP,   error "pgm_CP",          String)        -- cp
 
 GLOBAL_VAR(v_Path_package_config, error "path_package_config", String)
-GLOBAL_VAR(v_Path_usage,         error "ghc_usage.txt",       String)
+GLOBAL_VAR(v_Path_usages,        error "ghc_usage.txt",       (String,String))
 
 GLOBAL_VAR(v_TopDir,   error "TopDir", String)         -- -B<dir>
 
@@ -254,6 +254,10 @@ initSysTools minusB_args
                | am_installed = installed "ghc-usage.txt"
                | otherwise    = inplace cGHC_DRIVER_DIR_REL "ghc-usage.txt"
 
+             ghci_usage_msg_path
+               | am_installed = installed "ghci-usage.txt"
+               | otherwise    = inplace cGHC_DRIVER_DIR_REL "ghci-usage.txt"
+
                -- For all systems, unlit, split, mangle are GHC utilities
                -- architecture-specific stuff is done when building Config.hs
              unlit_path
@@ -316,16 +320,20 @@ initSysTools minusB_args
        --      pick up whatever happens to be lying around in the path,
        --      possibly including those from a cygwin install on the target,
        --      which is exactly what we're trying to avoid.
-       ; let gcc_path  | am_installed = installed_bin ("gcc -B\"" ++ installed "gcc-lib/\"")
-                       | otherwise    = cGCC
+       ; let gcc_b_arg = Option ("-B" ++ installed "gcc-lib/")
+             (gcc_prog,gcc_args)
+               | am_installed = (installed_bin "gcc", [gcc_b_arg])
+               | otherwise    = (cGCC, [])
                -- The trailing "/" is absolutely essential; gcc seems
-               -- to construct file names simply by concatenating to this
-               -- -B path with no extra slash
-               -- We use "/" rather than "\\" because otherwise "\\\" is mangled
-               -- later on; although gcc_path is in NATIVE format, gcc can cope
+               -- to construct file names simply by concatenating to
+               -- this -B path with no extra slash We use "/" rather
+               -- than "\\" because otherwise "\\\" is mangled
+               -- later on; although gcc_args are in NATIVE format,
+               -- gcc can cope
                --      (see comments with declarations of global variables)
                --
-               -- The quotes round the -B argument are in case TopDir has spaces in it
+               -- The quotes round the -B argument are in case TopDir
+               -- has spaces in it
 
              perl_path | am_installed = installed_bin cGHC_PERL
                        | otherwise    = cGHC_PERL
@@ -336,43 +344,49 @@ initSysTools minusB_args
 
        -- On Win32 we don't want to rely on #!/bin/perl, so we prepend 
        -- a call to Perl to get the invocation of split and mangle
-       ; let split_path  = perl_path ++ " \"" ++ split_script ++ "\""
-             mangle_path = perl_path ++ " \"" ++ mangle_script ++ "\""
-
-       ; let mkdll_path 
-               | am_installed = pgmPath (installed "gcc-lib/") cMKDLL ++
-                                " --dlltool-name " ++ pgmPath (installed "gcc-lib/") "dlltool" ++
-                                " --driver-name " ++ gcc_path
-               | otherwise    = cMKDLL
+       ; let (split_prog,  split_args)  = (perl_path, [Option split_script])
+             (mangle_prog, mangle_args) = (perl_path, [Option mangle_script])
+
+       ; let (mkdll_prog, mkdll_args)
+               | am_installed = 
+                   (pgmPath (installed "gcc-lib/") cMKDLL,
+                    [ Option "--dlltool-name",
+                      Option (pgmPath (installed "gcc-lib/") "dlltool"),
+                      Option "--driver-name",
+                      Option gcc_prog, gcc_b_arg ])
+               | otherwise    = (cMKDLL, [])
 #else
        --              UNIX-SPECIFIC STUFF
        -- On Unix, the "standard" tools are assumed to be
        -- in the same place whether we are running "in-place" or "installed"
        -- That place is wherever the build-time configure script found them.
-       ; let   gcc_path   = cGCC
+       ; let   gcc_prog   = cGCC
+               gcc_args   = []
                touch_path = "touch"
-               mkdll_path = panic "Can't build DLLs on a non-Win32 system"
+               mkdll_prog = panic "Can't build DLLs on a non-Win32 system"
+               mkdll_args = []
 
        -- On Unix, scripts are invoked using the '#!' method.  Binary
        -- installations of GHC on Unix place the correct line on the front
        -- of the script at installation time, so we don't want to wire-in
        -- our knowledge of $(PERL) on the host system here.
-       ; let split_path  = split_script
-             mangle_path = mangle_script
+       ; let (split_prog,  split_args)  = (split_script,  [])
+             (mangle_prog, mangle_args) = (mangle_script, [])
 #endif
 
        -- cpp is derived from gcc on all platforms
         -- HACK, see setPgmP below. We keep 'words' here to remember to fix
         -- Config.hs one day.
-        ; let cpp_path  = (gcc_path, (Option "-E"):(map Option (words cRAWCPP_FLAGS)))
+        ; let cpp_path  = (gcc_prog, gcc_args ++ 
+                          (Option "-E"):(map Option (words cRAWCPP_FLAGS)))
 
        -- For all systems, copy and remove are provided by the host
        -- system; architecture-specific stuff is done when building Config.hs
        ; let   cp_path = cGHC_CP
        
        -- Other things being equal, as and ld are simply gcc
-       ; let   as_path  = gcc_path
-               ld_path  = gcc_path
+       ; let   (as_prog,as_args)  = (gcc_prog,gcc_args)
+               (ld_prog,ld_args)  = (gcc_prog,gcc_args)
 
 #ifdef ILX
        -- ilx2il and ilasm are specified in Config.hs
@@ -382,7 +396,8 @@ initSysTools minusB_args
                                       
        -- Initialise the global vars
        ; writeIORef v_Path_package_config pkgconfig_path
-       ; writeIORef v_Path_usage          ghc_usage_msg_path
+       ; writeIORef v_Path_usages         (ghc_usage_msg_path,
+                                           ghci_usage_msg_path)
 
        ; writeIORef v_Pgm_sysman          (top_dir ++ "/ghc/rts/parallel/SysMan")
                -- Hans: this isn't right in general, but you can 
@@ -391,16 +406,16 @@ initSysTools minusB_args
        ; writeIORef v_Pgm_L               unlit_path
        ; writeIORef v_Pgm_P               cpp_path
        ; writeIORef v_Pgm_F               ""
-       ; writeIORef v_Pgm_c               gcc_path
-       ; writeIORef v_Pgm_m               mangle_path
-       ; writeIORef v_Pgm_s               split_path
-       ; writeIORef v_Pgm_a               as_path
+       ; writeIORef v_Pgm_c               (gcc_prog,gcc_args)
+       ; writeIORef v_Pgm_m               (mangle_prog,mangle_args)
+       ; writeIORef v_Pgm_s               (split_prog,split_args)
+       ; writeIORef v_Pgm_a               (as_prog,as_args)
 #ifdef ILX
        ; writeIORef v_Pgm_I               ilx2il_path
        ; writeIORef v_Pgm_i               ilasm_path
 #endif
-       ; writeIORef v_Pgm_l               ld_path
-       ; writeIORef v_Pgm_MkDLL           mkdll_path
+       ; writeIORef v_Pgm_l               (ld_prog,ld_args)
+       ; writeIORef v_Pgm_MkDLL           (mkdll_prog,mkdll_args)
        ; writeIORef v_Pgm_T               touch_path
        ; writeIORef v_Pgm_CP              cp_path
 
@@ -425,11 +440,12 @@ setPgmL = writeIORef v_Pgm_L
 -- Config.hs should really use Option.
 setPgmP arg = let (pgm:args) = words arg in writeIORef v_Pgm_P (pgm,map Option args)
 setPgmF = writeIORef v_Pgm_F
-setPgmc = writeIORef v_Pgm_c
-setPgmm = writeIORef v_Pgm_m
-setPgms = writeIORef v_Pgm_s
-setPgma = writeIORef v_Pgm_a
-setPgml = writeIORef v_Pgm_l
+setPgmc prog = writeIORef v_Pgm_c (prog,[])
+setPgmm prog = writeIORef v_Pgm_m (prog,[])
+setPgms prog = writeIORef v_Pgm_s (prog,[])
+setPgma prog = writeIORef v_Pgm_a (prog,[])
+setPgml prog = writeIORef v_Pgm_l (prog,[])
+setPgmDLL prog = writeIORef v_Pgm_MkDLL (prog,[])
 #ifdef ILX
 setPgmI = writeIORef v_Pgm_I
 setPgmi = writeIORef v_Pgm_i
@@ -531,24 +547,24 @@ runPp args =   do p <- readIORef v_Pgm_F
                  runSomething "Haskell pre-processor" p args
 
 runCc :: [Option] -> IO ()
-runCc args =   do p <- readIORef v_Pgm_c
-                 runSomething "C Compiler" p args
+runCc args =   do (p,args0) <- readIORef v_Pgm_c
+                 runSomething "C Compiler" p (args0++args)
 
 runMangle :: [Option] -> IO ()
-runMangle args = do p <- readIORef v_Pgm_m
-                   runSomething "Mangler" p args
+runMangle args = do (p,args0) <- readIORef v_Pgm_m
+                   runSomething "Mangler" p (args0++args)
 
 runSplit :: [Option] -> IO ()
-runSplit args = do p <- readIORef v_Pgm_s
-                  runSomething "Splitter" p args
+runSplit args = do (p,args0) <- readIORef v_Pgm_s
+                  runSomething "Splitter" p (args0++args)
 
 runAs :: [Option] -> IO ()
-runAs args = do p <- readIORef v_Pgm_a
-               runSomething "Assembler" p args
+runAs args = do (p,args0) <- readIORef v_Pgm_a
+               runSomething "Assembler" p (args0++args)
 
 runLink :: [Option] -> IO ()
-runLink args = do p <- readIORef v_Pgm_l
-                 runSomething "Linker" p args
+runLink args = do (p,args0) <- readIORef v_Pgm_l
+                 runSomething "Linker" p (args0++args)
 
 #ifdef ILX
 runIlx2il :: [Option] -> IO ()
@@ -561,8 +577,8 @@ runIlasm args = do p <- readIORef v_Pgm_i
 #endif
 
 runMkDLL :: [Option] -> IO ()
-runMkDLL args = do p <- readIORef v_Pgm_MkDLL
-                  runSomething "Make DLL" p args
+runMkDLL args = do (p,args0) <- readIORef v_Pgm_MkDLL
+                  runSomething "Make DLL" p (args0++args)
 
 touch :: String -> String -> IO ()
 touch purpose arg =  do p <- readIORef v_Pgm_T
@@ -586,23 +602,10 @@ getSysMan :: IO String    -- How to invoke the system manager
 getSysMan = readIORef v_Pgm_sysman
 \end{code}
 
-%************************************************************************
-%*                                                                     *
-\subsection{GHC Usage message}
-%*                                                                     *
-%************************************************************************
-
-Show the usage message and exit
-
 \begin{code}
-showGhcUsage = do { usage_path <- readIORef v_Path_usage
-                 ; usage      <- readFile usage_path
-                 ; dump usage
-                 ; exitWith ExitSuccess }
-  where
-     dump ""         = return ()
-     dump ('$':'$':s) = hPutStr stderr progName >> dump s
-     dump (c:s)              = hPutChar stderr c >> dump s
+getUsageMsgPaths :: IO (FilePath,FilePath)
+         -- the filenames of the usage messages (ghc, ghci)
+getUsageMsgPaths = readIORef v_Path_usages
 \end{code}
 
 
@@ -736,7 +739,7 @@ runSomething :: String              -- For -v message
 
 runSomething phase_name pgm args = do
   let real_args = filter notNull (map showOpt args)
-  traceCmd phase_name (concat (intersperse " " (pgm:real_args))) $ do
+  traceCmd phase_name (unwords (pgm:real_args)) $ do
   exit_code <- rawSystem pgm real_args
   if (exit_code /= ExitSuccess)
        then throwDyn (PhaseFailed phase_name exit_code)
@@ -765,53 +768,14 @@ traceCmd phase_name cmd_line action
 
 -- -----------------------------------------------------------------------------
 -- rawSystem: run an external command
+--
+-- In GHC 6.2.1 there's a correct implementation of rawSystem in the
+-- library System.Cmd.  If we are compiling with an earlier version of
+-- GHC than this, we'd better have a copy of the correct implementation
+-- right here.
 
-#if __GLASGOW_HASKELL__ < 601
-
--- This code is copied from System.Cmd on GHC 6.1.
-
-rawSystem :: FilePath -> [String] -> IO ExitCode
-
-#ifndef mingw32_TARGET_OS
-
-rawSystem cmd args =
-  withCString cmd $ \pcmd ->
-    withMany withCString (cmd:args) $ \cstrs ->
-      withArray0 nullPtr cstrs $ \arr -> do
-       status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmd arr)
-        case status of
-            0  -> return ExitSuccess
-            n  -> return (ExitFailure n)
-
-foreign import ccall "rawSystem" unsafe
-  c_rawSystem :: CString -> Ptr CString -> IO Int
-
-#else
-
--- On Windows, the command line is passed to the operating system as
--- a single string.  Command-line parsing is done by the executable
--- itself.
-rawSystem cmd args = do
-  let cmdline = {-translate-} cmd ++ concat (map ((' ':) . translate) args)
-       -- Urk, don't quote/escape the command name on Windows, because the
-       -- compiler is exceedingly naughty and sometimes uses 'perl "..."' 
-       -- as the command name.
-  withCString cmdline $ \pcmdline -> do
-    status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmdline)
-    case status of
-       0  -> return ExitSuccess
-       n  -> return (ExitFailure n)
-
-translate :: String -> String
-translate str = '"' : foldr escape "\"" str
-  where escape '"'  str = '\\' : '"'  : str
-       escape '\\' str = '\\' : '\\' : str
-       escape c    str = c : str
-
-foreign import ccall "rawSystem" unsafe
-  c_rawSystem :: CString -> IO Int
-
-#endif
+#if __GLASGOW_HASKELL__ < 603
+#include "../../libraries/base/System/RawSystem.hs-inc"
 #endif
 \end{code}
 
@@ -868,13 +832,6 @@ platformPath stuff = stuff
 
 \begin{code}
 slash           :: String -> String -> String
-absPath, relPath :: [String] -> String
-
-relPath [] = ""
-relPath xs = foldr1 slash xs
-
-absPath xs = "" `slash` relPath xs
-
 slash s1 s2 = s1 ++ ('/' : s2)
 \end{code}