{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# 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
  , getPackageDBContents
  , configCompilerEx, configCompilerAuxEx
  , computeEffectiveProfiling
  , ccLdOptionsBuildInfo
  , checkForeignDeps
  , interpretPackageDbFlags
  , ConfigStateFileError(..)
  , tryGetConfigStateFile
  , platformDefines,
  ) where

import qualified Prelude as Unsafe (tail)
import Distribution.Compat.Prelude

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

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

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

import qualified Data.Set as Set
import qualified Distribution.Compat.NonEmptySet as NES


type UseExternalInternalDeps = Bool

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

-- | Format a 'ConfigStateFileError' as a user-facing error message.
dispConfigStateFileError :: ConfigStateFileError -> Doc
dispConfigStateFileError :: ConfigStateFileError -> Doc
dispConfigStateFileError ConfigStateFileError
ConfigStateFileNoHeader =
    String -> Doc
text String
"Saved package config file header is missing."
    Doc -> Doc -> Doc
<+> String -> Doc
text String
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileBadHeader =
    String -> Doc
text String
"Saved package config file header is corrupt."
    Doc -> Doc -> Doc
<+> String -> Doc
text String
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileNoParse =
    String -> Doc
text String
"Saved package config file is corrupt."
    Doc -> Doc -> Doc
<+> String -> Doc
text String
"Re-run the 'configure' command."
dispConfigStateFileError ConfigStateFileError
ConfigStateFileMissing =
    String -> Doc
text String
"Run the 'configure' command first."
dispConfigStateFileError (ConfigStateFileBadVersion PackageIdentifier
oldCabal PackageIdentifier
oldCompiler Either ConfigStateFileError LocalBuildInfo
_) =
    String -> Doc
text String
"Saved package config file is outdated:"
    Doc -> Doc -> Doc
$+$ Doc
badCabal Doc -> Doc -> Doc
$+$ Doc
badCompiler
    Doc -> Doc -> Doc
$+$ String -> Doc
text String
"Re-run the 'configure' command."
    where
      badCabal :: Doc
badCabal =
          String -> Doc
text String
"• 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 =
            String -> Doc
text String
"• 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 -> String
show = Style -> Doc -> String
renderStyle Style
defaultStyle (Doc -> String)
-> (ConfigStateFileError -> Doc) -> ConfigStateFileError -> String
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 :: String -> IO LocalBuildInfo
getConfigStateFile String
filename = do
    Bool
exists <- String -> IO Bool
doesFileExist String
filename
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
exists (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ ConfigStateFileError -> IO ()
forall e a. Exception e => e -> IO a
throwIO ConfigStateFileError
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.
    ByteString
contents <- String -> IO ByteString
BS.readFile String
filename
    let (ByteString
header, ByteString
body) = (Char -> Bool) -> ByteString -> (ByteString, ByteString)
BLC8.span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
/=Char
'\n') ([ByteString] -> ByteString
BLC8.fromChunks [ByteString
contents])

    (PackageIdentifier
cabalId, PackageIdentifier
compId) <- ByteString -> IO (PackageIdentifier, PackageIdentifier)
parseHeader ByteString
header

    let getStoredValue :: IO LocalBuildInfo
getStoredValue = do
          Either String LocalBuildInfo
result <- ByteString -> IO (Either String LocalBuildInfo)
forall a.
(Binary a, Structured a) =>
ByteString -> IO (Either String a)
structuredDecodeOrFailIO (ByteString -> ByteString
BLC8.tail ByteString
body)
          case Either String LocalBuildInfo
result of
            Left String
_ -> ConfigStateFileError -> IO LocalBuildInfo
forall e a. Exception e => e -> IO a
throwIO ConfigStateFileError
ConfigStateFileNoParse
            Right LocalBuildInfo
x -> LocalBuildInfo -> IO LocalBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LocalBuildInfo
x
        deferErrorIfBadVersion :: IO LocalBuildInfo -> IO LocalBuildInfo
deferErrorIfBadVersion IO LocalBuildInfo
act
          | PackageIdentifier
cabalId PackageIdentifier -> PackageIdentifier -> Bool
forall a. Eq a => a -> a -> Bool
/= PackageIdentifier
currentCabalId = do
              Either ConfigStateFileError LocalBuildInfo
eResult <- IO LocalBuildInfo
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall e a. Exception e => IO a -> IO (Either e a)
try IO LocalBuildInfo
act
              ConfigStateFileError -> IO LocalBuildInfo
forall e a. Exception e => e -> IO a
throwIO (ConfigStateFileError -> IO LocalBuildInfo)
-> ConfigStateFileError -> IO LocalBuildInfo
forall a b. (a -> b) -> a -> b
$ PackageIdentifier
-> PackageIdentifier
-> Either ConfigStateFileError LocalBuildInfo
-> ConfigStateFileError
ConfigStateFileBadVersion PackageIdentifier
cabalId PackageIdentifier
compId Either ConfigStateFileError LocalBuildInfo
eResult
          | Bool
otherwise = IO LocalBuildInfo
act
    IO LocalBuildInfo -> IO LocalBuildInfo
deferErrorIfBadVersion IO LocalBuildInfo
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 :: String -> 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))
-> (String -> IO LocalBuildInfo)
-> String
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO LocalBuildInfo
getConfigStateFile

-- | Try to read the 'localBuildInfoFile'.
tryGetPersistBuildConfig :: FilePath -- ^ The @dist@ directory path.
                         -> IO (Either ConfigStateFileError LocalBuildInfo)
tryGetPersistBuildConfig :: String -> 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))
-> (String -> IO LocalBuildInfo)
-> String
-> IO (Either ConfigStateFileError LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> 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 :: String -> IO LocalBuildInfo
getPersistBuildConfig = String -> IO LocalBuildInfo
getConfigStateFile (String -> IO LocalBuildInfo)
-> ShowS -> String -> 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 :: String -> 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))
-> (String -> IO (Either ConfigStateFileError LocalBuildInfo))
-> String
-> IO (Maybe LocalBuildInfo)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> 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 :: String -> LocalBuildInfo -> IO ()
writePersistBuildConfig String
distPref LocalBuildInfo
lbi = do
    Bool -> String -> IO ()
createDirectoryIfMissing Bool
False String
distPref
    String -> ByteString -> IO ()
writeFileAtomic (ShowS
localBuildInfoFile String
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 (String -> PackageName
mkPackageName String
"Cabal") Version
cabalVersion

-- | Identifier of the current compiler package.
currentCompilerId :: PackageIdentifier
currentCompilerId :: PackageIdentifier
currentCompilerId = PackageName -> Version -> PackageIdentifier
PackageIdentifier (String -> PackageName
mkPackageName String
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. Exception e => e -> IO a
throwIO ConfigStateFileError
ConfigStateFileBadHeader) (PackageIdentifier, PackageIdentifier)
-> IO (PackageIdentifier, PackageIdentifier)
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
          PackageIdentifier
_ <- String -> Maybe PackageIdentifier
forall a. Parsec a => String -> Maybe a
simpleParsec (ByteString -> String
fromUTF8LBS ByteString
pkgId) :: Maybe PackageIdentifier
          PackageIdentifier
cabalId' <- String -> Maybe PackageIdentifier
forall a. Parsec a => String -> Maybe a
simpleParsec (ByteString -> String
BLC8.unpack ByteString
cabalId)
          PackageIdentifier
compId' <- String -> Maybe PackageIdentifier
forall a. Parsec a => String -> Maybe a
simpleParsec (ByteString -> String
BLC8.unpack ByteString
compId)
          (PackageIdentifier, PackageIdentifier)
-> Maybe (PackageIdentifier, PackageIdentifier)
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageIdentifier
cabalId', PackageIdentifier
compId')
  [ByteString]
_ -> ConfigStateFileError -> IO (PackageIdentifier, PackageIdentifier)
forall e a. 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"
    , String -> ByteString
toUTF8LBS (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow PackageIdentifier
pkgId
    , ByteString
"written", ByteString
"by"
    , String -> ByteString
BLC8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow PackageIdentifier
currentCabalId
    , ByteString
"using"
    , String -> ByteString
BLC8.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow PackageIdentifier
currentCompilerId
    ]

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

-- | Get the path of @dist\/setup-config@.
localBuildInfoFile :: FilePath -- ^ The @dist@ directory path.
                    -> FilePath
localBuildInfoFile :: ShowS
localBuildInfoFile String
distPref = String
distPref String -> ShowS
</> String
"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 :: String -> Flag String -> IO String
findDistPref String
defDistPref Flag String
overrideDistPref = do
    Flag String
envDistPref <- (Maybe String -> Flag String)
-> IO (Maybe String) -> IO (Flag String)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM Maybe String -> Flag String
forall (t :: * -> *) a. Foldable t => Maybe (t a) -> Flag (t a)
parseEnvDistPref (String -> IO (Maybe String)
lookupEnv String
"CABAL_BUILDDIR")
    String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ String -> Flag String -> String
forall a. a -> Flag a -> a
fromFlagOrDefault String
defDistPref (Flag String -> Flag String -> Flag String
forall a. Monoid a => a -> a -> a
mappend Flag String
envDistPref Flag String
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 (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 String -> IO String
findDistPrefOrDefault = String -> Flag String -> IO String
findDistPref String
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
pkg_descr0, HookedBuildInfo
pbi) ConfigFlags
cfg = do
    -- 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).
    (Maybe ComponentName
mb_cname :: Maybe ComponentName) <- do
        let flat_pkg_descr :: PackageDescription
flat_pkg_descr = GenericPackageDescription -> PackageDescription
flattenPackageDescription GenericPackageDescription
pkg_descr0
        [BuildTarget]
targets <- Verbosity -> PackageDescription -> [String] -> IO [BuildTarget]
readBuildTargets Verbosity
verbosity PackageDescription
flat_pkg_descr (ConfigFlags -> [String]
configArgs ConfigFlags
cfg)
        -- TODO: bleat if you use the module/file syntax
        let targets' :: [ComponentName]
targets' = [ ComponentName
cname | BuildTargetComponent ComponentName
cname <- [BuildTarget]
targets ]
        case [ComponentName]
targets' of
            [ComponentName]
_ | [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ConfigFlags -> [String]
configArgs ConfigFlags
cfg) -> Maybe ComponentName -> IO (Maybe ComponentName)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe ComponentName
forall a. Maybe a
Nothing
            [ComponentName
cname] -> Maybe ComponentName -> IO (Maybe ComponentName)
forall (m :: * -> *) a. Monad m => a -> m a
return (ComponentName -> Maybe ComponentName
forall a. a -> Maybe a
Just ComponentName
cname)
            [] -> Verbosity -> String -> IO (Maybe ComponentName)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
"No valid component targets found"
            [ComponentName]
