Forked from
Glasgow Haskell Compiler / GHC
This fork has diverged from the upstream repository.
-
Previously, the unit-id of ghc-the-library was fixed as `ghc`. This was done primarily because the compiler must know the unit-id of some packages (including ghc) a-priori to define wired-in names. However, as seen in #20742, a reinstallable `ghc` whose unit-id is fixed to `ghc` might result in subtle bugs when different ghc's interact. A good example of this is having GHC_A load a plugin compiled by GHC_B, where GHC_A and GHC_B are linked to ghc-libraries that are ABI incompatible. Without a distinction between the unit-id of the ghc library GHC_A is linked against and the ghc library the plugin it is loading was compiled against, we can't check compatibility. This patch gives a slightly better unit-id to ghc (ghc-version) by (1) Not setting -this-unit-id to ghc, but rather to the new unit-id (modulo stage0) (2) Adding a definition to `GHC.Settings.Config` whose value is the new unit-id. (2.1) `GHC.Settings.Config` is generated by Hadrian (2.2) and also by cabal through `compiler/Setup.hs` This unit-id definition is imported by `GHC.Unit.Types` and used to set the wired-in unit-id of "ghc", which was previously fixed to "ghc" The commits following this one will improve the unit-id with a cabal-style package hash and check compatibility when loading plugins. Note that we also ensure that ghc's unit key matches unit id both when hadrian or cabal builds ghc, and in this way we no longer need to add `ghc` to the WiringMap.
Previously, the unit-id of ghc-the-library was fixed as `ghc`. This was done primarily because the compiler must know the unit-id of some packages (including ghc) a-priori to define wired-in names. However, as seen in #20742, a reinstallable `ghc` whose unit-id is fixed to `ghc` might result in subtle bugs when different ghc's interact. A good example of this is having GHC_A load a plugin compiled by GHC_B, where GHC_A and GHC_B are linked to ghc-libraries that are ABI incompatible. Without a distinction between the unit-id of the ghc library GHC_A is linked against and the ghc library the plugin it is loading was compiled against, we can't check compatibility. This patch gives a slightly better unit-id to ghc (ghc-version) by (1) Not setting -this-unit-id to ghc, but rather to the new unit-id (modulo stage0) (2) Adding a definition to `GHC.Settings.Config` whose value is the new unit-id. (2.1) `GHC.Settings.Config` is generated by Hadrian (2.2) and also by cabal through `compiler/Setup.hs` This unit-id definition is imported by `GHC.Unit.Types` and used to set the wired-in unit-id of "ghc", which was previously fixed to "ghc" The commits following this one will improve the unit-id with a cabal-style package hash and check compatibility when loading plugins. Note that we also ensure that ghc's unit key matches unit id both when hadrian or cabal builds ghc, and in this way we no longer need to add `ghc` to the WiringMap.
Setup.hs 6.19 KiB
{-# LANGUAGE RecordWildCards #-}
module Main where
import Distribution.Simple
import Distribution.Simple.BuildPaths
import Distribution.Types.ComponentLocalBuildInfo
import Distribution.Types.ComponentName (ComponentName(CLibName))
import Distribution.Types.LocalBuildInfo
import Distribution.Types.LibraryName (LibraryName(LMainLibName))
import Distribution.Verbosity
import Distribution.Simple.Program
import Distribution.Simple.Utils
import Distribution.Simple.Setup
import System.IO
import System.Process
import System.Directory
import System.FilePath
import Control.Monad
import Data.Char
import qualified Data.Map as Map
import GHC.ResponseFile
import System.Environment
main :: IO ()
main = defaultMainWithHooks ghcHooks
where
ghcHooks = simpleUserHooks
{ postConf = \args cfg pd lbi -> do
let verbosity = fromFlagOrDefault minBound (configVerbosity cfg)
ghcAutogen verbosity lbi
postConf simpleUserHooks args cfg pd lbi
}
-- Mapping from primop-*.hs-incl file to command
primopIncls :: [(String,String)]
primopIncls =
[ ("primop-data-decl.hs-incl" , "--data-decl")
, ("primop-tag.hs-incl" , "--primop-tag")
, ("primop-list.hs-incl" , "--primop-list")
, ("primop-has-side-effects.hs-incl" , "--has-side-effects")
, ("primop-out-of-line.hs-incl" , "--out-of-line")
, ("primop-commutable.hs-incl" , "--commutable")
, ("primop-code-size.hs-incl" , "--code-size")
, ("primop-can-fail.hs-incl" , "--can-fail")
, ("primop-strictness.hs-incl" , "--strictness")
, ("primop-fixity.hs-incl" , "--fixity")
, ("primop-primop-info.hs-incl" , "--primop-primop-info")
, ("primop-vector-uniques.hs-incl" , "--primop-vector-uniques")
, ("primop-vector-tys.hs-incl" , "--primop-vector-tys")
, ("primop-vector-tys-exports.hs-incl", "--primop-vector-tys-exports")
, ("primop-vector-tycons.hs-incl" , "--primop-vector-tycons")
, ("primop-docs.hs-incl" , "--wired-in-docs")
]
ghcAutogen :: Verbosity -> LocalBuildInfo -> IO ()
ghcAutogen verbosity lbi@LocalBuildInfo{..} = do
-- Get compiler/ root directory from the cabal file
let Just compilerRoot = takeDirectory <$> pkgDescrFile
-- Require the necessary programs
(gcc ,withPrograms) <- requireProgram normal gccProgram withPrograms
(ghc ,withPrograms) <- requireProgram normal ghcProgram withPrograms
settings <- read <$> getProgramOutput normal ghc ["--info"]
-- We are reinstalling GHC
-- Write primop-*.hs-incl
let hsCppOpts = case lookup "Haskell CPP flags" settings of
Just fs -> unescapeArgs fs
Nothing -> []
primopsTxtPP = compilerRoot </> "GHC/Builtin/primops.txt.pp"
cppOpts = hsCppOpts ++ ["-P","-x","c"]
cppIncludes = map ("-I"++) [compilerRoot]
-- Preprocess primops.txt.pp
primopsStr <- getProgramOutput normal gcc (cppOpts ++ cppIncludes ++ [primopsTxtPP])
-- Call genprimopcode to generate *.hs-incl
forM_ primopIncls $ \(file,command) -> do
contents <- readProcess "genprimopcode" [command] primopsStr
rewriteFileEx verbosity (buildDir </> file) contents
-- Write GHC.Platform.Constants
let platformConstantsPath = autogenPackageModulesDir lbi </> "GHC/Platform/Constants.hs"
targetOS = case lookup "target os" settings of
Nothing -> error "no target os in settings"
Just os -> os
createDirectoryIfMissingVerbose verbosity True (takeDirectory platformConstantsPath)
withTempFile (takeDirectory platformConstantsPath) "Constants_tmp.hs" $ \tmp h -> do
hClose h
callProcess "deriveConstants" ["--gen-haskell-type","-o",tmp,"--target-os",targetOS]
renameFile tmp platformConstantsPath
let cProjectUnitId = case Map.lookup (CLibName LMainLibName) componentNameMap of
Just [LibComponentLocalBuildInfo{componentUnitId}] -> unUnitId componentUnitId
_ -> error "Couldn't find unique cabal library when building ghc"
-- Write GHC.Settings.Config
configHsPath = autogenPackageModulesDir lbi </> "GHC/Settings/Config.hs"
configHs = generateConfigHs cProjectUnitId settings
createDirectoryIfMissingVerbose verbosity True (takeDirectory configHsPath)
rewriteFileEx verbosity configHsPath configHs
getSetting :: [(String,String)] -> String -> String -> Either String String
getSetting settings kh kr = go settings kr
where
go settings k = case lookup k settings of
Nothing -> Left (show k ++ " not found in settings: " ++ show settings)
Just v -> Right v
generateConfigHs :: String -- ^ ghc's cabal-generated unit-id, which matches its package-id/key
-> [(String,String)] -> String
generateConfigHs cProjectUnitId settings = either error id $ do
let getSetting' = getSetting $ (("cStage","2"):) settings
buildPlatform <- getSetting' "cBuildPlatformString" "Host platform"
hostPlatform <- getSetting' "cHostPlatformString" "Target platform"
cProjectName <- getSetting' "cProjectName" "Project name"
cBooterVersion <- getSetting' "cBooterVersion" "Project version"
cStage <- getSetting' "cStage" "cStage"
return $ unlines
[ "module GHC.Settings.Config"
, " ( module GHC.Version"
, " , cBuildPlatformString"
, " , cHostPlatformString"
, " , cProjectName"
, " , cBooterVersion"
, " , cStage"
, " , cProjectUnitId"
, " ) where"
, ""
, "import GHC.Prelude.Basic"
, ""
, "import GHC.Version"
, ""
, "cBuildPlatformString :: String"
, "cBuildPlatformString = " ++ show buildPlatform
, ""
, "cHostPlatformString :: String"
, "cHostPlatformString = " ++ show hostPlatform
, ""
, "cProjectName :: String"
, "cProjectName = " ++ show cProjectName
, ""
, "cBooterVersion :: String"
, "cBooterVersion = " ++ show cBooterVersion
, ""
, "cStage :: String"
, "cStage = show ("++ cStage ++ " :: Int)"
, ""
, "cProjectUnitId :: String"
, "cProjectUnitId = " ++ show cProjectUnitId
]