-- Note [Settings file] -- ~~~~~~~~~~~~~~~~~~~~ -- -- GHC has a file, `${top_dir}/settings`, which is the main source of run-time -- configuration. ghc-pkg needs just a little bit of it: the target platform CPU -- arch and OS. It uses that to figure out what subdirectory of `~/.ghc` is -- associated with the current version/target. -- -- This module has just enough code to read key value pairs from the settings -- file, and read the target platform from those pairs. -- -- The "0" suffix is because the caller will partially apply it, and that will -- in turn be used a few more times. module GHC.Settings where import Prelude -- See Note [Why do we import Prelude here?] import GHC.BaseDir import GHC.Platform import Data.Char (isSpace) import Data.Map (Map) import qualified Data.Map as Map ----------------------------------------------------------------------------- -- parts of settings file getTargetPlatform :: FilePath -> RawSettings -> Either String Platform getTargetPlatform settingsFile mySettings = do let getBooleanSetting = getBooleanSetting0 settingsFile mySettings readSetting :: (Show a, Read a) => String -> Either String a readSetting = readSetting0 settingsFile mySettings targetArch <- readSetting "target arch" targetOS <- readSetting "target os" targetWordSize <- readSetting "target word size" targetUnregisterised <- getBooleanSetting "Unregisterised" targetHasGnuNonexecStack <- getBooleanSetting "target has GNU nonexec stack" targetHasIdentDirective <- getBooleanSetting "target has .ident directive" targetHasSubsectionsViaSymbols <- getBooleanSetting "target has subsections via symbols" crossCompiling <- getBooleanSetting "cross compiling" pure $ Platform { platformMini = PlatformMini { platformMini_arch = targetArch , platformMini_os = targetOS } , platformWordSize = targetWordSize , platformUnregisterised = targetUnregisterised , platformHasGnuNonexecStack = targetHasGnuNonexecStack , platformHasIdentDirective = targetHasIdentDirective , platformHasSubsectionsViaSymbols = targetHasSubsectionsViaSymbols , platformIsCrossCompiling = crossCompiling } ----------------------------------------------------------------------------- -- settings file helpers type RawSettings = Map String String -- | See Note [Settings file] for "0" suffix getSetting0 :: FilePath -> RawSettings -> String -> Either String String getSetting0 settingsFile mySettings key = case Map.lookup key mySettings of Just xs -> Right xs Nothing -> Left $ "No entry for " ++ show key ++ " in " ++ show settingsFile -- | See Note [Settings file] for "0" suffix getFilePathSetting0 :: FilePath -> FilePath -> RawSettings -> String -> Either String String getFilePathSetting0 top_dir settingsFile mySettings key = expandTopDir top_dir <$> getSetting0 settingsFile mySettings key -- | See Note [Settings file] for "0" suffix getBooleanSetting0 :: FilePath -> RawSettings -> String -> Either String Bool getBooleanSetting0 settingsFile mySettings key = do rawValue <- getSetting0 settingsFile mySettings key case rawValue of "YES" -> Right True "NO" -> Right False xs -> Left $ "Bad value for " ++ show key ++ ": " ++ show xs -- | See Note [Settings file] for "0" suffix readSetting0 :: (Show a, Read a) => FilePath -> RawSettings -> String -> Either String a readSetting0 settingsFile mySettings key = case Map.lookup key mySettings of Just xs -> case maybeRead xs of Just v -> Right v Nothing -> Left $ "Failed to read " ++ show key ++ " value " ++ show xs Nothing -> Left $ "No entry for " ++ show key ++ " in " ++ show settingsFile ----------------------------------------------------------------------------- -- read helpers maybeRead :: Read a => String -> Maybe a maybeRead str = case reads str of [(x, "")] -> Just x _ -> Nothing maybeReadFuzzy :: Read a => String -> Maybe a maybeReadFuzzy str = case reads str of [(x, s)] | all isSpace s -> Just x _ -> Nothing