{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}

-----------------------------------------------------------------------------

-- |
-- Module      :  Distribution.Simple.Configure
-- Copyright   :  Isaac Jones 2003-2005
-- License     :  BSD3
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This deals with the /configure/ phase. It provides the 'configure' action
-- which is given the package description and configure flags. It then tries
-- to: configure the compiler; resolves any conditionals in the package
-- description; resolve the package dependencies; check if all the extensions
-- used by this package are supported by the compiler; check that all the build
-- tools are available (including version checks if appropriate); checks for
-- any required @pkg-config@ packages (updating the 'BuildInfo' with the
-- results)
--
-- Then based on all this it saves the info in the 'LocalBuildInfo' and writes
-- it out to the @dist\/setup-config@ file. It also displays various details to
-- the user, the amount of information displayed depending on the verbosity
-- level.
module Distribution.Simple.Configure
  ( configure
  , writePersistBuildConfig
  , getConfigStateFile
  , getPersistBuildConfig
  , checkPersistBuildConfigOutdated
  , tryGetPersistBuildConfig
  , maybeGetPersistBuildConfig
  , findDistPref
  , findDistPrefOrDefault
  , getInternalLibraries
  , computeComponentId
  , computeCompatPackageKey
  , localBuildInfoFile
  , getInstalledPackages
  , getInstalledPackagesMonitorFiles
  , getInstalledPackagesById
  , getPackageDBContents
  , configCompilerEx
  , configCompilerAuxEx
  , computeEffectiveProfiling
  , ccLdOptionsBuildInfo
  , checkForeignDeps
  , interpretPackageDbFlags
  , ConfigStateFileError (..)
  , tryGetConfigStateFile
  , platformDefines
  ) where

import Control.Monad
import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Backpack.Configure
import Distribution.Backpack.ConfiguredComponent (newPackageDepsBehaviour)
import Distribution.Backpack.DescribeUnitId
import Distribution.Backpack.Id
import Distribution.Backpack.PreExistingComponent
import qualified Distribution.Compat.Graph as Graph
import Distribution.Compat.Stack
import Distribution.Compiler
import Distribution.InstalledPackageInfo (InstalledPackageInfo)
import qualified Distribution.InstalledPackageInfo as IPI
import Distribution.Package
import Distribution.PackageDescription
import Distribution.PackageDescription.Check hiding (doesFileExist)
import Distribution.PackageDescription.Configuration
import Distribution.PackageDescription.PrettyPrint
import Distribution.Simple.BuildTarget
import Distribution.Simple.BuildToolDepends
import Distribution.Simple.Compiler
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.PackageIndex (InstalledPackageIndex, lookupUnitId)
import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.Simple.PreProcess
import Distribution.Simple.Program
import Distribution.Simple.Program.Db (lookupProgramByName, modifyProgramSearchPath, prependProgramSearchPath)
import Distribution.Simple.Setup.Common as Setup
import Distribution.Simple.Setup.Config as Setup
import Distribution.Simple.Utils
import Distribution.System
import Distribution.Types.ComponentRequestedSpec
import Distribution.Types.GivenComponent
import qualified Distribution.Types.LocalBuildConfig as LBC
import Distribution.Types.LocalBuildInfo
import Distribution.Types.PackageVersionConstraint
import Distribution.Utils.LogProgress
import Distribution.Utils.NubList
import Distribution.Verbosity
import Distribution.Version

import qualified Distribution.Simple.GHC as GHC
import qualified Distribution.Simple.GHCJS as GHCJS
import qualified Distribution.Simple.HaskellSuite as HaskellSuite
import qualified Distribution.Simple.UHC as UHC

import Control.Exception
  ( try
  )
import qualified Data.ByteString as BS
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy.Char8 as BLC8
import Data.List
  ( intersect
  , stripPrefix
  , (\\)
  )
import qualified Data.List.NonEmpty as NEL
import qualified Data.Map as Map
import Distribution.Compat.Directory
  ( doesPathExist
  , listDirectory
  )
import Distribution.Compat.Environment (lookupEnv)
import Distribution.Parsec
  ( simpleParsec
  )
import Distribution.Pretty
  ( defaultStyle
  , pretty
  , prettyShow
  )
import Distribution.Utils.Structured (structuredDecodeOrFailIO, structuredEncode)
import System.Directory
  ( canonicalizePath
  , createDirectoryIfMissing
  , doesFileExist
  , getTemporaryDirectory
  , removeFile
  )
import System.FilePath
  ( isAbsolute
  , takeDirectory
  , (</>)
  )
import System.IO
  ( hClose
  , hPutStrLn
  )
import qualified System.Info
  ( compilerName
  , compilerVersion
  )
import Text.PrettyPrint
  ( Doc
  , char
  , hsep
  , quotes
  , renderStyle
  , text
  , ($+$)
  )

import qualified Data.Maybe as M
import qualified Data.Set as Set
import qualified Distribution.Compat.NonEmptySet as NES
import Distribution.Simple.Errors
import Distribution.Types.AnnotatedId

type UseExternalInternalDeps = Bool

-- | The errors that can be thrown when reading the @setup-config@ file.
data ConfigStateFileError
  = -- | No header found.
    ConfigStateFileNoHeader
  | -- | Incorrect header.
    ConfigStateFileBadHeader
  | -- | Cannot parse file contents.
    ConfigStateFileNoParse
  | -- | No file!
    ConfigStateFileMissing
  | -- | Mismatched version.
    ConfigStateFileBadVersion
      PackageIdentifier
      PackageIdentifier
      (Either ConfigStateFileError LocalBuildInfo)
  deriving (Typeable)

-- | Format a 'ConfigStateFileError' as a user-facing error message.
dispConfigStateFileError :: ConfigStateFileError -> Doc
dispConfigStateFileError :: ConfigStateFileError -> Doc
dispConfigStateFileError ConfigStateFileError
ConfigStateFileNoHeader =
  ProgArg -> Doc
text ProgArg
"Saved package config file header is missing."
    Doc -> Doc -> Doc
<+> ProgArg -> Doc
text ProgArg
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileBadHeader =
  ProgArg -> Doc
text ProgArg
"Saved package config file header is corrupt."
    Doc -> Doc -> Doc
<+> ProgArg -> Doc
text ProgArg
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileNoParse =
  ProgArg -> Doc
text ProgArg
"Saved package config file is corrupt."
    Doc -> Doc -> Doc
<+> ProgArg -> Doc
text ProgArg
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileMissing =
  ProgArg -> Doc
text ProgArg
"Run the 'configure' command first."
dispConfigStateFileError (ConfigStateFileBadVersion PackageIdentifier
oldCabal PackageIdentifier
oldCompiler Either ConfigStateFileError LocalBuildInfo
_) =
  ProgArg -> Doc
text ProgArg
"Saved package config file is outdated:"
    Doc -> Doc -> Doc
$+$ Doc
badCabal
    Doc -> Doc -> Doc
$+$ Doc
badCompiler
    Doc -> Doc -> Doc
$+$ ProgArg -> Doc
text ProgArg
"Re-run the 'configure' command."
  where
    badCabal :: Doc
badCabal =
      ProgArg -> Doc
text ProgArg
"• the Cabal version changed from"
        Doc -> Doc -> Doc
<+> PackageIdentifier -> Doc
forall a. Pretty a => a -> Doc
pretty PackageIdentifier
oldCabal
        Doc -> Doc -> Doc
<+> Doc
"to"
        Doc -> Doc -> Doc
<+> PackageIdentifier -> Doc
forall a. Pretty a => a -> Doc
pretty PackageIdentifier
currentCabalId
    badCompiler :: Doc
badCompiler
      | PackageIdentifier
oldCompiler PackageIdentifier -> PackageIdentifier -> Bool
forall a. Eq a => a -> a -> Bool
== PackageIdentifier
currentCompilerId = Doc
forall a. Monoid a => a
mempty
      | Bool
otherwise =
          ProgArg -> Doc
text ProgArg
"• the compiler changed from"
            Doc -> Doc -> Doc
<+> PackageIdentifier -> Doc
forall a. Pretty a => a -> Doc
pretty PackageIdentifier
oldCompiler
            Doc -> Doc -> Doc
<+> Doc
"to"
            Doc -> Doc -> Doc
<+> PackageIdentifier -> Doc
forall a. Pretty a => a -> Doc
pretty PackageIdentifier
currentCompilerId

instance Show ConfigStateFileError where
  show :: ConfigStateFileError -> ProgArg
show = Style -> Doc -> ProgArg
renderStyle Style
defaultStyle (Doc -> ProgArg)
-> (ConfigStateFileError -> Doc) -> ConfigStateFileError -> ProgArg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ConfigStateFileError -> Doc
dispConfigStateFileError

instance Exception ConfigStateFileError

-- | Read the 'localBuildInfoFile'.  Throw an exception if the file is
-- missing, if the file cannot be read, or if the file was created by an older
-- version of Cabal.
getConfigStateFile
  :: FilePath
  -- ^ The file path of the @setup-config@ file.
  -> IO LocalBuildInfo
getConfigStateFile :: ProgArg -> IO LocalBuildInfo
getConfigStateFile ProgArg
filename = do
  exists <- ProgArg -> IO Bool
doesFileExist ProgArg
filename
  unless exists $ throwIO ConfigStateFileMissing
  -- Read the config file into a strict ByteString to avoid problems with
  -- lazy I/O, then convert to lazy because the binary package needs that.
  contents <- BS.readFile filename
  let (header, body) = BLC8.span (/= '\n') (BLC8.fromChunks [contents])

  (cabalId, compId) <- parseHeader header

  let getStoredValue = do
        result <- ByteString -> IO (Either ProgArg LocalBuildInfo)
forall a.
(Binary a, Structured a) =>
ByteString -> IO (Either ProgArg a)
structuredDecodeOrFailIO (HasCallStack => ByteString -> ByteString
ByteString -> ByteString
BLC8.tail ByteString
body)
        case result of
          Left ProgArg
_ -> ConfigStateFileError -> IO LocalBuildInfo
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ConfigStateFileError
ConfigStateFileNoParse
          Right LocalBuildInfo
x -> LocalBuildInfo -> IO LocalBuildInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return LocalBuildInfo
x
      deferErrorIfBadVersion IO LocalBuildInfo
act
        | PackageIdentifier
cabalId PackageIdentifier -> PackageIdentifier -> Bool
forall a. Eq a => a -> a -> Bool
/= PackageIdentifier
currentCabalId = do
            eResult <- IO LocalBuildInfo
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall e a. Exception e => IO a -> IO (Either e a)
try IO LocalBuildInfo
act
            throwIO $ ConfigStateFileBadVersion cabalId compId eResult
        | Bool
otherwise = IO LocalBuildInfo
act
  deferErrorIfBadVersion getStoredValue
  where
    CallStack
_ = CallStack
HasCallStack => CallStack
callStack -- TODO: attach call stack to exception

-- | Read the 'localBuildInfoFile', returning either an error or the local build
-- info.
tryGetConfigStateFile
  :: FilePath
  -- ^ The file path of the @setup-config@ file.
  -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetConfigStateFile :: ProgArg -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetConfigStateFile = IO LocalBuildInfo
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO LocalBuildInfo
 -> IO (Either ConfigStateFileError LocalBuildInfo))
-> (ProgArg -> IO LocalBuildInfo)
-> ProgArg
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgArg -> IO LocalBuildInfo
getConfigStateFile

-- | Try to read the 'localBuildInfoFile'.
tryGetPersistBuildConfig
  :: FilePath
  -- ^ The @dist@ directory path.
  -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetPersistBuildConfig :: ProgArg -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetPersistBuildConfig = IO LocalBuildInfo
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall e a. Exception e => IO a -> IO (Either e a)
try (IO LocalBuildInfo
 -> IO (Either ConfigStateFileError LocalBuildInfo))
-> (ProgArg -> IO LocalBuildInfo)
-> ProgArg
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgArg -> IO LocalBuildInfo
getPersistBuildConfig

-- | Read the 'localBuildInfoFile'. Throw an exception if the file is
-- missing, if the file cannot be read, or if the file was created by an older
-- version of Cabal.
getPersistBuildConfig
  :: FilePath
  -- ^ The @dist@ directory path.
  -> IO LocalBuildInfo
getPersistBuildConfig :: ProgArg -> IO LocalBuildInfo
getPersistBuildConfig = ProgArg -> IO LocalBuildInfo
getConfigStateFile (ProgArg -> IO LocalBuildInfo)
-> ShowS -> ProgArg -> IO LocalBuildInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
localBuildInfoFile

-- | Try to read the 'localBuildInfoFile'.
maybeGetPersistBuildConfig
  :: FilePath
  -- ^ The @dist@ directory path.
  -> IO (Maybe LocalBuildInfo)
maybeGetPersistBuildConfig :: ProgArg -> IO (Maybe LocalBuildInfo)
maybeGetPersistBuildConfig =
  (Either ConfigStateFileError LocalBuildInfo
 -> Maybe LocalBuildInfo)
-> IO (Either ConfigStateFileError LocalBuildInfo)
-> IO (Maybe LocalBuildInfo)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM ((ConfigStateFileError -> Maybe LocalBuildInfo)
-> (LocalBuildInfo -> Maybe LocalBuildInfo)
-> Either ConfigStateFileError LocalBuildInfo
-> Maybe LocalBuildInfo
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Maybe LocalBuildInfo
-> ConfigStateFileError -> Maybe LocalBuildInfo
forall a b. a -> b -> a
const Maybe LocalBuildInfo
forall a. Maybe a
Nothing) LocalBuildInfo -> Maybe LocalBuildInfo
forall a. a -> Maybe a
Just) (IO (Either ConfigStateFileError LocalBuildInfo)
 -> IO (Maybe LocalBuildInfo))
-> (ProgArg -> IO (Either ConfigStateFileError LocalBuildInfo))
-> ProgArg
-> IO (Maybe LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgArg -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetPersistBuildConfig

-- | After running configure, output the 'LocalBuildInfo' to the
-- 'localBuildInfoFile'.
writePersistBuildConfig
  :: FilePath
  -- ^ The @dist@ directory path.
  -> LocalBuildInfo
  -- ^ The 'LocalBuildInfo' to write.
  -> IO ()
writePersistBuildConfig :: ProgArg -> LocalBuildInfo -> IO ()
writePersistBuildConfig ProgArg
distPref LocalBuildInfo
lbi = do
  Bool -> ProgArg -> IO ()
createDirectoryIfMissing Bool
False ProgArg
distPref
  ProgArg -> ByteString -> IO ()
writeFileAtomic (ShowS
localBuildInfoFile ProgArg
distPref) (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$
    [ByteString] -> ByteString
BLC8.unlines [PackageIdentifier -> ByteString
showHeader PackageIdentifier
pkgId, LocalBuildInfo -> ByteString
forall a. (Binary a, Structured a) => a -> ByteString
structuredEncode LocalBuildInfo
lbi]
  where
    pkgId :: PackageIdentifier
pkgId = LocalBuildInfo -> PackageIdentifier
localPackage LocalBuildInfo
lbi

-- | Identifier of the current Cabal package.
currentCabalId :: PackageIdentifier
currentCabalId :: PackageIdentifier
currentCabalId = PackageName -> Version -> PackageIdentifier
PackageIdentifier (ProgArg -> PackageName
mkPackageName ProgArg
"Cabal") Version
cabalVersion

-- | Identifier of the current compiler package.
currentCompilerId :: PackageIdentifier
currentCompilerId :: PackageIdentifier
currentCompilerId =
  PackageName -> Version -> PackageIdentifier
PackageIdentifier
    (ProgArg -> PackageName
mkPackageName ProgArg
System.Info.compilerName)
    (Version -> Version
mkVersion' Version
System.Info.compilerVersion)

-- | Parse the @setup-config@ file header, returning the package identifiers
-- for Cabal and the compiler.
parseHeader
  :: ByteString
  -- ^ The file contents.
  -> IO (PackageIdentifier, PackageIdentifier)
parseHeader :: ByteString -> IO (PackageIdentifier, PackageIdentifier)
parseHeader ByteString
header = case ByteString -> [ByteString]
BLC8.words ByteString
header of
  [ ByteString
"Saved"
    , ByteString
"package"
    , ByteString
"config"
    , ByteString
"for"
    , ByteString
pkgId
    , ByteString
"written"
    , ByteString
"by"
    , ByteString
cabalId
    , ByteString
"using"
    , ByteString
compId
    ] ->
      IO (PackageIdentifier, PackageIdentifier)
-> ((PackageIdentifier, PackageIdentifier)
    -> IO (PackageIdentifier, PackageIdentifier))
-> Maybe (PackageIdentifier, PackageIdentifier)
-> IO (PackageIdentifier, PackageIdentifier)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (ConfigStateFileError -> IO (PackageIdentifier, PackageIdentifier)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ConfigStateFileError
ConfigStateFileBadHeader) (PackageIdentifier, PackageIdentifier)
-> IO (PackageIdentifier, PackageIdentifier)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (PackageIdentifier, PackageIdentifier)
 -> IO (PackageIdentifier, PackageIdentifier))
-> Maybe (PackageIdentifier, PackageIdentifier)
-> IO (PackageIdentifier, PackageIdentifier)
forall a b. (a -> b) -> a -> b
$ do
        _ <- ProgArg -> Maybe PackageIdentifier
forall a. Parsec a => ProgArg -> Maybe a
simpleParsec (ByteString -> ProgArg
fromUTF8LBS ByteString
pkgId) :: Maybe PackageIdentifier
        cabalId' <- simpleParsec (BLC8.unpack cabalId)
        compId' <- simpleParsec (BLC8.unpack compId)
        return (cabalId', compId')
  [ByteString]
_ -> ConfigStateFileError -> IO (PackageIdentifier, PackageIdentifier)
forall e a. (HasCallStack, Exception e) => e -> IO a
throwIO ConfigStateFileError
ConfigStateFileNoHeader

-- | Generate the @setup-config@ file header.
showHeader
  :: PackageIdentifier
  -- ^ The processed package.
  -> ByteString
showHeader :: PackageIdentifier -> ByteString
showHeader PackageIdentifier
pkgId =
  [ByteString] -> ByteString
BLC8.unwords
    [ ByteString
"Saved"
    , ByteString
"package"
    , ByteString
"config"
    , ByteString
"for"
    , ProgArg -> ByteString
toUTF8LBS (ProgArg -> ByteString) -> ProgArg -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PackageIdentifier
pkgId
    , ByteString
"written"
    , ByteString
"by"
    , ProgArg -> ByteString
BLC8.pack (ProgArg -> ByteString) -> ProgArg -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PackageIdentifier
currentCabalId
    , ByteString
"using"
    , ProgArg -> ByteString
BLC8.pack (ProgArg -> ByteString) -> ProgArg -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PackageIdentifier
currentCompilerId
    ]

-- | Check that localBuildInfoFile is up-to-date with respect to the
-- .cabal file.
checkPersistBuildConfigOutdated :: FilePath -> FilePath -> IO Bool
checkPersistBuildConfigOutdated :: ProgArg -> ProgArg -> IO Bool
checkPersistBuildConfigOutdated ProgArg
distPref ProgArg
pkg_descr_file =
  ProgArg
pkg_descr_file ProgArg -> ProgArg -> IO Bool
`moreRecentFile` ShowS
localBuildInfoFile ProgArg
distPref

-- | Get the path of @dist\/setup-config@.
localBuildInfoFile
  :: FilePath
  -- ^ The @dist@ directory path.
  -> FilePath
localBuildInfoFile :: ShowS
localBuildInfoFile ProgArg
distPref = ProgArg
distPref ProgArg -> ShowS
</> ProgArg
"setup-config"

-- -----------------------------------------------------------------------------

-- * Configuration

-- -----------------------------------------------------------------------------

-- | Return the \"dist/\" prefix, or the default prefix. The prefix is taken
-- from (in order of highest to lowest preference) the override prefix, the
-- \"CABAL_BUILDDIR\" environment variable, or the default prefix.
findDistPref
  :: FilePath
  -- ^ default \"dist\" prefix
  -> Setup.Flag FilePath
  -- ^ override \"dist\" prefix
  -> IO FilePath
findDistPref :: ProgArg -> Flag ProgArg -> IO ProgArg
findDistPref ProgArg
defDistPref Flag ProgArg
overrideDistPref = do
  envDistPref <- (Maybe ProgArg -> Flag ProgArg)
-> IO (Maybe ProgArg) -> IO (Flag ProgArg)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Maybe ProgArg -> Flag ProgArg
forall {t :: * -> *} {a}. Foldable t => Maybe (t a) -> Flag (t a)
parseEnvDistPref (ProgArg -> IO (Maybe ProgArg)
lookupEnv ProgArg
"CABAL_BUILDDIR")
  return $ fromFlagOrDefault defDistPref (mappend envDistPref overrideDistPref)
  where
    parseEnvDistPref :: Maybe (t a) -> Flag (t a)
parseEnvDistPref Maybe (t a)
env =
      case Maybe (t a)
env of
        Just t a
distPref | Bool -> Bool
not (t a -> Bool
forall a. t a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null t a
distPref) -> t a -> Flag (t a)
forall a. a -> Flag a
toFlag t a
distPref
        Maybe (t a)
_ -> Flag (t a)
forall a. Flag a
NoFlag

-- | Return the \"dist/\" prefix, or the default prefix. The prefix is taken
-- from (in order of highest to lowest preference) the override prefix, the
-- \"CABAL_BUILDDIR\" environment variable, or 'defaultDistPref' is used. Call
-- this function to resolve a @*DistPref@ flag whenever it is not known to be
-- set. (The @*DistPref@ flags are always set to a definite value before
-- invoking 'UserHooks'.)
findDistPrefOrDefault
  :: Setup.Flag FilePath
  -- ^ override \"dist\" prefix
  -> IO FilePath
findDistPrefOrDefault :: Flag ProgArg -> IO ProgArg
findDistPrefOrDefault = ProgArg -> Flag ProgArg -> IO ProgArg
findDistPref ProgArg
defaultDistPref

-- | Perform the \"@.\/setup configure@\" action.
--  Returns the @.setup-config@ file.
configure
  :: (GenericPackageDescription, HookedBuildInfo)
  -> ConfigFlags
  -> IO LocalBuildInfo
configure :: (GenericPackageDescription, HookedBuildInfo)
-> ConfigFlags -> IO LocalBuildInfo
configure (GenericPackageDescription
g_pkg_descr, HookedBuildInfo
hookedBuildInfo) ConfigFlags
cfg = do
  -- Cabal pre-configure
  (lbc1, comp, platform, enabledComps) <- ConfigFlags
-> GenericPackageDescription
-> IO
     (LocalBuildConfig, Compiler, Platform, ComponentRequestedSpec)
preConfigurePackage ConfigFlags
cfg GenericPackageDescription
g_pkg_descr

  -- Cabal package-wide configure
  (lbc2, pbd2, pkg_info) <-
    finalizeAndConfigurePackage cfg lbc1 g_pkg_descr comp platform enabledComps

  -- Cabal per-component configure
  externalPkgDeps <- finalCheckPackage g_pkg_descr pbd2 hookedBuildInfo pkg_info
  configureComponents lbc2 pbd2 pkg_info externalPkgDeps

preConfigurePackage
  :: ConfigFlags
  -> GenericPackageDescription
  -> IO (LBC.LocalBuildConfig, Compiler, Platform, ComponentRequestedSpec)
preConfigurePackage :: ConfigFlags
-> GenericPackageDescription
-> IO
     (LocalBuildConfig, Compiler, Platform, ComponentRequestedSpec)
preConfigurePackage ConfigFlags
cfg GenericPackageDescription
g_pkg_descr = do
  let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)

  -- Determine the component we are configuring, if a user specified
  -- one on the command line.  We use a fake, flattened version of
  -- the package since at this point, we're not really sure what
  -- components we *can* configure.  @Nothing@ means that we should
  -- configure everything (the old behavior).
  (mb_cname :: Maybe ComponentName) <- do
    let flat_pkg_descr :: PackageDescription
