Skip to content

Commit

Permalink
Refactor the core component building logic
Browse files Browse the repository at this point in the history
1. Refactors the duplicated `buildExtraSources` function from `gbuild` and
    `buildOrReplLib` into a standalone monadic computation in the context of
    building a component. This refactor allows
    us to share the code for building an extra source amongst the two
    functions.

2. Creates a new module Distribution.Simple.GHC.Build.Modules which, in the
    same spirit as ...GHC.Build.ExtraModules, defines an action which builds
    all the Haskell modules of the component being built.

    This function clarifies and re-implements the logic of building Haskell
    modules in the different possible ways, while accounting for
    Template Haskell special "way requirements", which was previously
    duplicated in a non-obvious manner in gbuild and buildOrReplLib.

    The Note [Building Haskell modules accounting for TH] in that module
    explains the big picture, and the implementation is re-done in light of
    it.

3. Re-work the linker invocations, focusing on preserving existing
behaviour before simplifying or fixing bugs any further.

Fixes haskell#9389.
  • Loading branch information
alt-romes authored and Mikolaj committed Jan 29, 2024
1 parent 7b4d1b1 commit acd31e5
Show file tree
Hide file tree
Showing 15 changed files with 1,900 additions and 1,755 deletions.
7 changes: 5 additions & 2 deletions Cabal/Cabal.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ library
Distribution.Simple
Distribution.Simple.Bench
Distribution.Simple.Build
Distribution.Simple.Build.Inputs
Distribution.Simple.Build.Macros
Distribution.Simple.Build.PackageInfoModule
Distribution.Simple.Build.PathsModule
Expand Down Expand Up @@ -332,8 +333,10 @@ library
Distribution.Simple.Build.PackageInfoModule.Z
Distribution.Simple.Build.PathsModule.Z
Distribution.Simple.GHC.Build
Distribution.Simple.GHC.BuildOrRepl
Distribution.Simple.GHC.BuildGeneric
Distribution.Simple.GHC.Build.ExtraSources
Distribution.Simple.GHC.Build.Link
Distribution.Simple.GHC.Build.Modules
Distribution.Simple.GHC.Build.Utils
Distribution.Simple.GHC.EnvironmentParser
Distribution.Simple.GHC.Internal
Distribution.Simple.GHC.ImplInfo
Expand Down
103 changes: 53 additions & 50 deletions Cabal/src/Distribution/Simple/Build.hs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ build pkg_descr lbi flags suffixes = do
NoFlag -> Serial
mb_ipi <-
buildComponent
verbosity
flags
par_strat
pkg_descr
lbi'
Expand Down Expand Up @@ -301,7 +301,7 @@ repl pkg_descr lbi flags suffixes args = do
lbi' = lbiForComponent comp lbi
preBuildComponent verbosity lbi subtarget
buildComponent
verbosity
mempty{buildVerbosity = toFlag verbosity}
NoFlag
pkg_descr
lbi'
Expand All @@ -316,9 +316,8 @@ repl pkg_descr lbi flags suffixes args = do
let clbi = targetCLBI target
comp = targetComponent target
lbi' = lbiForComponent comp lbi
replFlags = replReplOptions flags
preBuildComponent verbosity lbi target
replComponent replFlags verbosity pkg_descr lbi' suffixes comp clbi distPref
replComponent flags verbosity pkg_descr lbi' suffixes comp clbi distPref

-- | Start an interpreter without loading any package files.
startInterpreter
Expand All @@ -335,7 +334,7 @@ startInterpreter verbosity programDb comp platform packageDBs =
_ -> dieWithException verbosity REPLNotSupported

