{-# LANGUAGE DataKinds #-}
module Distribution.Simple.GHC.Build where
import Distribution.Compat.Prelude
import Prelude ()
import Control.Monad.IO.Class
import qualified Data.Set as Set
import Distribution.PackageDescription as PD hiding (buildInfo)
import Distribution.Simple.Build.Inputs
import Distribution.Simple.Flag (Flag)
import Distribution.Simple.GHC.Build.ExtraSources
import Distribution.Simple.GHC.Build.Link
import Distribution.Simple.GHC.Build.Modules
import Distribution.Simple.GHC.Build.Utils (withDynFLib)
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Program.Builtin (ghcProgram)
import Distribution.Simple.Program.Db (requireProgram)
import Distribution.Simple.Utils
import Distribution.Types.ComponentLocalBuildInfo (componentIsIndefinite)
import Distribution.Types.ParStrat
import Distribution.Utils.NubList (fromNubListR)
import Distribution.Utils.Path
import System.FilePath (splitDirectories)
build
:: Flag ParStrat
-> PackageDescription
-> PreBuildComponentInputs
-> IO ()
build :: Flag ParStrat
-> PackageDescription -> PreBuildComponentInputs -> IO ()
build Flag ParStrat
numJobs PackageDescription
pkg_descr PreBuildComponentInputs
pbci = do
let
verbosity :: Verbosity
verbosity = PreBuildComponentInputs -> Verbosity
buildVerbosity PreBuildComponentInputs
pbci
component :: Component
component = PreBuildComponentInputs -> Component
buildComponent PreBuildComponentInputs
pbci
isLib :: Bool
isLib = PreBuildComponentInputs -> Bool
buildIsLib PreBuildComponentInputs
pbci
lbi :: LocalBuildInfo
lbi = PreBuildComponentInputs -> LocalBuildInfo
localBuildInfo PreBuildComponentInputs
pbci
clbi :: ComponentLocalBuildInfo
clbi = PreBuildComponentInputs -> ComponentLocalBuildInfo
buildCLBI PreBuildComponentInputs
pbci
mbWorkDir :: Maybe (SymbolicPath CWD ('Dir Pkg))
mbWorkDir = LocalBuildInfo -> Maybe (SymbolicPath CWD ('Dir Pkg))
mbWorkDirLBI LocalBuildInfo
lbi
i :: SymbolicPathX allowAbsolute Pkg to -> FilePath
i = LocalBuildInfo -> SymbolicPathX allowAbsolute Pkg to -> FilePath
forall (allowAbsolute :: AllowAbsolute) (to :: FileOrDir).
LocalBuildInfo -> SymbolicPathX allowAbsolute Pkg to -> FilePath
interpretSymbolicPathLBI LocalBuildInfo
lbi
let targetDir0 :: SymbolicPath Pkg ('Dir Build)
targetDir0 :: SymbolicPath Pkg ('Dir Build)
targetDir0 = LocalBuildInfo
-> ComponentLocalBuildInfo -> SymbolicPath Pkg ('Dir Build)
componentBuildDir LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi
buildTargetDir0 :: SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir0 :: SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir0
| Bool
isLib = SymbolicPath Pkg ('Dir Build) -> SymbolicPath Pkg ('Dir Artifacts)
forall (allowAbsolute :: AllowAbsolute) from (to1 :: FileOrDir)
(to2 :: FileOrDir).
SymbolicPathX allowAbsolute from to1
-> SymbolicPathX allowAbsolute from to2
coerceSymbolicPath SymbolicPath Pkg ('Dir Build)
targetDir0
| FilePath
targetDirName : [FilePath]
_ <- [FilePath] -> [FilePath]
forall a. [a] -> [a]
reverse ([FilePath] -> [FilePath]) -> [FilePath] -> [FilePath]
forall a b. (a -> b) -> a -> b
$ FilePath -> [FilePath]
splitDirectories (FilePath -> [FilePath]) -> FilePath -> [FilePath]
forall a b. (a -> b) -> a -> b
$ SymbolicPath Pkg ('Dir Build) -> FilePath
forall (allowAbsolute :: AllowAbsolute) from (to :: FileOrDir).
SymbolicPathX allowAbsolute from to -> FilePath
getSymbolicPath SymbolicPath Pkg ('Dir Build)
targetDir0 =
SymbolicPath Pkg ('Dir Build)
-> SymbolicPathX 'AllowAbsolute Pkg ('Dir Any)
forall (allowAbsolute :: AllowAbsolute) from (to1 :: FileOrDir)
(to2 :: FileOrDir).
SymbolicPathX allowAbsolute from to1
-> SymbolicPathX allowAbsolute from to2
coerceSymbolicPath SymbolicPath Pkg ('Dir Build)
targetDir0 SymbolicPathX 'AllowAbsolute Pkg ('Dir Any)
-> RelativePath Any ('Dir Artifacts)
-> SymbolicPath Pkg ('Dir Artifacts)
forall p q r. PathLike p q r => p -> q -> r
</> FilePath -> RelativePath Any ('Dir Artifacts)
forall from (to :: FileOrDir).
HasCallStack =>
FilePath -> RelativePath from to
makeRelativePathEx (FilePath
targetDirName FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"-tmp")
| Bool
otherwise = FilePath -> SymbolicPath Pkg ('Dir Artifacts)
forall a. HasCallStack => FilePath -> a
error FilePath
"GHC.build: targetDir is empty"
IO () -> IO ()
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
Verbosity -> Bool -> FilePath -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ SymbolicPath Pkg ('Dir Build) -> FilePath
forall {allowAbsolute :: AllowAbsolute} {to :: FileOrDir}.
SymbolicPathX allowAbsolute Pkg to -> FilePath
i SymbolicPath Pkg ('Dir Build)
targetDir0
Verbosity -> Bool -> FilePath -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True (FilePath -> IO ()) -> FilePath -> IO ()
forall a b. (a -> b) -> a -> b
$ SymbolicPath Pkg ('Dir Artifacts) -> FilePath
forall {allowAbsolute :: AllowAbsolute} {to :: FileOrDir}.
SymbolicPathX allowAbsolute Pkg to -> FilePath
i SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir0
let targetDir :: SymbolicPath Pkg ('Dir Build)
targetDir = SymbolicPath Pkg ('Dir Build)
targetDir0
SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir <-
if Bool
isLib
then
Maybe (SymbolicPath CWD ('Dir Pkg))
-> SymbolicPath Pkg ('Dir Artifacts)
-> IO (SymbolicPath Pkg ('Dir Artifacts))
forall dir (to :: FileOrDir).
Maybe (SymbolicPath CWD ('Dir dir))
-> SymbolicPath dir to -> IO (SymbolicPath dir to)
tryMakeRelativeToWorkingDir Maybe (SymbolicPath CWD ('Dir Pkg))
mbWorkDir SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir0
else SymbolicPath Pkg ('Dir Artifacts)
-> IO (SymbolicPath Pkg ('Dir Artifacts))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir0
(ConfiguredProgram
ghcProg, ProgramDb
_) <- IO (ConfiguredProgram, ProgramDb)
-> IO (ConfiguredProgram, ProgramDb)
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ConfiguredProgram, ProgramDb)
-> IO (ConfiguredProgram, ProgramDb))
-> IO (ConfiguredProgram, ProgramDb)
-> IO (ConfiguredProgram, ProgramDb)
forall a b. (a -> b) -> a -> b
$ Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ghcProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
let
wantVanilla :: Bool
wantVanilla = if Bool
isLib then LocalBuildInfo -> Bool
withVanillaLib LocalBuildInfo
lbi else Bool
False
wantStatic :: Bool
wantStatic = if Bool
isLib then LocalBuildInfo -> Bool
withStaticLib LocalBuildInfo
lbi else Bool -> Bool
not (Bool
wantDynamic Bool -> Bool -> Bool
|| Bool
wantProf)
wantDynamic :: Bool
wantDynamic = case Component
component of
CLib{} -> LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi
CFLib ForeignLib
flib -> ForeignLib -> Bool
withDynFLib ForeignLib
flib
CExe{} -> LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi
CTest{} -> LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi
CBench{} -> LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi
wantProf :: Bool
wantProf = if Bool
isLib then LocalBuildInfo -> Bool
withProfLib LocalBuildInfo
lbi else LocalBuildInfo -> Bool
withProfExe LocalBuildInfo
lbi
wantedWays :: Set BuildWay
wantedWays =
[BuildWay] -> Set BuildWay
forall a. Ord a => [a] -> Set a
Set.fromList ([BuildWay] -> Set BuildWay) -> [BuildWay] -> Set BuildWay
forall a b. (a -> b) -> a -> b
$
(if Bool
isLib then [BuildWay] -> [BuildWay]
forall a. a -> a
id else Int -> [BuildWay] -> [BuildWay]
forall a. Int -> [a] -> [a]
take Int
1) ([BuildWay] -> [BuildWay]) -> [BuildWay] -> [BuildWay]
forall a b. (a -> b) -> a -> b
$
[BuildWay
ProfWay | Bool
wantProf]
[BuildWay] -> [BuildWay] -> [BuildWay]
forall a. Semigroup a => a -> a -> a
<> [BuildWay
DynWay | Bool
wantDynamic Bool -> Bool -> Bool
&& Bool -> Bool
not (ComponentLocalBuildInfo -> Bool
componentIsIndefinite ComponentLocalBuildInfo
clbi)]
[BuildWay] -> [BuildWay] -> [BuildWay]
forall a. Semigroup a => a -> a -> a
<> [BuildWay
StaticWay | Bool
wantStatic Bool -> Bool -> Bool
|| Bool
wantVanilla Bool -> Bool -> Bool
|| Bool -> Bool
not (Bool
wantDynamic Bool -> Bool -> Bool
|| Bool
wantProf)]
IO () -> IO ()
forall a. IO a -> IO a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> FilePath -> IO ()
info Verbosity
verbosity (FilePath
"Wanted build ways: " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ [BuildWay] -> FilePath
forall a. Show a => a -> FilePath
show (Set BuildWay -> [BuildWay]
forall a. Set a -> [a]
Set.toList Set BuildWay
wantedWays))
BuildWay -> GhcOptions
buildOpts <- Flag ParStrat
-> ConfiguredProgram
-> PackageDescription
-> SymbolicPath Pkg ('Dir Artifacts)
-> Set BuildWay
-> PreBuildComponentInputs
-> IO (BuildWay -> GhcOptions)
buildHaskellModules Flag ParStrat
numJobs ConfiguredProgram
ghcProg PackageDescription
pkg_descr SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir Set BuildWay
wantedWays PreBuildComponentInputs
pbci
NubListR (SymbolicPath Pkg 'File)
extraSources <- ConfiguredProgram
-> SymbolicPath Pkg ('Dir Artifacts)
-> PreBuildComponentInputs
-> IO (NubListR (SymbolicPath Pkg 'File))
buildAllExtraSources ConfiguredProgram
ghcProg SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir PreBuildComponentInputs
pbci
ConfiguredProgram
-> PackageDescription
-> [SymbolicPath Pkg 'File]
-> (SymbolicPath Pkg ('Dir Artifacts),
SymbolicPath Pkg ('Dir Build))
-> (Set BuildWay, BuildWay -> GhcOptions)
-> PreBuildComponentInputs
-> IO ()
linkOrLoadComponent
ConfiguredProgram
ghcProg
PackageDescription
pkg_descr
(NubListR (SymbolicPath Pkg 'File) -> [SymbolicPath Pkg 'File]
forall a. NubListR a -> [a]
fromNubListR NubListR (SymbolicPath Pkg 'File)
extraSources)
(SymbolicPath Pkg ('Dir Artifacts)
buildTargetDir, SymbolicPath Pkg ('Dir Build)
targetDir)
(Set BuildWay
wantedWays, BuildWay -> GhcOptions
buildOpts)
PreBuildComponentInputs
pbci