[project @ 2003-06-23 10:35:15 by simonpj]
[ghc-hetmet.git] / ghc / compiler / main / DriverState.hs
index 109146f..93ac6b7 100644 (file)
@@ -1,5 +1,5 @@
 -----------------------------------------------------------------------------
--- $Id: DriverState.hs,v 1.72 2002/03/15 13:57:31 simonmar Exp $
+-- $Id: DriverState.hs,v 1.92 2003/06/23 10:35:17 simonpj Exp $
 --
 -- Settings for the driver
 --
@@ -12,22 +12,25 @@ module DriverState where
 #include "../includes/config.h"
 #include "HsVersions.h"
 
-import SysTools                ( getTopDir )
 import ParsePkgConf    ( loadPackageConfig )
-import Packages                ( PackageConfig(..), mungePackagePaths )
+import SysTools                ( getTopDir )
+import Packages
 import CmdLineOpts
 import DriverPhases
 import DriverUtil
+import UniqFM          ( eltsUFM )
 import Util
 import Config
-import Exception
-import IOExts
 import Panic
 
+import DATA_IOREF      ( IORef, readIORef, writeIORef )
+import EXCEPTION
+
 import List
 import Char  
 import Monad
-import Directory ( doesDirectoryExist )
+import Maybe           ( fromJust, isJust )
+import Directory       ( doesDirectoryExist )
 
 -----------------------------------------------------------------------------
 -- non-configured things
@@ -44,7 +47,7 @@ data GhcMode
   | DoMake                             -- ghc --make
   | DoInteractive                      -- ghc --interactive
   | DoLink                             -- [ the default ]
-  deriving (Eq)
+  deriving (Eq,Show)
 
 GLOBAL_VAR(v_GhcMode,     DoLink, GhcMode)
 GLOBAL_VAR(v_GhcModeFlag, "",     String)
@@ -53,7 +56,7 @@ setMode :: GhcMode -> String -> IO ()
 setMode m flag = do
   old_mode <- readIORef v_GhcMode
   old_flag <- readIORef v_GhcModeFlag
-  when (not (null (old_flag))) $
+  when (notNull old_flag && flag /= old_flag) $
       throwDyn (UsageError 
           ("cannot use `" ++ old_flag ++ "' with `" ++ flag ++ "'"))
   writeIORef v_GhcMode m
@@ -90,7 +93,10 @@ GLOBAL_VAR(v_Keep_ilx_files,         False,          Bool)
 -- Misc
 GLOBAL_VAR(v_Scale_sizes_by,           1.0,            Double)
 GLOBAL_VAR(v_Static,                   True,           Bool)
+GLOBAL_VAR(v_NoLink,                   False,          Bool)
 GLOBAL_VAR(v_NoHsMain,                         False,          Bool)
+GLOBAL_VAR(v_MainModIs,                        Nothing,        Maybe String)
+GLOBAL_VAR(v_MainFunIs,                        Nothing,        Maybe String)
 GLOBAL_VAR(v_Recomp,                   True,           Bool)
 GLOBAL_VAR(v_Collect_ghc_timing,       False,          Bool)
 GLOBAL_VAR(v_Do_asm_mangling,          True,           Bool)
@@ -125,7 +131,37 @@ GLOBAL_VAR(v_Output_dir,  Nothing, Maybe String)
 GLOBAL_VAR(v_Output_file, Nothing, Maybe String)
 GLOBAL_VAR(v_Output_hi,   Nothing, Maybe String)
 
