[project @ 2004-11-11 09:46:54 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / SysTools.lhs
index a108c9e..06850ef 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
 --
@@ -11,13 +11,15 @@ module SysTools (
        -- Initialisation
        initSysTools,
 
-       setPgmP,                -- String -> IO ()
+       setPgmL,                -- String -> IO ()
+       setPgmP,
        setPgmF,
        setPgmc,
        setPgmm,
        setPgms,
        setPgma,
        setPgml,
+       setPgmDLL,
 #ifdef ILX
        setPgmI,
        setPgmi,
@@ -27,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 ()
@@ -41,80 +44,73 @@ module SysTools (
 
        touch,                  -- String -> String -> IO ()
        copy,                   -- String -> String -> String -> IO ()
-       unDosifyPath,           -- String -> String
+       normalisePath,          -- FilePath -> FilePath
        
        -- 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(..)
 
  ) where
 
+#include "HsVersions.h"
+
 import DriverUtil
+import DriverPhases     ( isHaskellUserSrcFilename )
 import Config
 import Outputable
-import Panic           ( progName, GhcException(..) )
-import Util            ( global, dropList, notNull )
+import Panic           ( GhcException(..) )
+import Util            ( global, notNull )
 import CmdLineOpts     ( dynFlag, verbosity )
 
-import Exception       ( throwDyn )
-#if __GLASGOW_HASKELL__ > 408
-import qualified Exception ( catch )
-#else
-import Exception        ( catchAllIO )
-#endif
-import IO
-import Directory       ( doesFileExist, removeFile )
-import IOExts          ( IORef, readIORef, writeIORef )
-import Monad           ( when, unless )
-import System          ( ExitCode(..), exitWith, getEnv, system )
-import CString
-import Int
-import Addr
+import EXCEPTION       ( throwDyn )
+import DATA_IOREF      ( IORef, readIORef, writeIORef )
+import DATA_INT
     
-#include "../includes/config.h"
+import Monad           ( when, unless )
+import System          ( ExitCode(..), getEnv, system )
+import IO              ( try, catch,
+                         openFile, hPutStrLn, hPutStr, hClose, hFlush, IOMode(..),
+                         stderr )
+import Directory       ( doesFileExist, removeFile )
+import List             ( partition )
+
+#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.
+#if __GLASGOW_HASKELL__ < 500
+#error GHC >= 5.00 is required for bootstrapping GHC
+#endif
 
 #ifndef mingw32_HOST_OS
-import qualified Posix
+#if __GLASGOW_HASKELL__ > 504
+import qualified System.Posix.Internals
 #else
+import qualified Posix
+#endif
+#else /* Must be Win32 */
 import List            ( isPrefixOf )
-import MarshalArray
+import Util            ( dropList )
 import Foreign
+import CString         ( CString, peekCString )
 #endif
 
-#if __GLASGOW_HASKELL__ > 408
-# if __GLASGOW_HASKELL__ >= 503
-import GHC.IOBase
-# else
-# endif
-# ifdef mingw32_HOST_OS
-import SystemExts       ( rawSystem )
-# endif
+#if __GLASGOW_HASKELL__ < 603
+-- rawSystem comes from libghccompat.a in stage1
+import Compat.RawSystem        ( rawSystem )
 #else
-import System          ( system )
+import System.Cmd      ( rawSystem )
 #endif
-
-
-#include "HsVersions.h"
-
--- Make catch work on older GHCs
-#if __GLASGOW_HASKELL__ > 408
-myCatch = Exception.catch
-#else
-myCatch = catchAllIO
-#endif
-
 \end{code}
 
 
@@ -191,24 +187,24 @@ All these pathnames are maintained IN THE NATIVE FORMAT OF THE HOST MACHINE.
 
 \begin{code}
 GLOBAL_VAR(v_Pgm_L,    error "pgm_L",   String)        -- unlit
-GLOBAL_VAR(v_Pgm_P,    error "pgm_P",   String)        -- cpp
+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>
 
@@ -258,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
@@ -283,30 +283,21 @@ initSysTools minusB_args
          -- On Win32, consult GetTempPath() for a temp dir.
          --  => it first tries TMP, TEMP, then finally the
          --   Windows directory(!). The directory is in short-path
-         --   form and *does* have a trailing backslash.
+         --   form.
        ; IO.try (do
                let len = (2048::Int)
                buf  <- mallocArray len
                ret  <- getTempPath len buf
                tdir <-
                  if ret == 0 then do
-                     -- failed, consult TEMP.
+                     -- failed, consult TMPDIR.
                     free buf
-                    getEnv "TMP"
+                    getEnv "TMPDIR"
                   else do
                     s <- peekCString buf
                     free buf
                     return s
-               let
-                 -- strip the trailing backslash (awful, but 
-                 -- we only do this once).
-                 tmpdir =
-                   case last tdir of
-                     '/'  -> init tdir
-                     '\\' -> init tdir
-                     _   -> tdir
-               setTmpDir tmpdir
-               return ())
+               setTmpDir tdir)
 #endif
 
        -- Check that the package config exists
@@ -329,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
@@ -349,37 +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 = 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
-        ; let cpp_path  = gcc_path ++ " -E " ++ cRAWCPP_FLAGS
+        -- HACK, see setPgmP below. We keep 'words' here to remember to fix
+        -- Config.hs one day.
+        ; 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
@@ -389,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 
@@ -398,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
 
@@ -415,7 +423,7 @@ initSysTools minusB_args
        }
 
 #if defined(mingw32_HOST_OS)
