Sven Tennie pushed to branch wip/supersven/hadrian-cross-stage3 at Glasgow Haskell Compiler / GHC Commits: 46caa89b by Sven Tennie at 2026-02-24T23:06:12+00:00 Build stage2 libs for testing Provide js and wasm dependencies for stage1 as well. Stage2 should be good enough; However, this would imply changing topDir or adding a new configuration flag which would be a bigger untertaking. - - - - - bc30c235 by Sven Tennie at 2026-02-24T23:22:29+00:00 Fix weird space character - - - - - a366bebe by Sven Tennie at 2026-02-25T17:11:18+00:00 Add a config flag for LibDir and derived values For cross-compilers, we have to refer to the libs of the succeeding stage. This also affects other files previously relying on top_dir in GHC. - - - - - 6c99ca77 by Sven Tennie at 2026-02-25T17:13:24+00:00 Remove prior hack to provide WASM and GHCJS deps This can now be found in the succeeding stage. - - - - - 6a2aa024 by Sven Tennie at 2026-02-25T19:34:01+00:00 Use topLibDir - - - - - 5d7e35f3 by Sven Tennie at 2026-02-25T20:52:55+00:00 Fix stages in generateSettings - - - - - 9ad127f3 by Sven Tennie at 2026-02-26T11:12:42+00:00 Replace artificial "Lib TopDir" setting Hadrian can simply set "LibDir" instead. - - - - - c59356fb by Sven Tennie at 2026-02-26T12:50:15+00:00 Enable stage3 bin-dists - - - - - 1631a297 by Sven Tennie at 2026-02-26T12:50:15+00:00 Generated cross stage 3 CI jobs - - - - - f1c02ddf by Sven Tennie at 2026-02-26T12:50:15+00:00 Hack - - - - - 08edfc24 by Sven Tennie at 2026-02-26T12:50:15+00:00 WIP: Validate script - - - - - e921d232 by Sven Tennie at 2026-02-26T12:50:15+00:00 Fix stage3 bindist creation - - - - - 2d088be9 by Sven Tennie at 2026-02-26T12:50:15+00:00 Adjust jobs.yaml - - - - - 215fed2f by Sven Tennie at 2026-02-26T12:50:15+00:00 Fix final ghc-pkg recache run Sage3 cross-compiler's ghc-pkg cannot run on the build host. Resort to a prior stage's ghc-pkg. - - - - - c4c6e64e by Sven Tennie at 2026-02-26T12:50:15+00:00 Bindist name must start with ghc* - - - - - 568a597d by Sven Tennie at 2026-02-26T12:50:15+00:00 Increase generate-ci happyness Pass its checks by adding some metadata. - - - - - 15 changed files: - .gitlab/generate-ci/gen_ci.hs - .gitlab/jobs.yaml - compiler/GHC/Driver/Config/Interpreter.hs - compiler/GHC/Driver/DynFlags.hs - compiler/GHC/Driver/Session.hs - compiler/GHC/Settings.hs - compiler/GHC/Settings/IO.hs - hadrian/bindist/Makefile - hadrian/src/BindistConfig.hs - hadrian/src/Oracles/Flag.hs - hadrian/src/Rules/BinaryDist.hs - hadrian/src/Rules/Generate.hs - hadrian/src/Rules/Test.hs - hadrian/src/Settings/Builders/RunTest.hs - + validate-riscv-bindist.sh Changes: ===================================== .gitlab/generate-ci/gen_ci.hs ===================================== @@ -286,6 +286,18 @@ crossConfig triple emulator configure_wrapper = , configureWrapper = configure_wrapper } +-- | cross-compiled compilers (build /= host/target) +stage3CrossConfig :: String -- ^ target triple + -> CrossEmulator -- ^ emulator for testing + -> Maybe String -- ^ Configure wrapper + -> BuildConfig +stage3CrossConfig triple emulator configure_wrapper = + vanilla { crossTarget = Just triple + , crossStage = Just 3 + , crossEmulator = emulator + , configureWrapper = configure_wrapper + } + llvm :: BuildConfig llvm = vanilla { llvmBootstrap = True } @@ -373,6 +385,8 @@ testEnv arch opsys bc = , ["zstd" | withZstd bc ] , ["no_tntc" | not (tablesNextToCode bc) ] , ["cross_"++triple | Just triple <- pure $ crossTarget bc ] + -- TODO: Is there something better than `show` for this? + , ["stage" ++ show stage | Just stage <- pure (crossStage bc), Just triple <- pure (crossTarget bc), "riscv" `isInfixOf` triple ] , [flavourString (mkJobFlavour bc)] ] @@ -1293,9 +1307,12 @@ cross_jobs = [ -- x86 -> aarch64 validateBuilds Amd64 (Linux Debian11) (crossConfig "aarch64-linux-gnu" (Emulator "qemu-aarch64 -L /usr/aarch64-linux-gnu") Nothing) - -- x86_64 -> riscv + -- x86_64 (build/host) -> riscv (target) , addValidateRule RiscV (validateBuilds Amd64 (Linux Debian12Riscv) (crossConfig "riscv64-linux-gnu" (Emulator "qemu-riscv64 -L /usr/riscv64-linux-gnu") Nothing)) + -- x86_64 (build) -> riscv (host/target) + , addValidateRule RiscV (validateBuilds Amd64 (Linux Debian12Riscv) (stage3CrossConfig "riscv64-linux-gnu" (Emulator "qemu-riscv64 -L /usr/riscv64-linux-gnu") Nothing)) + -- x86_64 -> loongarch64 , addValidateRule LoongArch64 (validateBuilds Amd64 (Linux Ubuntu2404LoongArch64) (crossConfig "loongarch64-linux-gnu" (Emulator "qemu-loongarch64 -L /usr/loongarch64-linux-gnu") Nothing)) @@ -1430,6 +1447,11 @@ platform_mapping = Map.map go combined_result , "release-x86_64-linux-deb12-release" , "release-x86_64-linux-fedora43-release" , "release-x86_64-windows-release" + , "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate" + , "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate" + -- TODO: Added those here for now, but do we really need RISC-V nightlies? Weekly should be fine. + , "nightly-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate" + , "nightly-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate" ] process sel = ===================================== .gitlab/jobs.yaml ===================================== @@ -2442,7 +2442,7 @@ "XZ_OPT": "-9" } }, - "nightly-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate": { + "nightly-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate": { "after_script": [ ".gitlab/ci.sh save_cache", ".gitlab/ci.sh save_test_output", @@ -2453,7 +2453,7 @@ "artifacts": { "expire_in": "8 weeks", "paths": [ - "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate.tar.xz", + "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate.tar.xz", "junit.xml", "unexpected-test-output.tar.gz" ], @@ -2496,7 +2496,7 @@ ], "variables": { "BIGNUM_BACKEND": "gmp", - "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate", + "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate", "BUILD_FLAVOUR": "validate", "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check", "CROSS_EMULATOR": "qemu-riscv64 -L /usr/riscv64-linux-gnu", @@ -2504,7 +2504,73 @@ "CROSS_TARGET": "riscv64-linux-gnu", "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check", "RUNTEST_ARGS": "-e config.timeout=900", - "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate", + "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate", + "XZ_OPT": "-9" + } + }, + "nightly-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate": { + "after_script": [ + ".gitlab/ci.sh save_cache", + ".gitlab/ci.sh save_test_output", + ".gitlab/ci.sh clean", + "cat ci_timings.txt" + ], + "allow_failure": false, + "artifacts": { + "expire_in": "8 weeks", + "paths": [ + "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate.tar.xz", + "junit.xml", + "unexpected-test-output.tar.gz" + ], + "reports": { + "junit": "junit.xml" + }, + "when": "always" + }, + "cache": { + "key": "x86_64-linux-deb12-riscv-$CACHE_REV", + "paths": [ + "cabal-cache", + "toolchain" + ] + }, + "dependencies": [], + "image": "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb12-riscv:$DOCKER_REV", + "needs": [ + { + "artifacts": false, + "job": "hadrian-ghc-in-ghci" + } + ], + "rules": [ + { + "if": "(\"true\" == \"true\") && ($RELEASE_JOB != \"yes\") && ($NIGHTLY)", + "when": "on_success" + } + ], + "script": [ + "sudo chown ghc:ghc -R .", + ".gitlab/ci.sh setup", + ".gitlab/ci.sh configure", + ".gitlab/ci.sh build_hadrian", + ".gitlab/ci.sh test_hadrian" + ], + "stage": "full-build", + "tags": [ + "x86_64-linux" + ], + "variables": { + "BIGNUM_BACKEND": "gmp", + "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate", + "BUILD_FLAVOUR": "validate", + "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check", + "CROSS_EMULATOR": "qemu-riscv64 -L /usr/riscv64-linux-gnu", + "CROSS_STAGE": "3", + "CROSS_TARGET": "riscv64-linux-gnu", + "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check", + "RUNTEST_ARGS": "-e config.timeout=900", + "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate", "XZ_OPT": "-9" } }, @@ -6610,7 +6676,7 @@ "TEST_ENV": "x86_64-linux-deb12-release" } }, - "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate": { + "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate": { "after_script": [ ".gitlab/ci.sh save_cache", ".gitlab/ci.sh save_test_output", @@ -6621,7 +6687,7 @@ "artifacts": { "expire_in": "2 weeks", "paths": [ - "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate.tar.xz", + "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate.tar.xz", "junit.xml", "unexpected-test-output.tar.gz" ], @@ -6647,7 +6713,7 @@ ], "rules": [ { - "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\bx86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/)) || ($CI_MERGE_REQUEST_LABELS =~ /.*RISC-V.*/)))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)", + "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\bx86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/)) || ($CI_MERGE_REQUEST_LABELS =~ /.*RISC-V.*/)))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)", "when": "on_success" } ], @@ -6664,7 +6730,7 @@ ], "variables": { "BIGNUM_BACKEND": "gmp", - "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate", + "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate", "BUILD_FLAVOUR": "validate", "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check", "CROSS_EMULATOR": "qemu-riscv64 -L /usr/riscv64-linux-gnu", @@ -6672,7 +6738,72 @@ "CROSS_TARGET": "riscv64-linux-gnu", "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check", "RUNTEST_ARGS": "-e config.timeout=900", - "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-validate" + "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage2-validate" + } + }, + "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate": { + "after_script": [ + ".gitlab/ci.sh save_cache", + ".gitlab/ci.sh save_test_output", + ".gitlab/ci.sh clean", + "cat ci_timings.txt" + ], + "allow_failure": false, + "artifacts": { + "expire_in": "2 weeks", + "paths": [ + "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate.tar.xz", + "junit.xml", + "unexpected-test-output.tar.gz" + ], + "reports": { + "junit": "junit.xml" + }, + "when": "always" + }, + "cache": { + "key": "x86_64-linux-deb12-riscv-$CACHE_REV", + "paths": [ + "cabal-cache", + "toolchain" + ] + }, + "dependencies": [], + "image": "registry.gitlab.haskell.org/ghc/ci-images/x86_64-linux-deb12-riscv:$DOCKER_REV", + "needs": [ + { + "artifacts": false, + "job": "hadrian-ghc-in-ghci" + } + ], + "rules": [ + { + "if": "((($ONLY_JOBS) && ($ONLY_JOBS =~ /.*\\bx86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate(\\s|$).*/)) || (($ONLY_JOBS == null) && ((($CI_MERGE_REQUEST_LABELS =~ /.*full-ci.*/) || ($CI_MERGE_REQUEST_LABELS =~ /.*marge_bot_batch_merge_job.*/) || ($CI_COMMIT_BRANCH == \"master\") || ($CI_COMMIT_BRANCH =~ /ghc-[0-9]+\\.[0-9]+/)) || ($CI_MERGE_REQUEST_LABELS =~ /.*RISC-V.*/)))) && ($RELEASE_JOB != \"yes\") && ($NIGHTLY == null)", + "when": "on_success" + } + ], + "script": [ + "sudo chown ghc:ghc -R .", + ".gitlab/ci.sh setup", + ".gitlab/ci.sh configure", + ".gitlab/ci.sh build_hadrian", + ".gitlab/ci.sh test_hadrian" + ], + "stage": "full-build", + "tags": [ + "x86_64-linux" + ], + "variables": { + "BIGNUM_BACKEND": "gmp", + "BIN_DIST_NAME": "ghc-x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate", + "BUILD_FLAVOUR": "validate", + "CONFIGURE_ARGS": "--with-intree-gmp --enable-strict-ghc-toolchain-check", + "CROSS_EMULATOR": "qemu-riscv64 -L /usr/riscv64-linux-gnu", + "CROSS_STAGE": "3", + "CROSS_TARGET": "riscv64-linux-gnu", + "INSTALL_CONFIGURE_ARGS": "--enable-strict-ghc-toolchain-check", + "RUNTEST_ARGS": "-e config.timeout=900", + "TEST_ENV": "x86_64-linux-deb12-riscv-cross_riscv64-linux-gnu-stage3-validate" } }, "x86_64-linux-deb12-unreg-validate": { ===================================== compiler/GHC/Driver/Config/Interpreter.hs ===================================== @@ -17,8 +17,8 @@ import System.Directory initInterpOpts :: DynFlags -> IO InterpOpts initInterpOpts dflags = do - wasm_dyld <- makeAbsolute $ topDir dflags </> "dyld.mjs" - js_interp <- makeAbsolute $ topDir dflags </> "ghc-interp.js" + wasm_dyld <- makeAbsolute $ libDir dflags </> "dyld.mjs" + js_interp <- makeAbsolute $ libDir dflags </> "ghc-interp.js" pure $ InterpOpts { interpExternal = gopt Opt_ExternalInterpreter dflags , interpProg = pgm_i dflags ===================================== compiler/GHC/Driver/DynFlags.hs ===================================== @@ -60,7 +60,7 @@ module GHC.Driver.DynFlags ( -- ** System tool settings and locations programName, projectVersion, - ghcUsagePath, ghciUsagePath, topDir, toolDir, + ghcUsagePath, ghciUsagePath, topDir, libDir, toolDir, versionedAppDir, versionedFilePath, extraGccViaCFlags, globalPackageDatabasePath, @@ -1506,6 +1506,8 @@ ghciUsagePath :: DynFlags -> FilePath ghciUsagePath dflags = fileSettings_ghciUsagePath $ fileSettings dflags topDir :: DynFlags -> FilePath topDir dflags = fileSettings_topDir $ fileSettings dflags +libDir :: DynFlags -> FilePath +libDir dflags = fileSettings_libDir $ fileSettings dflags toolDir :: DynFlags -> Maybe FilePath toolDir dflags = fileSettings_toolDir $ fileSettings dflags extraGccViaCFlags :: DynFlags -> [String] ===================================== compiler/GHC/Driver/Session.hs ===================================== @@ -3647,7 +3647,6 @@ compilerInfo dflags -- Whether or not GHC was compiled using -prof ("GHC Profiled", showBool hostIsProfiled), ("Debug on", showBool debugIsOn), - ("LibDir", topDir dflags), -- This is always an absolute path, unlike "Relative Global Package DB" which is -- in the settings file. ("Global Package DB", globalPackageDatabasePath dflags) ===================================== compiler/GHC/Settings.hs ===================================== @@ -184,6 +184,7 @@ data FileSettings = FileSettings , fileSettings_toolDir :: Maybe FilePath -- ditto , fileSettings_topDir :: FilePath -- ditto , fileSettings_globalPackageDatabase :: FilePath + , fileSettings_libDir :: FilePath } ===================================== compiler/GHC/Settings/IO.hs ===================================== @@ -148,6 +148,8 @@ initSettings top_dir = do baseUnitId <- getSetting_raw "base unit-id" + lib_dir <- getSetting "LibDir" + return $ Settings { sGhcNameVersion = GhcNameVersion { ghcNameVersion_programName = "ghc" @@ -159,6 +161,7 @@ initSettings top_dir = do , fileSettings_ghciUsagePath = ghci_usage_msg_path , fileSettings_toolDir = mtool_dir , fileSettings_topDir = top_dir + , fileSettings_libDir = lib_dir , fileSettings_globalPackageDatabase = globalpkgdb_path } ===================================== hadrian/bindist/Makefile ===================================== @@ -90,6 +90,7 @@ lib/settings : config.mk @echo ',("RTS ways", "$(GhcRTSWays)")' >> $@ @echo ',("Relative Global Package DB", "package.conf.d")' >> $@ @echo ',("base unit-id", "$(BaseUnitId)")' >> $@ + @echo ',("LibDir", "$$topdir")' >> $@ @echo "]" >> $@ lib/targets/default.target : config.mk default.target ===================================== hadrian/src/BindistConfig.hs ===================================== @@ -1,29 +1,33 @@ module BindistConfig where -import Stage -import Oracles.Flag import Expression +import Oracles.Flag -data BindistConfig = BindistConfig { library_stage :: Stage -- ^ The stage compiler which builds the libraries - , executable_stage :: Stage -- ^ The stage compiler which builds the executables - } +data BindistConfig = BindistConfig + { -- | The stage compiler which builds the libraries + library_stage :: Stage, + -- | The stage compiler which builds the executables + executable_stage :: Stage, + -- | Which ghc-pkg to use (`targetBindist`'s + -- ghc-pkg cannot run on the build platform) + use_inplace_ghcPkg :: Bool + } -- | 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 } +normalBindist = BindistConfig {library_stage = Stage1, executable_stage = Stage1, use_inplace_ghcPkg = True} -- | 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 } +crossBindist = BindistConfig {library_stage = Stage2, executable_stage = Stage1, use_inplace_ghcPkg = True} -- | 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 } - +targetBindist :: BindistConfig +targetBindist = BindistConfig {library_stage = Stage2, executable_stage = Stage2, use_inplace_ghcPkg = False} -- | The implicit bindist config, if we don't know any better. implicitBindistConfig :: Action BindistConfig @@ -35,7 +39,7 @@ implicitBindistConfig = do return $ if cross then crossBindist else normalBindist -- | Are we building things in this stage for the final target? -buildingForTarget :: Stage -> Action Bool +buildingForTarget :: Stage -> Action Bool buildingForTarget st = do cfg <- implicitBindistConfig return $ st >= (library_stage cfg) ===================================== hadrian/src/Oracles/Flag.hs ===================================== @@ -96,7 +96,7 @@ arSupportsAtFile stage = Toolchain.arSupportsAtFile . tgtAr <$> targetStage stag targetSupportsSharedLibs :: Stage -> Action Bool targetSupportsSharedLibs stage = do windows <- isWinTarget stage - ppc_linux <- (&&) <$> anyTargetArch stage [ ArchPPC ] <*> anyTargetOs stage [ OSLinux ] + ppc_linux <- (&&) <$> anyTargetArch stage [ ArchPPC ] <*> anyTargetOs stage [ OSLinux ] solaris <- (&&) <$> anyTargetArch stage [ ArchX86 ] <*> anyTargetOs stage [ OSSolaris2 ] javascript <- anyTargetArch stage [ ArchJavaScript ] return $ not (windows || javascript || ppc_linux || solaris) ===================================== hadrian/src/Rules/BinaryDist.hs ===================================== @@ -122,8 +122,8 @@ installTo relocatable prefix = do runBuilderWithCmdOptions env (Make bindistFilesDir) ["install"] [] [] -buildBinDistDir :: FilePath -> BindistConfig -> Action () -buildBinDistDir root conf@BindistConfig{..} = do +buildBinDistDir :: FilePath -> FilePath -> BindistConfig -> Action () +buildBinDistDir dirSuffix root conf@BindistConfig{..} = do verbosity <- getVerbosity -- We 'need' all binaries and libraries @@ -153,7 +153,7 @@ buildBinDistDir root conf@BindistConfig{..} = do distDir <- Context.distDir (vanillaContext library_stage rts) let ghcBuildDir = root -/- stageString library_stage - bindistFilesDir = root -/- "bindist" -/- ghcVersionPretty + bindistFilesDir = root -/- "bindist" -/- ghcVersionPretty <> dirSuffix ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform rtsIncludeDir = distDir -/- "include" @@ -222,10 +222,16 @@ buildBinDistDir root conf@BindistConfig{..} = do -- -- N.B. the ghc-pkg executable may be prefixed with a target triple -- (c.f. #20267). - - -- Not going to work for cross - ghcPkgName <- programName (vanillaContext Stage1 ghcPkg) - cmd_ (bindistFilesDir -/- "bin" -/- ghcPkgName) ["recache", "--package-db", bindistFilesDir -/- "lib" -/- "package.conf.d" ] + -- + -- For Stage3 cross-compilers (those that are supposed to run on the target + -- platform), we have to resort to a prior stage's ghc-pkg as the final + -- stage can naturally not be executed on our current build host. + if use_inplace_ghcPkg then do + ghcPkgName <- programName (vanillaContext executable_stage ghcPkg) + cmd_ (bindistFilesDir -/- "bin" -/- ghcPkgName) ["recache", "--package-db", bindistFilesDir -/- "lib" -/- "package.conf.d" ] + else do + ghcPkgPath <- builderPath $ GhcPkg Recache library_stage + cmd_ ghcPkgPath ["recache", "--package-db", bindistFilesDir -/- "lib" -/- "package.conf.d" ] need ["docs"] @@ -316,27 +322,27 @@ bindistRules = do phony "binary-dist-dir" $ do cfg <- implicitBindistConfig - buildBinDistDir root cfg + buildBinDistDir "" root cfg + + phony "binary-dist-dir-cross" $ buildBinDistDir "" root crossBindist - phony "binary-dist-dir-cross" $ buildBinDistDir root crossBindist - -- MP: Not working yet - -- phony "binary-dist-dir-stage3" $ buildBinDistDir root targetBindist + phony "binary-dist-dir-stage3" $ buildBinDistDir "-stage3" root targetBindist let buildBinDist compressor = do win_host <- isWinHost win_target <- isWinTarget Stage2 when (win_target && win_host) (error "normal binary-dist does not work for windows targets, use `reloc-binary-dist-*` target instead.") - buildBinDistX "binary-dist-dir" "bindist" compressor - buildBinDistReloc = buildBinDistX "reloc-binary-dist-dir" "reloc-bindist" + buildBinDistX "binary-dist-dir" "bindist" "" compressor + buildBinDistReloc = buildBinDistX "reloc-binary-dist-dir" "reloc-bindist" "" - buildBinDistX :: String -> FilePath -> Compressor -> Action () - buildBinDistX target bindist_folder compressor = do + buildBinDistX :: String -> FilePath -> FilePath -> Compressor -> Action () + buildBinDistX target bindist_folder dirSuffix compressor = do need [target] version <- setting ProjectVersion targetPlatform <- setting TargetPlatformFull - let ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform + let ghcVersionPretty = "ghc-" ++ version ++ "-" ++ targetPlatform <> dirSuffix -- Finally, we create the archive <root>/bindist/ghc-X.Y.Z-platform.tar.xz tarPath <- builderPath (Tar Create) @@ -352,12 +358,12 @@ bindistRules = do phony (name <> "-dist-xz") $ mk_bindist Xz -- TODO: Generate these targets as well - phony ("binary-dist-cross") $ buildBinDistX "binary-dist-dir-cross" "bindist" Xz - phony ("binary-dist-stage3") $ buildBinDistX "binary-dist-dir-stage3" "bindist" Xz + 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 under <ghc root>/distrib/configure by 'autoreconf') - root -/- "bindist" -/- "ghc-*" -/- "configure" %> \configurePath -> do + root -/- "bindist" -/- "*ghc-*" -/- "configure" %> \configurePath -> do need ["distrib" -/- "configure.ac"] ghcRoot <- topDirectory copyFile (ghcRoot -/- "aclocal.m4") (ghcRoot -/- "distrib" -/- "aclocal.m4") @@ -372,7 +378,7 @@ bindistRules = do moveFile (ghcRoot -/- "distrib" -/- "configure") configurePath -- Generate the Makefile that enables the "make install" part - root -/- "bindist" -/- "ghc-*" -/- "Makefile" %> \makefilePath -> do + root -/- "bindist" -/- "*ghc-*" -/- "Makefile" %> \makefilePath -> do top <- topDirectory copyFile (top -/- "hadrian" -/- "bindist" -/- "Makefile") makefilePath @@ -381,7 +387,7 @@ bindistRules = do -- (see the list of files needed in the 'binary-dist' rule above, before -- creating the archive). forM_ bindistInstallFiles $ \file -> - root -/- "bindist" -/- "ghc-*" -/- file %> \dest -> do + root -/- "bindist" -/- "*ghc-*" -/- file %> \dest -> do copyFile (fixup file) dest where @@ -466,7 +472,7 @@ pkgToWrappers stage pkg = do -- These are the packages which we want to expose to the user and hence -- there are wrappers installed in the bindist. | pkg `elem` [hpcBin, haddock, hp2ps, hsc2hs, ghc, ghcPkg] - -> (:[]) <$> (programName =<< programContext Stage1 pkg) + -> (:[]) <$> (programName =<< programContext stage pkg) | otherwise -> pure [] wrapper :: Stage -> FilePath -> Action String ===================================== hadrian/src/Rules/Generate.hs ===================================== @@ -26,6 +26,7 @@ import GHC.Toolchain as Toolchain hiding (HsCpp(HsCpp)) import GHC.Platform.ArchOS import qualified Data.Set as Set import UserSettings (finalStage) +import Hadrian.Oracles.Path -- | Track this file to rebuild generated files whenever it changes. trackGenerateHs :: Expr () @@ -417,9 +418,15 @@ bindistRules = do templateRule ("distrib" -/- "configure.ac") $ mconcat [ interpolateSetting "ConfiguredEmsdkVersion" EmsdkVersion , interpolateVar "CrossCompilePrefix" $ do - crossCompiling <- interp $ getFlag CrossCompiling - tpf <- setting TargetPlatformFull - pure $ if crossCompiling then tpf <> "-" else "" + -- For a bindist, the prefix is needed only if the distributed compiler + -- is a cross-compiler (i.e., host != target in the bindist). + -- For Stage3 bindist (isStage3Cross=True), both host and target are the + -- target platform, so no prefix. For cross-compiler bindist (Stage1), + -- host != target, so we add the prefix. + -- Note: This template is shared by all bindist types, evaluated in Stage2 context. + host <- ifM isStage3Cross (setting TargetPlatformFull) (setting HostPlatformFull) + target <- setting TargetPlatformFull + pure $ if host /= target then target <> "-" else "" , interpolateVar "LeadingUnderscore" $ yesNo <$> getTarget tgtSymbolsHaveLeadingUnderscore , interpolateSetting "LlvmMaxVersion" LlvmMaxVersion , interpolateSetting "LlvmMinVersion" LlvmMinVersion @@ -429,8 +436,8 @@ bindistRules = do , interpolateVar "TablesNextToCode" $ yesNo <$> getTarget tgtTablesNextToCode , interpolateVar "TargetHasLibm" $ yesNo <$> interp (staged (buildFlag TargetHasLibm)) , interpolateVar "TargetPlatform" $ getTarget targetPlatformTriple - , interpolateVar "BuildPlatform" $ interp $ queryBuild targetPlatformTriple - , interpolateVar "HostPlatform" $ interp $ queryHost targetPlatformTriple + , interpolateVar "BuildPlatform" $ ifM isStage3Cross (getTarget targetPlatformTriple) (interp $ queryBuild targetPlatformTriple) + , interpolateVar "HostPlatform" $ ifM isStage3Cross (getTarget targetPlatformTriple) (interp $ queryHost targetPlatformTriple) , interpolateVar "TargetWordBigEndian" $ getTarget isBigEndian , interpolateVar "TargetWordSize" $ getTarget wordSize , interpolateVar "Unregisterised" $ yesNo <$> getTarget tgtUnregisterised @@ -439,13 +446,19 @@ bindistRules = do , interpolateVar "BaseUnitId" $ pkgUnitId Stage1 base , interpolateVar "GhcWithSMP" $ yesNo <$> targetSupportsSMP Stage2 , interpolateVar "TargetPlatformFull" (setting TargetPlatformFull) - , interpolateVar "BuildPlatformFull" (setting BuildPlatformFull) - , interpolateVar "HostPlatformFull" (setting HostPlatformFull) + , interpolateVar "BuildPlatformFull" $ ifM isStage3Cross (setting TargetPlatformFull) (setting BuildPlatformFull) + , interpolateVar "HostPlatformFull" $ ifM isStage3Cross (setting TargetPlatformFull) (setting HostPlatformFull) ] where interp = interpretInContext (semiEmptyTarget Stage2) getTarget = interp . queryTarget Stage2 + -- TODO: This is a hack. It should be covered by config files + isStage3Cross = do + crossCompiling <- interp $ getFlag CrossCompiling + stage <- interp getStage + pure $ if crossCompiling && stage >= Stage2 then True else False + -- | Given a 'String' replace characters '.' and '-' by underscores ('_') so that -- the resulting 'String' is a valid C preprocessor identifier. cppify :: String -> String @@ -468,6 +481,8 @@ generateSettings :: FilePath -> Expr String generateSettings settingsFile = do ctx <- getContext stage <- getStage + let ghcStage = predStage stage + isCrossStage <- expr $ crossStage ghcStage package_db_path <- expr $ do let get_pkg_db stg = packageDbPath (PackageDbLoc stg Final) @@ -487,7 +502,13 @@ generateSettings settingsFile = do Stage2 -> pkgUnitId Stage1 base Stage3 -> pkgUnitId Stage2 base + rel_lib_topDir :: FilePath <- expr $ buildRoot <&> (-/- stageString (if isCrossStage then stage else ghcStage) -/- "lib") let rel_pkg_db = makeRelativeNoSysLink (dropFileName settingsFile) package_db_path + make_absolute rel_path = do + abs_path <- liftIO (makeAbsolute rel_path) + fixAbsolutePathOnWindows abs_path + + lib_topDir :: FilePath <- expr $ make_absolute rel_lib_topDir settings <- traverse sequence $ [ ("unlit command", ("$topdir/../bin/" <>) <$> expr (programName (ctx { Context.package = unlit, Context.stage = predStage stage }))) @@ -498,6 +519,7 @@ generateSettings settingsFile = do , ("RTS ways", unwords . map show . Set.toList <$> getRtsWays) , ("Relative Global Package DB", pure rel_pkg_db) , ("base unit-id", pure base_unit_id) + , ("LibDir", pure lib_topDir) ] let showTuple (k, v) = "(" ++ show k ++ ", " ++ show v ++ ")" pure $ case settings of ===================================== hadrian/src/Rules/Test.hs ===================================== @@ -316,8 +316,10 @@ timeoutProgBuilder = do needTestsuitePackages :: Stage -> Action () needTestsuitePackages stg = do allpkgs <- packages <$> flavour - -- TODO: This used to force the packages to Stage1. Check if the tuple dance is still useful now. - libpkgs <- map (stg,) . filter isLibrary <$> allpkgs stg + isCross <- crossStage stg + -- In cross case, the libraries are one stage ahead + let libraryStage = if isCross then succStage stg else stg + libpkgs <- map (libraryStage,) . filter isLibrary <$> allpkgs libraryStage -- And the executables of the current stage exepkgs <- map (stg,) . filter isProgram <$> allpkgs stg -- Don't require lib:ghc or lib:cabal when testing the stage1 compiler ===================================== hadrian/src/Settings/Builders/RunTest.hs ===================================== @@ -105,6 +105,7 @@ allowHaveLLVM = not . (`elem` ["wasm32", "javascript"]) -- inTreeCompilerArgs :: Stage -> Action TestCompilerArgs inTreeCompilerArgs stg = do + -- TODO: executable and library stage would be clearer cross <- crossStage stg let ghcStage = succStage stg pkgCacheStage = if cross then ghcStage else stg @@ -142,7 +143,7 @@ inTreeCompilerArgs stg = do pkgConfCacheFile <- System.FilePath.normalise . (top -/-) <$> (packageDbPath (PackageDbLoc pkgCacheStage Final) <&> (-/- "package.cache")) libdir <- System.FilePath.normalise . (top -/-) - <$> stageLibPath stg + <$> stageLibPath pkgCacheStage -- For this information, we need to query ghc --info, however, that would -- require building ghc, which we don't want to do here. Therefore, the ===================================== validate-riscv-bindist.sh ===================================== @@ -0,0 +1,184 @@ +#!/usr/bin/env bash +# Script to validate that only RISC-V binaries, libraries, and target strings +# are present in _build/bindist/stage3-* directories + +set -e + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +ERRORS=0 +WARNINGS=0 + +echo "=== RISC-V Bindist Validation Script ===" +echo "" + +# Find all stage3-* directories +STAGE3_DIRS=$(find _build/bindist -maxdepth 1 -name "stage3-*" -type d 2>/dev/null || true) + +if [ -z "$STAGE3_DIRS" ]; then + echo -e "${YELLOW}Warning: No stage3-* directories found in _build/bindist/${NC}" + exit 1 +fi + +echo "Found stage3 directories:" +echo "$STAGE3_DIRS" +echo "" + +# Function to check if a file is a RISC-V binary/library +check_binary_arch() { + local file="$1" + + # Skip non-binary files + if ! file "$file" | grep -qE "ELF|archive"; then + return 0 + fi + + # Check architecture + local arch_info=$(file "$file") + + if echo "$arch_info" | grep -qE "RISC-V|riscv"; then + return 0 + else + echo -e "${RED}ERROR: Non-RISC-V binary/library found:${NC}" + echo " File: $file" + echo " Arch: $arch_info" + echo "" + return 1 + fi +} + +# Function to check target strings in text files +check_target_strings() { + local file="$1" + + # Skip if file is not readable or is a directory + if [ ! -f "$file" ] || [ ! -r "$file" ]; then + return 0 + fi + + # Skip binary files (ELF binaries and archives) + if file "$file" | grep -qE "ELF|archive"; then + return 0 + fi + + # Look for common non-RISC-V target patterns (case insensitive) + # Common architectures to check for: x86_64, aarch64, arm, i386, i686, powerpc, etc. + # Also check for build/host alias variables + local bad_patterns=( + "build_alias=.*x86_64" + "build_alias=.*aarch64" + "build_alias=.*i386" + "build_alias=.*i686" + "host_alias=.*x86_64" + "host_alias=.*aarch64" + "host_alias=.*i386" + "host_alias=.*i686" + "bootstrap_build=.*x86_64" + "bootstrap_build=.*aarch64" + "bootstrap_build=.*i386" + "bootstrap_build=.*i686" + "bootstrap_host=.*x86_64" + "bootstrap_host=.*aarch64" + "bootstrap_host=.*i386" + "bootstrap_host=.*i686" + ) + + local found_bad=0 + for pattern in "${bad_patterns[@]}"; do + if grep -qiE "$pattern" "$file" 2>/dev/null; then + if [ $found_bad -eq 0 ]; then + echo -e "${RED}ERROR: Non-RISC-V target string found in:${NC}" + echo " File: $file" + found_bad=1 + fi + echo " Pattern: $pattern" + # Show context (up to 3 lines) + grep -niE "$pattern" "$file" | head -3 | sed 's/^/ /' + fi + done + + if [ $found_bad -eq 1 ]; then + echo "" + return 1 + fi + + return 0 +} + +# Function to check for RISC-V references (informational) +check_riscv_presence() { + local file="$1" + + # Skip binary files for this check + if file "$file" | grep -qE "ELF|archive|executable"; then + return 0 + fi + + if [ ! -f "$file" ] || [ ! -r "$file" ]; then + return 0 + fi + + # Check if it's a text file + if ! file "$file" | grep -qE "text|ASCII|UTF-8|script"; then + return 0 + fi + + # Look for RISC-V patterns + if grep -qiE "riscv|risc-v" "$file" 2>/dev/null; then + return 0 + fi + + return 1 +} + +echo "=== Checking binaries and libraries for architecture ===" +echo "" + +for dir in $STAGE3_DIRS; do + echo "Scanning: $dir" + + # Find all ELF binaries and archives + while IFS= read -r -d '' file; do + if ! check_binary_arch "$file"; then + ((ERRORS++)) + fi + done < <(find "$dir" -type f -executable -print0 2>/dev/null) + + # Also check .a and .so files + while IFS= read -r -d '' file; do + if ! check_binary_arch "$file"; then + ((ERRORS++)) + fi + done < <(find "$dir" -type f \( -name "*.a" -o -name "*.so" -o -name "*.so.*" \) -print0 2>/dev/null) +done + +echo "" +echo "=== Checking text files for non-RISC-V target strings ===" +echo "" + +for dir in $STAGE3_DIRS; do + echo "Scanning: $dir" + + # Check common configuration and script files + while IFS= read -r -d '' file; do + if ! check_target_strings "$file"; then + ((ERRORS++)) + fi + done < <(find "$dir" -type f \( -name "*.conf" -o -name "*.config" -o -name "*.sh" -o -name "*.txt" -o -name "*.cabal" -o -name "*.mk" -o -name "Makefile" -o -name "configure" \) -print0 2>/dev/null) +done + +echo "" +echo "=== Summary ===" +echo "" + +if [ $ERRORS -eq 0 ]; then + echo -e "${GREEN}✓ All checks passed! Only RISC-V binaries/libraries and target strings found.${NC}" + exit 0 +else + echo -e "${RED}✗ Found $ERRORS error(s)${NC}" + echo -e "${RED}Non-RISC-V content detected in stage3 bindist directories!${NC}" + exit 1 +fi View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c52a9b511ff993064098aa43e4fd95a... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/c52a9b511ff993064098aa43e4fd95a... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Sven Tennie (@supersven)