[project @ 2003-06-12 16:25:31 by simonmar]
[ghc-hetmet.git] / ghc / compiler / main / SysTools.lhs
1 -----------------------------------------------------------------------------
2 --
3 -- (c) The University of Glasgow 2001
4 --
5 -- Access to system tools: gcc, cp, rm etc
6 --
7 -----------------------------------------------------------------------------
8
9 \begin{code}
10 module SysTools (
11         -- Initialisation
12         initSysTools,
13
14         setPgmL,                -- String -> IO ()
15         setPgmP,
16         setPgmF,
17         setPgmc,
18         setPgmm,
19         setPgms,
20         setPgma,
21         setPgml,
22 #ifdef ILX
23         setPgmI,
24         setPgmi,
25 #endif
26                                 -- Command-line override
27         setDryRun,
28
29         getTopDir,              -- IO String    -- The value of $libdir
30         getPackageConfigPath,   -- IO String    -- Where package.conf is
31
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 ()
37         runMkDLL,
38 #ifdef ILX
39         runIlx2il, runIlasm,     -- [String] -> IO ()
40 #endif
41
42
43         touch,                  -- String -> String -> IO ()
44         copy,                   -- String -> String -> String -> IO ()
45         normalisePath,          -- FilePath -> FilePath
46         
47         -- Temporary-file management
48         setTmpDir,
49         newTempName,
50         cleanTempFiles, cleanTempFilesExcept, removeTmpFiles,
51         addFilesToClean,
52
53         -- System interface
54         getProcessID,           -- IO Int
55         system,                 -- String -> IO ExitCode
56
57         -- Misc
58         showGhcUsage,           -- IO ()        Shows usage message and exits
59         getSysMan,              -- IO String    Parallel system only
60         
61         Option(..)
62
63  ) where
64
65 #include "HsVersions.h"
66
67 import DriverUtil
68 import Config
69 import Outputable
70 import Panic            ( progName, GhcException(..) )
71 import Util             ( global, notNull )
72 import CmdLineOpts      ( dynFlag, verbosity )
73
74 import EXCEPTION        ( throwDyn )
75 import DATA_IOREF       ( IORef, readIORef, writeIORef )
76 import DATA_INT
77     
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(..),
82                           stderr )
83 import Directory        ( doesFileExist, removeFile )
84 import List             ( intersperse )
85
86 #include "../includes/config.h"
87
88 -- GHC <= 4.08 didn't have rawSystem, and runs into problems with long command
89 -- lines on mingw32, so we disallow it now.
90 #if __GLASGOW_HASKELL__ < 500
91 #error GHC >= 5.00 is required for bootstrapping GHC
92 #endif
93
94 #ifndef mingw32_HOST_OS
95 #if __GLASGOW_HASKELL__ > 504
96 import qualified System.Posix.Internals
97 #else
98 import qualified Posix
99 #endif
100 #else /* Must be Win32 */
101 import List             ( isPrefixOf )
102 import Util             ( dropList )
103 import Foreign
104 import CString          ( CString, peekCString )
105 #endif
106
107 #if __GLASGOW_HASKELL__ < 601
108 import Foreign          ( withMany, withArray0, nullPtr, Ptr )
109 import CForeign         ( CString, withCString, throwErrnoIfMinus1 )
110 #else
111 import System.Cmd       ( rawSystem )
112 #endif
113 \end{code}
114
115
116                 The configuration story
117                 ~~~~~~~~~~~~~~~~~~~~~~~
118
119 GHC needs various support files (library packages, RTS etc), plus
120 various auxiliary programs (cp, gcc, etc).  It finds these in one
121 of two places:
122
123 * When running as an *installed program*, GHC finds most of this support
124   stuff in the installed library tree.  The path to this tree is passed
125   to GHC via the -B flag, and given to initSysTools .
126
127 * When running *in-place* in a build tree, GHC finds most of this support
128   stuff in the build tree.  The path to the build tree is, again passed
129   to GHC via -B. 
130
131 GHC tells which of the two is the case by seeing whether package.conf
132 is in TopDir [installed] or in TopDir/ghc/driver [inplace] (what a hack).
133
134
135 SysTools.initSysProgs figures out exactly where all the auxiliary programs
136 are, and initialises mutable variables to make it easy to call them.
137 To to this, it makes use of definitions in Config.hs, which is a Haskell
138 file containing variables whose value is figured out by the build system.
139
140 Config.hs contains two sorts of things
141
142   cGCC,         The *names* of the programs
143   cCPP            e.g.  cGCC = gcc
144   cUNLIT                cCPP = gcc -E
145   etc           They do *not* include paths
146                                 
147
148   cUNLIT_DIR_REL   The *path* to the directory containing unlit, split etc
149   cSPLIT_DIR_REL   *relative* to the root of the build tree,
150                    for use when running *in-place* in a build tree (only)
151                 
152
153
154 ---------------------------------------------
155 NOTES for an ALTERNATIVE scheme (i.e *not* what is currently implemented):
156
157 Another hair-brained scheme for simplifying the current tool location
158 nightmare in GHC: Simon originally suggested using another
159 configuration file along the lines of GCC's specs file - which is fine
160 except that it means adding code to read yet another configuration
161 file.  What I didn't notice is that the current package.conf is
162 general enough to do this:
163
164 Package
165     {name = "tools",    import_dirs = [],  source_dirs = [],
166      library_dirs = [], hs_libraries = [], extra_libraries = [],
167      include_dirs = [], c_includes = [],   package_deps = [],
168      extra_ghc_opts = ["-pgmc/usr/bin/gcc","-pgml${libdir}/bin/unlit", ... etc.],
169      extra_cc_opts = [], extra_ld_opts = []}
170
171 Which would have the advantage that we get to collect together in one
172 place the path-specific package stuff with the path-specific tool
173 stuff.
174                 End of NOTES
175 ---------------------------------------------
176
177
178 %************************************************************************
179 %*                                                                      *
180 \subsection{Global variables to contain system programs}
181 %*                                                                      *
182 %************************************************************************
183
184 All these pathnames are maintained IN THE NATIVE FORMAT OF THE HOST MACHINE.
185 (See remarks under pathnames below)
186
187 \begin{code}
188 GLOBAL_VAR(v_Pgm_L,     error "pgm_L",   String)        -- unlit
189 GLOBAL_VAR(v_Pgm_P,     error "pgm_P",   (String,[Option]))     -- cpp
190 GLOBAL_VAR(v_Pgm_F,     error "pgm_F",   String)        -- pp
191 GLOBAL_VAR(v_Pgm_c,     error "pgm_c",   String)        -- gcc
192 GLOBAL_VAR(v_Pgm_m,     error "pgm_m",   String)        -- asm code mangler
193 GLOBAL_VAR(v_Pgm_s,     error "pgm_s",   String)        -- asm code splitter
194 GLOBAL_VAR(v_Pgm_a,     error "pgm_a",   String)        -- as
195 #ifdef ILX
196 GLOBAL_VAR(v_Pgm_I,     error "pgm_I",   String)        -- ilx2il
197 GLOBAL_VAR(v_Pgm_i,     error "pgm_i",   String)        -- ilasm
198 #endif
199 GLOBAL_VAR(v_Pgm_l,     error "pgm_l",   String)        -- ld
200 GLOBAL_VAR(v_Pgm_MkDLL, error "pgm_dll", String)        -- mkdll
201
202 GLOBAL_VAR(v_Pgm_T,    error "pgm_T",    String)        -- touch
203 GLOBAL_VAR(v_Pgm_CP,   error "pgm_CP",   String)        -- cp
204
205 GLOBAL_VAR(v_Path_package_config, error "path_package_config", String)
206 GLOBAL_VAR(v_Path_usage,          error "ghc_usage.txt",       String)
207
208 GLOBAL_VAR(v_TopDir,    error "TopDir", String)         -- -B<dir>
209
210 -- Parallel system only
211 GLOBAL_VAR(v_Pgm_sysman, error "pgm_sysman", String)    -- system manager
212
213 -- ways to get at some of these variables from outside this module
214 getPackageConfigPath = readIORef v_Path_package_config
215 getTopDir            = readIORef v_TopDir
216 \end{code}
217
218
219 %************************************************************************
220 %*                                                                      *
221 \subsection{Initialisation}
222 %*                                                                      *
223 %************************************************************************
224
225 \begin{code}
226 initSysTools :: [String]        -- Command-line arguments starting "-B"
227
228              -> IO ()           -- Set all the mutable variables above, holding 
229                                 --      (a) the system programs
230                                 --      (b) the package-config file
231                                 --      (c) the GHC usage message
232
233
234 initSysTools minusB_args
235   = do  { (am_installed, top_dir) <- findTopDir minusB_args
236         ; writeIORef v_TopDir top_dir
237                 -- top_dir
238                 --      for "installed" this is the root of GHC's support files
239                 --      for "in-place" it is the root of the build tree
240                 -- NB: top_dir is assumed to be in standard Unix format '/' separated
241
242         ; let installed, installed_bin :: FilePath -> FilePath
243               installed_bin pgm   =  pgmPath top_dir pgm
244               installed     file  =  pgmPath top_dir file
245               inplace dir   pgm   =  pgmPath (top_dir `slash` 
246                                                 cPROJECT_DIR `slash` dir) pgm
247
248         ; let pkgconfig_path
249                 | am_installed = installed "package.conf"
250                 | otherwise    = inplace cGHC_DRIVER_DIR_REL "package.conf.inplace"
251
252               ghc_usage_msg_path
253                 | am_installed = installed "ghc-usage.txt"
254                 | otherwise    = inplace cGHC_DRIVER_DIR_REL "ghc-usage.txt"
255
256                 -- For all systems, unlit, split, mangle are GHC utilities
257                 -- architecture-specific stuff is done when building Config.hs
258               unlit_path
259                 | am_installed = installed_bin cGHC_UNLIT_PGM
260                 | otherwise    = inplace cGHC_UNLIT_DIR_REL cGHC_UNLIT_PGM
261
262                 -- split and mangle are Perl scripts
263               split_script
264                 | am_installed = installed_bin cGHC_SPLIT_PGM
265                 | otherwise    = inplace cGHC_SPLIT_DIR_REL cGHC_SPLIT_PGM
266
267               mangle_script
268                 | am_installed = installed_bin cGHC_MANGLER_PGM
269                 | otherwise    = inplace cGHC_MANGLER_DIR_REL cGHC_MANGLER_PGM
270
271 #ifndef mingw32_HOST_OS
272         -- check whether TMPDIR is set in the environment
273         ; IO.try (do dir <- getEnv "TMPDIR" -- fails if not set
274                      setTmpDir dir
275                      return ()
276                  )
277 #else
278           -- On Win32, consult GetTempPath() for a temp dir.
279           --  => it first tries TMP, TEMP, then finally the
280           --   Windows directory(!). The directory is in short-path
281           --   form and *does* have a trailing backslash.
282         ; IO.try (do
283                 let len = (2048::Int)
284                 buf  <- mallocArray len
285                 ret  <- getTempPath len buf
286                 tdir <-
287                   if ret == 0 then do
288                       -- failed, consult TEMP.
289                      free buf
290                      getEnv "TMP"
291                    else do
292                      s <- peekCString buf
293                      free buf
294                      return s
295                 let
296                   -- strip the trailing backslash (awful, but 
297                   -- we only do this once).
298                   tmpdir =
299                     case last tdir of
300                       '/'  -> init tdir
301                       '\\' -> init tdir
302                       _   -> tdir
303                 setTmpDir tmpdir
304                 return ())
305 #endif
306
307         -- Check that the package config exists
308         ; config_exists <- doesFileExist pkgconfig_path
309         ; when (not config_exists) $
310              throwDyn (InstallationError 
311                          ("Can't find package.conf as " ++ pkgconfig_path))
312
313 #if defined(mingw32_HOST_OS)
314         --              WINDOWS-SPECIFIC STUFF
315         -- On Windows, gcc and friends are distributed with GHC,
316         --      so when "installed" we look in TopDir/bin
317         -- When "in-place" we look wherever the build-time configure 
318         --      script found them
319         -- When "install" we tell gcc where its specs file + exes are (-B)
320         --      and also some places to pick up include files.  We need
321         --      to be careful to put all necessary exes in the -B place
322         --      (as, ld, cc1, etc) since if they don't get found there, gcc
323         --      then tries to run unadorned "as", "ld", etc, and will
324         --      pick up whatever happens to be lying around in the path,
325         --      possibly including those from a cygwin install on the target,
326         --      which is exactly what we're trying to avoid.
327         ; let gcc_path  | am_installed = installed_bin ("gcc -B\"" ++ installed "gcc-lib/\"")
328                         | otherwise    = cGCC
329                 -- The trailing "/" is absolutely essential; gcc seems
330                 -- to construct file names simply by concatenating to this
331                 -- -B path with no extra slash
332                 -- We use "/" rather than "\\" because otherwise "\\\" is mangled
333                 -- later on; although gcc_path is in NATIVE format, gcc can cope
334                 --      (see comments with declarations of global variables)
335                 --
336                 -- The quotes round the -B argument are in case TopDir has spaces in it
337
338               perl_path | am_installed = installed_bin cGHC_PERL
339                         | otherwise    = cGHC_PERL
340
341         -- 'touch' is a GHC util for Windows, and similarly unlit, mangle
342         ; let touch_path  | am_installed = installed_bin cGHC_TOUCHY_PGM
343                           | otherwise    = inplace cGHC_TOUCHY_DIR_REL cGHC_TOUCHY_PGM
344
345         -- On Win32 we don't want to rely on #!/bin/perl, so we prepend 
346         -- a call to Perl to get the invocation of split and mangle
347         ; let split_path  = perl_path ++ " \"" ++ split_script ++ "\""
348               mangle_path = perl_path ++ " \"" ++ mangle_script ++ "\""
349
350         ; let mkdll_path 
351                 | am_installed = pgmPath (installed "gcc-lib/") cMKDLL ++
352                                  " --dlltool-name " ++ pgmPath (installed "gcc-lib/") "dlltool" ++
353                                  " --driver-name " ++ gcc_path
354                 | otherwise    = cMKDLL
355 #else
356         --              UNIX-SPECIFIC STUFF
357         -- On Unix, the "standard" tools are assumed to be
358         -- in the same place whether we are running "in-place" or "installed"
359         -- That place is wherever the build-time configure script found them.
360         ; let   gcc_path   = cGCC
361                 touch_path = "touch"
362                 mkdll_path = panic "Can't build DLLs on a non-Win32 system"
363
364         -- On Unix, scripts are invoked using the '#!' method.  Binary
365         -- installations of GHC on Unix place the correct line on the front
366         -- of the script at installation time, so we don't want to wire-in
367         -- our knowledge of $(PERL) on the host system here.
368         ; let split_path  = split_script
369               mangle_path = mangle_script
370 #endif
371
372         -- cpp is derived from gcc on all platforms
373         -- HACK, see setPgmP below. We keep 'words' here to remember to fix
374         -- Config.hs one day.
375         ; let cpp_path  = (gcc_path, (Option "-E"):(map Option (words cRAWCPP_FLAGS)))
376
377         -- For all systems, copy and remove are provided by the host
378         -- system; architecture-specific stuff is done when building Config.hs
379         ; let   cp_path = cGHC_CP
380         
381         -- Other things being equal, as and ld are simply gcc
382         ; let   as_path  = gcc_path
383                 ld_path  = gcc_path
384
385 #ifdef ILX
386        -- ilx2il and ilasm are specified in Config.hs
387        ; let    ilx2il_path = cILX2IL
388                 ilasm_path  = cILASM
389 #endif
390                                        
391         -- Initialise the global vars
392         ; writeIORef v_Path_package_config pkgconfig_path
393         ; writeIORef v_Path_usage          ghc_usage_msg_path
394
395         ; writeIORef v_Pgm_sysman          (top_dir ++ "/ghc/rts/parallel/SysMan")
396                 -- Hans: this isn't right in general, but you can 
397                 -- elaborate it in the same way as the others
398
399         ; writeIORef v_Pgm_L               unlit_path
400         ; writeIORef v_Pgm_P               cpp_path
401         ; writeIORef v_Pgm_F               ""
402         ; writeIORef v_Pgm_c               gcc_path
403         ; writeIORef v_Pgm_m               mangle_path
404         ; writeIORef v_Pgm_s               split_path
405         ; writeIORef v_Pgm_a               as_path
406 #ifdef ILX
407         ; writeIORef v_Pgm_I               ilx2il_path
408         ; writeIORef v_Pgm_i               ilasm_path
409 #endif
410         ; writeIORef v_Pgm_l               ld_path
411         ; writeIORef v_Pgm_MkDLL           mkdll_path
412         ; writeIORef v_Pgm_T               touch_path
413         ; writeIORef v_Pgm_CP              cp_path
414
415         ; return ()
416         }
417
418 #if defined(mingw32_HOST_OS)
419 foreign import stdcall "GetTempPathA" unsafe getTempPath :: Int -> CString -> IO Int32
420 #endif
421 \end{code}
422
423 The various setPgm functions are called when a command-line option
424 like
425
426         -pgmLld
427
428 is used to override a particular program with a new one
429
430 \begin{code}
431 setPgmL = writeIORef v_Pgm_L
432 -- XXX HACK: Prelude> words "'does not' work" ===> ["'does","not'","work"]
433 -- Config.hs should really use Option.
434 setPgmP arg = let (pgm:args) = words arg in writeIORef v_Pgm_P (pgm,map Option args)
435 setPgmF = writeIORef v_Pgm_F
436 setPgmc = writeIORef v_Pgm_c
437 setPgmm = writeIORef v_Pgm_m
438 setPgms = writeIORef v_Pgm_s
439 setPgma = writeIORef v_Pgm_a
440 setPgml = writeIORef v_Pgm_l
441 #ifdef ILX
442 setPgmI = writeIORef v_Pgm_I
443 setPgmi = writeIORef v_Pgm_i
444 #endif
445 \end{code}
446
447
448 \begin{code}
449 -- Find TopDir
450 --      for "installed" this is the root of GHC's support files
451 --      for "in-place" it is the root of the build tree
452 --
453 -- Plan of action:
454 -- 1. Set proto_top_dir
455 --      a) look for (the last) -B flag, and use it
456 --      b) if there are no -B flags, get the directory 
457 --         where GHC is running (only on Windows)
458 --
459 -- 2. If package.conf exists in proto_top_dir, we are running
460 --      installed; and TopDir = proto_top_dir
461 --
462 -- 3. Otherwise we are running in-place, so
463 --      proto_top_dir will be /...stuff.../ghc/compiler
464 --      Set TopDir to /...stuff..., which is the root of the build tree
465 --
466 -- This is very gruesome indeed
467
468 findTopDir :: [String]
469           -> IO (Bool,          -- True <=> am installed, False <=> in-place
470                  String)        -- TopDir (in Unix format '/' separated)
471
472 findTopDir minusbs
473   = do { top_dir <- get_proto
474         -- Discover whether we're running in a build tree or in an installation,
475         -- by looking for the package configuration file.
476        ; am_installed <- doesFileExist (top_dir `slash` "package.conf")
477
478        ; return (am_installed, top_dir)
479        }
480   where
481     -- get_proto returns a Unix-format path (relying on getBaseDir to do so too)
482     get_proto | notNull minusbs
483               = return (normalisePath (drop 2 (last minusbs)))  -- 2 for "-B"
484               | otherwise          
485               = do { maybe_exec_dir <- getBaseDir -- Get directory of executable
486                    ; case maybe_exec_dir of       -- (only works on Windows; 
487                                                   --  returns Nothing on Unix)
488                         Nothing  -> throwDyn (InstallationError "missing -B<dir> option")
489                         Just dir -> return dir
490                    }
491 \end{code}
492
493
494 %************************************************************************
495 %*                                                                      *
496 \subsection{Command-line options}
497 n%*                                                                     *
498 %************************************************************************
499
500 When invoking external tools as part of the compilation pipeline, we
501 pass these a sequence of options on the command-line. Rather than
502 just using a list of Strings, we use a type that allows us to distinguish
503 between filepaths and 'other stuff'. [The reason being, of course, that
504 this type gives us a handle on transforming filenames, and filenames only,
505 to whatever format they're expected to be on a particular platform.]
506
507 \begin{code}
508 data Option
509  = FileOption -- an entry that _contains_ filename(s) / filepaths.
510               String  -- a non-filepath prefix that shouldn't be transformed (e.g., "/out=" 
511               String  -- the filepath/filename portion
512  | Option     String
513  
514 showOpt (FileOption pre f) = pre ++ platformPath f
515 showOpt (Option "") = ""
516 showOpt (Option s)  = s
517
518 \end{code}
519
520
521 %************************************************************************
522 %*                                                                      *
523 \subsection{Running an external program}
524 %*                                                                      *
525 %************************************************************************
526
527
528 \begin{code}
529 runUnlit :: [Option] -> IO ()
530 runUnlit args = do p <- readIORef v_Pgm_L
531                    runSomething "Literate pre-processor" p args
532
533 runCpp :: [Option] -> IO ()
534 runCpp args =   do (p,baseArgs) <- readIORef v_Pgm_P
535                    runSomething "C pre-processor" p (baseArgs ++ args)
536
537 runPp :: [Option] -> IO ()
538 runPp args =   do p <- readIORef v_Pgm_F
539                   runSomething "Haskell pre-processor" p args
540
541 runCc :: [Option] -> IO ()
542 runCc args =   do p <- readIORef v_Pgm_c
543                   runSomething "C Compiler" p args
544
545 runMangle :: [Option] -> IO ()
546 runMangle args = do p <- readIORef v_Pgm_m
547                     runSomething "Mangler" p args
548
549 runSplit :: [Option] -> IO ()
550 runSplit args = do p <- readIORef v_Pgm_s
551                    runSomething "Splitter" p args
552
553 runAs :: [Option] -> IO ()
554 runAs args = do p <- readIORef v_Pgm_a
555                 runSomething "Assembler" p args
556
557 runLink :: [Option] -> IO ()
558 runLink args = do p <- readIORef v_Pgm_l
559                   runSomething "Linker" p args
560
561 #ifdef ILX
562 runIlx2il :: [Option] -> IO ()
563 runIlx2il args = do p <- readIORef v_Pgm_I
564                     runSomething "Ilx2Il" p args
565
566 runIlasm :: [Option] -> IO ()
567 runIlasm args = do p <- readIORef v_Pgm_i
568                    runSomething "Ilasm" p args
569 #endif
570
571 runMkDLL :: [Option] -> IO ()
572 runMkDLL args = do p <- readIORef v_Pgm_MkDLL
573                    runSomething "Make DLL" p args
574
575 touch :: String -> String -> IO ()
576 touch purpose arg =  do p <- readIORef v_Pgm_T
577                         runSomething purpose p [FileOption "" arg]
578
579 copy :: String -> String -> String -> IO ()
580 copy purpose from to = do
581   verb <- dynFlag verbosity
582   when (verb >= 2) $ hPutStrLn stderr ("*** " ++ purpose)
583
584   h <- openFile to WriteMode
585   ls <- readFile from -- inefficient, but it'll do for now.
586                       -- ToDo: speed up via slurping.
587   hPutStr h ls
588   hClose h
589 \end{code}
590
591 \begin{code}
592 getSysMan :: IO String  -- How to invoke the system manager 
593                         -- (parallel system only)
594 getSysMan = readIORef v_Pgm_sysman
595 \end{code}
596
597 %************************************************************************
598 %*                                                                      *
599 \subsection{GHC Usage message}
600 %*                                                                      *
601 %************************************************************************
602
603 Show the usage message and exit
604
605 \begin{code}
606 showGhcUsage = do { usage_path <- readIORef v_Path_usage
607                   ; usage      <- readFile usage_path
608                   ; dump usage
609                   ; exitWith ExitSuccess }
610   where
611      dump ""          = return ()
612      dump ('$':'$':s) = hPutStr stderr progName >> dump s
613      dump (c:s)       = hPutChar stderr c >> dump s
614 \end{code}
615
616
617 %************************************************************************
618 %*                                                                      *
619 \subsection{Managing temporary files
620 %*                                                                      *
621 %************************************************************************
622
623 \begin{code}
624 GLOBAL_VAR(v_FilesToClean, [],               [String] )
625 GLOBAL_VAR(v_TmpDir,       cDEFAULT_TMPDIR,  String   )
626         -- v_TmpDir has no closing '/'
627 \end{code}
628
629 \begin{code}
630 setTmpDir dir = writeIORef v_TmpDir dir
631
632 cleanTempFiles :: Int -> IO ()
633 cleanTempFiles verb = do fs <- readIORef v_FilesToClean
634                          removeTmpFiles verb fs
635
636 cleanTempFilesExcept :: Int -> [FilePath] -> IO ()
637 cleanTempFilesExcept verb dont_delete
638   = do fs <- readIORef v_FilesToClean
639        let leftovers = filter (`notElem` dont_delete) fs
640        removeTmpFiles verb leftovers
641        writeIORef v_FilesToClean dont_delete
642
643
644 -- find a temporary name that doesn't already exist.
645 newTempName :: Suffix -> IO FilePath
646 newTempName extn
647   = do x <- getProcessID
648        tmp_dir <- readIORef v_TmpDir
649        findTempName tmp_dir x
650   where 
651     findTempName tmp_dir x
652       = do let filename = tmp_dir ++ "/ghc" ++ show x ++ '.':extn
653            b  <- doesFileExist filename
654            if b then findTempName tmp_dir (x+1)
655                 else do add v_FilesToClean filename -- clean it up later
656                         return filename
657
658 addFilesToClean :: [FilePath] -> IO ()
659 -- May include wildcards [used by DriverPipeline.run_phase SplitMangle]
660 addFilesToClean files = mapM_ (add v_FilesToClean) files
661
662 removeTmpFiles :: Int -> [FilePath] -> IO ()
663 removeTmpFiles verb fs
664   = traceCmd "Deleting temp files" 
665              ("Deleting: " ++ unwords fs)
666              (mapM_ rm fs)
667   where
668     rm f = removeFile f `IO.catch` 
669                 (\_ignored -> 
670                     when (verb >= 2) $
671                       hPutStrLn stderr ("Warning: deleting non-existent " ++ f)
672                 )
673
674 \end{code}
675
676
677 %************************************************************************
678 %*                                                                      *
679 \subsection{Running a program}
680 %*                                                                      *
681 %************************************************************************
682
683 \begin{code}
684 GLOBAL_VAR(v_Dry_run, False, Bool)
685
686 setDryRun :: IO () 
687 setDryRun = writeIORef v_Dry_run True
688
689 -----------------------------------------------------------------------------
690 -- Running an external program
691
692 runSomething :: String          -- For -v message
693              -> String          -- Command name (possibly a full path)
694                                 --      assumed already dos-ified
695              -> [Option]        -- Arguments
696                                 --      runSomething will dos-ify them
697              -> IO ()
698
699 runSomething phase_name pgm args = do
700   let real_args = filter notNull (map showOpt args)
701   traceCmd phase_name (concat (intersperse " " (pgm:real_args))) $ do
702   exit_code <- rawSystem pgm real_args
703   if (exit_code /= ExitSuccess)
704         then throwDyn (PhaseFailed phase_name exit_code)
705         else return ()
706
707 traceCmd :: String -> String -> IO () -> IO ()
708 -- a) trace the command (at two levels of verbosity)
709 -- b) don't do it at all if dry-run is set
710 traceCmd phase_name cmd_line action
711  = do   { verb <- dynFlag verbosity
712         ; when (verb >= 2) $ hPutStrLn stderr ("*** " ++ phase_name)
713         ; when (verb >= 3) $ hPutStrLn stderr cmd_line
714         ; hFlush stderr
715         
716            -- Test for -n flag
717         ; n <- readIORef v_Dry_run
718         ; unless n $ do {
719
720            -- And run it!
721         ; action `IO.catch` handle_exn verb
722         }}
723   where
724     handle_exn verb exn = do { when (verb >= 2) (hPutStr   stderr "\n")
725                              ; when (verb >= 3) (hPutStrLn stderr ("Failed: " ++ cmd_line ++ (show exn)))
726                              ; throwDyn (PhaseFailed phase_name (ExitFailure 1)) }
727
728 -- -----------------------------------------------------------------------------
729 -- rawSystem: run an external command
730
731 #if __GLASGOW_HASKELL__ < 601
732
733 -- This code is copied from System.Cmd on GHC 6.1.
734
735 rawSystem :: FilePath -> [String] -> IO ExitCode
736
737 #ifndef mingw32_TARGET_OS
738
739 rawSystem cmd args =
740   withCString cmd $ \pcmd ->
741     withMany withCString (cmd:args) $ \cstrs ->
742       withArray0 nullPtr cstrs $ \arr -> do
743         status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmd arr)
744         case status of
745             0  -> return ExitSuccess
746             n  -> return (ExitFailure n)
747
748 foreign import ccall unsafe "rawSystem"
749   c_rawSystem :: CString -> Ptr CString -> IO Int
750
751 #else
752
753 -- On Windows, the command line is passed to the operating system as
754 -- a single string.  Command-line parsing is done by the executable
755 -- itself.
756 rawSystem cmd args = do
757   let cmdline = {-translate-} cmd ++ concat (map ((' ':) . translate) args)
758   withCString cmdline $ \pcmdline -> do
759     status <- throwErrnoIfMinus1 "rawSystem" (c_rawSystem pcmdline)
760     case status of
761        0  -> return ExitSuccess
762        n  -> return (ExitFailure n)
763
764 translate :: String -> String
765 translate str = '"' : foldr escape "\"" str
766   where escape '"'  str = '\\' : '"'  : str
767         escape '\\' str = '\\' : '\\' : str
768         escape c    str = c : str
769
770 foreign import ccall unsafe "rawSystem"
771   c_rawSystem :: CString -> IO Int
772
773 #endif
774 #endif
775 \end{code}
776
777
778 %************************************************************************
779 %*                                                                      *
780 \subsection{Path names}
781 %*                                                                      *
782 %************************************************************************
783
784 We maintain path names in Unix form ('/'-separated) right until 
785 the last moment.  On Windows we dos-ify them just before passing them
786 to the Windows command.
787
788 The alternative, of using '/' consistently on Unix and '\' on Windows,
789 proved quite awkward.  There were a lot more calls to platformPath,
790 and even on Windows we might invoke a unix-like utility (eg 'sh'), which
791 interpreted a command line 'foo\baz' as 'foobaz'.
792
793 \begin{code}
794 -----------------------------------------------------------------------------
795 -- Convert filepath into platform / MSDOS form.
796
797 -- platformPath does two things
798 -- a) change '/' to '\'
799 -- b) remove initial '/cygdrive/'
800
801 normalisePath :: String -> String
802 -- Just change '\' to '/'
803
804 pgmPath :: String               -- Directory string in Unix format
805         -> String               -- Program name with no directory separators
806                                 --      (e.g. copy /y)
807         -> String               -- Program invocation string in native format
808
809
810
811 #if defined(mingw32_HOST_OS)
812 --------------------- Windows version ------------------
813 normalisePath xs = subst '\\' '/' xs
814 platformPath p   = subst '/' '\\' p
815 pgmPath dir pgm  = platformPath dir ++ '\\' : pgm
816
817 subst a b ls = map (\ x -> if x == a then b else x) ls
818 #else
819 --------------------- Non-Windows version --------------
820 normalisePath xs   = xs
821 pgmPath dir pgm    = dir ++ '/' : pgm
822 platformPath stuff = stuff
823 --------------------------------------------------------
824 #endif
825
826 \end{code}
827
828
829 -----------------------------------------------------------------------------
830    Path name construction
831
832 \begin{code}
833 slash            :: String -> String -> String
834 absPath, relPath :: [String] -> String
835
836 relPath [] = ""
837 relPath xs = foldr1 slash xs
838
839 absPath xs = "" `slash` relPath xs
840
841 slash s1 s2 = s1 ++ ('/' : s2)
842 \end{code}
843
844
845 %************************************************************************
846 %*                                                                      *
847 \subsection{Support code}
848 %*                                                                      *
849 %************************************************************************
850
851 \begin{code}
852 -----------------------------------------------------------------------------
853 -- Define       getBaseDir     :: IO (Maybe String)
854
855 #if defined(mingw32_HOST_OS)
856 getBaseDir :: IO (Maybe String)
857 -- Assuming we are running ghc, accessed by path  $()/bin/ghc.exe,
858 -- return the path $(stuff).  Note that we drop the "bin/" directory too.
859 getBaseDir = do let len = (2048::Int) -- plenty, PATH_MAX is 512 under Win32.
860                 buf <- mallocArray len
861                 ret <- getModuleFileName nullPtr buf len
862                 if ret == 0 then free buf >> return Nothing
863                             else do s <- peekCString buf
864                                     free buf
865                                     return (Just (rootDir s))
866   where
867     rootDir s = reverse (dropList "/bin/ghc.exe" (reverse (normalisePath s)))
868
869 foreign import stdcall "GetModuleFileNameA" unsafe
870   getModuleFileName :: Ptr () -> CString -> Int -> IO Int32
871 #else
872 getBaseDir :: IO (Maybe String) = do return Nothing
873 #endif
874
875 #ifdef mingw32_HOST_OS
876 foreign import ccall "_getpid" unsafe getProcessID :: IO Int -- relies on Int == Int32 on Windows
877 #elif __GLASGOW_HASKELL__ > 504
878 getProcessID :: IO Int
879 getProcessID = System.Posix.Internals.c_getpid >>= return . fromIntegral
880 #else
881 getProcessID :: IO Int
882 getProcessID = Posix.getProcessID
883 #endif
884
885 \end{code}