flat_pkg_descr = GenericPackageDescription -> PackageDescription
flattenPackageDescription GenericPackageDescription
g_pkg_descr
    targets <- Verbosity -> PackageDescription -> [ProgArg] -> IO [BuildTarget]
readBuildTargets Verbosity
verbosity PackageDescription
flat_pkg_descr (ConfigFlags -> [ProgArg]
configArgs ConfigFlags
cfg)
    -- TODO: bleat if you use the module/file syntax
    let targets' = [ComponentName
cname | BuildTargetComponent ComponentName
cname <- [BuildTarget]
targets]
    case targets' of
      [ComponentName]
_ | [ProgArg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ConfigFlags -> [ProgArg]
configArgs ConfigFlags
cfg) -> Maybe ComponentName -> IO (Maybe ComponentName)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ComponentName
forall a. Maybe a
Nothing
      [ComponentName
cname] -> Maybe ComponentName -> IO (Maybe ComponentName)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (ComponentName -> Maybe ComponentName
forall a. a -> Maybe a
Just ComponentName
cname)
      [] -> Verbosity -> CabalException -> IO (Maybe ComponentName)
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
NoValidComponent
      [ComponentName]
_ -> Verbosity -> CabalException -> IO (Maybe ComponentName)
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
ConfigureEitherSingleOrAll

  case mb_cname of
    Maybe ComponentName
Nothing -> Verbosity -> ProgArg -> PackageIdentifier -> IO ()
setupMessage Verbosity
verbosity ProgArg
"Configuring" (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
g_pkg_descr)
    Just ComponentName
cname ->
      Verbosity
-> ProgArg
-> PackageIdentifier
-> ComponentName
-> Maybe [(ModuleName, Module)]
-> IO ()
forall a.
Pretty a =>
Verbosity
-> ProgArg
-> PackageIdentifier
-> ComponentName
-> Maybe [(ModuleName, a)]
-> IO ()
setupMessage'
        Verbosity
verbosity
        ProgArg
"Configuring"
        (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
g_pkg_descr)
        ComponentName
cname
        ([(ModuleName, Module)] -> Maybe [(ModuleName, Module)]
forall a. a -> Maybe a
Just (ConfigFlags -> [(ModuleName, Module)]
configInstantiateWith ConfigFlags
cfg))

  -- configCID is only valid for per-component configure
  when (isJust (flagToMaybe (configCID cfg)) && isNothing mb_cname) $
    dieWithException verbosity ConfigCIDValidForPreComponent

  -- Make a data structure describing what components are enabled.
  let enabled :: ComponentRequestedSpec
      enabled = case Maybe ComponentName
mb_cname of
        Just ComponentName
cname -> ComponentName -> ComponentRequestedSpec
OneComponentRequestedSpec ComponentName
cname
        Maybe ComponentName
Nothing ->
          ComponentRequestedSpec
            { -- The flag name (@--enable-tests@) is a
              -- little bit of a misnomer, because
              -- just passing this flag won't
              -- "enable", in our internal
              -- nomenclature; it's just a request; a
              -- @buildable: False@ might make it
              -- not possible to enable.
              testsRequested :: Bool
testsRequested = Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configTests ConfigFlags
cfg)
            , benchmarksRequested :: Bool
benchmarksRequested =
                Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configBenchmarks ConfigFlags
cfg)
            }
  -- Some sanity checks related to enabling components.
  when
    ( isJust mb_cname
        && (fromFlag (configTests cfg) || fromFlag (configBenchmarks cfg))
    )
    $ dieWithException verbosity SanityCheckForEnableComponents

  checkDeprecatedFlags verbosity cfg
  checkExactConfiguration verbosity g_pkg_descr cfg

  programDbPre <- mkProgramDb cfg (configPrograms cfg)
  -- comp:            the compiler we're building with
  -- compPlatform:    the platform we're building for
  -- programDb:  location and args of all programs we're
  --                  building with
  ( comp :: Compiler
    , compPlatform :: Platform
    , programDb00 :: ProgramDb
    ) <-
    configCompilerEx
      (flagToMaybe (configHcFlavor cfg))
      (flagToMaybe (configHcPath cfg))
      (flagToMaybe (configHcPkg cfg))
      programDbPre
      (lessVerbose verbosity)

  -- Where to build the package
  let build_dir :: FilePath -- e.g. dist/build
      build_dir = ConfigFlags -> ProgArg
configFlagsBuildDir ConfigFlags
cfg
  -- NB: create this directory now so that all configure hooks get
  -- to see it. (In practice, the Configure build-type needs it before
  -- the postConfPackageHook runs.)
  createDirectoryIfMissingVerbose (lessVerbose verbosity) True build_dir

  lbc <- computeLocalBuildConfig cfg comp programDb00
  return (lbc, comp, compPlatform, enabled)

computeLocalBuildConfig
  :: ConfigFlags
  -> Compiler
  -> ProgramDb
  -> IO LBC.LocalBuildConfig
computeLocalBuildConfig :: ConfigFlags -> Compiler -> ProgramDb -> IO LocalBuildConfig
computeLocalBuildConfig ConfigFlags
cfg Compiler
comp ProgramDb
programDb = do
  let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)
  -- Decide if we're going to compile with split sections.
  split_sections :: Bool <-
    if Bool -> Bool
not (Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configSplitSections ConfigFlags
cfg)
      then Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
      else case Compiler -> CompilerFlavor
compilerFlavor Compiler
comp of
        CompilerFlavor
GHC
          | Compiler -> Version
compilerVersion Compiler
comp Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
8, Int
0] ->
              Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
        CompilerFlavor
GHCJS ->
          Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
        CompilerFlavor
_ -> do
          Verbosity -> ProgArg -> IO ()
warn
            Verbosity
verbosity
            ( ProgArg
"this compiler does not support "
                ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"--enable-split-sections; ignoring"
            )
          Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

  -- Decide if we're going to compile with split objects.
  split_objs :: Bool <-
    if not (fromFlag $ configSplitObjs cfg)
      then return False
      else case compilerFlavor comp of
        CompilerFlavor
_ | Bool
split_sections ->
          do
            Verbosity -> ProgArg -> IO ()
warn
              Verbosity
verbosity
              ( ProgArg
"--enable-split-sections and "
                  ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"--enable-split-objs are mutually "
                  ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"exclusive; ignoring the latter"
              )
            Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
        CompilerFlavor
GHC ->
          Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
        CompilerFlavor
GHCJS ->
          Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
        CompilerFlavor
_ -> do
          Verbosity -> ProgArg -> IO ()
warn
            Verbosity
verbosity
            ( ProgArg
"this compiler does not support "
                ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"--enable-split-objs; ignoring"
            )
          Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

  -- Basically yes/no/unknown.
  let linkerSupportsRelocations :: Maybe Bool
      linkerSupportsRelocations =
        case ProgArg -> ProgramDb -> Maybe ConfiguredProgram
lookupProgramByName ProgArg
"ld" ProgramDb
programDb of
          Maybe ConfiguredProgram
Nothing -> Maybe Bool
forall a. Maybe a
Nothing
          Just ConfiguredProgram
ld ->
            case ProgArg -> Map ProgArg ProgArg -> Maybe ProgArg
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup ProgArg
"Supports relocatable output" (Map ProgArg ProgArg -> Maybe ProgArg)
-> Map ProgArg ProgArg -> Maybe ProgArg
forall a b. (a -> b) -> a -> b
$ ConfiguredProgram -> Map ProgArg ProgArg
programProperties ConfiguredProgram
ld of
              Just ProgArg
"YES" -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
True
              Just ProgArg
"NO" -> Bool -> Maybe Bool
forall a. a -> Maybe a
Just Bool
False
              Maybe ProgArg
_other -> Maybe Bool
forall a. Maybe a
Nothing
  let ghciLibByDefault =
        case Compiler -> CompilerId
compilerId Compiler
comp of
          CompilerId CompilerFlavor
GHC Version
_ ->
            -- If ghc is non-dynamic, then ghci needs object files,
            -- so we build one by default.
            --
            -- Technically, archive files should be sufficient for ghci,
            -- but because of GHC bug #8942, it has never been safe to
            -- rely on them. By the time that bug was fixed, ghci had
            -- been changed to read shared libraries instead of archive
            -- files (see next code block).
            Bool -> Bool
not (Compiler -> Bool
GHC.isDynamic Compiler
comp)
          CompilerId CompilerFlavor
GHCJS Version
_ ->
            Bool -> Bool
not (Compiler -> Bool
GHCJS.isDynamic Compiler
comp)
          CompilerId
_ -> Bool
False

  withGHCiLib_ <-
    case fromFlagOrDefault ghciLibByDefault (configGHCiLib cfg) of
      -- NOTE: If linkerSupportsRelocations is Nothing this may still fail if the
      -- linker does not support -r.
      Bool
True | Bool -> Bool
not (Bool -> Maybe Bool -> Bool
forall a. a -> Maybe a -> a
fromMaybe Bool
True Maybe Bool
linkerSupportsRelocations) -> do
        Verbosity -> ProgArg -> IO ()
warn Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$
          ProgArg
"--enable-library-for-ghci is not supported with the current"
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"  linker; ignoring..."
        Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
      Bool
v -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
v

  let sharedLibsByDefault
        | Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configDynExe ConfigFlags
cfg) =
            -- build a shared library if dynamically-linked
            -- executables are requested
            Bool
True
        | Bool
otherwise = case Compiler -> CompilerId
compilerId Compiler
comp of
            CompilerId CompilerFlavor
GHC Version
_ ->
              -- if ghc is dynamic, then ghci needs a shared
              -- library, so we build one by default.
              Compiler -> Bool
GHC.isDynamic Compiler
comp
            CompilerId CompilerFlavor
GHCJS Version
_ ->
              Compiler -> Bool
GHCJS.isDynamic Compiler
comp
            CompilerId
_ -> Bool
False
      withSharedLib_ =
        -- build shared libraries if required by GHC or by the
        -- executable linking mode, but allow the user to force
        -- building only static library archives with
        -- --disable-shared.
        Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
sharedLibsByDefault (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configSharedLib ConfigFlags
cfg

      withStaticLib_ =
        -- build a static library (all dependent libraries rolled
        -- into a huge .a archive) via GHCs -staticlib flag.
        Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configStaticLib ConfigFlags
cfg

      withDynExe_ = Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configDynExe ConfigFlags
cfg

      withFullyStaticExe_ = Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configFullyStaticExe ConfigFlags
cfg

  when (withDynExe_ && not withSharedLib_) $
    warn verbosity $
      "Executables will use dynamic linking, but a shared library "
        ++ "is not being built. Linking will fail if any executables "
        ++ "depend on the library."

  setProfiling <- configureProfiling verbosity cfg comp

  setCoverage <- configureCoverage verbosity cfg comp

  -- Turn off library and executable stripping when `debug-info` is set
  -- to anything other than zero.
  let
    strip_libexe ProgArg
s ConfigFlags -> Flag Bool
f =
      let defaultStrip :: Bool
defaultStrip = Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
True (ConfigFlags -> Flag Bool
f ConfigFlags
cfg)
       in case Flag DebugInfoLevel -> DebugInfoLevel
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag DebugInfoLevel
configDebugInfo ConfigFlags
cfg) of
            DebugInfoLevel
NoDebugInfo -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
defaultStrip
            DebugInfoLevel
_ -> case ConfigFlags -> Flag Bool
f ConfigFlags
cfg of
              Flag Bool
True -> do
                Verbosity -> ProgArg -> IO ()
warn Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$
                  ProgArg
"Setting debug-info implies "
                    ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
s
                    ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"-stripping: False"
                Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
              Flag Bool
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

  strip_lib <- strip_libexe "library" configStripLibs
  strip_exe <- strip_libexe "executable" configStripExes

  let buildOptions =
        BuildOptions -> BuildOptions
setCoverage (BuildOptions -> BuildOptions)
-> (BuildOptions -> BuildOptions) -> BuildOptions -> BuildOptions
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuildOptions -> BuildOptions
setProfiling (BuildOptions -> BuildOptions) -> BuildOptions -> BuildOptions
forall a b. (a -> b) -> a -> b
$
          LBC.BuildOptions
            { withVanillaLib :: Bool
withVanillaLib = Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configVanillaLib ConfigFlags
cfg
            , withSharedLib :: Bool
withSharedLib = Bool
withSharedLib_
            , withStaticLib :: Bool
withStaticLib = Bool
withStaticLib_
            , withDynExe :: Bool
withDynExe = Bool
withDynExe_
            , withFullyStaticExe :: Bool
withFullyStaticExe = Bool
withFullyStaticExe_
            , withProfLib :: Bool
withProfLib = Bool
False
            , withProfLibDetail :: ProfDetailLevel
withProfLibDetail = ProfDetailLevel
ProfDetailNone
            , withProfExe :: Bool
withProfExe = Bool
False
            , withProfExeDetail :: ProfDetailLevel
withProfExeDetail = ProfDetailLevel
ProfDetailNone
            , withOptimization :: OptimisationLevel
withOptimization = Flag OptimisationLevel -> OptimisationLevel
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag OptimisationLevel -> OptimisationLevel)
-> Flag OptimisationLevel -> OptimisationLevel
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag OptimisationLevel
configOptimization ConfigFlags
cfg
            , withDebugInfo :: DebugInfoLevel
withDebugInfo = Flag DebugInfoLevel -> DebugInfoLevel
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag DebugInfoLevel -> DebugInfoLevel)
-> Flag DebugInfoLevel -> DebugInfoLevel
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag DebugInfoLevel
configDebugInfo ConfigFlags
cfg
            , withGHCiLib :: Bool
withGHCiLib = Bool
withGHCiLib_
            , splitSections :: Bool
splitSections = Bool
split_sections
            , splitObjs :: Bool
splitObjs = Bool
split_objs
            , stripExes :: Bool
stripExes = Bool
strip_exe
            , stripLibs :: Bool
stripLibs = Bool
strip_lib
            , exeCoverage :: Bool
exeCoverage = Bool
False
            , libCoverage :: Bool
libCoverage = Bool
False
            , relocatable :: Bool
relocatable = Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag Bool
configRelocatable ConfigFlags
cfg
            }

  return $
    LBC.LocalBuildConfig
      { extraConfigArgs = [] -- Currently configure does not
      -- take extra args, but if it
      -- did they would go here.
      , withPrograms = programDb
      , withBuildOptions = buildOptions
      }

data PackageInfo = PackageInfo
  { PackageInfo -> Set LibraryName
internalPackageSet :: Set LibraryName
  , PackageInfo -> Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: Map (PackageName, ComponentName) ComponentId
  , PackageInfo -> InstalledPackageIndex
installedPackageSet :: InstalledPackageIndex
  , PackageInfo
-> Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo
  }

configurePackage
  :: ConfigFlags
  -> LBC.LocalBuildConfig
  -> PackageDescription
  -> FlagAssignment
  -> ComponentRequestedSpec
  -> Compiler
  -> Platform
  -> ProgramDb
  -> PackageDBStack
  -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr)
configurePackage :: ConfigFlags
-> LocalBuildConfig
-> PackageDescription
-> FlagAssignment
-> ComponentRequestedSpec
-> Compiler
-> Platform
-> ProgramDb
-> PackageDBStack
-> IO (LocalBuildConfig, PackageBuildDescr)
configurePackage ConfigFlags
cfg LocalBuildConfig
lbc0 PackageDescription
pkg_descr00 FlagAssignment
flags ComponentRequestedSpec
enabled Compiler
comp Platform
platform ProgramDb
programDb0 PackageDBStack
packageDbs = do
  let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)

      -- add extra include/lib dirs as specified in cfg
      pkg_descr0 :: PackageDescription
pkg_descr0 = PackageDescription -> ConfigFlags -> PackageDescription
addExtraIncludeLibDirsFromConfigFlags PackageDescription
pkg_descr00 ConfigFlags
cfg
  -- TODO: it is not clear whether this adding these dirs is necessary
  -- when we are directly stating from a PackageDescription (e.g. when
  -- cabal-install has determined a PackageDescription, instead of rediscovering
  -- when working with a GenericPackageDescription).
  -- Could this function call be moved to the end of finalizeAndConfigurePackage
  -- right before calling configurePackage?

  -- Configure certain external build tools, see below for which ones.
  let requiredBuildTools :: [LegacyExeDependency]
requiredBuildTools = do
        bi <- PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr0 ComponentRequestedSpec
enabled
        -- First, we collect any tool dep that we know is external. This is,
        -- in practice:
        --
        -- 1. `build-tools` entries on the whitelist
        --
        -- 2. `build-tool-depends` that aren't from the current package.
        let externBuildToolDeps =
              [ ProgArg -> VersionRange -> LegacyExeDependency
LegacyExeDependency (UnqualComponentName -> ProgArg
unUnqualComponentName UnqualComponentName
eName) VersionRange
versionRange
              | buildTool :: ExeDependency
buildTool@(ExeDependency PackageName
_ UnqualComponentName
eName VersionRange
versionRange) <-
                  PackageDescription -> BuildInfo -> [ExeDependency]
getAllToolDependencies PackageDescription
pkg_descr0 BuildInfo
bi
              , Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ PackageDescription -> ExeDependency -> Bool
isInternal PackageDescription
pkg_descr0 ExeDependency
buildTool
              ]
        -- Second, we collect any build-tools entry we don't know how to
        -- desugar. We'll never have any idea how to build them, so we just
        -- hope they are already on the PATH.
        let unknownBuildTools =
              [ LegacyExeDependency
buildTool
              | LegacyExeDependency
buildTool <- BuildInfo -> [LegacyExeDependency]
buildTools BuildInfo
bi
              , Maybe ExeDependency
forall a. Maybe a
Nothing Maybe ExeDependency -> Maybe ExeDependency -> Bool
forall a. Eq a => a -> a -> Bool
== PackageDescription -> LegacyExeDependency -> Maybe ExeDependency
desugarBuildTool PackageDescription
pkg_descr0 LegacyExeDependency
buildTool
              ]
        externBuildToolDeps ++ unknownBuildTools

  programDb1 <-
    Verbosity -> ProgramDb -> IO ProgramDb
configureAllKnownPrograms (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity) ProgramDb
programDb0
      IO ProgramDb -> (ProgramDb -> IO ProgramDb) -> IO ProgramDb
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Verbosity -> [LegacyExeDependency] -> ProgramDb -> IO ProgramDb
configureRequiredPrograms Verbosity
verbosity [LegacyExeDependency]
requiredBuildTools

  (pkg_descr2, programDb2) <-
    configurePkgconfigPackages verbosity pkg_descr0 programDb1 enabled

  let use_external_internal_deps =
        case ComponentRequestedSpec
enabled of
          OneComponentRequestedSpec{} -> Bool
True
          ComponentRequestedSpec{} -> Bool
False

  -- Compute installation directory templates, based on user
  -- configuration.
  --
  -- TODO: Move this into a helper function.
  defaultDirs :: InstallDirTemplates <-
    defaultInstallDirs'
      use_external_internal_deps
      (compilerFlavor comp)
      (fromFlag (configUserInstall cfg))
      (hasLibs pkg_descr2)
  let
    installDirs =
      (PathTemplate -> Flag PathTemplate -> PathTemplate)
-> InstallDirTemplates
-> InstallDirs (Flag PathTemplate)
-> InstallDirTemplates
forall a b c.
(a -> b -> c) -> InstallDirs a -> InstallDirs b -> InstallDirs c
combineInstallDirs
        PathTemplate -> Flag PathTemplate -> PathTemplate
forall a. a -> Flag a -> a
fromFlagOrDefault
        InstallDirTemplates
defaultDirs
        (ConfigFlags -> InstallDirs (Flag PathTemplate)
configInstallDirs ConfigFlags
cfg)
    lbc = LocalBuildConfig
lbc0{LBC.withPrograms = programDb2}
    pbd =
      LBC.PackageBuildDescr
        { configFlags :: ConfigFlags
configFlags = ConfigFlags
cfg
        , flagAssignment :: FlagAssignment
flagAssignment = FlagAssignment
flags
        , componentEnabledSpec :: ComponentRequestedSpec
componentEnabledSpec = ComponentRequestedSpec
enabled
        , compiler :: Compiler
compiler = Compiler
comp
        , hostPlatform :: Platform
hostPlatform = Platform
platform
        , localPkgDescr :: PackageDescription
localPkgDescr = PackageDescription
pkg_descr2
        , installDirTemplates :: InstallDirTemplates
installDirTemplates = InstallDirTemplates
installDirs
        , withPackageDB :: PackageDBStack
withPackageDB = PackageDBStack
packageDbs
        , pkgDescrFile :: Maybe ProgArg
pkgDescrFile = Maybe ProgArg
forall a. Maybe a
Nothing
        , extraCoverageFor :: [UnitId]
extraCoverageFor = []
        }

  debug verbosity $
    "Finalized package description:\n"
      ++ showPackageDescription pkg_descr2

  return (lbc, pbd)

finalizeAndConfigurePackage
  :: ConfigFlags
  -> LBC.LocalBuildConfig
  -> GenericPackageDescription
  -> Compiler
  -> Platform
  -> ComponentRequestedSpec
  -> IO (LBC.LocalBuildConfig, LBC.PackageBuildDescr, PackageInfo)
finalizeAndConfigurePackage :: ConfigFlags
-> LocalBuildConfig
-> GenericPackageDescription
-> Compiler
-> Platform
-> ComponentRequestedSpec
-> IO (LocalBuildConfig, PackageBuildDescr, PackageInfo)
finalizeAndConfigurePackage ConfigFlags
cfg LocalBuildConfig
lbc0 GenericPackageDescription
g_pkg_descr Compiler
comp Platform
platform ComponentRequestedSpec
enabled = do
  let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)

  let programDb0 :: ProgramDb
programDb0 = LocalBuildConfig -> ProgramDb
LBC.withPrograms LocalBuildConfig
lbc0
      -- What package database(s) to use
      packageDbs :: PackageDBStack
      packageDbs :: PackageDBStack
packageDbs =
        Bool -> [Maybe PackageDB] -> PackageDBStack
interpretPackageDbFlags
          (Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configUserInstall ConfigFlags
cfg))
          (ConfigFlags -> [Maybe PackageDB]
configPackageDBs ConfigFlags
cfg)

  -- The InstalledPackageIndex of all installed packages
  installedPackageSet :: InstalledPackageIndex <-
    Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
getInstalledPackages
      (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity)
      Compiler
comp
      PackageDBStack
packageDbs
      ProgramDb
programDb0

  -- The set of package names which are "shadowed" by internal
  -- packages, and which component they map to
  let internalPackageSet :: Set LibraryName
      internalPackageSet = GenericPackageDescription -> Set LibraryName
getInternalLibraries GenericPackageDescription
g_pkg_descr

  -- Some sanity checks related to dynamic/static linking.
  when (fromFlag (configDynExe cfg) && fromFlag (configFullyStaticExe cfg)) $
    dieWithException verbosity SanityCheckForDynamicStaticLinking

  -- allConstraints:  The set of all 'Dependency's we have.  Used ONLY
  --                  to 'configureFinalizedPackage'.
  -- requiredDepsMap: A map from 'PackageName' to the specifically
  --                  required 'InstalledPackageInfo', due to --dependency
  --
  -- NB: These constraints are to be applied to ALL components of
  -- a package.  Thus, it's not an error if allConstraints contains
  -- more constraints than is necessary for a component (another
  -- component might need it.)
  --
  -- NB: The fact that we bundle all the constraints together means
  -- that is not possible to configure a test-suite to use one
  -- version of a dependency, and the executable to use another.
  ( allConstraints :: [PackageVersionConstraint]
    , requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo
    ) <-
    either (dieWithException verbosity) return $
      combinedConstraints
        (configConstraints cfg)
        (configDependencies cfg)
        installedPackageSet

  let
    promisedDepsSet = [GivenComponent] -> Map (PackageName, ComponentName) ComponentId
