-----------------------------------------------------------------------------
--- Access to system tools: gcc, cp, rm etc
--
--- (c) The University of Glasgow 2000
+-- (c) The University of Glasgow 2001
+--
+-- Access to system tools: gcc, cp, rm etc
--
-----------------------------------------------------------------------------
-- Command-line override
setDryRun,
- packageConfigPath, -- IO String
- -- Where package.conf is
+ getTopDir, -- IO String -- The value of $libdir
+ getPackageConfigPath, -- IO String -- Where package.conf is
-- Interface to system tools
runUnlit, runCpp, runCc, -- [Option] -> IO ()
runMangle, runSplit, -- [Option] -> IO ()
runAs, runLink, -- [Option] -> IO ()
runMkDLL,
+#ifdef ILX
+ runIlx2il, runIlasm, -- [String] -> IO ()
+#endif
+
touch, -- String -> String -> IO ()
copy, -- String -> String -> String -> IO ()
#else
import List ( isPrefixOf )
import MarshalArray
-import SystemExts ( rawSystem )
+#endif
+
+-- This is a kludge for bootstrapping with 4.08.X. Given that
+-- all distributed compilers >= 5.0 will be compiled with themselves.
+-- I don't think this kludge is a problem. And we have to start
+-- building with >= 5.0 on Win32 anyway.
+#if __GLASGOW_HASKELL__ > 408
+-- use the line below when we can be sure of compiling with GHC >=
+-- 5.02, and remove the implementation of rawSystem at the end of this
+-- file
+import PrelIOBase -- this can be removed when SystemExts is used
+import CError ( throwErrnoIfMinus1 ) -- as can this
+-- import SystemExts ( rawSystem )
+#else
+import System ( system )
#endif
#include "HsVersions.h"
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
+#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_Path_package_config, error "path_package_config", String)
GLOBAL_VAR(v_Path_usage, error "ghc_usage.txt", String)
+GLOBAL_VAR(v_TopDir, error "TopDir", String) -- -B<dir>
+
-- Parallel system only
GLOBAL_VAR(v_Pgm_sysman, error "pgm_sysman", String) -- system manager
+
+-- ways to get at some of these variables from outside this module
+getPackageConfigPath = readIORef v_Path_package_config
+getTopDir = readIORef v_TopDir
\end{code}
\begin{code}
initSysTools :: [String] -- Command-line arguments starting "-B"
- -> IO String -- Set all the mutable variables above, holding
+ -> IO () -- Set all the mutable variables above, holding
-- (a) the system programs
-- (b) the package-config file
-- (c) the GHC usage message
- -- Return TopDir
initSysTools minusB_args
- = do { (am_installed, top_dir) <- getTopDir minusB_args
+ = do { (am_installed, top_dir) <- findTopDir minusB_args
+ ; writeIORef v_TopDir top_dir
-- top_dir
-- for "installed" this is the root of GHC's support files
-- for "in-place" it is the root of the build tree
-- NB: top_dir is assumed to be in standard Unix format '/' separated
; let installed, installed_bin :: FilePath -> FilePath
- installed_bin pgm = pgmPath (top_dir `slash` "extra-bin") pgm
+ installed_bin pgm = pgmPath top_dir pgm
installed file = pgmPath top_dir file
inplace dir pgm = pgmPath (top_dir `slash` dir) pgm
setTmpDir dir
return ()
)
+#else
+ -- 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.
+ ; IO.try (do
+ let len = (2048::Int)
+ buf <- mallocArray len
+ ret <- getTempPath len buf
+ tdir <-
+ if ret == 0 then do
+ -- failed, consult TEMP.
+ destructArray len buf
+ getEnv "TMP"
+ else do
+ s <- peekCString buf
+ destructArray len 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 ())
#endif
-- Check that the package config exists
; let as_path = gcc_path
ld_path = gcc_path
+#ifdef ILX
+ -- ilx2il and ilasm are specified in Config.hs
+ ; let ilx2il_path = cILX2IL
+ ilasm_path = cILASM
+#endif
-- Initialise the global vars
; writeIORef v_Path_package_config pkgconfig_path
; writeIORef v_Pgm_m mangle_path
; writeIORef v_Pgm_s split_path
; writeIORef v_Pgm_a as_path
+#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_T touch_path
; writeIORef v_Pgm_CP cp_path
- ; return top_dir
+ ; return ()
}
+
+#if defined(mingw32_TARGET_OS)
+foreign import stdcall "GetTempPathA" getTempPath :: Int -> CString -> IO Int32
+#endif
\end{code}
setPgm is called when a command-line option like
-pgmLld
-is used to override a particular program with a new onw
+is used to override a particular program with a new one
\begin{code}
setPgm :: String -> IO ()
setPgm ('s' : pgm) = writeIORef v_Pgm_s pgm
setPgm ('a' : pgm) = writeIORef v_Pgm_a pgm
setPgm ('l' : pgm) = writeIORef v_Pgm_l pgm
+#ifdef ILX
+setPgm ('I' : pgm) = writeIORef v_Pgm_I pgm
+setPgm ('i' : pgm) = writeIORef v_Pgm_i pgm
+#endif
setPgm pgm = unknownFlagErr ("-pgm" ++ pgm)
\end{code}
--
-- This is very gruesome indeed
-getTopDir :: [String]
+findTopDir :: [String]
-> IO (Bool, -- True <=> am installed, False <=> in-place
String) -- TopDir (in Unix format '/' separated)
-getTopDir minusbs
+findTopDir minusbs
= 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.
this type gives us a handle on transforming filenames, and filenames only,
to whatever format they're expected to be on a particular platform.]
-
\begin{code}
data Option
- = FileOption String
+ = FileOption -- an entry that _contains_ filename(s) / filepaths.
+ String -- a non-filepath prefix that shouldn't be transformed (e.g., "/out="
+ String -- the filepath/filename portion
| Option String
showOptions :: [Option] -> String
showOptions ls = unwords (map (quote.showOpt) ls)
where
- showOpt (FileOption f) = dosifyPath f
+ showOpt (FileOption pre f) = pre ++ dosifyPath f
showOpt (Option s) = s
#if defined(mingw32_TARGET_OS)
runLink args = do p <- readIORef v_Pgm_l
runSomething "Linker" p args
+#ifdef ILX
+runIlx2il :: [Option] -> IO ()
+runIlx2il args = do p <- readIORef v_Pgm_I
+ runSomething "Ilx2Il" p args
+
+runIlasm :: [Option] -> IO ()
+runIlasm args = do p <- readIORef v_Pgm_i
+ runSomething "Ilasm" p args
+#endif
+
runMkDLL :: [Option] -> IO ()
runMkDLL args = do p <- readIORef v_Pgm_MkDLL
runSomething "Make DLL" p args
touch :: String -> String -> IO ()
touch purpose arg = do p <- readIORef v_Pgm_T
- runSomething purpose p [FileOption arg]
+ runSomething purpose p [FileOption "" arg]
copy :: String -> String -> String -> IO ()
copy purpose from to = do
dump "" = return ()
dump ('$':'$':s) = hPutStr stderr progName >> dump s
dump (c:s) = hPutChar stderr c >> dump s
-
-packageConfigPath = readIORef v_Path_package_config
\end{code}
slash :: String -> String -> String
absPath, relPath :: [String] -> String
-isSlash '/' = True
-isSlash other = False
-
relPath [] = ""
relPath xs = foldr1 slash xs
#if defined(mingw32_TARGET_OS)
getExecDir :: IO (Maybe String)
-getExecDir = do let len = 2048 -- plenty, PATH_MAX is 512 under Win32.
- buf <- mallocArray (fromIntegral len)
+getExecDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
+ buf <- mallocArray len
ret <- getModuleFileName nullAddr buf len
- if ret == 0 then return Nothing
+ if ret == 0 then destructArray len buf >> return Nothing
else do s <- peekCString buf
- destructArray (fromIntegral len) buf
+ destructArray len buf
return (Just (reverse (drop (length "/bin/ghc.exe") (reverse (unDosifyPath s)))))
-foreign import stdcall "GetModuleFileNameA" getModuleFileName :: Addr -> CString -> Int32 -> IO Int32
+foreign import stdcall "GetModuleFileNameA" getModuleFileName :: Addr -> CString -> Int -> IO Int32
#else
getExecDir :: IO (Maybe String) = do return Nothing
#endif
getProcessID :: IO Int
getProcessID = Posix.getProcessID
#endif
+
+rawSystem :: String -> IO ExitCode
+#if __GLASGOW_HASKELL__ > 408
+rawSystem "" = ioException (IOError Nothing InvalidArgument "rawSystem" "null command" Nothing)
+rawSystem cmd =
+ withCString cmd $ \s -> do
+ status <- throwErrnoIfMinus1 "rawSystem" (primRawSystem s)
+ case status of
+ 0 -> return ExitSuccess
+ n -> return (ExitFailure n)
+
+foreign import ccall "rawSystemCmd" unsafe primRawSystem :: CString -> IO Int
+#else
+rawSystem = System.system
+#endif
+
+
\end{code}