1 -----------------------------------------------------------------------------
3 -- (c) The University of Glasgow 2001
5 -- Access to system tools: gcc, cp, rm etc
7 -----------------------------------------------------------------------------
14 setPgmL, -- String -> IO ()
26 -- Command-line override
29 getTopDir, -- IO String -- The value of $libdir
30 getPackageConfigPath, -- IO String -- Where package.conf is
32 -- Interface to system tools
33 runUnlit, runCpp, runCc, -- [Option] -> IO ()
34 runPp, -- [Option] -> IO ()
35 runMangle, runSplit, -- [Option] -> IO ()
36 runAs, runLink, -- [Option] -> IO ()
39 runIlx2il, runIlasm, -- [String] -> IO ()
43 touch, -- String -> String -> IO ()
44 copy, -- String -> String -> String -> IO ()
45 unDosifyPath, -- String -> String
47 -- Temporary-file management
50 cleanTempFiles, cleanTempFilesExcept, removeTmpFiles,
54 getProcessID, -- IO Int
55 system, -- String -> IO ExitCode
58 showGhcUsage, -- IO () Shows usage message and exits
59 getSysMan, -- IO String Parallel system only
65 #include "HsVersions.h"
70 import Panic ( progName, GhcException(..) )
71 import Util ( global, notNull )
72 import CmdLineOpts ( dynFlag, verbosity )
74 import EXCEPTION ( throwDyn )
75 import DATA_IOREF ( IORef, readIORef, writeIORef )
78 import Monad ( when, unless )
79 import System ( ExitCode(..), exitWith, getEnv, system )
80 import IO ( try, catch,
81 openFile, hPutChar, hPutStrLn, hPutStr, hClose, hFlush, IOMode(..),
83 import Directory ( doesFileExist, removeFile )
85 #include "../includes/config.h"
87 -- GHC <= 4.08 didn't have rawSystem, and runs into problems with long command
88 -- lines on mingw32, so we disallow it now.
89 #if defined(mingw32_HOST_OS) && (__GLASGOW_HASKELL__ <= 408)
90 #error GHC <= 4.08 is not supported for bootstrapping GHC on i386-unknown-mingw32
93 #ifndef mingw32_HOST_OS
94 #if __GLASGOW_HASKELL__ > 504
95 import qualified GHC.Posix
97 import qualified Posix
99 #else /* Must be Win32 */
100 import List ( isPrefixOf )
101 import Util ( dropList )
103 import CString ( CString, peekCString )
106 #ifdef mingw32_HOST_OS
107 #if __GLASGOW_HASKELL__ > 504
108 import System.Cmd ( rawSystem )
111 -- For Win32 and GHC <= 504
112 -- rawSystem is defined in this module
113 -- We just need an import
114 #if __GLASGOW_HASKELL__ < 503
115 import PrelIOBase( ioException, IOException(..), IOErrorType(InvalidArgument) )
117 import GHC.IOBase( ioException, IOException(..), IOErrorType(InvalidArgument) )
119 import CError ( throwErrnoIfMinus1 )
120 import CString ( withCString )
123 #else /* Not Win32 */
125 import System ( system )
130 The configuration story
131 ~~~~~~~~~~~~~~~~~~~~~~~
133 GHC needs various support files (library packages, RTS etc), plus
134 various auxiliary programs (cp, gcc, etc). It finds these in one
137 * When running as an *installed program*, GHC finds most of this support
138 stuff in the installed library tree. The path to this tree is passed
139 to GHC via the -B flag, and given to initSysTools .
141 * When running *in-place* in a build tree, GHC finds most of this support
142 stuff in the build tree. The path to the build tree is, again passed
145 GHC tells which of the two is the case by seeing whether package.conf
146 is in TopDir [installed] or in TopDir/ghc/driver [inplace] (what a hack).
149 SysTools.initSysProgs figures out exactly where all the auxiliary programs
150 are, and initialises mutable variables to make it easy to call them.
151 To to this, it makes use of definitions in Config.hs, which is a Haskell
152 file containing variables whose value is figured out by the build system.
154 Config.hs contains two sorts of things
156 cGCC, The *names* of the programs
159 etc They do *not* include paths
162 cUNLIT_DIR_REL The *path* to the directory containing unlit, split etc
163 cSPLIT_DIR_REL *relative* to the root of the build tree,
164 for use when running *in-place* in a build tree (only)
168 ---------------------------------------------
169 NOTES for an ALTERNATIVE scheme (i.e *not* what is currently implemented):
171 Another hair-brained scheme for simplifying the current tool location
172 nightmare in GHC: Simon originally suggested using another
173 configuration file along the lines of GCC's specs file - which is fine
174 except that it means adding code to read yet another configuration
175 file. What I didn't notice is that the current package.conf is
176 general enough to do this:
179 {name = "tools", import_dirs = [], source_dirs = [],
180 library_dirs = [], hs_libraries = [], extra_libraries = [],
181 include_dirs = [], c_includes = [], package_deps = [],
182 extra_ghc_opts = ["-pgmc/usr/bin/gcc","-pgml${libdir}/bin/unlit", ... etc.],
183 extra_cc_opts = [], extra_ld_opts = []}
185 Which would have the advantage that we get to collect together in one
186 place the path-specific package stuff with the path-specific tool
189 ---------------------------------------------
192 %************************************************************************
194 \subsection{Global variables to contain system programs}
196 %************************************************************************
198 All these pathnames are maintained IN THE NATIVE FORMAT OF THE HOST MACHINE.
199 (See remarks under pathnames below)
202 GLOBAL_VAR(v_Pgm_L, error "pgm_L", String) -- unlit
203 GLOBAL_VAR(v_Pgm_P, error "pgm_P", String) -- cpp
204 GLOBAL_VAR(v_Pgm_F, error "pgm_F", String) -- pp
205 GLOBAL_VAR(v_Pgm_c, error "pgm_c", String) -- gcc
206 GLOBAL_VAR(v_Pgm_m, error "pgm_m", String) -- asm code mangler
207 GLOBAL_VAR(v_Pgm_s, error "pgm_s", String) -- asm code splitter
208 GLOBAL_VAR(v_Pgm_a, error "pgm_a", String) -- as
210 GLOBAL_VAR(v_Pgm_I, error "pgm_I", String) -- ilx2il
211 GLOBAL_VAR(v_Pgm_i, error "pgm_i", String) -- ilasm
213 GLOBAL_VAR(v_Pgm_l, error "pgm_l", String) -- ld
214 GLOBAL_VAR(v_Pgm_MkDLL, error "pgm_dll", String) -- mkdll
216 GLOBAL_VAR(v_Pgm_T, error "pgm_T", String) -- touch
217 GLOBAL_VAR(v_Pgm_CP, error "pgm_CP", String) -- cp
219 GLOBAL_VAR(v_Path_package_config, error "path_package_config", String)
220 GLOBAL_VAR(v_Path_usage, error "ghc_usage.txt", String)
222 GLOBAL_VAR(v_TopDir, error "TopDir", String) -- -B<dir>
224 -- Parallel system only
225 GLOBAL_VAR(v_Pgm_sysman, error "pgm_sysman", String) -- system manager
227 -- ways to get at some of these variables from outside this module
228 getPackageConfigPath = readIORef v_Path_package_config
229 getTopDir = readIORef v_TopDir
233 %************************************************************************
235 \subsection{Initialisation}
237 %************************************************************************
240 initSysTools :: [String] -- Command-line arguments starting "-B"
242 -> IO () -- Set all the mutable variables above, holding
243 -- (a) the system programs
244 -- (b) the package-config file
245 -- (c) the GHC usage message
248 initSysTools minusB_args
249 = do { (am_installed, top_dir) <- findTopDir minusB_args
250 ; writeIORef v_TopDir top_dir
252 -- for "installed" this is the root of GHC's support files
253 -- for "in-place" it is the root of the build tree
254 -- NB: top_dir is assumed to be in standard Unix format '/' separated
256 ; let installed, installed_bin :: FilePath -> FilePath
257 installed_bin pgm = pgmPath top_dir pgm
258 installed file = pgmPath top_dir file
259 inplace dir pgm = pgmPath (top_dir `slash`
260 cPROJECT_DIR `slash` dir) pgm
263 | am_installed = installed "package.conf"
264 | otherwise = inplace cGHC_DRIVER_DIR_REL "package.conf.inplace"
267 | am_installed = installed "ghc-usage.txt"
268 | otherwise = inplace cGHC_DRIVER_DIR_REL "ghc-usage.txt"
270 -- For all systems, unlit, split, mangle are GHC utilities
271 -- architecture-specific stuff is done when building Config.hs
273 | am_installed = installed_bin cGHC_UNLIT_PGM
274 | otherwise = inplace cGHC_UNLIT_DIR_REL cGHC_UNLIT_PGM
276 -- split and mangle are Perl scripts
278 | am_installed = installed_bin cGHC_SPLIT_PGM
279 | otherwise = inplace cGHC_SPLIT_DIR_REL cGHC_SPLIT_PGM
282 | am_installed = installed_bin cGHC_MANGLER_PGM
283 | otherwise = inplace cGHC_MANGLER_DIR_REL cGHC_MANGLER_PGM
285 #ifndef mingw32_HOST_OS
286 -- check whether TMPDIR is set in the environment
287 ; IO.try (do dir <- getEnv "TMPDIR" -- fails if not set
292 -- On Win32, consult GetTempPath() for a temp dir.
293 -- => it first tries TMP, TEMP, then finally the
294 -- Windows directory(!). The directory is in short-path
295 -- form and *does* have a trailing backslash.
297 let len = (2048::Int)
298 buf <- mallocArray len
299 ret <- getTempPath len buf
302 -- failed, consult TEMP.
310 -- strip the trailing backslash (awful, but
311 -- we only do this once).
321 -- Check that the package config exists
322 ; config_exists <- doesFileExist pkgconfig_path
323 ; when (not config_exists) $
324 throwDyn (InstallationError
325 ("Can't find package.conf as " ++ pkgconfig_path))
327 #if defined(mingw32_HOST_OS)
328 -- WINDOWS-SPECIFIC STUFF
329 -- On Windows, gcc and friends are distributed with GHC,
330 -- so when "installed" we look in TopDir/bin
331 -- When "in-place" we look wherever the build-time configure
333 -- When "install" we tell gcc where its specs file + exes are (-B)
334 -- and also some places to pick up include files. We need
335 -- to be careful to put all necessary exes in the -B place
336 -- (as, ld, cc1, etc) since if they don't get found there, gcc
337 -- then tries to run unadorned "as", "ld", etc, and will
338 -- pick up whatever happens to be lying around in the path,
339 -- possibly including those from a cygwin install on the target,
340 -- which is exactly what we're trying to avoid.
341 ; let gcc_path | am_installed = installed_bin ("gcc -B\"" ++ installed "gcc-lib/\"")
343 -- The trailing "/" is absolutely essential; gcc seems
344 -- to construct file names simply by concatenating to this
345 -- -B path with no extra slash
346 -- We use "/" rather than "\\" because otherwise "\\\" is mangled
347 -- later on; although gcc_path is in NATIVE format, gcc can cope
348 -- (see comments with declarations of global variables)
350 -- The quotes round the -B argument are in case TopDir has spaces in it
352 perl_path | am_installed = installed_bin cGHC_PERL
353 | otherwise = cGHC_PERL
355 -- 'touch' is a GHC util for Windows, and similarly unlit, mangle
356 ; let touch_path | am_installed = installed_bin cGHC_TOUCHY_PGM
357 | otherwise = inplace cGHC_TOUCHY_DIR_REL cGHC_TOUCHY_PGM
359 -- On Win32 we don't want to rely on #!/bin/perl, so we prepend
360 -- a call to Perl to get the invocation of split and mangle
361 ; let split_path = perl_path ++ " \"" ++ split_script ++ "\""
362 mangle_path = perl_path ++ " \"" ++ mangle_script ++ "\""
365 | am_installed = pgmPath (installed "gcc-lib/") cMKDLL ++
366 " --dlltool-name " ++ pgmPath (installed "gcc-lib/") "dlltool" ++
367 " --driver-name " ++ gcc_path
370 -- UNIX-SPECIFIC STUFF
371 -- On Unix, the "standard" tools are assumed to be
372 -- in the same place whether we are running "in-place" or "installed"
373 -- That place is wherever the build-time configure script found them.
374 ; let gcc_path = cGCC
376 mkdll_path = panic "Can't build DLLs on a non-Win32 system"
378 -- On Unix, scripts are invoked using the '#!' method. Binary
379 -- installations of GHC on Unix place the correct line on the front
380 -- of the script at installation time, so we don't want to wire-in
381 -- our knowledge of $(PERL) on the host system here.
382 ; let split_path = split_script
383 mangle_path = mangle_script
386 -- cpp is derived from gcc on all platforms
387 ; let cpp_path = gcc_path ++ " -E " ++ cRAWCPP_FLAGS
389 -- For all systems, copy and remove are provided by the host
390 -- system; architecture-specific stuff is done when building Config.hs
391 ; let cp_path = cGHC_CP
393 -- Other things being equal, as and ld are simply gcc
394 ; let as_path = gcc_path
398 -- ilx2il and ilasm are specified in Config.hs
399 ; let ilx2il_path = cILX2IL
403 -- Initialise the global vars
404 ; writeIORef v_Path_package_config pkgconfig_path
405 ; writeIORef v_Path_usage ghc_usage_msg_path
407 ; writeIORef v_Pgm_sysman (top_dir ++ "/ghc/rts/parallel/SysMan")
408 -- Hans: this isn't right in general, but you can
409 -- elaborate it in the same way as the others
411 ; writeIORef v_Pgm_L unlit_path
412 ; writeIORef v_Pgm_P cpp_path
413 ; writeIORef v_Pgm_F ""
414 ; writeIORef v_Pgm_c gcc_path
415 ; writeIORef v_Pgm_m mangle_path
416 ; writeIORef v_Pgm_s split_path
417 ; writeIORef v_Pgm_a as_path
419 ; writeIORef v_Pgm_I ilx2il_path
420 ; writeIORef v_Pgm_i ilasm_path
422 ; writeIORef v_Pgm_l ld_path
423 ; writeIORef v_Pgm_MkDLL mkdll_path
424 ; writeIORef v_Pgm_T touch_path
425 ; writeIORef v_Pgm_CP cp_path
430 #if defined(mingw32_HOST_OS)
431 foreign import stdcall "GetTempPathA" unsafe getTempPath :: Int -> CString -> IO Int32
435 The various setPgm functions are called when a command-line option
440 is used to override a particular program with a new one
443 setPgmL = writeIORef v_Pgm_L
444 setPgmP = writeIORef v_Pgm_P
445 setPgmF = writeIORef v_Pgm_F
446 setPgmc = writeIORef v_Pgm_c
447 setPgmm = writeIORef v_Pgm_m
448 setPgms = writeIORef v_Pgm_s
449 setPgma = writeIORef v_Pgm_a
450 setPgml = writeIORef v_Pgm_l
452 setPgmI = writeIORef v_Pgm_I
453 setPgmi = writeIORef v_Pgm_i
460 -- for "installed" this is the root of GHC's support files
461 -- for "in-place" it is the root of the build tree
464 -- 1. Set proto_top_dir
465 -- a) look for (the last) -B flag, and use it
466 -- b) if there are no -B flags, get the directory
467 -- where GHC is running (only on Windows)
469 -- 2. If package.conf exists in proto_top_dir, we are running
470 -- installed; and TopDir = proto_top_dir
472 -- 3. Otherwise we are running in-place, so
473 -- proto_top_dir will be /...stuff.../ghc/compiler
474 -- Set TopDir to /...stuff..., which is the root of the build tree
476 -- This is very gruesome indeed
478 findTopDir :: [String]
479 -> IO (Bool, -- True <=> am installed, False <=> in-place
480 String) -- TopDir (in Unix format '/' separated)
483 = do { top_dir <- get_proto
484 -- Discover whether we're running in a build tree or in an installation,
485 -- by looking for the package configuration file.
486 ; am_installed <- doesFileExist (top_dir `slash` "package.conf")
488 ; return (am_installed, top_dir)
491 -- get_proto returns a Unix-format path (relying on getExecDir to do so too)
492 get_proto | notNull minusbs
493 = return (unDosifyPath (drop 2 (last minusbs))) -- 2 for "-B"
495 = do { maybe_exec_dir <- getExecDir -- Get directory of executable
496 ; case maybe_exec_dir of -- (only works on Windows;
497 -- returns Nothing on Unix)
498 Nothing -> throwDyn (InstallationError "missing -B<dir> option")
499 Just dir -> return dir
504 %************************************************************************
506 \subsection{Command-line options}
508 %************************************************************************
510 When invoking external tools as part of the compilation pipeline, we
511 pass these a sequence of options on the command-line. Rather than
512 just using a list of Strings, we use a type that allows us to distinguish
513 between filepaths and 'other stuff'. [The reason being, of course, that
514 this type gives us a handle on transforming filenames, and filenames only,
515 to whatever format they're expected to be on a particular platform.]
519 = FileOption -- an entry that _contains_ filename(s) / filepaths.
520 String -- a non-filepath prefix that shouldn't be transformed (e.g., "/out="
521 String -- the filepath/filename portion
524 showOptions :: [Option] -> String
525 showOptions ls = unwords (map (quote.showOpt) ls)
527 showOpt (FileOption pre f) = pre ++ dosifyPath f
528 showOpt (Option s) = s
533 %************************************************************************
535 \subsection{Running an external program}
537 %************************************************************************
541 runUnlit :: [Option] -> IO ()
542 runUnlit args = do p <- readIORef v_Pgm_L
543 runSomething "Literate pre-processor" p args
545 runCpp :: [Option] -> IO ()
546 runCpp args = do p <- readIORef v_Pgm_P
547 runSomething "C pre-processor" p args
549 runPp :: [Option] -> IO ()
550 runPp args = do p <- readIORef v_Pgm_F
551 runSomething "Haskell pre-processor" p args
553 runCc :: [Option] -> IO ()
554 runCc args = do p <- readIORef v_Pgm_c
555 runSomething "C Compiler" p args
557 runMangle :: [Option] -> IO ()
558 runMangle args = do p <- readIORef v_Pgm_m
559 runSomething "Mangler" p args
561 runSplit :: [Option] -> IO ()
562 runSplit args = do p <- readIORef v_Pgm_s
563 runSomething "Splitter" p args
565 runAs :: [Option] -> IO ()
566 runAs args = do p <- readIORef v_Pgm_a
567 runSomething "Assembler" p args
569 runLink :: [Option] -> IO ()
570 runLink args = do p <- readIORef v_Pgm_l
571 runSomething "Linker" p args
574 runIlx2il :: [Option] -> IO ()
575 runIlx2il args = do p <- readIORef v_Pgm_I
576 runSomething "Ilx2Il" p args
578 runIlasm :: [Option] -> IO ()
579 runIlasm args = do p <- readIORef v_Pgm_i
580 runSomething "Ilasm" p args
583 runMkDLL :: [Option] -> IO ()
584 runMkDLL args = do p <- readIORef v_Pgm_MkDLL
585 runSomething "Make DLL" p args
587 touch :: String -> String -> IO ()
588 touch purpose arg = do p <- readIORef v_Pgm_T
589 runSomething purpose p [FileOption "" arg]
591 copy :: String -> String -> String -> IO ()
592 copy purpose from to = do
593 verb <- dynFlag verbosity
594 when (verb >= 2) $ hPutStrLn stderr ("*** " ++ purpose)
596 h <- openFile to WriteMode
597 ls <- readFile from -- inefficient, but it'll do for now.
598 -- ToDo: speed up via slurping.
604 getSysMan :: IO String -- How to invoke the system manager
605 -- (parallel system only)
606 getSysMan = readIORef v_Pgm_sysman
609 %************************************************************************
611 \subsection{GHC Usage message}
613 %************************************************************************
615 Show the usage message and exit
618 showGhcUsage = do { usage_path <- readIORef v_Path_usage
619 ; usage <- readFile usage_path
621 ; exitWith ExitSuccess }
624 dump ('$':'$':s) = hPutStr stderr progName >> dump s
625 dump (c:s) = hPutChar stderr c >> dump s
629 %************************************************************************
631 \subsection{Managing temporary files
633 %************************************************************************
636 GLOBAL_VAR(v_FilesToClean, [], [String] )
637 GLOBAL_VAR(v_TmpDir, cDEFAULT_TMPDIR, String )
638 -- v_TmpDir has no closing '/'
642 setTmpDir dir = writeIORef v_TmpDir dir
644 cleanTempFiles :: Int -> IO ()
645 cleanTempFiles verb = do fs <- readIORef v_FilesToClean
646 removeTmpFiles verb fs
648 cleanTempFilesExcept :: Int -> [FilePath] -> IO ()
649 cleanTempFilesExcept verb dont_delete
650 = do fs <- readIORef v_FilesToClean
651 let leftovers = filter (`notElem` dont_delete) fs
652 removeTmpFiles verb leftovers
653 writeIORef v_FilesToClean dont_delete
656 -- find a temporary name that doesn't already exist.
657 newTempName :: Suffix -> IO FilePath
659 = do x <- getProcessID
660 tmp_dir <- readIORef v_TmpDir
661 findTempName tmp_dir x
663 findTempName tmp_dir x
664 = do let filename = tmp_dir ++ "/ghc" ++ show x ++ '.':extn
665 b <- doesFileExist filename
666 if b then findTempName tmp_dir (x+1)
667 else do add v_FilesToClean filename -- clean it up later
670 addFilesToClean :: [FilePath] -> IO ()
671 -- May include wildcards [used by DriverPipeline.run_phase SplitMangle]
672 addFilesToClean files = mapM_ (add v_FilesToClean) files
674 removeTmpFiles :: Int -> [FilePath] -> IO ()
675 removeTmpFiles verb fs
676 = traceCmd "Deleting temp files"
677 ("Deleting: " ++ unwords fs)
680 rm f = removeFile f `IO.catch`
683 hPutStrLn stderr ("Warning: deleting non-existent " ++ f)
689 %************************************************************************
691 \subsection{Running a program}
693 %************************************************************************
696 GLOBAL_VAR(v_Dry_run, False, Bool)
699 setDryRun = writeIORef v_Dry_run True
701 -----------------------------------------------------------------------------
702 -- Running an external program
704 runSomething :: String -- For -v message
705 -> String -- Command name (possibly a full path)
706 -- assumed already dos-ified
707 -> [Option] -- Arguments
708 -- runSomething will dos-ify them
711 runSomething phase_name pgm args
712 = traceCmd phase_name cmd_line $
714 #ifndef mingw32_HOST_OS
715 exit_code <- system cmd_line
717 exit_code <- rawSystem cmd_line
719 ; if exit_code /= ExitSuccess
720 then throwDyn (PhaseFailed phase_name exit_code)
724 -- The pgm is already in native format (appropriate dir separators)
725 cmd_line = pgm ++ ' ':showOptions args
726 -- unwords (pgm : dosifyPaths (map quote args))
728 traceCmd :: String -> String -> IO () -> IO ()
729 -- a) trace the command (at two levels of verbosity)
730 -- b) don't do it at all if dry-run is set
731 traceCmd phase_name cmd_line action
732 = do { verb <- dynFlag verbosity
733 ; when (verb >= 2) $ hPutStrLn stderr ("*** " ++ phase_name)
734 ; when (verb >= 3) $ hPutStrLn stderr cmd_line
738 ; n <- readIORef v_Dry_run
742 ; action `IO.catch` handle_exn verb
745 handle_exn verb exn = do { when (verb >= 2) (hPutStr stderr "\n")
746 ; when (verb >= 3) (hPutStrLn stderr ("Failed: " ++ cmd_line))
747 ; throwDyn (PhaseFailed phase_name (ExitFailure 1)) }
751 %************************************************************************
753 \subsection{Path names}
755 %************************************************************************
757 We maintain path names in Unix form ('/'-separated) right until
758 the last moment. On Windows we dos-ify them just before passing them
759 to the Windows command.
761 The alternative, of using '/' consistently on Unix and '\' on Windows,
762 proved quite awkward. There were a lot more calls to dosifyPath,
763 and even on Windows we might invoke a unix-like utility (eg 'sh'), which
764 interpreted a command line 'foo\baz' as 'foobaz'.
767 -----------------------------------------------------------------------------
768 -- Convert filepath into MSDOS form.
770 dosifyPaths :: [String] -> [String]
771 -- dosifyPaths does two things
772 -- a) change '/' to '\'
773 -- b) remove initial '/cygdrive/'
775 unDosifyPath :: String -> String
776 -- Just change '\' to '/'
778 pgmPath :: String -- Directory string in Unix format
779 -> String -- Program name with no directory separators
781 -> String -- Program invocation string in native format
785 #if defined(mingw32_HOST_OS)
787 --------------------- Windows version ------------------
788 dosifyPaths xs = map dosifyPath xs
790 unDosifyPath xs = subst '\\' '/' xs
792 pgmPath dir pgm = dosifyPath dir ++ '\\' : pgm
795 = subst '/' '\\' real_stuff
797 -- fully convince myself that /cygdrive/ prefixes cannot
798 -- really appear here.
799 cygdrive_prefix = "/cygdrive/"
802 | cygdrive_prefix `isPrefixOf` stuff = dropList cygdrive_prefix stuff
807 --------------------- Unix version ---------------------
810 pgmPath dir pgm = dir ++ '/' : pgm
811 dosifyPath stuff = stuff
812 --------------------------------------------------------
815 subst a b ls = map (\ x -> if x == a then b else x) ls
819 -----------------------------------------------------------------------------
820 Path name construction
823 slash :: String -> String -> String
824 absPath, relPath :: [String] -> String
827 relPath xs = foldr1 slash xs
829 absPath xs = "" `slash` relPath xs
831 slash s1 s2 = s1 ++ ('/' : s2)
835 %************************************************************************
837 \subsection{Support code}
839 %************************************************************************
842 -----------------------------------------------------------------------------
843 -- Define getExecDir :: IO (Maybe String)
845 #if defined(mingw32_HOST_OS)
846 getExecDir :: IO (Maybe String)
847 getExecDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
848 buf <- mallocArray len
849 ret <- getModuleFileName nullPtr buf len
850 if ret == 0 then free buf >> return Nothing
851 else do s <- peekCString buf
853 return (Just (reverse (dropList "/bin/ghc.exe" (reverse (unDosifyPath s)))))
856 foreign import stdcall "GetModuleFileNameA" unsafe
857 getModuleFileName :: Ptr () -> CString -> Int -> IO Int32
859 getExecDir :: IO (Maybe String) = do return Nothing
862 #ifdef mingw32_HOST_OS
863 foreign import "_getpid" unsafe getProcessID :: IO Int -- relies on Int == Int32 on Windows
864 #elif __GLASGOW_HASKELL__ > 504
865 getProcessID :: IO Int
866 getProcessID = GHC.Posix.c_getpid >>= return . fromIntegral
868 getProcessID :: IO Int
869 getProcessID = Posix.getProcessID
872 quote :: String -> String
873 #if defined(mingw32_HOST_OS)
875 quote s = "\"" ++ s ++ "\""
882 This next blob is in System.Cmd after 5.04, but until then it needs
883 to be here (for Win32 only).
886 #if defined(mingw32_HOST_OS)
887 #if __GLASGOW_HASKELL__ <= 504
889 rawSystem :: String -> IO ExitCode
890 rawSystem "" = ioException (IOError Nothing InvalidArgument "rawSystem" "null command" Nothing)
892 withCString cmd $ \s -> do
893 status <- throwErrnoIfMinus1 "rawSystem" (primRawSystem s)
895 0 -> return ExitSuccess
896 n -> return (ExitFailure n)
898 foreign import ccall "rawSystemCmd" unsafe primRawSystem :: CString -> IO Int