-GLOBAL_VAR(v_Object_suf,  Nothing, Maybe String)
+-- called to verify that the output files & directories
+-- point somewhere valid. 
+--
+-- The assumption is that the directory portion of these output
+-- options will have to exist by the time 'verifyOutputFiles'
+-- is invoked.
+-- 
+verifyOutputFiles :: IO ()
+verifyOutputFiles = do
+  odir <- readIORef v_Output_dir
+  when (isJust odir) $ do
+     let dir = fromJust odir
+     flg <- doesDirectoryExist dir
+     when (not flg) (nonExistentDir "-odir" dir)
+  ofile <- readIORef v_Output_file
+  when (isJust ofile) $ do
+     let fn = fromJust ofile
+     flg <- doesDirNameExist fn
+     when (not flg) (nonExistentDir "-o" fn)
+  ohi <- readIORef v_Output_hi
+  when (isJust ohi) $ do
+     let hi = fromJust ohi
+     flg <- doesDirNameExist hi
+     when (not flg) (nonExistentDir "-ohi" hi)
+ where
+   nonExistentDir flg dir = 
+     throwDyn (CmdLineError ("error: directory portion of " ++ 
+                             show dir ++ " does not exist (used with " ++ 
+                            show flg ++ " option.)"))
+
+GLOBAL_VAR(v_Object_suf,  phaseInputExt Ln, String)
 GLOBAL_VAR(v_HC_suf,     Nothing, Maybe String)
 GLOBAL_VAR(v_Hi_dir,      Nothing, Maybe String)
 GLOBAL_VAR(v_Hi_suf,      "hi",           String)
@@ -137,14 +173,12 @@ odir_ify f = do
   odir_opt <- readIORef v_Output_dir
   case odir_opt of
        Nothing -> return f
-       Just d  -> return (newdir d f)
+       Just d  -> return (replaceFilenameDirectory f d)
 
 osuf_ify :: String -> IO String
 osuf_ify f = do
-  osuf_opt <- readIORef v_Object_suf
-  case osuf_opt of
-       Nothing -> return f
-       Just s  -> return (newsuf s f)
+  osuf <- readIORef v_Object_suf
+  return (replaceFilenameSuffix f osuf)
 
 -----------------------------------------------------------------------------
 -- Compiler optimisation options
@@ -159,11 +193,7 @@ setOptLevel n = do
 GLOBAL_VAR(v_minus_o2_for_C,            False, Bool)
 GLOBAL_VAR(v_MaxSimplifierIterations,   4,     Int)
 GLOBAL_VAR(v_StgStats,                  False, Bool)
-GLOBAL_VAR(v_UsageSPInf,               False, Bool)  -- Off by default
 GLOBAL_VAR(v_Strictness,               True,  Bool)
-#ifdef OLD_STRICTNESS
-GLOBAL_VAR(v_CPR,                      True,  Bool)
-#endif
 GLOBAL_VAR(v_CSE,                      True,  Bool)
 GLOBAL_VAR(v_RuleCheck,                Nothing,  Maybe String)
 
@@ -201,11 +231,7 @@ buildCoreToDo :: IO [CoreToDo]
 buildCoreToDo = do
    opt_level  <- readIORef v_OptLevel
    max_iter   <- readIORef v_MaxSimplifierIterations
-   usageSP    <- readIORef v_UsageSPInf
    strictness <- readIORef v_Strictness
-#ifdef OLD_STRICTNESS
-   cpr        <- readIORef v_CPR
-#endif
    cse        <- readIORef v_CSE
    rule_check <- readIORef v_RuleCheck
 
