[project @ 2000-06-28 15:56:28 by simonmar]
[ghc-hetmet.git] / ghc / driver / Main.hs
1 -----------------------------------------------------------------------------
2 -- GHC Driver program
3 --
4 -- (c) Simon Marlow 2000
5 --
6 -----------------------------------------------------------------------------
7
8 module Main (main) where
9
10 import Package
11 import Config
12
13 import RegexString
14 import Concurrent
15 import Posix
16 import IOExts
17 import Exception
18 import Dynamic
19
20 import IO
21 import Array
22 import List
23 import System
24 import Maybe
25 import Char
26
27 #define GLOBAL_VAR(name,value,ty)  \
28 name = global (value) :: IORef (ty); \
29 {-# NOINLINE name #-}
30
31 -----------------------------------------------------------------------------
32 -- ToDo:
33
34 -- time commands when run with -v
35 -- split marker
36 -- mkDLL
37 -- java generation
38 -- user ways
39 -- Win32 support
40 -- make sure OPTIONS in .hs file propogate to .hc file if -C or -keep-hc-file-too
41
42 -----------------------------------------------------------------------------
43 -- Differences vs. old driver:
44
45 -- No more "Enter your Haskell program, end with ^D (on a line of its own):"
46 -- consistency checking removed (may do this properly later)
47 -- removed -noC
48 -- no hi diffs (could be added later)
49 -- no -Ofile
50
51 -----------------------------------------------------------------------------
52 -- non-configured things
53
54 _Haskell1Version = "5" -- i.e., Haskell 98
55
56 -----------------------------------------------------------------------------
57 -- Usage Message
58
59 short_usage = do
60   hPutStr stderr "\nUsage: For basic information, try the `-help' option.\n"
61   exitWith ExitSuccess
62    
63 long_usage = do
64   let usage_dir = findFile "ghc-usage.txt" (cGHC_DRIVER_DIR++"/ghc-usage.txt")
65   usage <- readFile (usage_dir++"/ghc-usage.txt")
66   dump usage
67   exitWith ExitSuccess
68   where
69      dump "" = return ()
70      dump ('$':'$':s) = hPutStr stderr get_prog_name >> dump s
71      dump (c:s) = hPutChar stderr c >> dump s
72
73 version_str = cProjectVersion ++ 
74                 ( if cProjectPatchLevel /= "0" && cProjectPatchLevel /= ""
75                         then '.':cProjectPatchLevel
76                         else "")
77
78 -----------------------------------------------------------------------------
79 -- Phases
80
81 {-
82 Phase of the           | Suffix saying | Flag saying   | (suffix of)
83 compilation system     | ``start here''| ``stop after''| output file
84
85 literate pre-processor | .lhs          | -             | -
86 C pre-processor (opt.) | -             | -E            | -
87 Haskell compiler       | .hs           | -C, -S        | .hc, .s
88 C compiler (opt.)      | .hc or .c     | -S            | .s
89 assembler              | .s  or .S     | -c            | .o
90 linker                 | other         | -             | a.out
91 -}
92
93 data Phase 
94         = MkDependHS    -- haskell dependency generation
95         | Unlit
96         | Cpp
97         | Hsc
98         | Cc
99         | HCc           -- Haskellised C (as opposed to vanilla C) compilation
100         | Mangle        -- assembly mangling, now done by a separate script.
101         | SplitMangle   -- after mangler if splitting
102         | SplitAs
103         | As
104         | Ln 
105   deriving (Eq,Ord,Enum,Ix,Show,Bounded)
106
107 initial_phase = Unlit
108
109 -----------------------------------------------------------------------------
110 -- Errors
111
112 data BarfKind
113   = UnknownFileType String
114   | UnknownFlag String
115   | AmbiguousPhase
116   | MultipleSrcsOneOutput
117   | UnknownPackage String
118   | WayCombinationNotSupported [WayName]
119   | PhaseFailed String ExitCode
120   | Interrupted
121   | NoInputFiles
122   deriving Eq
123
124 GLOBAL_VAR(prog_name, "ghc", String)
125
126 get_prog_name = unsafePerformIO (readIORef prog_name) -- urk!
127
128 instance Show BarfKind where
129   showsPrec _ e 
130         = showString get_prog_name . showString ": " . showBarf e
131
132 showBarf AmbiguousPhase
133    = showString "only one of the flags -M, -E, -C, -S, -c is allowed"
134 showBarf (UnknownFileType s)
135    = showString "unknown file type, and linking not done: " . showString s
136 showBarf (UnknownFlag s)
137    = showString "unrecognised flag: " . showString s
138 showBarf MultipleSrcsOneOutput
139    = showString "can't apply -o option to multiple source files"
140 showBarf (UnknownPackage s)
141    = showString "unknown package name: " . showString s
142 showBarf (WayCombinationNotSupported ws)
143    = showString "combination not supported: " 
144    . foldr1 (\a b -> a . showChar '/' . b) 
145         (map (showString . wayName . lkupWay) ws)
146 showBarf (NoInputFiles)
147    = showString "no input files"
148
149 barfKindTc = mkTyCon "BarfKind"
150
151 instance Typeable BarfKind where
152   typeOf _ = mkAppTy barfKindTc []
153
154 -----------------------------------------------------------------------------
155 -- Temporary files
156
157 GLOBAL_VAR(files_to_clean, [], [String])
158
159 cleanTempFiles :: IO ()
160 cleanTempFiles = do
161   fs <- readIORef files_to_clean
162   verb <- readIORef verbose
163
164   let blowAway f =
165            (do  on verb (hPutStrLn stderr ("removing: " ++ f))
166                 if '*' `elem` f then system ("rm -f " ++ f) >> return ()
167                                 else removeLink f)
168             `catchAllIO`
169            (\e -> on verb (hPutStrLn stderr 
170                                 ("warning: can't remove tmp file" ++ f)))
171   mapM_ blowAway fs
172
173 -----------------------------------------------------------------------------
174 -- Which phase to stop at
175
176 GLOBAL_VAR(stop_after, Ln, Phase)
177
178 end_phase_flag :: String -> Maybe Phase
179 end_phase_flag "-M" = Just MkDependHS
180 end_phase_flag "-E" = Just Cpp
181 end_phase_flag "-C" = Just Hsc
182 end_phase_flag "-S" = Just Mangle
183 end_phase_flag "-c" = Just As
184 end_phase_flag _    = Nothing
185
186 getStopAfter :: [String]
187          -> IO ( [String]   -- rest of command line
188                , Phase      -- stop after phase
189                , Bool       -- do linking?
190                )
191 getStopAfter flags 
192   = case my_partition end_phase_flag flags of
193         ([]   , rest) -> return (rest, As,  True)
194         ([one], rest) -> return (rest, one, False)
195         (_    , rest) -> throwDyn AmbiguousPhase
196
197 -----------------------------------------------------------------------------
198 -- Global compilation flags
199
200         -- Cpp-related flags
201 GLOBAL_VAR(cpp_flag, False, Bool)
202 hs_source_cpp_opts = global
203         [ "-D__HASKELL1__="++_Haskell1Version
204         , "-D__GLASGOW_HASKELL__="++cProjectVersionInt                          
205         , "-D__HASKELL98__"
206         , "-D__CONCURRENT_HASKELL__"
207         ]
208
209         -- Keep output from intermediate phases
210 GLOBAL_VAR(keep_hi_diffs,       False,          Bool)
211 GLOBAL_VAR(keep_hc_files,       False,          Bool)
212 GLOBAL_VAR(keep_s_files,        False,          Bool)
213 GLOBAL_VAR(keep_raw_s_files,    False,          Bool)
214
215         -- Compiler RTS options
216 GLOBAL_VAR(specific_heap_size,  6 * 1000 * 1000, Integer)
217 GLOBAL_VAR(specific_stack_size, 1000 * 1000,     Integer)
218 GLOBAL_VAR(scale_sizes_by,      1.0,             Double)
219
220         -- Verbose
221 GLOBAL_VAR(verbose, False, Bool)
222 is_verbose = do v <- readIORef verbose; if v then return "-v" else return ""
223
224         -- Misc
225 GLOBAL_VAR(dry_run,             False,          Bool)
226 GLOBAL_VAR(recomp,              True,           Bool)
227 GLOBAL_VAR(tmp_prefix,          cTMPDIR,        String)
228 GLOBAL_VAR(stolen_x86_regs,     4,              Int)
229 GLOBAL_VAR(static,              True,           Bool)  -- ToDo: not for mingw32
230 GLOBAL_VAR(collect_ghc_timing,  False,          Bool)
231 GLOBAL_VAR(do_asm_mangling,     True,           Bool)
232
233 -----------------------------------------------------------------------------
234 -- Splitting object files (for libraries)
235
236 GLOBAL_VAR(split_object_files,  False,          Bool)
237 GLOBAL_VAR(split_prefix,        "",             String)
238 GLOBAL_VAR(n_split_files,       0,              Int)
239         
240 can_split :: Bool
241 can_split =  prefixMatch "i386" cTARGETPLATFORM
242           || prefixMatch "alpha" cTARGETPLATFORM
243           || prefixMatch "hppa" cTARGETPLATFORM
244           || prefixMatch "m68k" cTARGETPLATFORM
245           || prefixMatch "mips" cTARGETPLATFORM
246           || prefixMatch "powerpc" cTARGETPLATFORM
247           || prefixMatch "rs6000" cTARGETPLATFORM
248           || prefixMatch "sparc" cTARGETPLATFORM
249
250 -----------------------------------------------------------------------------
251 -- Compiler output options
252
253 data HscLang
254   = HscC
255   | HscAsm
256   | HscJava
257
258 GLOBAL_VAR(hsc_lang, if cGhcWithNativeCodeGen == "YES" && 
259                          prefixMatch "i386" cTARGETPLATFORM
260                         then  HscAsm
261                         else  HscC, 
262            HscLang)
263
264 GLOBAL_VAR(output_dir,  Nothing, Maybe String)
265 GLOBAL_VAR(output_suf,  Nothing, Maybe String)
266 GLOBAL_VAR(output_file, Nothing, Maybe String)
267 GLOBAL_VAR(output_hi,   Nothing, Maybe String)
268
269 GLOBAL_VAR(ld_inputs,   [],      [String])
270
271 odir_ify :: String -> IO String
272 odir_ify f = do
273   odir_opt <- readIORef output_dir
274   case odir_opt of
275         Nothing -> return f
276         Just d  -> return (newdir d f)
277
278 osuf_ify :: String -> IO String
279 osuf_ify f = do
280   osuf_opt <- readIORef output_suf
281   case osuf_opt of
282         Nothing -> return f
283         Just s  -> return (newsuf s f)
284
285 -----------------------------------------------------------------------------
286 -- Hi Files
287
288 GLOBAL_VAR(produceHi,           True,   Bool)
289 GLOBAL_VAR(hi_on_stdout,        False,  Bool)
290 GLOBAL_VAR(hi_with,             "",     String)
291 GLOBAL_VAR(hi_suf,              "hi",   String)
292
293 data HiDiffFlag = NormalHiDiffs | UsageHiDiffs | NoHiDiffs
294 GLOBAL_VAR(hi_diffs, NoHiDiffs, HiDiffFlag)
295
296 -----------------------------------------------------------------------------
297 -- Warnings & sanity checking
298
299 -- Warning packages that are controlled by -W and -Wall.  The 'standard'
300 -- warnings that you get all the time are
301 --         
302 --         -fwarn-overlapping-patterns
303 --         -fwarn-missing-methods
304 --         -fwarn-missing-fields
305 --         -fwarn-deprecations
306 --         -fwarn-duplicate-exports
307 -- 
308 -- these are turned off by -Wnot.
309
310 standardWarnings  = [ "-fwarn-overlapping-patterns"
311                     , "-fwarn-missing-methods"
312                     , "-fwarn-missing-fields"
313                     , "-fwarn-deprecations"
314                     , "-fwarn-duplicate-exports"
315                     ]
316 minusWOpts        = standardWarnings ++ 
317                     [ "-fwarn-unused-binds"
318                     , "-fwarn-unused-matches"
319                     , "-fwarn-incomplete-patterns"
320                     , "-fwarn-unused-imports"
321                     ]
322 minusWallOpts     = minusWOpts ++
323                     [ "-fwarn-type-defaults"
324                     , "-fwarn-name-shadowing"
325                     , "-fwarn-missing-signatures"
326                     ]
327
328 data WarningState = W_default | W_ | W_all | W_not
329
330 GLOBAL_VAR(warning_opt, W_default, WarningState)
331
332 -----------------------------------------------------------------------------
333 -- Compiler optimisation options
334
335 GLOBAL_VAR(opt_level, 0, Int)
336
337 setOptLevel :: String -> IO ()
338 setOptLevel ""              = do { writeIORef opt_level 1; go_via_C }
339 setOptLevel "not"           = writeIORef opt_level 0
340 setOptLevel [c] | isDigit c = do
341    let level = ord c - ord '0'
342    writeIORef opt_level level
343    on (level >= 1) go_via_C
344 setOptLevel s = throwDyn (UnknownFlag ("-O"++s))
345
346 go_via_C = do
347    l <- readIORef hsc_lang
348    case l of { HscAsm -> writeIORef hsc_lang HscC; 
349                _other -> return () }
350
351 GLOBAL_VAR(opt_minus_o2_for_C, False, Bool)
352
353 GLOBAL_VAR(opt_MaxSimplifierIterations, 4, Int)
354 GLOBAL_VAR(opt_StgStats,    False, Bool)
355 GLOBAL_VAR(opt_UsageSPInf,  False, Bool)  -- Off by default
356
357 hsc_minusO2_flags = hsc_minusO_flags    -- for now
358
359 hsc_minusNoO_flags = do
360   iter        <- readIORef opt_MaxSimplifierIterations
361   return [ 
362         "-fignore-interface-pragmas",
363         "-fomit-interface-pragmas",
364         "-fsimplify",
365             "[",
366                 "-fmax-simplifier-iterations" ++ show iter,
367             "]"
368         ]
369
370 hsc_minusO_flags = do
371   iter       <- readIORef opt_MaxSimplifierIterations
372   usageSP    <- readIORef opt_UsageSPInf
373   stgstats   <- readIORef opt_StgStats
374
375   return [ 
376         "-ffoldr-build-on",
377
378         "-fdo-eta-reduction",
379         "-fdo-lambda-eta-expansion",
380         "-fcase-of-case",
381         "-fcase-merge",
382         "-flet-to-case",
383
384         -- initial simplify: mk specialiser happy: minimum effort please
385
386         "-fsimplify",
387           "[", 
388                 "-finline-phase0",
389                         -- Don't inline anything till full laziness has bitten
390                         -- In particular, inlining wrappers inhibits floating
391                         -- e.g. ...(case f x of ...)...
392                         --  ==> ...(case (case x of I# x# -> fw x#) of ...)...
393                         --  ==> ...(case x of I# x# -> case fw x# of ...)...
394                         -- and now the redex (f x) isn't floatable any more
395
396                 "-fno-rules",
397                         -- Similarly, don't apply any rules until after full 
398                         -- laziness.  Notably, list fusion can prevent floating.
399
400                 "-fno-case-of-case",
401                         -- Don't do case-of-case transformations.
402                         -- This makes full laziness work better
403
404                 "-fmax-simplifier-iterations2",
405           "]",
406
407         -- Specialisation is best done before full laziness
408         -- so that overloaded functions have all their dictionary lambdas manifest
409         "-fspecialise",
410
411         "-ffloat-outwards",
412         "-ffloat-inwards",
413
414         "-fsimplify",
415           "[", 
416                 "-finline-phase1",
417                 -- Want to run with inline phase 1 after the specialiser to give
418                 -- maximum chance for fusion to work before we inline build/augment
419                 -- in phase 2.  This made a difference in 'ansi' where an 
420                 -- overloaded function wasn't inlined till too late.
421                 "-fmax-simplifier-iterations" ++ show iter,
422           "]",
423
424         -- infer usage information here in case we need it later.
425         -- (add more of these where you need them --KSW 1999-04)
426         if usageSP then "-fusagesp" else "",
427
428         "-fsimplify",
429           "[", 
430                 -- Need inline-phase2 here so that build/augment get 
431                 -- inlined.  I found that spectral/hartel/genfft lost some useful
432                 -- strictness in the function sumcode' if augment is not inlined
433                 -- before strictness analysis runs
434
435                 "-finline-phase2",
436                 "-fmax-simplifier-iterations2",
437           "]",
438
439
440         "-fsimplify",
441           "[", 
442                 "-fmax-simplifier-iterations2",
443                 -- No -finline-phase: allow all Ids to be inlined now
444                 -- This gets foldr inlined before strictness analysis
445           "]",
446
447         "-fstrictness",
448         "-fcpr-analyse",
449         "-fworker-wrapper",
450
451         "-fsimplify",
452           "[", 
453                 "-fmax-simplifier-iterations" ++ show iter,
454                 -- No -finline-phase: allow all Ids to be inlined now
455           "]",
456
457         "-ffloat-outwards",
458                 -- nofib/spectral/hartel/wang doubles in speed if you
459                 -- do full laziness late in the day.  It only happens
460                 -- after fusion and other stuff, so the early pass doesn't
461                 -- catch it.  For the record, the redex is 
462                 --        f_el22 (f_el21 r_midblock)
463
464 -- Leave out lambda lifting for now
465 --        "-fsimplify", -- Tidy up results of full laziness
466 --          "[", 
467 --                "-fmax-simplifier-iterations2",
468 --          "]",
469 --        "-ffloat-outwards-full",      
470
471         -- We want CSE to follow the final full-laziness pass, because it may
472         -- succeed in commoning up things floated out by full laziness.
473         --
474         -- CSE must immediately follow a simplification pass, because it relies
475         -- on the no-shadowing invariant.  See comments at the top of CSE.lhs
476         -- So it must NOT follow float-inwards, which can give rise to shadowing,
477         -- even if its input doesn't have shadows.  Hence putting it between
478         -- the two passes.
479         "-fcse",        
480                         
481
482         "-ffloat-inwards",
483
484 -- Case-liberation for -O2.  This should be after
485 -- strictness analysis and the simplification which follows it.
486
487 --        ( ($OptLevel != 2)
488 --        ? ""
489 --        : "-fliberate-case -fsimplify [ $Oopt_FB_Support -ffloat-lets-exposing-whnf -ffloat-primops-ok -fcase-of-case -fdo-case-elim -fcase-merge -fdo-lambda-eta-expansion -freuse-con -flet-to-case $Oopt_PedanticBottoms $Oopt_MaxSimplifierIterations $Oopt_ShowSimplifierProgress ]" ),
490 --
491 --        "-fliberate-case",
492
493         -- Final clean-up simplification:
494         "-fsimplify",
495           "[", 
496                 "-fmax-simplifier-iterations" ++ show iter,
497                 -- No -finline-phase: allow all Ids to be inlined now
498           "]"
499
500         ]
501
502 -----------------------------------------------------------------------------
503 -- Paths & Libraries
504
505 split_marker = ':'   -- not configurable
506
507 import_paths, include_paths, library_paths :: IORef [String]
508 GLOBAL_VAR(import_paths,  ["."], [String])
509 GLOBAL_VAR(include_paths, ["."], [String])
510 GLOBAL_VAR(library_paths, [],    [String])
511
512 GLOBAL_VAR(cmdline_libraries,   [], [String])
513 GLOBAL_VAR(cmdline_hc_includes, [], [String])
514
515 augment_import_paths :: String -> IO ()
516 augment_import_paths "" = writeIORef import_paths []
517 augment_import_paths path
518   = do paths <- readIORef import_paths
519        writeIORef import_paths (paths ++ dirs)
520   where dirs = split split_marker path
521
522 augment_include_paths :: String -> IO ()
523 augment_include_paths path
524   = do paths <- readIORef include_paths
525        writeIORef include_paths (paths ++ split split_marker path)
526
527 augment_library_paths :: String -> IO ()
528 augment_library_paths path
529   = do paths <- readIORef library_paths
530        writeIORef library_paths (paths ++ split split_marker path)
531
532 -----------------------------------------------------------------------------
533 -- Packages
534
535 -- package list is maintained in dependency order
536 packages = global ["std", "rts", "gmp"] :: IORef [String]
537 -- comma in value, so can't use macro, grrr
538 {-# NOINLINE packages #-}
539
540 addPackage :: String -> IO ()
541 addPackage package
542   = do pkg_details <- readIORef package_details
543        case lookup package pkg_details of
544           Nothing -> throwDyn (UnknownPackage package)
545           Just details -> do
546             ps <- readIORef packages
547             if package `elem` ps 
548                 then return ()
549                 else do mapM_ addPackage (package_deps details)
550                         ps <- readIORef packages
551                         writeIORef packages (package:ps)
552
553 getPackageImportPath   :: IO [String]
554 getPackageImportPath = do
555   ps <- readIORef packages
556   ps' <- getPackageDetails ps
557   return (nub (concat (map import_dirs ps')))
558
559 getPackageIncludePath   :: IO [String]
560 getPackageIncludePath = do
561   ps <- readIORef packages
562   ps' <- getPackageDetails ps
563   return (nub (filter (not.null) (map include_dir ps')))
564
565         -- includes are in reverse dependency order (i.e. rts first)
566 getPackageCIncludes   :: IO [String]
567 getPackageCIncludes = do
568   ps <- readIORef packages
569   ps' <- getPackageDetails ps
570   return (reverse (nub (filter (not.null) (map c_include ps'))))
571
572 getPackageLibraryPath  :: IO [String]
573 getPackageLibraryPath = do
574   ps <- readIORef packages
575   ps' <- getPackageDetails ps
576   return (nub (concat (map library_dirs ps')))
577
578 getPackageLibraries    :: IO [String]
579 getPackageLibraries = do
580   ps <- readIORef packages
581   ps' <- getPackageDetails ps
582   tag <- readIORef build_tag
583   let suffix = if null tag then "" else '_':tag
584   return (concat (map libraries ps'))
585
586 getPackageExtraGhcOpts :: IO [String]
587 getPackageExtraGhcOpts = do
588   ps <- readIORef packages
589   ps' <- getPackageDetails ps
590   return (map extra_ghc_opts ps')
591
592 getPackageExtraCcOpts  :: IO [String]
593 getPackageExtraCcOpts = do
594   ps <- readIORef packages
595   ps' <- getPackageDetails ps
596   return (map extra_cc_opts ps')
597
598 getPackageExtraLdOpts  :: IO [String]
599 getPackageExtraLdOpts = do
600   ps <- readIORef packages
601   ps' <- getPackageDetails ps
602   return (map extra_ld_opts ps')
603
604 getPackageDetails ps = do
605   pkg_details <- readIORef package_details
606   let getDetails p =  case lookup p pkg_details of
607                         Just details -> return details
608                         Nothing -> error "getPackageDetails"
609   mapM getDetails ps
610
611 GLOBAL_VAR(package_details, (error "package_details"), [(String,Package)])
612
613 -----------------------------------------------------------------------------
614 -- Ways
615
616 -- The central concept of a "way" is that all objects in a given
617 -- program must be compiled in the same "way".  Certain options change
618 -- parameters of the virtual machine, eg. profiling adds an extra word
619 -- to the object header, so profiling objects cannot be linked with
620 -- non-profiling objects.
621
622 -- After parsing the command-line options, we determine which "way" we
623 -- are building - this might be a combination way, eg. profiling+ticky-ticky.
624
625 -- We then find the "build-tag" associated with this way, and this
626 -- becomes the suffix used to find .hi files and libraries used in
627 -- this compilation.
628
629 GLOBAL_VAR(build_tag, "", String)
630
631 data WayName
632   = WayProf
633   | WayUnreg
634   | WayTicky
635   | WayPar
636   | WayGran
637   | WaySMP
638   | WayDebug
639   | WayUser_a
640   | WayUser_b
641   | WayUser_c
642   | WayUser_d
643   | WayUser_e
644   | WayUser_f
645   | WayUser_g
646   | WayUser_h
647   | WayUser_i
648   | WayUser_j
649   | WayUser_k
650   | WayUser_l
651   | WayUser_m
652   | WayUser_n
653   | WayUser_o
654   | WayUser_A
655   | WayUser_B
656   deriving (Eq,Ord)
657
658 GLOBAL_VAR(ways, [] ,[WayName])
659
660 allowed_combinations = 
661    [  [WayProf,WayUnreg],
662       [WayProf,WaySMP]     -- works???
663    ]
664
665 findBuildTag :: IO [String]  -- new options
666 findBuildTag = do
667   way_names <- readIORef ways
668   case sort way_names of
669      []  -> do  writeIORef build_tag ""
670                 return []
671
672      [w] -> do let details = lkupWay w
673                writeIORef build_tag (wayTag details)
674                return (wayOpts details)
675
676      ws  -> if  ws `notElem` allowed_combinations
677                 then throwDyn (WayCombinationNotSupported ws)
678                 else let stuff = map lkupWay ws
679                          tag   = concat (map wayTag stuff)
680                          flags = map wayOpts stuff
681                      in do
682                      writeIORef build_tag tag
683                      return (concat flags)
684
685 lkupWay w = 
686    case lookup w way_details of
687         Nothing -> error "findBuildTag"
688         Just details -> details
689
690 data Way = Way {
691   wayTag   :: String,
692   wayName  :: String,
693   wayOpts  :: [String]
694   }
695
696 way_details :: [ (WayName, Way) ]
697 way_details =
698   [ (WayProf, Way  "p" "Profiling"  
699         [ "-fscc-profiling"
700         , "-DPROFILING"
701         , "-optc-DPROFILING" ]),
702
703     (WayTicky, Way  "t" "Ticky-ticky Profiling"  
704         [ "-fticky-ticky"
705         , "-DTICKY_TICKY"
706         , "-optc-DTICKY_TICKY" ]),
707
708     (WayUnreg, Way  "u" "Unregisterised" 
709         [ "-optc-DNO_REGS"
710         , "-optc-DUSE_MINIINTERPRETER"
711         , "-fno-asm-mangling"
712         , "-funregisterised" ]),
713
714     (WayPar, Way  "mp" "Parallel" 
715         [ "-fstack-check"
716         , "-fparallel"
717         , "-D__PARALLEL_HASKELL__"
718         , "-optc-DPAR"
719         , "-package concurrent" ]),
720
721     (WayGran, Way  "mg" "Gransim" 
722         [ "-fstack-check"
723         , "-fgransim"
724         , "-D__GRANSIM__"
725         , "-optc-DGRAN"
726         , "-package concurrent" ]),
727
728     (WaySMP, Way  "s" "SMP"  
729         [ "-fsmp"
730         , "-optc-pthread"
731         , "-optl-pthread"
732         , "-optc-DSMP" ]),
733
734     (WayUser_a,  Way  "a"  "User way 'a'"  ["$WAY_a_REAL_OPTS"]),       
735     (WayUser_b,  Way  "b"  "User way 'b'"  ["$WAY_b_REAL_OPTS"]),       
736     (WayUser_c,  Way  "c"  "User way 'c'"  ["$WAY_c_REAL_OPTS"]),       
737     (WayUser_d,  Way  "d"  "User way 'd'"  ["$WAY_d_REAL_OPTS"]),       
738     (WayUser_e,  Way  "e"  "User way 'e'"  ["$WAY_e_REAL_OPTS"]),       
739     (WayUser_f,  Way  "f"  "User way 'f'"  ["$WAY_f_REAL_OPTS"]),       
740     (WayUser_g,  Way  "g"  "User way 'g'"  ["$WAY_g_REAL_OPTS"]),       
741     (WayUser_h,  Way  "h"  "User way 'h'"  ["$WAY_h_REAL_OPTS"]),       
742     (WayUser_i,  Way  "i"  "User way 'i'"  ["$WAY_i_REAL_OPTS"]),       
743     (WayUser_j,  Way  "j"  "User way 'j'"  ["$WAY_j_REAL_OPTS"]),       
744     (WayUser_k,  Way  "k"  "User way 'k'"  ["$WAY_k_REAL_OPTS"]),       
745     (WayUser_l,  Way  "l"  "User way 'l'"  ["$WAY_l_REAL_OPTS"]),       
746     (WayUser_m,  Way  "m"  "User way 'm'"  ["$WAY_m_REAL_OPTS"]),       
747     (WayUser_n,  Way  "n"  "User way 'n'"  ["$WAY_n_REAL_OPTS"]),       
748     (WayUser_o,  Way  "o"  "User way 'o'"  ["$WAY_o_REAL_OPTS"]),       
749     (WayUser_A,  Way  "A"  "User way 'A'"  ["$WAY_A_REAL_OPTS"]),       
750     (WayUser_B,  Way  "B"  "User way 'B'"  ["$WAY_B_REAL_OPTS"]) 
751   ]
752
753 -----------------------------------------------------------------------------
754 -- Programs for particular phases
755
756 GLOBAL_VAR(pgm_dep, findFile "mkdependHS" cGHC_MKDEPENDHS, String)
757 GLOBAL_VAR(pgm_L,   findFile "unlit"      cGHC_UNLIT,      String)
758 GLOBAL_VAR(pgm_P,   cRAWCPP,                               String)
759 GLOBAL_VAR(pgm_C,   findFile "hsc"        cGHC_HSC,        String)
760 GLOBAL_VAR(pgm_c,   cGCC,                                  String)
761 GLOBAL_VAR(pgm_m,   findFile "ghc-asm"    cGHC_MANGLER,    String)
762 GLOBAL_VAR(pgm_s,   findFile "ghc-split"  cGHC_SPLIT,      String)
763 GLOBAL_VAR(pgm_a,   cGCC,                                  String)
764 GLOBAL_VAR(pgm_l,   cGCC,                                  String)
765
766 -----------------------------------------------------------------------------
767 -- Options for particular phases
768
769 GLOBAL_VAR(opt_dep, [], [String])
770 GLOBAL_VAR(opt_L, [], [String])
771 GLOBAL_VAR(opt_P, [], [String])
772 GLOBAL_VAR(opt_C, [], [String])
773 GLOBAL_VAR(opt_Crts, [], [String])
774 GLOBAL_VAR(opt_c, [], [String])
775 GLOBAL_VAR(opt_a, [], [String])
776 GLOBAL_VAR(opt_m, [], [String])
777 GLOBAL_VAR(opt_l, [], [String])
778 GLOBAL_VAR(opt_dll, [], [String])
779
780         -- we add to the options from the front, so we need to reverse the list
781 getOpts :: IORef [String] -> IO [String]
782 getOpts opts = readIORef opts >>= return . reverse
783
784 GLOBAL_VAR(anti_opt_C, [], [String])
785
786 -----------------------------------------------------------------------------
787 -- Via-C compilation stuff
788
789 -- flags returned are: ( all C compilations
790 --                     , registerised HC compilations
791 --                     )
792
793 machdepCCOpts 
794    | prefixMatch "alpha"   cTARGETPLATFORM  
795         = return ( ["-static"], [] )
796
797    | prefixMatch "hppa"    cTARGETPLATFORM  
798         -- ___HPUX_SOURCE, not _HPUX_SOURCE, is #defined if -ansi!
799         -- (very nice, but too bad the HP /usr/include files don't agree.)
800         = return ( ["-static", "-D_HPUX_SOURCE"], [] )
801
802    | prefixMatch "m68k"    cTARGETPLATFORM
803       -- -fno-defer-pop : for the .hc files, we want all the pushing/
804       --    popping of args to routines to be explicit; if we let things
805       --    be deferred 'til after an STGJUMP, imminent death is certain!
806       --
807       -- -fomit-frame-pointer : *don't*
808       --     It's better to have a6 completely tied up being a frame pointer
809       --     rather than let GCC pick random things to do with it.
810       --     (If we want to steal a6, then we would try to do things
811       --     as on iX86, where we *do* steal the frame pointer [%ebp].)
812         = return ( [], ["-fno-defer-pop", "-fno-omit-frame-pointer"] )
813
814    | prefixMatch "i386"    cTARGETPLATFORM  
815       -- -fno-defer-pop : basically the same game as for m68k
816       --
817       -- -fomit-frame-pointer : *must* in .hc files; because we're stealing
818       --   the fp (%ebp) for our register maps.
819         = do n_regs <- readIORef stolen_x86_regs
820              sta    <- readIORef static
821              return ( [ if sta then "-DDONT_WANT_WIN32_DLL_SUPPORT" else "" ],
822                       [ "-fno-defer-pop", "-fomit-frame-pointer",
823                         "-DSTOLEN_X86_REGS="++show n_regs ]
824                     )
825
826    | prefixMatch "mips"    cTARGETPLATFORM
827         = return ( ["static"], [] )
828
829    | prefixMatch "powerpc" cTARGETPLATFORM || prefixMatch "rs6000" cTARGETPLATFORM
830         = return ( ["static"], ["-finhibit-size-directive"] )
831
832    | otherwise
833         = return ( [], [] )
834
835 -----------------------------------------------------------------------------
836 -- Build the Hsc command line
837
838 build_hsc_opts :: IO [String]
839 build_hsc_opts = do
840   opt_C_ <- getOpts opt_C               -- misc hsc opts
841
842         -- warnings
843   warn_level <- readIORef warning_opt
844   let warn_opts =  case warn_level of
845                         W_default -> standardWarnings
846                         W_        -> minusWOpts
847                         W_all     -> minusWallOpts
848                         W_not     -> []
849
850         -- optimisation
851   minus_o <- readIORef opt_level
852   optimisation_opts <-
853         case minus_o of
854             0 -> hsc_minusNoO_flags
855             1 -> hsc_minusO_flags
856             2 -> hsc_minusO2_flags
857             -- ToDo: -Ofile
858  
859         -- STG passes
860   ways_ <- readIORef ways
861   let stg_massage | WayProf `elem` ways_ =  "-fmassage-stg-for-profiling"
862                   | otherwise            = ""
863
864   stg_stats <- readIORef opt_StgStats
865   let stg_stats_flag | stg_stats = "-dstg-stats"
866                      | otherwise = ""
867
868   let stg_opts = [ stg_massage, stg_stats_flag, "-flet-no-escape" ]
869         -- let-no-escape always on for now
870
871   verb <- is_verbose
872   let hi_vers = "-fhi-version="++cProjectVersionInt
873   static <- (do s <- readIORef static; if s then return "-static" else return "")
874
875   l <- readIORef hsc_lang
876   let lang = case l of
877                 HscC    -> "-olang=C"
878                 HscAsm  -> "-olang=asm"
879                 HscJava -> "-olang=java"
880
881   -- get hi-file suffix
882   hisuf <- readIORef hi_suf
883
884   -- hi-suffix for packages depends on the build tag.
885   package_hisuf <-
886         do tag <- readIORef build_tag
887            if null tag
888                 then return "hi"
889                 else return (tag ++ "_hi")
890
891   import_dirs <- readIORef import_paths
892   package_import_dirs <- getPackageImportPath
893   
894   let hi_map = "-himap=" ++
895                 makeHiMap import_dirs hisuf 
896                          package_import_dirs package_hisuf
897                          split_marker
898
899       hi_map_sep = "-himap-sep=" ++ [split_marker]
900
901   scale <- readIORef scale_sizes_by
902   heap  <- readIORef specific_heap_size
903   stack <- readIORef specific_stack_size
904   cmdline_rts_opts <- getOpts opt_Crts
905   let heap'  = truncate (fromIntegral heap  * scale) :: Integer
906       stack' = truncate (fromIntegral stack * scale) :: Integer
907       rts_opts = [ "+RTS", "-H"++show heap', "-K"++show stack' ]
908                  ++ cmdline_rts_opts ++ [ "-RTS" ]
909
910   -- take into account -fno-* flags by removing the equivalent -f*
911   -- flag from our list.
912   anti_flags <- getOpts anti_opt_C
913   let basic_opts = opt_C_ ++ warn_opts ++ optimisation_opts ++ stg_opts
914       filtered_opts = filter (`notElem` anti_flags) basic_opts
915   
916   return 
917         (  
918         filtered_opts
919         -- ToDo: C stub files
920         ++ [ hi_vers, static, verb, lang, hi_map, hi_map_sep ]
921         ++ rts_opts
922         )
923
924 makeHiMap 
925   (import_dirs         :: [String])
926   (hi_suffix           :: String)
927   (package_import_dirs :: [String])
928   (package_hi_suffix   :: String)   
929   (split_marker        :: Char)
930   = foldr (add_dir hi_suffix) 
931         (foldr (add_dir package_hi_suffix) "" package_import_dirs)
932         import_dirs
933   where
934      add_dir hisuf dir str = dir ++ "%." ++ hisuf ++ split_marker : str
935
936
937 getOptionsFromSource 
938         :: String               -- input file
939         -> IO [String]          -- options, if any
940 getOptionsFromSource file
941   = do h <- openFile file ReadMode
942        look h
943   where
944         look h = do
945             l <- hGetLine h
946             case () of
947                 () | null l -> look h
948                    | prefixMatch "{-# LINE" l -> look h
949                    | Just (opts:_) <- matchRegex optionRegex l
950                         -> return (words opts)
951                    | otherwise -> return []
952
953 optionRegex = mkRegex "{-#[ \t]+OPTIONS[ \t]+(.*)#-}"
954
955 -----------------------------------------------------------------------------
956 -- Main loop
957
958 get_source_files :: [String] -> ([String],[String])
959 get_source_files = partition (('-' /=) . head)
960
961 suffixes :: [(String,Phase)]
962 suffixes =
963   [ ("lhs",   Unlit)
964   , ("hs",    Cpp)
965   , ("hc",    HCc)
966   , ("c",     Cc)
967   , ("raw_s", Mangle)
968   , ("s",     As)
969   , ("S",     As)
970   , ("o",     Ln)
971   ]
972
973 phase_input_ext Unlit       = "lhs"
974 phase_input_ext Cpp         = "lpp"
975 phase_input_ext Hsc         = "cpp"
976 phase_input_ext HCc         = "hc"
977 phase_input_ext Cc          = "c"
978 phase_input_ext Mangle      = "raw_s"
979 phase_input_ext SplitMangle = "split_s" -- not really generated
980 phase_input_ext As          = "s"
981 phase_input_ext SplitAs     = "split_s" -- not really generated
982 phase_input_ext Ln          = "o"
983
984 find_phase :: String -> ([(Phase,String)], [String])
985    -> ([(Phase,String)], [String])
986 find_phase f (phase_srcs, unknown_srcs)
987   = case lookup ext suffixes of
988         Just the_phase -> ((the_phase,f):phase_srcs, unknown_srcs)
989         Nothing        -> (phase_srcs, f:unknown_srcs)
990   where (basename,ext) = split_filename f
991
992
993 find_phases srcs = (phase_srcs, unknown_srcs)
994   where (phase_srcs, unknown_srcs) = foldr find_phase ([],[]) srcs
995
996 main =
997   -- all error messages are propagated as exceptions
998   my_catchDyn (\dyn -> case dyn of
999                           PhaseFailed phase code -> exitWith code
1000                           Interrupted -> exitWith (ExitFailure 1)
1001                           _ -> do hPutStrLn stderr (show (dyn :: BarfKind))
1002                                   exitWith (ExitFailure 1)) $
1003
1004   later cleanTempFiles $
1005         -- exceptions will be blocked while we clean the temporary files,
1006         -- so there shouldn't be any difficulty if we receive further
1007         -- signals.
1008
1009   do
1010         -- install signal handlers
1011    main_thread <- myThreadId
1012    let sig_handler = Catch (raiseInThread main_thread 
1013                                 (DynException (toDyn Interrupted)))
1014    installHandler sigQUIT sig_handler Nothing 
1015    installHandler sigINT  sig_handler Nothing
1016
1017    pgm    <- getProgName
1018    writeIORef prog_name pgm
1019
1020    argv   <- getArgs
1021
1022    -- grab any -B options from the command line first
1023    argv'  <- setTopDir argv
1024
1025    -- read the package configuration
1026    let conf = findFile "package.conf" (cGHC_DRIVER_DIR++"/package.conf.inplace")
1027    contents <- readFile conf
1028    writeIORef package_details (read contents)
1029
1030    -- find the phase to stop after (i.e. -E, -C, -c, -S flags)
1031    (flags2, stop_phase, do_linking) <- getStopAfter argv'
1032
1033    -- process all the other arguments, and get the source files
1034    srcs   <- processArgs flags2 []
1035
1036    -- find the build tag, and re-process the build-specific options
1037    more_opts <- findBuildTag
1038    _ <- processArgs more_opts []
1039
1040    if stop_phase == MkDependHS          -- mkdependHS is special
1041         then do_mkdependHS flags2 srcs
1042         else do
1043
1044    -- for each source file, find which phase to start at
1045    let (phase_srcs, unknown_srcs) = find_phases srcs
1046
1047    o_file <- readIORef output_file
1048    if isJust o_file && not do_linking && length phase_srcs > 1
1049         then throwDyn MultipleSrcsOneOutput
1050         else do
1051
1052    if null unknown_srcs && null phase_srcs
1053         then throwDyn NoInputFiles
1054         else do
1055
1056    -- if we have unknown files, and we're not doing linking, complain
1057    -- (otherwise pass them through to the linker).
1058    if not (null unknown_srcs) && not do_linking
1059         then throwDyn (UnknownFileType (head unknown_srcs))
1060         else do
1061
1062    let  compileFile :: (Phase, String) -> IO String
1063         compileFile (phase, src) = do
1064           let (orig_base, _) = split_filename src
1065           if phase < Ln -- anything to do?
1066                 then run_pipeline stop_phase do_linking True orig_base (phase,src)
1067                 else return src
1068
1069    o_files <- mapM compileFile phase_srcs
1070
1071    if do_linking
1072         then do_link o_files unknown_srcs
1073         else return ()
1074
1075
1076 -- The following compilation pipeline algorithm is fairly hacky.  A
1077 -- better way to do this would be to express the whole comilation as a
1078 -- data flow DAG, where the nodes are the intermediate files and the
1079 -- edges are the compilation phases.  This framework would also work
1080 -- nicely if a haskell dependency generator was included in the
1081 -- driver.
1082
1083 -- It would also deal much more cleanly with compilation phases that
1084 -- generate multiple intermediates, (eg. hsc generates .hc, .hi, and
1085 -- possibly stub files), where some of the output files need to be
1086 -- processed further (eg. the stub files need to be compiled by the C
1087 -- compiler).
1088
1089 -- A cool thing to do would then be to execute the data flow graph
1090 -- concurrently, automatically taking advantage of extra processors on
1091 -- the host machine.  For example, when compiling two Haskell files
1092 -- where one depends on the other, the data flow graph would determine
1093 -- that the C compiler from the first comilation can be overlapped
1094 -- with the hsc comilation for the second file.
1095
1096 run_pipeline
1097   :: Phase              -- phase to end on (never Linker)
1098   -> Bool               -- doing linking afterward?
1099   -> Bool               -- take into account -o when generating output?
1100   -> String             -- original basename (eg. Main)
1101   -> (Phase, String)    -- phase to run, input file
1102   -> IO String          -- return final filename
1103
1104 run_pipeline last_phase do_linking use_ofile orig_basename (phase, input_fn) 
1105   | phase > last_phase = return input_fn
1106   | otherwise
1107   = do
1108
1109      let (basename,ext) = split_filename input_fn
1110
1111      split  <- readIORef split_object_files
1112      mangle <- readIORef do_asm_mangling
1113      lang   <- readIORef hsc_lang
1114
1115         -- figure out what the next phase is.  This is
1116         -- straightforward, apart from the fact that hsc can generate
1117         -- either C or assembler direct, and assembly mangling is
1118         -- optional, and splitting involves one extra phase and an alternate
1119         -- assembler.
1120      let next_phase =
1121           case phase of
1122                 Hsc -> case lang of
1123                             HscC   -> HCc
1124                             HscAsm -> As
1125
1126                 HCc  | mangle    -> Mangle
1127                      | otherwise -> As
1128
1129                 Cc -> As
1130
1131                 Mangle | not split -> As
1132                 SplitMangle -> SplitAs
1133                 SplitAs -> Ln
1134
1135                 _  -> succ phase
1136
1137
1138         -- filename extension for the output, determined by next_phase
1139      let new_ext = phase_input_ext next_phase
1140
1141         -- Figure out what the output from this pass should be called.
1142
1143         -- If we're keeping the output from this phase, then we just save
1144         -- it in the current directory, otherwise we generate a new temp file.
1145      keep_s <- readIORef keep_s_files
1146      keep_raw_s <- readIORef keep_raw_s_files
1147      keep_hc <- readIORef keep_hc_files
1148      let keep_this_output = 
1149            case next_phase of
1150                 Ln -> True
1151                 Mangle | keep_raw_s -> True -- first enhancement :)
1152                 As | keep_s  -> True
1153                 Cc | keep_hc -> True
1154                 _other -> False
1155
1156      output_fn <- 
1157         (if phase == last_phase && not do_linking && use_ofile
1158             then do o_file <- readIORef output_file
1159                     case o_file of 
1160                         Just s  -> return s
1161                         Nothing -> do
1162                             f <- odir_ify (orig_basename ++ '.':new_ext)
1163                             osuf_ify f
1164
1165                 -- .o files are always kept.  .s files and .hc file may be kept.
1166             else if keep_this_output
1167                         then odir_ify (orig_basename ++ '.':new_ext)
1168                         else do filename <- newTempName new_ext
1169                                 add files_to_clean filename
1170                                 return filename
1171         )
1172
1173      run_phase phase orig_basename input_fn output_fn
1174
1175         -- sadly, ghc -E is supposed to write the file to stdout.  We
1176         -- generate <file>.cpp, so we also have to cat the file here.
1177      if (next_phase > last_phase && last_phase == Cpp)
1178         then run_something "Dump pre-processed file to stdout"
1179                 ("cat " ++ output_fn)
1180         else return ()
1181
1182      run_pipeline last_phase do_linking use_ofile 
1183           orig_basename (next_phase, output_fn)
1184
1185
1186 -- find a temporary name that doesn't already exist.
1187 newTempName :: String -> IO String
1188 newTempName extn = do
1189   x <- getProcessID
1190   tmp_dir <- readIORef tmp_prefix 
1191   findTempName tmp_dir x
1192   where findTempName tmp_dir x = do
1193            let filename = tmp_dir ++ "/ghc" ++ show x ++ '.':extn
1194            b  <- fileExist filename
1195            if b then findTempName tmp_dir (x+1)
1196                 else return filename
1197
1198 -------------------------------------------------------------------------------
1199 -- mkdependHS phase 
1200
1201 do_mkdependHS :: [String] -> [String] -> IO ()
1202 do_mkdependHS cmd_opts srcs = do
1203
1204     --  # They're not (currently) needed, but we need to quote any -#include options
1205     -- foreach (@Cmd_opts) {
1206     --     s/-#include.*$/'$&'/g;
1207     -- };  
1208
1209    mkdependHS      <- readIORef pgm_dep
1210    mkdependHS_opts <- getOpts opt_dep
1211    hs_src_cpp_opts <- readIORef hs_source_cpp_opts
1212
1213    run_something "Dependency generation"
1214         (unwords (mkdependHS : 
1215                       mkdependHS_opts
1216                    ++ hs_src_cpp_opts
1217                    ++ ("--" : cmd_opts )
1218                    ++ ("--" : srcs)
1219         ))
1220
1221 -------------------------------------------------------------------------------
1222 -- Unlit phase 
1223
1224 run_phase Unlit basename input_fn output_fn
1225   = do unlit <- readIORef pgm_L
1226        unlit_flags <- getOpts opt_L
1227        run_something "Literate pre-processor"
1228           ("echo '# 1 \"" ++input_fn++"\"' > "++output_fn++" && "
1229            ++ unlit ++ ' ':input_fn ++ " - >> " ++ output_fn)
1230
1231 -------------------------------------------------------------------------------
1232 -- Cpp phase 
1233
1234 run_phase Cpp basename input_fn output_fn
1235   = do src_opts <- getOptionsFromSource input_fn
1236        processArgs src_opts []
1237
1238        do_cpp <- readIORef cpp_flag
1239        if do_cpp
1240           then do
1241             cpp <- readIORef pgm_P
1242             hscpp_opts <- getOpts opt_P
1243             hs_src_cpp_opts <- readIORef hs_source_cpp_opts
1244
1245             cmdline_include_paths <- readIORef include_paths
1246             pkg_include_dirs <- getPackageIncludePath
1247             let include_paths = map (\p -> "-I"++p) (cmdline_include_paths
1248                                                         ++ pkg_include_dirs)
1249
1250             verb <- is_verbose
1251             run_something "C pre-processor" 
1252                 (unwords
1253                    (["echo '{-# LINE 1 \"" ++ input_fn ++ "\" -}'", ">", output_fn, "&&",
1254                      cpp, verb] 
1255                     ++ include_paths
1256                     ++ hs_src_cpp_opts
1257                     ++ hscpp_opts
1258                     ++ [ "-x", "c", input_fn, ">>", output_fn ]
1259                    ))
1260           else do
1261             run_something "Inefective C pre-processor"
1262                    ("echo '{-# LINE 1 \""  ++ input_fn ++ "\" -}' > " 
1263                     ++ output_fn ++ " && cat " ++ input_fn
1264                     ++ " >> " ++ output_fn)
1265
1266 -----------------------------------------------------------------------------
1267 -- Hsc phase
1268
1269 run_phase Hsc   basename input_fn output_fn
1270   = do  hsc <- readIORef pgm_C
1271         
1272   -- we add the current directory (i.e. the directory in which
1273   -- the .hs files resides) to the import path, since this is
1274   -- what gcc does, and it's probably what you want.
1275         let (root,dir) = break (=='/') (reverse basename)
1276             current_dir = if null dir then "." else reverse dir
1277         
1278         paths <- readIORef include_paths
1279         writeIORef include_paths (current_dir : paths)
1280         
1281   -- build the hsc command line
1282         hsc_opts <- build_hsc_opts
1283         
1284         doing_hi <- readIORef produceHi
1285         tmp_hi_file <- if doing_hi      
1286                           then do fn <- newTempName "hi"
1287                                   add files_to_clean fn
1288                                   return fn
1289                           else return ""
1290         
1291         let hi_flag = if doing_hi then "-hifile=" ++ tmp_hi_file
1292                                   else ""
1293         
1294   -- deal with -Rghc-timing
1295         timing <- readIORef collect_ghc_timing
1296         stat_file <- newTempName "stat"
1297         add files_to_clean stat_file
1298         let stat_opts | timing    = [ "+RTS", "-S"++stat_file, "-RTS" ]
1299                       | otherwise = []
1300
1301   -- tmp files for foreign export stub code
1302         tmp_stub_h <- newTempName "stub_h"
1303         tmp_stub_c <- newTempName "stub_c"
1304         add files_to_clean tmp_stub_h
1305         add files_to_clean tmp_stub_c
1306         
1307         run_something "Haskell Compiler" 
1308                  (unwords (hsc : input_fn : (
1309                     hsc_opts
1310                     ++ [ hi_flag, " -ofile="++output_fn ]
1311                     ++ [ "-F="++tmp_stub_c, "-FH="++tmp_stub_h ]
1312                     ++ stat_opts
1313                  )))
1314
1315   -- Copy the .hi file into the current dir if it changed
1316         on doing_hi 
1317                   (do ohi <- readIORef output_hi
1318                       hisuf <- readIORef hi_suf
1319                       let hi_target = case ohi of
1320                                         Nothing -> basename ++ '.':hisuf
1321                                         Just fn -> fn
1322                       new_hi_file <- fileExist tmp_hi_file
1323                       on new_hi_file
1324                              (run_something "Copy hi file"
1325                                 (unwords ["mv", tmp_hi_file, hi_target]))
1326                   )     
1327         
1328   -- Generate -Rghc-timing info
1329         on (timing) (
1330             run_something "Generate timing stats"
1331                 (findFile "ghc-stats" cGHC_STATS ++ ' ':stat_file)
1332          )
1333
1334   -- Deal with stubs
1335         let stub_h = basename ++ "_stub.h"
1336         let stub_c = basename ++ "_stub.c"
1337         
1338                 -- copy .h_stub file into current dir if present
1339         b <- fileExist tmp_stub_h
1340         on b (do
1341                 run_something "Copy stub .h file"
1342                                 ("cp " ++ tmp_stub_h ++ ' ':stub_h)
1343         
1344                         -- #include <..._stub.h> in .hc file
1345                 add cmdline_hc_includes tmp_stub_h      -- hack
1346
1347                         -- copy the _stub.c file into the current dir
1348                 run_something "Copy stub .c file" 
1349                     (unwords [ 
1350                         "rm -f", stub_c, "&&",
1351                         "echo \'#include \""++stub_h++"\"\' >"++stub_c, " &&",
1352                         "cat", tmp_stub_c, ">> ", stub_c
1353                         ])
1354
1355                         -- compile the _stub.c file w/ gcc
1356                 run_pipeline As False{-no linking-} 
1357                                 False{-no -o option-}
1358                                 (basename++"_stub")
1359                                 (Cc, stub_c)
1360
1361                 add ld_inputs (basename++"_stub.o")
1362          )
1363
1364 -----------------------------------------------------------------------------
1365 -- Cc phase
1366
1367 -- we don't support preprocessing .c files (with -E) now.  Doing so introduces
1368 -- way too many hacks, and I can't say I've ever used it anyway.
1369
1370 run_phase cc_phase basename input_fn output_fn
1371    | cc_phase == Cc || cc_phase == HCc
1372    = do cc <- readIORef pgm_c
1373         cc_opts <- getOpts opt_c
1374         cmdline_include_dirs <- readIORef include_paths
1375        -- ToDo: $c_flags .= " -mno-cygwin" if ( $TargetPlatform =~ /-mingw32$/ );
1376
1377         let hcc = cc_phase == HCc
1378
1379                 -- add package include paths even if we're just compiling
1380                 -- .c files; this is the Value Add(TM) that using
1381                 -- ghc instead of gcc gives you :)
1382         pkg_include_dirs <- getPackageIncludePath
1383         let include_paths = map (\p -> "-I"++p) (cmdline_include_dirs 
1384                                                         ++ pkg_include_dirs)
1385
1386         c_includes <- getPackageCIncludes
1387         cmdline_includes <- readIORef cmdline_hc_includes -- -#include options
1388
1389         let cc_injects | hcc = unlines (map mk_include 
1390                                         (c_includes ++ reverse cmdline_includes))
1391                        | otherwise = ""
1392             mk_include h_file = 
1393                 case h_file of 
1394                    '"':_{-"-} -> "#include "++h_file
1395                    '<':_      -> "#include "++h_file
1396                    _          -> "#include \""++h_file++"\""
1397
1398         cc_help <- newTempName "c"
1399         add files_to_clean cc_help
1400         h <- openFile cc_help WriteMode
1401         hPutStr h cc_injects
1402         hPutStrLn h ("#include \"" ++ input_fn ++ "\"\n")
1403         hClose h
1404
1405         ccout <- newTempName "ccout"
1406         add files_to_clean ccout
1407
1408         mangle <- readIORef do_asm_mangling
1409         (md_c_flags, md_regd_c_flags) <- machdepCCOpts
1410
1411         verb <- is_verbose
1412
1413         o2 <- readIORef opt_minus_o2_for_C
1414         let opt_flag | o2        = "-O2"
1415                      | otherwise = "-O"
1416
1417         pkg_extra_cc_opts <- getPackageExtraCcOpts
1418
1419         run_something "C Compiler"
1420          (unwords ([ cc, "-x", "c", cc_help, "-o", output_fn ]
1421                    ++ md_c_flags
1422                    ++ (if cc_phase == HCc && mangle
1423                          then md_regd_c_flags
1424                          else [])
1425                    ++ [ verb, "-S", "-Wimplicit", opt_flag ]
1426                    ++ [ "-D__GLASGOW_HASKELL__="++cProjectVersionInt ]
1427                    ++ cc_opts
1428                    ++ include_paths
1429                    ++ pkg_extra_cc_opts
1430 --                 ++ [">", ccout]
1431                    ))
1432
1433         -- ToDo: postprocess the output from gcc
1434
1435 -----------------------------------------------------------------------------
1436 -- Mangle phase
1437
1438 run_phase Mangle basename input_fn output_fn
1439   = do mangler <- readIORef pgm_m
1440        mangler_opts <- getOpts opt_m
1441        machdep_opts <-
1442          if (prefixMatch "i386" cTARGETPLATFORM)
1443             then do n_regs <- readIORef stolen_x86_regs
1444                     return [ show n_regs ]
1445             else return []
1446        run_something "Assembly Mangler"
1447         (unwords (mangler : 
1448                      mangler_opts
1449                   ++ [ input_fn, output_fn ]
1450                   ++ machdep_opts
1451                 ))
1452
1453 -----------------------------------------------------------------------------
1454 -- Splitting phase
1455
1456 run_phase SplitMangle basename input_fn outputfn
1457   = do  splitter <- readIORef pgm_s
1458
1459         -- this is the prefix used for the split .s files
1460         tmp_pfx <- readIORef tmp_prefix
1461         x <- getProcessID
1462         let split_s_prefix = tmp_pfx ++ "/ghc" ++ show x
1463         writeIORef split_prefix split_s_prefix
1464         add files_to_clean (split_s_prefix ++ "__*") -- d:-)
1465
1466         -- allocate a tmp file to put the no. of split .s files in (sigh)
1467         n_files <- newTempName "n_files"
1468         add files_to_clean n_files
1469
1470         run_something "Split Assembly File"
1471          (unwords [ splitter
1472                   , input_fn
1473                   , split_s_prefix
1474                   , n_files ]
1475          )
1476
1477         -- save the number of split files for future references
1478         s <- readFile n_files
1479         let n = read s :: Int
1480         writeIORef n_split_files n
1481
1482 -----------------------------------------------------------------------------
1483 -- As phase
1484
1485 run_phase As basename input_fn output_fn
1486   = do  as <- readIORef pgm_a
1487         as_opts <- getOpts opt_a
1488
1489         cmdline_include_paths <- readIORef include_paths
1490         let cmdline_include_flags = map (\p -> "-I"++p) cmdline_include_paths
1491         run_something "Assembler"
1492            (unwords (as : as_opts
1493                        ++ cmdline_include_flags
1494                        ++ [ "-c", input_fn, "-o",  output_fn ]
1495                     ))
1496
1497 run_phase SplitAs basename input_fn output_fn
1498   = do  as <- readIORef pgm_a
1499         as_opts <- getOpts opt_a
1500
1501         odir_opt <- readIORef output_dir
1502         let odir | Just s <- odir_opt = s
1503                      | otherwise          = basename
1504         
1505         split_s_prefix <- readIORef split_prefix
1506         n <- readIORef n_split_files
1507
1508         odir <- readIORef output_dir
1509         let real_odir = case odir of
1510                                 Nothing -> basename
1511                                 Just d  -> d
1512
1513         let assemble_file n = do
1514                     let input_s  = split_s_prefix ++ "__" ++ show n ++ ".s"
1515                     let output_o = newdir real_odir 
1516                                         (basename ++ "__" ++ show n ++ ".o")
1517                     real_o <- osuf_ify output_o
1518                     run_something "Assembler" 
1519                             (unwords (as : as_opts
1520                                       ++ [ "-c", "-o", real_o, input_s ]
1521                             ))
1522         
1523         mapM_ assemble_file [1..n]
1524
1525 -----------------------------------------------------------------------------
1526 -- Linking
1527
1528 do_link :: [String] -> [String] -> IO ()
1529 do_link o_files unknown_srcs = do
1530     ln <- readIORef pgm_l
1531     verb <- is_verbose
1532     o_file <- readIORef output_file
1533     let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }
1534
1535     pkg_lib_paths <- getPackageLibraryPath
1536     let pkg_lib_path_opts = map ("-L"++) pkg_lib_paths
1537
1538     lib_paths <- readIORef library_paths
1539     let lib_path_opts = map ("-L"++) lib_paths
1540
1541     pkg_libs <- getPackageLibraries
1542     let pkg_lib_opts = map ("-l"++) pkg_libs
1543
1544     libs <- readIORef cmdline_libraries
1545     let lib_opts = map ("-l"++) (reverse libs)
1546          -- reverse because they're added in reverse order from the cmd line
1547
1548     pkg_extra_ld_opts <- getPackageExtraLdOpts
1549
1550         -- probably _stub.o files
1551     extra_ld_inputs <- readIORef ld_inputs
1552
1553         -- opts from -optl-<blah>
1554     extra_ld_opts <- getOpts opt_l
1555
1556     run_something "Linker"
1557        (unwords 
1558          ([ ln, verb, "-o", output_fn ]
1559          ++ o_files
1560          ++ unknown_srcs
1561          ++ extra_ld_inputs
1562          ++ lib_path_opts
1563          ++ lib_opts
1564          ++ pkg_lib_path_opts
1565          ++ pkg_lib_opts
1566          ++ pkg_extra_ld_opts
1567          ++ extra_ld_opts
1568         )
1569        )
1570
1571 -----------------------------------------------------------------------------
1572 -- Running an external program
1573
1574 run_something phase_name cmd
1575  = do
1576    verb <- readIORef verbose
1577    if verb then do
1578         putStr phase_name
1579         putStrLn ":"
1580         putStrLn cmd
1581      else
1582         return ()
1583
1584    -- test for -n flag
1585    n <- readIORef dry_run
1586    if n then return () else do 
1587
1588    -- and run it!
1589    exit_code <- system cmd  `catchAllIO` 
1590                    (\e -> throwDyn (PhaseFailed phase_name (ExitFailure 1)))
1591
1592    if exit_code /= ExitSuccess
1593         then throwDyn (PhaseFailed phase_name exit_code)
1594         else do on verb (putStr "\n")
1595                 return ()
1596
1597 -----------------------------------------------------------------------------
1598 -- Flags
1599
1600 data OptKind 
1601         = NoArg (IO ())                 -- flag with no argument
1602         | HasArg (String -> IO ())      -- flag has an argument (maybe prefix)
1603         | SepArg (String -> IO ())      -- flag has a separate argument
1604         | Prefix (String -> IO ())      -- flag is a prefix only
1605         | OptPrefix (String -> IO ())   -- flag may be a prefix
1606         | AnySuffix (String -> IO ())   -- flag is a prefix, pass whole arg to fn
1607         | PassFlag  (String -> IO ())   -- flag with no arg, pass flag to fn
1608
1609 -- note that ordering is important in the following list: any flag which
1610 -- is a prefix flag (i.e. HasArg, Prefix, OptPrefix, AnySuffix) will override
1611 -- flags further down the list with the same prefix.
1612
1613 opts = 
1614   [  ------- help -------------------------------------------------------
1615      ( "?"              , NoArg long_usage)
1616   ,  ( "-help"          , NoArg long_usage)
1617   
1618
1619       ------- version ----------------------------------------------------
1620   ,  ( "-version"        , NoArg (do hPutStrLn stderr (cProjectName
1621                                       ++ ", version " ++ version_str)
1622                                      exitWith ExitSuccess))
1623   ,  ( "-numeric-version", NoArg (do hPutStrLn stderr version_str
1624                                      exitWith ExitSuccess))
1625
1626       ------- verbosity ----------------------------------------------------
1627   ,  ( "v"              , NoArg (writeIORef verbose True) )
1628   ,  ( "n"              , NoArg (writeIORef dry_run True) )
1629
1630         ------- recompilation checker --------------------------------------
1631   ,  ( "recomp"         , NoArg (writeIORef recomp True) )
1632   ,  ( "no-recomp"      , NoArg (writeIORef recomp False) )
1633
1634         ------- ways --------------------------------------------------------
1635   ,  ( "prof"           , NoArg (addNoDups ways WayProf) )
1636   ,  ( "unreg"          , NoArg (addNoDups ways WayUnreg) )
1637   ,  ( "ticky"          , NoArg (addNoDups ways WayTicky) )
1638   ,  ( "parallel"       , NoArg (addNoDups ways WayPar) )
1639   ,  ( "gransim"        , NoArg (addNoDups ways WayGran) )
1640   ,  ( "smp"            , NoArg (addNoDups ways WaySMP) )
1641   ,  ( "debug"          , NoArg (addNoDups ways WayDebug) )
1642         -- ToDo: user ways
1643
1644         ------- Interface files ---------------------------------------------
1645   ,  ( "hi"             , NoArg (writeIORef produceHi True) )
1646   ,  ( "nohi"           , NoArg (writeIORef produceHi False) )
1647   ,  ( "hi-diffs"       , NoArg (writeIORef hi_diffs  NormalHiDiffs) )
1648   ,  ( "no-hi-diffs"    , NoArg (writeIORef hi_diffs  NoHiDiffs) )
1649   ,  ( "hi-diffs-with-usages" , NoArg (writeIORef hi_diffs UsageHiDiffs) )
1650   ,  ( "keep-hi-diffs"  , NoArg (writeIORef keep_hi_diffs True) )
1651         --"hi-with-*"    -> hiw <- readIORef hi_with  (ToDo)
1652
1653         --------- Profiling --------------------------------------------------
1654   ,  ( "auto-dicts"     , NoArg (add opt_C "-fauto-sccs-on-dicts") )
1655   ,  ( "auto-all"       , NoArg (add opt_C "-fauto-sccs-on-all-toplevs") )
1656   ,  ( "auto"           , NoArg (add opt_C "-fauto-sccs-on-exported-toplevs") )
1657   ,  ( "caf-all"        , NoArg (add opt_C "-fauto-sccs-on-individual-cafs") )
1658          -- "ignore-sccs"  doesn't work  (ToDo)
1659
1660         ------- Miscellaneous -----------------------------------------------
1661   ,  ( "cpp"            , NoArg (writeIORef cpp_flag True) )
1662   ,  ( "#include"       , HasArg (add cmdline_hc_includes) )
1663   ,  ( "no-link-chk"    , NoArg (return ()) ) -- ignored for backwards compat
1664
1665         ------- Output Redirection ------------------------------------------
1666   ,  ( "odir"           , HasArg (writeIORef output_dir  . Just) )
1667   ,  ( "o"              , SepArg (writeIORef output_file . Just) )
1668   ,  ( "osuf"           , HasArg (writeIORef output_suf  . Just) )
1669   ,  ( "hisuf"          , HasArg (writeIORef hi_suf) )
1670   ,  ( "tmpdir"         , HasArg (writeIORef tmp_prefix  . (++ "/")) )
1671   ,  ( "ohi"            , HasArg (\s -> case s of 
1672                                           "-" -> writeIORef hi_on_stdout True
1673                                           _   -> writeIORef output_hi (Just s)) )
1674         -- -odump?
1675
1676   ,  ( "keep-hc-file"   , AnySuffix (\_ -> writeIORef keep_hc_files True) )
1677   ,  ( "keep-s-file"    , AnySuffix (\_ -> writeIORef keep_s_files  True) )
1678   ,  ( "keep-raw-s-file", AnySuffix (\_ -> writeIORef keep_raw_s_files  True) )
1679
1680   ,  ( "split-objs"     , NoArg (if can_split
1681                                     then do writeIORef split_object_files True
1682                                             writeIORef hsc_lang HscC
1683                                             add opt_C "-fglobalise-toplev-names"
1684                                             add opt_c "-DUSE_SPLIT_MARKERS"
1685                                     else hPutStrLn stderr
1686                                             "warning: don't know how to  split \
1687                                             \object files on this architecture"
1688                                 ) )
1689   
1690         ------- Include/Import Paths ----------------------------------------
1691   ,  ( "i"              , OptPrefix augment_import_paths )
1692   ,  ( "I"              , Prefix augment_include_paths )
1693
1694         ------- Libraries ---------------------------------------------------
1695   ,  ( "L"              , Prefix augment_library_paths )
1696   ,  ( "l"              , Prefix (add cmdline_libraries) )
1697
1698         ------- Packages ----------------------------------------------------
1699   ,  ( "package-name"   , HasArg (\s -> add opt_C ("-inpackage="++s)) )
1700
1701   ,  ( "package"        , HasArg (addPackage) )
1702   ,  ( "syslib"         , HasArg (addPackage) ) -- for compatibility w/ old vsns
1703
1704         ------- Specific phases  --------------------------------------------
1705   ,  ( "pgmdep"         , HasArg (writeIORef pgm_dep) )
1706   ,  ( "pgmL"           , HasArg (writeIORef pgm_L) )
1707   ,  ( "pgmP"           , HasArg (writeIORef pgm_P) )
1708   ,  ( "pgmC"           , HasArg (writeIORef pgm_C) )
1709   ,  ( "pgmc"           , HasArg (writeIORef pgm_c) )
1710   ,  ( "pgmm"           , HasArg (writeIORef pgm_m) )
1711   ,  ( "pgms"           , HasArg (writeIORef pgm_s) )
1712   ,  ( "pgma"           , HasArg (writeIORef pgm_a) )
1713   ,  ( "pgml"           , HasArg (writeIORef pgm_l) )
1714
1715   ,  ( "optdep"         , HasArg (add opt_dep) )
1716   ,  ( "optL"           , HasArg (add opt_L) )
1717   ,  ( "optP"           , HasArg (add opt_P) )
1718   ,  ( "optCrts"        , HasArg (add opt_Crts) )
1719   ,  ( "optC"           , HasArg (add opt_C) )
1720   ,  ( "optc"           , HasArg (add opt_c) )
1721   ,  ( "optm"           , HasArg (add opt_m) )
1722   ,  ( "opta"           , HasArg (add opt_a) )
1723   ,  ( "optl"           , HasArg (add opt_l) )
1724   ,  ( "optdll"         , HasArg (add opt_dll) )
1725
1726         ------ HsCpp opts ---------------------------------------------------
1727   ,  ( "D"              , Prefix (\s -> add opt_P ("-D'"++s++"'") ) )
1728   ,  ( "U"              , Prefix (\s -> add opt_P ("-U'"++s++"'") ) )
1729
1730         ------ Warning opts -------------------------------------------------
1731   ,  ( "W"              , NoArg (writeIORef warning_opt W_))
1732   ,  ( "Wall"           , NoArg (writeIORef warning_opt W_all))
1733   ,  ( "Wnot"           , NoArg (writeIORef warning_opt W_not))
1734   ,  ( "w"              , NoArg (writeIORef warning_opt W_not))
1735
1736         ----- Linker --------------------------------------------------------
1737   ,  ( "static"         , NoArg (writeIORef static True) )
1738
1739         ------ Compiler RTS options -----------------------------------------
1740   ,  ( "H"                 , HasArg (sizeOpt specific_heap_size) )
1741   ,  ( "K"                 , HasArg (sizeOpt specific_stack_size) )
1742   ,  ( "Rscale-sizes"      , HasArg (floatOpt scale_sizes_by) )
1743   ,  ( "Rghc-timing"       , NoArg (writeIORef collect_ghc_timing True) )
1744
1745         ------ Debugging ----------------------------------------------------
1746   ,  ( "dstg-stats"        , NoArg (writeIORef opt_StgStats True) )
1747
1748   ,  ( "dno-"              , Prefix (\s -> add anti_opt_C ("-d"++s)) )
1749   ,  ( "d"                 , AnySuffix (add opt_C) )
1750
1751         ------ Machine dependant (-m<blah>) stuff ---------------------------
1752
1753   ,  ( "monly-2-regs",          NoArg (writeIORef stolen_x86_regs 2) )
1754   ,  ( "monly-3-regs",          NoArg (writeIORef stolen_x86_regs 3) )
1755   ,  ( "monly-4-regs",          NoArg (writeIORef stolen_x86_regs 4) )
1756
1757         ------ Compiler flags -----------------------------------------------
1758   ,  ( "O2-for-C"          , NoArg (writeIORef opt_minus_o2_for_C True) )
1759   ,  ( "O"                 , OptPrefix (setOptLevel) )
1760
1761   ,  ( "fglasgow-exts-no-lang", NoArg ( do add opt_C "-fglasgow-exts") )
1762
1763   ,  ( "fglasgow-exts"     , NoArg (do add opt_C "-fglasgow-exts"
1764                                        addPackage "lang"))
1765
1766   ,  ( "fasm"              , OptPrefix (\_ -> writeIORef hsc_lang HscAsm) )
1767
1768   ,  ( "fvia-C"            , NoArg (writeIORef hsc_lang HscC) )
1769
1770   ,  ( "fno-asm-mangling"  , NoArg (writeIORef do_asm_mangling False) )
1771
1772   ,  ( "fmax-simplifier-iterations", 
1773                 Prefix (writeIORef opt_MaxSimplifierIterations . read) )
1774
1775   ,  ( "fusagesp",              NoArg (do writeIORef opt_UsageSPInf True
1776                                           add opt_C "-fusagesp-on") )
1777
1778         -- flags that are "active negatives"
1779   ,  ( "fno-implicit-prelude"   , PassFlag (add opt_C) )
1780   ,  ( "fno-prune-tydecls"      , PassFlag (add opt_C) )
1781   ,  ( "fno-prune-instdecls"    , PassFlag (add opt_C) )
1782   ,  ( "fno-pre-inlining"       , PassFlag (add opt_C) )
1783
1784         -- All other "-fno-<blah>" options cancel out "-f<blah>" on the hsc cmdline
1785   ,  ( "fno-",                  Prefix (\s -> add anti_opt_C ("-f"++s)) )
1786
1787         -- Pass all remaining "-f<blah>" options to hsc
1788   ,  ( "f",                     AnySuffix (add opt_C) )
1789   ]
1790
1791 -----------------------------------------------------------------------------
1792 -- Process command-line  
1793
1794 processArgs :: [String] -> [String] -> IO [String]  -- returns spare args
1795 processArgs [] spare = return (reverse spare)
1796 processArgs args@(('-':_):_) spare = do
1797   args' <- processOneArg args
1798   processArgs args' spare
1799 processArgs (arg:args) spare = 
1800   processArgs args (arg:spare)
1801
1802 processOneArg :: [String] -> IO [String]
1803 processOneArg (('-':arg):args) = do
1804   let (rest,action) = findArg arg
1805       dash_arg = '-':arg
1806   case action of
1807
1808         NoArg  io -> 
1809                 if rest == ""
1810                         then io >> return args
1811                         else throwDyn (UnknownFlag dash_arg)
1812
1813         HasArg fio -> 
1814                 if rest /= "" 
1815                         then fio rest >> return args
1816                         else case args of
1817                                 [] -> throwDyn (UnknownFlag dash_arg)
1818                                 (arg1:args1) -> fio arg1 >> return args1
1819
1820         SepArg fio -> 
1821                 case args of
1822                         [] -> throwDyn (UnknownFlag dash_arg)
1823                         (arg1:args1) -> fio arg1 >> return args1
1824
1825         Prefix fio -> 
1826                 if rest /= ""
1827                         then fio rest >> return args
1828                         else throwDyn (UnknownFlag dash_arg)
1829         
1830         OptPrefix fio -> fio rest >> return args
1831
1832         AnySuffix fio -> fio ('-':arg) >> return args
1833
1834         PassFlag fio  -> 
1835                 if rest /= ""
1836                         then throwDyn (UnknownFlag dash_arg)
1837                         else fio ('-':arg) >> return args
1838
1839 findArg :: String -> (String,OptKind)
1840 findArg arg
1841   = case [ (remove_spaces rest, k) | (pat,k) <- opts, 
1842                                      Just rest <- [my_prefix_match pat arg],
1843                                      is_prefix k || null rest ] of
1844         [] -> throwDyn (UnknownFlag ('-':arg))
1845         (one:_) -> one
1846
1847 is_prefix (NoArg _) = False
1848 is_prefix (SepArg _) = False
1849 is_prefix (PassFlag _) = False
1850 is_prefix _ = True
1851
1852 -----------------------------------------------------------------------------
1853 -- convert sizes like "3.5M" into integers
1854
1855 sizeOpt :: IORef Integer -> String -> IO ()
1856 sizeOpt ref str
1857   | c == ""              = writeSizeOpt ref (truncate n)
1858   | c == "K" || c == "k" = writeSizeOpt ref (truncate (n * 1000))
1859   | c == "M" || c == "m" = writeSizeOpt ref (truncate (n * 1000 * 1000))
1860   | c == "G" || c == "g" = writeSizeOpt ref (truncate (n * 1000 * 1000 * 1000))
1861   | otherwise            = throwDyn (UnknownFlag str)
1862   where (m, c) = span pred str
1863         n      = read m  :: Double
1864         pred c = isDigit c || c == '.'
1865
1866 writeSizeOpt :: IORef Integer -> Integer -> IO ()
1867 writeSizeOpt ref new = do
1868   current <- readIORef ref
1869   if (new > current) 
1870         then writeIORef ref new
1871         else return ()
1872
1873 floatOpt :: IORef Double -> String -> IO ()
1874 floatOpt ref str
1875   = writeIORef ref (read str :: Double)
1876
1877 -----------------------------------------------------------------------------
1878 -- Finding files in the installation
1879
1880 GLOBAL_VAR(topDir, clibdir, String)
1881
1882         -- grab the last -B option on the command line, and
1883         -- set topDir to its value.
1884 setTopDir :: [String] -> IO [String]
1885 setTopDir args = do
1886   let (minusbs, others) = partition (prefixMatch "-B") args
1887   (case minusbs of
1888     []   -> writeIORef topDir clibdir
1889     some -> writeIORef topDir (drop 2 (last some)))
1890   return others
1891
1892 findFile name alt_path = unsafePerformIO (do
1893   top_dir <- readIORef topDir
1894   let installed_file = top_dir ++ '/':name
1895   let inplace_file   = top_dir ++ '/':cCURRENT_DIR ++ '/':alt_path
1896   b <- fileExist inplace_file
1897   if b  then return inplace_file
1898         else return installed_file
1899  )
1900
1901 -----------------------------------------------------------------------------
1902 -- Utils
1903
1904 my_partition :: (a -> Maybe b) -> [a] -> ([b],[a])
1905 my_partition p [] = ([],[])
1906 my_partition p (a:as)
1907   = let (bs,cs) = my_partition p as in
1908     case p a of
1909         Nothing -> (bs,a:cs)
1910         Just b  -> (b:bs,cs)
1911
1912 my_prefix_match :: String -> String -> Maybe String
1913 my_prefix_match [] rest = Just rest
1914 my_prefix_match (p:pat) [] = Nothing
1915 my_prefix_match (p:pat) (r:rest)
1916   | p == r    = my_prefix_match pat rest
1917   | otherwise = Nothing
1918
1919 prefixMatch :: Eq a => [a] -> [a] -> Bool
1920 prefixMatch [] str = True
1921 prefixMatch pat [] = False
1922 prefixMatch (p:ps) (s:ss) | p == s    = prefixMatch ps ss
1923                           | otherwise = False
1924
1925 postfixMatch :: String -> String -> Bool
1926 postfixMatch pat str = prefixMatch (reverse pat) (reverse str)
1927
1928 later = flip finally
1929
1930 on b io = if b then io >> return (error "on") else return (error "on")
1931
1932 my_catch = flip catchAllIO
1933 my_catchDyn = flip catchDyn
1934
1935 global :: a -> IORef a
1936 global a = unsafePerformIO (newIORef a)
1937
1938 split_filename :: String -> (String,String)
1939 split_filename f = (reverse rev_basename, reverse rev_ext)
1940   where (rev_ext, '.':rev_basename) = span ('.' /=) (reverse f)
1941
1942 split :: Char -> String -> [String]
1943 split c s = case rest of
1944                 []     -> [chunk] 
1945                 _:rest -> chunk : split c rest
1946   where (chunk, rest) = break (==c) s
1947
1948 add :: IORef [a] -> a -> IO ()
1949 add var x = do
1950   xs <- readIORef var
1951   writeIORef var (x:xs)
1952
1953 addNoDups :: Eq a => IORef [a] -> a -> IO ()
1954 addNoDups var x = do
1955   xs <- readIORef var
1956   if x `elem` xs then return () else writeIORef var (x:xs)
1957
1958 remove_suffix :: String -> Char -> String
1959 remove_suffix s c 
1960   | null pre  = reverse suf
1961   | otherwise = reverse pre
1962   where (suf,pre) = break (==c) (reverse s)
1963
1964 drop_longest_prefix :: String -> Char -> String
1965 drop_longest_prefix s c = reverse suf
1966   where (suf,pre) = break (==c) (reverse s)
1967
1968 take_longest_prefix :: String -> Char -> String
1969 take_longest_prefix s c = reverse pre
1970   where (suf,pre) = break (==c) (reverse s)
1971
1972 newsuf :: String -> String -> String
1973 newsuf suf s = remove_suffix s '.' ++ suf
1974
1975 newdir :: String -> String -> String
1976 newdir dir s = dir ++ '/':drop_longest_prefix s '/'
1977
1978 remove_spaces :: String -> String
1979 remove_spaces = reverse . dropWhile isSpace . reverse . dropWhile isSpace