buildComponent
:: Verbosity
:: BuildFlags
-> Flag ParStrat
-> PackageDescription
-> LocalBuildInfo
Expand All @@ -344,12 +343,12 @@ buildComponent
-> ComponentLocalBuildInfo
-> FilePath
-> IO (Maybe InstalledPackageInfo)
buildComponent verbosity _ _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ =
dieWithException verbosity $ NoSupportBuildingTestSuite tt
buildComponent verbosity _ _ _ _ (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) _ _ =
dieWithException verbosity $ NoSupportBuildingBenchMark tt
buildComponent flags _ _ _ _ (CTest TestSuite{testInterface = TestSuiteUnsupported tt}) _ _ =
dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingTestSuite tt
buildComponent flags _ _ _ _ (CBench Benchmark{benchmarkInterface = BenchmarkUnsupported tt}) _ _ =
dieWithException (fromFlag $ buildVerbosity flags) $ NoSupportBuildingBenchMark tt
buildComponent
verbosity
flags
numJobs
pkg_descr
lbi0
Expand All @@ -364,6 +363,7 @@ buildComponent
-- built.
distPref =
do
let verbosity = fromFlag $ buildVerbosity flags
pwd <- getCurrentDirectory
let (pkg, lib, libClbi, lbi, ipi, exe, exeClbi) =
testSuiteLibV09AsLibAndExe pkg_descr test clbi lbi0 distPref pwd
Expand All @@ -378,7 +378,7 @@ buildComponent
(maybeComponentInstantiatedWith clbi)
let libbi = libBuildInfo lib
lib' = lib{libBuildInfo = addSrcDir (addExtraOtherModules libbi generatedExtras) genDir}
buildLib verbosity numJobs pkg lbi lib' libClbi
buildLib flags numJobs pkg lbi lib' libClbi
-- NB: need to enable multiple instances here, because on 7.10+
-- the package name is the same as the library, and we still
-- want the registration to go through.
Expand All @@ -399,7 +399,7 @@ buildComponent
buildExe verbosity numJobs pkg_descr lbi exe' exeClbi
return Nothing -- Can't depend on test suite
buildComponent
verbosity
flags
numJobs
pkg_descr
lbi
Expand All @@ -408,6 +408,7 @@ buildComponent
clbi
distPref =
do
let verbosity = fromFlag $ buildVerbosity flags
preprocessComponent pkg_descr comp lbi clbi False verbosity suffixes
extras <- preprocessExtras verbosity comp lbi
setupMessage'
Expand All @@ -430,7 +431,7 @@ buildComponent
libbi
}

buildLib verbosity numJobs pkg_descr lbi lib' clbi
buildLib flags numJobs pkg_descr lbi lib' clbi

let oneComponentRequested (OneComponentRequestedSpec _) = True
oneComponentRequested _ = False
Expand Down Expand Up @@ -573,7 +574,7 @@ addSrcDir bi extra = bi{hsSourceDirs = new}
new = ordNub (unsafeMakeSymbolicPath extra : hsSourceDirs bi)