_  -> Verbosity -> String -> IO (Maybe ComponentName)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity
                  String
"Can only configure either single component or all of them"

    let use_external_internal_deps :: Bool
use_external_internal_deps = Maybe ComponentName -> Bool
forall a. Maybe a -> Bool
isJust Maybe ComponentName
mb_cname
    case Maybe ComponentName
mb_cname of
        Maybe ComponentName
Nothing -> Verbosity -> String -> PackageIdentifier -> IO ()
setupMessage Verbosity
verbosity String
"Configuring" (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
pkg_descr0)
        Just ComponentName
cname -> Verbosity
-> String
-> PackageIdentifier
-> ComponentName
-> Maybe [(ModuleName, Module)]
-> IO ()
forall a.
Pretty a =>
Verbosity
-> String
-> PackageIdentifier
-> ComponentName
-> Maybe [(ModuleName, a)]
-> IO ()
setupMessage' Verbosity
verbosity String
"Configuring" (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
pkg_descr0)
                        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
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe ComponentId -> Bool
forall a. Maybe a -> Bool
isJust (Flag ComponentId -> Maybe ComponentId
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag ComponentId
configCID ConfigFlags
cfg)) Bool -> Bool -> Bool
&& Maybe ComponentName -> Bool
forall a. Maybe a -> Bool
isNothing Maybe ComponentName
mb_cname) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
"--cid is only supported for per-component configure"

    Verbosity -> ConfigFlags -> IO ()
checkDeprecatedFlags Verbosity
verbosity ConfigFlags
cfg
    Verbosity -> GenericPackageDescription -> ConfigFlags -> IO ()
checkExactConfiguration Verbosity
verbosity GenericPackageDescription
pkg_descr0 ConfigFlags
cfg

    -- Where to build the package
    let buildDir :: FilePath -- e.g. dist/build
        -- fromFlag OK due to Distribution.Simple calling
        -- findDistPrefOrDefault to fill it in
        buildDir :: String
buildDir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag String
configDistPref ConfigFlags
cfg) String -> ShowS
</> String
"build"
    Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity) Bool
True String
buildDir

    -- What package database(s) to use
    let 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)

    -- 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
    (Compiler
comp         :: Compiler,
     Platform
compPlatform :: Platform,
     ProgramDb
programDb    :: ProgramDb)
        <- Maybe CompilerFlavor
-> Maybe String
-> Maybe String
-> ProgramDb
-> Verbosity
-> IO (Compiler, Platform, ProgramDb)
configCompilerEx
            (Flag CompilerFlavor -> Maybe CompilerFlavor
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag CompilerFlavor
configHcFlavor ConfigFlags
cfg))
            (Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag String
configHcPath ConfigFlags
cfg))
            (Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag String
configHcPkg ConfigFlags
cfg))
            (ConfigFlags -> ProgramDb -> ProgramDb
mkProgramDb ConfigFlags
cfg (WithCallStack (ConfigFlags -> ProgramDb)
ConfigFlags -> ProgramDb
configPrograms ConfigFlags
cfg))
            (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity)

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

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

    -- Make a data structure describing what components are enabled.
    let enabled :: ComponentRequestedSpec
        enabled :: ComponentRequestedSpec
enabled = case Maybe ComponentName
mb_cname of
                    Just ComponentName
cname -> ComponentName -> ComponentRequestedSpec
OneComponentRequestedSpec ComponentName
cname
                    Maybe ComponentName
Nothing -> ComponentRequestedSpec :: Bool -> Bool -> ComponentRequestedSpec
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.
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Maybe ComponentName -> Bool
forall a. Maybe a -> Bool
isJust Maybe ComponentName
mb_cname
          Bool -> Bool -> Bool
&& (Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configTests ConfigFlags
cfg) Bool -> Bool -> Bool
|| Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configBenchmarks ConfigFlags
cfg))) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
              String
"--enable-tests/--enable-benchmarks are incompatible with" String -> ShowS
forall a. [a] -> [a] -> [a]
++
              String
" explicitly specifying a component to configure."

    -- Some sanity checks related to dynamic/static linking.
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configDynExe ConfigFlags
cfg) Bool -> Bool -> Bool
&& Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configFullyStaticExe ConfigFlags
cfg)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
              String
"--enable-executable-dynamic and --enable-executable-static" String -> ShowS
forall a. [a] -> [a] -> [a]
++
              String
" are incompatible with each other."

    -- 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.
    ([PackageVersionConstraint]
allConstraints  :: [PackageVersionConstraint],
     Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap :: Map (PackageName, ComponentName) InstalledPackageInfo)
        <- (String
 -> IO
      ([PackageVersionConstraint],
       Map (PackageName, ComponentName) InstalledPackageInfo))
-> (([PackageVersionConstraint],
     Map (PackageName, ComponentName) InstalledPackageInfo)
    -> IO
         ([PackageVersionConstraint],
          Map (PackageName, ComponentName) InstalledPackageInfo))
-> Either
     String
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
-> IO
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Verbosity
-> String
-> IO
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity) ([PackageVersionConstraint],
 Map (PackageName, ComponentName) InstalledPackageInfo)
-> IO
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either
   String
   ([PackageVersionConstraint],
    Map (PackageName, ComponentName) InstalledPackageInfo)
 -> IO
      ([PackageVersionConstraint],
       Map (PackageName, ComponentName) InstalledPackageInfo))
-> Either
     String
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
-> IO
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
forall a b. (a -> b) -> a -> b
$
              [PackageVersionConstraint]
-> [GivenComponent]
-> InstalledPackageIndex
-> Either
     String
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
combinedConstraints (ConfigFlags -> [PackageVersionConstraint]
configConstraints ConfigFlags
cfg)
                                  (ConfigFlags -> [GivenComponent]
configDependencies ConfigFlags
cfg)
                                  InstalledPackageIndex
installedPackageSet

    -- 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.
    (PackageDescription
pkg_descr :: PackageDescription,
     FlagAssignment
flags     :: FlagAssignment)
        <- Verbosity
-> ConfigFlags
-> ComponentRequestedSpec
-> [PackageVersionConstraint]
-> (Dependency -> Bool)
-> Compiler
-> Platform
-> GenericPackageDescription
-> IO (PackageDescription, FlagAssignment)
configureFinalizedPackage Verbosity
verbosity ConfigFlags
cfg ComponentRequestedSpec
enabled
                [PackageVersionConstraint]
allConstraints
                (Bool
-> Bool
-> Bool
-> PackageName
-> InstalledPackageIndex
-> Set LibraryName
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Dependency
-> Bool
dependencySatisfiable
                    Bool
use_external_internal_deps
                    (Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (ConfigFlags -> Flag Bool
configExactConfiguration ConfigFlags
cfg))
                    (Bool -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
False (ConfigFlags -> Flag Bool
configAllowDependingOnPrivateLibs ConfigFlags
cfg))
                    (GenericPackageDescription -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName GenericPackageDescription
pkg_descr0)
                    InstalledPackageIndex
installedPackageSet
                    Set LibraryName
internalPackageSet
                    Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap)
                Compiler
comp
                Platform
compPlatform
                GenericPackageDescription
pkg_descr0

    Verbosity -> String -> IO ()
debug Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Finalized package description:\n"
                  String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageDescription -> String
showPackageDescription PackageDescription
pkg_descr

    let cabalFileDir :: String
cabalFileDir = String -> ShowS -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"." ShowS
takeDirectory (Maybe String -> String) -> Maybe String -> String
forall a b. (a -> b) -> a -> b
$
          Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag String
configCabalFilePath ConfigFlags
cfg)
    Verbosity
-> Compiler
-> PackageDescription
-> ComponentRequestedSpec
-> IO ()
checkCompilerProblems Verbosity
verbosity Compiler
comp PackageDescription
pkg_descr ComponentRequestedSpec
enabled
    Verbosity
-> String
-> GenericPackageDescription
-> PackageDescription
-> IO ()
checkPackageProblems Verbosity
verbosity String
cabalFileDir GenericPackageDescription
pkg_descr0
        (HookedBuildInfo -> PackageDescription -> PackageDescription
updatePackageDescription HookedBuildInfo
pbi PackageDescription
pkg_descr)

    -- 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.)
    [PreExistingComponent]
externalPkgDeps :: [PreExistingComponent]
        <- Verbosity
-> Bool
-> Set LibraryName
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> PackageDescription
-> ComponentRequestedSpec
-> IO [PreExistingComponent]
configureDependencies
                Verbosity
verbosity
                Bool
use_external_internal_deps
                Set LibraryName
internalPackageSet
                InstalledPackageIndex
installedPackageSet
                Map (PackageName, ComponentName) InstalledPackageInfo
requiredDepsMap
                PackageDescription
pkg_descr
                ComponentRequestedSpec
enabled

    -- Compute installation directory templates, based on user
    -- configuration.
    --
    -- TODO: Move this into a helper function.
    InstallDirTemplates
defaultDirs :: InstallDirTemplates
        <- Bool -> CompilerFlavor -> Bool -> Bool -> IO InstallDirTemplates
defaultInstallDirs' Bool
use_external_internal_deps
                              (Compiler -> CompilerFlavor
compilerFlavor Compiler
comp)
                              (Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configUserInstall ConfigFlags
cfg))
                              (PackageDescription -> Bool
hasLibs PackageDescription
pkg_descr)
    let installDirs :: InstallDirTemplates
        installDirs :: InstallDirTemplates
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)

    -- 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 (t :: * -> *) a. Foldable t => t a -> Bool
null [Language]
langs)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"The package " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
pkg_descr0)
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" requires the following languages which are not "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"supported by " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerId -> String
forall a. Pretty a => a -> String
prettyShow (Compiler -> CompilerId
compilerId Compiler
comp) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((Language -> String) -> [Language] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Language -> String
forall a. Pretty a => a -> String
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 (t :: * -> *) a. Foldable t => t a -> Bool
null [Extension]
exts)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"The package " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow (GenericPackageDescription -> PackageIdentifier
forall pkg. Package pkg => pkg -> PackageIdentifier
packageId GenericPackageDescription
pkg_descr0)
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" requires the following language extensions which are not "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"supported by " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerId -> String
forall a. Pretty a => a -> String
prettyShow (Compiler -> CompilerId
compilerId Compiler
comp) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((Extension -> String) -> [Extension] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Extension -> String
forall a. Pretty a => a -> String
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 :: [String]
unsupportedFLibs = Compiler -> Platform -> [ForeignLib] -> [String]
unsupportedForeignLibs Compiler
comp Platform
compPlatform [ForeignLib]
flibs
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
unsupportedFLibs)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Cannot build some foreign libraries: "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"," [String]
unsupportedFLibs

    -- Configure certain external build tools, see below for which ones.
    let requiredBuildTools :: [LegacyExeDependency]