-foreign import stdcall "GetTempPathA" unsafe getTempPath :: Int -> CString -> IO Int32
+foreign import stdcall unsafe "GetTempPathA" getTempPath :: Int -> CString -> IO Int32
 #endif
 \end{code}
 
@@ -427,13 +435,17 @@ like
 is used to override a particular program with a new one
 
 \begin{code}
-setPgmP = writeIORef v_Pgm_P
+setPgmL = writeIORef v_Pgm_L
+-- XXX HACK: Prelude> words "'does not' work" ===> ["'does","not'","work"]
+-- 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
@@ -474,11 +486,11 @@ findTopDir minusbs
        ; return (am_installed, top_dir)
        }
   where
-    -- get_proto returns a Unix-format path (relying on getExecDir to do so too)
+    -- get_proto returns a Unix-format path (relying on getBaseDir to do so too)
     get_proto | notNull minusbs
-             = return (unDosifyPath (drop 2 (last minusbs)))   -- 2 for "-B"
+             = return (normalisePath (drop 2 (last minusbs)))  -- 2 for "-B"
              | otherwise          
-             = do { maybe_exec_dir <- getExecDir -- Get directory of executable
+             = do { maybe_exec_dir <- getBaseDir -- Get directory of executable
                   ; case maybe_exec_dir of       -- (only works on Windows; 
                                                  --  returns Nothing on Unix)
                        Nothing  -> throwDyn (InstallationError "missing -B<dir> option")
@@ -507,11 +519,9 @@ data Option
              String  -- the filepath/filename portion
  | Option     String
  
-showOptions :: [Option] -> String
-showOptions ls = unwords (map (quote.showOpt) ls)
- where
-   showOpt (FileOption pre f) = pre ++ dosifyPath f
-   showOpt (Option s)     = s
+showOpt (FileOption pre f) = pre ++ platformPath f
+showOpt (Option "") = ""
+showOpt (Option s)  = s
 
 \end{code}
 
@@ -529,32 +539,32 @@ runUnlit args = do p <- readIORef v_Pgm_L
                   runSomething "Literate pre-processor" p args
 
 runCpp :: [Option] -> IO ()
-runCpp args =   do p <- readIORef v_Pgm_P
-                  runSomething "C pre-processor" p args
+runCpp args =   do (p,baseArgs) <- readIORef v_Pgm_P
+                  runSomething "C pre-processor" p (baseArgs ++ args)
 
 runPp :: [Option] -> IO ()
 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 ()
@@ -567,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
@@ -592,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}
 
 
@@ -625,18 +622,49 @@ GLOBAL_VAR(v_TmpDir,       cDEFAULT_TMPDIR,  String   )
 \end{code}
 
 \begin{code}
-setTmpDir dir = writeIORef v_TmpDir dir
+setTmpDir dir = writeIORef v_TmpDir (canonicalise dir)
+    where
+#if !defined(mingw32_HOST_OS)
+     canonicalise p = normalisePath p
+#else
+       -- Canonicalisation of temp path under win32 is a bit more
+       -- involved: (a) strip trailing slash, 
+       --           (b) normalise slashes
+       --           (c) just in case, if there is a prefix /cygdrive/x/, change to x:
+       -- 
+     canonicalise path = normalisePath (xltCygdrive (removeTrailingSlash path))
+
+        -- if we're operating under cygwin, and TMP/TEMP is of
+       -- the form "/cygdrive/drive/path", translate this to
+       -- "drive:/path" (as GHC isn't a cygwin app and doesn't
+       -- understand /cygdrive paths.)
+     xltCygdrive path
+      | "/cygdrive/" `isPrefixOf` path = 
+         case drop (length "/cygdrive/") path of
+           drive:xs@('/':_) -> drive:':':xs
+           _ -> path
+      | otherwise = path
+
+        -- strip the trailing backslash (awful, but we only do this once).
+     removeTrailingSlash path = 
+       case last path of
+         '/'  -> init path
+         '\\' -> init path
+         _    -> path
+#endif
 
 cleanTempFiles :: Int -> IO ()
-cleanTempFiles verb = do fs <- readIORef v_FilesToClean
-                        removeTmpFiles verb fs
+cleanTempFiles verb
+   = do fs <- readIORef v_FilesToClean
+       removeTmpFiles verb fs
+       writeIORef v_FilesToClean []
 
 cleanTempFilesExcept :: Int -> [FilePath] -> IO ()
 cleanTempFilesExcept verb dont_delete
-  = do fs <- readIORef v_FilesToClean
-       let leftovers = filter (`notElem` dont_delete) fs
-       removeTmpFiles verb leftovers
-       writeIORef v_FilesToClean dont_delete
+   = do files <- readIORef v_FilesToClean
+       let (to_keep, to_delete) = partition (`elem` dont_delete) files
+       removeTmpFiles verb to_delete
+       writeIORef v_FilesToClean to_keep
 
 
 -- find a temporary name that doesn't already exist.
@@ -659,11 +687,26 @@ addFilesToClean files = mapM_ (add v_FilesToClean) files
 
 removeTmpFiles :: Int -> [FilePath] -> IO ()
 removeTmpFiles verb fs
-  = traceCmd "Deleting temp files" 
-            ("Deleting: " ++ unwords fs)
-            (mapM_ rm fs)
+  = warnNon $
+    traceCmd "Deleting temp files" 
+            ("Deleting: " ++ unwords deletees)
+            (mapM_ rm deletees)
   where
-    rm f = removeFile f `myCatch` 
+     -- Flat out refuse to delete files that are likely to be source input
+     -- files (is there a worse bug than having a compiler delete your source
+     -- files?)
+     -- 
+     -- Deleting source files is a sign of a bug elsewhere, so prominently flag
+     -- the condition.
+    warnNon act
+     | null non_deletees = act
+     | otherwise         = do
+        hPutStrLn stderr ("WARNING - NOT deleting source files: " ++ unwords non_deletees)
+       act
+
+    (non_deletees, deletees) = partition isHaskellUserSrcFilename fs
+
+    rm f = removeFile f `IO.catch` 
                (\_ignored -> 
                    when (verb >= 2) $
                      hPutStrLn stderr ("Warning: deleting non-existent " ++ f)
@@ -694,22 +737,22 @@ runSomething :: String            -- For -v message
                                --      runSomething will dos-ify them
             -> IO ()
 
-runSomething phase_name pgm args
- = traceCmd phase_name cmd_line $
-   do   {
-#ifndef mingw32_HOST_OS
-         exit_code <- system cmd_line
-#else
-          exit_code <- rawSystem cmd_line
-#endif
-       ; if exit_code /= ExitSuccess
-         then throwDyn (PhaseFailed phase_name exit_code)
-         else return ()
-       }
-  where
-       -- The pgm is already in native format (appropriate dir separators)
-    cmd_line = pgm ++ ' ':showOptions args 
-                -- unwords (pgm : dosifyPaths (map quote args))
+runSomething phase_name pgm args = do
+  let real_args = filter notNull (map showOpt args)
+  traceCmd phase_name (unwords (pgm:real_args)) $ do
+  exit_code <- rawSystem pgm real_args
+  case exit_code of
+     ExitSuccess -> 
+       return ()
+     -- rawSystem returns (ExitFailure 127) if the exec failed for any
+     -- reason (eg. the program doesn't exist).  This is the only clue
+     -- we have, but we need to report something to the user because in
+     -- the case of a missing program there will otherwise be no output
+     -- at all.
+     ExitFailure 127 -> 
+       throwDyn (InstallationError ("could not execute: " ++ pgm))
+     ExitFailure _other ->
+       throwDyn (PhaseFailed phase_name exit_code)
 
 traceCmd :: String -> String -> IO () -> IO ()
 -- a) trace the command (at two levels of verbosity)
@@ -725,11 +768,11 @@ traceCmd phase_name cmd_line action
        ; unless n $ do {
 
           -- And run it!
-       ; action `myCatch` handle_exn verb
+       ; action `IO.catch` handle_exn verb
        }}
   where
     handle_exn verb exn = do { when (verb >= 2) (hPutStr   stderr "\n")
-                            ; when (verb >= 3) (hPutStrLn stderr ("Failed: " ++ cmd_line))
+                            ; when (verb >= 3) (hPutStrLn stderr ("Failed: " ++ cmd_line ++ (show exn)))
                             ; throwDyn (PhaseFailed phase_name (ExitFailure 1)) }
 \end{code}
 
@@ -745,21 +788,16 @@ the last moment.  On Windows we dos-ify them just before passing them
 to the Windows command.
 
 The alternative, of using '/' consistently on Unix and '\' on Windows,
-proved quite awkward.  There were a lot more calls to dosifyPath,
+proved quite awkward.  There were a lot more calls to platformPath,
 and even on Windows we might invoke a unix-like utility (eg 'sh'), which
 interpreted a command line 'foo\baz' as 'foobaz'.
 
 \begin{code}
 -----------------------------------------------------------------------------
--- Convert filepath into MSDOS form.
-
-dosifyPaths :: [String] -> [String]
--- dosifyPaths does two things
--- a) change '/' to '\'
--- b) remove initial '/cygdrive/'
+-- Convert filepath into platform / MSDOS form.
 