replComponent
:: ReplOptions
:: ReplFlags
-> Verbosity
-> PackageDescription
-> LocalBuildInfo
Expand Down Expand Up @@ -604,7 +605,7 @@ replComponent
extras <- preprocessExtras verbosity comp lbi
let libbi = libBuildInfo lib
lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}}
replLib replFlags verbosity pkg lbi lib' libClbi
replLib replFlags pkg lbi lib' libClbi
replComponent
replFlags
verbosity
Expand All @@ -621,23 +622,23 @@ replComponent
CLib lib -> do
let libbi = libBuildInfo lib
lib' = lib{libBuildInfo = libbi{cSources = cSources libbi ++ extras}}
replLib replFlags verbosity pkg_descr lbi lib' clbi
replLib replFlags pkg_descr lbi lib' clbi
CFLib flib ->
replFLib replFlags verbosity pkg_descr lbi flib clbi
replFLib replFlags pkg_descr lbi flib clbi
CExe exe -> do
let ebi = buildInfo exe
exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}}
replExe replFlags verbosity pkg_descr lbi exe' clbi
replExe replFlags pkg_descr lbi exe' clbi
CTest test@TestSuite{testInterface = TestSuiteExeV10{}} -> do
let exe = testSuiteExeV10AsExe test
let ebi = buildInfo exe
exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}}
replExe replFlags verbosity pkg_descr lbi exe' clbi
replExe replFlags pkg_descr lbi exe' clbi
CBench bm@Benchmark{benchmarkInterface = BenchmarkExeV10{}} -> do
let exe = benchmarkExeV10asExe bm
let ebi = buildInfo exe
exe' = exe{buildInfo = ebi{cSources = cSources ebi ++ extras}}
replExe replFlags verbosity pkg_descr lbi exe' clbi
replExe replFlags pkg_descr lbi exe' clbi
#if __GLASGOW_HASKELL__ < 811
-- silence pattern-match warnings prior to GHC 9.0
_ -> error "impossible"
Expand Down Expand Up @@ -822,20 +823,21 @@ addInternalBuildTools pkg lbi bi progs =
-- TODO: build separate libs in separate dirs so that we can build
-- multiple libs, e.g. for 'LibTest' library-style test suites
buildLib
:: Verbosity
:: BuildFlags
-> Flag ParStrat
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
buildLib verbosity numJobs pkg_descr lbi lib clbi =
case compilerFlavor (compiler lbi) of
GHC -> GHC.buildLib verbosity numJobs pkg_descr lbi lib clbi
GHCJS -> GHCJS.buildLib verbosity numJobs pkg_descr lbi lib clbi
UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi
HaskellSuite{} -> HaskellSuite.buildLib verbosity pkg_descr lbi lib clbi
_ -> dieWithException verbosity BuildingNotSupportedWithCompiler
buildLib flags numJobs pkg_descr lbi lib clbi =
let verbosity = fromFlag $ buildVerbosity flags
in case compilerFlavor (compiler lbi) of
GHC -> GHC.buildLib flags numJobs pkg_descr lbi lib clbi
GHCJS -> GHCJS.buildLib verbosity numJobs pkg_descr lbi lib clbi
UHC -> UHC.buildLib verbosity pkg_descr lbi lib clbi
HaskellSuite{} -> HaskellSuite.buildLib verbosity pkg_descr lbi lib clbi
_ -> dieWithException verbosity BuildingNotSupportedWithCompiler

-- | Build a foreign library
--
Expand Down Expand Up @@ -870,47 +872,48 @@ buildExe verbosity numJobs pkg_descr lbi exe clbi =
_ -> dieWithException verbosity BuildingNotSupportedWithCompiler

replLib
:: ReplOptions
-> Verbosity
:: ReplFlags
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
replLib replFlags verbosity pkg_descr lbi lib clbi =
case compilerFlavor (compiler lbi) of
-- 'cabal repl' doesn't need to support 'ghc --make -j', so we just pass
-- NoFlag as the numJobs parameter.
GHC -> GHC.replLib replFlags verbosity NoFlag pkg_descr lbi lib clbi
GHCJS -> GHCJS.replLib (replOptionsFlags replFlags) verbosity NoFlag pkg_descr lbi lib clbi
_ -> dieWithException verbosity REPLNotSupported
replLib replFlags pkg_descr lbi lib clbi =
let verbosity = fromFlag $ replVerbosity replFlags
opts = replReplOptions replFlags
in case compilerFlavor (compiler lbi) of
-- 'cabal repl' doesn't need to support 'ghc --make -j', so we just pass
-- NoFlag as the numJobs parameter.
GHC -> GHC.replLib replFlags NoFlag pkg_descr lbi lib clbi
GHCJS -> GHCJS.replLib (replOptionsFlags opts) verbosity NoFlag pkg_descr lbi lib clbi
_ -> dieWithException verbosity REPLNotSupported

replExe
:: ReplOptions
-> Verbosity
:: ReplFlags
-> PackageDescription
-> LocalBuildInfo
-> Executable
-> ComponentLocalBuildInfo
-> IO ()
replExe replFlags verbosity pkg_descr lbi exe clbi =
case compilerFlavor (compiler lbi) of
GHC -> GHC.replExe replFlags verbosity NoFlag pkg_descr lbi exe clbi
GHCJS -> GHCJS.replExe (replOptionsFlags replFlags) verbosity NoFlag pkg_descr lbi exe clbi
_ -> dieWithException verbosity REPLNotSupported
replExe flags pkg_descr lbi exe clbi =
let verbosity = fromFlag $ replVerbosity flags
in case compilerFlavor (compiler lbi) of
GHC -> GHC.replExe flags NoFlag pkg_descr lbi exe clbi
GHCJS -> GHCJS.replExe (replOptionsFlags $ replReplOptions flags) verbosity NoFlag pkg_descr lbi exe clbi
_ -> dieWithException verbosity REPLNotSupported