requiredBuildTools = do
          BuildInfo
bi <- PackageDescription -> ComponentRequestedSpec -> [BuildInfo]
enabledBuildInfos PackageDescription
pkg_descr 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 :: [LegacyExeDependency]
externBuildToolDeps =
                [ String -> VersionRange -> LegacyExeDependency
LegacyExeDependency (UnqualComponentName -> String
unUnqualComponentName UnqualComponentName
eName) VersionRange
versionRange
                | buildTool :: ExeDependency
buildTool@(ExeDependency PackageName
_ UnqualComponentName
eName VersionRange
versionRange)
                  <- PackageDescription -> BuildInfo -> [ExeDependency]
getAllToolDependencies PackageDescription
pkg_descr BuildInfo
bi
                , Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ PackageDescription -> ExeDependency -> Bool
isInternal PackageDescription
pkg_descr 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]
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_descr LegacyExeDependency
buildTool ]
          [LegacyExeDependency]
externBuildToolDeps [LegacyExeDependency]
-> [LegacyExeDependency] -> [LegacyExeDependency]
forall a. [a] -> [a] -> [a]
++ [LegacyExeDependency]
unknownBuildTools

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

    (PackageDescription
pkg_descr', ProgramDb
programDb'') <-
      Verbosity
-> PackageDescription
-> ProgramDb
-> ComponentRequestedSpec
-> IO (PackageDescription, ProgramDb)
configurePkgconfigPackages Verbosity
verbosity PackageDescription
pkg_descr ProgramDb
programDb' ComponentRequestedSpec
enabled

    -- 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.
    -- internalPackageSet
    -- use_external_internal_deps
    ([ComponentLocalBuildInfo]
buildComponents :: [ComponentLocalBuildInfo],
     InstalledPackageIndex
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 String
-> Flag ComponentId
-> PackageDescription
-> [PreExistingComponent]
-> 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 String
configIPID ConfigFlags
cfg)
            (ConfigFlags -> Flag ComponentId
configCID ConfigFlags
cfg)
            PackageDescription
pkg_descr
            [PreExistingComponent]
externalPkgDeps
            (ConfigFlags -> FlagAssignment
configConfigurationsFlags ConfigFlags
cfg)
            (ConfigFlags -> [(ModuleName, Module)]
configInstantiateWith ConfigFlags
cfg)
            InstalledPackageIndex
installedPackageSet
            Compiler
comp

    -- Decide if we're going to compile with split sections.
    Bool
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 (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 (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                        CompilerFlavor
GHCJS
                          -> Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                        CompilerFlavor
_ -> do Verbosity -> String -> IO ()
warn Verbosity
verbosity
                                     (String
"this compiler does not support " String -> ShowS
forall a. [a] -> [a] -> [a]
++
                                      String
"--enable-split-sections; ignoring")
                                Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

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

    let ghciLibByDefault :: Bool
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

    let sharedLibsByDefault :: Bool
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_ :: Bool
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_ :: Bool
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_ :: Bool
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_ :: Bool
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
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
withDynExe_ Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
withSharedLib_) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
           String
"Executables will use dynamic linking, but a shared library "
        String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"is not being built. Linking will fail if any executables "
        String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"depend on the library."

    LocalBuildInfo -> LocalBuildInfo
setProfLBI <- Verbosity
-> ConfigFlags -> Compiler -> IO (LocalBuildInfo -> LocalBuildInfo)
configureProfiling Verbosity
verbosity ConfigFlags
cfg Compiler
comp

    LocalBuildInfo -> LocalBuildInfo
setCoverageLBI <- Verbosity
-> ConfigFlags -> Compiler -> IO (LocalBuildInfo -> LocalBuildInfo)
configureCoverage Verbosity
verbosity ConfigFlags
cfg Compiler
comp



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

                             Flag Bool
_ -> Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False

    Bool
strip_lib <- String -> (ConfigFlags -> Flag Bool) -> IO Bool
strip_libexe String
"library" ConfigFlags -> Flag Bool
configStripLibs
    Bool
strip_exe <- String -> (ConfigFlags -> Flag Bool) -> IO Bool
strip_libexe String
"executable" ConfigFlags -> Flag Bool
configStripExes


    let reloc :: Bool
reloc = 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

    let buildComponentsMap :: Map ComponentName [ComponentLocalBuildInfo]
buildComponentsMap =
            (Map ComponentName [ComponentLocalBuildInfo]
 -> ComponentLocalBuildInfo
 -> Map ComponentName [ComponentLocalBuildInfo])
-> Map ComponentName [ComponentLocalBuildInfo]
-> [ComponentLocalBuildInfo]
-> Map ComponentName [ComponentLocalBuildInfo]
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 lbi :: LocalBuildInfo
lbi = (LocalBuildInfo -> LocalBuildInfo
setCoverageLBI (LocalBuildInfo -> LocalBuildInfo)
-> (LocalBuildInfo -> LocalBuildInfo)
-> LocalBuildInfo
-> LocalBuildInfo
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LocalBuildInfo -> LocalBuildInfo
setProfLBI)
              LocalBuildInfo :: ConfigFlags
-> FlagAssignment
-> ComponentRequestedSpec
-> [String]
-> InstallDirTemplates
-> Compiler
-> Platform
-> String
-> Maybe String
-> Graph ComponentLocalBuildInfo
-> Map ComponentName [ComponentLocalBuildInfo]
-> InstalledPackageIndex
-> Maybe String
-> PackageDescription
-> ProgramDb
-> PackageDBStack
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> ProfDetailLevel
-> ProfDetailLevel
-> OptimisationLevel
-> DebugInfoLevel
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> PathTemplate
-> PathTemplate
-> Bool
-> LocalBuildInfo
LocalBuildInfo {
                configFlags :: ConfigFlags
configFlags         = ConfigFlags
cfg,
                flagAssignment :: FlagAssignment
flagAssignment      = FlagAssignment
flags,
                componentEnabledSpec :: ComponentRequestedSpec
componentEnabledSpec = ComponentRequestedSpec
enabled,
                extraConfigArgs :: [String]
extraConfigArgs     = [],  -- Currently configure does not
                                           -- take extra args, but if it
                                           -- did they would go here.
                installDirTemplates :: InstallDirTemplates
installDirTemplates = InstallDirTemplates
installDirs,
                compiler :: Compiler
compiler            = Compiler
comp,
                hostPlatform :: Platform
hostPlatform        = Platform
compPlatform,
                buildDir :: String
buildDir            = String
buildDir,
                cabalFilePath :: Maybe String
cabalFilePath       = Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (ConfigFlags -> Flag String
configCabalFilePath ConfigFlags
cfg),
                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,
                installedPkgs :: InstalledPackageIndex
installedPkgs       = InstalledPackageIndex
packageDependsIndex,
                pkgDescrFile :: Maybe String
pkgDescrFile        = Maybe String
forall a. Maybe a
Nothing,
                localPkgDescr :: PackageDescription
localPkgDescr       = PackageDescription
pkg_descr',
                withPrograms :: ProgramDb
withPrograms        = ProgramDb
programDb'',
                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 -> Flag Bool -> Bool
forall a. a -> Flag a -> a
fromFlagOrDefault Bool
ghciLibByDefault (Flag Bool -> Bool) -> Flag Bool -> Bool
forall a b. (a -> b) -> a -> b
$
                                      ConfigFlags -> Flag Bool
configGHCiLib ConfigFlags
cfg,
                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,
                withPackageDB :: PackageDBStack
withPackageDB       = PackageDBStack
packageDbs,
                progPrefix :: PathTemplate
progPrefix          = Flag PathTemplate -> PathTemplate
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag PathTemplate -> PathTemplate)
-> Flag PathTemplate -> PathTemplate
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag PathTemplate
configProgPrefix ConfigFlags
cfg,
                progSuffix :: PathTemplate
progSuffix          = Flag PathTemplate -> PathTemplate
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag PathTemplate -> PathTemplate)
-> Flag PathTemplate -> PathTemplate
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag PathTemplate
configProgSuffix ConfigFlags
cfg,
                relocatable :: Bool
relocatable         = Bool
reloc
              }

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
reloc (Verbosity -> PackageDescription -> LocalBuildInfo -> IO ()
checkRelocatable Verbosity
verbosity PackageDescription
pkg_descr LocalBuildInfo
lbi)

    -- TODO: This is not entirely correct, because the dirs may vary
    -- across libraries/executables
    let dirs :: InstallDirs String
dirs = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs String
absoluteInstallDirs PackageDescription
pkg_descr LocalBuildInfo
lbi CopyDest
NoCopyDest
        relative :: InstallDirs (Maybe String)
relative = PackageIdentifier -> LocalBuildInfo -> InstallDirs (Maybe String)
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
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (String -> Bool
isAbsolute (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs)
           Bool -> Bool -> Bool
|| String
"${pkgroot}" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
        String
"expected an absolute directory name for --prefix: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
"${pkgroot}" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Using ${pkgroot} in prefix " String -> ShowS
forall a. [a] -> [a] -> [a]
++ InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" will not work if you rely on the Path_* module "
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" or other hard coded paths.  Cabal does not yet "
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" support fully  relocatable builds! "
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" See #462 #2302 #2994 #3305 #3473 #3586 #3909"
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" #4097 #4291 #4872"

    Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Using " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow PackageIdentifier
currentCabalId
                  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" compiled by " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> String
forall a. Pretty a => a -> String
prettyShow PackageIdentifier
currentCompilerId
    Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Using compiler: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Compiler -> String
showCompilerId Compiler
comp
    Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Using install prefix: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
dirs

    let dirinfo :: String -> String -> Maybe a -> IO ()
dirinfo String
name String
dir Maybe a
isPrefixRelative =
          Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" installed in: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
dir String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
relNote
          where relNote :: String
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
                         -> String
"  (fixed location)"
                  OS
_      -> String
""

    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Executables"      (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
bindir InstallDirs String
dirs)     (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
bindir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Libraries"        (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
libdir InstallDirs String
dirs)     (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
libdir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Dynamic Libraries" (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
dynlibdir InstallDirs String
dirs) (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
dynlibdir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Private executables" (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
libexecdir InstallDirs String
dirs) (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
libexecdir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Data files"       (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
datadir InstallDirs String
dirs)    (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
datadir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Documentation"    (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
docdir InstallDirs String
dirs)     (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
docdir InstallDirs (Maybe String)
relative)
    String -> String -> Maybe String -> IO ()