-unDosifyPath :: String -> String
--- Just change '\' to '/'
+normalisePath :: String -> String
+-- Just changes '\' to '/'
 
 pgmPath :: String              -- Directory string in Unix format
        -> String               -- Program name with no directory separators
@@ -769,36 +807,20 @@ pgmPath :: String         -- Directory string in Unix format
 
 
 #if defined(mingw32_HOST_OS)
-
 --------------------- Windows version ------------------
-dosifyPaths xs = map dosifyPath xs
-
-unDosifyPath xs = subst '\\' '/' xs
+normalisePath xs = subst '\\' '/' xs
+platformPath p   = subst '/' '\\' p
+pgmPath dir pgm  = platformPath dir ++ '\\' : pgm
 
-pgmPath dir pgm = dosifyPath dir ++ '\\' : pgm
-
-dosifyPath stuff
-  = subst '/' '\\' real_stuff
- where
-   -- fully convince myself that /cygdrive/ prefixes cannot
-   -- really appear here.
-  cygdrive_prefix = "/cygdrive/"
-
-  real_stuff
-    | cygdrive_prefix `isPrefixOf` stuff = dropList cygdrive_prefix stuff
-    | otherwise = stuff
-   
+subst a b ls = map (\ x -> if x == a then b else x) ls
 #else