mkPromisedDepsSet (ConfigFlags -> [GivenComponent]
configPromisedDependencies ConfigFlags
cfg)
    pkg_info =
      PackageInfo
        { Set LibraryName
internalPackageSet :: Set LibraryName
internalPackageSet :: Set LibraryName
internalPackageSet
        , Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: Map (PackageName, ComponentName) ComponentId
promisedDepsSet
        , InstalledPackageIndex
installedPackageSet :: InstalledPackageIndex
installedPackageSet :: InstalledPackageIndex
installedPackageSet
        , Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
        }

  -- pkg_descr:   The resolved package description, that does not contain any
  --              conditionals, because we have an assignment for
  --              every flag, either picking them ourselves using a
  --              simple naive algorithm, or having them be passed to
  --              us by 'configConfigurationsFlags')
  -- flags:       The 'FlagAssignment' that the conditionals were
  --              resolved with.
  --
  -- NB: Why doesn't finalizing a package also tell us what the
  -- dependencies are (e.g. when we run the naive algorithm,
  -- we are checking if dependencies are satisfiable)?  The
  -- primary reason is that we may NOT have done any solving:
  -- if the flags are all chosen for us, this step is a simple
  -- matter of flattening according to that assignment.  It's
  -- cleaner to then configure the dependencies afterwards.
  let use_external_internal_deps = case ComponentRequestedSpec
enabled of
        OneComponentRequestedSpec{} -> Bool
True
        ComponentRequestedSpec{} -> Bool
False
  ( pkg_descr0 :: PackageDescription
    , flags :: FlagAssignment
    ) <-
    configureFinalizedPackage
      verbosity
      cfg
      enabled
      allConstraints
      ( dependencySatisfiable
          use_external_internal_deps
          (fromFlagOrDefault False (configExactConfiguration cfg))
          (fromFlagOrDefault False (configAllowDependingOnPrivateLibs cfg))
          (packageName g_pkg_descr)
          installedPackageSet
          internalPackageSet
          promisedDepsSet
          requiredDepsMap
      )
      comp
      platform
      g_pkg_descr

  (lbc, pbd) <-
    configurePackage
      cfg
      lbc0
      pkg_descr0
      flags
      enabled
      comp
      platform
      programDb0
      packageDbs
  return (lbc, pbd, pkg_info)

addExtraIncludeLibDirsFromConfigFlags
  :: PackageDescription -> ConfigFlags -> PackageDescription
addExtraIncludeLibDirsFromConfigFlags :: PackageDescription -> ConfigFlags -> PackageDescription
addExtraIncludeLibDirsFromConfigFlags PackageDescription
pkg_descr ConfigFlags
cfg =
  let extraBi :: BuildInfo
extraBi =
        BuildInfo
forall a. Monoid a => a
mempty
          { extraLibDirs = configExtraLibDirs cfg
          , extraLibDirsStatic = configExtraLibDirsStatic cfg
          , extraFrameworkDirs = configExtraFrameworkDirs cfg
          , includeDirs = configExtraIncludeDirs cfg
          }
      modifyLib :: Library -> Library
modifyLib Library
l =
        Library
l
          { libBuildInfo =
              libBuildInfo l
                `mappend` extraBi
          }
      modifyExecutable :: Executable -> Executable
modifyExecutable Executable
e =
        Executable
e
          { buildInfo =
              buildInfo e
                `mappend` extraBi
          }
      modifyForeignLib :: ForeignLib -> ForeignLib
modifyForeignLib ForeignLib
f =
        ForeignLib
f
          { foreignLibBuildInfo =
              foreignLibBuildInfo f
                `mappend` extraBi
          }
      modifyTestsuite :: TestSuite -> TestSuite
modifyTestsuite TestSuite
t =
        TestSuite
t
          { testBuildInfo =
              testBuildInfo t
                `mappend` extraBi
          }
      modifyBenchmark :: Benchmark -> Benchmark
modifyBenchmark Benchmark
b =
        Benchmark
b
          { benchmarkBuildInfo =
              benchmarkBuildInfo b
                `mappend` extraBi
          }
   in PackageDescription
pkg_descr
        { library = modifyLib `fmap` library pkg_descr
        , subLibraries = modifyLib `map` subLibraries pkg_descr
        , executables = modifyExecutable `map` executables pkg_descr
        , foreignLibs = modifyForeignLib `map` foreignLibs pkg_descr
        , testSuites = modifyTestsuite `map` testSuites pkg_descr
        , benchmarks = modifyBenchmark `map` benchmarks pkg_descr
        }

finalCheckPackage
  :: GenericPackageDescription
  -> LBC.PackageBuildDescr
  -> HookedBuildInfo
  -> PackageInfo
  -> IO ([PreExistingComponent], [PromisedComponent])
finalCheckPackage :: GenericPackageDescription
-> PackageBuildDescr
-> HookedBuildInfo
-> PackageInfo
-> IO ([PreExistingComponent], [PromisedComponent])
finalCheckPackage
  GenericPackageDescription
g_pkg_descr
  ( LBC.PackageBuildDescr
      { configFlags :: PackageBuildDescr -> ConfigFlags
configFlags = ConfigFlags
cfg
      , localPkgDescr :: PackageBuildDescr -> PackageDescription
localPkgDescr = PackageDescription
pkg_descr
      , compiler :: PackageBuildDescr -> Compiler
compiler = Compiler
comp
      , hostPlatform :: PackageBuildDescr -> Platform
hostPlatform = Platform
compPlatform
      , componentEnabledSpec :: PackageBuildDescr -> ComponentRequestedSpec
componentEnabledSpec = ComponentRequestedSpec
enabled
      }
    )
  HookedBuildInfo
hookedBuildInfo
  (PackageInfo{Set LibraryName
internalPackageSet :: PackageInfo -> Set LibraryName
internalPackageSet :: Set LibraryName
internalPackageSet, Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: PackageInfo -> Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: Map (PackageName, ComponentName) ComponentId
promisedDepsSet, InstalledPackageIndex
installedPackageSet :: PackageInfo -> InstalledPackageIndex
installedPackageSet :: InstalledPackageIndex
installedPackageSet, Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: PackageInfo
-> Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap}) =
    do
      let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)
          use_external_internal_deps :: Bool
use_external_internal_deps =
            case ComponentRequestedSpec
enabled of
              OneComponentRequestedSpec{} -> Bool
True
              ComponentRequestedSpec{} -> Bool
False

      let cabalFileDir :: ProgArg
cabalFileDir =
            ProgArg -> ShowS -> Maybe ProgArg -> ProgArg
forall b a. b -> (a -> b) -> Maybe a -> b
maybe ProgArg
"." ShowS
takeDirectory (Maybe ProgArg -> ProgArg) -> Maybe ProgArg -> ProgArg
forall a b. (a -> b) -> a -> b
$
              Flag ProgArg -> Maybe ProgArg
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag ProgArg
configCabalFilePath ConfigFlags
cfg)
      Verbosity
-> Compiler
-> PackageDescription
-> ComponentRequestedSpec
-> IO ()
checkCompilerProblems Verbosity
verbosity Compiler
comp PackageDescription
pkg_descr ComponentRequestedSpec
enabled
      Verbosity
-> ProgArg
-> GenericPackageDescription
-> PackageDescription
-> IO ()
checkPackageProblems
        Verbosity
verbosity
        ProgArg
cabalFileDir
        GenericPackageDescription
g_pkg_descr
        (HookedBuildInfo -> PackageDescription -> PackageDescription
updatePackageDescription HookedBuildInfo
hookedBuildInfo PackageDescription
pkg_descr)
      -- NB: we apply the HookedBuildInfo to check it is valid,
      -- but we don't propagate it.
      -- Other UserHooks must separately return it again, and we
      -- will re-apply it each time.

      -- Check languages and extensions
      -- TODO: Move this into a helper function.
      let langlist :: [Language]
langlist =
            [Language] -> [Language]
forall a. Eq a => [a] -> [a]
nub ([Language] -> [Language]) -> [Language] -> [Language]
forall a b. (a -> b) -> a -> b
$
              [Maybe Language] -> [Language]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe Language] -> [Language]) -> [Maybe Language] -> [Language]
forall a b. (a -> b) -> a -> b
$
                (BuildInfo -> Maybe Language) -> [BuildInfo] -> [Maybe Language]
forall a b. (a -> b) -> [a] -> [b]
map
                  BuildInfo -> Maybe Language
defaultLanguage
                  (PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr ComponentRequestedSpec
enabled)
      let langs :: [Language]
langs = Compiler -> [Language] -> [Language]
unsupportedLanguages Compiler
comp [Language]
langlist
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([Language] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Language]
langs)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          PackageIdentifier -> CompilerId -> [ProgArg] -> CabalException
UnsupportedLanguages (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
g_pkg_descr) (Compiler -> CompilerId
compilerId Compiler
comp) ((Language -> ProgArg) -> [Language] -> [ProgArg]
forall a b. (a -> b) -> [a] -> [b]
map Language -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow [Language]
langs)
      let extlist :: [Extension]
extlist =
            [Extension] -> [Extension]
forall a. Eq a => [a] -> [a]
nub ([Extension] -> [Extension]) -> [Extension] -> [Extension]
forall a b. (a -> b) -> a -> b
$
              (BuildInfo -> [Extension]) -> [BuildInfo] -> [Extension]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap
                BuildInfo -> [Extension]
allExtensions
                (PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr ComponentRequestedSpec
enabled)
      let exts :: [Extension]
exts = Compiler -> [Extension] -> [Extension]
unsupportedExtensions Compiler
comp [Extension]
extlist
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([Extension] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Extension]
exts)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          PackageIdentifier -> CompilerId -> [ProgArg] -> CabalException
UnsupportedLanguageExtension (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
g_pkg_descr) (Compiler -> CompilerId
compilerId Compiler
comp) ((Extension -> ProgArg) -> [Extension] -> [ProgArg]
forall a b. (a -> b) -> [a] -> [b]
map Extension -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow [Extension]
exts)

      -- Check foreign library build requirements
      let flibs :: [ForeignLib]
flibs = [ForeignLib
flib | CFLib ForeignLib
flib <- PackageDescription -> ComponentRequestedSpec -> [Component]
enabledComponents PackageDescription
pkg_descr ComponentRequestedSpec
enabled]
      let unsupportedFLibs :: [ProgArg]
unsupportedFLibs = Compiler -> Platform -> [ForeignLib] -> [ProgArg]
unsupportedForeignLibs Compiler
comp Platform
compPlatform [ForeignLib]
flibs
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([ProgArg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ProgArg]
unsupportedFLibs)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          [ProgArg] -> CabalException
CantFindForeignLibraries [ProgArg]
unsupportedFLibs

      -- The list of 'InstalledPackageInfo' recording the selected
      -- dependencies on external packages.
      --
      -- Invariant: For any package name, there is at most one package
      -- in externalPackageDeps which has that name.
      --
      -- NB: The dependency selection is global over ALL components
      -- in the package (similar to how allConstraints and
      -- requiredDepsMap are global over all components).  In particular,
      -- if *any* component (post-flag resolution) has an unsatisfiable
      -- dependency, we will fail.  This can sometimes be undesirable
      -- for users, see #1786 (benchmark conflicts with executable),
      --
      -- In the presence of Backpack, these package dependencies are
      -- NOT complete: they only ever include the INDEFINITE
      -- dependencies.  After we apply an instantiation, we'll get
      -- definite references which constitute extra dependencies.
      -- (Why not have cabal-install pass these in explicitly?
      -- For one it's deterministic; for two, we need to associate
      -- them with renamings which would require a far more complicated
      -- input scheme than what we have today.)
      Verbosity
-> Bool
-> Set LibraryName
-> Map (PackageName, ComponentName) ComponentId
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> PackageDescription
-> ComponentRequestedSpec
-> IO ([PreExistingComponent], [PromisedComponent])
configureDependencies
        Verbosity
verbosity
        Bool
use_external_internal_deps
        Set LibraryName
internalPackageSet
        Map (PackageName, ComponentName) ComponentId
promisedDepsSet
        InstalledPackageIndex
installedPackageSet
        Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
        PackageDescription
pkg_descr
        ComponentRequestedSpec
enabled

configureComponents
  :: LBC.LocalBuildConfig
  -> LBC.PackageBuildDescr
  -> PackageInfo
  -> ([PreExistingComponent], [PromisedComponent])
  -> IO LocalBuildInfo
configureComponents :: LocalBuildConfig
-> PackageBuildDescr
-> PackageInfo
-> ([PreExistingComponent], [PromisedComponent])
-> IO LocalBuildInfo
configureComponents
  lbc :: LocalBuildConfig
lbc@(LBC.LocalBuildConfig{withPrograms :: LocalBuildConfig -> ProgramDb
withPrograms = ProgramDb
programDb})
  pbd0 :: PackageBuildDescr
pbd0@( LBC.PackageBuildDescr
          { configFlags :: PackageBuildDescr -> ConfigFlags
configFlags = ConfigFlags
cfg
          , localPkgDescr :: PackageBuildDescr -> PackageDescription
localPkgDescr = PackageDescription
pkg_descr
          , compiler :: PackageBuildDescr -> Compiler
compiler = Compiler
comp
          , componentEnabledSpec :: PackageBuildDescr -> ComponentRequestedSpec
componentEnabledSpec = ComponentRequestedSpec
enabled
          }
        )
  (PackageInfo{Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: PackageInfo -> Map (PackageName, ComponentName) ComponentId
promisedDepsSet :: Map (PackageName, ComponentName) ComponentId
promisedDepsSet, InstalledPackageIndex
installedPackageSet :: PackageInfo -> InstalledPackageIndex
installedPackageSet :: InstalledPackageIndex
installedPackageSet})
  ([PreExistingComponent], [PromisedComponent])
externalPkgDeps =
    do
      let verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)
          use_external_internal_deps :: Bool
use_external_internal_deps =
            case ComponentRequestedSpec
enabled of
              OneComponentRequestedSpec{} -> Bool
True
              ComponentRequestedSpec{} -> Bool
False

      -- Compute internal component graph
      --
      -- The general idea is that we take a look at all the source level
      -- components (which may build-depends on each other) and form a graph.
      -- From there, we build a ComponentLocalBuildInfo for each of the
      -- components, which lets us actually build each component.
      ( buildComponents :: [ComponentLocalBuildInfo]
        , packageDependsIndex :: InstalledPackageIndex
        ) <-
        Verbosity
-> LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
-> IO ([ComponentLocalBuildInfo], InstalledPackageIndex)
forall a. Verbosity -> LogProgress a -> IO a
runLogProgress Verbosity
verbosity (LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
 -> IO ([ComponentLocalBuildInfo], InstalledPackageIndex))
-> LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
-> IO ([ComponentLocalBuildInfo], InstalledPackageIndex)
forall a b. (a -> b) -> a -> b
$
          Verbosity
-> Bool
-> ComponentRequestedSpec
-> Bool
-> Flag ProgArg
-> Flag ComponentId
-> PackageDescription
-> ([PreExistingComponent], [PromisedComponent])
-> FlagAssignment
-> [(ModuleName, Module)]
-> InstalledPackageIndex
-> Compiler
-> LogProgress ([ComponentLocalBuildInfo], InstalledPackageIndex)
configureComponentLocalBuildInfos
            Verbosity
verbosity
            Bool
use_external_internal_deps
            ComponentRequestedSpec
enabled
            (Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (ConfigFlags -> Flag Bool
configDeterministic ConfigFlags
cfg))
            (ConfigFlags -> Flag ProgArg
configIPID ConfigFlags
cfg)
            (ConfigFlags -> Flag ComponentId
configCID ConfigFlags
cfg)
            PackageDescription
pkg_descr
            ([PreExistingComponent], [PromisedComponent])
externalPkgDeps
            (ConfigFlags -> FlagAssignment
configConfigurationsFlags ConfigFlags
cfg)
            (ConfigFlags -> [(ModuleName, Module)]
configInstantiateWith ConfigFlags
cfg)
            InstalledPackageIndex
installedPackageSet
            Compiler
comp

      let buildComponentsMap =
            (Map ComponentName [ComponentLocalBuildInfo]
 -> ComponentLocalBuildInfo
 -> Map ComponentName [ComponentLocalBuildInfo])
-> Map ComponentName [ComponentLocalBuildInfo]
-> [ComponentLocalBuildInfo]
-> Map ComponentName [ComponentLocalBuildInfo]
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl'
              ( \Map ComponentName [ComponentLocalBuildInfo]
m ComponentLocalBuildInfo
clbi ->
                  ([ComponentLocalBuildInfo]
 -> [ComponentLocalBuildInfo] -> [ComponentLocalBuildInfo])
-> ComponentName
-> [ComponentLocalBuildInfo]
-> Map ComponentName [ComponentLocalBuildInfo]
-> Map ComponentName [ComponentLocalBuildInfo]
forall k a. Ord k => (a -> a -> a) -> k -> a -> Map k a -> Map k a
Map.insertWith
                    [ComponentLocalBuildInfo]
-> [ComponentLocalBuildInfo] -> [ComponentLocalBuildInfo]
forall a. [a] -> [a] -> [a]
(++)
                    (ComponentLocalBuildInfo -> ComponentName
componentLocalName ComponentLocalBuildInfo
clbi)
                    [ComponentLocalBuildInfo
clbi]
                    Map ComponentName [ComponentLocalBuildInfo]
m
              )
              Map ComponentName [ComponentLocalBuildInfo]
forall k a. Map k a
Map.empty
              [ComponentLocalBuildInfo]
buildComponents

      let cbd =
            LBC.ComponentBuildDescr
              { componentGraph :: Graph ComponentLocalBuildInfo
componentGraph = [ComponentLocalBuildInfo] -> Graph ComponentLocalBuildInfo
forall a. (IsNode a, Show (Key a)) => [a] -> Graph a
Graph.fromDistinctList [ComponentLocalBuildInfo]
buildComponents
              , componentNameMap :: Map ComponentName [ComponentLocalBuildInfo]
componentNameMap = Map ComponentName [ComponentLocalBuildInfo]
buildComponentsMap
              , promisedPkgs :: Map (PackageName, ComponentName) ComponentId
promisedPkgs = Map (PackageName, ComponentName) ComponentId
promisedDepsSet
              , installedPkgs :: InstalledPackageIndex
installedPkgs = InstalledPackageIndex
packageDependsIndex
              }

          -- For whole-package configure, we determine the
          -- extraCoverageFor of the main lib and sub libs here.
          extraCoverageUnitIds = case ComponentRequestedSpec
enabled of
            -- Whole package configure, add package libs
            ComponentRequestedSpec{} -> (ComponentLocalBuildInfo -> Maybe UnitId)
-> [ComponentLocalBuildInfo] -> [UnitId]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe ComponentLocalBuildInfo -> Maybe UnitId
mbCompUnitId [ComponentLocalBuildInfo]
buildComponents
            -- Component configure, no need to do anything
            OneComponentRequestedSpec{} -> []
          mbCompUnitId LibComponentLocalBuildInfo{UnitId
componentUnitId :: UnitId
componentUnitId :: ComponentLocalBuildInfo -> UnitId
componentUnitId} = UnitId -> Maybe UnitId
forall a. a -> Maybe a
Just UnitId
componentUnitId
          mbCompUnitId ComponentLocalBuildInfo
_ = Maybe UnitId
forall a. Maybe a
Nothing

          pbd =
            PackageBuildDescr
pbd0
              { LBC.extraCoverageFor = extraCoverageUnitIds
              }

          lbd =
            LBC.LocalBuildDescr
              { packageBuildDescr :: PackageBuildDescr
packageBuildDescr = PackageBuildDescr
pbd
              , componentBuildDescr :: ComponentBuildDescr
componentBuildDescr = ComponentBuildDescr
cbd
              }

          lbi =
            NewLocalBuildInfo
              { localBuildDescr :: LocalBuildDescr
localBuildDescr = LocalBuildDescr
lbd
              , localBuildConfig :: LocalBuildConfig
localBuildConfig = LocalBuildConfig
lbc
              }

      when (LBC.relocatable $ LBC.withBuildOptions lbc) $
        checkRelocatable verbosity pkg_descr lbi

      -- TODO: This is not entirely correct, because the dirs may vary
      -- across libraries/executables
      let dirs = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs ProgArg
absoluteInstallDirs PackageDescription
pkg_descr LocalBuildInfo
lbi CopyDest
NoCopyDest
          relative = PackageIdentifier -> LocalBuildInfo -> InstallDirs (Maybe ProgArg)
prefixRelativeInstallDirs (PackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId PackageDescription
pkg_descr) LocalBuildInfo
lbi

      -- PKGROOT: allowing ${pkgroot} to be passed as --prefix to
      -- cabal configure, is only a hidden option. It allows packages
      -- to be relocatable with their package database.  This however
      -- breaks when the Paths_* or other includes are used that
      -- contain hard coded paths. This is still an open TODO.
      --
      -- Allowing ${pkgroot} here, however requires less custom hooks
      -- in scripts that *really* want ${pkgroot}. See haskell/cabal/#4872
      unless
        ( isAbsolute (prefix dirs)
            || "${pkgroot}" `isPrefixOf` prefix dirs
        )
        $ dieWithException verbosity
        $ ExpectedAbsoluteDirectory (prefix dirs)

      when ("${pkgroot}" `isPrefixOf` prefix dirs) $
        warn verbosity $
          "Using ${pkgroot} in prefix "
            ++ prefix dirs
            ++ " will not work if you rely on the Path_* module "
            ++ " or other hard coded paths.  Cabal does not yet "
            ++ " support fully relocatable builds! "
            ++ " See #462 #2302 #2994 #3305 #3473 #3586 #3909"
            ++ " #4097 #4291 #4872"

      info verbosity $
        "Using "
          ++ prettyShow currentCabalId
          ++ " compiled by "
          ++ prettyShow currentCompilerId
      info verbosity $ "Using compiler: " ++ showCompilerId comp
      info verbosity $ "Using install prefix: " ++ prefix dirs

      let dirinfo ProgArg
name ProgArg
dir Maybe a
isPrefixRelative =
            Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$ ProgArg
name ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
" installed in: " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
dir ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
relNote
            where
              relNote :: ProgArg
relNote = case OS
buildOS of
                OS
Windows
                  | Bool -> Bool
not (PackageDescription -> Bool
hasLibs PackageDescription
pkg_descr)
                      Bool -> Bool -> Bool
&& Maybe a -> Bool
forall a. Maybe a -> Bool
isNothing Maybe a
isPrefixRelative ->
                      ProgArg
"  (fixed location)"
                OS
_ -> ProgArg
""

      dirinfo "Executables" (bindir dirs) (bindir relative)
      dirinfo "Libraries" (libdir dirs) (libdir relative)
      dirinfo "Dynamic Libraries" (dynlibdir dirs) (dynlibdir relative)
      dirinfo "Private executables" (libexecdir dirs) (libexecdir relative)
      dirinfo "Data files" (datadir dirs) (datadir relative)
      dirinfo "Documentation" (docdir dirs) (docdir relative)
      dirinfo "Configuration files" (sysconfdir dirs) (sysconfdir relative)

      sequence_
        [ reportProgram verbosity prog configuredProg
        | (prog, configuredProg) <- knownPrograms programDb
        ]

      return lbi

mkPromisedDepsSet :: [GivenComponent] -> Map (PackageName, ComponentName) ComponentId
mkPromisedDepsSet :: [GivenComponent] -> Map (PackageName, ComponentName) ComponentId
mkPromisedDepsSet [GivenComponent]
comps = [((PackageName, ComponentName), ComponentId)]
-> Map (PackageName, ComponentName) ComponentId
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [((PackageName
pn, LibraryName -> ComponentName
CLibName LibraryName
ln), ComponentId
cid) | GivenComponent PackageName
pn LibraryName
ln ComponentId
cid <- [GivenComponent]
comps]

