Sven Tennie pushed to branch wip/supersven/libDir-setting at Glasgow Haskell Compiler / GHC
Commits:
-
bec88f8b
by Sven Tennie at 2026-05-03T10:46:22+02:00
8 changed files:
- + changelog.d/libdir-setting
- 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/src/Rules/BinaryDist.hs
- hadrian/src/Rules/Generate.hs
Changes:
| 1 | +section: packaging
|
|
| 2 | +synopsis: Added a new optional configuration setting for `LibDir` to support inplace
|
|
| 3 | + stage2 cross-compilers where binaries and libraries are in different stage
|
|
| 4 | + directories.
|
|
| 5 | +issues: #19174
|
|
| 6 | +mrs: !15716
|
|
| 7 | + |
|
| 8 | +description: {
|
|
| 9 | + Previously, the `libDir` was always derived from `topDir`, which won't work
|
|
| 10 | + for inplace stage2 cross-compilers where executables are in `_build/stage1/`
|
|
| 11 | + and libraries are in `_build/stage2/`. Now, `LibDir` can be set, but is by
|
|
| 12 | + default derived from `topDir`. This facilitates the mentioned behaviour
|
|
| 13 | + while keeping the binary distribution code relocatable. This is a refactoring
|
|
| 14 | + step that does not change actual behaviour.
|
|
| 15 | +} |
| ... | ... | @@ -17,8 +17,8 @@ import System.Directory |
| 17 | 17 | |
| 18 | 18 | initInterpOpts :: DynFlags -> IO InterpOpts
|
| 19 | 19 | initInterpOpts dflags = do
|
| 20 | - wasm_dyld <- makeAbsolute $ topDir dflags </> "dyld.mjs"
|
|
| 21 | - js_interp <- makeAbsolute $ topDir dflags </> "ghc-interp.js"
|
|
| 20 | + wasm_dyld <- makeAbsolute $ libDir dflags </> "dyld.mjs"
|
|
| 21 | + js_interp <- makeAbsolute $ libDir dflags </> "ghc-interp.js"
|
|
| 22 | 22 | pure $ InterpOpts
|
| 23 | 23 | { interpExternal = gopt Opt_ExternalInterpreter dflags
|
| 24 | 24 | , interpProg = pgm_i dflags
|
| ... | ... | @@ -60,7 +60,7 @@ module GHC.Driver.DynFlags ( |
| 60 | 60 | |
| 61 | 61 | -- ** System tool settings and locations
|
| 62 | 62 | programName, projectVersion,
|
| 63 | - ghcUsagePath, ghciUsagePath, topDir, toolDir,
|
|
| 63 | + ghcUsagePath, ghciUsagePath, topDir, libDir, toolDir,
|
|
| 64 | 64 | versionedAppDir, versionedFilePath,
|
| 65 | 65 | extraGccViaCFlags, globalPackageDatabasePath,
|
| 66 | 66 | |
| ... | ... | @@ -1508,6 +1508,8 @@ ghciUsagePath :: DynFlags -> FilePath |
| 1508 | 1508 | ghciUsagePath dflags = fileSettings_ghciUsagePath $ fileSettings dflags
|
| 1509 | 1509 | topDir :: DynFlags -> FilePath
|
| 1510 | 1510 | topDir dflags = fileSettings_topDir $ fileSettings dflags
|
| 1511 | +libDir :: DynFlags -> FilePath
|
|
| 1512 | +libDir dflags = fileSettings_libDir $ fileSettings dflags
|
|
| 1511 | 1513 | toolDir :: DynFlags -> Maybe FilePath
|
| 1512 | 1514 | toolDir dflags = fileSettings_toolDir $ fileSettings dflags
|
| 1513 | 1515 | extraGccViaCFlags :: DynFlags -> [String]
|
| ... | ... | @@ -3548,9 +3548,9 @@ compilerInfo dflags |
| 3548 | 3548 | ("Project name", cProjectName)
|
| 3549 | 3549 | -- Next come the settings, so anything else can be overridden
|
| 3550 | 3550 | -- in the settings file (as "lookup" uses the first match for the
|
| 3551 | - -- key)
|
|
| 3551 | + -- key). We filter out LibDir from rawSettings to avoid duplication.
|
|
| 3552 | 3552 | : map (fmap expandDirectories)
|
| 3553 | - (rawSettings dflags)
|
|
| 3553 | + (filter ((/= "LibDir") . fst) (rawSettings dflags))
|
|
| 3554 | 3554 | ++
|
| 3555 | 3555 | [("C compiler command", queryCmd $ ccProgram . tgtCCompiler),
|
| 3556 | 3556 | ("C compiler flags", queryFlags $ ccProgram . tgtCCompiler),
|
| ... | ... | @@ -3651,7 +3651,7 @@ compilerInfo dflags |
| 3651 | 3651 | -- Whether or not GHC was compiled using -prof
|
| 3652 | 3652 | ("GHC Profiled", showBool hostIsProfiled),
|
| 3653 | 3653 | ("Debug on", showBool debugIsOn),
|
| 3654 | - ("LibDir", topDir dflags),
|
|
| 3654 | + ("LibDir", libDir dflags),
|
|
| 3655 | 3655 | -- This is always an absolute path, unlike "Relative Global Package DB" which is
|
| 3656 | 3656 | -- in the settings file.
|
| 3657 | 3657 | ("Global Package DB", globalPackageDatabasePath dflags)
|
| ... | ... | @@ -184,6 +184,7 @@ data FileSettings = FileSettings |
| 184 | 184 | , fileSettings_toolDir :: Maybe FilePath -- ditto
|
| 185 | 185 | , fileSettings_topDir :: FilePath -- ditto
|
| 186 | 186 | , fileSettings_globalPackageDatabase :: FilePath
|
| 187 | + , fileSettings_libDir :: FilePath
|
|
| 187 | 188 | }
|
| 188 | 189 | |
| 189 | 190 |
| ... | ... | @@ -28,6 +28,7 @@ import GHC.Toolchain.Program |
| 28 | 28 | import GHC.Toolchain
|
| 29 | 29 | import GHC.Data.Maybe
|
| 30 | 30 | import Data.Bifunctor (Bifunctor(second))
|
| 31 | +import Data.Either (fromRight)
|
|
| 31 | 32 | |
| 32 | 33 | data SettingsError
|
| 33 | 34 | = SettingsError_MissingData String
|
| ... | ... | @@ -148,6 +149,13 @@ initSettings top_dir = do |
| 148 | 149 | |
| 149 | 150 | baseUnitId <- getSetting_raw "base unit-id"
|
| 150 | 151 | |
| 152 | + -- LibDir is optional. If not set, derive it from topDir. This allows
|
|
| 153 | + -- bindists to work without explicitly setting LibDir, but gives us the
|
|
| 154 | + -- option to override it for inplace test compilers (the "stage2
|
|
| 155 | + -- cross-compiler" scenario).
|
|
| 156 | + let lib_dir = fromRight top_dir $
|
|
| 157 | + getRawFilePathSetting top_dir settingsFile mySettings "LibDir"
|
|
| 158 | + |
|
| 151 | 159 | return $ Settings
|
| 152 | 160 | { sGhcNameVersion = GhcNameVersion
|
| 153 | 161 | { ghcNameVersion_programName = "ghc"
|
| ... | ... | @@ -159,6 +167,7 @@ initSettings top_dir = do |
| 159 | 167 | , fileSettings_ghciUsagePath = ghci_usage_msg_path
|
| 160 | 168 | , fileSettings_toolDir = mtool_dir
|
| 161 | 169 | , fileSettings_topDir = top_dir
|
| 170 | + , fileSettings_libDir = lib_dir
|
|
| 162 | 171 | , fileSettings_globalPackageDatabase = globalpkgdb_path
|
| 163 | 172 | }
|
| 164 | 173 |
| ... | ... | @@ -14,6 +14,7 @@ import qualified System.Directory.Extra as IO |
| 14 | 14 | import Data.Either
|
| 15 | 15 | import qualified Data.Set as Set
|
| 16 | 16 | import Oracles.Flavour
|
| 17 | +import Rules.Generate (generateSettings)
|
|
| 17 | 18 | |
| 18 | 19 | {-
|
| 19 | 20 | Note [Binary distributions]
|
| ... | ... | @@ -218,6 +219,16 @@ bindistRules = do |
| 218 | 219 | IO.createFileLink version_prog versioned_runhaskell_path
|
| 219 | 220 | |
| 220 | 221 | copyDirectory (ghcBuildDir -/- "lib") bindistFilesDir
|
| 222 | + |
|
| 223 | + -- Regenerate settings file without LibDir. For bindists, LibDir should
|
|
| 224 | + -- be derived from topdir at runtime such that the GHC binary is
|
|
| 225 | + -- relocatable.
|
|
| 226 | + let bindistSettings = bindistFilesDir -/- "lib" -/- "settings"
|
|
| 227 | + bindistContext = vanillaContext Stage1 compiler
|
|
| 228 | + bindistSettingsContent <- interpretInContext bindistContext $
|
|
| 229 | + generateSettings bindistSettings False (bindistFilesDir -/- "lib" -/- "package.conf.d")
|
|
| 230 | + writeFile' bindistSettings bindistSettingsContent
|
|
| 231 | + |
|
| 221 | 232 | copyDirectory (rtsIncludeDir) bindistFilesDir
|
| 222 | 233 | when windowsHost $ createGhcii (bindistFilesDir -/- "bin")
|
| 223 | 234 |
| 1 | 1 | module Rules.Generate (
|
| 2 | 2 | isGeneratedCmmFile, compilerDependencies, generatePackageCode,
|
| 3 | 3 | generateRules, copyRules, generatedDependencies,
|
| 4 | - templateRules
|
|
| 4 | + templateRules, generateSettings
|
|
| 5 | 5 | ) where
|
| 6 | 6 | |
| 7 | 7 | import Development.Shake.FilePath
|
| ... | ... | @@ -25,6 +25,7 @@ import Utilities |
| 25 | 25 | import GHC.Toolchain as Toolchain hiding (HsCpp(HsCpp))
|
| 26 | 26 | import GHC.Platform.ArchOS
|
| 27 | 27 | import Settings.Program (ghcWithInterpreter)
|
| 28 | +import Hadrian.Oracles.Path
|
|
| 28 | 29 | |
| 29 | 30 | -- | Track this file to rebuild generated files whenever it changes.
|
| 30 | 31 | trackGenerateHs :: Expr ()
|
| ... | ... | @@ -256,8 +257,17 @@ generateRules = do |
| 256 | 257 | |
| 257 | 258 | forM_ allStages $ \stage -> do
|
| 258 | 259 | let prefix = root -/- stageString stage -/- "lib"
|
| 259 | - go gen file = generate file (semiEmptyTarget (succStage stage)) gen
|
|
| 260 | - (prefix -/- "settings") %> \out -> go (generateSettings out) out
|
|
| 260 | + -- Stage0 compiler builds Stage1, Stage1 -> Stage2, etc.
|
|
| 261 | + buildStage = succStage stage
|
|
| 262 | + go gen file = generate file (semiEmptyTarget buildStage) gen
|
|
| 263 | + (prefix -/- "settings") %> \out -> do
|
|
| 264 | + let get_pkg_db stg = packageDbPath (PackageDbLoc stg Final)
|
|
| 265 | + pkgDb <- case buildStage of
|
|
| 266 | + Stage0 {} -> error "Unable to generate settings for stage0. This should never be reached."
|
|
| 267 | + Stage1 -> get_pkg_db Stage1
|
|
| 268 | + Stage2 -> get_pkg_db Stage1
|
|
| 269 | + Stage3 -> get_pkg_db Stage2
|
|
| 270 | + go (generateSettings out True pkgDb) out
|
|
| 261 | 271 | (prefix -/- "targets" -/- "default.target") %> \out -> go (show <$> expr getTargetTarget) out
|
| 262 | 272 | |
| 263 | 273 | where
|
| ... | ... | @@ -459,19 +469,16 @@ ghcWrapper stage = do |
| 459 | 469 | return $ unwords $ map show $ [ ghcPath ]
|
| 460 | 470 | ++ [ "$@" ]
|
| 461 | 471 | |
| 462 | -generateSettings :: FilePath -> Expr String
|
|
| 463 | -generateSettings settingsFile = do
|
|
| 472 | +-- | Generate settings file, optionally including @LibDir@.
|
|
| 473 | +--
|
|
| 474 | +-- @pkgDb@: absolute path to the package DB for the @"Relative Global Package
|
|
| 475 | +-- DB"@ setting. Callers determine the correct path (in-tree or bindist). For
|
|
| 476 | +-- bindists, we omit @LibDir@ so it defaults to @topDir@ at runtime.
|
|
| 477 | +generateSettings :: FilePath -> Bool -> FilePath -> Expr String
|
|
| 478 | +generateSettings settingsFile includeLibDir package_db_path = do
|
|
| 464 | 479 | ctx <- getContext
|
| 465 | 480 | stage <- getStage
|
| 466 | 481 | |
| 467 | - package_db_path <- expr $ do
|
|
| 468 | - let get_pkg_db stg = packageDbPath (PackageDbLoc stg Final)
|
|
| 469 | - case stage of
|
|
| 470 | - Stage0 {} -> error "Unable to generate settings for stage0"
|
|
| 471 | - Stage1 -> get_pkg_db Stage1
|
|
| 472 | - Stage2 -> get_pkg_db Stage1
|
|
| 473 | - Stage3 -> get_pkg_db Stage2
|
|
| 474 | - |
|
| 475 | 482 | -- The unit-id of the base package which is always linked against (#25382)
|
| 476 | 483 | base_unit_id <- expr $ do
|
| 477 | 484 | case stage of
|
| ... | ... | @@ -481,14 +488,26 @@ generateSettings settingsFile = do |
| 481 | 488 | Stage3 -> pkgUnitId Stage2 base
|
| 482 | 489 | |
| 483 | 490 | let rel_pkg_db = makeRelativeNoSysLink (dropFileName settingsFile) package_db_path
|
| 491 | + make_absolute rel_path = do
|
|
| 492 | + abs_path <- liftIO (makeAbsolute rel_path)
|
|
| 493 | + fixAbsolutePathOnWindows abs_path
|
|
| 494 | + |
|
| 495 | + -- E.g. the Stage2 compiler lives in _build/stage1
|
|
| 496 | + -- So, we need to decrement the stage to get the correct directory
|
|
| 497 | + stage_dir_stage = predStage stage
|
|
| 498 | + |
|
| 499 | + rel_lib_topDir :: FilePath <- expr $ stageLibPath stage_dir_stage
|
|
| 500 | + lib_topDir :: FilePath <- expr $ make_absolute rel_lib_topDir
|
|
| 484 | 501 | |
| 485 | 502 | settings <- traverse sequence $
|
| 486 | - [ ("unlit command", ("$topdir/../bin/" <>) <$> expr (programName (ctx { Context.package = unlit })))
|
|
| 487 | - , ("Use interpreter", expr $ yesNo <$> ghcWithInterpreter (predStage stage))
|
|
| 488 | - , ("RTS ways", escapeArgs . map show . Set.toList <$> getRtsWays)
|
|
| 489 | - , ("Relative Global Package DB", pure rel_pkg_db)
|
|
| 490 | - , ("base unit-id", pure base_unit_id)
|
|
| 491 | - ]
|
|
| 503 | + [ ("unlit command", ("$topdir/../bin/" <>) <$> expr (programName (ctx { Context.package = unlit })))
|
|
| 504 | + , ("Use interpreter", expr $ yesNo <$> ghcWithInterpreter (predStage stage))
|
|
| 505 | + , ("RTS ways", escapeArgs . map show . Set.toList <$> getRtsWays)
|
|
| 506 | + , ("Relative Global Package DB", pure rel_pkg_db)
|
|
| 507 | + , ("base unit-id", pure base_unit_id)
|
|
| 508 | + ]
|
|
| 509 | + ++ ([("LibDir", pure lib_topDir) | includeLibDir])
|
|
| 510 | + |
|
| 492 | 511 | let showTuple (k, v) = "(" ++ show k ++ ", " ++ show v ++ ")"
|
| 493 | 512 | pure $ case settings of
|
| 494 | 513 | [] -> "[]"
|