-
---------------------- Unix version ---------------------
-dosifyPaths  ps  = ps
-unDosifyPath xs  = xs
-pgmPath dir pgm  = dir ++ '/' : pgm
-dosifyPath stuff = stuff
+--------------------- Non-Windows version --------------
+normalisePath xs   = xs
+pgmPath dir pgm    = dir ++ '/' : pgm
+platformPath stuff = stuff
 --------------------------------------------------------
 #endif
 
-subst a b ls = map (\ x -> if x == a then b else x) ls
 \end{code}
 
 
@@ -807,13 +829,6 @@ subst a b ls = map (\ x -> if x == a then b else x) ls
 
 \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}
 
@@ -826,47 +841,36 @@ slash s1 s2 = s1 ++ ('/' : s2)
 
 \begin{code}
 -----------------------------------------------------------------------------
--- Define      getExecDir     :: IO (Maybe String)
+-- Define      getBaseDir     :: IO (Maybe String)
 
 #if defined(mingw32_HOST_OS)
-getExecDir :: IO (Maybe String)
-getExecDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
+getBaseDir :: IO (Maybe String)
+-- Assuming we are running ghc, accessed by path  $()/bin/ghc.exe,
+-- return the path $(stuff).  Note that we drop the "bin/" directory too.
+getBaseDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
                buf <- mallocArray len
