-----------------------------------------------------------------------------
--- $Id: DriverState.hs,v 1.38 2001/05/09 09:38:18 simonmar Exp $
+-- $Id: DriverState.hs,v 1.62 2001/12/05 00:08:27 sof Exp $
--
-- Settings for the driver
--
module DriverState where
+#include "../includes/config.h"
#include "HsVersions.h"
-import CmStaticInfo
+import SysTools ( getTopDir )
+import ParsePkgConf ( loadPackageConfig )
+import Packages ( PackageConfig(..), mungePackagePaths )
import CmdLineOpts
+import DriverPhases
import DriverUtil
import Util
import Config
import Exception
import IOExts
-#ifdef mingw32_TARGET_OS
-import TmpFiles ( newTempName )
-import Directory ( removeFile )
-#endif
import Panic
import List
import Char
import Monad
+import Directory ( doesDirectoryExist )
-----------------------------------------------------------------------------
-- non-configured things
cHaskell1Version = "5" -- i.e., Haskell 98
-----------------------------------------------------------------------------
--- Global compilation flags
+-- GHC modes of operation
+
+data GhcMode
+ = DoMkDependHS -- ghc -M
+ | DoMkDLL -- ghc --mk-dll
+ | StopBefore Phase -- ghc -E | -C | -S | -c
+ | DoMake -- ghc --make
+ | DoInteractive -- ghc --interactive
+ | DoLink -- [ the default ]
+ deriving (Eq)
--- location of compiler-related files
-GLOBAL_VAR(v_TopDir, error "no TOPDIR", String)
+GLOBAL_VAR(v_GhcMode, error "mode not set", GhcMode)
+
+isCompManagerMode DoMake = True
+isCompManagerMode DoInteractive = True
+isCompManagerMode _ = False
+
+-----------------------------------------------------------------------------
+-- Global compilation flags
-- Cpp-related flags
v_Hs_source_cpp_opts = global
]
{-# NOINLINE v_Hs_source_cpp_opts #-}
+
-- Keep output from intermediate phases
GLOBAL_VAR(v_Keep_hi_diffs, False, Bool)
GLOBAL_VAR(v_Keep_hc_files, False, Bool)
GLOBAL_VAR(v_Keep_s_files, False, Bool)
GLOBAL_VAR(v_Keep_raw_s_files, False, Bool)
GLOBAL_VAR(v_Keep_tmp_files, False, Bool)
+#ifdef ILX
+GLOBAL_VAR(v_Keep_il_files, False, Bool)
+GLOBAL_VAR(v_Keep_ilx_files, False, Bool)
+#endif
-- Misc
GLOBAL_VAR(v_Scale_sizes_by, 1.0, Double)
-GLOBAL_VAR(v_Dry_run, False, Bool)
GLOBAL_VAR(v_Static, True, Bool)
GLOBAL_VAR(v_NoHsMain, False, Bool)
GLOBAL_VAR(v_Recomp, True, Bool)
GLOBAL_VAR(v_Collect_ghc_timing, False, Bool)
GLOBAL_VAR(v_Do_asm_mangling, True, Bool)
GLOBAL_VAR(v_Excess_precision, False, Bool)
+GLOBAL_VAR(v_Read_DotGHCi, True, Bool)
+
+-- Preprocessor flags
+GLOBAL_VAR(v_Hs_source_pp_opts, [], [String])
-----------------------------------------------------------------------------
-- Splitting object files (for libraries)
GLOBAL_VAR(v_Split_object_files, False, Bool)
-GLOBAL_VAR(v_Split_prefix, "", String)
-GLOBAL_VAR(v_N_split_files, 0, Int)
+GLOBAL_VAR(v_Split_info, ("",0), (String,Int))
+ -- The split prefix and number of files
+
can_split :: Bool
can_split = prefixMatch "i386" cTARGETPLATFORM
GLOBAL_VAR(v_Object_suf, Nothing, Maybe String)
GLOBAL_VAR(v_HC_suf, Nothing, Maybe String)
+GLOBAL_VAR(v_Hi_dir, Nothing, Maybe String)
GLOBAL_VAR(v_Hi_suf, "hi", String)
GLOBAL_VAR(v_Ld_inputs, [], [String])
GLOBAL_VAR(v_Strictness, True, Bool)
GLOBAL_VAR(v_CPR, True, Bool)
GLOBAL_VAR(v_CSE, True, Bool)
+GLOBAL_VAR(v_RuleCheck, Nothing, Maybe String)
-- these are the static flags you get without -O.
hsc_minusNoO_flags =
strictness <- readIORef v_Strictness
cpr <- readIORef v_CPR
cse <- readIORef v_CSE
+ rule_check <- readIORef v_RuleCheck
if opt_level == 0 then return
[
- CoreDoSimplify (isAmongSimpl [
+ CoreDoSimplify (SimplPhase 0) [
MaxSimplifierIterations max_iter
- ])
+ ]
]
else {- opt_level >= 1 -} return [
-- initial simplify: mk specialiser happy: minimum effort please
- CoreDoSimplify (isAmongSimpl [
- SimplInlinePhase 0,
+ CoreDoSimplify SimplGently [
+ -- Simplify "gently"
-- Don't inline anything till full laziness has bitten
-- In particular, inlining wrappers inhibits floating
-- e.g. ...(case f x of ...)...
-- ==> ...(case (case x of I# x# -> fw x#) of ...)...
-- ==> ...(case x of I# x# -> case fw x# of ...)...
-- and now the redex (f x) isn't floatable any more
- DontApplyRules,
-- Similarly, don't apply any rules until after full
-- laziness. Notably, list fusion can prevent floating.
+
NoCaseOfCase,
-- Don't do case-of-case transformations.
-- This makes full laziness work better
MaxSimplifierIterations max_iter
- ]),
+ ],
-- Specialisation is best done before full laziness
-- so that overloaded functions have all their dictionary lambdas manifest
CoreDoFloatOutwards False{-not full-},
CoreDoFloatInwards,
- CoreDoSimplify (isAmongSimpl [
- SimplInlinePhase 1,
- -- Want to run with inline phase 1 after the specialiser to give
+ CoreDoSimplify (SimplPhase 2) [
+ -- Want to run with inline phase 2 after the specialiser to give
-- maximum chance for fusion to work before we inline build/augment
- -- in phase 2. This made a difference in 'ansi' where an
+ -- in phase 1. This made a difference in 'ansi' where an
-- overloaded function wasn't inlined till too late.
MaxSimplifierIterations max_iter
- ]),
+ ],
+ case rule_check of { Just pat -> CoreDoRuleCheck 2 pat; Nothing -> CoreDoNothing },
-- infer usage information here in case we need it later.
-- (add more of these where you need them --KSW 1999-04)
if usageSP then CoreDoUSPInf else CoreDoNothing,
- CoreDoSimplify (isAmongSimpl [
+ CoreDoSimplify (SimplPhase 1) [
-- Need inline-phase2 here so that build/augment get
-- inlined. I found that spectral/hartel/genfft lost some useful
-- strictness in the function sumcode' if augment is not inlined
-- before strictness analysis runs
- SimplInlinePhase 2,
MaxSimplifierIterations max_iter
- ]),
+ ],
+ case rule_check of { Just pat -> CoreDoRuleCheck 1 pat; Nothing -> CoreDoNothing },
- CoreDoSimplify (isAmongSimpl [
- MaxSimplifierIterations 2
- -- No -finline-phase: allow all Ids to be inlined now
+ CoreDoSimplify (SimplPhase 0) [
+ -- Phase 0: allow all Ids to be inlined now
-- This gets foldr inlined before strictness analysis
- ]),
- if strictness then CoreDoStrictness else CoreDoNothing,
+ MaxSimplifierIterations 3
+ -- At least 3 iterations because otherwise we land up with
+ -- huge dead expressions because of an infelicity in the
+ -- simpifier.
+ -- let k = BIG in foldr k z xs
+ -- ==> let k = BIG in letrec go = \xs -> ...(k x).... in go xs
+ -- ==> let k = BIG in letrec go = \xs -> ...(BIG x).... in go xs
+ -- Don't stop now!
+
+ ],
+ case rule_check of { Just pat -> CoreDoRuleCheck 0 pat; Nothing -> CoreDoNothing },
+
if cpr then CoreDoCPResult else CoreDoNothing,
+ if strictness then CoreDoStrictness else CoreDoNothing,
CoreDoWorkerWrapper,
CoreDoGlomBinds,
- CoreDoSimplify (isAmongSimpl [
+ CoreDoSimplify (SimplPhase 0) [
MaxSimplifierIterations max_iter
- -- No -finline-phase: allow all Ids to be inlined now
- ]),
+ ],
CoreDoFloatOutwards False{-not full-},
-- nofib/spectral/hartel/wang doubles in speed if you
-- Case-liberation for -O2. This should be after
-- strictness analysis and the simplification which follows it.
+ case rule_check of { Just pat -> CoreDoRuleCheck 0 pat; Nothing -> CoreDoNothing },
+
if opt_level >= 2 then
CoreLiberateCase
else
CoreDoNothing,
-- Final clean-up simplification:
- CoreDoSimplify (isAmongSimpl [
+ CoreDoSimplify (SimplPhase 0) [
MaxSimplifierIterations max_iter
- -- No -finline-phase: allow all Ids to be inlined now
- ])
+ ]
]
buildStgToDo :: IO [ StgToDo ]
addToDirList :: IORef [String] -> String -> IO ()
addToDirList ref path
- = do paths <- readIORef ref
- writeIORef ref (paths ++ split split_marker path)
+ = do paths <- readIORef ref
+ shiny_new_ones <- splitUp path
+ writeIORef ref (paths ++ shiny_new_ones)
+
+ where
+ splitUp ::String -> IO [String]
+#ifdef mingw32_TARGET_OS
+ -- 'hybrid' support for DOS-style paths in directory lists.
+ --
+ -- That is, if "foo:bar:baz" is used, this interpreted as
+ -- consisting of three entries, 'foo', 'bar', 'baz'.
+ -- However, with "c:/foo:c:\\foo;x:/bar", this is interpreted
+ -- as four elts, "c:/foo", "c:\\foo", "x", and "/bar" --
+ -- *provided* c:/foo exists and x:/bar doesn't.
+ --
+ -- Notice that no attempt is made to fully replace the 'standard'
+ -- split marker ':' with the Windows / DOS one, ';'. The reason being
+ -- that this will cause too much breakage for users & ':' will
+ -- work fine even with DOS paths, if you're not insisting on being silly.
+ -- So, use either.
+ splitUp [] = return []
+ splitUp (x:':':div:xs)
+ | div `elem` dir_markers = do
+ let (p,rs) = findNextPath xs
+ ps <- splitUp rs
+ {-
+ Consult the file system to check the interpretation
+ of (x:':':div:p) -- this is arguably excessive, we
+ could skip this test & just say that it is a valid
+ dir path.
+ -}
+ flg <- doesDirectoryExist (x:':':div:p)
+ if flg then
+ return ((x:':':div:p):ps)
+ else
+ return ([x]:(div:p):ps)
+ splitUp xs = do
+ let (p,rs) = findNextPath xs
+ ps <- splitUp rs
+ return (cons p ps)
+
+ cons "" xs = xs
+ cons x xs = x:xs
+
+ -- will be called either when we've consumed nought or the "<Drive>:/" part of
+ -- a DOS path, so splitting is just a Q of finding the next split marker.
+ findNextPath xs =
+ case break (`elem` split_markers) xs of
+ (p, d:ds) -> (p, ds)
+ (p, xs) -> (p, xs)
+
+ split_markers :: [Char]
+ split_markers = [':', ';']
+
+ dir_markers :: [Char]
+ dir_markers = ['/', '\\']
+
+#else
+ splitUp xs = return (split split_marker xs)
+#endif
GLOBAL_VAR(v_HCHeader, "", String)
-----------------------------------------------------------------------------
-- Packages
-GLOBAL_VAR(v_Path_package_config, error "path_package_config", String)
-
-- package list is maintained in dependency order
GLOBAL_VAR(v_Packages, ("std":"rts":"gmp":[]), [String])
+readPackageConf :: String -> IO ()
+readPackageConf conf_file = do
+ proto_pkg_details <- loadPackageConfig conf_file
+ top_dir <- getTopDir
+ let pkg_details = mungePackagePaths top_dir proto_pkg_details
+ old_pkg_details <- readIORef v_Package_details
+ let intersection = filter (`elem` map name old_pkg_details)
+ (map name pkg_details)
+ if (not (null intersection))
+ then throwDyn (InstallationError ("package `" ++ head intersection ++ "' is already defined"))
+ else do
+ writeIORef v_Package_details (pkg_details ++ old_pkg_details)
+
addPackage :: String -> IO ()
addPackage package
= do pkg_details <- readIORef v_Package_details
getPackageImportPath :: IO [String]
getPackageImportPath = do
ps <- getPackageInfo
- return (nub (concat (map import_dirs ps)))
+ return (nub (filter (not.null) (concatMap import_dirs ps)))
getPackageIncludePath :: IO [String]
getPackageIncludePath = do
getPackageLibraryPath :: IO [String]
getPackageLibraryPath = do
ps <- getPackageInfo
- return (nub (concat (map library_dirs ps)))
+ return (nub (filter (not.null) (concatMap library_dirs ps)))
getPackageLibraries :: IO [String]
getPackageLibraries = do
tag <- readIORef v_Build_tag
let suffix = if null tag then "" else '_':tag
return (concat (
- map (\p -> map (++suffix) (hs_libraries p) ++ extra_libraries p) ps
+ map (\p -> map (++suffix) (hACK (hs_libraries p)) ++ extra_libraries p) ps
))
+ where
+ -- This is a totally horrible (temporary) hack, for Win32. Problem is
+ -- that package.conf for Win32 says that the main prelude lib is
+ -- split into HSstd1 and HSstd2, which is needed due to limitations in
+ -- the PEi386 file format, to make GHCi work. However, we still only
+ -- have HSstd.a for static linking, not HSstd1.a and HSstd2.a.
+ -- getPackageLibraries is called to find the .a's to add to the static
+ -- link line. On Win32, this hACK detects HSstd1 and HSstd2 and
+ -- replaces them with HSstd, so static linking still works.
+ -- Libraries needed for dynamic (GHCi) linking are discovered via
+ -- different route (in InteractiveUI.linkPackage).
+ -- See driver/PackageSrc.hs for the HSstd1/HSstd2 split definition.
+ -- THIS IS A STRICTLY TEMPORARY HACK (famous last words ...)
+ -- JRS 04 Sept 01: Same appalling hack for HSwin32[1,2]
+ hACK libs
+# ifndef mingw32_TARGET_OS
+ = libs
+# else
+ = if "HSstd1" `elem` libs && "HSstd2" `elem` libs
+ then "HSstd" : filter ((/= "HSstd").(take 5)) libs
+ else
+ if "HSwin321" `elem` libs && "HSwin322" `elem` libs
+ then "HSwin32" : filter ((/= "HSwin32").(take 7)) libs
+ else
+ libs
+# endif
getPackageExtraGhcOpts :: IO [String]
getPackageExtraGhcOpts = do
pkg_details <- readIORef v_Package_details
return [ pkg | p <- ps, Just pkg <- [ lookupPkg p pkg_details ] ]
-GLOBAL_VAR(v_Package_details, (error "package_details"), [PackageConfig])
+GLOBAL_VAR(v_Package_details, [], [PackageConfig])
lookupPkg :: String -> [PackageConfig] -> Maybe PackageConfig
lookupPkg nm ps
= case [p | p <- ps, name p == nm] of
[] -> Nothing
(p:_) -> Just p
+
-----------------------------------------------------------------------------
-- Ways
findBuildTag = do
way_names <- readIORef v_Ways
case sort way_names of
- [] -> do writeIORef v_Build_tag ""
+ [] -> do -- writeIORef v_Build_tag ""
return []
[w] -> do let details = lkupWay w
, "-fvia-C" ]
-----------------------------------------------------------------------------
--- Programs for particular phases
-
-GLOBAL_VAR(v_Pgm_L, error "pgm_L", String)
-GLOBAL_VAR(v_Pgm_P, cRAWCPP, String)
-GLOBAL_VAR(v_Pgm_c, cGCC, String)
-GLOBAL_VAR(v_Pgm_m, error "pgm_m", String)
-GLOBAL_VAR(v_Pgm_s, error "pgm_s", String)
-GLOBAL_VAR(v_Pgm_a, cGCC, String)
-GLOBAL_VAR(v_Pgm_l, cGCC, String)
-GLOBAL_VAR(v_Pgm_dll, cMkDLL, String)
+-- Options for particular phases
GLOBAL_VAR(v_Opt_dep, [], [String])
GLOBAL_VAR(v_Anti_opt_C, [], [String])