-- | Adds the extra program paths from the flags provided to @configure@ as
-- well as specified locations for certain known programs and their default
-- arguments.
mkProgramDb :: ConfigFlags -> ProgramDb -> IO ProgramDb
mkProgramDb :: ConfigFlags -> ProgramDb -> IO ProgramDb
mkProgramDb ConfigFlags
cfg ProgramDb
initialProgramDb = do
  programDb <-
    (ProgramSearchPath -> ProgramSearchPath) -> ProgramDb -> ProgramDb
modifyProgramSearchPath (ProgramDb -> ProgramSearchPath
getProgramSearchPath ProgramDb
initialProgramDb ProgramSearchPath -> ProgramSearchPath -> ProgramSearchPath
forall a. [a] -> [a] -> [a]
++) -- We need to have the paths to programs installed by build-tool-depends before all other paths
      (ProgramDb -> ProgramDb) -> IO ProgramDb -> IO ProgramDb
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Verbosity -> [ProgArg] -> ProgramDb -> IO ProgramDb
prependProgramSearchPath (Verbosity -> Flag Verbosity -> Verbosity
forall a. a -> Flag a -> a
fromFlagOrDefault Verbosity
normal (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)) [ProgArg]
searchpath ProgramDb
initialProgramDb
  pure
    . userSpecifyArgss (configProgramArgs cfg)
    . userSpecifyPaths (configProgramPaths cfg)
    $ programDb
  where
    searchpath :: [ProgArg]
searchpath = NubList ProgArg -> [ProgArg]
forall a. NubList a -> [a]
fromNubList (ConfigFlags -> NubList ProgArg
configProgramPathExtra ConfigFlags
cfg)

-- Note. We try as much as possible to _prepend_ rather than postpend the extra-prog-path
-- so that we can override the system path. However, in a v2-build, at this point, the "system" path
-- has already been extended by both the built-tools-depends paths, as well as the program-path-extra
-- so for v2 builds adding it again is entirely unnecessary. However, it needs to get added again _anyway_
-- so as to take effect for v1 builds or standalone calls to Setup.hs
-- In this instance, the lesser evil is to not allow it to override the system path.

-- -----------------------------------------------------------------------------
-- Helper functions for configure

-- | Check if the user used any deprecated flags.
checkDeprecatedFlags :: Verbosity -> ConfigFlags -> IO ()
checkDeprecatedFlags :: Verbosity -> ConfigFlags -> IO ()
checkDeprecatedFlags Verbosity
verbosity ConfigFlags
cfg = do
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ConfigFlags -> Flag Bool
configProfExe ConfigFlags
cfg Flag Bool -> Flag Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Flag Bool
forall a. Flag a
NoFlag) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    let enable :: ProgArg
enable
          | Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configProfExe ConfigFlags
cfg) = ProgArg
"enable"
          | Bool
otherwise = ProgArg
"disable"
    Verbosity -> ProgArg -> IO ()
warn
      Verbosity
verbosity
      ( ProgArg
"The flag --"
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
enable
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"-executable-profiling is deprecated. "
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"Please use --"
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
enable
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"-profiling instead."
      )

  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (ConfigFlags -> Flag Bool
configLibCoverage ConfigFlags
cfg Flag Bool -> Flag Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Flag Bool
forall a. Flag a
NoFlag) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    let enable :: ProgArg
enable
          | Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configLibCoverage ConfigFlags
cfg) = ProgArg
"enable"
          | Bool
otherwise = ProgArg
"disable"
    Verbosity -> ProgArg -> IO ()
warn
      Verbosity
verbosity
      ( ProgArg
"The flag --"
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
enable
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"-library-coverage is deprecated. "
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"Please use --"
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
enable
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"-coverage instead."
      )

-- | Sanity check: if '--exact-configuration' was given, ensure that the
-- complete flag assignment was specified on the command line.
checkExactConfiguration
  :: Verbosity -> GenericPackageDescription -> ConfigFlags -> IO ()
checkExactConfiguration :: Verbosity -> GenericPackageDescription -> ConfigFlags -> IO ()
checkExactConfiguration Verbosity
verbosity GenericPackageDescription
pkg_descr0 ConfigFlags
cfg =
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (ConfigFlags -> Flag Bool
configExactConfiguration ConfigFlags
cfg)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    let cmdlineFlags :: [FlagName]
cmdlineFlags = ((FlagName, Bool) -> FlagName) -> [(FlagName, Bool)] -> [FlagName]
forall a b. (a -> b) -> [a] -> [b]
map (FlagName, Bool) -> FlagName
forall a b. (a, b) -> a
fst (FlagAssignment -> [(FlagName, Bool)]
unFlagAssignment (ConfigFlags -> FlagAssignment
configConfigurationsFlags ConfigFlags
cfg))
        allFlags :: [FlagName]
allFlags = (PackageFlag -> FlagName) -> [PackageFlag] -> [FlagName]
forall a b. (a -> b) -> [a] -> [b]
map PackageFlag -> FlagName
flagName ([PackageFlag] -> [FlagName])
-> (GenericPackageDescription -> [PackageFlag])
-> GenericPackageDescription
-> [FlagName]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GenericPackageDescription -> [PackageFlag]
genPackageFlags (GenericPackageDescription -> [FlagName])
-> GenericPackageDescription -> [FlagName]
forall a b. (a -> b) -> a -> b
$ GenericPackageDescription
pkg_descr0
        diffFlags :: [FlagName]
diffFlags = [FlagName]
allFlags [FlagName] -> [FlagName] -> [FlagName]
forall a. Eq a => [a] -> [a] -> [a]
\\ [FlagName]
cmdlineFlags
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Bool -> Bool) -> ([FlagName] -> Bool) -> [FlagName] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [FlagName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([FlagName] -> Bool) -> [FlagName] -> Bool
forall a b. (a -> b) -> a -> b
$ [FlagName]
diffFlags) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
        [FlagName] -> CabalException
FlagsNotSpecified [FlagName]
diffFlags

-- | Create a PackageIndex that makes *any libraries that might be*
-- defined internally to this package look like installed packages, in
-- case an executable should refer to any of them as dependencies.
--
-- It must be *any libraries that might be* defined rather than the
-- actual definitions, because these depend on conditionals in the .cabal
-- file, and we haven't resolved them yet.  finalizePD
-- does the resolution of conditionals, and it takes internalPackageSet
-- as part of its input.
getInternalLibraries
  :: GenericPackageDescription
  -> Set LibraryName
getInternalLibraries :: GenericPackageDescription -> Set LibraryName
getInternalLibraries GenericPackageDescription
pkg_descr0 =
  -- TODO: some day, executables will be fair game here too!
  let pkg_descr :: PackageDescription
pkg_descr = GenericPackageDescription -> PackageDescription
flattenPackageDescription GenericPackageDescription
pkg_descr0
   in [LibraryName] -> Set LibraryName
forall a. Ord a => [a] -> Set a
Set.fromList ((Library -> LibraryName) -> [Library] -> [LibraryName]
forall a b. (a -> b) -> [a] -> [b]
map Library -> LibraryName
libName (PackageDescription -> [Library]
allLibraries PackageDescription
pkg_descr))

-- | Returns true if a dependency is satisfiable.  This function may
-- report a dependency satisfiable even when it is not, but not vice
-- versa. This is to be passed to finalize
dependencySatisfiable
  :: Bool
  -- ^ use external internal deps?
  -> Bool
  -- ^ exact configuration?
  -> Bool
  -- ^ allow depending on private libs?
  -> PackageName
  -> InstalledPackageIndex
  -- ^ installed set
  -> Set LibraryName
  -- ^ library components
  -> Map (PackageName, ComponentName) ComponentId
  -> Map (PackageName, ComponentName) InstalledPackageInfo
  -- ^ required dependencies
  -> (Dependency -> Bool)
dependencySatisfiable :: Bool
-> Bool
-> Bool
-> PackageName
-> InstalledPackageIndex
-> Set LibraryName
-> Map (PackageName, ComponentName) ComponentId
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Dependency
-> Bool
dependencySatisfiable
  Bool
use_external_internal_deps
  Bool
exact_config
  Bool
allow_private_deps
  PackageName
pn
  InstalledPackageIndex
installedPackageSet
  Set LibraryName
packageLibraries
  Map (PackageName, ComponentName) ComponentId
promisedDeps
  Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
  (Dependency PackageName
depName VersionRange
vr NonEmptySet LibraryName
sublibs)
    | Bool
exact_config =
        -- When we're given '--exact-configuration', we assume that all
        -- dependencies and flags are exactly specified on the command
        -- line. Thus we only consult the 'requiredDepsMap'. Note that
        -- we're not doing the version range check, so if there's some
        -- dependency that wasn't specified on the command line,
        -- 'finalizePD' will fail.
        -- TODO: mention '--exact-configuration' in the error message
        -- when this fails?
        if Bool
isInternalDep Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
use_external_internal_deps
          then -- Except for internal deps, when we're NOT per-component mode;
          -- those are just True.
            Bool
internalDepSatisfiable
          else -- Backward compatibility for the old sublibrary syntax

            ( NonEmptySet LibraryName
sublibs NonEmptySet LibraryName -> NonEmptySet LibraryName -> Bool
forall a. Eq a => a -> a -> Bool
== NonEmptySet LibraryName
mainLibSet
                Bool -> Bool -> Bool
&& (PackageName, ComponentName)
-> Map (PackageName, ComponentName) InstalledPackageInfo -> Bool
forall k a. Ord k => k -> Map k a -> Bool
Map.member
                  ( PackageName
pn
                  , LibraryName -> ComponentName
CLibName (LibraryName -> ComponentName) -> LibraryName -> ComponentName
forall a b. (a -> b) -> a -> b
$
                      UnqualComponentName -> LibraryName
LSubLibName (UnqualComponentName -> LibraryName)
-> UnqualComponentName -> LibraryName
forall a b. (a -> b) -> a -> b
$
                        PackageName -> UnqualComponentName
packageNameToUnqualComponentName PackageName
depName
                  )
                  Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
            )
              Bool -> Bool -> Bool
|| (LibraryName -> Bool) -> NonEmptySet LibraryName -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all LibraryName -> Bool
visible NonEmptySet LibraryName
sublibs
    | Bool
isInternalDep =
        if Bool
use_external_internal_deps
          then -- When we are doing per-component configure, we now need to
          -- test if the internal dependency is in the index.  This has
          -- DIFFERENT semantics from normal dependency satisfiability.
            Bool
internalDepSatisfiableExternally
          else -- If a 'PackageName' is defined by an internal component, the dep is
          -- satisfiable (we're going to build it ourselves)
            Bool
internalDepSatisfiable
    | Bool
otherwise =
        Bool
depSatisfiable
    where
      -- Internal dependency is when dependency is the same as package.
      isInternalDep :: Bool
isInternalDep = PackageName
pn PackageName -> PackageName -> Bool
forall a. Eq a => a -> a -> Bool
== PackageName
depName

      depSatisfiable :: Bool
depSatisfiable =
        Bool -> Bool
not (Bool -> Bool)
-> ([(Version, [InstalledPackageInfo])] -> Bool)
-> [(Version, [InstalledPackageInfo])]
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(Version, [InstalledPackageInfo])] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(Version, [InstalledPackageInfo])] -> Bool)
-> [(Version, [InstalledPackageInfo])] -> Bool
forall a b. (a -> b) -> a -> b
$ InstalledPackageIndex
-> PackageName
-> VersionRange
-> [(Version, [InstalledPackageInfo])]
PackageIndex.lookupDependency InstalledPackageIndex
installedPackageSet PackageName
depName VersionRange
vr

      internalDepSatisfiable :: Bool
internalDepSatisfiable =
        Set LibraryName -> Set LibraryName -> Bool
forall a. Ord a => Set a -> Set a -> Bool
Set.isSubsetOf (NonEmptySet LibraryName -> Set LibraryName
forall a. NonEmptySet a -> Set a
NES.toSet NonEmptySet LibraryName
sublibs) Set LibraryName
packageLibraries
      internalDepSatisfiableExternally :: Bool
internalDepSatisfiableExternally =
        (LibraryName -> Bool) -> NonEmptySet LibraryName -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (\LibraryName
ln -> Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ [(Version, [InstalledPackageInfo])] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([(Version, [InstalledPackageInfo])] -> Bool)
-> [(Version, [InstalledPackageInfo])] -> Bool
forall a b. (a -> b) -> a -> b
$ InstalledPackageIndex
-> PackageName
-> VersionRange
-> LibraryName
-> [(Version, [InstalledPackageInfo])]
PackageIndex.lookupInternalDependency InstalledPackageIndex
installedPackageSet PackageName
pn VersionRange
vr LibraryName
ln) NonEmptySet LibraryName
sublibs

      -- Check whether a library exists and is visible.
      -- We don't disambiguate between dependency on non-existent or private
      -- library yet, so we just return a bool and later report a generic error.
      visible :: LibraryName -> Bool
visible LibraryName
lib =
        Bool
-> (InstalledPackageInfo -> Bool)
-> Maybe InstalledPackageInfo
-> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe
          Bool
False -- Does not even exist (wasn't in the depsMap)
          ( \InstalledPackageInfo
ipi ->
              InstalledPackageInfo -> LibraryVisibility
IPI.libVisibility InstalledPackageInfo
ipi LibraryVisibility -> LibraryVisibility -> Bool
forall a. Eq a => a -> a -> Bool
== LibraryVisibility
LibraryVisibilityPublic
                -- If the override is enabled, the visibility does
                -- not matter (it's handled externally)
                Bool -> Bool -> Bool
|| Bool
allow_private_deps
                -- If it's a library of the same package then it's
                -- always visible.
                -- This is only triggered when passing a component
                -- of the same package as --dependency, such as in:
                -- cabal-testsuite/PackageTests/ConfigureComponent/SubLib/setup-explicit.test.hs
                Bool -> Bool -> Bool
|| PackageIdentifier -> PackageName
pkgName (InstalledPackageInfo -> PackageIdentifier
IPI.sourcePackageId InstalledPackageInfo
ipi) PackageName -> PackageName -> Bool
forall a. Eq a => a -> a -> Bool
== PackageName
pn
          )
          Maybe InstalledPackageInfo
maybeIPI
          -- Don't check if it's visible, we promise to build it before we need it.
          Bool -> Bool -> Bool
|| Bool
promised
        where
          maybeIPI :: Maybe InstalledPackageInfo
maybeIPI = (PackageName, ComponentName)
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Maybe InstalledPackageInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
depName, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
          promised :: Bool
promised = Maybe ComponentId -> Bool
forall a. Maybe a -> Bool
isJust (Maybe ComponentId -> Bool) -> Maybe ComponentId -> Bool
forall a b. (a -> b) -> a -> b
$ (PackageName, ComponentName)
-> Map (PackageName, ComponentName) ComponentId
-> Maybe ComponentId
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
depName, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) ComponentId
promisedDeps

-- | Finalize a generic package description.
--
-- The workhorse is 'finalizePD'.
configureFinalizedPackage
  :: Verbosity
  -> ConfigFlags
  -> ComponentRequestedSpec
  -> [PackageVersionConstraint]
  -> (Dependency -> Bool)
  -- ^ tests if a dependency is satisfiable.
  -- Might say it's satisfiable even when not.
  -> Compiler
  -> Platform
  -> GenericPackageDescription
  -> IO (PackageDescription, FlagAssignment)
configureFinalizedPackage :: Verbosity
-> ConfigFlags
-> ComponentRequestedSpec
-> [PackageVersionConstraint]
-> (Dependency -> Bool)
-> Compiler
-> Platform
-> GenericPackageDescription
-> IO (PackageDescription, FlagAssignment)
configureFinalizedPackage
  Verbosity
verbosity
  ConfigFlags
cfg
  ComponentRequestedSpec
enabled
  [PackageVersionConstraint]
allConstraints
  Dependency -> Bool
satisfies
  Compiler
comp
  Platform
compPlatform
  GenericPackageDescription
pkg_descr0 = do
    (pkg_descr, flags) <-
      case FlagAssignment
-> ComponentRequestedSpec
-> (Dependency -> Bool)
-> Platform
-> CompilerInfo
-> [PackageVersionConstraint]
-> GenericPackageDescription
-> Either [Dependency] (PackageDescription, FlagAssignment)
finalizePD
        (ConfigFlags -> FlagAssignment
configConfigurationsFlags ConfigFlags
cfg)
        ComponentRequestedSpec
enabled
        Dependency -> Bool
satisfies
        Platform
compPlatform
        (Compiler -> CompilerInfo
compilerInfo Compiler
comp)
        [PackageVersionConstraint]
allConstraints
        GenericPackageDescription
pkg_descr0 of
        Right (PackageDescription, FlagAssignment)
r -> (PackageDescription, FlagAssignment)
-> IO (PackageDescription, FlagAssignment)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription, FlagAssignment)
r
        Left [Dependency]
missing ->
          Verbosity
-> CabalException -> IO (PackageDescription, FlagAssignment)
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO (PackageDescription, FlagAssignment))
-> CabalException -> IO (PackageDescription, FlagAssignment)
forall a b. (a -> b) -> a -> b
$ [Dependency] -> CabalException
EncounteredMissingDependency [Dependency]
missing

    unless (nullFlagAssignment flags) $
      info verbosity $
        "Flags chosen: "
          ++ intercalate
            ", "
            [ unFlagName fn ++ "=" ++ prettyShow value
            | (fn, value) <- unFlagAssignment flags
            ]

    return (pkg_descr, flags)

-- | Check for use of Cabal features which require compiler support
checkCompilerProblems
  :: Verbosity -> Compiler -> PackageDescription -> ComponentRequestedSpec -> IO ()
checkCompilerProblems :: Verbosity
-> Compiler
-> PackageDescription
-> ComponentRequestedSpec
-> IO ()
checkCompilerProblems Verbosity
verbosity Compiler
comp PackageDescription
pkg_descr ComponentRequestedSpec
enabled = do
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless
    ( Compiler -> Bool
renamingPackageFlagsSupported Compiler
comp
        Bool -> Bool -> Bool
|| (BuildInfo -> Bool) -> [BuildInfo] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all
          ((Mixin -> Bool) -> [Mixin] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all (IncludeRenaming -> Bool
isDefaultIncludeRenaming (IncludeRenaming -> Bool)
-> (Mixin -> IncludeRenaming) -> Mixin -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mixin -> IncludeRenaming
mixinIncludeRenaming) ([Mixin] -> Bool) -> (BuildInfo -> [Mixin]) -> BuildInfo -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BuildInfo -> [Mixin]
mixins)
          (PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr ComponentRequestedSpec
enabled)
    )
    (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
CompilerDoesn'tSupportThinning
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when
    ( (Library -> Bool) -> [Library] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Bool -> Bool
not (Bool -> Bool) -> (Library -> Bool) -> Library -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ModuleReexport] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([ModuleReexport] -> Bool)
-> (Library -> [ModuleReexport]) -> Library -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Library -> [ModuleReexport]
reexportedModules) (PackageDescription -> [Library]
allLibraries PackageDescription
pkg_descr)
        Bool -> Bool -> Bool
&& Bool -> Bool
not (Compiler -> Bool
reexportedModulesSupported Compiler
comp)
    )
    (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
CompilerDoesn'tSupportReexports
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when
    ( (Library -> Bool) -> [Library] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (Bool -> Bool
not (Bool -> Bool) -> (Library -> Bool) -> Library -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ModuleName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([ModuleName] -> Bool)
-> (Library -> [ModuleName]) -> Library -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Library -> [ModuleName]
signatures) (PackageDescription -> [Library]
allLibraries PackageDescription
pkg_descr)
        Bool -> Bool -> Bool
&& Bool -> Bool
not (Compiler -> Bool
backpackSupported Compiler
comp)
    )
    (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
CompilerDoesn'tSupportBackpack

-- | Select dependencies for the package.
configureDependencies
  :: Verbosity
  -> UseExternalInternalDeps
  -> Set LibraryName
  -> Map (PackageName, ComponentName) ComponentId
  -> InstalledPackageIndex
  -- ^ installed packages
  -> Map (PackageName, ComponentName) InstalledPackageInfo
  -- ^ required deps
  -> PackageDescription
  -> ComponentRequestedSpec
  -> IO ([PreExistingComponent], [PromisedComponent])
configureDependencies :: Verbosity
-> Bool
-> Set LibraryName
-> Map (PackageName, ComponentName) ComponentId
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> PackageDescription
-> ComponentRequestedSpec
-> IO ([PreExistingComponent], [PromisedComponent])
configureDependencies
  Verbosity
verbosity
  Bool
use_external_internal_deps
  Set LibraryName
packageLibraries
  Map (PackageName, ComponentName) ComponentId
promisedDeps
  InstalledPackageIndex
installedPackageSet
  Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
  PackageDescription
pkg_descr
  ComponentRequestedSpec
enableSpec = do
    let failedDeps :: [FailedDependency]
        allPkgDeps :: [ResolvedDependency]
        ([FailedDependency]
failedDeps, [ResolvedDependency]
allPkgDeps) =
          [Either FailedDependency ResolvedDependency]
-> ([FailedDependency], [ResolvedDependency])
forall a b. [Either a b] -> ([a], [b])
partitionEithers ([Either FailedDependency ResolvedDependency]
 -> ([FailedDependency], [ResolvedDependency]))
-> [Either FailedDependency ResolvedDependency]
-> ([FailedDependency], [ResolvedDependency])
forall a b. (a -> b) -> a -> b
$
            [[Either FailedDependency ResolvedDependency]]
-> [Either FailedDependency ResolvedDependency]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
              [ (DependencyResolution -> ResolvedDependency)
-> Either FailedDependency DependencyResolution
-> Either FailedDependency ResolvedDependency
forall a b.
(a -> b) -> Either FailedDependency a -> Either FailedDependency b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\DependencyResolution
s -> (Dependency
dep, DependencyResolution
s)) (Either FailedDependency DependencyResolution
 -> Either FailedDependency ResolvedDependency)
-> [Either FailedDependency DependencyResolution]
-> [Either FailedDependency ResolvedDependency]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Either FailedDependency DependencyResolution]
status
              | Dependency
dep <- PackageDescription -> ComponentRequestedSpec -> [Dependency]
enabledBuildDepends PackageDescription
pkg_descr ComponentRequestedSpec
enableSpec
              , let status :: [Either FailedDependency DependencyResolution]
status =
                      PackageIdentifier
-> Set LibraryName
-> Map (PackageName, ComponentName) ComponentId
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Bool
-> Dependency
-> [Either FailedDependency DependencyResolution]
selectDependency
                        (PackageDescription -> PackageIdentifier
package PackageDescription
pkg_descr)
                        Set LibraryName
packageLibraries
                        Map (PackageName, ComponentName) ComponentId
promisedDeps
                        InstalledPackageIndex
installedPackageSet
                        Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
                        Bool
use_external_internal_deps
                        Dependency
dep
              ]

        internalPkgDeps :: [PackageIdentifier]
internalPkgDeps =
          [ PackageIdentifier
pkgid
          | (Dependency
_, InternalDependency PackageIdentifier
pkgid) <- [ResolvedDependency]
allPkgDeps
          ]
        -- NB: we have to SAVE the package name, because this is the only
        -- way we can be able to resolve package names in the package
        -- description.
        externalPkgDeps :: [PreExistingComponent]
externalPkgDeps =
          [ PreExistingComponent
pec
          | (Dependency
_, ExternalDependency PreExistingComponent
pec) <- [ResolvedDependency]
allPkgDeps
          ]

        promisedPkgDeps :: [PromisedComponent]
promisedPkgDeps =
          [ PromisedComponent
fpec
          | (Dependency
_, PromisedDependency PromisedComponent
fpec) <- [ResolvedDependency]
allPkgDeps
          ]

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when
      ( Bool -> Bool
not ([PackageIdentifier] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PackageIdentifier]
internalPkgDeps)
          Bool -> Bool -> Bool