-               ret <- getModuleFileName nullAddr buf len
+               ret <- getModuleFileName nullPtr buf len
                if ret == 0 then free buf >> return Nothing
                            else do s <- peekCString buf
                                    free buf
-                                   return (Just (reverse (dropList "/bin/ghc.exe" (reverse (unDosifyPath s)))))
-
+                                   return (Just (rootDir s))
+  where
+    rootDir s = reverse (dropList "/bin/ghc.exe" (reverse (normalisePath s)))
 
-foreign import stdcall "GetModuleFileNameA" unsafe getModuleFileName :: Addr -> CString -> Int -> IO Int32
+foreign import stdcall unsafe "GetModuleFileNameA"
+  getModuleFileName :: Ptr () -> CString -> Int -> IO Int32
 #else
-getExecDir :: IO (Maybe String) = do return Nothing
+getBaseDir :: IO (Maybe String) = do return Nothing
 #endif
 
 #ifdef mingw32_HOST_OS
-foreign import "_getpid" unsafe getProcessID :: IO Int -- relies on Int == Int32 on Windows
+foreign import ccall unsafe "_getpid" getProcessID :: IO Int -- relies on Int == Int32 on Windows
+#elif __GLASGOW_HASKELL__ > 504
+getProcessID :: IO Int
+getProcessID = System.Posix.Internals.c_getpid >>= return . fromIntegral
 #else
 getProcessID :: IO Int
 getProcessID = Posix.getProcessID
 #endif
 
-#if defined(mingw32_HOST_OS) && (__GLASGOW_HASKELL__ <= 408)
-rawSystem :: String -> IO ExitCode
-rawSystem cmd = system cmd
- -- mingw only: if you try to build a stage2 compiler with a stage1
- -- that has been bootstrapped with 4.08 (or earlier), this will run
- -- into problems with limits on command-line lengths with the std.
- -- Win32 command interpreters. So don't this - use 5.00 or later
- -- to compile up the GHC sources.
-#endif
-
-quote :: String -> String
-#if defined(mingw32_HOST_OS)
-quote "" = ""
-quote s  = "\"" ++ s ++ "\""
-#else
-quote s = s
-#endif
-
 \end{code}