replFLib
:: ReplOptions
-> Verbosity
:: ReplFlags
-> PackageDescription
-> LocalBuildInfo
-> ForeignLib
-> ComponentLocalBuildInfo
-> IO ()
replFLib replFlags verbosity pkg_descr lbi exe clbi =
case compilerFlavor (compiler lbi) of
GHC -> GHC.replFLib replFlags verbosity NoFlag pkg_descr lbi exe clbi
_ -> dieWithException verbosity REPLNotSupported
replFLib flags pkg_descr lbi exe clbi =
let verbosity = fromFlag $ replVerbosity flags
in case compilerFlavor (compiler lbi) of
GHC -> GHC.replFLib flags NoFlag pkg_descr lbi exe clbi
_ -> dieWithException verbosity REPLNotSupported

-- | Pre-build steps for a component: creates the autogenerated files
-- for a particular configured component.
Expand Down
74 changes: 74 additions & 0 deletions Cabal/src/Distribution/Simple/Build/Inputs.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE PatternSynonyms #-}

module Distribution.Simple.Build.Inputs
( -- * Inputs of actions for building components
PreBuildComponentInputs (..)

-- * Queries over the component being built
, buildVerbosity
, buildComponent
, buildIsLib
, buildCLBI
, buildBI
, buildCompiler

-- * Re-exports
, BuildingWhat (..)
, LocalBuildInfo (..)
, TargetInfo (..)
, buildingWhatVerbosity
, buildingWhatDistPref
)
where

import Distribution.Simple.Compiler
import Distribution.Simple.Setup (BuildingWhat (..), buildingWhatDistPref, buildingWhatVerbosity)
import Distribution.Types.BuildInfo
import Distribution.Types.Component
import Distribution.Types.ComponentLocalBuildInfo
import Distribution.Types.LocalBuildInfo
import Distribution.Types.TargetInfo
import Distribution.Verbosity

-- | The information required for a build computation which is available right
-- before building each component, i.e. the pre-build component inputs.
data PreBuildComponentInputs = PreBuildComponentInputs
{ buildingWhat :: BuildingWhat
-- ^ What kind of build are we doing?
, localBuildInfo :: LocalBuildInfo
-- ^ Information about the package
, targetInfo :: TargetInfo
-- ^ Information about an individual component
}

-- | Get the @'Verbosity'@ from the context the component being built is in.
buildVerbosity :: PreBuildComponentInputs -> Verbosity
buildVerbosity = buildingWhatVerbosity . buildingWhat

-- | Get the @'Component'@ being built.
buildComponent :: PreBuildComponentInputs -> Component
buildComponent = targetComponent . targetInfo

-- | Is the @'Component'@ being built a @'Library'@?
buildIsLib :: PreBuildComponentInputs -> Bool
buildIsLib = do
component <- buildComponent
let isLib
| CLib{} <- component = True
| otherwise = False
return isLib
{-# INLINE buildIsLib #-}

-- | Get the @'ComponentLocalBuildInfo'@ for the component being built.
buildCLBI :: PreBuildComponentInputs -> ComponentLocalBuildInfo
buildCLBI = targetCLBI . targetInfo

-- | Get the @'BuildInfo'@ of the component being built.
buildBI :: PreBuildComponentInputs -> BuildInfo
buildBI = componentBuildInfo . buildComponent

-- | Get the @'Compiler'@ being used to build the component.
buildCompiler :: PreBuildComponentInputs -> Compiler
buildCompiler = compiler . localBuildInfo
Loading

0 comments on commit acd31e5

Please sign in to comment.