&& Bool -> Bool
not (PackageDescription -> Bool
newPackageDepsBehaviour PackageDescription
pkg_descr)
      )
      (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity
      (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$ [PackageIdentifier] -> CabalException
LibraryWithinSamePackage [PackageIdentifier]
internalPkgDeps
    Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies Verbosity
verbosity [FailedDependency]
failedDeps
    Verbosity -> [ResolvedDependency] -> IO ()
reportSelectedDependencies Verbosity
verbosity [ResolvedDependency]
allPkgDeps

    ([PreExistingComponent], [PromisedComponent])
-> IO ([PreExistingComponent], [PromisedComponent])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([PreExistingComponent]
externalPkgDeps, [PromisedComponent]
promisedPkgDeps)

-- | Select and apply coverage settings for the build based on the
-- 'ConfigFlags' and 'Compiler'.
configureCoverage
  :: Verbosity
  -> ConfigFlags
  -> Compiler
  -> IO (LBC.BuildOptions -> LBC.BuildOptions)
configureCoverage :: Verbosity
-> ConfigFlags -> Compiler -> IO (BuildOptions -> BuildOptions)
configureCoverage Verbosity
verbosity ConfigFlags
cfg Compiler
comp = do
  let tryExeCoverage :: Bool
tryExeCoverage = Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (ConfigFlags -> Flag Bool
configCoverage ConfigFlags
cfg)
      tryLibCoverage :: Bool
tryLibCoverage =
        Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault
          Bool
tryExeCoverage
          (Flag Bool -> Flag Bool -> Flag Bool
forall a. Monoid a => a -> a -> a
mappend (ConfigFlags -> Flag Bool
configCoverage ConfigFlags
cfg) (ConfigFlags -> Flag Bool
configLibCoverage ConfigFlags
cfg))
  -- TODO: Should we also enforce something here on that --coverage-for cannot
  -- include indefinite components or instantiations?
  if Compiler -> Bool
coverageSupported Compiler
comp
    then do
      let apply :: BuildOptions -> BuildOptions
apply BuildOptions
buildOptions =
            BuildOptions
buildOptions
              { LBC.libCoverage = tryLibCoverage
              , LBC.exeCoverage = tryExeCoverage
              }
      (BuildOptions -> BuildOptions) -> IO (BuildOptions -> BuildOptions)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return BuildOptions -> BuildOptions
apply
    else do
      let apply :: BuildOptions -> BuildOptions
apply BuildOptions
buildOptions =
            BuildOptions
buildOptions
              { LBC.libCoverage = False
              , LBC.exeCoverage = False
              }
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
tryExeCoverage Bool -> Bool -> Bool
|| Bool
tryLibCoverage) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> ProgArg -> IO ()
warn
          Verbosity
verbosity
          ( ProgArg
"The compiler "
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Compiler -> ProgArg
showCompilerId Compiler
comp
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
" does not support "
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"program coverage. Program coverage has been disabled."
          )
      (BuildOptions -> BuildOptions) -> IO (BuildOptions -> BuildOptions)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return BuildOptions -> BuildOptions
apply

-- | Compute the effective value of the profiling flags
-- @--enable-library-profiling@ and @--enable-executable-profiling@
-- from the specified 'ConfigFlags'.  This may be useful for
-- external Cabal tools which need to interact with Setup in
-- a backwards-compatible way: the most predictable mechanism
-- for enabling profiling across many legacy versions is to
-- NOT use @--enable-profiling@ and use those two flags instead.
--
-- Note that @--enable-executable-profiling@ also affects profiling
-- of benchmarks and (non-detailed) test suites.
computeEffectiveProfiling :: ConfigFlags -> (Bool {- lib -}, Bool {- exe -})
computeEffectiveProfiling :: ConfigFlags -> (Bool, Bool)
computeEffectiveProfiling ConfigFlags
cfg =
  -- The --profiling flag sets the default for both libs and exes,
  -- but can be overridden by --library-profiling, or the old deprecated
  -- --executable-profiling flag.
  --
  -- The --profiling-detail and --library-profiling-detail flags behave
  -- similarly
  let tryExeProfiling :: Bool
tryExeProfiling =
        Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault
          Bool
False
          (Flag Bool -> Flag Bool -> Flag Bool
forall a. Monoid a => a -> a -> a
mappend (ConfigFlags -> Flag Bool
configProf ConfigFlags
cfg) (ConfigFlags -> Flag Bool
configProfExe ConfigFlags
cfg))
      tryLibProfiling :: Bool
tryLibProfiling =
        Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault
          Bool
tryExeProfiling
          (Flag Bool -> Flag Bool -> Flag Bool
forall a. Monoid a => a -> a -> a
mappend (ConfigFlags -> Flag Bool
configProf ConfigFlags
cfg) (ConfigFlags -> Flag Bool
configProfLib ConfigFlags
cfg))
   in (Bool
tryLibProfiling, Bool
tryExeProfiling)

-- | Select and apply profiling settings for the build based on the
-- 'ConfigFlags' and 'Compiler'.
configureProfiling
  :: Verbosity
  -> ConfigFlags
  -> Compiler
  -> IO (LBC.BuildOptions -> LBC.BuildOptions)
configureProfiling :: Verbosity
-> ConfigFlags -> Compiler -> IO (BuildOptions -> BuildOptions)
configureProfiling Verbosity
verbosity ConfigFlags
cfg Compiler
comp = do
  let (Bool
tryLibProfiling, Bool
tryExeProfiling) = ConfigFlags -> (Bool, Bool)
computeEffectiveProfiling ConfigFlags
cfg

      tryExeProfileLevel :: ProfDetailLevel
tryExeProfileLevel =
        ProfDetailLevel -> Flag ProfDetailLevel -> ProfDetailLevel
forall a. a -> Flag a -> a
fromFlagOrDefault
          ProfDetailLevel
ProfDetailDefault
          (ConfigFlags -> Flag ProfDetailLevel
configProfDetail ConfigFlags
cfg)
      tryLibProfileLevel :: ProfDetailLevel
tryLibProfileLevel =
        ProfDetailLevel -> Flag ProfDetailLevel -> ProfDetailLevel
forall a. a -> Flag a -> a
fromFlagOrDefault
          ProfDetailLevel
ProfDetailDefault
          ( Flag ProfDetailLevel
-> Flag ProfDetailLevel -> Flag ProfDetailLevel
forall a. Monoid a => a -> a -> a
mappend
              (ConfigFlags -> Flag ProfDetailLevel
configProfDetail ConfigFlags
cfg)
              (ConfigFlags -> Flag ProfDetailLevel
configProfLibDetail ConfigFlags
cfg)
          )

      checkProfileLevel :: ProfDetailLevel -> IO ProfDetailLevel
checkProfileLevel (ProfDetailOther ProgArg
other) = do
        Verbosity -> ProgArg -> IO ()
warn
          Verbosity
verbosity
          ( ProgArg
"Unknown profiling detail level '"
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
other
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"', using default.\nThe profiling detail levels are: "
              ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg -> [ProgArg] -> ProgArg
forall a. [a] -> [[a]] -> [a]
intercalate
                ProgArg
", "
                [ProgArg
name | (ProgArg
name, [ProgArg]
_, ProfDetailLevel
_) <- [(ProgArg, [ProgArg], ProfDetailLevel)]
knownProfDetailLevels]
          )
        ProfDetailLevel -> IO ProfDetailLevel
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ProfDetailLevel
ProfDetailDefault
      checkProfileLevel ProfDetailLevel
other = ProfDetailLevel -> IO ProfDetailLevel
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ProfDetailLevel
other

  (exeProfWithoutLibProf, applyProfiling) <-
    if Compiler -> Bool
profilingSupported Compiler
comp
      then do
        exeLevel <- ProfDetailLevel -> IO ProfDetailLevel
checkProfileLevel ProfDetailLevel
tryExeProfileLevel
        libLevel <- checkProfileLevel tryLibProfileLevel
        let apply BuildOptions
buildOptions =
              BuildOptions
buildOptions
                { LBC.withProfLib = tryLibProfiling
                , LBC.withProfLibDetail = libLevel
                , LBC.withProfExe = tryExeProfiling
                , LBC.withProfExeDetail = exeLevel
                }
        return (tryExeProfiling && not tryLibProfiling, apply)
      else do
        let apply :: BuildOptions -> BuildOptions
apply BuildOptions
buildOptions =
              BuildOptions
buildOptions
                { LBC.withProfLib = False
                , LBC.withProfLibDetail = ProfDetailNone
                , LBC.withProfExe = False
                , LBC.withProfExeDetail = ProfDetailNone
                }
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
tryExeProfiling Bool -> Bool -> Bool
|| Bool
tryLibProfiling) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          Verbosity -> ProgArg -> IO ()
warn
            Verbosity
verbosity
            ( ProgArg
"The compiler "
                ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Compiler -> ProgArg
showCompilerId Compiler
comp
                ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
" does not support "
                ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"profiling. Profiling has been disabled."
            )
        (Bool, BuildOptions -> BuildOptions)
-> IO (Bool, BuildOptions -> BuildOptions)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Bool
False, BuildOptions -> BuildOptions
apply)

  when exeProfWithoutLibProf $
    warn
      verbosity
      ( "Executables will be built with profiling, but library "
          ++ "profiling is disabled. Linking will fail if any executables "
          ++ "depend on the library."
      )

  return applyProfiling

-- -----------------------------------------------------------------------------
-- Configuring package dependencies

reportProgram :: Verbosity -> Program -> Maybe ConfiguredProgram -> IO ()
reportProgram :: Verbosity -> Program -> Maybe ConfiguredProgram -> IO ()
reportProgram Verbosity
verbosity Program
prog Maybe ConfiguredProgram
Nothing =
  Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$ ProgArg
"No " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Program -> ProgArg
programName Program
prog ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
" found"
reportProgram Verbosity
verbosity Program
prog (Just ConfiguredProgram
configuredProg) =
  Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$ ProgArg
"Using " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Program -> ProgArg
programName Program
prog ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
version ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
location
  where
    location :: ProgArg
location = case ConfiguredProgram -> ProgramLocation
programLocation ConfiguredProgram
configuredProg of
      FoundOnSystem ProgArg
p -> ProgArg
" found on system at: " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
p
      UserSpecified ProgArg
p -> ProgArg
" given by user at: " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
p
    version :: ProgArg
version = case ConfiguredProgram -> Maybe Version
programVersion ConfiguredProgram
configuredProg of
      Maybe Version
Nothing -> ProgArg
""
      Just Version
v -> ProgArg
" version " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Version -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow Version
v

hackageUrl :: String
hackageUrl :: ProgArg
hackageUrl = ProgArg
"http://hackage.haskell.org/package/"

type ResolvedDependency = (Dependency, DependencyResolution)

data DependencyResolution
  = -- | An external dependency from the package database, OR an
    -- internal dependency which we are getting from the package
    -- database.
    ExternalDependency PreExistingComponent
  | -- | A promised dependency, which doesn't yet exist, but should be provided
    -- at the build time.
    --
    -- We have these such that we can configure components without actually
    -- building its dependencies, if these dependencies need to be built later
    -- again. For example, when launching a multi-repl,
    -- we need to build packages in the interactive ghci session, no matter
    -- whether they have been built before.
    -- Building them in the configure phase is then redundant and costs time.
    PromisedDependency PromisedComponent
  | -- | An internal dependency ('PackageId' should be a library name)
    -- which we are going to have to build.  (The
    -- 'PackageId' here is a hack to get a modest amount of
    -- polymorphism out of the 'Package' typeclass.)
    InternalDependency PackageId

-- | Test for a package dependency and record the version we have installed.
selectDependency
  :: PackageId
  -- ^ Package id of current package
  -> Set LibraryName
  -- ^ package libraries
  -> Map (PackageName, ComponentName) ComponentId
  -- ^ Set of components that are promised, i.e. are not installed already. See 'PromisedDependency' for more details.
  -> InstalledPackageIndex
  -- ^ Installed packages
  -> Map (PackageName, ComponentName) InstalledPackageInfo
  -- ^ Packages for which we have been given specific deps to
  -- use
  -> UseExternalInternalDeps
  -- ^ Are we configuring a
  -- single component?
  -> Dependency
  -> [Either FailedDependency DependencyResolution]
selectDependency :: PackageIdentifier
-> Set LibraryName
-> Map (PackageName, ComponentName) ComponentId
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Bool
-> Dependency
-> [Either FailedDependency DependencyResolution]
selectDependency
  PackageIdentifier
pkgid
  Set LibraryName
internalIndex
  Map (PackageName, ComponentName) ComponentId
promisedIndex
  InstalledPackageIndex
installedIndex
  Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
  Bool
use_external_internal_deps
  (Dependency PackageName
dep_pkgname VersionRange
vr NonEmptySet LibraryName
libs) =
    -- If the dependency specification matches anything in the internal package
    -- index, then we prefer that match to anything in the second.
    -- For example:
    --
    -- Name: MyLibrary
    -- Version: 0.1
    -- Library
    --     ..
    -- Executable my-exec
    --     build-depends: MyLibrary
    --
    -- We want "build-depends: MyLibrary" always to match the internal library
    -- even if there is a newer installed library "MyLibrary-0.2".
    if PackageName
dep_pkgname PackageName -> PackageName -> Bool
forall a. Eq a => a -> a -> Bool
== PackageName
pn
      then
        if Bool
use_external_internal_deps
          then LibraryName -> Either FailedDependency DependencyResolution
do_external_internal (LibraryName -> Either FailedDependency DependencyResolution)
-> [LibraryName] -> [Either FailedDependency DependencyResolution]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmptySet LibraryName -> [LibraryName]
forall a. NonEmptySet a -> [a]
NES.toList NonEmptySet LibraryName
libs
          else LibraryName -> Either FailedDependency DependencyResolution
do_internal (LibraryName -> Either FailedDependency DependencyResolution)
-> [LibraryName] -> [Either FailedDependency DependencyResolution]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmptySet LibraryName -> [LibraryName]
forall a. NonEmptySet a -> [a]
NES.toList NonEmptySet LibraryName
libs
      else LibraryName -> Either FailedDependency DependencyResolution
do_external_external (LibraryName -> Either FailedDependency DependencyResolution)
-> [LibraryName] -> [Either FailedDependency DependencyResolution]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> NonEmptySet LibraryName -> [LibraryName]
forall a. NonEmptySet a -> [a]
NES.toList NonEmptySet LibraryName
libs
    where
      pn :: PackageName
pn = PackageIdentifier -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageIdentifier
pkgid

      -- It's an internal library, and we're not per-component build
      do_internal :: LibraryName -> Either FailedDependency DependencyResolution
do_internal LibraryName
lib
        | LibraryName -> Set LibraryName -> Bool
forall a. Ord a => a -> Set a -> Bool
Set.member LibraryName
lib Set LibraryName
internalIndex =
            DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. b -> Either a b
Right (DependencyResolution
 -> Either FailedDependency DependencyResolution)
-> DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> DependencyResolution
InternalDependency (PackageIdentifier -> DependencyResolution)
-> PackageIdentifier -> DependencyResolution
forall a b. (a -> b) -> a -> b
$ PackageName -> Version -> PackageIdentifier
PackageIdentifier PackageName
dep_pkgname (Version -> PackageIdentifier) -> Version -> PackageIdentifier
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> Version
forall pkg. Package pkg => pkg -> Version
packageVersion PackageIdentifier
pkgid
        | Bool
otherwise =
            FailedDependency -> Either FailedDependency DependencyResolution
forall a b. a -> Either a b
Left (FailedDependency -> Either FailedDependency DependencyResolution)
-> FailedDependency -> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PackageName -> LibraryName -> FailedDependency
DependencyMissingInternal PackageName
dep_pkgname LibraryName
lib

      -- We have to look it up externally
      do_external_external :: LibraryName -> Either FailedDependency DependencyResolution
      do_external_external :: LibraryName -> Either FailedDependency DependencyResolution
do_external_external LibraryName
lib
        | Just ComponentId
cid <- (PackageName, ComponentName)
-> Map (PackageName, ComponentName) ComponentId
-> Maybe ComponentId
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
dep_pkgname, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) ComponentId
promisedIndex =
            DependencyResolution
-> Either FailedDependency DependencyResolution
forall a. a -> Either FailedDependency a
forall (m :: * -> *) a. Monad m => a -> m a
return (DependencyResolution
 -> Either FailedDependency DependencyResolution)
-> DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PromisedComponent -> DependencyResolution
PromisedDependency (PackageName -> AnnotatedId ComponentId -> PromisedComponent
PromisedComponent PackageName
dep_pkgname (PackageIdentifier
-> ComponentName -> ComponentId -> AnnotatedId ComponentId
forall id.
PackageIdentifier -> ComponentName -> id -> AnnotatedId id
AnnotatedId PackageIdentifier
currentCabalId (LibraryName -> ComponentName
CLibName LibraryName
lib) ComponentId
cid))
      do_external_external LibraryName
lib = do
        ipi <- case (PackageName, ComponentName)
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Maybe InstalledPackageInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
dep_pkgname, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap of
          -- If we know the exact pkg to use, then use it.
          Just InstalledPackageInfo
pkginstance -> InstalledPackageInfo
-> Either FailedDependency InstalledPackageInfo
forall a b. b -> Either a b
Right InstalledPackageInfo
pkginstance
          -- Otherwise we just pick an arbitrary instance of the latest version.
          Maybe InstalledPackageInfo