forall a. String -> String -> Maybe a -> IO ()
dirinfo String
"Configuration files" (InstallDirs String -> String
forall dir. InstallDirs dir -> dir
sysconfdir InstallDirs String
dirs) (InstallDirs (Maybe String) -> Maybe String
forall dir. InstallDirs dir -> dir
sysconfdir InstallDirs (Maybe String)
relative)

    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_ [ Verbosity -> Program -> Maybe ConfiguredProgram -> IO ()
reportProgram Verbosity
verbosity Program
prog Maybe ConfiguredProgram
configuredProg
              | (Program
prog, Maybe ConfiguredProgram
configuredProg) <- ProgramDb -> [(Program, Maybe ConfiguredProgram)]
knownPrograms ProgramDb
programDb'' ]

    LocalBuildInfo -> IO LocalBuildInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LocalBuildInfo
lbi

    where
      verbosity :: Verbosity
verbosity = Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg)

mkProgramDb :: ConfigFlags -> ProgramDb -> ProgramDb
mkProgramDb :: ConfigFlags -> ProgramDb -> ProgramDb
mkProgramDb ConfigFlags
cfg ProgramDb
initialProgramDb = ProgramDb
programDb
  where
    programDb :: ProgramDb
programDb  = [(String, [String])] -> ProgramDb -> ProgramDb
userSpecifyArgss (ConfigFlags -> [(String, [String])]
configProgramArgs ConfigFlags
cfg)
                 (ProgramDb -> ProgramDb)
-> (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(String, String)] -> ProgramDb -> ProgramDb
userSpecifyPaths (ConfigFlags -> [(String, String)]
configProgramPaths ConfigFlags
cfg)
                 (ProgramDb -> ProgramDb)