@@ -252,10 +278,6 @@ buildCoreToDo = do
        ],
        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 (SimplPhase 1) [
                -- Need inline-phase2 here so that build/augment get 
                -- inlined.  I found that spectral/hartel/genfft lost some useful
@@ -282,7 +304,7 @@ buildCoreToDo = do
        case rule_check of { Just pat -> CoreDoRuleCheck 0 pat; Nothing -> CoreDoNothing },
 
 #ifdef OLD_STRICTNESS
-       if cpr        then CoreDoCPResult   else CoreDoNothing,
+       CoreDoOldStrictness
 #endif
        if strictness then CoreDoStrictness else CoreDoNothing,
        CoreDoWorkerWrapper,
@@ -352,13 +374,16 @@ GLOBAL_VAR(v_Import_paths,  ["."], [String])
 GLOBAL_VAR(v_Include_paths, ["."], [String])
 GLOBAL_VAR(v_Library_paths, [],         [String])
 
-GLOBAL_VAR(v_Cmdline_libraries,   [], [String])
+#ifdef darwin_TARGET_OS
+GLOBAL_VAR(v_Framework_paths, [], [String])
+GLOBAL_VAR(v_Cmdline_frameworks, [], [String])
+#endif
 
 addToDirList :: IORef [String] -> String -> IO ()
 addToDirList ref path
   = do paths           <- readIORef ref
        shiny_new_ones  <- splitUp path
-       writeIORef ref (paths ++ filter (not.null) shiny_new_ones)
+       writeIORef ref (paths ++ filter notNull shiny_new_ones)
                -- empty paths are ignored: there might be a trailing
                -- ':' in the initial list, for example.  Empty paths can
                -- cause confusion when they are translated into -I options
@@ -420,128 +445,186 @@ addToDirList ref path
     splitUp xs = return (split split_marker xs)
 #endif
 
-GLOBAL_VAR(v_HCHeader, "", String)
-
------------------------------------------------------------------------------
--- Packages
-
--- package list is maintained in dependency order
-GLOBAL_VAR(v_Packages, ("haskell98":"base":"rts":[]), [String])
+-- ----------------------------------------------------------------------------
+-- Loading the package config file
 
 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
+  proto_pkg_configs <- loadPackageConfig conf_file
+  top_dir          <- getTopDir
+  let pkg_configs = mungePackagePaths top_dir proto_pkg_configs
+  extendPackageConfigMap pkg_configs
+
+mungePackagePaths :: String -> [PackageConfig] -> [PackageConfig]
+-- Replace the string "$libdir" at the beginning of a path
+-- with the current libdir (obtained from the -B option).
+mungePackagePaths top_dir ps = map munge_pkg ps
+ where 
+  munge_pkg p = p{ import_dirs  = munge_paths (import_dirs p),
+                  include_dirs = munge_paths (include_dirs p),
+                  library_dirs = munge_paths (library_dirs p),
+                  framework_dirs = munge_paths (framework_dirs p) }
+
+  munge_paths = map munge_path
+
+  munge_path p 
+         | Just p' <- my_prefix_match "$libdir" p = top_dir ++ p'
+         | otherwise                              = p
+
 
-  let -- new package override old ones
-      new_pkg_names = map name pkg_details
-      filtered_old_pkg_details = 
-        filter (\p -> name p `notElem` new_pkg_names) old_pkg_details
+-- -----------------------------------------------------------------------------
+-- The list of packages requested on the command line
 
-  writeIORef v_Package_details (pkg_details ++ filtered_old_pkg_details)
+-- The package list reflects what packages were given as command-line options,
+-- plus their dependent packages.  It is maintained in dependency order;
+-- earlier packages may depend on later ones, but not vice versa
+GLOBAL_VAR(v_ExplicitPackages, initPackageList, [PackageName])
 
+initPackageList = [basePackage, rtsPackage]
+       -- basePackage is part of this list entirely because of 
+       -- wired-in names in GHCi.  See the notes on wired-in names in
+       -- Linker.linkExpr.  By putting the base backage in initPackageList
+       -- we make sure that it'll always by linked.
+
+
+-- add a package requested from the command-line
 addPackage :: String -> IO ()
-addPackage package
-  = do pkg_details <- readIORef v_Package_details
-       case lookupPkg package pkg_details of
-         Nothing -> throwDyn (CmdLineError ("unknown package name: " ++ package))
-         Just details -> do
-           ps <- readIORef v_Packages
-           unless (package `elem` ps) $ do
-               mapM_ addPackage (package_deps details)
-               ps <- readIORef v_Packages
-               writeIORef v_Packages (package:ps)
-
-getPackageImportPath   :: IO [String]
+addPackage package = do
+  pkg_details <- getPackageConfigMap
+  ps  <- readIORef v_ExplicitPackages
+  ps' <- add_package pkg_details ps (mkPackageName package)
+               -- Throws an exception if it fails
+  writeIORef v_ExplicitPackages ps'
+
+-- internal helper
+add_package :: PackageConfigMap -> [PackageName]
+           -> PackageName -> IO [PackageName]
+add_package pkg_details ps p   
+  | p `elem` ps        -- Check if we've already added this package
+  = return ps
+  | Just details <- lookupPkg pkg_details p
+  -- Add the package's dependents also
+  = do ps' <- foldM (add_package pkg_details) ps (packageDependents details)
+       return (p : ps')
+  | otherwise
+  = throwDyn (CmdLineError ("unknown package name: " ++ packageNameString p))
+
+
+-- -----------------------------------------------------------------------------
+-- Extracting information from the packages in scope
+
+-- Many of these functions take a list of packages: in those cases,
+-- the list is expected to contain the "dependent packages",
+-- i.e. those packages that were found to be depended on by the
+-- current module/program.  These can be auto or non-auto packages, it
+-- doesn't really matter.  The list is always combined with the list
+-- of explicit (command-line) packages to determine which packages to
+-- use.
+
+getPackageImportPath :: IO [String]
 getPackageImportPath = do
-  ps <- getPackageInfo
-  return (nub (filter (not.null) (concatMap import_dirs ps)))
+  ps <- getExplicitAndAutoPackageConfigs
+                 -- import dirs are always derived from the 'auto' 
+                 -- packages as well as the explicit ones
+  return (nub (filter notNull (concatMap import_dirs ps)))
 
-getPackageIncludePath   :: IO [String]
-getPackageIncludePath = do
-  ps <- getPackageInfo
-  return (nub (filter (not.null) (concatMap include_dirs ps)))
+getPackageIncludePath :: [PackageName] -> IO [String]
+getPackageIncludePath pkgs = do
+  ps <- getExplicitPackagesAnd pkgs
+  return (nub (filter notNull (concatMap include_dirs ps)))
 
        -- includes are in reverse dependency order (i.e. rts first)
-getPackageCIncludes   :: IO [String]
-getPackageCIncludes = do
-  ps <- getPackageInfo
-  return (reverse (nub (filter (not.null) (concatMap c_includes ps))))
-
-getPackageLibraryPath  :: IO [String]
-getPackageLibraryPath = do
-  ps <- getPackageInfo
-  return (nub (filter (not.null) (concatMap library_dirs ps)))
-
-getPackageLibraries    :: IO [String]
-getPackageLibraries = do
-  ps <- getPackageInfo
+getPackageCIncludes :: [PackageConfig] -> IO [String]
+getPackageCIncludes pkg_configs = do
+  return (reverse (nub (filter notNull (concatMap c_includes pkg_configs))))
+
+getPackageLibraryPath :: [PackageName] -> IO [String]
+getPackageLibraryPath pkgs = do 
+  ps <- getExplicitPackagesAnd pkgs
+  return (nub (filter notNull (concatMap library_dirs ps)))
+
+getPackageLinkOpts :: [PackageName] -> IO [String]
+getPackageLinkOpts pkgs = do
+  ps <- getExplicitPackagesAnd pkgs
   tag <- readIORef v_Build_tag
-  let suffix = if null tag then "" else '_':tag
-  return (concat (
-       map (\p -> map (++suffix) (hACK (hs_libraries p)) ++ extra_libraries p) ps
-     ))
+  static <- readIORef v_Static
+  let 
+       imp        = if static then "" else "_imp"
+       suffix     = if null tag then "" else '_':tag
+       libs p     = map (++suffix) (hACK (hs_libraries p)) ++ extra_libraries p
+       imp_libs p = map (++imp) (libs p)
+       all_opts p = map ("-l" ++) (imp_libs p) ++ extra_ld_opts p
+
+  return (concat (map all_opts 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 HSbase1 and HSbase2, which is needed due to limitations in
-     -- the PEi386 file format, to make GHCi work.  However, we still only
-     -- have HSbase.a for static linking, not HSbase1.a and HSbase2.a.  
+     -- split into HSbase1, HSbase2 and HSbase3, which is needed due to a bug
+     -- in the GNU linker (PEi386 backend). However, we still only
+     -- have HSbase.a for static linking, not HSbase{1,2,3}.a
      -- getPackageLibraries is called to find the .a's to add to the static
-     -- link line.  On Win32, this hACK detects HSbase1 and HSbase2 and 
+     -- link line.  On Win32, this hACK detects HSbase{1,2,3} and 
      -- replaces them with HSbase, 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 HSbase1/HSbase2 split definition.
      -- THIS IS A STRICTLY TEMPORARY HACK (famous last words ...)
      -- JRS 04 Sept 01: Same appalling hack for HSwin32[1,2]
+     -- KAA 29 Mar  02: Same appalling hack for HSobjectio[1,2,3,4]
      hACK libs
-#      ifndef mingw32_TARGET_OS
+#      if !defined(mingw32_TARGET_OS) && !defined(cygwin32_TARGET_OS)
        = libs
 #      else
-       = if   "HSbase1" `elem` libs && "HSbase2" `elem` libs
+       = if   "HSbase1" `elem` libs && "HSbase2" `elem` libs && "HSbase3" `elem` libs
          then "HSbase" : filter (not.(isPrefixOf "HSbase")) libs
          else
          if   "HSwin321" `elem` libs && "HSwin322" `elem` libs
          then "HSwin32" : filter (not.(isPrefixOf "HSwin32")) libs
          else 
+         if   "HSobjectio1" `elem` libs && "HSobjectio2" `elem` libs && "HSobjectio3" `elem` libs && "HSobjectio4" `elem` libs
+        then "HSobjectio" : filter (not.(isPrefixOf "HSobjectio")) libs
+         else 
          libs
 #      endif
 
 getPackageExtraGhcOpts :: IO [String]
 getPackageExtraGhcOpts = do
-  ps <- getPackageInfo
+  ps <- getExplicitAndAutoPackageConfigs
   return (concatMap extra_ghc_opts ps)
 
-getPackageExtraCcOpts  :: IO [String]
-getPackageExtraCcOpts = do
-  ps <- getPackageInfo
+getPackageExtraCcOpts :: [PackageName] -> IO [String]
+getPackageExtraCcOpts pkgs = do
+  ps <- getExplicitPackagesAnd pkgs
   return (concatMap extra_cc_opts ps)
 
-getPackageExtraLdOpts  :: IO [String]
-getPackageExtraLdOpts = do
-  ps <- getPackageInfo
-  return (concatMap extra_ld_opts ps)
+#ifdef darwin_TARGET_OS
+getPackageFrameworkPath  :: [PackageName] -> IO [String]
+getPackageFrameworkPath pkgs = do
+  ps <- getExplicitPackagesAnd pkgs
+  return (nub (filter notNull (concatMap framework_dirs ps)))
 
-getPackageInfo :: IO [PackageConfig]
-getPackageInfo = do
-  ps <- readIORef v_Packages
-  getPackageDetails ps
-
-getPackageDetails :: [String] -> IO [PackageConfig]
-getPackageDetails ps = do
-  pkg_details <- readIORef v_Package_details
-  return [ pkg | p <- ps, Just pkg <- [ lookupPkg p pkg_details ] ]
-
-GLOBAL_VAR(v_Package_details, [], [PackageConfig])
+getPackageFrameworks  :: [PackageName] -> IO [String]
+getPackageFrameworks pkgs = do
+  ps <- getExplicitPackagesAnd pkgs
+  return (concatMap extra_frameworks ps)
+#endif
 
-lookupPkg :: String -> [PackageConfig] -> Maybe PackageConfig
-lookupPkg nm ps
-   = case [p | p <- ps, name p == nm] of
-        []    -> Nothing
-        (p:_) -> Just p
+-- -----------------------------------------------------------------------------
+-- Package Utils
+
+getExplicitPackagesAnd :: [PackageName] -> IO [PackageConfig]
+getExplicitPackagesAnd pkg_names = do
+  pkg_map <- getPackageConfigMap
+  expl <- readIORef v_ExplicitPackages
+  all_pkgs <- foldM (add_package pkg_map) expl pkg_names
+  getPackageDetails all_pkgs
+
+-- return all packages, including both the auto packages and the explicit ones
+getExplicitAndAutoPackageConfigs :: IO [PackageConfig]
+getExplicitAndAutoPackageConfigs = do
+  pkg_map <- getPackageConfigMap
+  let auto_packages = [ mkPackageName (name p) | p <- eltsUFM pkg_map, auto p ]
+  getExplicitPackagesAnd auto_packages
 
 -----------------------------------------------------------------------------
 -- Ways