Nothing -> case [(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo
pickLastIPI ([(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo)
-> [(Version, [InstalledPackageInfo])]
-> Maybe InstalledPackageInfo
forall a b. (a -> b) -> a -> b
$ InstalledPackageIndex
-> PackageName
-> VersionRange
-> LibraryName
-> [(Version, [InstalledPackageInfo])]
PackageIndex.lookupInternalDependency InstalledPackageIndex
installedIndex PackageName
dep_pkgname VersionRange
vr LibraryName
lib of
            Maybe InstalledPackageInfo
Nothing -> FailedDependency -> Either FailedDependency InstalledPackageInfo
forall a b. a -> Either a b
Left (PackageName -> FailedDependency
DependencyNotExists PackageName
dep_pkgname)
            Just InstalledPackageInfo
pkg -> InstalledPackageInfo
-> Either FailedDependency InstalledPackageInfo
forall a b. b -> Either a b
Right InstalledPackageInfo
pkg
        return $ ExternalDependency $ ipiToPreExistingComponent ipi

      do_external_internal :: LibraryName -> Either FailedDependency DependencyResolution
      do_external_internal :: LibraryName -> Either FailedDependency DependencyResolution
do_external_internal LibraryName
lib
        | Just ComponentId
cid <- (PackageName, ComponentName)
-> Map (PackageName, ComponentName) ComponentId
-> Maybe ComponentId
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
dep_pkgname, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) ComponentId
promisedIndex =
            DependencyResolution
-> Either FailedDependency DependencyResolution
forall a. a -> Either FailedDependency a
forall (m :: * -> *) a. Monad m => a -> m a
return (DependencyResolution
 -> Either FailedDependency DependencyResolution)
-> DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PromisedComponent -> DependencyResolution
PromisedDependency (PackageName -> AnnotatedId ComponentId -> PromisedComponent
PromisedComponent PackageName
dep_pkgname (PackageIdentifier
-> ComponentName -> ComponentId -> AnnotatedId ComponentId
forall id.
PackageIdentifier -> ComponentName -> id -> AnnotatedId id
AnnotatedId PackageIdentifier
currentCabalId (LibraryName -> ComponentName
CLibName LibraryName
lib) ComponentId
cid))
      do_external_internal LibraryName
lib = do
        ipi <- case (PackageName, ComponentName)
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Maybe InstalledPackageInfo
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (PackageName
dep_pkgname, LibraryName -> ComponentName
CLibName LibraryName
lib) Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap of
          -- If we know the exact pkg to use, then use it.
          Just InstalledPackageInfo
pkginstance -> InstalledPackageInfo
-> Either FailedDependency InstalledPackageInfo
forall a b. b -> Either a b
Right InstalledPackageInfo
pkginstance
          Maybe InstalledPackageInfo
Nothing -> case [(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo
pickLastIPI ([(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo)
-> [(Version, [InstalledPackageInfo])]
-> Maybe InstalledPackageInfo
forall a b. (a -> b) -> a -> b
$ InstalledPackageIndex
-> PackageName
-> VersionRange
-> LibraryName
-> [(Version, [InstalledPackageInfo])]
PackageIndex.lookupInternalDependency InstalledPackageIndex
installedIndex PackageName
pn VersionRange
vr LibraryName
lib of
            -- It's an internal library, being looked up externally
            Maybe InstalledPackageInfo
Nothing -> FailedDependency -> Either FailedDependency InstalledPackageInfo
forall a b. a -> Either a b
Left (PackageName -> LibraryName -> FailedDependency
DependencyMissingInternal PackageName
dep_pkgname LibraryName
lib)
            Just InstalledPackageInfo
pkg -> InstalledPackageInfo
-> Either FailedDependency InstalledPackageInfo
forall a b. b -> Either a b
Right InstalledPackageInfo
pkg
        return $ ExternalDependency $ ipiToPreExistingComponent ipi

      pickLastIPI :: [(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo
      pickLastIPI :: [(Version, [InstalledPackageInfo])] -> Maybe InstalledPackageInfo
pickLastIPI [(Version, [InstalledPackageInfo])]
pkgs = [InstalledPackageInfo] -> Maybe InstalledPackageInfo
forall a. [a] -> Maybe a
safeHead ([InstalledPackageInfo] -> Maybe InstalledPackageInfo)
-> (NonEmpty (Version, [InstalledPackageInfo])
    -> [InstalledPackageInfo])
-> NonEmpty (Version, [InstalledPackageInfo])
-> Maybe InstalledPackageInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Version, [InstalledPackageInfo]) -> [InstalledPackageInfo]
forall a b. (a, b) -> b
snd ((Version, [InstalledPackageInfo]) -> [InstalledPackageInfo])
-> (NonEmpty (Version, [InstalledPackageInfo])
    -> (Version, [InstalledPackageInfo]))
-> NonEmpty (Version, [InstalledPackageInfo])
-> [InstalledPackageInfo]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (Version, [InstalledPackageInfo])
-> (Version, [InstalledPackageInfo])
forall a. NonEmpty a -> a
last (NonEmpty (Version, [InstalledPackageInfo])
 -> Maybe InstalledPackageInfo)
-> Maybe (NonEmpty (Version, [InstalledPackageInfo]))
-> Maybe InstalledPackageInfo
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< [(Version, [InstalledPackageInfo])]
-> Maybe (NonEmpty (Version, [InstalledPackageInfo]))
forall a. [a] -> Maybe (NonEmpty a)
nonEmpty [(Version, [InstalledPackageInfo])]
pkgs

reportSelectedDependencies
  :: Verbosity
  -> [ResolvedDependency]
  -> IO ()
reportSelectedDependencies :: Verbosity -> [ResolvedDependency] -> IO ()
reportSelectedDependencies Verbosity
verbosity [ResolvedDependency]
deps =
  Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$
    [ProgArg] -> ProgArg
unlines
      [ ProgArg
"Dependency "
        ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ Dependency -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow (Dependency -> Dependency
simplifyDependency Dependency
dep)
        ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
": using "
        ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PackageIdentifier
pkgid
      | (Dependency
dep, DependencyResolution
resolution) <- [ResolvedDependency]
deps
      , let pkgid :: PackageIdentifier
pkgid = case DependencyResolution
resolution of
              ExternalDependency PreExistingComponent
pkg' -> PreExistingComponent -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId PreExistingComponent
pkg'
              InternalDependency PackageIdentifier
pkgid' -> PackageIdentifier
pkgid'
              PromisedDependency PromisedComponent
promisedComp -> PromisedComponent -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId PromisedComponent
promisedComp
      ]

reportFailedDependencies :: Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies :: Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies Verbosity
_ [] = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
reportFailedDependencies Verbosity
verbosity [FailedDependency]
failed =
  Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$ [FailedDependency] -> ProgArg -> CabalException
ReportFailedDependencies [FailedDependency]
failed ProgArg
hackageUrl

-- | List all installed packages in the given package databases.
-- Non-existent package databases do not cause errors, they just get skipped
-- with a warning and treated as empty ones, since technically they do not
-- contain any package.
getInstalledPackages
  :: Verbosity
  -> Compiler
  -> PackageDBStack
  -- ^ The stack of package databases.
  -> ProgramDb
  -> IO InstalledPackageIndex
getInstalledPackages :: Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
getInstalledPackages Verbosity
verbosity Compiler
comp PackageDBStack
packageDBs ProgramDb
progdb = do
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (PackageDBStack -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null PackageDBStack
packageDBs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
NoPackageDatabaseSpecified

  Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity ProgArg
"Reading installed packages..."
  -- do not check empty packagedbs (ghc-pkg would error out)
  packageDBs' <- (PackageDB -> IO Bool) -> PackageDBStack -> IO PackageDBStack
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM PackageDB -> IO Bool
packageDBExists PackageDBStack
packageDBs
  case compilerFlavor comp of
    CompilerFlavor
GHC -> Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
GHC.getInstalledPackages Verbosity
verbosity Compiler
comp PackageDBStack
packageDBs' ProgramDb
progdb
    CompilerFlavor
GHCJS -> Verbosity
-> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
GHCJS.getInstalledPackages Verbosity
verbosity PackageDBStack
packageDBs' ProgramDb
progdb
    CompilerFlavor
UHC -> Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
UHC.getInstalledPackages Verbosity
verbosity Compiler
comp PackageDBStack
packageDBs' ProgramDb
progdb
    HaskellSuite{} ->
      Verbosity
-> PackageDBStack -> ProgramDb -> IO InstalledPackageIndex
HaskellSuite.getInstalledPackages Verbosity
verbosity PackageDBStack
packageDBs' ProgramDb
progdb
    CompilerFlavor
flv ->
      Verbosity -> CabalException -> IO InstalledPackageIndex
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO InstalledPackageIndex)
-> CabalException -> IO InstalledPackageIndex
forall a b. (a -> b) -> a -> b
$ CompilerFlavor -> CabalException
HowToFindInstalledPackages CompilerFlavor
flv
  where
    packageDBExists :: PackageDB -> IO Bool
packageDBExists (SpecificPackageDB ProgArg
path) = do
      exists <- ProgArg -> IO Bool
doesPathExist ProgArg
path
      unless exists $
        warn verbosity $
          "Package db " <> path <> " does not exist yet"
      return exists
    -- Checking the user and global package dbs is more complicated and needs
    -- way more data. Also ghc-pkg won't error out unless the user/global
    -- pkgdb is overridden with an empty one, so we just don't check for them.
    packageDBExists PackageDB
UserPackageDB = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
    packageDBExists PackageDB
GlobalPackageDB = Bool -> IO Bool
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True

-- | Like 'getInstalledPackages', but for a single package DB.
--
-- NB: Why isn't this always a fall through to 'getInstalledPackages'?
-- That is because 'getInstalledPackages' performs some sanity checks
-- on the package database stack in question.  However, when sandboxes
-- are involved these sanity checks are not desirable.
getPackageDBContents
  :: Verbosity
  -> Compiler
  -> PackageDB
  -> ProgramDb
  -> IO InstalledPackageIndex
getPackageDBContents :: Verbosity
-> Compiler -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
getPackageDBContents Verbosity
verbosity Compiler
comp PackageDB
packageDB ProgramDb
progdb = do
  Verbosity -> ProgArg -> IO ()
info Verbosity
verbosity ProgArg
"Reading installed packages..."
  case Compiler -> CompilerFlavor
compilerFlavor Compiler
comp of
    CompilerFlavor
GHC -> Verbosity -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
GHC.getPackageDBContents Verbosity
verbosity PackageDB
packageDB ProgramDb
progdb
    CompilerFlavor
GHCJS -> Verbosity -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
GHCJS.getPackageDBContents Verbosity
verbosity PackageDB
packageDB ProgramDb
progdb
    -- For other compilers, try to fall back on 'getInstalledPackages'.
    CompilerFlavor
_ -> Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
getInstalledPackages Verbosity
verbosity Compiler
comp [PackageDB
packageDB] ProgramDb
progdb

-- | A set of files (or directories) that can be monitored to detect when
-- there might have been a change in the installed packages.
getInstalledPackagesMonitorFiles
  :: Verbosity
  -> Compiler
  -> PackageDBStack
  -> ProgramDb
  -> Platform
  -> IO [FilePath]
getInstalledPackagesMonitorFiles :: Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> Platform
-> IO [ProgArg]
getInstalledPackagesMonitorFiles Verbosity
verbosity Compiler
comp PackageDBStack
packageDBs ProgramDb
progdb Platform
platform =
  case Compiler -> CompilerFlavor
compilerFlavor Compiler
comp of
    CompilerFlavor
GHC ->
      Verbosity
-> Platform -> ProgramDb -> PackageDBStack -> IO [ProgArg]
GHC.getInstalledPackagesMonitorFiles
        Verbosity
verbosity
        Platform
platform
        ProgramDb
progdb
        PackageDBStack
packageDBs
    CompilerFlavor
other -> do
      Verbosity -> ProgArg -> IO ()
warn Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$
        ProgArg
"don't know how to find change monitoring files for "
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"the installed package databases for "
          ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerFlavor -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow CompilerFlavor
other
      [ProgArg] -> IO [ProgArg]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | Looks up the 'InstalledPackageInfo' of the given 'UnitId's from the
-- 'PackageDBStack' in the 'LocalBuildInfo'.
getInstalledPackagesById
  :: (Exception (VerboseException exception), Show exception, Typeable exception)
  => Verbosity
  -> LocalBuildInfo
  -> (UnitId -> exception)
  -- ^ Construct an exception that is thrown if a
  -- unit-id is not found in the installed packages,
  -- from the unit-id that is missing.
  -> [UnitId]
  -- ^ The unit ids to lookup in the installed packages
  -> IO [InstalledPackageInfo]
getInstalledPackagesById :: forall exception.
(Exception (VerboseException exception), Show exception,
 Typeable exception) =>
Verbosity
-> LocalBuildInfo
-> (UnitId -> exception)
-> [UnitId]
-> IO [InstalledPackageInfo]
getInstalledPackagesById Verbosity
verbosity LocalBuildInfo{compiler :: LocalBuildInfo -> Compiler
compiler = Compiler
comp, withPackageDB :: LocalBuildInfo -> PackageDBStack
withPackageDB = PackageDBStack
pkgDb, withPrograms :: LocalBuildInfo -> ProgramDb
withPrograms = ProgramDb
progDb} UnitId -> exception
mkException [UnitId]
unitids = do
  ipindex <- Verbosity
-> Compiler
-> PackageDBStack
-> ProgramDb
-> IO InstalledPackageIndex
getInstalledPackages Verbosity
verbosity Compiler
comp PackageDBStack
pkgDb ProgramDb
progDb
  mapM
    ( \UnitId
uid -> case InstalledPackageIndex -> UnitId -> Maybe InstalledPackageInfo
forall a. PackageIndex a -> UnitId -> Maybe a
lookupUnitId InstalledPackageIndex
ipindex UnitId
uid of
        Maybe InstalledPackageInfo
Nothing -> Verbosity -> exception -> IO InstalledPackageInfo
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (UnitId -> exception
mkException UnitId
uid)
        Just InstalledPackageInfo
ipkg -> InstalledPackageInfo -> IO InstalledPackageInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return InstalledPackageInfo
ipkg
    )
    unitids

-- | The user interface specifies the package dbs to use with a combination of
-- @--global@, @--user@ and @--package-db=global|user|clear|$file@.
-- This function combines the global/user flag and interprets the package-db
-- flag into a single package db stack.
interpretPackageDbFlags :: Bool -> [Maybe PackageDB] -> PackageDBStack
interpretPackageDbFlags :: Bool -> [Maybe PackageDB] -> PackageDBStack
interpretPackageDbFlags Bool
userInstall [Maybe PackageDB]
specificDBs =
  PackageDBStack -> [Maybe PackageDB] -> PackageDBStack
forall {a}. [a] -> [Maybe a] -> [a]
extra PackageDBStack
initialStack [Maybe PackageDB]
specificDBs
  where
    initialStack :: PackageDBStack
initialStack
      | Bool
userInstall = [PackageDB
GlobalPackageDB, PackageDB
UserPackageDB]
      | Bool
otherwise = [PackageDB
GlobalPackageDB]

    extra :: [a] -> [Maybe a] -> [a]
extra [a]
dbs' [] = [a]
dbs'
    extra [a]
_ (Maybe a
Nothing : [Maybe a]
dbs) = [a] -> [Maybe a] -> [a]
extra [] [Maybe a]
dbs
    extra [a]
dbs' (Just a
db : [Maybe a]
dbs) = [a] -> [Maybe a] -> [a]
extra ([a]
dbs' [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
db]) [Maybe a]
dbs

-- We are given both --constraint="foo < 2.0" style constraints and also
-- specific packages to pick via --dependency="foo=foo-2.0-177d5cdf20962d0581".
--
-- When finalising the package we have to take into account the specific
-- installed deps we've been given, and the finalise function expects
-- constraints, so we have to translate these deps into version constraints.
--
-- But after finalising we then have to make sure we pick the right specific
-- deps in the end. So we still need to remember which installed packages to
-- pick.
combinedConstraints
  :: [PackageVersionConstraint]
  -> [GivenComponent]
  -- ^ installed dependencies
  -> InstalledPackageIndex
  -> Either
      CabalException
      ( [PackageVersionConstraint]
      , Map (PackageName, ComponentName) InstalledPackageInfo
      )
combinedConstraints :: [PackageVersionConstraint]
-> [GivenComponent]
-> InstalledPackageIndex
-> Either
     CabalException
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
combinedConstraints [PackageVersionConstraint]
constraints [GivenComponent]
dependencies InstalledPackageIndex
installedPackages = do
  Bool -> Either CabalException () -> Either CabalException ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([(PackageName, ComponentName, ComponentId)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(PackageName, ComponentName, ComponentId)]
badComponentIds)) (Either CabalException () -> Either CabalException ())
-> Either CabalException () -> Either CabalException ()
forall a b. (a -> b) -> a -> b
$
    CabalException -> Either CabalException ()
forall a b. a -> Either a b
Left (CabalException -> Either CabalException ())
-> CabalException -> Either CabalException ()
forall a b. (a -> b) -> a -> b
$
      Doc -> CabalException
CombinedConstraints ([(PackageName, ComponentName, ComponentId)] -> Doc
forall {a} {a}.
(Pretty a, Pretty a) =>
[(a, ComponentName, a)] -> Doc
dispDependencies [(PackageName, ComponentName, ComponentId)]
badComponentIds)

  -- TODO: we don't check that all dependencies are used!

  ([PackageVersionConstraint],
 Map (PackageName, ComponentName) InstalledPackageInfo)
-> Either
     CabalException
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
forall a. a -> Either CabalException a
forall (m :: * -> *) a. Monad m => a -> m a
return ([PackageVersionConstraint]
allConstraints, Map (PackageName, ComponentName) InstalledPackageInfo
idConstraintMap)
  where
    allConstraints :: [PackageVersionConstraint]
    allConstraints :: [PackageVersionConstraint]
allConstraints =
      [PackageVersionConstraint]
constraints
        [PackageVersionConstraint]
-> [PackageVersionConstraint] -> [PackageVersionConstraint]
forall a. [a] -> [a] -> [a]
++ [ PackageIdentifier -> PackageVersionConstraint
thisPackageVersionConstraint (InstalledPackageInfo -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId InstalledPackageInfo
pkg)
           | (PackageName
_, ComponentName
_, ComponentId
_, Just InstalledPackageInfo
pkg) <- [(PackageName, ComponentName, ComponentId,
  Maybe InstalledPackageInfo)]
dependenciesPkgInfo
           ]

    idConstraintMap :: Map (PackageName, ComponentName) InstalledPackageInfo
    idConstraintMap :: Map (PackageName, ComponentName) InstalledPackageInfo
idConstraintMap =
      [((PackageName, ComponentName), InstalledPackageInfo)]
-> Map (PackageName, ComponentName) InstalledPackageInfo
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList
        -- NB: do NOT use the packageName from
        -- dependenciesPkgInfo!
        [ ((PackageName
pn, ComponentName
cname), InstalledPackageInfo
pkg)
        | (PackageName
pn, ComponentName
cname, ComponentId
_, Just InstalledPackageInfo
pkg) <- [(PackageName, ComponentName, ComponentId,
  Maybe InstalledPackageInfo)]
dependenciesPkgInfo
        ]

    -- The dependencies along with the installed package info, if it exists
    dependenciesPkgInfo :: [(PackageName, ComponentName, ComponentId, Maybe InstalledPackageInfo)]
    dependenciesPkgInfo :: [(PackageName, ComponentName, ComponentId,
  Maybe InstalledPackageInfo)]
dependenciesPkgInfo =
      [ (PackageName
pkgname, LibraryName -> ComponentName
CLibName LibraryName
lname, ComponentId
cid, Maybe InstalledPackageInfo
mpkg)
      | GivenComponent PackageName
pkgname LibraryName
lname ComponentId
cid <- [GivenComponent]
dependencies
      , let mpkg :: Maybe InstalledPackageInfo
mpkg =
              InstalledPackageIndex -> ComponentId -> Maybe InstalledPackageInfo
forall a. PackageIndex a -> ComponentId -> Maybe a
PackageIndex.lookupComponentId
                InstalledPackageIndex
installedPackages
                ComponentId
cid
      ]

    -- If we looked up a package specified by an installed package id
    -- (i.e. someone has written a hash) and didn't find it then it's
    -- an error.
    badComponentIds :: [(PackageName, ComponentName, ComponentId)]
badComponentIds =
      [ (PackageName
pkgname, ComponentName
cname, ComponentId
cid)
      | (PackageName
pkgname, ComponentName
cname, ComponentId
cid, Maybe InstalledPackageInfo
Nothing) <- [(PackageName, ComponentName, ComponentId,
  Maybe InstalledPackageInfo)]
dependenciesPkgInfo
      ]

    dispDependencies :: [(a, ComponentName, a)] -> Doc
dispDependencies [(a, ComponentName, a)]
deps =
      [Doc] -> Doc
hsep
        [ ProgArg -> Doc
text ProgArg
"--dependency="
          Doc -> Doc -> Doc
<<>> Doc -> Doc
quotes
            ( a -> Doc
forall a. Pretty a => a -> Doc
pretty a
pkgname
                Doc -> Doc -> Doc
<<>> case ComponentName
cname of
                  CLibName LibraryName
LMainLibName -> Doc
""
                  CLibName (LSubLibName UnqualComponentName
n) -> Doc
":" Doc -> Doc -> Doc
<<>> UnqualComponentName -> Doc
forall a. Pretty a => a -> Doc
pretty UnqualComponentName
n
                  ComponentName
_ -> Doc
":" Doc -> Doc -> Doc
<<>> ComponentName -> Doc
forall a. Pretty a => a -> Doc
pretty ComponentName
cname
                Doc -> Doc -> Doc
<<>> Char -> Doc
char Char
'='
                Doc -> Doc -> Doc
<<>> a -> Doc
forall a. Pretty a => a -> Doc
pretty a
cid
            )
        | (a
pkgname, ComponentName
cname, a
cid) <- [(a, ComponentName, a)]
deps
        ]

-- -----------------------------------------------------------------------------
-- Configuring program dependencies

configureRequiredPrograms
  :: Verbosity
  -> [LegacyExeDependency]
  -> ProgramDb
  -> IO ProgramDb
configureRequiredPrograms :: Verbosity -> [LegacyExeDependency] -> ProgramDb -> IO ProgramDb
configureRequiredPrograms Verbosity
verbosity [LegacyExeDependency]
deps ProgramDb
progdb =
  (ProgramDb -> LegacyExeDependency -> IO ProgramDb)
-> ProgramDb -> [LegacyExeDependency] -> IO ProgramDb
forall (t :: * -> *) (m :: * -> *) b a.
(Foldable t, Monad m) =>
(b -> a -> m b) -> b -> t a -> m b
foldM (Verbosity -> ProgramDb -> LegacyExeDependency -> IO ProgramDb
configureRequiredProgram Verbosity
verbosity) ProgramDb
progdb [LegacyExeDependency]
deps

-- | Configure a required program, ensuring that it exists in the PATH
-- (or where the user has specified the program must live) and making it
-- available for use via the 'ProgramDb' interface.  If the program is
-- known (exists in the input 'ProgramDb'), we will make sure that the
-- program matches the required version; otherwise we will accept
-- any version of the program and assume that it is a simpleProgram.
configureRequiredProgram
  :: Verbosity
  -> ProgramDb
  -> LegacyExeDependency
  -> IO ProgramDb
configureRequiredProgram :: Verbosity -> ProgramDb -> LegacyExeDependency -> IO ProgramDb
configureRequiredProgram
  Verbosity
verbosity
  ProgramDb
progdb
  (LegacyExeDependency ProgArg
progName VersionRange
verRange) =
    case ProgArg -> ProgramDb -> Maybe Program
lookupKnownProgram ProgArg
progName ProgramDb
progdb of
      Maybe Program
Nothing ->
        -- Try to configure it as a 'simpleProgram' automatically
        --
        -- There's a bit of a story behind this line.  In old versions
        -- of Cabal, there were only internal build-tools dependencies.  So the
        -- behavior in this case was:
        --
        --    - If a build-tool dependency was internal, don't do
        --      any checking.
        --
        --    - If it was external, call 'configureRequiredProgram' to
        --      "configure" the executable.  In particular, if
        --      the program was not "known" (present in 'ProgramDb'),
        --      then we would just error.  This was fine, because
        --      the only way a program could be executed from 'ProgramDb'
        --      is if some library code from Cabal actually called it,
        --      and the pre-existing Cabal code only calls known
        --      programs from 'defaultProgramDb', and so if it
        --      is calling something else, you have a Custom setup
        --      script, and in that case you are expected to register
        --      the program you want to call in the ProgramDb.
        --
        -- OK, so that was fine, until I (ezyang, in 2016) refactored
        -- Cabal to support per-component builds.  In this case, what
        -- was previously an internal build-tool dependency now became
        -- an external one, and now previously "internal" dependencies
        -- are now external.  But these are permitted to exist even
        -- when they are not previously configured (something that
        -- can only occur by a Custom script.)
        --
        -- So, I decided, "Fine, let's just accept these in any
        -- case."  Thus this line.  The alternative would have been to
        -- somehow detect when a build-tools dependency was "internal" (by
        -- looking at the unflattened package description) but this
        -- would also be incompatible with future work to support
        -- external executable dependencies: we definitely cannot
        -- assume they will be preinitialized in the 'ProgramDb'.
        Verbosity -> Program -> ProgramDb -> IO ProgramDb
configureProgram Verbosity
verbosity (ProgArg -> Program
simpleProgram ProgArg
progName) ProgramDb
progdb
      Just Program
prog
        -- requireProgramVersion always requires the program have a version
        -- but if the user says "build-depends: foo" ie no version constraint
        -- then we should not fail if we cannot discover the program version.
        | VersionRange
verRange VersionRange -> VersionRange -> Bool
forall a. Eq a => a -> a -> Bool
== VersionRange
anyVersion -> do
            (_, progdb') <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
prog ProgramDb
progdb
            return progdb'
        | Bool
otherwise -> do
            (_, _, progdb') <- Verbosity
-> Program
-> VersionRange
-> ProgramDb
-> IO (ConfiguredProgram, Version, ProgramDb)
requireProgramVersion Verbosity
verbosity Program
prog VersionRange
verRange ProgramDb
progdb
            return progdb'

-- -----------------------------------------------------------------------------
-- Configuring pkg-config package dependencies

configurePkgconfigPackages
  :: Verbosity
  -> PackageDescription
  -> ProgramDb
  -> ComponentRequestedSpec
  -> IO (PackageDescription, ProgramDb)
configurePkgconfigPackages :: Verbosity
-> PackageDescription
-> ProgramDb
-> ComponentRequestedSpec
-> IO (PackageDescription, ProgramDb)
configurePkgconfigPackages Verbosity
verbosity PackageDescription
pkg_descr ProgramDb
progdb ComponentRequestedSpec
enabled
  | [PkgconfigDependency] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [PkgconfigDependency]
allpkgs = (PackageDescription, ProgramDb)
-> IO (PackageDescription, ProgramDb)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription
pkg_descr, ProgramDb
progdb)
  | Bool
otherwise = do
      (_, _, progdb') <-
        Verbosity
-> Program
-> VersionRange
-> ProgramDb
-> IO (ConfiguredProgram, Version, ProgramDb)
requireProgramVersion
          (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity)
          Program
pkgConfigProgram
          (Version -> VersionRange
orLaterVersion (Version -> VersionRange) -> Version -> VersionRange
forall a b. (a -> b) -> a -> b
$ [Int] -> Version
mkVersion [Int
0, Int
9, Int
0])
          ProgramDb
progdb
      traverse_ requirePkg allpkgs
      mlib' <- traverse addPkgConfigBILib (library pkg_descr)
      libs' <- traverse addPkgConfigBILib (subLibraries pkg_descr)
      exes' <- traverse addPkgConfigBIExe (executables pkg_descr)
      tests' <- traverse addPkgConfigBITest (testSuites pkg_descr)
      benches' <- traverse addPkgConfigBIBench (benchmarks pkg_descr)
      let pkg_descr' =
            PackageDescription
pkg_descr
              { library = mlib'
              , subLibraries = libs'
              , executables = exes'
              , testSuites = tests'
              , benchmarks = benches'
              }
      return (pkg_descr', progdb')
  where
    allpkgs :: [PkgconfigDependency]
allpkgs = (BuildInfo -> [PkgconfigDependency])
-> [BuildInfo] -> [PkgconfigDependency]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [PkgconfigDependency]
pkgconfigDepends (PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr ComponentRequestedSpec
enabled)
    pkgconfig :: [ProgArg] -> IO ProgArg
pkgconfig =
      Verbosity -> Program -> ProgramDb -> [ProgArg] -> IO ProgArg
getDbProgramOutput
        (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity)
        Program
pkgConfigProgram
        ProgramDb
progdb

    requirePkg :: PkgconfigDependency -> IO ()
requirePkg dep :: PkgconfigDependency
dep@(PkgconfigDependency PkgconfigName
pkgn PkgconfigVersionRange
range) = do
      version <-
        [ProgArg] -> IO ProgArg
pkgconfig [ProgArg
"--modversion", ProgArg
pkg]
          IO ProgArg -> (IOException -> IO ProgArg) -> IO ProgArg
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> Verbosity -> CabalException -> IO ProgArg
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ProgArg) -> CabalException -> IO ProgArg
forall a b. (a -> b) -> a -> b
$ ProgArg -> ProgArg -> CabalException
PkgConfigNotFound ProgArg
pkg ProgArg
versionRequirement)
          IO ProgArg -> (ExitCode -> IO ProgArg) -> IO ProgArg
forall a. IO a -> (ExitCode -> IO a) -> IO a
`catchExit` (\ExitCode
_ -> Verbosity -> CabalException -> IO ProgArg
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ProgArg) -> CabalException -> IO ProgArg
forall a b. (a -> b) -> a -> b
$ ProgArg -> ProgArg -> CabalException
PkgConfigNotFound ProgArg
pkg ProgArg
versionRequirement)
      let trim = (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isSpace ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd Char -> Bool
isSpace
      let v = ByteString -> PkgconfigVersion
PkgconfigVersion (ProgArg -> ByteString
toUTF8BS (ProgArg -> ByteString) -> ProgArg -> ByteString
forall a b. (a -> b) -> a -> b
$ ShowS
trim ProgArg
version)
      if not (withinPkgconfigVersionRange v range)
        then dieWithException verbosity $ BadVersion pkg versionRequirement v
        else info verbosity (depSatisfied v)
      where
        depSatisfied :: a -> ProgArg
depSatisfied a
v =
          ProgArg
"Dependency "
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ PkgconfigDependency -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PkgconfigDependency
dep
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
": using version "
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow a
v

        versionRequirement :: ProgArg
versionRequirement
          | PkgconfigVersionRange -> Bool
isAnyPkgconfigVersion PkgconfigVersionRange
range = ProgArg
""
          | Bool
otherwise = ProgArg
" version " ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ PkgconfigVersionRange -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PkgconfigVersionRange
range

        pkg :: ProgArg
pkg = PkgconfigName -> ProgArg
unPkgconfigName PkgconfigName
pkgn

    -- Adds pkgconfig dependencies to the build info for a component
    addPkgConfigBI :: (t -> BuildInfo) -> (t -> BuildInfo -> b) -> t -> IO b
addPkgConfigBI t -> BuildInfo
compBI t -> BuildInfo -> b
setCompBI t
comp = do
      bi <- [PkgconfigDependency] -> IO BuildInfo
pkgconfigBuildInfo (BuildInfo -> [PkgconfigDependency]
pkgconfigDepends (t -> BuildInfo
compBI t
comp))
      return $ setCompBI comp (compBI comp `mappend` bi)

    -- Adds pkgconfig dependencies to the build info for a library
    addPkgConfigBILib :: Library -> IO Library
addPkgConfigBILib = (Library -> BuildInfo)
-> (Library -> BuildInfo -> Library) -> Library -> IO Library
forall {t} {b}.
(t -> BuildInfo) -> (t -> BuildInfo -> b) -> t -> IO b
addPkgConfigBI Library -> BuildInfo
libBuildInfo ((Library -> BuildInfo -> Library) -> Library -> IO Library)
-> (Library -> BuildInfo -> Library) -> Library -> IO Library
forall a b. (a -> b) -> a -> b
$
      \Library
lib BuildInfo
bi -> Library
lib{libBuildInfo = bi}

    -- Adds pkgconfig dependencies to the build info for an executable
    addPkgConfigBIExe :: Executable -> IO Executable
addPkgConfigBIExe = (Executable -> BuildInfo)
-> (Executable -> BuildInfo -> Executable)
-> Executable
-> IO Executable
forall {t} {b}.
(t -> BuildInfo) -> (t -> BuildInfo -> b) -> t -> IO b
addPkgConfigBI Executable -> BuildInfo
buildInfo ((Executable -> BuildInfo -> Executable)
 -> Executable -> IO Executable)
-> (Executable -> BuildInfo -> Executable)
-> Executable
-> IO Executable
forall a b. (a -> b) -> a -> b
$
      \Executable
exe BuildInfo
bi -> Executable
exe{buildInfo = bi}

    -- Adds pkgconfig dependencies to the build info for a test suite
    addPkgConfigBITest :: TestSuite -> IO TestSuite
addPkgConfigBITest = (TestSuite -> BuildInfo)
-> (TestSuite -> BuildInfo -> TestSuite)
-> TestSuite
-> IO TestSuite
forall {t} {b}.
(t -> BuildInfo) -> (t -> BuildInfo -> b) -> t -> IO b
addPkgConfigBI TestSuite -> BuildInfo
testBuildInfo ((TestSuite -> BuildInfo -> TestSuite)
 -> TestSuite -> IO TestSuite)
-> (TestSuite -> BuildInfo -> TestSuite)
-> TestSuite
-> IO TestSuite
forall a b. (a -> b) -> a -> b
$
      \TestSuite
test BuildInfo
bi -> TestSuite
test{testBuildInfo = bi}

    -- Adds pkgconfig dependencies to the build info for a benchmark
    addPkgConfigBIBench :: Benchmark -> IO Benchmark
addPkgConfigBIBench = (Benchmark -> BuildInfo)
-> (Benchmark -> BuildInfo -> Benchmark)
-> Benchmark
-> IO Benchmark
forall {t} {b}.
(t -> BuildInfo) -> (t -> BuildInfo -> b) -> t -> IO b
addPkgConfigBI Benchmark -> BuildInfo
benchmarkBuildInfo ((Benchmark -> BuildInfo -> Benchmark)
 -> Benchmark -> IO Benchmark)
-> (Benchmark -> BuildInfo -> Benchmark)
-> Benchmark
-> IO Benchmark
forall a b. (a -> b) -> a -> b
$
      \Benchmark
bench BuildInfo
bi -> Benchmark
bench{benchmarkBuildInfo = bi}

    pkgconfigBuildInfo :: [PkgconfigDependency] -> IO BuildInfo
    pkgconfigBuildInfo :: [PkgconfigDependency] -> IO BuildInfo
pkgconfigBuildInfo [] = BuildInfo -> IO BuildInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return BuildInfo
forall a. Monoid a => a
mempty
    pkgconfigBuildInfo [PkgconfigDependency]
pkgdeps = do
      let pkgs :: [ProgArg]
pkgs = [ProgArg] -> [ProgArg]
forall a. Eq a => [a] -> [a]
nub [PkgconfigName -> ProgArg
forall a. Pretty a => a -> ProgArg
prettyShow PkgconfigName
pkg | PkgconfigDependency PkgconfigName
pkg PkgconfigVersionRange
_ <- [PkgconfigDependency]
pkgdeps]
      ccflags <- [ProgArg] -> IO ProgArg
pkgconfig (ProgArg
"--cflags" ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: [ProgArg]
pkgs)
      ldflags <- pkgconfig ("--libs" : pkgs)
      ldflags_static <- pkgconfig ("--libs" : "--static" : pkgs)
      return (ccLdOptionsBuildInfo (words ccflags) (words ldflags) (words ldflags_static))

-- | Makes a 'BuildInfo' from C compiler and linker flags.
--
-- This can be used with the output from configuration programs like pkg-config
-- and similar package-specific programs like mysql-config, freealut-config etc.
-- For example:
--
-- > ccflags <- getDbProgramOutput verbosity prog progdb ["--cflags"]
-- > ldflags <- getDbProgramOutput verbosity prog progdb ["--libs"]
-- > ldflags_static <- getDbProgramOutput verbosity prog progdb ["--libs", "--static"]
-- > return (ccldOptionsBuildInfo (words ccflags) (words ldflags) (words ldflags_static))
ccLdOptionsBuildInfo :: [String] -> [String] -> [String] -> BuildInfo
ccLdOptionsBuildInfo :: [ProgArg] -> [ProgArg] -> [ProgArg] -> BuildInfo
ccLdOptionsBuildInfo [ProgArg]
cflags [ProgArg]
ldflags [ProgArg]
ldflags_static =
  let ([ProgArg]
includeDirs', [ProgArg]
cflags') = (ProgArg -> Bool) -> [ProgArg] -> ([ProgArg], [ProgArg])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (ProgArg
"-I" ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [ProgArg]
cflags
      ([ProgArg]
extraLibs', [ProgArg]
ldflags') = (ProgArg -> Bool) -> [ProgArg] -> ([ProgArg], [ProgArg])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (ProgArg
"-l" ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [ProgArg]
ldflags
      ([ProgArg]
extraLibDirs', [ProgArg]
ldflags'') = (ProgArg -> Bool) -> [ProgArg] -> ([ProgArg], [ProgArg])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (ProgArg
"-L" ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [ProgArg]
ldflags'
      ([ProgArg]
extraLibsStatic') = (ProgArg -> Bool) -> [ProgArg] -> [ProgArg]
forall a. (a -> Bool) -> [a] -> [a]
filter (ProgArg
"-l" ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [ProgArg]
ldflags_static
      ([ProgArg]
extraLibDirsStatic') = (ProgArg -> Bool) -> [ProgArg] -> [ProgArg]
forall a. (a -> Bool) -> [a] -> [a]
filter (ProgArg
"-L" ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [ProgArg]
ldflags_static
   in BuildInfo
forall a. Monoid a => a
mempty
        { includeDirs = map (drop 2) includeDirs'
        , extraLibs = map (drop 2) extraLibs'
        , extraLibDirs = map (drop 2) extraLibDirs'
        , extraLibsStatic = map (drop 2) extraLibsStatic'
        , extraLibDirsStatic = map (drop 2) extraLibDirsStatic'
        , ccOptions = cflags'
        , ldOptions = ldflags''
        }

-- -----------------------------------------------------------------------------
-- Determining the compiler details

configCompilerAuxEx
  :: ConfigFlags
  -> IO (Compiler, Platform, ProgramDb)
configCompilerAuxEx :: ConfigFlags -> IO (Compiler, Platform, ProgramDb)
configCompilerAuxEx ConfigFlags
cfg = do
  programDb <- ConfigFlags -> ProgramDb -> IO ProgramDb
mkProgramDb ConfigFlags
cfg ProgramDb
defaultProgramDb
  configCompilerEx
    (flagToMaybe $ configHcFlavor cfg)
    (flagToMaybe $ configHcPath cfg)
    (flagToMaybe $ configHcPkg cfg)
    programDb
    (fromFlag (configVerbosity cfg))

configCompilerEx
  :: Maybe CompilerFlavor
  -> Maybe FilePath
  -> Maybe FilePath
  -> ProgramDb
  -> Verbosity
  -> IO (Compiler, Platform, ProgramDb)
configCompilerEx :: Maybe CompilerFlavor
-> Maybe ProgArg
-> Maybe ProgArg
-> ProgramDb
-> Verbosity
-> IO (Compiler, Platform, ProgramDb)
configCompilerEx Maybe CompilerFlavor
Nothing Maybe ProgArg
_ Maybe ProgArg
_ ProgramDb
_ Verbosity
verbosity = Verbosity -> CabalException -> IO (Compiler, Platform, ProgramDb)
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
UnknownCompilerException
configCompilerEx (Just CompilerFlavor
hcFlavor) Maybe ProgArg
hcPath Maybe ProgArg
hcPkg ProgramDb
progdb Verbosity
verbosity = do
  (comp, maybePlatform, programDb) <- case CompilerFlavor
hcFlavor of
    CompilerFlavor
GHC -> Verbosity
-> Maybe ProgArg
-> Maybe ProgArg
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
GHC.configure Verbosity
verbosity Maybe ProgArg
hcPath Maybe ProgArg
hcPkg ProgramDb
progdb
    CompilerFlavor
GHCJS -> Verbosity
-> Maybe ProgArg
-> Maybe ProgArg
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
GHCJS.configure Verbosity
verbosity Maybe ProgArg
hcPath Maybe ProgArg
hcPkg ProgramDb
progdb
    CompilerFlavor
UHC -> Verbosity
-> Maybe ProgArg
-> Maybe ProgArg
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
UHC.configure Verbosity
verbosity Maybe ProgArg
hcPath Maybe ProgArg
hcPkg ProgramDb
progdb
    HaskellSuite{} -> Verbosity
-> Maybe ProgArg
-> Maybe ProgArg
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
HaskellSuite.configure Verbosity
verbosity Maybe ProgArg
hcPath Maybe ProgArg
hcPkg ProgramDb
progdb
    CompilerFlavor
_ -> Verbosity
-> CabalException -> IO (Compiler, Maybe Platform, ProgramDb)
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
UnknownCompilerException
  return (comp, fromMaybe buildPlatform maybePlatform, programDb)

-- -----------------------------------------------------------------------------
-- Testing C lib and header dependencies

-- Try to build a test C program which includes every header and links every
-- lib. If that fails, try to narrow it down by preprocessing (only) and linking
-- with individual headers and libs.  If none is the obvious culprit then give a
-- generic error message.
-- TODO: produce a log file from the compiler errors, if any.
checkForeignDeps :: PackageDescription -> LocalBuildInfo -> Verbosity -> IO ()
checkForeignDeps :: PackageDescription -> LocalBuildInfo -> Verbosity -> IO ()
checkForeignDeps PackageDescription
pkg LocalBuildInfo
lbi Verbosity
verbosity =
  [ProgArg] -> [ProgArg] -> IO () -> IO () -> IO ()
forall {b}. [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith
    [ProgArg]
allHeaders
    ([ProgArg]
commonCcArgs [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ProgArg] -> [ProgArg]
makeLdArgs [ProgArg]
allLibs) -- I'm feeling
    -- lucky
    (() -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
    ( do
        missingLibs <- IO [ProgArg]
findMissingLibs
        missingHdr <- findOffendingHdr
        explainErrors missingHdr missingLibs
    )
  where
    allHeaders :: [ProgArg]
allHeaders = (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
includes
    allLibs :: [ProgArg]
allLibs =
      (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField ((BuildInfo -> [ProgArg]) -> [ProgArg])
-> (BuildInfo -> [ProgArg]) -> [ProgArg]
forall a b. (a -> b) -> a -> b
$
        if LocalBuildInfo -> Bool
withFullyStaticExe LocalBuildInfo
lbi
          then BuildInfo -> [ProgArg]
extraLibsStatic
          else BuildInfo -> [ProgArg]
extraLibs

    ifBuildsWith :: [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith [ProgArg]
headers [ProgArg]
args IO b
success IO b
failure = do
      IO ()
checkDuplicateHeaders
      ok <- ProgArg -> [ProgArg] -> IO Bool
builds ([ProgArg] -> ProgArg
makeProgram [ProgArg]
headers) [ProgArg]
args
      if ok then success else failure

    -- Ensure that there is only one header with a given name
    -- in either the generated (most likely by `configure`)
    -- build directory (e.g. `dist/build`) or in the source directory.
    --
    -- If it exists in both, we'll remove the one in the source
    -- directory, as the generated should take precedence.
    --
    -- C compilers like to prefer source local relative includes,
    -- so the search paths provided to the compiler via -I are
    -- ignored if the included file can be found relative to the
    -- including file.  As such we need to take drastic measures
    -- and delete the offending file in the source directory.
    checkDuplicateHeaders :: IO ()
checkDuplicateHeaders = do
      let relIncDirs :: [ProgArg]
relIncDirs = (ProgArg -> Bool) -> [ProgArg] -> [ProgArg]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (ProgArg -> Bool) -> ProgArg -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgArg -> Bool
isAbsolute) ((BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
includeDirs)
          isHeader :: ProgArg -> Bool
isHeader = ProgArg -> ProgArg -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isSuffixOf ProgArg
".h"
      genHeaders <- [ProgArg] -> (ProgArg -> IO [ProgArg]) -> IO [[ProgArg]]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [ProgArg]
relIncDirs ((ProgArg -> IO [ProgArg]) -> IO [[ProgArg]])
-> (ProgArg -> IO [ProgArg]) -> IO [[ProgArg]]
forall a b. (a -> b) -> a -> b
$ \ProgArg
dir ->
        ShowS -> [ProgArg] -> [ProgArg]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ProgArg
dir ProgArg -> ShowS
</>) ([ProgArg] -> [ProgArg])
-> ([ProgArg] -> [ProgArg]) -> [ProgArg] -> [ProgArg]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ProgArg -> Bool) -> [ProgArg] -> [ProgArg]
forall a. (a -> Bool) -> [a] -> [a]
filter ProgArg -> Bool
isHeader
          ([ProgArg] -> [ProgArg]) -> IO [ProgArg] -> IO [ProgArg]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ProgArg -> IO [ProgArg]
listDirectory (LocalBuildInfo -> ProgArg
buildDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
dir) IO [ProgArg] -> (IOException -> IO [ProgArg]) -> IO [ProgArg]
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> [ProgArg] -> IO [ProgArg]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [])
      srcHeaders <- for relIncDirs $ \ProgArg
dir ->
        ShowS -> [ProgArg] -> [ProgArg]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ProgArg
dir ProgArg -> ShowS
</>) ([ProgArg] -> [ProgArg])
-> ([ProgArg] -> [ProgArg]) -> [ProgArg] -> [ProgArg]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ProgArg -> Bool) -> [ProgArg] -> [ProgArg]
forall a. (a -> Bool) -> [a] -> [a]
filter ProgArg -> Bool
isHeader
          ([ProgArg] -> [ProgArg]) -> IO [ProgArg] -> IO [ProgArg]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ProgArg -> IO [ProgArg]
listDirectory (LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
dir) IO [ProgArg] -> (IOException -> IO [ProgArg]) -> IO [ProgArg]
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> [ProgArg] -> IO [ProgArg]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [])
      let commonHeaders = [[ProgArg]] -> [ProgArg]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[ProgArg]]
genHeaders [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. Eq a => [a] -> [a] -> [a]
`intersect` [[ProgArg]] -> [ProgArg]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[ProgArg]]
srcHeaders
      for_ commonHeaders $ \ProgArg
hdr -> do
        Verbosity -> ProgArg -> IO ()
warn Verbosity
verbosity (ProgArg -> IO ()) -> ProgArg -> IO ()
forall a b. (a -> b) -> a -> b
$
          ProgArg
"Duplicate header found in "
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> ProgArg
buildDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
hdr)
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
" and "
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
hdr)
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"; removing "
            ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
hdr)
        ProgArg -> IO ()
removeFile (LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
hdr)

    findOffendingHdr :: IO (Maybe (Either ProgArg ProgArg))
findOffendingHdr =
      [ProgArg]
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
forall {b}. [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith
        [ProgArg]
allHeaders
        [ProgArg]
ccArgs
        (Maybe (Either ProgArg ProgArg)
-> IO (Maybe (Either ProgArg ProgArg))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Either ProgArg ProgArg)
forall a. Maybe a
Nothing)
        ([[ProgArg]] -> IO (Maybe (Either ProgArg ProgArg))
go ([[ProgArg]] -> IO (Maybe (Either ProgArg ProgArg)))
-> ([ProgArg] -> [[ProgArg]])
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty [ProgArg] -> [[ProgArg]]
forall a. NonEmpty a -> [a]
tail (NonEmpty [ProgArg] -> [[ProgArg]])
-> ([ProgArg] -> NonEmpty [ProgArg]) -> [ProgArg] -> [[ProgArg]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ProgArg] -> NonEmpty [ProgArg]
forall (f :: * -> *) a. Foldable f => f a -> NonEmpty [a]
NEL.inits ([ProgArg] -> IO (Maybe (Either ProgArg ProgArg)))
-> [ProgArg] -> IO (Maybe (Either ProgArg ProgArg))
forall a b. (a -> b) -> a -> b
$ [ProgArg]
allHeaders)
      where
        go :: [[ProgArg]] -> IO (Maybe (Either ProgArg ProgArg))
go [] = Maybe (Either ProgArg ProgArg)
-> IO (Maybe (Either ProgArg ProgArg))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Either ProgArg ProgArg)
forall a. Maybe a
Nothing -- cannot happen
        go ([ProgArg]
hdrs : [[ProgArg]]
hdrsInits) =
          -- Try just preprocessing first
          [ProgArg]
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
forall {b}. [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith
            [ProgArg]
hdrs
            [ProgArg]
cppArgs
            -- If that works, try compiling too
            ( [ProgArg]
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
-> IO (Maybe (Either ProgArg ProgArg))
forall {b}. [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith
                [ProgArg]
hdrs
                [ProgArg]
ccArgs
                ([[ProgArg]] -> IO (Maybe (Either ProgArg ProgArg))
go [[ProgArg]]
hdrsInits)
                (Maybe (Either ProgArg ProgArg)
-> IO (Maybe (Either ProgArg ProgArg))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Either ProgArg ProgArg)
 -> IO (Maybe (Either ProgArg ProgArg)))
-> ([ProgArg] -> Maybe (Either ProgArg ProgArg))
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ProgArg -> Either ProgArg ProgArg)
-> Maybe ProgArg -> Maybe (Either ProgArg ProgArg)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ProgArg -> Either ProgArg ProgArg
forall a b. b -> Either a b
Right (Maybe ProgArg -> Maybe (Either ProgArg ProgArg))
-> ([ProgArg] -> Maybe ProgArg)
-> [ProgArg]
-> Maybe (Either ProgArg ProgArg)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ProgArg] -> Maybe ProgArg
forall a. [a] -> Maybe a
safeLast ([ProgArg] -> IO (Maybe (Either ProgArg ProgArg)))
-> [ProgArg] -> IO (Maybe (Either ProgArg ProgArg))
forall a b. (a -> b) -> a -> b
$ [ProgArg]
hdrs)
            )
            (Maybe (Either ProgArg ProgArg)
-> IO (Maybe (Either ProgArg ProgArg))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Either ProgArg ProgArg)
 -> IO (Maybe (Either ProgArg ProgArg)))
-> ([ProgArg] -> Maybe (Either ProgArg ProgArg))
-> [ProgArg]
-> IO (Maybe (Either ProgArg ProgArg))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ProgArg -> Either ProgArg ProgArg)
-> Maybe ProgArg -> Maybe (Either ProgArg ProgArg)
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ProgArg -> Either ProgArg ProgArg
forall a b. a -> Either a b
Left (Maybe ProgArg -> Maybe (Either ProgArg ProgArg))
-> ([ProgArg] -> Maybe ProgArg)
-> [ProgArg]
-> Maybe (Either ProgArg ProgArg)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ProgArg] -> Maybe ProgArg
forall a. [a] -> Maybe a
safeLast ([ProgArg] -> IO (Maybe (Either ProgArg ProgArg)))
-> [ProgArg] -> IO (Maybe (Either ProgArg ProgArg))
forall a b. (a -> b) -> a -> b
$ [ProgArg]
hdrs)

        cppArgs :: [ProgArg]