-> (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProgramSearchPath -> ProgramDb -> ProgramDb
setProgramSearchPath ProgramSearchPath
searchpath
                 (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall a b. (a -> b) -> a -> b
$ ProgramDb
initialProgramDb
    searchpath :: ProgramSearchPath
searchpath = ProgramDb -> ProgramSearchPath
getProgramSearchPath ProgramDb
initialProgramDb
                 ProgramSearchPath -> ProgramSearchPath -> ProgramSearchPath
forall a. [a] -> [a] -> [a]
++ (String -> ProgramSearchPathEntry) -> [String] -> ProgramSearchPath
forall a b. (a -> b) -> [a] -> [b]
map String -> ProgramSearchPathEntry
ProgramSearchPathDir
                 (NubList String -> [String]
forall a. NubList a -> [a]
fromNubList (NubList String -> [String]) -> NubList String -> [String]
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> NubList String
configProgramPathExtra ConfigFlags
cfg)

-- -----------------------------------------------------------------------------
-- 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 :: String
enable | Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configProfExe ConfigFlags
cfg) = String
"enable"
                 | Bool
otherwise = String
"disable"
      Verbosity -> String -> IO ()
warn Verbosity
verbosity
        (String
"The flag --" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
enable String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-executable-profiling is deprecated. "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Please use --" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
enable String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-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 :: String
enable | Flag Bool -> Bool
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Bool
configLibCoverage ConfigFlags
cfg) = String
"enable"
                 | Bool
otherwise = String
"disable"
      Verbosity -> String -> IO ()
warn Verbosity
verbosity
        (String
"The flag --" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
enable String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-library-coverage is deprecated. "
         String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Please use --" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
enable String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-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 (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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"'--exact-configuration' was given, "
        String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"but the following flags were not specified: "
        String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((FlagName -> String) -> [FlagName] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map FlagName -> String
forall a. Show a => a -> String
show [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) InstalledPackageInfo
       -- ^ required dependencies
    -> (Dependency -> Bool)
dependencySatisfiable :: Bool
-> Bool
-> Bool
-> PackageName
-> InstalledPackageIndex
-> Set LibraryName
-> 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) 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
        -- Except for internal deps, when we're NOT per-component mode;
        -- those are just True.
        then 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
        -- 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.
        then Bool
internalDepSatisfiableExternally
        -- If a 'PackageName' is defined by an internal component, the dep is
        -- satisfiable (we're going to build it ourselves)
        else 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 (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 (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
      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

-- | Finalize a generic package description.  The workhorse is
-- 'finalizePD' but there's a bit of other nattering
-- about necessary.
--
-- TODO: what exactly is the business with @flaggedTests@ and
-- @flaggedBenchmarks@?
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

    (PackageDescription
pkg_descr0', FlagAssignment
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 (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription, FlagAssignment)
r
               Left [Dependency]
missing ->
                   Verbosity -> String -> IO (PackageDescription, FlagAssignment)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO (PackageDescription, FlagAssignment))
-> String -> IO (PackageDescription, FlagAssignment)
forall a b. (a -> b) -> a -> b
$ String
"Encountered missing or private dependencies:\n"
                     String -> ShowS
forall a. [a] -> [a] -> [a]
++ (Doc -> String
render (Doc -> String) -> ([Dependency] -> Doc) -> [Dependency] -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> Doc -> Doc
nest Int
4 (Doc -> Doc) -> ([Dependency] -> Doc) -> [Dependency] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Doc] -> Doc
sep ([Doc] -> Doc) -> ([Dependency] -> [Doc]) -> [Dependency] -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Doc -> [Doc] -> [Doc]
punctuate Doc
comma
                                ([Doc] -> [Doc])
-> ([Dependency] -> [Doc]) -> [Dependency] -> [Doc]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Dependency -> Doc) -> [Dependency] -> [Doc]
forall a b. (a -> b) -> [a] -> [b]
map (Dependency -> Doc
forall a. Pretty a => a -> Doc
pretty (Dependency -> Doc)
-> (Dependency -> Dependency) -> Dependency -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dependency -> Dependency
simplifyDependency)
                                ([Dependency] -> String) -> [Dependency] -> String
forall a b. (a -> b) -> a -> b
$ [Dependency]
missing)

    -- add extra include/lib dirs as specified in cfg
    -- we do it here so that those get checked too
    let pkg_descr :: PackageDescription
pkg_descr = PackageDescription -> PackageDescription
addExtraIncludeLibDirs PackageDescription
pkg_descr0'

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (FlagAssignment -> Bool
nullFlagAssignment FlagAssignment
flags) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Flags chosen: "
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [ FlagName -> String
unFlagName FlagName
fn String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Bool -> String
forall a. Pretty a => a -> String
prettyShow Bool
value
                                        | (FlagName
fn, Bool
value) <- FlagAssignment -> [(FlagName, Bool)]
unFlagAssignment FlagAssignment
flags ]

    (PackageDescription, FlagAssignment)
-> IO (PackageDescription, FlagAssignment)
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription
pkg_descr, FlagAssignment
flags)
  where
    addExtraIncludeLibDirs :: PackageDescription -> PackageDescription
addExtraIncludeLibDirs PackageDescription
pkg_descr =
        let extraBi :: BuildInfo
extraBi = BuildInfo
forall a. Monoid a => a
mempty { extraLibDirs :: [String]
extraLibDirs = ConfigFlags -> [String]
configExtraLibDirs ConfigFlags
cfg
                             , extraFrameworkDirs :: [String]
extraFrameworkDirs = ConfigFlags -> [String]
configExtraFrameworkDirs ConfigFlags
cfg
                             , includeDirs :: [String]
includeDirs = ConfigFlags -> [String]
configExtraIncludeDirs ConfigFlags
cfg}
            modifyLib :: Library -> Library
modifyLib Library
l        = Library
l{ libBuildInfo :: BuildInfo
libBuildInfo        = Library -> BuildInfo
libBuildInfo Library
l
                                                          BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
extraBi }
            modifyExecutable :: Executable -> Executable
modifyExecutable Executable
e = Executable
e{ buildInfo :: BuildInfo
buildInfo           = Executable -> BuildInfo
buildInfo Executable
e
                                                          BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
extraBi}
            modifyForeignLib :: ForeignLib -> ForeignLib
modifyForeignLib ForeignLib
f = ForeignLib
f{ foreignLibBuildInfo :: BuildInfo
foreignLibBuildInfo = ForeignLib -> BuildInfo
foreignLibBuildInfo ForeignLib
f
                                                          BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
extraBi}
            modifyTestsuite :: TestSuite -> TestSuite
modifyTestsuite  TestSuite
t = TestSuite
t{ testBuildInfo :: BuildInfo
testBuildInfo      = TestSuite -> BuildInfo
testBuildInfo TestSuite
t
                                                          BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
extraBi}
            modifyBenchmark :: Benchmark -> Benchmark
modifyBenchmark  Benchmark
b = Benchmark
b{ benchmarkBuildInfo :: BuildInfo
benchmarkBuildInfo  = Benchmark -> BuildInfo
benchmarkBuildInfo Benchmark
b
                                                          BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
extraBi}
        in PackageDescription
pkg_descr
             { library :: Maybe Library
library      = Library -> Library
modifyLib        (Library -> Library) -> Maybe Library -> Maybe Library
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` PackageDescription -> Maybe Library
library      PackageDescription
pkg_descr
             , subLibraries :: [Library]
subLibraries = Library -> Library
modifyLib        (Library -> Library) -> [Library] -> [Library]
forall a b. (a -> b) -> [a] -> [b]
`map`  PackageDescription -> [Library]
subLibraries PackageDescription
pkg_descr
             , executables :: [Executable]
executables  = Executable -> Executable
modifyExecutable (Executable -> Executable) -> [Executable] -> [Executable]
forall a b. (a -> b) -> [a] -> [b]
`map`  PackageDescription -> [Executable]
executables  PackageDescription
pkg_descr
             , foreignLibs :: [ForeignLib]
foreignLibs  = ForeignLib -> ForeignLib
modifyForeignLib (ForeignLib -> ForeignLib) -> [ForeignLib] -> [ForeignLib]
forall a b. (a -> b) -> [a] -> [b]
`map`  PackageDescription -> [ForeignLib]
foreignLibs  PackageDescription
pkg_descr
             , testSuites :: [TestSuite]
testSuites   = TestSuite -> TestSuite
modifyTestsuite  (TestSuite -> TestSuite) -> [TestSuite] -> [TestSuite]
forall a b. (a -> b) -> [a] -> [b]
`map`  PackageDescription -> [TestSuite]
testSuites   PackageDescription
pkg_descr
             , benchmarks :: [Benchmark]
benchmarks   = Benchmark -> Benchmark
modifyBenchmark  (Benchmark -> Benchmark) -> [Benchmark] -> [Benchmark]
forall a b. (a -> b) -> [a] -> [b]
`map`  PackageDescription -> [Benchmark]
benchmarks   PackageDescription
pkg_descr
             }

-- | 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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
              String
"Your compiler does not support thinning and renaming on "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"package flags.  To use this feature you must use "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"GHC 7.9 or later."

    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 (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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
             String
"Your compiler does not support module re-exports. To use "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"this feature you must use GHC 7.9 or later."

    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 (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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
               String
"Your compiler does not support Backpack. To use "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"this feature you must use GHC 8.1 or later."

-- | Select dependencies for the package.
configureDependencies
    :: Verbosity
    -> UseExternalInternalDeps
    -> Set LibraryName
    -> InstalledPackageIndex -- ^ installed packages
    -> Map (PackageName, ComponentName) InstalledPackageInfo -- ^ required deps
    -> PackageDescription
    -> ComponentRequestedSpec
    -> IO [PreExistingComponent]
configureDependencies :: Verbosity
-> Bool
-> Set LibraryName
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> PackageDescription
-> ComponentRequestedSpec
-> IO [PreExistingComponent]
configureDependencies Verbosity
verbosity Bool
use_external_internal_deps
  Set LibraryName
packageLibraries 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 (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
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Bool
-> Dependency
-> [Either FailedDependency DependencyResolution]
selectDependency (PackageDescription -> PackageIdentifier
package PackageDescription
pkg_descr)
                  Set LibraryName
packageLibraries 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 ]

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([PackageIdentifier] -> 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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"The field 'build-depends: "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " ((PackageIdentifier -> String) -> [PackageIdentifier] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (PackageName -> String
forall a. Pretty a => a -> String
prettyShow (PackageName -> String)
-> (PackageIdentifier -> PackageName)
-> PackageIdentifier
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageIdentifier -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName) [PackageIdentifier]
internalPkgDeps)
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"' refers to a library which is defined within the same "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"package. To use this feature the package must specify at "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"least 'cabal-version: >= 1.8'."

    Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies Verbosity
verbosity [FailedDependency]
failedDeps
    Verbosity -> [ResolvedDependency] -> IO ()
reportSelectedDependencies Verbosity
verbosity [ResolvedDependency]
allPkgDeps

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

-- | Select and apply coverage settings for the build based on the
-- 'ConfigFlags' and 'Compiler'.
configureCoverage :: Verbosity -> ConfigFlags -> Compiler
                  -> IO (LocalBuildInfo -> LocalBuildInfo)
configureCoverage :: Verbosity
-> ConfigFlags -> Compiler -> IO (LocalBuildInfo -> LocalBuildInfo)
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))
    if Compiler -> Bool
coverageSupported Compiler
comp
      then do
        let apply :: LocalBuildInfo -> LocalBuildInfo
apply LocalBuildInfo
lbi = LocalBuildInfo
lbi { libCoverage :: Bool
libCoverage = Bool
tryLibCoverage
                            , exeCoverage :: Bool
exeCoverage = Bool
tryExeCoverage
                            }
        (LocalBuildInfo -> LocalBuildInfo)
-> IO (LocalBuildInfo -> LocalBuildInfo)
forall (m :: * -> *) a. Monad m => a -> m a
return LocalBuildInfo -> LocalBuildInfo
apply
      else do
        let apply :: LocalBuildInfo -> LocalBuildInfo
apply LocalBuildInfo
lbi = LocalBuildInfo
lbi { libCoverage :: Bool
libCoverage = Bool
False
                            , exeCoverage :: Bool
exeCoverage = Bool
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 -> String -> IO ()
warn Verbosity
verbosity
          (String
"The compiler " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Compiler -> String
showCompilerId Compiler
comp String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" does not support "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"program coverage. Program coverage has been disabled.")
        (LocalBuildInfo -> LocalBuildInfo)
-> IO (LocalBuildInfo -> LocalBuildInfo)
forall (m :: * -> *) a. Monad m => a -> m a
return LocalBuildInfo -> LocalBuildInfo
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 overidden 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 (LocalBuildInfo -> LocalBuildInfo)
configureProfiling :: Verbosity
-> ConfigFlags -> Compiler -> IO (LocalBuildInfo -> LocalBuildInfo)
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 String
other) = do
        Verbosity -> String -> IO ()
warn Verbosity
verbosity
          (String
"Unknown profiling detail level '" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
other
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"', using default.\nThe profiling detail levels are: "
           String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", "
           [ String
name | (String
name, [String]
_, ProfDetailLevel
_) <- [(String, [String], ProfDetailLevel)]
knownProfDetailLevels ])
        ProfDetailLevel -> IO ProfDetailLevel
forall (m :: * -> *) a. Monad m => a -> m a
return ProfDetailLevel
ProfDetailDefault
      checkProfileLevel ProfDetailLevel
other = ProfDetailLevel -> IO ProfDetailLevel
forall (m :: * -> *) a. Monad m => a -> m a
return ProfDetailLevel
other

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

  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
exeProfWithoutLibProf (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> IO ()
warn Verbosity
verbosity
    (String
"Executables will be built with profiling, but library "
     String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"profiling is disabled. Linking will fail if any executables "
     String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"depend on the library.")

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

hackageUrl :: String
hackageUrl :: String
hackageUrl = String
"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
    -- | 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

data FailedDependency = DependencyNotExists PackageName
                      | DependencyMissingInternal PackageName LibraryName
                      | DependencyNoVersion Dependency

-- | Test for a package dependency and record the version we have installed.
selectDependency :: PackageId -- ^ Package id of current package
                 -> Set LibraryName -- ^ package libraries
                 -> 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
-> InstalledPackageIndex
-> Map (PackageName, ComponentName) InstalledPackageInfo
-> Bool
-> Dependency
-> [Either FailedDependency DependencyResolution]
selectDependency PackageIdentifier
pkgid Set LibraryName
internalIndex 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 = do
      InstalledPackageInfo
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
-> [(Version, [InstalledPackageInfo])]
PackageIndex.lookupDependency InstalledPackageIndex
installedIndex PackageName
dep_pkgname VersionRange
vr 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
      DependencyResolution
-> Either FailedDependency DependencyResolution
forall (m :: * -> *) a. Monad m => a -> m a
return (DependencyResolution
 -> Either FailedDependency DependencyResolution)
-> DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PreExistingComponent -> DependencyResolution
ExternalDependency (PreExistingComponent -> DependencyResolution)
-> PreExistingComponent -> DependencyResolution
forall a b. (a -> b) -> a -> b
$ InstalledPackageInfo -> PreExistingComponent
ipiToPreExistingComponent InstalledPackageInfo
ipi

    do_external_internal :: LibraryName -> Either FailedDependency DependencyResolution
    do_external_internal :: LibraryName -> Either FailedDependency DependencyResolution
do_external_internal LibraryName
lib = do
      InstalledPackageInfo
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
      DependencyResolution
-> Either FailedDependency DependencyResolution
forall (m :: * -> *) a. Monad m => a -> m a
return (DependencyResolution
 -> Either FailedDependency DependencyResolution)
-> DependencyResolution
-> Either FailedDependency DependencyResolution
forall a b. (a -> b) -> a -> b
$ PreExistingComponent -> DependencyResolution
ExternalDependency (PreExistingComponent -> DependencyResolution)
-> PreExistingComponent -> DependencyResolution
forall a b. (a -> b) -> a -> b
$ InstalledPackageInfo -> PreExistingComponent
ipiToPreExistingComponent InstalledPackageInfo
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 -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
    [ String
"Dependency " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Dependency -> String
forall a. Pretty a => a -> String
prettyShow (Dependency -> Dependency
simplifyDependency Dependency
dep)
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": using " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageIdentifier -> String
forall a. Pretty a => a -> String
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' ]

reportFailedDependencies :: Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies :: Verbosity -> [FailedDependency] -> IO ()
reportFailedDependencies Verbosity
_ []     = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
reportFailedDependencies Verbosity
verbosity [FailedDependency]
failed =
    Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n\n" ((FailedDependency -> String) -> [FailedDependency] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map FailedDependency -> String
reportFailedDependency [FailedDependency]
failed))

  where
    reportFailedDependency :: FailedDependency -> String
reportFailedDependency (DependencyNotExists PackageName
pkgname) =
         String
"there is no version of " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" installed.\n"
      String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Perhaps you need to download and install it from\n"
      String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
hackageUrl String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"?"

    reportFailedDependency (DependencyMissingInternal PackageName
pkgname LibraryName
lib) =
         String
"internal dependency " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Doc -> String
forall a. Pretty a => a -> String
prettyShow (LibraryName -> Doc
prettyLibraryNameComponent LibraryName
lib) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" not installed.\n"
      String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Perhaps you need to configure and install it first?\n"
      String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"(This library was defined by " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkgname String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
")"

    reportFailedDependency (DependencyNoVersion Dependency
dep) =
        String
"cannot satisfy dependency " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Dependency -> String
forall a. Pretty a => a -> String
prettyShow (Dependency -> Dependency
simplifyDependency Dependency
dep) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\n"

-- | 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 (t :: * -> *) a. Foldable t => t a -> Bool
null PackageDBStack
packageDBs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"No package databases have been specified. If you use "
       String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"--package-db=clear, you must follow it with --package-db= "
       String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"with 'global', 'user' or a specific file."

  Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Reading installed packages..."
  -- do not check empty packagedbs (ghc-pkg would error out)
  PackageDBStack
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 Compiler -> CompilerFlavor
compilerFlavor Compiler
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 -> String -> IO InstalledPackageIndex
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO InstalledPackageIndex)
-> String -> IO InstalledPackageIndex
forall a b. (a -> b) -> a -> b
$ String
"don't know how to find the installed packages for "
              String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerFlavor -> String
forall a. Pretty a => a -> String
prettyShow CompilerFlavor
flv
  where
    packageDBExists :: PackageDB -> IO Bool
packageDBExists (SpecificPackageDB String
path) = do
      Bool
exists <- String -> IO Bool
doesPathExist String
path
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
exists (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Package db " String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
path String -> ShowS
forall a. Semigroup a => a -> a -> a
<> String
" does not exist yet"
      Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
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 (f :: * -> *) a. Applicative f => a -> f a
pure Bool
True
    packageDBExists PackageDB
GlobalPackageDB          = Bool -> IO Bool
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 -> String -> IO ()
info Verbosity
verbosity String
"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 [String]
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 [String]
GHC.getInstalledPackagesMonitorFiles
               Verbosity
verbosity Platform
platform ProgramDb
progdb PackageDBStack
packageDBs
    CompilerFlavor
other -> do
      Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"don't know how to find change monitoring files for "
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"the installed package databases for " String -> ShowS
forall a. [a] -> [a] -> [a]
++ CompilerFlavor -> String
forall a. Pretty a => a -> String
prettyShow CompilerFlavor
other
      [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return []

-- | 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]
  -> InstalledPackageIndex
  -> Either String ([PackageVersionConstraint],
                     Map (PackageName, ComponentName) InstalledPackageInfo)
combinedConstraints :: [PackageVersionConstraint]
-> [GivenComponent]
-> InstalledPackageIndex
-> Either
     String
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
combinedConstraints [PackageVersionConstraint]
constraints [GivenComponent]
dependencies InstalledPackageIndex
installedPackages = do

    Bool -> Either String () -> Either String ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([(PackageName, ComponentName, ComponentId)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(PackageName, ComponentName, ComponentId)]
badComponentIds)) (Either String () -> Either String ())
-> Either String () -> Either String ()
forall a b. (a -> b) -> a -> b
$
      String -> Either String ()
forall a b. a -> Either a b
Left (String -> Either String ()) -> String -> Either String ()
forall a b. (a -> b) -> a -> b
$ Doc -> String
render (Doc -> String) -> Doc -> String
forall a b. (a -> b) -> a -> b
$ String -> Doc
text String
"The following package dependencies were requested"
         Doc -> Doc -> Doc
$+$ Int -> Doc -> Doc
nest Int
4 ([(PackageName, ComponentName, ComponentId)] -> Doc
forall a a. (Pretty a, Pretty a) => [(a, ComponentName, a)] -> Doc
dispDependencies [(PackageName, ComponentName, ComponentId)]
badComponentIds)
         Doc -> Doc -> Doc
$+$ String -> Doc
text String
"however the given installed package instance does not exist."

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

    ([PackageVersionConstraint],
 Map (PackageName, ComponentName) InstalledPackageInfo)
-> Either
     String
     ([PackageVersionConstraint],
      Map (PackageName, ComponentName) InstalledPackageInfo)
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 [      String -> Doc
text String
"--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 String
progName VersionRange
verRange) =
  case String -> ProgramDb -> Maybe Program
lookupKnownProgram String
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 (String -> Program
simpleProgram String
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
          (ConfiguredProgram
_, ProgramDb
progdb') <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
prog ProgramDb
progdb
          ProgramDb -> IO ProgramDb
forall (m :: * -> *) a. Monad m => a -> m a
return ProgramDb
progdb'
      | Bool
otherwise -> do
          (ConfiguredProgram
_, Version
_, ProgramDb
progdb') <- Verbosity
-> Program
-> VersionRange
-> ProgramDb
-> IO (ConfiguredProgram, Version, ProgramDb)
requireProgramVersion Verbosity
verbosity Program
prog VersionRange
verRange ProgramDb
progdb
          ProgramDb -> IO ProgramDb
forall (m :: * -> *) a. Monad m => a -> m a
return ProgramDb
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 (t :: * -> *) a. Foldable t => t a -> Bool
null [PkgconfigDependency]
allpkgs = (PackageDescription, ProgramDb)
-> IO (PackageDescription, ProgramDb)
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription
pkg_descr, ProgramDb
progdb)
  | Bool
otherwise    = do
    (ConfiguredProgram
_, Version
_, ProgramDb
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
    (PkgconfigDependency -> IO ()) -> [PkgconfigDependency] -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ PkgconfigDependency -> IO ()
requirePkg [PkgconfigDependency]
allpkgs
    Maybe Library
mlib' <- (Library -> IO Library) -> Maybe Library -> IO (Maybe Library)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Library -> IO Library
addPkgConfigBILib (PackageDescription -> Maybe Library
library PackageDescription
pkg_descr)
    [Library]
libs' <- (Library -> IO Library) -> [Library] -> IO [Library]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Library -> IO Library
addPkgConfigBILib (PackageDescription -> [Library]
subLibraries PackageDescription
pkg_descr)
    [Executable]
exes' <- (Executable -> IO Executable) -> [Executable] -> IO [Executable]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Executable -> IO Executable
addPkgConfigBIExe (PackageDescription -> [Executable]
executables PackageDescription
pkg_descr)
    [TestSuite]
tests' <- (TestSuite -> IO TestSuite) -> [TestSuite] -> IO [TestSuite]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse TestSuite -> IO TestSuite
addPkgConfigBITest (PackageDescription -> [TestSuite]
testSuites PackageDescription
pkg_descr)
    [Benchmark]
benches' <- (Benchmark -> IO Benchmark) -> [Benchmark] -> IO [Benchmark]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Benchmark -> IO Benchmark
addPkgConfigBIBench (PackageDescription -> [Benchmark]
benchmarks PackageDescription
pkg_descr)
    let pkg_descr' :: PackageDescription
pkg_descr' = PackageDescription
pkg_descr { library :: Maybe Library
library = Maybe Library
mlib',
                                 subLibraries :: [Library]
subLibraries = [Library]
libs', executables :: [Executable]
executables = [Executable]
exes',
                                 testSuites :: [TestSuite]
testSuites = [TestSuite]
tests', benchmarks :: [Benchmark]
benchmarks = [Benchmark]
benches' }
    (PackageDescription, ProgramDb)
-> IO (PackageDescription, ProgramDb)
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDescription
pkg_descr', ProgramDb
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 :: [String] -> IO String
pkgconfig = Verbosity -> Program -> ProgramDb -> [String] -> IO String
getDbProgramOutput (Verbosity -> Verbosity
lessVerbose Verbosity
verbosity)
                  Program
pkgConfigProgram ProgramDb
progdb

    requirePkg :: PkgconfigDependency -> IO ()
requirePkg dep :: PkgconfigDependency
dep@(PkgconfigDependency PkgconfigName
pkgn PkgconfigVersionRange
range) = do
      String
version <- [String] -> IO String
pkgconfig [String
"--modversion", String
pkg]
                 IO String -> (IOException -> IO String) -> IO String
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO`   (\IOException
_ -> Verbosity -> String -> IO String
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
notFound)
                 IO String -> (ExitCode -> IO String) -> IO String
forall a. IO a -> (ExitCode -> IO a) -> IO a
`catchExit` (\ExitCode
_ -> Verbosity -> String -> IO String
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
notFound)
      let trim :: ShowS
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 :: PkgconfigVersion
v = ByteString -> PkgconfigVersion
PkgconfigVersion (String -> ByteString
toUTF8BS (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$ ShowS
trim String
version)
      if Bool -> Bool
not (PkgconfigVersion -> PkgconfigVersionRange -> Bool
withinPkgconfigVersionRange PkgconfigVersion
v PkgconfigVersionRange
range)
      then Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (PkgconfigVersion -> String
forall a. Pretty a => a -> String
badVersion PkgconfigVersion
v)
      else Verbosity -> String -> IO ()
info Verbosity
verbosity (PkgconfigVersion -> String
forall a. Pretty a => a -> String
depSatisfied PkgconfigVersion
v)
      where
        notFound :: String
notFound     = String
"The pkg-config package '" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
pkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"'"
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
versionRequirement
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" is required but it could not be found."
        badVersion :: a -> String
badVersion a
v = String
"The pkg-config package '" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
pkg String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"'"
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
versionRequirement
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" is required but the version installed on the"
                    String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" system is version " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Pretty a => a -> String
prettyShow a
v
        depSatisfied :: a -> String
depSatisfied a
v = String
"Dependency " String -> ShowS
forall a. [a] -> [a] -> [a]
++ PkgconfigDependency -> String
forall a. Pretty a => a -> String
prettyShow PkgconfigDependency
dep
                      String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
": using version " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Pretty a => a -> String
prettyShow a
v

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

        pkg :: String
pkg = PkgconfigName -> String
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
      BuildInfo
bi <- [PkgconfigDependency] -> IO BuildInfo
pkgconfigBuildInfo (BuildInfo -> [PkgconfigDependency]
pkgconfigDepends (t -> BuildInfo
compBI t
comp))
      b -> IO b
forall (m :: * -> *) a. Monad m => a -> m a
return (b -> IO b) -> b -> IO b
forall a b. (a -> b) -> a -> b
$ t -> BuildInfo -> b
setCompBI t
comp (t -> BuildInfo
compBI t
comp BuildInfo -> BuildInfo -> BuildInfo
forall a. Monoid a => a -> a -> a
`mappend` BuildInfo
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 :: BuildInfo
libBuildInfo = BuildInfo
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 :: BuildInfo
buildInfo = 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 :: BuildInfo
testBuildInfo = BuildInfo
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 :: BuildInfo
benchmarkBuildInfo = BuildInfo
bi }

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

-- | 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"]
-- > return (ccldOptionsBuildInfo (words ccflags) (words ldflags))
--
ccLdOptionsBuildInfo :: [String] -> [String] -> BuildInfo
ccLdOptionsBuildInfo :: [String] -> [String] -> BuildInfo
ccLdOptionsBuildInfo [String]
cflags [String]
ldflags =
  let ([String]
includeDirs',  [String]
cflags')   = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (String
"-I" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
cflags
      ([String]
extraLibs',    [String]
ldflags')  = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (String
"-l" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
ldflags
      ([String]
extraLibDirs', [String]
ldflags'') = (String -> Bool) -> [String] -> ([String], [String])
forall a. (a -> Bool) -> [a] -> ([a], [a])
partition (String
"-L" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
ldflags'
  in BuildInfo
forall a. Monoid a => a
mempty {
       includeDirs :: [String]
includeDirs  = ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
2) [String]
includeDirs',
       extraLibs :: [String]
extraLibs    = ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
2) [String]
extraLibs',
       extraLibDirs :: [String]
extraLibDirs = ShowS -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
2) [String]
extraLibDirs',
       ccOptions :: [String]
ccOptions    = [String]
cflags',
       ldOptions :: [String]
ldOptions    = [String]
ldflags''
     }

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

configCompilerAuxEx :: ConfigFlags
                    -> IO (Compiler, Platform, ProgramDb)
configCompilerAuxEx :: ConfigFlags -> IO (Compiler, Platform, ProgramDb)
configCompilerAuxEx ConfigFlags
cfg = Maybe CompilerFlavor
-> Maybe String
-> Maybe String
-> ProgramDb
-> Verbosity
-> IO (Compiler, Platform, ProgramDb)
configCompilerEx (Flag CompilerFlavor -> Maybe CompilerFlavor
forall a. Flag a -> Maybe a
flagToMaybe (Flag CompilerFlavor -> Maybe CompilerFlavor)
-> Flag CompilerFlavor -> Maybe CompilerFlavor
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag CompilerFlavor
configHcFlavor ConfigFlags
cfg)
                                           (Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (Flag String -> Maybe String) -> Flag String -> Maybe String
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag String
configHcPath ConfigFlags
cfg)
                                           (Flag String -> Maybe String
forall a. Flag a -> Maybe a
flagToMaybe (Flag String -> Maybe String) -> Flag String -> Maybe String
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag String
configHcPkg ConfigFlags
cfg)
                                           ProgramDb
programDb
                                           (Flag Verbosity -> Verbosity
forall a. WithCallStack (Flag a -> a)
fromFlag (ConfigFlags -> Flag Verbosity
configVerbosity ConfigFlags
cfg))
  where
    programDb :: ProgramDb
programDb = ConfigFlags -> ProgramDb -> ProgramDb
mkProgramDb ConfigFlags
cfg ProgramDb
defaultProgramDb

configCompilerEx :: Maybe CompilerFlavor -> Maybe FilePath -> Maybe FilePath
                 -> ProgramDb -> Verbosity
                 -> IO (Compiler, Platform, ProgramDb)
configCompilerEx :: Maybe CompilerFlavor
-> Maybe String
-> Maybe String
-> ProgramDb
-> Verbosity
-> IO (Compiler, Platform, ProgramDb)
configCompilerEx Maybe CompilerFlavor
Nothing Maybe String
_ Maybe String
_ ProgramDb
_ Verbosity
verbosity = Verbosity -> String -> IO (Compiler, Platform, ProgramDb)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
"Unknown compiler"
configCompilerEx (Just CompilerFlavor
hcFlavor) Maybe String
hcPath Maybe String
hcPkg ProgramDb
progdb Verbosity
verbosity = do
  (Compiler
comp, Maybe Platform
maybePlatform, ProgramDb
programDb) <- case CompilerFlavor
hcFlavor of
    CompilerFlavor
GHC   -> Verbosity
-> Maybe String
-> Maybe String
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
GHC.configure  Verbosity
verbosity Maybe String
hcPath Maybe String
hcPkg ProgramDb
progdb
    CompilerFlavor
GHCJS -> Verbosity
-> Maybe String
-> Maybe String
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
GHCJS.configure Verbosity
verbosity Maybe String
hcPath Maybe String
hcPkg ProgramDb
progdb
    CompilerFlavor
UHC   -> Verbosity
-> Maybe String
-> Maybe String
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
UHC.configure  Verbosity
verbosity Maybe String
hcPath Maybe String
hcPkg ProgramDb
progdb
    HaskellSuite {} -> Verbosity
-> Maybe String
-> Maybe String
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
HaskellSuite.configure Verbosity
verbosity Maybe String
hcPath Maybe String
hcPkg ProgramDb
progdb
    CompilerFlavor
_    -> Verbosity -> String -> IO (Compiler, Maybe Platform, ProgramDb)
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity String
"Unknown compiler"
  (Compiler, Platform, ProgramDb)
-> IO (Compiler, Platform, ProgramDb)
forall (m :: * -> *) a. Monad m => a -> m a
return (Compiler
comp, Platform -> Maybe Platform -> Platform
forall a. a -> Maybe a -> a
fromMaybe Platform
buildPlatform Maybe Platform
maybePlatform, ProgramDb
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 =
  [String] -> [String] -> IO () -> IO () -> IO ()
forall b. [String] -> [String] -> IO b -> IO b -> IO b
ifBuildsWith [String]
allHeaders ([String]
commonCcArgs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String] -> [String]
makeLdArgs [String]
allLibs) -- I'm feeling
                                                               -- lucky
           (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
           (do [String]
missingLibs <- IO [String]
findMissingLibs
               Maybe (Either String String)
missingHdr  <- IO (Maybe (Either String String))
findOffendingHdr
               Maybe (Either String String) -> [String] -> IO ()
explainErrors Maybe (Either String String)
missingHdr [String]
missingLibs)
      where
        allHeaders :: [String]
allHeaders = (BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
includes
        allLibs :: [String]
allLibs    = (BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
extraLibs

        ifBuildsWith :: [String] -> [String] -> IO b -> IO b -> IO b
ifBuildsWith [String]
headers [String]
args IO b
success IO b
failure = do
            IO ()
checkDuplicateHeaders
            Bool
ok <- String -> [String] -> IO Bool
builds ([String] -> String
makeProgram [String]
headers) [String]
args
            if Bool
ok then IO b
success else IO b
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 :: [String]
relIncDirs = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
isAbsolute) ((BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
includeDirs)
              isHeader :: String -> Bool
isHeader   = String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isSuffixOf String
".h"
          [[String]]
genHeaders <- [String] -> (String -> IO [String]) -> IO [[String]]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [String]
relIncDirs ((String -> IO [String]) -> IO [[String]])
-> (String -> IO [String]) -> IO [[String]]
forall a b. (a -> b) -> a -> b
$ \String
dir ->
            ShowS -> [String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String
dir String -> ShowS
</>) ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter String -> Bool
isHeader ([String] -> [String]) -> IO [String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
            String -> IO [String]
listDirectory (LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi String -> ShowS
</> String
dir) IO [String] -> (IOException -> IO [String]) -> IO [String]
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [])
          [[String]]
srcHeaders <- [String] -> (String -> IO [String]) -> IO [[String]]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
t a -> (a -> f b) -> f (t b)
for [String]
relIncDirs ((String -> IO [String]) -> IO [[String]])
-> (String -> IO [String]) -> IO [[String]]
forall a b. (a -> b) -> a -> b
$ \String
dir ->
            ShowS -> [String] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String
dir String -> ShowS
</>) ([String] -> [String])
-> ([String] -> [String]) -> [String] -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter String -> Bool
isHeader ([String] -> [String]) -> IO [String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
            String -> IO [String]
listDirectory (LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi String -> ShowS
</> String
dir) IO [String] -> (IOException -> IO [String]) -> IO [String]
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO` (\IOException
_ -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [])
          let commonHeaders :: [String]
commonHeaders = [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]]
genHeaders [String] -> [String] -> [String]
forall a. Eq a => [a] -> [a] -> [a]
`intersect` [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[String]]
srcHeaders
          [String] -> (String -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ [String]
commonHeaders ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
hdr -> do
            Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Duplicate header found in "
                          String -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi String -> ShowS
</> String
hdr)
                          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" and "
                          String -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi String -> ShowS
</> String
hdr)
                          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"; removing "
                          String -> ShowS
forall a. [a] -> [a] -> [a]
++ (LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi String -> ShowS
</> String
hdr)
            String -> IO ()
removeFile (LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi String -> ShowS
</> String
hdr)

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


              cppArgs :: [String]
cppArgs = String
"-E"String -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
commonCppArgs -- preprocess only
              ccArgs :: [String]
ccArgs  = String
"-c"String -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
commonCcArgs  -- don't try to link

        findMissingLibs :: IO [String]
findMissingLibs = [String] -> [String] -> IO [String] -> IO [String] -> IO [String]
forall b. [String] -> [String] -> IO b -> IO b -> IO b
ifBuildsWith [] ([String] -> [String]
makeLdArgs [String]
allLibs)
                                       ([String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [])
                                       ((String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM ((Bool -> Bool) -> IO Bool -> IO Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Bool -> Bool
not (IO Bool -> IO Bool) -> (String -> IO Bool) -> String -> IO Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO Bool
libExists) [String]
allLibs)

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

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

        commonCppArgs :: [String]
commonCppArgs = LocalBuildInfo -> [String]
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.)
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi String -> ShowS
</> String
"autogen" ]
                     -- `configure' may generate headers in the build directory
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi String -> ShowS
</> String
dir
                        | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
includeDirs)
                        , Bool -> Bool
not (String -> Bool
isAbsolute String
dir)]
                     -- we might also reference headers from the
                     -- packages directory.
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi String -> ShowS
</> String
dir
                        | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
includeDirs)
                        , Bool -> Bool
not (String -> Bool
isAbsolute String
dir)]
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
dir | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
includeDirs)
                                      , String -> Bool
isAbsolute String
dir]
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ LocalBuildInfo -> String
baseDir LocalBuildInfo
lbi]
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
cppOptions
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
ccOptions
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-I" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
dir
                        | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub [ String
dir
                                        | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
                                        , String
dir <- InstalledPackageInfo -> [String]
IPI.includeDirs InstalledPackageInfo
dep ]
                                 -- dedupe include dirs of dependencies
                                 -- to prevent quadratic blow-up
                        ]
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
opt
                        | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
                        , String
