| 1 | {-# OPTIONS -fno-warn-incomplete-patterns -optc-DNON_POSIX_SOURCE #-} |
|---|
| 2 | |
|---|
| 3 | ----------------------------------------------------------------------------- |
|---|
| 4 | -- |
|---|
| 5 | -- GHC Driver program |
|---|
| 6 | -- |
|---|
| 7 | -- (c) The University of Glasgow 2005 |
|---|
| 8 | -- |
|---|
| 9 | ----------------------------------------------------------------------------- |
|---|
| 10 | |
|---|
| 11 | module Main (main) where |
|---|
| 12 | |
|---|
| 13 | -- The official GHC API |
|---|
| 14 | import qualified GHC |
|---|
| 15 | import GHC ( -- DynFlags(..), HscTarget(..), |
|---|
| 16 | -- GhcMode(..), GhcLink(..), |
|---|
| 17 | Ghc, GhcMonad(..), |
|---|
| 18 | LoadHowMuch(..) ) |
|---|
| 19 | import CmdLineParser |
|---|
| 20 | |
|---|
| 21 | -- Implementations of the various modes (--show-iface, mkdependHS. etc.) |
|---|
| 22 | import LoadIface ( showIface ) |
|---|
| 23 | import HscMain ( newHscEnv ) |
|---|
| 24 | import DriverPipeline ( oneShot, compileFile ) |
|---|
| 25 | import DriverMkDepend ( doMkDependHS ) |
|---|
| 26 | #ifdef GHCI |
|---|
| 27 | import InteractiveUI ( interactiveUI, ghciWelcomeMsg ) |
|---|
| 28 | #endif |
|---|
| 29 | |
|---|
| 30 | |
|---|
| 31 | -- Various other random stuff that we need |
|---|
| 32 | import Config |
|---|
| 33 | import HscTypes |
|---|
| 34 | import Packages ( dumpPackages ) |
|---|
| 35 | import DriverPhases ( Phase(..), isSourceFilename, anyHsc, |
|---|
| 36 | startPhase, isHaskellSrcFilename ) |
|---|
| 37 | import BasicTypes ( failed ) |
|---|
| 38 | import StaticFlags |
|---|
| 39 | import StaticFlagParser |
|---|
| 40 | import DynFlags |
|---|
| 41 | import ErrUtils |
|---|
| 42 | import FastString |
|---|
| 43 | import Outputable |
|---|
| 44 | import SrcLoc |
|---|
| 45 | import Util |
|---|
| 46 | import Panic |
|---|
| 47 | import MonadUtils ( liftIO ) |
|---|
| 48 | |
|---|
| 49 | -- Imports for --abi-hash |
|---|
| 50 | import LoadIface ( loadUserInterface ) |
|---|
| 51 | import Module ( mkModuleName ) |
|---|
| 52 | import Finder ( findImportedModule, cannotFindInterface ) |
|---|
| 53 | import TcRnMonad ( initIfaceCheck ) |
|---|
| 54 | import Binary ( openBinMem, put_, fingerprintBinMem ) |
|---|
| 55 | |
|---|
| 56 | -- Standard Haskell libraries |
|---|
| 57 | import System.IO |
|---|
| 58 | import System.Environment |
|---|
| 59 | import System.Exit |
|---|
| 60 | import System.FilePath |
|---|
| 61 | import Control.Monad |
|---|
| 62 | import Data.Char |
|---|
| 63 | import Data.List |
|---|
| 64 | import Data.Maybe |
|---|
| 65 | |
|---|
| 66 | ----------------------------------------------------------------------------- |
|---|
| 67 | -- ToDo: |
|---|
| 68 | |
|---|
| 69 | -- time commands when run with -v |
|---|
| 70 | -- user ways |
|---|
| 71 | -- Win32 support: proper signal handling |
|---|
| 72 | -- reading the package configuration file is too slow |
|---|
| 73 | -- -K<size> |
|---|
| 74 | |
|---|
| 75 | ----------------------------------------------------------------------------- |
|---|
| 76 | -- GHC's command-line interface |
|---|
| 77 | |
|---|
| 78 | main :: IO () |
|---|
| 79 | main = do |
|---|
| 80 | hSetBuffering stdout NoBuffering |
|---|
| 81 | GHC.defaultErrorHandler defaultLogAction defaultFlushOut $ do |
|---|
| 82 | -- 1. extract the -B flag from the args |
|---|
| 83 | argv0 <- getArgs |
|---|
| 84 | |
|---|
| 85 | let (minusB_args, argv1) = partition ("-B" `isPrefixOf`) argv0 |
|---|
| 86 | mbMinusB | null minusB_args = Nothing |
|---|
| 87 | | otherwise = Just (drop 2 (last minusB_args)) |
|---|
| 88 | |
|---|
| 89 | let argv1' = map (mkGeneralLocated "on the commandline") argv1 |
|---|
| 90 | (argv2, staticFlagWarnings) <- parseStaticFlags argv1' |
|---|
| 91 | |
|---|
| 92 | -- 2. Parse the "mode" flags (--make, --interactive etc.) |
|---|
| 93 | (mode, argv3, modeFlagWarnings) <- parseModeFlags argv2 |
|---|
| 94 | |
|---|
| 95 | let flagWarnings = staticFlagWarnings ++ modeFlagWarnings |
|---|
| 96 | |
|---|
| 97 | -- If all we want to do is something like showing the version number |
|---|
| 98 | -- then do it now, before we start a GHC session etc. This makes |
|---|
| 99 | -- getting basic information much more resilient. |
|---|
| 100 | |
|---|
| 101 | -- In particular, if we wait until later before giving the version |
|---|
| 102 | -- number then bootstrapping gets confused, as it tries to find out |
|---|
| 103 | -- what version of GHC it's using before package.conf exists, so |
|---|
| 104 | -- starting the session fails. |
|---|
| 105 | case mode of |
|---|
| 106 | Left preStartupMode -> |
|---|
| 107 | do case preStartupMode of |
|---|
| 108 | ShowSupportedExtensions -> showSupportedExtensions |
|---|
| 109 | ShowVersion -> showVersion |
|---|
| 110 | ShowNumVersion -> putStrLn cProjectVersion |
|---|
| 111 | Print str -> putStrLn str |
|---|
| 112 | Right postStartupMode -> |
|---|
| 113 | -- start our GHC session |
|---|
| 114 | GHC.runGhc mbMinusB $ do |
|---|
| 115 | |
|---|
| 116 | dflags <- GHC.getSessionDynFlags |
|---|
| 117 | |
|---|
| 118 | case postStartupMode of |
|---|
| 119 | Left preLoadMode -> |
|---|
| 120 | liftIO $ do |
|---|
| 121 | case preLoadMode of |
|---|
| 122 | ShowInfo -> showInfo dflags |
|---|
| 123 | ShowGhcUsage -> showGhcUsage dflags |
|---|
| 124 | ShowGhciUsage -> showGhciUsage dflags |
|---|
| 125 | PrintWithDynFlags f -> putStrLn (f dflags) |
|---|
| 126 | Right postLoadMode -> |
|---|
| 127 | main' postLoadMode dflags argv3 flagWarnings |
|---|
| 128 | |
|---|
| 129 | main' :: PostLoadMode -> DynFlags -> [Located String] -> [Located String] |
|---|
| 130 | -> Ghc () |
|---|
| 131 | main' postLoadMode dflags0 args flagWarnings = do |
|---|
| 132 | -- set the default GhcMode, HscTarget and GhcLink. The HscTarget |
|---|
| 133 | -- can be further adjusted on a module by module basis, using only |
|---|
| 134 | -- the -fvia-C and -fasm flags. If the default HscTarget is not |
|---|
| 135 | -- HscC or HscAsm, -fvia-C and -fasm have no effect. |
|---|
| 136 | let dflt_target = hscTarget dflags0 |
|---|
| 137 | (mode, lang, link) |
|---|
| 138 | = case postLoadMode of |
|---|
| 139 | DoInteractive -> (CompManager, HscInterpreted, LinkInMemory) |
|---|
| 140 | DoEval _ -> (CompManager, HscInterpreted, LinkInMemory) |
|---|
| 141 | DoMake -> (CompManager, dflt_target, LinkBinary) |
|---|
| 142 | DoMkDependHS -> (MkDepend, dflt_target, LinkBinary) |
|---|
| 143 | DoAbiHash -> (OneShot, dflt_target, LinkBinary) |
|---|
| 144 | _ -> (OneShot, dflt_target, LinkBinary) |
|---|
| 145 | |
|---|
| 146 | let dflags1 = dflags0{ ghcMode = mode, |
|---|
| 147 | hscTarget = lang, |
|---|
| 148 | ghcLink = link, |
|---|
| 149 | -- leave out hscOutName for now |
|---|
| 150 | hscOutName = panic "Main.main:hscOutName not set", |
|---|
| 151 | verbosity = case postLoadMode of |
|---|
| 152 | DoEval _ -> 0 |
|---|
| 153 | _other -> 1 |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | -- turn on -fimplicit-import-qualified for GHCi now, so that it |
|---|
| 157 | -- can be overriden from the command-line |
|---|
| 158 | -- XXX: this should really be in the interactive DynFlags, but |
|---|
| 159 | -- we don't set that until later in interactiveUI |
|---|
| 160 | dflags1a | DoInteractive <- postLoadMode = imp_qual_enabled |
|---|
| 161 | | DoEval _ <- postLoadMode = imp_qual_enabled |
|---|
| 162 | | otherwise = dflags1 |
|---|
| 163 | where imp_qual_enabled = dflags1 `dopt_set` Opt_ImplicitImportQualified |
|---|
| 164 | |
|---|
| 165 | -- The rest of the arguments are "dynamic" |
|---|
| 166 | -- Leftover ones are presumably files |
|---|
| 167 | (dflags2, fileish_args, dynamicFlagWarnings) <- GHC.parseDynamicFlags dflags1a args |
|---|
| 168 | |
|---|
| 169 | let flagWarnings' = flagWarnings ++ dynamicFlagWarnings |
|---|
| 170 | |
|---|
| 171 | handleSourceError (\e -> do |
|---|
| 172 | GHC.printException e |
|---|
| 173 | liftIO $ exitWith (ExitFailure 1)) $ do |
|---|
| 174 | liftIO $ handleFlagWarnings dflags2 flagWarnings' |
|---|
| 175 | |
|---|
| 176 | -- make sure we clean up after ourselves |
|---|
| 177 | GHC.defaultCleanupHandler dflags2 $ do |
|---|
| 178 | |
|---|
| 179 | liftIO $ showBanner postLoadMode dflags2 |
|---|
| 180 | |
|---|
| 181 | -- we've finished manipulating the DynFlags, update the session |
|---|
| 182 | _ <- GHC.setSessionDynFlags dflags2 |
|---|
| 183 | dflags3 <- GHC.getSessionDynFlags |
|---|
| 184 | hsc_env <- GHC.getSession |
|---|
| 185 | |
|---|
| 186 | let |
|---|
| 187 | -- To simplify the handling of filepaths, we normalise all filepaths right |
|---|
| 188 | -- away - e.g., for win32 platforms, backslashes are converted |
|---|
| 189 | -- into forward slashes. |
|---|
| 190 | normal_fileish_paths = map (normalise . unLoc) fileish_args |
|---|
| 191 | (srcs, objs) = partition_args normal_fileish_paths [] [] |
|---|
| 192 | |
|---|
| 193 | -- Note: have v_Ld_inputs maintain the order in which 'objs' occurred on |
|---|
| 194 | -- the command-line. |
|---|
| 195 | liftIO $ mapM_ (consIORef v_Ld_inputs) (reverse objs) |
|---|
| 196 | |
|---|
| 197 | ---------------- Display configuration ----------- |
|---|
| 198 | when (verbosity dflags3 >= 4) $ |
|---|
| 199 | liftIO $ dumpPackages dflags3 |
|---|
| 200 | |
|---|
| 201 | when (verbosity dflags3 >= 3) $ do |
|---|
| 202 | liftIO $ hPutStrLn stderr ("Hsc static flags: " ++ unwords staticFlags) |
|---|
| 203 | |
|---|
| 204 | ---------------- Final sanity checking ----------- |
|---|
| 205 | liftIO $ checkOptions postLoadMode dflags3 srcs objs |
|---|
| 206 | |
|---|
| 207 | ---------------- Do the business ----------- |
|---|
| 208 | handleSourceError (\e -> do |
|---|
| 209 | GHC.printException e |
|---|
| 210 | liftIO $ exitWith (ExitFailure 1)) $ do |
|---|
| 211 | case postLoadMode of |
|---|
| 212 | ShowInterface f -> liftIO $ doShowIface dflags3 f |
|---|
| 213 | DoMake -> doMake srcs |
|---|
| 214 | DoMkDependHS -> doMkDependHS (map fst srcs) |
|---|
| 215 | StopBefore p -> liftIO (oneShot hsc_env p srcs) |
|---|
| 216 | DoInteractive -> interactiveUI srcs Nothing |
|---|
| 217 | DoEval exprs -> interactiveUI srcs $ Just $ reverse exprs |
|---|
| 218 | DoAbiHash -> abiHash srcs |
|---|
| 219 | |
|---|
| 220 | liftIO $ dumpFinalStats dflags3 |
|---|
| 221 | |
|---|
| 222 | #ifndef GHCI |
|---|
| 223 | interactiveUI :: b -> c -> Ghc () |
|---|
| 224 | interactiveUI _ _ = |
|---|
| 225 | ghcError (CmdLineError "not built for interactive use") |
|---|
| 226 | #endif |
|---|
| 227 | |
|---|
| 228 | -- ----------------------------------------------------------------------------- |
|---|
| 229 | -- Splitting arguments into source files and object files. This is where we |
|---|
| 230 | -- interpret the -x <suffix> option, and attach a (Maybe Phase) to each source |
|---|
| 231 | -- file indicating the phase specified by the -x option in force, if any. |
|---|
| 232 | |
|---|
| 233 | partition_args :: [String] -> [(String, Maybe Phase)] -> [String] |
|---|
| 234 | -> ([(String, Maybe Phase)], [String]) |
|---|
| 235 | partition_args [] srcs objs = (reverse srcs, reverse objs) |
|---|
| 236 | partition_args ("-x":suff:args) srcs objs |
|---|
| 237 | | "none" <- suff = partition_args args srcs objs |
|---|
| 238 | | StopLn <- phase = partition_args args srcs (slurp ++ objs) |
|---|
| 239 | | otherwise = partition_args rest (these_srcs ++ srcs) objs |
|---|
| 240 | where phase = startPhase suff |
|---|
| 241 | (slurp,rest) = break (== "-x") args |
|---|
| 242 | these_srcs = zip slurp (repeat (Just phase)) |
|---|
| 243 | partition_args (arg:args) srcs objs |
|---|
| 244 | | looks_like_an_input arg = partition_args args ((arg,Nothing):srcs) objs |
|---|
| 245 | | otherwise = partition_args args srcs (arg:objs) |
|---|
| 246 | |
|---|
| 247 | {- |
|---|
| 248 | We split out the object files (.o, .dll) and add them |
|---|
| 249 | to v_Ld_inputs for use by the linker. |
|---|
| 250 | |
|---|
| 251 | The following things should be considered compilation manager inputs: |
|---|
| 252 | |
|---|
| 253 | - haskell source files (strings ending in .hs, .lhs or other |
|---|
| 254 | haskellish extension), |
|---|
| 255 | |
|---|
| 256 | - module names (not forgetting hierarchical module names), |
|---|
| 257 | |
|---|
| 258 | - things beginning with '-' are flags that were not recognised by |
|---|
| 259 | the flag parser, and we want them to generate errors later in |
|---|
| 260 | checkOptions, so we class them as source files (#5921) |
|---|
| 261 | |
|---|
| 262 | - and finally we consider everything not containing a '.' to be |
|---|
| 263 | a comp manager input, as shorthand for a .hs or .lhs filename. |
|---|
| 264 | |
|---|
| 265 | Everything else is considered to be a linker object, and passed |
|---|
| 266 | straight through to the linker. |
|---|
| 267 | -} |
|---|
| 268 | looks_like_an_input :: String -> Bool |
|---|
| 269 | looks_like_an_input m = isSourceFilename m |
|---|
| 270 | || looksLikeModuleName m |
|---|
| 271 | || "-" `isPrefixOf` m |
|---|
| 272 | || '.' `notElem` m |
|---|
| 273 | |
|---|
| 274 | -- ----------------------------------------------------------------------------- |
|---|
| 275 | -- Option sanity checks |
|---|
| 276 | |
|---|
| 277 | -- | Ensure sanity of options. |
|---|
| 278 | -- |
|---|
| 279 | -- Throws 'UsageError' or 'CmdLineError' if not. |
|---|
| 280 | checkOptions :: PostLoadMode -> DynFlags -> [(String,Maybe Phase)] -> [String] -> IO () |
|---|
| 281 | -- Final sanity checking before kicking off a compilation (pipeline). |
|---|
| 282 | checkOptions mode dflags srcs objs = do |
|---|
| 283 | -- Complain about any unknown flags |
|---|
| 284 | let unknown_opts = [ f | (f@('-':_), _) <- srcs ] |
|---|
| 285 | when (notNull unknown_opts) (unknownFlagsErr unknown_opts) |
|---|
| 286 | |
|---|
| 287 | when (notNull (filter isRTSWay (wayNames dflags)) |
|---|
| 288 | && isInterpretiveMode mode) $ |
|---|
| 289 | hPutStrLn stderr ("Warning: -debug, -threaded and -ticky are ignored by GHCi") |
|---|
| 290 | |
|---|
| 291 | -- -prof and --interactive are not a good combination |
|---|
| 292 | when (notNull (filter (not . isRTSWay) (wayNames dflags)) |
|---|
| 293 | && isInterpretiveMode mode) $ |
|---|
| 294 | do ghcError (UsageError |
|---|
| 295 | "--interactive can't be used with -prof or -unreg.") |
|---|
| 296 | -- -ohi sanity check |
|---|
| 297 | if (isJust (outputHi dflags) && |
|---|
| 298 | (isCompManagerMode mode || srcs `lengthExceeds` 1)) |
|---|
| 299 | then ghcError (UsageError "-ohi can only be used when compiling a single source file") |
|---|
| 300 | else do |
|---|
| 301 | |
|---|
| 302 | -- -o sanity checking |
|---|
| 303 | if (srcs `lengthExceeds` 1 && isJust (outputFile dflags) |
|---|
| 304 | && not (isLinkMode mode)) |
|---|
| 305 | then ghcError (UsageError "can't apply -o to multiple source files") |
|---|
| 306 | else do |
|---|
| 307 | |
|---|
| 308 | let not_linking = not (isLinkMode mode) || isNoLink (ghcLink dflags) |
|---|
| 309 | |
|---|
| 310 | when (not_linking && not (null objs)) $ |
|---|
| 311 | hPutStrLn stderr ("Warning: the following files would be used as linker inputs, but linking is not being done: " ++ unwords objs) |
|---|
| 312 | |
|---|
| 313 | -- Check that there are some input files |
|---|
| 314 | -- (except in the interactive case) |
|---|
| 315 | if null srcs && (null objs || not_linking) && needsInputsMode mode |
|---|
| 316 | then ghcError (UsageError "no input files") |
|---|
| 317 | else do |
|---|
| 318 | |
|---|
| 319 | -- Verify that output files point somewhere sensible. |
|---|
| 320 | verifyOutputFiles dflags |
|---|
| 321 | |
|---|
| 322 | |
|---|
| 323 | -- Compiler output options |
|---|
| 324 | |
|---|
| 325 | -- called to verify that the output files & directories |
|---|
| 326 | -- point somewhere valid. |
|---|
| 327 | -- |
|---|
| 328 | -- The assumption is that the directory portion of these output |
|---|
| 329 | -- options will have to exist by the time 'verifyOutputFiles' |
|---|
| 330 | -- is invoked. |
|---|
| 331 | -- |
|---|
| 332 | verifyOutputFiles :: DynFlags -> IO () |
|---|
| 333 | verifyOutputFiles dflags = do |
|---|
| 334 | -- not -odir: we create the directory for -odir if it doesn't exist (#2278). |
|---|
| 335 | let ofile = outputFile dflags |
|---|
| 336 | when (isJust ofile) $ do |
|---|
| 337 | let fn = fromJust ofile |
|---|
| 338 | flg <- doesDirNameExist fn |
|---|
| 339 | when (not flg) (nonExistentDir "-o" fn) |
|---|
| 340 | let ohi = outputHi dflags |
|---|
| 341 | when (isJust ohi) $ do |
|---|
| 342 | let hi = fromJust ohi |
|---|
| 343 | flg <- doesDirNameExist hi |
|---|
| 344 | when (not flg) (nonExistentDir "-ohi" hi) |
|---|
| 345 | where |
|---|
| 346 | nonExistentDir flg dir = |
|---|
| 347 | ghcError (CmdLineError ("error: directory portion of " ++ |
|---|
| 348 | show dir ++ " does not exist (used with " ++ |
|---|
| 349 | show flg ++ " option.)")) |
|---|
| 350 | |
|---|
| 351 | ----------------------------------------------------------------------------- |
|---|
| 352 | -- GHC modes of operation |
|---|
| 353 | |
|---|
| 354 | type Mode = Either PreStartupMode PostStartupMode |
|---|
| 355 | type PostStartupMode = Either PreLoadMode PostLoadMode |
|---|
| 356 | |
|---|
| 357 | data PreStartupMode |
|---|
| 358 | = ShowVersion -- ghc -V/--version |
|---|
| 359 | | ShowNumVersion -- ghc --numeric-version |
|---|
| 360 | | ShowSupportedExtensions -- ghc --supported-extensions |
|---|
| 361 | | Print String -- ghc --print-foo |
|---|
| 362 | |
|---|
| 363 | showVersionMode, showNumVersionMode, showSupportedExtensionsMode :: Mode |
|---|
| 364 | showVersionMode = mkPreStartupMode ShowVersion |
|---|
| 365 | showNumVersionMode = mkPreStartupMode ShowNumVersion |
|---|
| 366 | showSupportedExtensionsMode = mkPreStartupMode ShowSupportedExtensions |
|---|
| 367 | |
|---|
| 368 | mkPreStartupMode :: PreStartupMode -> Mode |
|---|
| 369 | mkPreStartupMode = Left |
|---|
| 370 | |
|---|
| 371 | isShowVersionMode :: Mode -> Bool |
|---|
| 372 | isShowVersionMode (Left ShowVersion) = True |
|---|
| 373 | isShowVersionMode _ = False |
|---|
| 374 | |
|---|
| 375 | isShowNumVersionMode :: Mode -> Bool |
|---|
| 376 | isShowNumVersionMode (Left ShowNumVersion) = True |
|---|
| 377 | isShowNumVersionMode _ = False |
|---|
| 378 | |
|---|
| 379 | data PreLoadMode |
|---|
| 380 | = ShowGhcUsage -- ghc -? |
|---|
| 381 | | ShowGhciUsage -- ghci -? |
|---|
| 382 | | ShowInfo -- ghc --info |
|---|
| 383 | | PrintWithDynFlags (DynFlags -> String) -- ghc --print-foo |
|---|
| 384 | |
|---|
| 385 | showGhcUsageMode, showGhciUsageMode, showInfoMode :: Mode |
|---|
| 386 | showGhcUsageMode = mkPreLoadMode ShowGhcUsage |
|---|
| 387 | showGhciUsageMode = mkPreLoadMode ShowGhciUsage |
|---|
| 388 | showInfoMode = mkPreLoadMode ShowInfo |
|---|
| 389 | |
|---|
| 390 | printSetting :: String -> Mode |
|---|
| 391 | printSetting k = mkPreLoadMode (PrintWithDynFlags f) |
|---|
| 392 | where f dflags = fromMaybe (panic ("Setting not found: " ++ show k)) |
|---|
| 393 | $ lookup k (compilerInfo dflags) |
|---|
| 394 | |
|---|
| 395 | mkPreLoadMode :: PreLoadMode -> Mode |
|---|
| 396 | mkPreLoadMode = Right . Left |
|---|
| 397 | |
|---|
| 398 | isShowGhcUsageMode :: Mode -> Bool |
|---|
| 399 | isShowGhcUsageMode (Right (Left ShowGhcUsage)) = True |
|---|
| 400 | isShowGhcUsageMode _ = False |
|---|
| 401 | |
|---|
| 402 | isShowGhciUsageMode :: Mode -> Bool |
|---|
| 403 | isShowGhciUsageMode (Right (Left ShowGhciUsage)) = True |
|---|
| 404 | isShowGhciUsageMode _ = False |
|---|
| 405 | |
|---|
| 406 | data PostLoadMode |
|---|
| 407 | = ShowInterface FilePath -- ghc --show-iface |
|---|
| 408 | | DoMkDependHS -- ghc -M |
|---|
| 409 | | StopBefore Phase -- ghc -E | -C | -S |
|---|
| 410 | -- StopBefore StopLn is the default |
|---|
| 411 | | DoMake -- ghc --make |
|---|
| 412 | | DoInteractive -- ghc --interactive |
|---|
| 413 | | DoEval [String] -- ghc -e foo -e bar => DoEval ["bar", "foo"] |
|---|
| 414 | | DoAbiHash -- ghc --abi-hash |
|---|
| 415 | |
|---|
| 416 | doMkDependHSMode, doMakeMode, doInteractiveMode, doAbiHashMode :: Mode |
|---|
| 417 | doMkDependHSMode = mkPostLoadMode DoMkDependHS |
|---|
| 418 | doMakeMode = mkPostLoadMode DoMake |
|---|
| 419 | doInteractiveMode = mkPostLoadMode DoInteractive |
|---|
| 420 | doAbiHashMode = mkPostLoadMode DoAbiHash |
|---|
| 421 | |
|---|
| 422 | showInterfaceMode :: FilePath -> Mode |
|---|
| 423 | showInterfaceMode fp = mkPostLoadMode (ShowInterface fp) |
|---|
| 424 | |
|---|
| 425 | stopBeforeMode :: Phase -> Mode |
|---|
| 426 | stopBeforeMode phase = mkPostLoadMode (StopBefore phase) |
|---|
| 427 | |
|---|
| 428 | doEvalMode :: String -> Mode |
|---|
| 429 | doEvalMode str = mkPostLoadMode (DoEval [str]) |
|---|
| 430 | |
|---|
| 431 | mkPostLoadMode :: PostLoadMode -> Mode |
|---|
| 432 | mkPostLoadMode = Right . Right |
|---|
| 433 | |
|---|
| 434 | isDoInteractiveMode :: Mode -> Bool |
|---|
| 435 | isDoInteractiveMode (Right (Right DoInteractive)) = True |
|---|
| 436 | isDoInteractiveMode _ = False |
|---|
| 437 | |
|---|
| 438 | isStopLnMode :: Mode -> Bool |
|---|
| 439 | isStopLnMode (Right (Right (StopBefore StopLn))) = True |
|---|
| 440 | isStopLnMode _ = False |
|---|
| 441 | |
|---|
| 442 | isDoMakeMode :: Mode -> Bool |
|---|
| 443 | isDoMakeMode (Right (Right DoMake)) = True |
|---|
| 444 | isDoMakeMode _ = False |
|---|
| 445 | |
|---|
| 446 | #ifdef GHCI |
|---|
| 447 | isInteractiveMode :: PostLoadMode -> Bool |
|---|
| 448 | isInteractiveMode DoInteractive = True |
|---|
| 449 | isInteractiveMode _ = False |
|---|
| 450 | #endif |
|---|
| 451 | |
|---|
| 452 | -- isInterpretiveMode: byte-code compiler involved |
|---|
| 453 | isInterpretiveMode :: PostLoadMode -> Bool |
|---|
| 454 | isInterpretiveMode DoInteractive = True |
|---|
| 455 | isInterpretiveMode (DoEval _) = True |
|---|
| 456 | isInterpretiveMode _ = False |
|---|
| 457 | |
|---|
| 458 | needsInputsMode :: PostLoadMode -> Bool |
|---|
| 459 | needsInputsMode DoMkDependHS = True |
|---|
| 460 | needsInputsMode (StopBefore _) = True |
|---|
| 461 | needsInputsMode DoMake = True |
|---|
| 462 | needsInputsMode _ = False |
|---|
| 463 | |
|---|
| 464 | -- True if we are going to attempt to link in this mode. |
|---|
| 465 | -- (we might not actually link, depending on the GhcLink flag) |
|---|
| 466 | isLinkMode :: PostLoadMode -> Bool |
|---|
| 467 | isLinkMode (StopBefore StopLn) = True |
|---|
| 468 | isLinkMode DoMake = True |
|---|
| 469 | isLinkMode DoInteractive = True |
|---|
| 470 | isLinkMode (DoEval _) = True |
|---|
| 471 | isLinkMode _ = False |
|---|
| 472 | |
|---|
| 473 | isCompManagerMode :: PostLoadMode -> Bool |
|---|
| 474 | isCompManagerMode DoMake = True |
|---|
| 475 | isCompManagerMode DoInteractive = True |
|---|
| 476 | isCompManagerMode (DoEval _) = True |
|---|
| 477 | isCompManagerMode _ = False |
|---|
| 478 | |
|---|
| 479 | -- ----------------------------------------------------------------------------- |
|---|
| 480 | -- Parsing the mode flag |
|---|
| 481 | |
|---|
| 482 | parseModeFlags :: [Located String] |
|---|
| 483 | -> IO (Mode, |
|---|
| 484 | [Located String], |
|---|
| 485 | [Located String]) |
|---|
| 486 | parseModeFlags args = do |
|---|
| 487 | let ((leftover, errs1, warns), (mModeFlag, errs2, flags')) = |
|---|
| 488 | runCmdLine (processArgs mode_flags args) |
|---|
| 489 | (Nothing, [], []) |
|---|
| 490 | mode = case mModeFlag of |
|---|
| 491 | Nothing -> doMakeMode |
|---|
| 492 | Just (m, _) -> m |
|---|
| 493 | errs = errs1 ++ map (mkGeneralLocated "on the commandline") errs2 |
|---|
| 494 | when (not (null errs)) $ ghcError $ errorsToGhcException errs |
|---|
| 495 | return (mode, flags' ++ leftover, warns) |
|---|
| 496 | |
|---|
| 497 | type ModeM = CmdLineP (Maybe (Mode, String), [String], [Located String]) |
|---|
| 498 | -- mode flags sometimes give rise to new DynFlags (eg. -C, see below) |
|---|
| 499 | -- so we collect the new ones and return them. |
|---|
| 500 | |
|---|
| 501 | mode_flags :: [Flag ModeM] |
|---|
| 502 | mode_flags = |
|---|
| 503 | [ ------- help / version ---------------------------------------------- |
|---|
| 504 | Flag "?" (PassFlag (setMode showGhcUsageMode)) |
|---|
| 505 | , Flag "-help" (PassFlag (setMode showGhcUsageMode)) |
|---|
| 506 | , Flag "V" (PassFlag (setMode showVersionMode)) |
|---|
| 507 | , Flag "-version" (PassFlag (setMode showVersionMode)) |
|---|
| 508 | , Flag "-numeric-version" (PassFlag (setMode showNumVersionMode)) |
|---|
| 509 | , Flag "-info" (PassFlag (setMode showInfoMode)) |
|---|
| 510 | , Flag "-supported-languages" (PassFlag (setMode showSupportedExtensionsMode)) |
|---|
| 511 | , Flag "-supported-extensions" (PassFlag (setMode showSupportedExtensionsMode)) |
|---|
| 512 | ] ++ |
|---|
| 513 | [ Flag k' (PassFlag (setMode (printSetting k))) |
|---|
| 514 | | k <- ["Project version", |
|---|
| 515 | "Booter version", |
|---|
| 516 | "Stage", |
|---|
| 517 | "Build platform", |
|---|
| 518 | "Host platform", |
|---|
| 519 | "Target platform", |
|---|
| 520 | "Have interpreter", |
|---|
| 521 | "Object splitting supported", |
|---|
| 522 | "Have native code generator", |
|---|
| 523 | "Support SMP", |
|---|
| 524 | "Unregisterised", |
|---|
| 525 | "Tables next to code", |
|---|
| 526 | "RTS ways", |
|---|
| 527 | "Leading underscore", |
|---|
| 528 | "Debug on", |
|---|
| 529 | "LibDir", |
|---|
| 530 | "Global Package DB", |
|---|
| 531 | "C compiler flags", |
|---|
| 532 | "Gcc Linker flags", |
|---|
| 533 | "Ld Linker flags"], |
|---|
| 534 | let k' = "-print-" ++ map (replaceSpace . toLower) k |
|---|
| 535 | replaceSpace ' ' = '-' |
|---|
| 536 | replaceSpace c = c |
|---|
| 537 | ] ++ |
|---|
| 538 | ------- interfaces ---------------------------------------------------- |
|---|
| 539 | [ Flag "-show-iface" (HasArg (\f -> setMode (showInterfaceMode f) |
|---|
| 540 | "--show-iface")) |
|---|
| 541 | |
|---|
| 542 | ------- primary modes ------------------------------------------------ |
|---|
| 543 | , Flag "c" (PassFlag (\f -> do setMode (stopBeforeMode StopLn) f |
|---|
| 544 | addFlag "-no-link" f)) |
|---|
| 545 | , Flag "M" (PassFlag (setMode doMkDependHSMode)) |
|---|
| 546 | , Flag "E" (PassFlag (setMode (stopBeforeMode anyHsc))) |
|---|
| 547 | , Flag "C" (PassFlag setGenerateC) |
|---|
| 548 | , Flag "S" (PassFlag (setMode (stopBeforeMode As))) |
|---|
| 549 | , Flag "-make" (PassFlag (setMode doMakeMode)) |
|---|
| 550 | , Flag "-interactive" (PassFlag (setMode doInteractiveMode)) |
|---|
| 551 | , Flag "-abi-hash" (PassFlag (setMode doAbiHashMode)) |
|---|
| 552 | , Flag "e" (SepArg (\s -> setMode (doEvalMode s) "-e")) |
|---|
| 553 | ] |
|---|
| 554 | |
|---|
| 555 | setGenerateC :: String -> EwM ModeM () |
|---|
| 556 | setGenerateC f |
|---|
| 557 | | cGhcUnregisterised /= "YES" = do |
|---|
| 558 | addWarn ("Compiler not unregisterised, so ignoring " ++ f) |
|---|
| 559 | | otherwise = do |
|---|
| 560 | setMode (stopBeforeMode HCc) f |
|---|
| 561 | addFlag "-fvia-C" f |
|---|
| 562 | |
|---|
| 563 | setMode :: Mode -> String -> EwM ModeM () |
|---|
| 564 | setMode newMode newFlag = liftEwM $ do |
|---|
| 565 | (mModeFlag, errs, flags') <- getCmdLineState |
|---|
| 566 | let (modeFlag', errs') = |
|---|
| 567 | case mModeFlag of |
|---|
| 568 | Nothing -> ((newMode, newFlag), errs) |
|---|
| 569 | Just (oldMode, oldFlag) -> |
|---|
| 570 | case (oldMode, newMode) of |
|---|
| 571 | -- -c/--make are allowed together, and mean --make -no-link |
|---|
| 572 | _ | isStopLnMode oldMode && isDoMakeMode newMode |
|---|
| 573 | || isStopLnMode newMode && isDoMakeMode oldMode -> |
|---|
| 574 | ((doMakeMode, "--make"), []) |
|---|
| 575 | |
|---|
| 576 | -- If we have both --help and --interactive then we |
|---|
| 577 | -- want showGhciUsage |
|---|
| 578 | _ | isShowGhcUsageMode oldMode && |
|---|
| 579 | isDoInteractiveMode newMode -> |
|---|
| 580 | ((showGhciUsageMode, oldFlag), []) |
|---|
| 581 | | isShowGhcUsageMode newMode && |
|---|
| 582 | isDoInteractiveMode oldMode -> |
|---|
| 583 | ((showGhciUsageMode, newFlag), []) |
|---|
| 584 | -- Otherwise, --help/--version/--numeric-version always win |
|---|
| 585 | | isDominantFlag oldMode -> ((oldMode, oldFlag), []) |
|---|
| 586 | | isDominantFlag newMode -> ((newMode, newFlag), []) |
|---|
| 587 | -- We need to accumulate eval flags like "-e foo -e bar" |
|---|
| 588 | (Right (Right (DoEval esOld)), |
|---|
| 589 | Right (Right (DoEval [eNew]))) -> |
|---|
| 590 | ((Right (Right (DoEval (eNew : esOld))), oldFlag), |
|---|
| 591 | errs) |
|---|
| 592 | -- Saying e.g. --interactive --interactive is OK |
|---|
| 593 | _ | oldFlag == newFlag -> ((oldMode, oldFlag), errs) |
|---|
| 594 | -- Otherwise, complain |
|---|
| 595 | _ -> let err = flagMismatchErr oldFlag newFlag |
|---|
| 596 | in ((oldMode, oldFlag), err : errs) |
|---|
| 597 | putCmdLineState (Just modeFlag', errs', flags') |
|---|
| 598 | where isDominantFlag f = isShowGhcUsageMode f || |
|---|
| 599 | isShowGhciUsageMode f || |
|---|
| 600 | isShowVersionMode f || |
|---|
| 601 | isShowNumVersionMode f |
|---|
| 602 | |
|---|
| 603 | flagMismatchErr :: String -> String -> String |
|---|
| 604 | flagMismatchErr oldFlag newFlag |
|---|
| 605 | = "cannot use `" ++ oldFlag ++ "' with `" ++ newFlag ++ "'" |
|---|
| 606 | |
|---|
| 607 | addFlag :: String -> String -> EwM ModeM () |
|---|
| 608 | addFlag s flag = liftEwM $ do |
|---|
| 609 | (m, e, flags') <- getCmdLineState |
|---|
| 610 | putCmdLineState (m, e, mkGeneralLocated loc s : flags') |
|---|
| 611 | where loc = "addFlag by " ++ flag ++ " on the commandline" |
|---|
| 612 | |
|---|
| 613 | -- ---------------------------------------------------------------------------- |
|---|
| 614 | -- Run --make mode |
|---|
| 615 | |
|---|
| 616 | doMake :: [(String,Maybe Phase)] -> Ghc () |
|---|
| 617 | doMake srcs = do |
|---|
| 618 | let (hs_srcs, non_hs_srcs) = partition haskellish srcs |
|---|
| 619 | |
|---|
| 620 | haskellish (f,Nothing) = |
|---|
| 621 | looksLikeModuleName f || isHaskellSrcFilename f || '.' `notElem` f |
|---|
| 622 | haskellish (_,Just phase) = |
|---|
| 623 | phase `notElem` [As, Cc, Cobjc, Cobjcpp, CmmCpp, Cmm, StopLn] |
|---|
| 624 | |
|---|
| 625 | hsc_env <- GHC.getSession |
|---|
| 626 | |
|---|
| 627 | -- if we have no haskell sources from which to do a dependency |
|---|
| 628 | -- analysis, then just do one-shot compilation and/or linking. |
|---|
| 629 | -- This means that "ghc Foo.o Bar.o -o baz" links the program as |
|---|
| 630 | -- we expect. |
|---|
| 631 | if (null hs_srcs) |
|---|
| 632 | then liftIO (oneShot hsc_env StopLn srcs) |
|---|
| 633 | else do |
|---|
| 634 | |
|---|
| 635 | o_files <- mapM (\x -> liftIO $ compileFile hsc_env StopLn x) |
|---|
| 636 | non_hs_srcs |
|---|
| 637 | liftIO $ mapM_ (consIORef v_Ld_inputs) (reverse o_files) |
|---|
| 638 | |
|---|
| 639 | targets <- mapM (uncurry GHC.guessTarget) hs_srcs |
|---|
| 640 | GHC.setTargets targets |
|---|
| 641 | ok_flag <- GHC.load LoadAllTargets |
|---|
| 642 | |
|---|
| 643 | when (failed ok_flag) (liftIO $ exitWith (ExitFailure 1)) |
|---|
| 644 | return () |
|---|
| 645 | |
|---|
| 646 | |
|---|
| 647 | -- --------------------------------------------------------------------------- |
|---|
| 648 | -- --show-iface mode |
|---|
| 649 | |
|---|
| 650 | doShowIface :: DynFlags -> FilePath -> IO () |
|---|
| 651 | doShowIface dflags file = do |
|---|
| 652 | hsc_env <- newHscEnv dflags |
|---|
| 653 | showIface hsc_env file |
|---|
| 654 | |
|---|
| 655 | -- --------------------------------------------------------------------------- |
|---|
| 656 | -- Various banners and verbosity output. |
|---|
| 657 | |
|---|
| 658 | showBanner :: PostLoadMode -> DynFlags -> IO () |
|---|
| 659 | showBanner _postLoadMode dflags = do |
|---|
| 660 | let verb = verbosity dflags |
|---|
| 661 | |
|---|
| 662 | #ifdef GHCI |
|---|
| 663 | -- Show the GHCi banner |
|---|
| 664 | when (isInteractiveMode _postLoadMode && verb >= 1) $ putStrLn ghciWelcomeMsg |
|---|
| 665 | #endif |
|---|
| 666 | |
|---|
| 667 | -- Display details of the configuration in verbose mode |
|---|
| 668 | when (verb >= 2) $ |
|---|
| 669 | do hPutStr stderr "Glasgow Haskell Compiler, Version " |
|---|
| 670 | hPutStr stderr cProjectVersion |
|---|
| 671 | hPutStr stderr ", stage " |
|---|
| 672 | hPutStr stderr cStage |
|---|
| 673 | hPutStr stderr " booted by GHC version " |
|---|
| 674 | hPutStrLn stderr cBooterVersion |
|---|
| 675 | |
|---|
| 676 | -- We print out a Read-friendly string, but a prettier one than the |
|---|
| 677 | -- Show instance gives us |
|---|
| 678 | showInfo :: DynFlags -> IO () |
|---|
| 679 | showInfo dflags = do |
|---|
| 680 | let sq x = " [" ++ x ++ "\n ]" |
|---|
| 681 | putStrLn $ sq $ intercalate "\n ," $ map show $ compilerInfo dflags |
|---|
| 682 | |
|---|
| 683 | showSupportedExtensions :: IO () |
|---|
| 684 | showSupportedExtensions = mapM_ putStrLn supportedLanguagesAndExtensions |
|---|
| 685 | |
|---|
| 686 | showVersion :: IO () |
|---|
| 687 | showVersion = putStrLn (cProjectName ++ ", version " ++ cProjectVersion) |
|---|
| 688 | |
|---|
| 689 | showGhcUsage :: DynFlags -> IO () |
|---|
| 690 | showGhcUsage = showUsage False |
|---|
| 691 | |
|---|
| 692 | showGhciUsage :: DynFlags -> IO () |
|---|
| 693 | showGhciUsage = showUsage True |
|---|
| 694 | |
|---|
| 695 | showUsage :: Bool -> DynFlags -> IO () |
|---|
| 696 | showUsage ghci dflags = do |
|---|
| 697 | let usage_path = if ghci then ghciUsagePath dflags |
|---|
| 698 | else ghcUsagePath dflags |
|---|
| 699 | usage <- readFile usage_path |
|---|
| 700 | dump usage |
|---|
| 701 | where |
|---|
| 702 | dump "" = return () |
|---|
| 703 | dump ('$':'$':s) = putStr progName >> dump s |
|---|
| 704 | dump (c:s) = putChar c >> dump s |
|---|
| 705 | |
|---|
| 706 | dumpFinalStats :: DynFlags -> IO () |
|---|
| 707 | dumpFinalStats dflags = |
|---|
| 708 | when (dopt Opt_D_faststring_stats dflags) $ dumpFastStringStats dflags |
|---|
| 709 | |
|---|
| 710 | dumpFastStringStats :: DynFlags -> IO () |
|---|
| 711 | dumpFastStringStats dflags = do |
|---|
| 712 | buckets <- getFastStringTable |
|---|
| 713 | let (entries, longest, is_z, has_z) = countFS 0 0 0 0 buckets |
|---|
| 714 | msg = text "FastString stats:" $$ |
|---|
| 715 | nest 4 (vcat [text "size: " <+> int (length buckets), |
|---|
| 716 | text "entries: " <+> int entries, |
|---|
| 717 | text "longest chain: " <+> int longest, |
|---|
| 718 | text "z-encoded: " <+> (is_z `pcntOf` entries), |
|---|
| 719 | text "has z-encoding: " <+> (has_z `pcntOf` entries) |
|---|
| 720 | ]) |
|---|
| 721 | -- we usually get more "has z-encoding" than "z-encoded", because |
|---|
| 722 | -- when we z-encode a string it might hash to the exact same string, |
|---|
| 723 | -- which will is not counted as "z-encoded". Only strings whose |
|---|
| 724 | -- Z-encoding is different from the original string are counted in |
|---|
| 725 | -- the "z-encoded" total. |
|---|
| 726 | putMsg dflags msg |
|---|
| 727 | where |
|---|
| 728 | x `pcntOf` y = int ((x * 100) `quot` y) <> char '%' |
|---|
| 729 | |
|---|
| 730 | countFS :: Int -> Int -> Int -> Int -> [[FastString]] -> (Int, Int, Int, Int) |
|---|
| 731 | countFS entries longest is_z has_z [] = (entries, longest, is_z, has_z) |
|---|
| 732 | countFS entries longest is_z has_z (b:bs) = |
|---|
| 733 | let |
|---|
| 734 | len = length b |
|---|
| 735 | longest' = max len longest |
|---|
| 736 | entries' = entries + len |
|---|
| 737 | is_zs = length (filter isZEncoded b) |
|---|
| 738 | has_zs = length (filter hasZEncoding b) |
|---|
| 739 | in |
|---|
| 740 | countFS entries' longest' (is_z + is_zs) (has_z + has_zs) bs |
|---|
| 741 | |
|---|
| 742 | -- ----------------------------------------------------------------------------- |
|---|
| 743 | -- ABI hash support |
|---|
| 744 | |
|---|
| 745 | {- |
|---|
| 746 | ghc --abi-hash Data.Foo System.Bar |
|---|
| 747 | |
|---|
| 748 | Generates a combined hash of the ABI for modules Data.Foo and |
|---|
| 749 | System.Bar. The modules must already be compiled, and appropriate -i |
|---|
| 750 | options may be necessary in order to find the .hi files. |
|---|
| 751 | |
|---|
| 752 | This is used by Cabal for generating the InstalledPackageId for a |
|---|
| 753 | package. The InstalledPackageId must change when the visible ABI of |
|---|
| 754 | the package chagnes, so during registration Cabal calls ghc --abi-hash |
|---|
| 755 | to get a hash of the package's ABI. |
|---|
| 756 | -} |
|---|
| 757 | |
|---|
| 758 | abiHash :: [(String, Maybe Phase)] -> Ghc () |
|---|
| 759 | abiHash strs = do |
|---|
| 760 | hsc_env <- getSession |
|---|
| 761 | let dflags = hsc_dflags hsc_env |
|---|
| 762 | |
|---|
| 763 | liftIO $ do |
|---|
| 764 | |
|---|
| 765 | let find_it str = do |
|---|
| 766 | let modname = mkModuleName str |
|---|
| 767 | r <- findImportedModule hsc_env modname Nothing |
|---|
| 768 | case r of |
|---|
| 769 | Found _ m -> return m |
|---|
| 770 | _error -> ghcError $ CmdLineError $ showSDoc $ |
|---|
| 771 | cannotFindInterface dflags modname r |
|---|
| 772 | |
|---|
| 773 | mods <- mapM find_it (map fst strs) |
|---|
| 774 | |
|---|
| 775 | let get_iface modl = loadUserInterface False (text "abiHash") modl |
|---|
| 776 | ifaces <- initIfaceCheck hsc_env $ mapM get_iface mods |
|---|
| 777 | |
|---|
| 778 | bh <- openBinMem (3*1024) -- just less than a block |
|---|
| 779 | put_ bh opt_HiVersion |
|---|
| 780 | -- package hashes change when the compiler version changes (for now) |
|---|
| 781 | -- see #5328 |
|---|
| 782 | mapM_ (put_ bh . mi_mod_hash) ifaces |
|---|
| 783 | f <- fingerprintBinMem bh |
|---|
| 784 | |
|---|
| 785 | putStrLn (showSDoc (ppr f)) |
|---|
| 786 | |
|---|
| 787 | -- ----------------------------------------------------------------------------- |
|---|
| 788 | -- Util |
|---|
| 789 | |
|---|
| 790 | unknownFlagsErr :: [String] -> a |
|---|
| 791 | unknownFlagsErr fs = ghcError (UsageError ("unrecognised flags: " ++ unwords fs)) |
|---|