cppArgs = ProgArg
"-E" ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: [ProgArg]
commonCppArgs -- preprocess only
        ccArgs :: [ProgArg]
ccArgs = ProgArg
"-c" ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: [ProgArg]
commonCcArgs -- don't try to link
    findMissingLibs :: IO [ProgArg]
findMissingLibs =
      [ProgArg]
-> [ProgArg] -> IO [ProgArg] -> IO [ProgArg] -> IO [ProgArg]
forall {b}. [ProgArg] -> [ProgArg] -> IO b -> IO b -> IO b
ifBuildsWith
        []
        ([ProgArg] -> [ProgArg]
makeLdArgs [ProgArg]
allLibs)
        ([ProgArg] -> IO [ProgArg]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return [])
        ((ProgArg -> IO Bool) -> [ProgArg] -> IO [ProgArg]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM ((Bool -> Bool) -> IO Bool -> IO Bool
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> Bool
not (IO Bool -> IO Bool) -> (ProgArg -> IO Bool) -> ProgArg -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgArg -> IO Bool
libExists) [ProgArg]
allLibs)

    libExists :: ProgArg -> IO Bool
libExists ProgArg
lib = ProgArg -> [ProgArg] -> IO Bool
builds ([ProgArg] -> ProgArg
makeProgram []) ([ProgArg] -> [ProgArg]
makeLdArgs [ProgArg
lib])

    baseDir :: LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi' = ProgArg -> Maybe ProgArg -> ProgArg
