[Git][ghc/ghc][wip/supersven/hadrian-cross-stage3] 7 commits: WIP
Sven Tennie pushed to branch wip/supersven/hadrian-cross-stage3 at Glasgow Haskell Compiler / GHC Commits: b1983873 by Sven Tennie at 2026-07-13T19:14:30+02:00 WIP - - - - - 8d455fca by Sven Tennie at 2026-07-13T19:14:38+02:00 WIP - - - - - 998e2372 by Sven Tennie at 2026-07-13T19:14:47+02:00 WIP - - - - - 8c179fa9 by Sven Tennie at 2026-07-13T19:14:54+02:00 WIP - - - - - 946742b1 by Sven Tennie at 2026-07-13T19:15:00+02:00 Need configure.ac - - - - - 63f20eca by Sven Tennie at 2026-07-13T19:15:06+02:00 WIP - - - - - 4713cc0b by Sven Tennie at 2026-07-13T19:15:10+02:00 WIP - - - - - 4 changed files: - .gitignore - hadrian/src/BindistConfig.hs - hadrian/src/Rules/BinaryDist.hs - hadrian/src/Rules/Generate.hs Changes: ===================================== .gitignore ===================================== @@ -120,8 +120,6 @@ _darcs/ /compiler/GHC/CmmToLlvm/Version/Bounds.hs /compiler/ghc.cabal /compiler/ghc.cabal.old -/stage1/distrib/configure.ac -/stage2/distrib/configure.ac /distrib/ghc.iss /docs/index.html /docs/man ===================================== hadrian/src/BindistConfig.hs ===================================== @@ -3,28 +3,31 @@ module BindistConfig where import Stage import Oracles.Flag import Expression -data BindistConfig = BindistConfig - { library_stage :: Stage -- ^ The stage compiler which builds the libraries - , executable_stage :: Stage -- ^ The stage compiler which builds the executables - , bindistFolder :: FilePath -- ^ Parent folder under build root ("bindist" or "bindist-stage3") - } +data BindistConfig = BindistConfig { library_stage :: Stage -- ^ The stage compiler which builds the libraries + , executable_stage :: Stage -- ^ The stage compiler which builds the executables + } + -- | A bindist for when the host = target, non cross-compilation setting. -- Both the libraries and final executables are built with stage1 compiler. normalBindist :: BindistConfig -normalBindist = BindistConfig { library_stage = Stage1, executable_stage = Stage1, bindistFolder = "bindist" } +normalBindist = BindistConfig { library_stage = Stage1, executable_stage = Stage1 } -- | A bindist which contains a cross compiler (when host /= target) -- The cross compiler is produced by the stage1 compiler, but then we must compile -- all the boot libraries with the cross compiler (hence stage2 for libraries) crossBindist :: BindistConfig -crossBindist = BindistConfig { library_stage = Stage2, executable_stage = Stage1, bindistFolder = "bindist" } +crossBindist = BindistConfig { library_stage = Stage2, executable_stage = Stage1 } -- | A bindist which contains executables for the target, which produce code for the -- target. These are produced as "Stage3" build products, produced by a stage2 cross compiler. targetBindist :: BindistConfig -targetBindist = BindistConfig { library_stage = Stage2, executable_stage = Stage2, bindistFolder = "bindist-stage3" } +targetBindist = BindistConfig { library_stage = Stage2, executable_stage = Stage2 } +-- | Parent folder under build root ("bindist" or "bindist-stage3") +bindistFolder :: BindistConfig -> FilePath +bindistFolder conf | executable_stage conf == Stage2 = "bindist-stage3" +bindistFolder _conf = "bindist" -- | The implicit bindist config, if we don't know any better. implicitBindistConfig :: Action BindistConfig ===================================== hadrian/src/Rules/BinaryDist.hs ===================================== @@ -6,7 +6,6 @@ import Context import Data.Either import qualified Data.Set as Set import Expression -import Hadrian.Oracles.Path (fixUnixPathsOnWindows) import Oracles.Flavour import Oracles.Setting import Packages @@ -14,8 +13,6 @@ import Rules.Generate (generateSettings) import Settings import qualified System.Directory.Extra as IO import Settings.Program (programContext) -import Target -import Utilities import BindistConfig {- @@ -168,7 +165,7 @@ buildBinDistDir root conf@BindistConfig{..} = do distDir <- Context.distDir (vanillaContext library_stage rts) let ghcBuildDir = root -/- stageString library_stage - bindistFilesDir = root -/- bindistFolder -/- ghcVersionPretty + bindistFilesDir = root -/- bindistFolder conf -/- ghcVersionPretty ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform rtsIncludeDir = distDir -/- "include" @@ -390,64 +387,34 @@ bindistRules = do phony "binary-dist-cross" $ buildBinDistX "binary-dist-dir-cross" "bindist" Xz phony "binary-dist-stage3" $ buildBinDistX "binary-dist-dir-stage3" "bindist-stage3" Xz - -- Prepare binary distribution configure script - -- (generated in a per-stage temporary distrib directory by 'autoreconf') - forM_ [("bindist", Stage1), ("bindist-stage3", Stage2)] $ \(folder, stage) -> - root -/- folder -/- "ghc-*" -/- "configure" %> generateConfigure root stage - - -- Generate the Makefile that enables the "make install" part - forM_ ["bindist", "bindist-stage3"] $ \folder -> - root -/- folder -/- "ghc-*" -/- "Makefile" %> \makefilePath -> do - top <- topDirectory - copyFile (top -/- "hadrian" -/- "bindist" -/- "Makefile") makefilePath - - -- Copy various configure-related files needed for a working - -- './configure [...] && make install' workflow - -- (see the list of files needed in the 'binary-dist' rule above, before - -- creating the archive). - forM_ ["bindist", "bindist-stage3"] $ \folder -> - forM_ bindistInstallFiles $ \file -> - root -/- folder -/- "ghc-*" -/- file %> \dest -> do - copyFile (fixup file) dest + forM_ [normalBindist, targetBindist] $ \bindistCfg -> do + let bindistFolderName = bindistFolder bindistCfg + stg = executable_stage bindistCfg + -- Copy the per-stage 'configure' (produced by autoreconf in Generate.hs) + -- from the build distrib dir into the bindist. Generating it there keeps + -- the autoreconf inputs (configure.ac, aclocal.m4, m4/*.m4) next to the + -- configure script and lets Shake track their changes correctly. + root -/- bindistFolderName -/- "ghc-*" -/- "configure" %> \configurePath -> do + let distribConfigure = root -/- stageString stg -/- "distrib" -/- "configure" + need [distribConfigure] + copyFile distribConfigure configurePath + + -- Generate the Makefile that enables the "make install" part + root -/- bindistFolderName -/- "ghc-*" -/- "Makefile" %> \makefilePath -> do + top <- topDirectory + copyFile (top -/- "hadrian" -/- "bindist" -/- "Makefile") makefilePath + + -- Copy various configure-related files needed for a working + -- './configure [...] && make install' workflow + -- (see the list of files needed in the 'binary-dist' rule above, before + -- creating the archive). + forM_ bindistInstallFiles $ \file -> + root -/- bindistFolderName -/- "ghc-*" -/- file %> \dest -> do + copyFile (fixup file) dest where fixup f | f `elem` ["INSTALL", "README"] = "distrib" -/- f | otherwise = f - generateConfigure root stage configurePath = do - let acFile = stageString stage -/- "distrib" -/- "configure.ac" - need [acFile] - ghcRoot <- topDirectory - -- Use a per-stage temporary distrib directory so that Stage1 and - -- Stage2 configure generation can run concurrently without - -- clobbering each other's inputs/outputs. - let distribDir = root -/- ("distrib-" ++ stageString stage) - removeDirectory distribDir - createDirectory distribDir - copyFile (ghcRoot -/- acFile) (distribDir -/- "configure.ac") - copyFile (ghcRoot -/- "aclocal.m4") (distribDir -/- "aclocal.m4") - copyDirectory (ghcRoot -/- "m4") distribDir - - -- Note [Autoreconf unix paths from ACLOCAL_PATH] - -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- On Windows, autoreconf fails when the ACLOCAL_PATH env variable contains Windows- - -- style paths. This happens because MSYS2 automatically converts env variables to - -- Windows-style paths. To fix this, we convert ACLOCAL_PATH back to Unix style. - -- This is done both in the boot Python script and here when building a bindist. - win_host <- isWinHost - env <- if not win_host - then pure [] - else do - aclocalPathMay <- getEnv "ACLOCAL_PATH" - case aclocalPathMay of - Nothing -> pure [] - Just aclocalPath -> do - unixAclocalPath <- fixUnixPathsOnWindows aclocalPath - pure [AddEnv "ACLOCAL_PATH" unixAclocalPath] - - buildWithCmdOptions env $ - target (vanillaContext Stage1 ghc) (Autoreconf distribDir) [] [] - moveFile (distribDir -/- "configure") configurePath - removeDirectory distribDir data Compressor = Gzip | Bzip2 | Xz deriving (Eq, Ord, Show) ===================================== hadrian/src/Rules/Generate.hs ===================================== @@ -9,6 +9,7 @@ import qualified Data.Set as Set import Base import qualified Context import Expression +import Hadrian.Oracles.Path (fixUnixPathsOnWindows) import Hadrian.Oracles.TextFile (lookupStageBuildConfig) import Oracles.Flag hiding (arSupportsAtFile, arSupportsDashL) import Oracles.ModuleFiles @@ -360,11 +361,6 @@ templateRule :: FilePath -> Interpolations -> Rules () templateRule outPath = templateRuleFrom (outPath <.> "in") outPath -templateRuleForStages :: FilePath -> (Stage -> Interpolations) -> Rules () -templateRuleForStages outPath mkInterps = - forM_ [Stage1, Stage2] $ \stage -> - templateRuleFrom (outPath <.> "in") (stageString stage -/- outPath) (mkInterps stage) - templateRules :: Rules () templateRules = do templateRule "compiler/ghc.cabal" $ projectVersion @@ -415,6 +411,7 @@ templateRules = do bindistRules :: Rules () bindistRules = do + root <- buildRootRules templateRule ("mk" -/- "project.mk") $ mconcat [ interpolateSetting "ProjectName" ProjectName , interpolateSetting "ProjectVersion" ProjectVersion @@ -426,45 +423,125 @@ bindistRules = do , interpolateVar "HostOS_CPP" $ fmap cppify $ interp $ queryHost queryOS - , interpolateVar "TargetPlatform" $ getTarget targetPlatformTriple - , interpolateVar "TargetPlatform_CPP" $ cppify <$> getTarget targetPlatformTriple - , interpolateVar "TargetArch_CPP" $ cppify <$> getTarget queryArch - , interpolateVar "TargetOS_CPP" $ cppify <$> getTarget queryOS - , interpolateVar "LLVMTarget" $ getTarget tgtLlvmTarget + -- Stage2 always targets the final architecture. Thus, we can use a + -- constant stage here. + , interpolateVar "TargetPlatform" $ getTarget Stage2 targetPlatformTriple + , interpolateVar "TargetPlatform_CPP" $ cppify <$> getTarget Stage2 targetPlatformTriple + , interpolateVar "TargetArch_CPP" $ cppify <$> getTarget Stage2 queryArch + , interpolateVar "TargetOS_CPP" $ cppify <$> getTarget Stage2 queryOS + , interpolateVar "LLVMTarget" $ getTarget Stage2 tgtLlvmTarget ] - templateRuleForStages ("distrib" -/- "configure.ac") $ \stage -> mconcat + forM_ [Stage1, Stage2] $ \stage -> + let crossStageInterps = Interpolations $ do + isCrossStage <- crossStage stage + targetPlatform <- setting TargetPlatformFull + -- For cross-compiled compilers we need to pretend that they were + -- build on the target. For regular commpilers we can assume that: + -- build == host == target + buildPlatform <- + if isCrossStage + then + interp $ queryBuild targetPlatformTriple + else getTarget stage targetPlatformTriple + hostPlatform <- + if isCrossStage + then + interp $ queryHost targetPlatformTriple + else getTarget stage targetPlatformTriple + baseUnitId <- pkgUnitId (if isCrossStage then succStage stage else stage) base + buildPlatformFull <- if isCrossStage then setting BuildPlatformFull else setting TargetPlatformFull + hostPlatformFull <- if isCrossStage then setting HostPlatformFull else setting TargetPlatformFull + pure + [ ("CrossCompilePrefix", if isCrossStage then targetPlatform <> "-" else "") + , ("TargetPlatformFull", targetPlatform) + , ("BuildPlatform", buildPlatform) + , ("HostPlatform", hostPlatform) + , ("BaseUnitId", baseUnitId) + , ("BuildPlatformFull", buildPlatformFull) + , ("HostPlatformFull", hostPlatformFull) + ] + in templateRuleFrom + ("distrib" -/- "configure.ac" <.> "in") + (root -/- stageString stage -/- "distrib" -/- "configure.ac") + $ mconcat [ interpolateSetting "ConfiguredEmsdkVersion" EmsdkVersion - , interpolateVar "CrossCompilePrefix" $ do - isCross <- crossStage stage - target <- setting TargetPlatformFull - pure $ if isCross then target <> "-" else "" - , interpolateVar "LeadingUnderscore" $ yesNo <$> getTarget tgtSymbolsHaveLeadingUnderscore + , interpolateVar "LeadingUnderscore" $ yesNo <$> getTarget stage tgtSymbolsHaveLeadingUnderscore , interpolateSetting "LlvmMaxVersion" LlvmMaxVersion , interpolateSetting "LlvmMinVersion" LlvmMinVersion - , interpolateVar "LlvmTarget" $ getTarget tgtLlvmTarget + , interpolateVar "LlvmTarget" $ getTarget stage tgtLlvmTarget , interpolateSetting "ProjectVersion" ProjectVersion , interpolateVar "EnableDistroToolchain" $ interp (staged (lookupStageBuildConfig "settings-use-distro-mingw")) - , interpolateVar "TablesNextToCode" $ yesNo <$> getTarget tgtTablesNextToCode + , interpolateVar "TablesNextToCode" $ yesNo <$> getTarget stage tgtTablesNextToCode , interpolateVar "TargetHasLibm" $ yesNo <$> interp (staged (buildFlag TargetHasLibm)) - , interpolateVar "TargetPlatform" $ getTarget targetPlatformTriple - , interpolateVar "BuildPlatform" $ ifM (not <$> crossStage stage) (getTarget targetPlatformTriple) (interp $ queryBuild targetPlatformTriple) - , interpolateVar "HostPlatform" $ ifM (not <$> crossStage stage) (getTarget targetPlatformTriple) (interp $ queryHost targetPlatformTriple) - , interpolateVar "TargetWordBigEndian" $ getTarget isBigEndian - , interpolateVar "TargetWordSize" $ getTarget wordSize - , interpolateVar "Unregisterised" $ yesNo <$> getTarget tgtUnregisterised + , interpolateVar "TargetPlatform" $ getTarget stage targetPlatformTriple + , interpolateVar "TargetWordBigEndian" $ getTarget stage isBigEndian + , interpolateVar "TargetWordSize" $ getTarget stage wordSize + , interpolateVar "Unregisterised" $ yesNo <$> getTarget stage tgtUnregisterised , interpolateVar "UseLibdw" $ fmap yesNo $ interp $ staged (fmap (isJust . tgtRTSWithLibdw) . targetStage) - , interpolateVar "UseLibffiForAdjustors" $ yesNo <$> getTarget tgtUseLibffiForAdjustors - , interpolateVar "BaseUnitId" $ do - isCross <- crossStage stage - pkgUnitId (if isCross then succStage stage else stage) base - , interpolateVar "GhcWithSMP" $ yesNo <$> targetSupportsSMP Stage2 - , interpolateVar "TargetPlatformFull" (setting TargetPlatformFull) - , interpolateVar "BuildPlatformFull" $ ifM (not <$> crossStage stage) (setting TargetPlatformFull) (setting BuildPlatformFull) - , interpolateVar "HostPlatformFull" $ ifM (not <$> crossStage stage) (setting TargetPlatformFull) (setting HostPlatformFull) + , interpolateVar "UseLibffiForAdjustors" $ yesNo <$> getTarget stage tgtUseLibffiForAdjustors + , interpolateVar "GhcWithSMP" $ yesNo <$> targetSupportsSMP stage + , crossStageInterps ] + + -- Stage the autoreconf inputs (aclocal.m4 and the m4/ macro directory) next + -- to each per-stage generated configure.ac under _build, then run + -- 'autoreconf' to produce a per-stage 'configure' script there. + -- + -- The 'Autoreconf' builder auto-needs <dir>/configure.ac (Builder.hs); we + -- also explicitly need the staged macros so editing them triggers + -- re-generation of 'configure'. BinaryDist.hs copies this configure into + -- the bindist; it no longer runs autoreconf itself. + forM_ [Stage1, Stage2] $ \stage -> do + let distribDir = root -/- stageString stage -/- "distrib" + + distribDir -/- "aclocal.m4" %> \out -> do + top <- topDirectory + copyFile (top -/- "aclocal.m4") out + + -- Autoconf auxiliary files required by autoreconf (config.sub, + -- config.guess, install-sh). They live in-tree at the repo root and must + -- be staged next to configure.ac for autoreconf to find them. + forM_ ["config.sub", "config.guess", "install-sh"] $ \f -> + distribDir -/- f %> \out -> do + top <- topDirectory + copyFile (top -/- f) out + + distribDir -/- "m4/*.m4" %> \out -> do + top <- topDirectory + copyFile (top -/- "m4" -/- takeFileName out) out + + distribDir -/- "configure" %> \_ -> do + top <- topDirectory + m4Files <- getDirectoryFiles (top -/- "m4") ["*.m4"] + need $ [ distribDir -/- "configure.ac" + , distribDir -/- "config.sub" + , distribDir -/- "config.guess" + , distribDir -/- "install-sh" + , distribDir -/- "aclocal.m4" + ] + ++ [ distribDir -/- "m4" -/- takeFileName f | f <- m4Files ] + + -- Note [Autoreconf unix paths from ACLOCAL_PATH] + -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + -- On Windows, autoreconf fails when the ACLOCAL_PATH env variable + -- contains Windows-style paths. MSYS2 auto-converts env vars to + -- Windows-style, so we convert ACLOCAL_PATH back to Unix style here. + win_host <- isWinHost + env <- if not win_host + then pure [] + else do + aclocalPathMay <- getEnv "ACLOCAL_PATH" + case aclocalPathMay of + Nothing -> pure [] + Just aclocalPath -> do + unixAclocalPath <- fixUnixPathsOnWindows aclocalPath + pure [AddEnv "ACLOCAL_PATH" unixAclocalPath] + + buildWithCmdOptions env $ + target (vanillaContext stage ghc) (Autoreconf distribDir) [] [] where interp = interpretInContext (semiEmptyTarget Stage2) - getTarget = interp . queryTarget Stage2 + getTarget stage = interp . queryTarget stage -- | Given a 'String' replace characters '.' and '-' by underscores ('_') so that -- the resulting 'String' is a valid C preprocessor identifier. View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/58e8070e93dfb897aec41098d456eec... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/58e8070e93dfb897aec41098d456eec... You're receiving this email because of your account on gitlab.haskell.org. Manage all notifications: https://gitlab.haskell.org/-/profile/notifications | Help: https://gitlab.haskell.org/help
participants (1)
-
Sven Tennie (@supersven)