opt <- InstalledPackageInfo -> [String]
IPI.ccOptions InstalledPackageInfo
dep ]

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

        commonLdArgs :: [String]
commonLdArgs  = [ String
"-L" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
dir
                        | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub ((BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
extraLibDirs) ]
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (BuildInfo -> [String]) -> [String]
forall b. (BuildInfo -> [b]) -> [b]
collectField BuildInfo -> [String]
ldOptions
                     [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [ String
"-L" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
dir
                        | String
dir <- [String] -> [String]
forall a. Ord a => [a] -> [a]
ordNub [ String
dir
                                        | InstalledPackageInfo
dep <- [InstalledPackageInfo]
deps
                                        , String
dir <- InstalledPackageInfo -> [String]
IPI.libraryDirs InstalledPackageInfo
dep ]
                        ]
                     --TODO: do we also need dependent packages' ld options?
        makeLdArgs :: [String] -> [String]
makeLdArgs [String]
libs = [ String
"-l"String -> ShowS
forall a. [a] -> [a] -> [a]
++String
lib | String
lib <- [String]
libs ] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
commonLdArgs

        makeProgram :: [String] -> String
makeProgram [String]
hdrs = [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
                           [ String
"#include \""  String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
hdr String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\"" | String
hdr <- [String]
hdrs ] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++
                           [String
"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 :: String -> [String] -> IO Bool
builds String
program [String]
args = do
            String
tempDir <- IO String
getTemporaryDirectory
            String -> String -> (String -> Handle -> IO Bool) -> IO Bool
forall a. String -> String -> (String -> Handle -> IO a) -> IO a
withTempFile String
tempDir String
".c" ((String -> Handle -> IO Bool) -> IO Bool)
-> (String -> Handle -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \String
cName Handle
cHnd ->
              String -> String -> (String -> Handle -> IO Bool) -> IO Bool
forall a. String -> String -> (String -> Handle -> IO a) -> IO a
withTempFile String
tempDir String
"" ((String -> Handle -> IO Bool) -> IO Bool)
-> (String -> Handle -> IO Bool) -> IO Bool
forall a b. (a -> b) -> a -> b
$ \String
oNname Handle
oHnd -> do
                Handle -> String -> IO ()
hPutStrLn Handle
cHnd String
program
                Handle -> IO ()
hClose Handle
cHnd
                Handle -> IO ()
hClose Handle
oHnd
                String
_ <- Verbosity -> Program -> ProgramDb -> [String] -> IO String
getDbProgramOutput Verbosity
verbosity
                  Program
gccProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi) (String
cNameString -> [String] -> [String]
forall a. a -> [a] -> [a]
:String
"-o"String -> [String] -> [String]
forall a. a -> [a] -> [a]
:String
oNnameString -> [String] -> [String]
forall a. a -> [a] -> [a]
:[String]
args)
                Bool -> IO Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
           IO Bool -> (IOException -> IO Bool) -> IO Bool
forall a. IO a -> (IOException -> IO a) -> IO a
`catchIO`   (\IOException
_ -> Bool -> IO Bool
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 (m :: * -> *) a. Monad m => a -> m a
return Bool
False)

        explainErrors :: Maybe (Either String String) -> [String] -> IO ()
explainErrors Maybe (Either String String)
Nothing [] = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () -- should be impossible!
        explainErrors Maybe (Either String String)
_ [String]
_
           | 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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines
              [ String
"No working gcc",
                  String
"This package depends on foreign library but we cannot "
               String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"find a working C compiler. If you have it in a "
               String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"non-standard location you can use the --with-gcc "
               String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"flag to specify it." ]

        explainErrors Maybe (Either String String)
hdr [String]
libs = Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ [String] -> String
unlines ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
             [ if Bool
plural
                 then String
"Missing dependencies on foreign libraries:"
                 else String
"Missing dependency on a foreign library:"
             | Bool
missing ]
          [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ case Maybe (Either String String)
hdr of
               Just (Left String
h) -> [String
"* Missing (or bad) header file: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
h ]
               Maybe (Either String String)
_             -> []
          [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ case [String]
libs of
               []    -> []
               [String
lib] -> [String
"* Missing (or bad) C library: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
lib]
               [String]
_     -> [String
"* Missing (or bad) C libraries: " String -> ShowS
forall a. [a] -> [a] -> [a]
++
                         String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
", " [String]
libs]
          [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [if Bool
plural then String
messagePlural else String
messageSingular | Bool
missing]
          [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ case Maybe (Either String String)
hdr of
               Just (Left  String
_) -> [ String
headerCppMessage ]
               Just (Right String
h) -> [ (if Bool
missing then String
"* " else String
"")
                                   String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"Bad header file: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
h
                                 , String
headerCcMessage ]
               Maybe (Either String String)
_              -> []

          where
            plural :: Bool
plural  = [String] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [String]
libs Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
2
            -- Is there something missing? (as opposed to broken)
            missing :: Bool
missing = Bool -> Bool
not ([String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
libs)
                   Bool -> Bool -> Bool
|| case Maybe (Either String String)
hdr of Just (Left _) -> Bool
True; Maybe (Either String String)
_ -> Bool
False

        messageSingular :: String
messageSingular =
             String
"This problem can usually be solved by installing the system "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"package that provides this library (you may need the "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\"-dev\" version). If the library is already installed "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"but in a non-standard location then you can use the flags "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"--extra-include-dirs= and --extra-lib-dirs= to specify "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"where it is."
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"If the library file does exist, it may contain errors that "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"are caught by the C compiler at the preprocessing stage. "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"In this case you can re-run configure with the verbosity "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"flag -v3 to see the error messages."
        messagePlural :: String
messagePlural =
             String
"This problem can usually be solved by installing the system "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"packages that provide these libraries (you may need the "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"\"-dev\" versions). If the libraries are already installed "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"but in a non-standard location then you can use the flags "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"--extra-include-dirs= and --extra-lib-dirs= to specify "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"where they are."
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"If the library files do exist, it may contain errors that "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"are caught by the C compiler at the preprocessing stage. "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"In this case you can re-run configure with the verbosity "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"flag -v3 to see the error messages."
        headerCppMessage :: String
headerCppMessage =
             String
"If the header file does exist, it may contain errors that "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"are caught by the C compiler at the preprocessing stage. "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"In this case you can re-run configure with the verbosity "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"flag -v3 to see the error messages."
        headerCcMessage :: String
headerCcMessage =
             String
"The header file contains a compile error. "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"You can re-run configure with the verbosity flag "
          String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
"-v3 to see the error messages from the C compiler."

-- | 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
-> String
-> GenericPackageDescription
-> PackageDescription
-> IO ()
checkPackageProblems Verbosity
verbosity String
dir GenericPackageDescription
gpkg PackageDescription
pkg = do
  [PackageCheck]
ioChecks      <- Verbosity -> PackageDescription -> String -> IO [PackageCheck]
checkPackageFiles Verbosity
verbosity PackageDescription
pkg String
dir
  let pureChecks :: [PackageCheck]
pureChecks = GenericPackageDescription
-> Maybe PackageDescription -> [PackageCheck]
checkPackage GenericPackageDescription
gpkg (PackageDescription -> Maybe PackageDescription
forall a. a -> Maybe a
Just PackageDescription
pkg)
      errors :: [String]
errors   = [ String
e | PackageBuildImpossible String
e <- [PackageCheck]
pureChecks [PackageCheck] -> [PackageCheck] -> [PackageCheck]
forall a. [a] -> [a] -> [a]
++ [PackageCheck]
ioChecks ]
      warnings :: [String]
warnings = [ String
w | PackageBuildWarning    String
w <- [PackageCheck]
pureChecks [PackageCheck] -> [PackageCheck] -> [PackageCheck]
forall a. [a] -> [a] -> [a]
++ [PackageCheck]
ioChecks ]
  if [String] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
errors
    then (String -> IO ()) -> [String] -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (Verbosity -> String -> IO ()
warn Verbosity
verbosity) [String]
warnings
    else Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> [String] -> String
forall a. [a] -> [[a]] -> [a]
intercalate String
"\n\n" [String]
errors)

-- | 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 (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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Operating system: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ OS -> String
forall a. Pretty a => a -> String
prettyShow OS
os String -> ShowS
forall a. [a] -> [a] -> [a]
++
                String
", does not support relocatable builds"
      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 (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 -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Compiler: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Compiler -> String
forall a. Show a => a -> String
show Compiler
comp String -> ShowS
forall a. [a] -> [a] -> [a]
++
                String
", does not support relocatable builds"
      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 String -> Bool
relativeInstallDirs InstallDirs String
installDirs)
        (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Installation directories are not prefix_relative:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++
                InstallDirs String -> String
forall a. Show a => a -> String
show InstallDirs String
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 String
installDirs = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs String
absoluteInstallDirs PackageDescription
pkg LocalBuildInfo
lbi CopyDest
NoCopyDest
        p :: String
p           = InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
installDirs
        relativeInstallDirs :: InstallDirs String -> Bool
relativeInstallDirs (InstallDirs {String
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
sysconfdir :: String
haddockdir :: String
htmldir :: String
mandir :: String
docdir :: String
datasubdir :: String
datadir :: String
includedir :: String
libexecsubdir :: String
libexecdir :: String
flibdir :: String
dynlibdir :: String
libsubdir :: String
libdir :: String
bindir :: String
prefix :: String
sysconfdir :: forall dir. InstallDirs dir -> dir
docdir :: forall dir. InstallDirs dir -> dir
datadir :: forall dir. InstallDirs dir -> dir
libexecdir :: forall dir. InstallDirs dir -> dir
dynlibdir :: forall dir. InstallDirs dir -> dir
libdir :: forall dir. InstallDirs dir -> dir
bindir :: forall dir. InstallDirs dir -> dir
prefix :: forall dir. InstallDirs dir -> dir
..}) =
          (Maybe String -> Bool) -> [Maybe String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Maybe String -> Bool
forall a. Maybe a -> Bool
isJust
              ((String -> Maybe String) -> [String] -> [Maybe String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix String
p)
                    [ String
bindir, String
libdir, String
dynlibdir, String
libexecdir, String
includedir, String
datadir
                    , String
docdir, String
mandir, String
htmldir, String
haddockdir, String
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
        String
pkgr <- Verbosity -> LocalBuildInfo -> PackageDB -> IO String
GHC.pkgRoot Verbosity
verbosity LocalBuildInfo
lbi (PackageDBStack -> PackageDB
registrationPackageDB (LocalBuildInfo -> PackageDBStack
withPackageDB LocalBuildInfo
lbi))
        (InstalledPackageInfo -> IO ()) -> [InstalledPackageInfo] -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
(a -> f b) -> t a -> f ()
traverse_ (String -> InstalledPackageInfo -> IO ()
doCheck String
pkgr) [InstalledPackageInfo]
ipkgs
      where
        doCheck :: String -> InstalledPackageInfo -> IO ()
doCheck String
pkgr InstalledPackageInfo
ipkg
          | Bool -> (String -> Bool) -> Maybe String -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
pkgr) (InstalledPackageInfo -> Maybe String
IPI.pkgRoot InstalledPackageInfo
ipkg)
          = [String] -> (String -> IO ()) -> IO ()
forall (t :: * -> *) (f :: * -> *) a b.
(Foldable t, Applicative f) =>
t a -> (a -> f b) -> f ()
for_ (InstalledPackageInfo -> [String]
IPI.libraryDirs InstalledPackageInfo
ipkg) ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
libdir -> do
              -- When @prefix@ is not under @pkgroot@,
              -- @shortRelativePath prefix pkgroot@ will return a path with
              -- @..@s and following check will fail without @canonicalizePath@.
              String
canonicalized <- String -> IO String
canonicalizePath String
libdir
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (String
p String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
canonicalized) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
                Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ ShowS
forall a. Show a => a -> String
msg String
libdir
          | Bool
otherwise
          = () -> IO ()
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 String
installDirs   = PackageDescription
-> LocalBuildInfo -> CopyDest -> InstallDirs String
absoluteInstallDirs PackageDescription
pkg LocalBuildInfo
lbi CopyDest
NoCopyDest
        p :: String
p             = InstallDirs String -> String
forall dir. InstallDirs dir -> dir
prefix InstallDirs String
installDirs
        ipkgs :: [InstalledPackageInfo]
ipkgs         = InstalledPackageIndex -> [InstalledPackageInfo]
forall a. PackageIndex a -> [a]
PackageIndex.allPackages (LocalBuildInfo -> InstalledPackageIndex
installedPkgs LocalBuildInfo
lbi)
        msg :: a -> String
msg a
l         = String
"Library directory of a dependency: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ a -> String
forall a. Show a => a -> String
show a
l String -> ShowS
forall a. [a] -> [a] -> [a]
++
                        String
"\nis not relative to the installation prefix:\n" String -> ShowS
forall a. [a] -> [a] -> [a]
++
                        ShowS
forall a. Show a => a -> String
show String
p

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

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

checkForeignLibSupported :: Compiler -> Platform -> ForeignLib -> Maybe String
checkForeignLibSupported :: Compiler -> Platform -> ForeignLib -> Maybe String
checkForeignLibSupported Compiler
comp Platform
platform ForeignLib
flib = CompilerFlavor -> Maybe String
go (Compiler -> CompilerFlavor
compilerFlavor Compiler
comp)
  where
    go :: CompilerFlavor -> Maybe String
    go :: CompilerFlavor -> Maybe String
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] = [String] -> Maybe String
unsupported [
        String
"Building foreign libraires is only supported with GHC >= 7.8"
      ]
      | Bool
otherwise = Platform -> Maybe String
goGhcPlatform Platform
platform
    go CompilerFlavor
_   = [String] -> Maybe String
unsupported [
        String
"Building foreign libraries is currently only supported with ghc"
      ]

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

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

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

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

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

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