forall a. a -> Maybe a -> a
fromMaybe ProgArg
"." (ShowS
takeDirectory ShowS -> Maybe ProgArg -> Maybe ProgArg
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> LocalBuildInfo -> Maybe ProgArg
cabalFilePath LocalBuildInfo
lbi')

    commonCppArgs :: [ProgArg]
commonCppArgs =
      LocalBuildInfo -> [ProgArg]
platformDefines LocalBuildInfo
lbi
        -- TODO: This is a massive hack, to work around the
        -- fact that the test performed here should be
        -- PER-component (c.f. the "I'm Feeling Lucky"; we
        -- should NOT be glomming everything together.)
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> ProgArg
buildDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
"autogen"]
        -- `configure' may generate headers in the build directory
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> ProgArg
buildDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
dir
           | ProgArg
dir <- [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
includeDirs)
           , Bool -> Bool
not (ProgArg -> Bool
isAbsolute ProgArg
dir)
           ]
        -- we might also reference headers from the
        -- packages directory.
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi ProgArg -> ShowS
</> ProgArg
dir
           | ProgArg
dir <- [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
includeDirs)
           , Bool -> Bool
not (ProgArg -> Bool
isAbsolute ProgArg
dir)
           ]
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
dir | ProgArg
dir <- [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
includeDirs), ProgArg -> Bool
isAbsolute ProgArg
dir
           ]
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> ProgArg
baseDir LocalBuildInfo
lbi]
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
cppOptions
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
ccOptions
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
"-I" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
dir
           | ProgArg
dir <-
              [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub
                [ ProgArg
dir
                | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
                , ProgArg
dir <- InstalledPackageInfo -> [ProgArg]
IPI.includeDirs InstalledPackageInfo
dep
                ]
                -- dedupe include dirs of dependencies
                -- to prevent quadratic blow-up
           ]
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
opt
           | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
           , ProgArg
opt <- InstalledPackageInfo -> [ProgArg]
IPI.ccOptions InstalledPackageInfo
dep
           ]

    commonCcArgs :: [ProgArg]
commonCcArgs =
      [ProgArg]
commonCppArgs
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
ccOptions
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
opt
           | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
           , ProgArg
opt <- InstalledPackageInfo -> [ProgArg]
IPI.ccOptions InstalledPackageInfo
dep
           ]

    commonLdArgs :: [ProgArg]
commonLdArgs =
      [ ProgArg
"-L" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
dir
      | ProgArg
dir <-
          [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub ([ProgArg] -> [ProgArg]) -> [ProgArg] -> [ProgArg]
forall a b. (a -> b) -> a -> b
$
            (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField
              ( if LocalBuildInfo -> Bool
withFullyStaticExe LocalBuildInfo
lbi
                  then BuildInfo -> [ProgArg]
extraLibDirsStatic
                  else BuildInfo -> [ProgArg]
extraLibDirs
              )
      ]
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [ProgArg]) -> [ProgArg]
forall {b}. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [ProgArg]
ldOptions
        [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ ProgArg
"-L" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
dir
           | ProgArg
dir <-
              [ProgArg] -> [ProgArg]
forall a. Ord a => [a] -> [a]
ordNub
                [ ProgArg
dir
                | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
                , ProgArg
dir <-
                    if LocalBuildInfo -> Bool
withFullyStaticExe LocalBuildInfo
lbi
                      then InstalledPackageInfo -> [ProgArg]
IPI.libraryDirsStatic InstalledPackageInfo
dep
                      else InstalledPackageInfo -> [ProgArg]
IPI.libraryDirs InstalledPackageInfo
dep
                ]
           ]
    -- TODO: do we also need dependent packages' ld options?
    makeLdArgs :: [ProgArg] -> [ProgArg]
makeLdArgs [ProgArg]
libs = [ProgArg
"-l" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
lib | ProgArg
lib <- [ProgArg]
libs] [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ProgArg]
commonLdArgs

    makeProgram :: [ProgArg] -> ProgArg
makeProgram [ProgArg]
hdrs =
      [ProgArg] -> ProgArg
unlines ([ProgArg] -> ProgArg) -> [ProgArg] -> ProgArg
forall a b. (a -> b) -> a -> b
$
        [ProgArg
"#include \"" ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
hdr ProgArg -> ShowS
forall a. [a] -> [a] -> [a]
++ ProgArg
"\"" | ProgArg
hdr <- [ProgArg]
hdrs]
          [ProgArg] -> [ProgArg] -> [ProgArg]
forall a. [a] -> [a] -> [a]
++ [ProgArg
"int main(int argc, char** argv) { return 0; }"]

    collectField :: (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [b]
f = (BuildInfo -> [b]) -> [BuildInfo] -> [b]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap BuildInfo -> [b]
f [BuildInfo]
allBi
    allBi :: [BuildInfo]
allBi = PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg (LocalBuildInfo -> ComponentRequestedSpec
componentEnabledSpec LocalBuildInfo
lbi)
    deps :: [InstalledPackageInfo]
deps = InstalledPackageIndex -> [InstalledPackageInfo]
forall a. PackageInstalled a => PackageIndex a -> [a]
PackageIndex.topologicalOrder (LocalBuildInfo -> InstalledPackageIndex
installedPkgs LocalBuildInfo
lbi)

    builds :: ProgArg -> [ProgArg] -> IO Bool
builds ProgArg
program [ProgArg]
args =
      do
        tempDir <- IO ProgArg
getTemporaryDirectory
        withTempFile tempDir ".c" $ \ProgArg
cName Handle
cHnd ->
          ProgArg -> ProgArg -> (ProgArg -> Handle -> IO Bool) -> IO Bool
forall a. ProgArg -> ProgArg -> (ProgArg -> Handle -> IO a) -> IO a
withTempFile ProgArg
tempDir ProgArg
"" ((ProgArg -> Handle -> IO Bool) -> IO Bool)
-> (ProgArg -> Handle -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \ProgArg
oNname Handle
oHnd -> do
            Handle -> ProgArg -> IO ()
hPutStrLn Handle
cHnd ProgArg
program
            Handle -> IO ()
hClose Handle
cHnd
            Handle -> IO ()
hClose Handle
oHnd
            _ <-
              Verbosity -> Program -> ProgramDb -> [ProgArg] -> IO ProgArg
getDbProgramOutput
                Verbosity
verbosity
                Program
gccProgram
                (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
                (ProgArg
cName ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: ProgArg
"-o" ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: ProgArg
oNname ProgArg -> [ProgArg] -> [ProgArg]
forall a. a -> [a] -> [a]
: [ProgArg]
args)
            return True
        IO Bool -> (IOException -> IO Bool) -> IO Bool
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)
        IO Bool -> (ExitCode -> IO Bool) -> IO Bool
forall a. IO a -> (ExitCode -> IO a) -> IO a
`catchExit` (\ExitCode
_ -> Bool -> IO Bool
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)

    explainErrors :: Maybe (Either ProgArg ProgArg) -> [ProgArg] -> IO ()
explainErrors Maybe (Either ProgArg ProgArg)
Nothing [] = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return () -- should be impossible!
    explainErrors Maybe (Either ProgArg ProgArg)
_ [ProgArg]
_
      | Maybe ConfiguredProgram -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe ConfiguredProgram -> Bool)
-> (LocalBuildInfo -> Maybe ConfiguredProgram)
-> LocalBuildInfo
-> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Program -> ProgramDb -> Maybe ConfiguredProgram
lookupProgram Program
gccProgram (ProgramDb -> Maybe ConfiguredProgram)
-> (LocalBuildInfo -> ProgramDb)
-> LocalBuildInfo
-> Maybe ConfiguredProgram
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LocalBuildInfo -> ProgramDb
withPrograms (LocalBuildInfo -> Bool) -> LocalBuildInfo -> Bool
forall a b. (a -> b) -> a -> b
$ LocalBuildInfo
lbi =
          Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity CabalException
NoWorkingGcc
    explainErrors Maybe (Either ProgArg ProgArg)
hdr [ProgArg]
libs =
      Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$ Maybe (Either ProgArg ProgArg) -> [ProgArg] -> CabalException
ExplainErrors Maybe (Either ProgArg ProgArg)
hdr [ProgArg]
libs

-- | Output package check warnings and errors. Exit if any errors.
checkPackageProblems
  :: Verbosity
  -> FilePath
  -- ^ Path to the @.cabal@ file's directory
  -> GenericPackageDescription
  -> PackageDescription
  -> IO ()
checkPackageProblems :: Verbosity
-> ProgArg
-> GenericPackageDescription
-> PackageDescription
-> IO ()
checkPackageProblems Verbosity
verbosity ProgArg
dir GenericPackageDescription
gpkg PackageDescription
pkg = do
  ioChecks <- Verbosity -> PackageDescription -> ProgArg -> IO [PackageCheck]
checkPackageFiles Verbosity
verbosity PackageDescription
pkg ProgArg
dir
  let pureChecks = GenericPackageDescription -> [PackageCheck]
checkPackage GenericPackageDescription
gpkg
      (errors, warnings) =
        partitionEithers (M.mapMaybe classEW $ pureChecks ++ ioChecks)
  if null errors
    then traverse_ (warn verbosity) (map ppPackageCheck warnings)
    else dieWithException verbosity $ CheckPackageProblems (map ppPackageCheck errors)
  where
    -- Classify error/warnings. Left: error, Right: warning.
    classEW :: PackageCheck -> Maybe (Either PackageCheck PackageCheck)
    classEW :: PackageCheck -> Maybe (Either PackageCheck PackageCheck)
classEW e :: PackageCheck
e@(PackageBuildImpossible CheckExplanation
_) = Either PackageCheck PackageCheck
-> Maybe (Either PackageCheck PackageCheck)
forall a. a -> Maybe a
Just (PackageCheck -> Either PackageCheck PackageCheck
forall a b. a -> Either a b
Left PackageCheck
e)
    classEW w :: PackageCheck
w@(PackageBuildWarning CheckExplanation
_) = Either PackageCheck PackageCheck
-> Maybe (Either PackageCheck PackageCheck)
forall a. a -> Maybe a
Just (PackageCheck -> Either PackageCheck PackageCheck
forall a b. b -> Either a b
Right PackageCheck
w)
    classEW (PackageDistSuspicious CheckExplanation
_) = Maybe (Either PackageCheck PackageCheck)
forall a. Maybe a
Nothing
    classEW (PackageDistSuspiciousWarn CheckExplanation
_) = Maybe (Either PackageCheck PackageCheck)
forall a. Maybe a
Nothing
    classEW (PackageDistInexcusable CheckExplanation
_) = Maybe (Either PackageCheck PackageCheck)
forall a. Maybe a
Nothing

-- | Preform checks if a relocatable build is allowed
checkRelocatable
  :: Verbosity
  -> PackageDescription
  -> LocalBuildInfo
  -> IO ()
checkRelocatable :: Verbosity -> PackageDescription -> LocalBuildInfo -> IO ()
checkRelocatable Verbosity
verbosity PackageDescription
pkg LocalBuildInfo
lbi =
  [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
    [ IO ()
checkOS
    , IO ()
checkCompiler
    , IO ()
packagePrefixRelative
    , IO ()
depsPrefixRelative
    ]
  where
    -- Check if the OS support relocatable builds.
    --
    -- If you add new OS' to this list, and your OS supports dynamic libraries
    -- and RPATH, make sure you add your OS to RPATH-support list of:
    -- Distribution.Simple.GHC.getRPaths
    checkOS :: IO ()
checkOS =
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (OS
os OS -> [OS] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [OS
OSX, OS
Linux]) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          OS -> CabalException
NoOSSupport OS
os
      where
        (Platform Arch
_ OS
os) = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi

    -- Check if the Compiler support relocatable builds
    checkCompiler :: IO ()
checkCompiler =
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Compiler -> CompilerFlavor
compilerFlavor Compiler
comp CompilerFlavor -> [CompilerFlavor] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [CompilerFlavor
GHC]) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          ProgArg -> CabalException
NoCompilerSupport (Compiler -> ProgArg
forall a. Show a => a -> ProgArg
show Compiler
comp)
      where
        comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi

    -- Check if all the install dirs are relative to same prefix
    packagePrefixRelative :: IO ()
packagePrefixRelative =
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (InstallDirs ProgArg -> Bool
relativeInstallDirs InstallDirs ProgArg
installDirs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> CabalException -> IO ()
forall a1 a.
(HasCallStack, Show a1, Typeable a1,
 Exception (VerboseException a1)) =>
Verbosity -> a1 -> IO a
dieWithException Verbosity
verbosity (CabalException -> IO ()) -> CabalException -> IO ()
forall a b. (a -> b) -> a -> b
$
          InstallDirs ProgArg -> CabalException
InstallDirsNotPrefixRelative (InstallDirs ProgArg
installDirs)
      where
        -- NB: should be good enough to check this against the default
        -- component ID, but if we wanted to be strictly correct we'd
        -- check for each ComponentId.
        installDirs :: InstallDirs ProgArg
installDirs = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs ProgArg
absoluteInstallDirs PackageDescription
pkg LocalBuildInfo
lbi CopyDest
NoCopyDest
        p :: ProgArg
p = InstallDirs ProgArg -> ProgArg
forall dir. InstallDirs dir -> dir
prefix InstallDirs ProgArg
installDirs
        relativeInstallDirs :: InstallDirs ProgArg -> Bool
relativeInstallDirs (InstallDirs{ProgArg
prefix :: forall dir. InstallDirs dir -> dir
bindir :: forall dir. InstallDirs dir -> dir
libdir :: forall dir. InstallDirs dir -> dir
dynlibdir :: forall dir. InstallDirs dir -> dir
libexecdir :: forall dir. InstallDirs dir -> dir
datadir :: forall dir. InstallDirs dir -> dir
docdir :: forall dir. InstallDirs dir -> dir
sysconfdir :: forall dir. InstallDirs dir -> dir
prefix :: ProgArg
bindir :: ProgArg
libdir :: ProgArg
libsubdir :: ProgArg
dynlibdir :: ProgArg
flibdir :: ProgArg
libexecdir :: ProgArg
libexecsubdir :: ProgArg
includedir :: ProgArg
datadir :: ProgArg
datasubdir :: ProgArg
docdir :: ProgArg
mandir :: ProgArg
htmldir :: ProgArg
haddockdir :: ProgArg
sysconfdir :: ProgArg
haddockdir :: forall dir. InstallDirs dir -> dir
htmldir :: forall dir. InstallDirs dir -> dir
mandir :: forall dir. InstallDirs dir -> dir
datasubdir :: forall dir. InstallDirs dir -> dir
includedir :: forall dir. InstallDirs dir -> dir
libexecsubdir :: forall dir. InstallDirs dir -> dir
flibdir :: forall dir. InstallDirs dir -> dir
libsubdir :: forall dir. InstallDirs dir -> dir
..}) =
          (Maybe ProgArg -> Bool) -> [Maybe ProgArg] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all
            Maybe ProgArg -> Bool
forall a. Maybe a -> Bool
isJust
            ( (ProgArg -> Maybe ProgArg) -> [ProgArg] -> [Maybe ProgArg]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap
                (ProgArg -> ProgArg -> Maybe ProgArg
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix ProgArg
p)
                [ ProgArg
bindir
                , ProgArg
libdir
                , ProgArg
dynlibdir
                , ProgArg
libexecdir
                , ProgArg
includedir
                , ProgArg
datadir
                , ProgArg
docdir
                , ProgArg
mandir
                , ProgArg
htmldir
                , ProgArg
haddockdir
                , ProgArg
sysconfdir
                ]
            )

    -- Check if the library dirs of the dependencies that are in the package
    -- database to which the package is installed are relative to the
    -- prefix of the package
    depsPrefixRelative :: IO ()
depsPrefixRelative = do
      pkgr <- Verbosity -> LocalBuildInfo -> PackageDB -> IO ProgArg
GHC.pkgRoot Verbosity
verbosity LocalBuildInfo
lbi (PackageDBStack -> PackageDB
registrationPackageDB (LocalBuildInfo -> PackageDBStack
withPackageDB LocalBuildInfo
lbi))
      traverse_ (doCheck pkgr) ipkgs
      where
        doCheck :: ProgArg -> InstalledPackageInfo -> IO ()
doCheck ProgArg
pkgr InstalledPackageInfo
ipkg
          | Bool -> (ProgArg -> Bool) -> Maybe ProgArg -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (ProgArg -> ProgArg -> Bool
forall a. Eq a => a -> a -> Bool
== ProgArg
pkgr) (InstalledPackageInfo -> Maybe ProgArg
IPI.pkgRoot InstalledPackageInfo
ipkg) =
              [ProgArg] -> (ProgArg -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (InstalledPackageInfo -> [ProgArg]
IPI.libraryDirs InstalledPackageInfo
ipkg) ((ProgArg -> IO ()) -> IO ()) -> (ProgArg -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ProgArg
libdir -> do
                -- When @prefix@ is not under @pkgroot@,
                -- @shortRelativePath prefix pkgroot@ will return a path with
                -- @..@s and following check will fail without @canonicalizePath@.
                canonicalized <- ProgArg -> IO ProgArg
canonicalizePath ProgArg
libdir
                -- The @prefix@ itself must also be canonicalized because
                -- canonicalizing @libdir@ may expand symlinks which would make
                -- @prefix@ no longer being a prefix of @canonical libdir@,
                -- while @canonical p@ could be a prefix of @canonical libdir@
                p' <- canonicalizePath p
                unless (p' `isPrefixOf` canonicalized) $
                  dieWithException verbosity $
                    LibDirDepsPrefixNotRelative libdir p
          | Bool
otherwise =
              () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        -- NB: should be good enough to check this against the default
        -- component ID, but if we wanted to be strictly correct we'd
        -- check for each ComponentId.
        installDirs :: InstallDirs ProgArg
installDirs = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs ProgArg
absoluteInstallDirs PackageDescription
pkg LocalBuildInfo
lbi CopyDest
NoCopyDest
        p :: ProgArg
p = InstallDirs ProgArg -> ProgArg
forall dir. InstallDirs dir -> dir
prefix InstallDirs ProgArg
installDirs
        ipkgs :: [InstalledPackageInfo]
ipkgs = InstalledPackageIndex -> [InstalledPackageInfo]
forall a. PackageIndex a -> [a]
PackageIndex.allPackages (LocalBuildInfo -> InstalledPackageIndex
installedPkgs LocalBuildInfo
lbi)

-- -----------------------------------------------------------------------------
-- Testing foreign library requirements

unsupportedForeignLibs :: Compiler -> Platform -> [ForeignLib] -> [String]
unsupportedForeignLibs :: Compiler -> Platform -> [ForeignLib] -> [ProgArg]
unsupportedForeignLibs Compiler
comp Platform
platform =
  (ForeignLib -> Maybe ProgArg) -> [ForeignLib] -> [ProgArg]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (Compiler -> Platform -> ForeignLib -> Maybe ProgArg
checkForeignLibSupported Compiler
comp Platform
platform)

checkForeignLibSupported :: Compiler -> Platform -> ForeignLib -> Maybe String
checkForeignLibSupported :: Compiler -> Platform -> ForeignLib -> Maybe ProgArg
checkForeignLibSupported Compiler
comp Platform
platform ForeignLib
flib = CompilerFlavor -> Maybe ProgArg
go (Compiler -> CompilerFlavor
compilerFlavor Compiler
comp)
  where
    go :: CompilerFlavor -> Maybe String
    go :: CompilerFlavor -> Maybe ProgArg
go CompilerFlavor
GHC
      | Compiler -> Version
compilerVersion Compiler
comp Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
8] =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"Building foreign libraries is only supported with GHC >= 7.8"
            ]
      | Bool
otherwise = Platform -> Maybe ProgArg
goGhcPlatform Platform
platform
    go CompilerFlavor
_ =
      [ProgArg] -> Maybe ProgArg
unsupported
        [ ProgArg
"Building foreign libraries is currently only supported with ghc"
        ]

    goGhcPlatform :: Platform -> Maybe String
    goGhcPlatform :: Platform -> Maybe ProgArg
goGhcPlatform (Platform Arch
_ OS
OSX) = ForeignLibType -> Maybe ProgArg
goGhcOsx (ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib)
    goGhcPlatform (Platform Arch
_ OS
Linux) = ForeignLibType -> Maybe ProgArg
goGhcLinux (ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib)
    goGhcPlatform (Platform Arch
I386 OS
Windows) = ForeignLibType -> Maybe ProgArg
goGhcWindows (ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib)
    goGhcPlatform (Platform Arch
X86_64 OS
Windows) = ForeignLibType -> Maybe ProgArg
goGhcWindows (ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib)
    goGhcPlatform Platform
_ =
      [ProgArg] -> Maybe ProgArg
unsupported
        [ ProgArg
"Building foreign libraries is currently only supported on Mac OS, "
        , ProgArg
"Linux and Windows"
        ]

    goGhcOsx :: ForeignLibType -> Maybe String
    goGhcOsx :: ForeignLibType -> Maybe ProgArg
goGhcOsx ForeignLibType
ForeignLibNativeShared
      | Bool -> Bool
not ([ProgArg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> [ProgArg]
foreignLibModDefFile ForeignLib
flib)) =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"Module definition file not supported on OSX"
            ]
      | Bool -> Bool
not (Maybe LibVersionInfo -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> Maybe LibVersionInfo
foreignLibVersionInfo ForeignLib
flib)) =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"Foreign library versioning not currently supported on OSX"
            ]
      | Bool
otherwise =
          Maybe ProgArg
forall a. Maybe a
Nothing
    goGhcOsx ForeignLibType
_ =
      [ProgArg] -> Maybe ProgArg
unsupported
        [ ProgArg
"We can currently only build shared foreign libraries on OSX"
        ]

    goGhcLinux :: ForeignLibType -> Maybe String
    goGhcLinux :: ForeignLibType -> Maybe ProgArg
goGhcLinux ForeignLibType
ForeignLibNativeShared
      | Bool -> Bool
not ([ProgArg] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> [ProgArg]
foreignLibModDefFile ForeignLib
flib)) =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"Module definition file not supported on Linux"
            ]
      | Bool -> Bool
not (Maybe LibVersionInfo -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> Maybe LibVersionInfo
foreignLibVersionInfo ForeignLib
flib))
          Bool -> Bool -> Bool
&& Bool -> Bool
not (Maybe Version -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> Maybe Version
foreignLibVersionLinux ForeignLib
flib)) =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"You must not specify both lib-version-info and lib-version-linux"
            ]
      | Bool
otherwise =
          Maybe ProgArg
forall a. Maybe a
Nothing
    goGhcLinux ForeignLibType
_ =
      [ProgArg] -> Maybe ProgArg
unsupported
        [ ProgArg
"We can currently only build shared foreign libraries on Linux"
        ]

    goGhcWindows :: ForeignLibType -> Maybe String
    goGhcWindows :: ForeignLibType -> Maybe ProgArg
goGhcWindows ForeignLibType
ForeignLibNativeShared
      | Bool -> Bool
not Bool
standalone =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"We can currently only build standalone libraries on Windows. Use\n"
            , ProgArg
"  if os(Windows)\n"
            , ProgArg
"    options: standalone\n"
            , ProgArg
"in your foreign-library stanza."
            ]
      | Bool -> Bool
not (Maybe LibVersionInfo -> Bool
forall a. Maybe a -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> Maybe LibVersionInfo
foreignLibVersionInfo ForeignLib
flib)) =
          [ProgArg] -> Maybe ProgArg
unsupported
            [ ProgArg
"Foreign library versioning not currently supported on Windows.\n"
            , ProgArg
"You can specify module definition files in the mod-def-file field."
            ]
      | Bool
otherwise =
          Maybe ProgArg
forall a. Maybe a
Nothing
    goGhcWindows ForeignLibType
_ =
      [ProgArg] -> Maybe ProgArg
unsupported
        [ ProgArg
"We can currently only build shared foreign libraries on Windows"
        ]

    standalone :: Bool
    standalone :: Bool
standalone = ForeignLibOption
ForeignLibStandalone ForeignLibOption -> [ForeignLibOption] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` ForeignLib -> [ForeignLibOption]
foreignLibOptions ForeignLib
flib

    unsupported :: [String] -> Maybe String
    unsupported :: [ProgArg] -> Maybe ProgArg
unsupported = ProgArg -> Maybe ProgArg
forall a. a -> Maybe a
Just (ProgArg -> Maybe ProgArg)
-> ([ProgArg] -> ProgArg) -> [ProgArg] -> Maybe ProgArg
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ProgArg] -> ProgArg
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat