X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=compiler%2Fmain%2FSysTools.lhs;h=41421d641118ade6ba1003d124fbdc53465ec1cf;hb=983c316af4654b6532909a0e85dec175e808401a;hp=87c55717bd0035e82e005b657ae8e015d7a9c75a;hpb=6c53f40f3dd84cc91a8e6850dbfb271cb24db89a;p=ghc-hetmet.git
diff --git a/compiler/main/SysTools.lhs b/compiler/main/SysTools.lhs
index 87c5571..41421d6 100644
--- a/compiler/main/SysTools.lhs
+++ b/compiler/main/SysTools.lhs
@@ -7,6 +7,13 @@
-----------------------------------------------------------------------------
\begin{code}
+{-# OPTIONS -w #-}
+-- The above warning supression flag is a temporary kludge.
+-- While working on this module you are encouraged to remove it and fix
+-- any warnings in the module. See
+-- http://hackage.haskell.org/trac/ghc/wiki/Commentary/CodingStyle#Warnings
+-- for details
+
module SysTools (
-- Initialisation
initSysTools,
@@ -17,11 +24,12 @@ module SysTools (
runMangle, runSplit, -- [Option] -> IO ()
runAs, runLink, -- [Option] -> IO ()
runMkDLL,
+ runWindres,
touch, -- String -> String -> IO ()
copy,
copyWithHeader,
- normalisePath, -- FilePath -> FilePath
+ getExtraViaCOpts,
-- Temporary-file management
setTmpDir,
@@ -49,6 +57,7 @@ import Data.IORef
import Control.Monad
import System.Exit
import System.Environment
+import System.FilePath
import System.IO
import SYSTEM_IO_ERROR as IO
import System.Directory
@@ -57,11 +66,7 @@ import Data.Maybe
import Data.List
#ifndef mingw32_HOST_OS
-#if __GLASGOW_HASKELL__ > 504
import qualified System.Posix.Internals
-#else
-import qualified Posix
-#endif
#else /* Must be Win32 */
import Foreign
import CString ( CString, peekCString )
@@ -75,7 +80,6 @@ import GHC.IOBase ( IOErrorType(..) )
#else
import System.Process ( runInteractiveProcess, getProcessExitCode )
import Control.Concurrent( forkIO, newChan, readChan, writeChan )
-import Data.Char ( isSpace )
import FastString ( mkFastString )
import SrcLoc ( SrcLoc, mkSrcLoc, noSrcSpan, mkSrcSpan )
#endif
@@ -168,10 +172,9 @@ initSysTools mbMinusB dflags
-- format, '/' separated
; let installed, installed_bin :: FilePath -> FilePath
- installed_bin pgm = pgmPath top_dir pgm
- installed file = pgmPath top_dir file
- inplace dir pgm = pgmPath (top_dir `joinFileName`
- cPROJECT_DIR `joinFileName` dir) pgm
+ installed_bin pgm = top_dir > pgm
+ installed file = top_dir > file
+ inplace dir pgm = top_dir > cPROJECT_DIR > dir > pgm
; let pkgconfig_path
| am_installed = installed "package.conf"
@@ -200,6 +203,10 @@ initSysTools mbMinusB dflags
| am_installed = installed_bin cGHC_MANGLER_PGM
| otherwise = inplace cGHC_MANGLER_DIR_REL cGHC_MANGLER_PGM
+ windres_path
+ | am_installed = installed_bin "bin/windres"
+ | otherwise = "windres"
+
; let dflags0 = defaultDynFlags
#ifndef mingw32_HOST_OS
-- check whether TMPDIR is set in the environment
@@ -258,9 +265,6 @@ initSysTools mbMinusB dflags
-- 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
perl_path | am_installed = installed_bin cGHC_PERL
| otherwise = cGHC_PERL
@@ -276,9 +280,9 @@ initSysTools mbMinusB dflags
; let (mkdll_prog, mkdll_args)
| am_installed =
- (pgmPath (installed "gcc-lib/") cMKDLL,
+ (installed "gcc-lib/" > cMKDLL,
[ Option "--dlltool-name",
- Option (pgmPath (installed "gcc-lib/") "dlltool"),
+ Option (installed "gcc-lib/" > "dlltool"),
Option "--driver-name",
Option gcc_prog, gcc_b_arg ])
| otherwise = (cMKDLL, [])
@@ -330,7 +334,8 @@ initSysTools mbMinusB dflags
pgm_l = (ld_prog,ld_args),
pgm_dll = (mkdll_prog,mkdll_args),
pgm_T = touch_path,
- pgm_sysman = top_dir ++ "/ghc/rts/parallel/SysMan"
+ pgm_sysman = top_dir ++ "/ghc/rts/parallel/SysMan",
+ pgm_windres = windres_path
-- Hans: this isn't right in general, but you can
-- elaborate it in the same way as the others
}
@@ -368,14 +373,14 @@ findTopDir mbMinusB
= do { top_dir <- get_proto
-- Discover whether we're running in a build tree or in an installation,
-- by looking for the package configuration file.
- ; am_installed <- doesFileExist (top_dir `joinFileName` "package.conf")
+ ; am_installed <- doesFileExist (top_dir > "package.conf")
; return (am_installed, top_dir)
}
where
-- get_proto returns a Unix-format path (relying on getBaseDir to do so too)
get_proto = case mbMinusB of
- Just minusb -> return (normalisePath minusb)
+ Just minusb -> return (normalise minusb)
Nothing
-> do maybe_exec_dir <- getBaseDir -- Get directory of executable
case maybe_exec_dir of -- (only works on Windows;
@@ -401,7 +406,9 @@ runUnlit dflags args = do
runCpp :: DynFlags -> [Option] -> IO ()
runCpp dflags args = do
let (p,args0) = pgm_P dflags
- runSomething dflags "C pre-processor" p (args0 ++ args)
+ args1 = args0 ++ args
+ mb_env <- getGccEnv args1
+ runSomethingFiltered dflags id "C pre-processor" p args1 mb_env
runPp :: DynFlags -> [Option] -> IO ()
runPp dflags args = do
@@ -411,7 +418,8 @@ runPp dflags args = do
runCc :: DynFlags -> [Option] -> IO ()
runCc dflags args = do
let (p,args0) = pgm_c dflags
- (args1,mb_env) <- getGccEnv (args0++args)
+ args1 = args0 ++ args
+ mb_env <- getGccEnv args1
runSomethingFiltered dflags cc_filter "C Compiler" p args1 mb_env
where
-- discard some harmless warnings from gcc that we can't turn off
@@ -467,22 +475,27 @@ runCc dflags args = do
isContainedIn :: String -> String -> Bool
xs `isContainedIn` ys = any (xs `isPrefixOf`) (tails ys)
--- Turn the -B
option to gcc into the GCC_EXEC_PREFIX env var, to
--- workaround a bug in MinGW gcc on Windows Vista, see bug #1110.
-getGccEnv :: [Option] -> IO ([Option], Maybe [(String,String)])
+-- If the -B option is set, add to PATH. This works around
+-- a bug in gcc on Windows Vista where it can't find its auxiliary
+-- binaries (see bug #1110).
+getGccEnv :: [Option] -> IO (Maybe [(String,String)])
getGccEnv opts =
#if __GLASGOW_HASKELL__ < 603
- return (opts,Nothing)
+ return Nothing
#else
if null b_dirs
- then return (opts,Nothing)
+ then return Nothing
else do env <- getEnvironment
- return (rest, Just (("GCC_EXEC_PREFIX", head b_dirs) : env))
+ return (Just (map mangle_path env))
where
- (b_dirs, rest) = partitionWith get_b_opt opts
+ (b_dirs, _) = partitionWith get_b_opt opts
get_b_opt (Option ('-':'B':dir)) = Left dir
get_b_opt other = Right other
+
+ mangle_path (path,paths) | map toUpper path == "PATH"
+ = (path, '\"' : head b_dirs ++ "\";" ++ paths)
+ mangle_path other = other
#endif
runMangle :: DynFlags -> [Option] -> IO ()
@@ -498,19 +511,46 @@ runSplit dflags args = do
runAs :: DynFlags -> [Option] -> IO ()
runAs dflags args = do
let (p,args0) = pgm_a dflags
- runSomething dflags "Assembler" p (args0++args)
+ args1 = args0 ++ args
+ mb_env <- getGccEnv args1
+ runSomethingFiltered dflags id "Assembler" p args1 mb_env
runLink :: DynFlags -> [Option] -> IO ()
runLink dflags args = do
let (p,args0) = pgm_l dflags
- runSomething dflags "Linker" p (args0++args)
+ args1 = args0 ++ args
+ mb_env <- getGccEnv args1
+ runSomethingFiltered dflags id "Linker" p args1 mb_env
runMkDLL :: DynFlags -> [Option] -> IO ()
runMkDLL dflags args = do
let (p,args0) = pgm_dll dflags
- (args1,mb_env) <- getGccEnv (args0++args)
+ args1 = args0 ++ args
+ mb_env <- getGccEnv (args0++args)
runSomethingFiltered dflags id "Make DLL" p args1 mb_env
+runWindres :: DynFlags -> [Option] -> IO ()
+runWindres dflags args = do
+ let (gcc,gcc_args) = pgm_c dflags
+ windres = pgm_windres dflags
+ mb_env <- getGccEnv gcc_args
+ runSomethingFiltered dflags id "Windres" windres
+ -- we must tell windres where to find gcc: it might not be on PATH
+ (Option ("--preprocessor=" ++
+ unwords (map quote (gcc : map showOpt gcc_args ++
+ ["-E", "-xc", "-DRC_INVOKED"])))
+ -- -- use-temp-file is required for windres to interpret the
+ -- quoting in the preprocessor arg above correctly. Without
+ -- this, windres calls the preprocessor with popen, which gets
+ -- the quoting wrong (discovered by experimentation and
+ -- reading the windres sources). See #1828.
+ : Option "--use-temp-file"
+ : args)
+ -- we must use the PATH workaround here too, since windres invokes gcc
+ mb_env
+ where
+ quote x = '\"' : x ++ "\""
+
touch :: DynFlags -> String -> String -> IO ()
touch dflags purpose arg =
runSomething dflags purpose (pgm_T dflags) [FileOption "" arg]
@@ -530,6 +570,10 @@ copyWithHeader dflags purpose maybe_header from to = do
hPutStr h ls
hClose h
+getExtraViaCOpts :: DynFlags -> IO [String]
+getExtraViaCOpts dflags = do
+ f <- readFile (topDir dflags > "extra-gcc-opts")
+ return (words f)
\end{code}
%************************************************************************
@@ -573,13 +617,14 @@ newTempName dflags extn
= do d <- getTempDir dflags
x <- getProcessID
findTempName (d ++ "/ghc" ++ show x ++ "_") 0
- where
+ where
+ findTempName :: FilePath -> Integer -> IO FilePath
findTempName prefix x
- = do let filename = (prefix ++ show x) `joinFileExt` extn
- b <- doesFileExist filename
- if b then findTempName prefix (x+1)
- else do consIORef v_FilesToClean filename -- clean it up later
- return filename
+ = do let filename = (prefix ++ show x) <.> extn
+ b <- doesFileExist filename
+ if b then findTempName prefix (x+1)
+ else do consIORef v_FilesToClean filename -- clean it up later
+ return filename
-- return our temporary directory within tmp_dir, creating one if we
-- don't have one yet
@@ -590,6 +635,8 @@ getTempDir dflags@(DynFlags{tmpDir=tmp_dir})
Nothing ->
do x <- getProcessID
let prefix = tmp_dir ++ "/ghc" ++ show x ++ "_"
+ let
+ mkTempDir :: Integer -> IO FilePath
mkTempDir x
= let dirname = prefix ++ show x
in do createDirectory dirname
@@ -713,7 +760,11 @@ builderMainLoop dflags filter_fn pgm real_args mb_env = do
hSetBuffering hStdErr LineBuffering
forkIO (readerProc chan hStdOut filter_fn)
forkIO (readerProc chan hStdErr filter_fn)
- rc <- loop chan hProcess 2 1 ExitSuccess
+ -- we don't want to finish until 2 streams have been completed
+ -- (stdout and stderr)
+ -- nor until 1 exit code has been retrieved.
+ rc <- loop chan hProcess (2::Integer) (1::Integer) ExitSuccess
+ -- after that, we're done here.
hClose hStdIn
hClose hStdOut
hClose hStdErr
@@ -810,8 +861,7 @@ data BuildMessage
| EOF
#endif
-showOpt (FileOption pre f) = pre ++ platformPath f
-showOpt (Option "") = ""
+showOpt (FileOption pre f) = pre ++ f
showOpt (Option s) = s
traceCmd :: DynFlags -> String -> String -> IO () -> IO ()
@@ -857,7 +907,12 @@ getBaseDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
free buf
return (Just (rootDir s))
where
- rootDir s = reverse (dropList "/bin/ghc.exe" (reverse (normalisePath s)))
+ rootDir s = case splitFileName $ normalise s of
+ (d, "ghc.exe") ->
+ case splitFileName $ takeDirectory d of
+ (d', "bin") -> takeDirectory d'
+ _ -> panic ("Expected \"bin\" in " ++ show s)
+ _ -> panic ("Expected \"ghc.exe\" in " ++ show s)
foreign import stdcall unsafe "GetModuleFileNameA"
getModuleFileName :: Ptr () -> CString -> Int -> IO Int32
@@ -867,12 +922,9 @@ getBaseDir = return Nothing
#ifdef mingw32_HOST_OS
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
+getProcessID = System.Posix.Internals.c_getpid >>= return . fromIntegral
#endif
-- Divvy up text stream into lines, taking platform dependent