{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}

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

-- |
-- Module      :  Distribution.Simple.GHC
-- Copyright   :  Isaac Jones 2003-2007
-- License     :  BSD3
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This is a fairly large module. It contains most of the GHC-specific code for
-- configuring, building and installing packages. It also exports a function
-- for finding out what packages are already installed. Configuring involves
-- finding the @ghc@ and @ghc-pkg@ programs, finding what language extensions
-- this version of ghc supports and returning a 'Compiler' value.
--
-- 'getInstalledPackages' involves calling the @ghc-pkg@ program to find out
-- what packages are installed.
--
-- Building is somewhat complex as there is quite a bit of information to take
-- into account. We have to build libs and programs, possibly for profiling and
-- shared libs. We have to support building libraries that will be usable by
-- GHCi and also ghc's @-split-objs@ feature. We have to compile any C files
-- using ghc. Linking, especially for @split-objs@ is remarkably complex,
-- partly because there tend to be 1,000's of @.o@ files and this can often be
-- more than we can pass to the @ld@ or @ar@ programs in one go.
--
-- Installing for libs and exes involves finding the right files and copying
-- them to the right places. One of the more tricky things about this module is
-- remembering the layout of files in the build directory (which is not
-- explicitly documented) and thus what search dirs are used for various kinds
-- of files.
module Distribution.Simple.GHC
  ( getGhcInfo
  , configure
  , getInstalledPackages
  , getInstalledPackagesMonitorFiles
  , getPackageDBContents
  , buildLib
  , buildFLib
  , buildExe
  , replLib
  , replFLib
  , replExe
  , startInterpreter
  , installLib
  , installFLib
  , installExe
  , libAbiHash
  , hcPkgInfo
  , registerPackage
  , componentGhcOptions
  , componentCcGhcOptions
  , getGhcAppDir
  , getLibDir
  , isDynamic
  , getGlobalPackageDB
  , pkgRoot

    -- * Constructing and deconstructing GHC environment files
  , Internal.GhcEnvironmentFileEntry (..)
  , Internal.simpleGhcEnvironmentFile
  , Internal.renderGhcEnvironmentFile
  , Internal.writeGhcEnvironmentFile
  , Internal.ghcPlatformAndVersionString
  , readGhcEnvironmentFile
  , parseGhcEnvironmentFile
  , ParseErrorExc (..)

    -- * Version-specific implementation quirks
  , getImplInfo
  , GhcImplInfo (..)
  ) where

import Distribution.Compat.Prelude
import Prelude ()

import Distribution.CabalSpecVersion
import Distribution.InstalledPackageInfo (InstalledPackageInfo)
import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo
import Distribution.ModuleName (ModuleName)
import qualified Distribution.ModuleName as ModuleName
import Distribution.Package
import Distribution.PackageDescription as PD
import Distribution.PackageDescription.Utils (cabalBug)
import Distribution.Pretty
import Distribution.Simple.BuildPaths
import Distribution.Simple.Compiler
import Distribution.Simple.Flag (Flag (..), fromFlag, fromFlagOrDefault, toFlag)
import Distribution.Simple.GHC.EnvironmentParser
import Distribution.Simple.GHC.ImplInfo
import qualified Distribution.Simple.GHC.Internal as Internal
import qualified Distribution.Simple.Hpc as Hpc
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.PackageIndex (InstalledPackageIndex)
import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.Simple.Program
import qualified Distribution.Simple.Program.Ar as Ar
import Distribution.Simple.Program.Builtin (runghcProgram)
import Distribution.Simple.Program.GHC
import qualified Distribution.Simple.Program.HcPkg as HcPkg
import qualified Distribution.Simple.Program.Ld as Ld
import qualified Distribution.Simple.Program.Strip as Strip
import Distribution.Simple.Setup.Config
import Distribution.Simple.Setup.Repl
import Distribution.Simple.Utils
import Distribution.System
import Distribution.Types.ComponentLocalBuildInfo
import Distribution.Types.PackageName.Magic
import Distribution.Utils.NubList
import Distribution.Utils.Path
import Distribution.Verbosity
import Distribution.Version
import Language.Haskell.Extension

import Control.Monad (forM_, msum)
import Data.Char (isLower)
import qualified Data.Map as Map
import System.Directory
  ( canonicalizePath
  , createDirectoryIfMissing
  , doesDirectoryExist
  , doesFileExist
  , getAppUserDataDirectory
  , getCurrentDirectory
  , getDirectoryContents
  , makeRelativeToCurrentDirectory
  , removeFile
  , renameFile
  )
import System.FilePath
  ( isRelative
  , replaceExtension
  , takeDirectory
  , takeExtension
  , (<.>)
  , (</>)
  )
import qualified System.Info
#ifndef mingw32_HOST_OS
import System.Posix (createSymbolicLink)
#endif /* mingw32_HOST_OS */
import qualified Data.ByteString.Lazy.Char8 as BS
import Distribution.Compat.Binary (encode)
import Distribution.Compat.ResponseFile (escapeArgs)
import qualified Distribution.InstalledPackageInfo as IPI

-- -----------------------------------------------------------------------------
-- Configuring

configure
  :: Verbosity
  -> Maybe FilePath
  -> Maybe FilePath
  -> ProgramDb
  -> IO (Compiler, Maybe Platform, ProgramDb)
configure :: Verbosity
-> Maybe String
-> Maybe String
-> ProgramDb
-> IO (Compiler, Maybe Platform, ProgramDb)
configure Verbosity
verbosity Maybe String
hcPath Maybe String
hcPkgPath ProgramDb
conf0 = do
  (ConfiguredProgram
ghcProg, Version
ghcVersion, ProgramDb
progdb1) <-
    Verbosity
-> Program
-> VersionRange
-> ProgramDb
-> IO (ConfiguredProgram, Version, ProgramDb)
requireProgramVersion
      Verbosity
verbosity
      Program
ghcProgram
      (Version -> VersionRange
orLaterVersion ([Int] -> Version
mkVersion [Int
7, Int
0, Int
1]))
      (String -> Maybe String -> ProgramDb -> ProgramDb
userMaybeSpecifyPath String
"ghc" Maybe String
hcPath ProgramDb
conf0)
  let implInfo :: GhcImplInfo
implInfo = Version -> GhcImplInfo
ghcVersionImplInfo Version
ghcVersion

  -- Cabal currently supports ghc >= 7.0.1 && < 9.8
  -- ... and the following odd development version
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
9, Int
8]) (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
"Unknown/unsupported 'ghc' version detected "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"(Cabal "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
prettyShow Version
cabalVersion
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" supports 'ghc' version < 9.8): "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ ConfiguredProgram -> String
programPath ConfiguredProgram
ghcProg
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is version "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
prettyShow Version
ghcVersion

  -- This is slightly tricky, we have to configure ghc first, then we use the
  -- location of ghc to help find ghc-pkg in the case that the user did not
  -- specify the location of ghc-pkg directly:
  (ConfiguredProgram
ghcPkgProg, Version
ghcPkgVersion, ProgramDb
progdb2) <-
    Verbosity
-> Program
-> VersionRange
-> ProgramDb
-> IO (ConfiguredProgram, Version, ProgramDb)
requireProgramVersion
      Verbosity
verbosity
      Program
ghcPkgProgram
        { programFindLocation = guessGhcPkgFromGhcPath ghcProg
        }
      VersionRange
anyVersion
      (String -> Maybe String -> ProgramDb -> ProgramDb
userMaybeSpecifyPath String
"ghc-pkg" Maybe String
hcPkgPath ProgramDb
progdb1)

  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Version
ghcVersion Version -> Version -> Bool
forall a. Eq a => a -> a -> Bool
/= Version
ghcPkgVersion) (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
"Version mismatch between ghc and ghc-pkg: "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ ConfiguredProgram -> String
programPath ConfiguredProgram
ghcProg
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is version "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
prettyShow Version
ghcVersion
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ ConfiguredProgram -> String
programPath ConfiguredProgram
ghcPkgProg
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" is version "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
prettyShow Version
ghcPkgVersion

  -- Likewise we try to find the matching hsc2hs and haddock programs.
  let hsc2hsProgram' :: Program
hsc2hsProgram' =
        Program
hsc2hsProgram
          { programFindLocation = guessHsc2hsFromGhcPath ghcProg
          }
      haddockProgram' :: Program
haddockProgram' =
        Program
haddockProgram
          { programFindLocation = guessHaddockFromGhcPath ghcProg
          }
      hpcProgram' :: Program
hpcProgram' =
        Program
hpcProgram
          { programFindLocation = guessHpcFromGhcPath ghcProg
          }
      runghcProgram' :: Program
runghcProgram' =
        Program
runghcProgram
          { programFindLocation = guessRunghcFromGhcPath ghcProg
          }
      progdb3 :: ProgramDb
progdb3 =
        Program -> ProgramDb -> ProgramDb
addKnownProgram Program
haddockProgram' (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall a b. (a -> b) -> a -> b
$
          Program -> ProgramDb -> ProgramDb
addKnownProgram Program
hsc2hsProgram' (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall a b. (a -> b) -> a -> b
$
            Program -> ProgramDb -> ProgramDb
addKnownProgram Program
hpcProgram' (ProgramDb -> ProgramDb) -> ProgramDb -> ProgramDb
forall a b. (a -> b) -> a -> b
$
              Program -> ProgramDb -> ProgramDb
addKnownProgram Program
runghcProgram' ProgramDb
progdb2

  [(Language, String)]
languages <- Verbosity
-> GhcImplInfo -> ConfiguredProgram -> IO [(Language, String)]
Internal.getLanguages Verbosity
verbosity GhcImplInfo
implInfo ConfiguredProgram
ghcProg
  [(Extension, Maybe String)]
extensions0 <- Verbosity
-> GhcImplInfo
-> ConfiguredProgram
-> IO [(Extension, Maybe String)]
Internal.getExtensions Verbosity
verbosity GhcImplInfo
implInfo ConfiguredProgram
ghcProg

  [(String, String)]
ghcInfo <- Verbosity
-> GhcImplInfo -> ConfiguredProgram -> IO [(String, String)]
Internal.getGhcInfo Verbosity
verbosity GhcImplInfo
implInfo ConfiguredProgram
ghcProg
  let ghcInfoMap :: Map String String
ghcInfoMap = [(String, String)] -> Map String String
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(String, String)]
ghcInfo
      filterJS :: [(Extension, b)] -> [(Extension, b)]
filterJS = if Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
9, Int
8] then KnownExtension -> [(Extension, b)] -> [(Extension, b)]
forall {b}. KnownExtension -> [(Extension, b)] -> [(Extension, b)]
filterExt KnownExtension
JavaScriptFFI else [(Extension, b)] -> [(Extension, b)]
forall a. a -> a
id
      extensions :: [(Extension, Maybe String)]
extensions =
        -- workaround https://gitlab.haskell.org/ghc/ghc/-/issues/11214
        [(Extension, Maybe String)] -> [(Extension, Maybe String)]
forall {b}. [(Extension, b)] -> [(Extension, b)]
filterJS ([(Extension, Maybe String)] -> [(Extension, Maybe String)])
-> [(Extension, Maybe String)] -> [(Extension, Maybe String)]
forall a b. (a -> b) -> a -> b
$
          -- see 'filterExtTH' comment below
          [(Extension, Maybe String)] -> [(Extension, Maybe String)]
forall {b}. [(Extension, b)] -> [(Extension, b)]
filterExtTH ([(Extension, Maybe String)] -> [(Extension, Maybe String)])
-> [(Extension, Maybe String)] -> [(Extension, Maybe String)]
forall a b. (a -> b) -> a -> b
$
            [(Extension, Maybe String)]
extensions0

      -- starting with GHC 8.0, `TemplateHaskell` will be omitted from
      -- `--supported-extensions` when it's not available.
      -- for older GHCs we can use the "Have interpreter" property to
      -- filter out `TemplateHaskell`
      filterExtTH :: [(Extension, b)] -> [(Extension, b)]
filterExtTH
        | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
8]
        , Just String
"NO" <- String -> Map String String -> Maybe String
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup String
"Have interpreter" Map String String
ghcInfoMap =
            KnownExtension -> [(Extension, b)] -> [(Extension, b)]
forall {b}. KnownExtension -> [(Extension, b)] -> [(Extension, b)]
filterExt KnownExtension
TemplateHaskell
        | Bool
otherwise = [(Extension, b)] -> [(Extension, b)]
forall a. a -> a
id

      filterExt :: KnownExtension -> [(Extension, b)] -> [(Extension, b)]
filterExt KnownExtension
ext = ((Extension, b) -> Bool) -> [(Extension, b)] -> [(Extension, b)]
forall a. (a -> Bool) -> [a] -> [a]
filter ((Extension -> Extension -> Bool
forall a. Eq a => a -> a -> Bool
/= KnownExtension -> Extension
EnableExtension KnownExtension
ext) (Extension -> Bool)
-> ((Extension, b) -> Extension) -> (Extension, b) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Extension, b) -> Extension
forall a b. (a, b) -> a
fst)

  let comp :: Compiler
comp =
        Compiler
          { compilerId :: CompilerId
compilerId = CompilerFlavor -> Version -> CompilerId
CompilerId CompilerFlavor
GHC Version
ghcVersion
          , compilerAbiTag :: AbiTag
compilerAbiTag = AbiTag
NoAbiTag
          , compilerCompat :: [CompilerId]
compilerCompat = []
          , compilerLanguages :: [(Language, String)]
compilerLanguages = [(Language, String)]
languages
          , compilerExtensions :: [(Extension, Maybe String)]
compilerExtensions = [(Extension, Maybe String)]
extensions
          , compilerProperties :: Map String String
compilerProperties = Map String String
ghcInfoMap
          }
      compPlatform :: Maybe Platform
compPlatform = [(String, String)] -> Maybe Platform
Internal.targetPlatform [(String, String)]
ghcInfo
      -- configure gcc and ld
      progdb4 :: ProgramDb
progdb4 = GhcImplInfo
-> ConfiguredProgram -> Map String String -> ProgramDb -> ProgramDb
Internal.configureToolchain GhcImplInfo
implInfo ConfiguredProgram
ghcProg Map String String
ghcInfoMap ProgramDb
progdb3
  (Compiler, Maybe Platform, ProgramDb)
-> IO (Compiler, Maybe Platform, ProgramDb)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (Compiler
comp, Maybe Platform
compPlatform, ProgramDb
progdb4)

-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find
-- the corresponding tool; e.g. if the tool is ghc-pkg, we try looking
-- for a versioned or unversioned ghc-pkg in the same dir, that is:
--
-- > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)
-- > /usr/local/bin/ghc-pkg-6.6.1(.exe)
-- > /usr/local/bin/ghc-pkg(.exe)
guessToolFromGhcPath
  :: Program
  -> ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessToolFromGhcPath :: Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
tool ConfiguredProgram
ghcProg Verbosity
verbosity ProgramSearchPath
searchpath =
  do
    let toolname :: String
toolname = Program -> String
programName Program
tool
        given_path :: String
given_path = ConfiguredProgram -> String
programPath ConfiguredProgram
ghcProg
        given_dir :: String
given_dir = String -> String
takeDirectory String
given_path
    String
real_path <- String -> IO String
canonicalizePath String
given_path
    let real_dir :: String
real_dir = String -> String
takeDirectory String
real_path
        versionSuffix :: String -> String
versionSuffix String
path = String -> String
takeVersionSuffix (String -> String
dropExeExtension String
path)
        given_suf :: String
given_suf = String -> String
versionSuffix String
given_path
        real_suf :: String
real_suf = String -> String
versionSuffix String
real_path
        guessNormal :: String -> String
guessNormal String
dir = String
dir String -> String -> String
</> String
toolname String -> String -> String
<.> Platform -> String
exeExtension Platform
buildPlatform
        guessGhcVersioned :: String -> String -> String
guessGhcVersioned String
dir String
suf =
          String
dir
            String -> String -> String
</> (String
toolname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-ghc" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
suf)
              String -> String -> String
<.> Platform -> String
exeExtension Platform
buildPlatform
        guessVersioned :: String -> String -> String
guessVersioned String
dir String
suf =
          String
dir
            String -> String -> String
</> (String
toolname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
suf)
              String -> String -> String
<.> Platform -> String
exeExtension Platform
buildPlatform
        mkGuesses :: String -> String -> [String]
mkGuesses String
dir String
suf
          | String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
suf = [String -> String
guessNormal String
dir]
          | Bool
otherwise =
              [ String -> String -> String
guessGhcVersioned String
dir String
suf
              , String -> String -> String
guessVersioned String
dir String
suf
              , String -> String
guessNormal String
dir
              ]
        -- order matters here, see https://github.com/haskell/cabal/issues/7390
        guesses :: [String]
guesses =
          ( if String
real_path String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
given_path
              then []
              else String -> String -> [String]
mkGuesses String
real_dir String
real_suf
          )
            [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ String -> String -> [String]
mkGuesses String
given_dir String
given_suf
    Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
      String
"looking for tool "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
toolname
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" near compiler in "
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
given_dir
    Verbosity -> String -> IO ()
debug Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"candidate locations: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
forall a. Show a => a -> String
show [String]
guesses
    [Bool]
exists <- (String -> IO Bool) -> [String] -> IO [Bool]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse String -> IO Bool
doesFileExist [String]
guesses
    case [String
file | (String
file, Bool
True) <- [String] -> [Bool] -> [(String, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
guesses [Bool]
exists] of
      -- If we can't find it near ghc, fall back to the usual
      -- method.
      [] -> Program
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
programFindLocation Program
tool Verbosity
verbosity ProgramSearchPath
searchpath
      (String
fp : [String]
_) -> do
        Verbosity -> String -> IO ()
info Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"found " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
toolname String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
fp
        let lookedAt :: [String]
lookedAt =
              ((String, Bool) -> String) -> [(String, Bool)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, Bool) -> String
forall a b. (a, b) -> a
fst
                ([(String, Bool)] -> [String])
-> ([(String, Bool)] -> [(String, Bool)])
-> [(String, Bool)]
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((String, Bool) -> Bool) -> [(String, Bool)] -> [(String, Bool)]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (\(String
_file, Bool
exist) -> Bool -> Bool
not Bool
exist)
                ([(String, Bool)] -> [String]) -> [(String, Bool)] -> [String]
forall a b. (a -> b) -> a -> b
$ [String] -> [Bool] -> [(String, Bool)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
guesses [Bool]
exists
        Maybe (String, [String]) -> IO (Maybe (String, [String]))
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((String, [String]) -> Maybe (String, [String])
forall a. a -> Maybe a
Just (String
fp, [String]
lookedAt))
  where
    takeVersionSuffix :: FilePath -> String
    takeVersionSuffix :: String -> String
takeVersionSuffix = (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhileEndLE Char -> Bool
isSuffixChar

    isSuffixChar :: Char -> Bool
    isSuffixChar :: Char -> Bool
isSuffixChar Char
c = Char -> Bool
isDigit Char
c Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'-'

-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a
-- corresponding ghc-pkg, we try looking for both a versioned and unversioned
-- ghc-pkg in the same dir, that is:
--
-- > /usr/local/bin/ghc-pkg-ghc-6.6.1(.exe)
-- > /usr/local/bin/ghc-pkg-6.6.1(.exe)
-- > /usr/local/bin/ghc-pkg(.exe)
guessGhcPkgFromGhcPath
  :: ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessGhcPkgFromGhcPath :: ConfiguredProgram
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
guessGhcPkgFromGhcPath = Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
ghcPkgProgram

-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a
-- corresponding hsc2hs, we try looking for both a versioned and unversioned
-- hsc2hs in the same dir, that is:
--
-- > /usr/local/bin/hsc2hs-ghc-6.6.1(.exe)
-- > /usr/local/bin/hsc2hs-6.6.1(.exe)
-- > /usr/local/bin/hsc2hs(.exe)
guessHsc2hsFromGhcPath
  :: ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessHsc2hsFromGhcPath :: ConfiguredProgram
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
guessHsc2hsFromGhcPath = Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
hsc2hsProgram

-- | Given something like /usr/local/bin/ghc-6.6.1(.exe) we try and find a
-- corresponding haddock, we try looking for both a versioned and unversioned
-- haddock in the same dir, that is:
--
-- > /usr/local/bin/haddock-ghc-6.6.1(.exe)
-- > /usr/local/bin/haddock-6.6.1(.exe)
-- > /usr/local/bin/haddock(.exe)
guessHaddockFromGhcPath
  :: ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessHaddockFromGhcPath :: ConfiguredProgram
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
guessHaddockFromGhcPath = Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
haddockProgram

guessHpcFromGhcPath
  :: ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessHpcFromGhcPath :: ConfiguredProgram
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
guessHpcFromGhcPath = Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
hpcProgram

guessRunghcFromGhcPath
  :: ConfiguredProgram
  -> Verbosity
  -> ProgramSearchPath
  -> IO (Maybe (FilePath, [FilePath]))
guessRunghcFromGhcPath :: ConfiguredProgram
-> Verbosity -> ProgramSearchPath -> IO (Maybe (String, [String]))
guessRunghcFromGhcPath = Program
-> ConfiguredProgram
-> Verbosity
-> ProgramSearchPath
-> IO (Maybe (String, [String]))
guessToolFromGhcPath Program
runghcProgram

getGhcInfo :: Verbosity -> ConfiguredProgram -> IO [(String, String)]
getGhcInfo :: Verbosity -> ConfiguredProgram -> IO [(String, String)]
getGhcInfo Verbosity
verbosity ConfiguredProgram
ghcProg = Verbosity
-> GhcImplInfo -> ConfiguredProgram -> IO [(String, String)]
Internal.getGhcInfo Verbosity
verbosity GhcImplInfo
implInfo ConfiguredProgram
ghcProg
  where
    version :: Version
version = Version -> Maybe Version -> Version
forall a. a -> Maybe a -> a
fromMaybe (String -> Version
forall a. HasCallStack => String -> a
error String
"GHC.getGhcInfo: no ghc version") (Maybe Version -> Version) -> Maybe Version -> Version
forall a b. (a -> b) -> a -> b
$ ConfiguredProgram -> Maybe Version
programVersion ConfiguredProgram
ghcProg
    implInfo :: GhcImplInfo
implInfo = Version -> GhcImplInfo
ghcVersionImplInfo Version
version

-- | Given a single package DB, return all installed packages.
getPackageDBContents
  :: Verbosity
  -> PackageDB
  -> ProgramDb
  -> IO InstalledPackageIndex
getPackageDBContents :: Verbosity -> PackageDB -> ProgramDb -> IO InstalledPackageIndex
getPackageDBContents Verbosity
verbosity PackageDB
packagedb ProgramDb
progdb = do
  [(PackageDB, [InstalledPackageInfo])]
pkgss <- Verbosity
-> [PackageDB]
-> ProgramDb
-> IO [(PackageDB, [InstalledPackageInfo])]
getInstalledPackages' Verbosity
verbosity [PackageDB
packagedb] ProgramDb
progdb
  Verbosity
-> [(PackageDB, [InstalledPackageInfo])]
-> ProgramDb
-> IO InstalledPackageIndex
toPackageIndex Verbosity
verbosity [(PackageDB, [InstalledPackageInfo])]
pkgss ProgramDb
progdb

-- | Given a package DB stack, return all installed packages.
getInstalledPackages
  :: Verbosity
  -> Compiler
  -> PackageDBStack
  -> ProgramDb
  -> IO InstalledPackageIndex
getInstalledPackages :: Verbosity
-> Compiler -> [PackageDB] -> ProgramDb -> IO InstalledPackageIndex
getInstalledPackages Verbosity
verbosity Compiler
comp [PackageDB]
packagedbs ProgramDb
progdb = do
  Verbosity -> IO ()
checkPackageDbEnvVar Verbosity
verbosity
  Verbosity -> Compiler -> [PackageDB] -> IO ()
checkPackageDbStack Verbosity
verbosity Compiler
comp [PackageDB]
packagedbs
  [(PackageDB, [InstalledPackageInfo])]
pkgss <- Verbosity
-> [PackageDB]
-> ProgramDb
-> IO [(PackageDB, [InstalledPackageInfo])]
getInstalledPackages' Verbosity
verbosity [PackageDB]
packagedbs ProgramDb
progdb
  InstalledPackageIndex
index <- Verbosity
-> [(PackageDB, [InstalledPackageInfo])]
-> ProgramDb
-> IO InstalledPackageIndex
toPackageIndex Verbosity
verbosity [(PackageDB, [InstalledPackageInfo])]
pkgss ProgramDb
progdb
  InstalledPackageIndex -> IO InstalledPackageIndex
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (InstalledPackageIndex -> IO InstalledPackageIndex)
-> InstalledPackageIndex -> IO InstalledPackageIndex
forall a b. (a -> b) -> a -> b
$! InstalledPackageIndex -> InstalledPackageIndex
hackRtsPackage InstalledPackageIndex
index
  where
    hackRtsPackage :: InstalledPackageIndex -> InstalledPackageIndex
hackRtsPackage InstalledPackageIndex
index =
      case InstalledPackageIndex
-> PackageName -> [(Version, [InstalledPackageInfo])]
forall a. PackageIndex a -> PackageName -> [(Version, [a])]
PackageIndex.lookupPackageName InstalledPackageIndex
index (String -> PackageName
mkPackageName String
"rts") of
        [(Version
_, [InstalledPackageInfo
rts])] ->
          InstalledPackageInfo
-> InstalledPackageIndex -> InstalledPackageIndex
PackageIndex.insert (InstalledPackageInfo -> InstalledPackageInfo
removeMingwIncludeDir InstalledPackageInfo
rts) InstalledPackageIndex
index
        [(Version, [InstalledPackageInfo])]
_ -> InstalledPackageIndex
index -- No (or multiple) ghc rts package is registered!!
        -- Feh, whatever, the ghc test suite does some crazy stuff.

-- | Given a list of @(PackageDB, InstalledPackageInfo)@ pairs, produce a
-- @PackageIndex@. Helper function used by 'getPackageDBContents' and
-- 'getInstalledPackages'.
toPackageIndex
  :: Verbosity
  -> [(PackageDB, [InstalledPackageInfo])]
  -> ProgramDb
  -> IO InstalledPackageIndex
toPackageIndex :: Verbosity
-> [(PackageDB, [InstalledPackageInfo])]
-> ProgramDb
-> IO InstalledPackageIndex
toPackageIndex Verbosity
verbosity [(PackageDB, [InstalledPackageInfo])]
pkgss ProgramDb
progdb = do
  -- On Windows, various fields have $topdir/foo rather than full
  -- paths. We need to substitute the right value in so that when
  -- we, for example, call gcc, we have proper paths to give it.
  String
topDir <- Verbosity -> ConfiguredProgram -> IO String
getLibDir' Verbosity
verbosity ConfiguredProgram
ghcProg
  let indices :: [InstalledPackageIndex]
indices =
        [ [InstalledPackageInfo] -> InstalledPackageIndex
PackageIndex.fromList ((InstalledPackageInfo -> InstalledPackageInfo)
-> [InstalledPackageInfo] -> [InstalledPackageInfo]
forall a b. (a -> b) -> [a] -> [b]
map (String -> InstalledPackageInfo -> InstalledPackageInfo
Internal.substTopDir String
topDir) [InstalledPackageInfo]
pkgs)
        | (PackageDB
_, [InstalledPackageInfo]
pkgs) <- [(PackageDB, [InstalledPackageInfo])]
pkgss
        ]
  InstalledPackageIndex -> IO InstalledPackageIndex
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (InstalledPackageIndex -> IO InstalledPackageIndex)
-> InstalledPackageIndex -> IO InstalledPackageIndex
forall a b. (a -> b) -> a -> b
$! [InstalledPackageIndex] -> InstalledPackageIndex
forall a. Monoid a => [a] -> a
mconcat [InstalledPackageIndex]
indices
  where
    ghcProg :: ConfiguredProgram
ghcProg = ConfiguredProgram -> Maybe ConfiguredProgram -> ConfiguredProgram
forall a. a -> Maybe a -> a
fromMaybe (String -> ConfiguredProgram
forall a. HasCallStack => String -> a
error String
"GHC.toPackageIndex: no ghc program") (Maybe ConfiguredProgram -> ConfiguredProgram)
-> Maybe ConfiguredProgram -> ConfiguredProgram
forall a b. (a -> b) -> a -> b
$ Program -> ProgramDb -> Maybe ConfiguredProgram
lookupProgram Program
ghcProgram ProgramDb
progdb

-- | Return the 'FilePath' to the GHC application data directory.
--
-- @since 3.4.0.0
getGhcAppDir :: IO FilePath
getGhcAppDir :: IO String
getGhcAppDir = String -> IO String
getAppUserDataDirectory String
"ghc"

getLibDir :: Verbosity -> LocalBuildInfo -> IO FilePath
getLibDir :: Verbosity -> LocalBuildInfo -> IO String
getLibDir Verbosity
verbosity LocalBuildInfo
lbi =
  (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEndLE Char -> Bool
isSpace
    (String -> String) -> IO String -> IO String
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Verbosity -> Program -> ProgramDb -> [String] -> IO String
getDbProgramOutput
      Verbosity
verbosity
      Program
ghcProgram
      (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
      [String
"--print-libdir"]

getLibDir' :: Verbosity -> ConfiguredProgram -> IO FilePath
getLibDir' :: Verbosity -> ConfiguredProgram -> IO String
getLibDir' Verbosity
verbosity ConfiguredProgram
ghcProg =
  (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEndLE Char -> Bool
isSpace
    (String -> String) -> IO String -> IO String
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Verbosity -> ConfiguredProgram -> [String] -> IO String
getProgramOutput Verbosity
verbosity ConfiguredProgram
ghcProg [String
"--print-libdir"]

-- | Return the 'FilePath' to the global GHC package database.
getGlobalPackageDB :: Verbosity -> ConfiguredProgram -> IO FilePath
getGlobalPackageDB :: Verbosity -> ConfiguredProgram -> IO String
getGlobalPackageDB Verbosity
verbosity ConfiguredProgram
ghcProg =
  (Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEndLE Char -> Bool
isSpace
    (String -> String) -> IO String -> IO String
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` Verbosity -> ConfiguredProgram -> [String] -> IO String
getProgramOutput Verbosity
verbosity ConfiguredProgram
ghcProg [String
"--print-global-package-db"]

-- | Return the 'FilePath' to the per-user GHC package database.
getUserPackageDB
  :: Verbosity -> ConfiguredProgram -> Platform -> IO FilePath
getUserPackageDB :: Verbosity -> ConfiguredProgram -> Platform -> IO String
getUserPackageDB Verbosity
_verbosity ConfiguredProgram
ghcProg Platform
platform = do
  -- It's rather annoying that we have to reconstruct this, because ghc
  -- hides this information from us otherwise. But for certain use cases
  -- like change monitoring it really can't remain hidden.
  String
appdir <- IO String
getGhcAppDir
  String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
appdir String -> String -> String
</> String
platformAndVersion String -> String -> String
</> String
packageConfFileName)
  where
    platformAndVersion :: String
platformAndVersion =
      Platform -> Version -> String
Internal.ghcPlatformAndVersionString
        Platform
platform
        Version
ghcVersion
    packageConfFileName :: String
packageConfFileName = String
"package.conf.d"
    ghcVersion :: Version
ghcVersion = Version -> Maybe Version -> Version
forall a. a -> Maybe a -> a
fromMaybe (String -> Version
forall a. HasCallStack => String -> a
error String
"GHC.getUserPackageDB: no ghc version") (Maybe Version -> Version) -> Maybe Version -> Version
forall a b. (a -> b) -> a -> b
$ ConfiguredProgram -> Maybe Version
programVersion ConfiguredProgram
ghcProg

checkPackageDbEnvVar :: Verbosity -> IO ()
checkPackageDbEnvVar :: Verbosity -> IO ()
checkPackageDbEnvVar Verbosity
verbosity =
  Verbosity -> String -> String -> IO ()
Internal.checkPackageDbEnvVar Verbosity
verbosity String
"GHC" String
"GHC_PACKAGE_PATH"

checkPackageDbStack :: Verbosity -> Compiler -> PackageDBStack -> IO ()
checkPackageDbStack :: Verbosity -> Compiler -> [PackageDB] -> IO ()
checkPackageDbStack Verbosity
verbosity Compiler
comp =
  if GhcImplInfo -> Bool
flagPackageConf GhcImplInfo
implInfo
    then Verbosity -> [PackageDB] -> IO ()
checkPackageDbStackPre76 Verbosity
verbosity
    else Verbosity -> [PackageDB] -> IO ()
checkPackageDbStackPost76 Verbosity
verbosity
  where
    implInfo :: GhcImplInfo
implInfo = Version -> GhcImplInfo
ghcVersionImplInfo (Compiler -> Version
compilerVersion Compiler
comp)

checkPackageDbStackPost76 :: Verbosity -> PackageDBStack -> IO ()
checkPackageDbStackPost76 :: Verbosity -> [PackageDB] -> IO ()
checkPackageDbStackPost76 Verbosity
_ (PackageDB
GlobalPackageDB : [PackageDB]
rest)
  | PackageDB
GlobalPackageDB PackageDB -> [PackageDB] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [PackageDB]
rest = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
checkPackageDbStackPost76 Verbosity
verbosity [PackageDB]
rest
  | PackageDB
GlobalPackageDB PackageDB -> [PackageDB] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [PackageDB]
rest =
      Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
        String
"If the global package db is specified, it must be "
          String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"specified first and cannot be specified multiple times"
checkPackageDbStackPost76 Verbosity
_ [PackageDB]
_ = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()

checkPackageDbStackPre76 :: Verbosity -> PackageDBStack -> IO ()
checkPackageDbStackPre76 :: Verbosity -> [PackageDB] -> IO ()
checkPackageDbStackPre76 Verbosity
_ (PackageDB
GlobalPackageDB : [PackageDB]
rest)
  | PackageDB
GlobalPackageDB PackageDB -> [PackageDB] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [PackageDB]
rest = () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
checkPackageDbStackPre76 Verbosity
verbosity [PackageDB]
rest
  | PackageDB
GlobalPackageDB PackageDB -> [PackageDB] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` [PackageDB]
rest =
      Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
        String
"With current ghc versions the global package db is always used "
          String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"and must be listed first. This ghc limitation is lifted in GHC 7.6,"
          String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"see https://gitlab.haskell.org/ghc/ghc/-/issues/5977"
checkPackageDbStackPre76 Verbosity
verbosity [PackageDB]
_ =
  Verbosity -> String -> IO ()
forall a. Verbosity -> String -> IO a
die' Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
    String
"If the global package db is specified, it must be "
      String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"specified first and cannot be specified multiple times"

-- GHC < 6.10 put "$topdir/include/mingw" in rts's installDirs. This
-- breaks when you want to use a different gcc, so we need to filter
-- it out.
removeMingwIncludeDir :: InstalledPackageInfo -> InstalledPackageInfo
removeMingwIncludeDir :: InstalledPackageInfo -> InstalledPackageInfo
removeMingwIncludeDir InstalledPackageInfo
pkg =
  let ids :: [String]
ids = InstalledPackageInfo -> [String]
InstalledPackageInfo.includeDirs InstalledPackageInfo
pkg
      ids' :: [String]
ids' = (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
"mingw" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isSuffixOf`)) [String]
ids
   in InstalledPackageInfo
pkg{InstalledPackageInfo.includeDirs = ids'}

-- | Get the packages from specific PackageDBs, not cumulative.
getInstalledPackages'
  :: Verbosity
  -> [PackageDB]
  -> ProgramDb
  -> IO [(PackageDB, [InstalledPackageInfo])]
getInstalledPackages' :: Verbosity
-> [PackageDB]
-> ProgramDb
-> IO [(PackageDB, [InstalledPackageInfo])]
getInstalledPackages' Verbosity
verbosity [PackageDB]
packagedbs ProgramDb
progdb =
  [IO (PackageDB, [InstalledPackageInfo])]
-> IO [(PackageDB, [InstalledPackageInfo])]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA
    [ do
      [InstalledPackageInfo]
pkgs <- HcPkgInfo -> Verbosity -> PackageDB -> IO [InstalledPackageInfo]
HcPkg.dump (ProgramDb -> HcPkgInfo
hcPkgInfo ProgramDb
progdb) Verbosity
verbosity PackageDB
packagedb
      (PackageDB, [InstalledPackageInfo])
-> IO (PackageDB, [InstalledPackageInfo])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (PackageDB
packagedb, [InstalledPackageInfo]
pkgs)
    | PackageDB
packagedb <- [PackageDB]
packagedbs
    ]

getInstalledPackagesMonitorFiles
  :: Verbosity
  -> Platform
  -> ProgramDb
  -> [PackageDB]
  -> IO [FilePath]
getInstalledPackagesMonitorFiles :: Verbosity -> Platform -> ProgramDb -> [PackageDB] -> IO [String]
getInstalledPackagesMonitorFiles Verbosity
verbosity Platform
platform ProgramDb
progdb =
  (PackageDB -> IO String) -> [PackageDB] -> IO [String]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> [a] -> f [b]
traverse PackageDB -> IO String
getPackageDBPath
  where
    getPackageDBPath :: PackageDB -> IO FilePath
    getPackageDBPath :: PackageDB -> IO String
getPackageDBPath PackageDB
GlobalPackageDB =
      String -> IO String
selectMonitorFile (String -> IO String) -> IO String -> IO String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Verbosity -> ConfiguredProgram -> IO String
getGlobalPackageDB Verbosity
verbosity ConfiguredProgram
ghcProg
    getPackageDBPath PackageDB
UserPackageDB =
      String -> IO String
selectMonitorFile (String -> IO String) -> IO String -> IO String
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Verbosity -> ConfiguredProgram -> Platform -> IO String
getUserPackageDB Verbosity
verbosity ConfiguredProgram
ghcProg Platform
platform
    getPackageDBPath (SpecificPackageDB String
path) = String -> IO String
selectMonitorFile String
path

    -- GHC has old style file dbs, and new style directory dbs.
    -- Note that for dir style dbs, we only need to monitor the cache file, not
    -- the whole directory. The ghc program itself only reads the cache file
    -- so it's safe to only monitor this one file.
    selectMonitorFile :: String -> IO String
selectMonitorFile String
path = do
      Bool
isFileStyle <- String -> IO Bool
doesFileExist String
path
      if Bool
isFileStyle
        then String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return String
path
        else String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String
path String -> String -> String
</> String
"package.cache")

    ghcProg :: ConfiguredProgram
ghcProg = ConfiguredProgram -> Maybe ConfiguredProgram -> ConfiguredProgram
forall a. a -> Maybe a -> a
fromMaybe (String -> ConfiguredProgram
forall a. HasCallStack => String -> a
error String
"GHC.toPackageIndex: no ghc program") (Maybe ConfiguredProgram -> ConfiguredProgram)
-> Maybe ConfiguredProgram -> ConfiguredProgram
forall a b. (a -> b) -> a -> b
$ Program -> ProgramDb -> Maybe ConfiguredProgram
lookupProgram Program
ghcProgram ProgramDb
progdb

-- -----------------------------------------------------------------------------
-- Building a library

buildLib
  :: Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> Library
  -> ComponentLocalBuildInfo
  -> IO ()
buildLib :: Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
buildLib = Maybe ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
buildOrReplLib Maybe ReplOptions
forall a. Maybe a
Nothing

replLib
  :: ReplOptions
  -> Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> Library
  -> ComponentLocalBuildInfo
  -> IO ()
replLib :: ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
replLib = Maybe ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
buildOrReplLib (Maybe ReplOptions
 -> Verbosity
 -> Flag (Maybe Int)
 -> PackageDescription
 -> LocalBuildInfo
 -> Library
 -> ComponentLocalBuildInfo
 -> IO ())
-> (ReplOptions -> Maybe ReplOptions)
-> ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReplOptions -> Maybe ReplOptions
forall a. a -> Maybe a
Just

buildOrReplLib
  :: Maybe ReplOptions
  -> Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> Library
  -> ComponentLocalBuildInfo
  -> IO ()
buildOrReplLib :: Maybe ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO ()
buildOrReplLib Maybe ReplOptions
mReplFlags Verbosity
verbosity Flag (Maybe Int)
numJobs PackageDescription
pkg_descr LocalBuildInfo
lbi Library
lib ComponentLocalBuildInfo
clbi = do
  let uid :: UnitId
uid = ComponentLocalBuildInfo -> UnitId
componentUnitId ComponentLocalBuildInfo
clbi
      libTargetDir :: String
libTargetDir = LocalBuildInfo -> ComponentLocalBuildInfo -> String
componentBuildDir LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi
      whenVanillaLib :: Bool -> f () -> f ()
whenVanillaLib Bool
forceVanilla =
        Bool -> f () -> f ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
forceVanilla Bool -> Bool -> Bool
|| LocalBuildInfo -> Bool
withVanillaLib LocalBuildInfo
lbi)
      whenProfLib :: IO () -> IO ()
whenProfLib = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LocalBuildInfo -> Bool
withProfLib LocalBuildInfo
lbi)
      whenSharedLib :: Bool -> f () -> f ()
whenSharedLib Bool
forceShared =
        Bool -> f () -> f ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
forceShared Bool -> Bool -> Bool
|| LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi)
      whenStaticLib :: Bool -> f () -> f ()
whenStaticLib Bool
forceStatic =
        Bool -> f () -> f ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
forceStatic Bool -> Bool -> Bool
|| LocalBuildInfo -> Bool
withStaticLib LocalBuildInfo
lbi)
      whenGHCiLib :: IO () -> IO ()
whenGHCiLib = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LocalBuildInfo -> Bool
withGHCiLib LocalBuildInfo
lbi)
      forRepl :: Bool
forRepl = Bool -> (ReplOptions -> Bool) -> Maybe ReplOptions -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (Bool -> ReplOptions -> Bool
forall a b. a -> b -> a
const Bool
True) Maybe ReplOptions
mReplFlags
      whenReplLib :: (ReplOptions -> IO b) -> IO ()
whenReplLib = Maybe ReplOptions -> (ReplOptions -> IO b) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ Maybe ReplOptions
mReplFlags
      replFlags :: ReplOptions
replFlags = ReplOptions -> Maybe ReplOptions -> ReplOptions
forall a. a -> Maybe a -> a
fromMaybe ReplOptions
forall a. Monoid a => a
mempty Maybe ReplOptions
mReplFlags
      comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi
      ghcVersion :: Version
ghcVersion = Compiler -> Version
compilerVersion Compiler
comp
      implInfo :: GhcImplInfo
implInfo = Compiler -> GhcImplInfo
getImplInfo Compiler
comp
      platform :: Platform
platform@(Platform Arch
hostArch OS
hostOS) = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
      hasJsSupport :: Bool
hasJsSupport = Arch
hostArch Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
== Arch
JavaScript
      has_code :: Bool
has_code = Bool -> Bool
not (ComponentLocalBuildInfo -> Bool
componentIsIndefinite ComponentLocalBuildInfo
clbi)

  String
relLibTargetDir <- String -> IO String
makeRelativeToCurrentDirectory String
libTargetDir

  (ConfiguredProgram
ghcProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ghcProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
  let runGhcProg :: GhcOptions -> IO ()
runGhcProg = Verbosity
-> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ()
runGHC Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform

  let libBi :: BuildInfo
libBi = Library -> BuildInfo
libBuildInfo Library
lib

  -- ensure extra lib dirs exist before passing to ghc
  [String]
cleanedExtraLibDirs <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesDirectoryExist (BuildInfo -> [String]
extraLibDirs BuildInfo
libBi)
  [String]
cleanedExtraLibDirsStatic <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesDirectoryExist (BuildInfo -> [String]
extraLibDirsStatic BuildInfo
libBi)

  let isGhcDynamic :: Bool
isGhcDynamic = Compiler -> Bool
isDynamic Compiler
comp
      dynamicTooSupported :: Bool
dynamicTooSupported = Compiler -> Bool
supportsDynamicToo Compiler
comp
      doingTH :: Bool
doingTH = BuildInfo -> Bool
usesTemplateHaskellOrQQ BuildInfo
libBi
      forceVanillaLib :: Bool
forceVanillaLib = Bool
doingTH Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
isGhcDynamic
      forceSharedLib :: Bool
forceSharedLib = Bool
doingTH Bool -> Bool -> Bool
&& Bool
isGhcDynamic
  -- TH always needs default libs, even when building for profiling

  -- Determine if program coverage should be enabled and if so, what
  -- '-hpcdir' should be.
  let isCoverageEnabled :: Bool
isCoverageEnabled = LocalBuildInfo -> Bool
libCoverage LocalBuildInfo
lbi
      -- TODO: Historically HPC files have been put into a directory which
      -- has the package name.  I'm going to avoid changing this for
      -- now, but it would probably be better for this to be the
      -- component ID instead...
      pkg_name :: String
pkg_name = PackageId -> String
forall a. Pretty a => a -> String
prettyShow (PackageDescription -> PackageId
PD.package PackageDescription
pkg_descr)
      distPref :: String
distPref = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag String -> String) -> Flag String -> String
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag String
configDistPref (ConfigFlags -> Flag String) -> ConfigFlags -> Flag String
forall a b. (a -> b) -> a -> b
$ LocalBuildInfo -> ConfigFlags
configFlags LocalBuildInfo
lbi
      hpcdir :: Way -> Flag String
hpcdir Way
way
        | Bool
forRepl = Flag String
forall a. Monoid a => a
mempty -- HPC is not supported in ghci
        | Bool
isCoverageEnabled = String -> Flag String
forall a. a -> Flag a
toFlag (String -> Flag String) -> String -> Flag String
forall a b. (a -> b) -> a -> b
$ String -> Way -> String -> String
Hpc.mixDir String
distPref Way
way String
pkg_name
        | Bool
otherwise = Flag String
forall a. Monoid a => a
mempty

  Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
libTargetDir
  -- TODO: do we need to put hs-boot files into place for mutually recursive
  -- modules?
  let cLikeSources :: [String]
cLikeSources =
        NubListR String -> [String]
forall a. NubListR a -> [a]
fromNubListR (NubListR String -> [String]) -> NubListR String -> [String]
forall a b. (a -> b) -> a -> b
$
          [NubListR String] -> NubListR String
forall a. Monoid a => [a] -> a
mconcat
            [ [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR (BuildInfo -> [String]
cSources BuildInfo
libBi)
            , [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR (BuildInfo -> [String]
cxxSources BuildInfo
libBi)
            , [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR (BuildInfo -> [String]
cmmSources BuildInfo
libBi)
            , [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR (BuildInfo -> [String]
asmSources BuildInfo
libBi)
            , if Bool
hasJsSupport
                then -- JS files are C-like with GHC's JS backend: they are
                -- "compiled" into `.o` files (renamed with a header).
                -- This is a difference from GHCJS, for which we only
                -- pass the JS files at link time.
                  [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR (BuildInfo -> [String]
jsSources BuildInfo
libBi)
                else NubListR String
forall a. Monoid a => a
mempty
            ]
      cLikeObjs :: [String]
cLikeObjs = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
`replaceExtension` String
objExtension) [String]
cLikeSources
      baseOpts :: GhcOptions
baseOpts = Verbosity
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> GhcOptions
componentGhcOptions Verbosity
verbosity LocalBuildInfo
lbi BuildInfo
libBi ComponentLocalBuildInfo
clbi String
libTargetDir
      vanillaOpts :: GhcOptions
vanillaOpts =
        GhcOptions
baseOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptMode = toFlag GhcModeMake
            , ghcOptNumJobs = numJobs
            , ghcOptInputModules = toNubListR $ allLibModules lib clbi
            , ghcOptHPCDir = hpcdir Hpc.Vanilla
            }

      profOpts :: GhcOptions
profOpts =
        GhcOptions
vanillaOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptProfilingMode = toFlag True
            , ghcOptProfilingAuto =
                Internal.profDetailLevelFlag
                  True
                  (withProfLibDetail lbi)
            , ghcOptHiSuffix = toFlag "p_hi"
            , ghcOptObjSuffix = toFlag "p_o"
            , ghcOptExtra = hcProfOptions GHC libBi
            , ghcOptHPCDir = hpcdir Hpc.Prof
            }

      sharedOpts :: GhcOptions
sharedOpts =
        GhcOptions
vanillaOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptDynLinkMode = toFlag GhcDynamicOnly
            , ghcOptFPic = toFlag True
            , ghcOptHiSuffix = toFlag "dyn_hi"
            , ghcOptObjSuffix = toFlag "dyn_o"
            , ghcOptExtra = hcSharedOptions GHC libBi
            , ghcOptHPCDir = hpcdir Hpc.Dyn
            }
      linkerOpts :: GhcOptions
linkerOpts =
        GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptLinkOptions =
              PD.ldOptions libBi
                ++ [ "-static"
                   | withFullyStaticExe lbi
                   ]
                -- Pass extra `ld-options` given
                -- through to GHC's linker.
                ++ maybe
                  []
                  programOverrideArgs
                  (lookupProgram ldProgram (withPrograms lbi))
          , ghcOptLinkLibs =
              if withFullyStaticExe lbi
                then extraLibsStatic libBi
                else extraLibs libBi
          , ghcOptLinkLibPath =
              toNubListR $
                if withFullyStaticExe lbi
                  then cleanedExtraLibDirsStatic
                  else cleanedExtraLibDirs
          , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi
          , ghcOptLinkFrameworkDirs =
              toNubListR $
                PD.extraFrameworkDirs libBi
          , ghcOptInputFiles =
              toNubListR
                [relLibTargetDir </> x | x <- cLikeObjs]
          }
      replOpts :: GhcOptions
replOpts =
        GhcOptions
vanillaOpts
          { ghcOptExtra =
              Internal.filterGhciFlags
                (ghcOptExtra vanillaOpts)
                <> replOptionsFlags replFlags
          , ghcOptNumJobs = mempty
          , ghcOptInputModules = replNoLoad replFlags (ghcOptInputModules vanillaOpts)
          }
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
linkerOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptMode = isInteractive
            , ghcOptOptimisation = toFlag GhcNoOptimisation
            }

      isInteractive :: Flag GhcMode
isInteractive = GhcMode -> Flag GhcMode
forall a. a -> Flag a
toFlag GhcMode
GhcModeInteractive

      vanillaSharedOpts :: GhcOptions
vanillaSharedOpts =
        GhcOptions
vanillaOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic
            , ghcOptDynHiSuffix = toFlag "dyn_hi"
            , ghcOptDynObjSuffix = toFlag "dyn_o"
            , ghcOptHPCDir = hpcdir Hpc.Dyn
            }

  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool
forRepl Bool -> Bool -> Bool
|| [ModuleName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    do
      let vanilla :: IO ()
vanilla = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenVanillaLib Bool
forceVanillaLib (GhcOptions -> IO ()
runGhcProg GhcOptions
vanillaOpts)
          shared :: IO ()
shared = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
forceSharedLib (GhcOptions -> IO ()
runGhcProg GhcOptions
sharedOpts)
          useDynToo :: Bool
useDynToo =
            Bool
dynamicTooSupported
              Bool -> Bool -> Bool
&& (Bool
forceVanillaLib Bool -> Bool -> Bool
|| LocalBuildInfo -> Bool
withVanillaLib LocalBuildInfo
lbi)
              Bool -> Bool -> Bool
&& (Bool
forceSharedLib Bool -> Bool -> Bool
|| LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi)
              Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (CompilerFlavor -> BuildInfo -> [String]
hcSharedOptions CompilerFlavor
GHC BuildInfo
libBi)
      if Bool -> Bool
not Bool
has_code
        then IO ()
vanilla
        else
          if Bool
useDynToo
            then do
              GhcOptions -> IO ()
runGhcProg GhcOptions
vanillaSharedOpts
              case (Way -> Flag String
hpcdir Way
Hpc.Dyn, Way -> Flag String
hpcdir Way
Hpc.Vanilla) of
                (Flag String
dynDir, Flag String
vanillaDir) ->
                  -- When the vanilla and shared library builds are done
                  -- in one pass, only one set of HPC module interfaces
                  -- are generated. This set should suffice for both
                  -- static and dynamically linked executables. We copy
                  -- the modules interfaces so they are available under
                  -- both ways.
                  Verbosity -> String -> String -> IO ()
copyDirectoryRecursive Verbosity
verbosity String
dynDir String
vanillaDir
                (Flag String, Flag String)
_ -> () -> IO ()
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ()
            else
              if Bool
isGhcDynamic
                then do IO ()
shared; IO ()
vanilla
                else do IO ()
vanilla; IO ()
shared
      IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProg GhcOptions
profOpts)

  -- Build any C++ sources separately.
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
not Bool
has_code Bool -> Bool -> Bool
|| [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cxxSources BuildInfo
libBi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building C++ Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseCxxOpts :: GhcOptions
baseCxxOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCxxGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
libBi
                ComponentLocalBuildInfo
clbi
                String
relLibTargetDir
                String
filename
            vanillaCxxOpts :: GhcOptions
vanillaCxxOpts =
              if Bool
isGhcDynamic
                then GhcOptions
baseCxxOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseCxxOpts
            profCxxOpts :: GhcOptions
profCxxOpts =
              GhcOptions
vanillaCxxOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  , ghcOptObjSuffix = toFlag "p_o"
                  }
            sharedCxxOpts :: GhcOptions
sharedCxxOpts =
              GhcOptions
vanillaCxxOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  , ghcOptObjSuffix = toFlag "dyn_o"
                  }
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
vanillaCxxOpts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        let runGhcProgIfNeeded :: GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
cxxOpts = do
              Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
cxxOpts
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg GhcOptions
cxxOpts
        GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
vanillaCxxOpts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
forceSharedLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
sharedCxxOpts)
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
profCxxOpts)
      | String
filename <- BuildInfo -> [String]
cxxSources BuildInfo
libBi
      ]

  -- build any C sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
not Bool
has_code Bool -> Bool -> Bool
|| [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cSources BuildInfo
libBi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building C Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseCcOpts :: GhcOptions
baseCcOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCcGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
libBi
                ComponentLocalBuildInfo
clbi
                String
relLibTargetDir
                String
filename
            vanillaCcOpts :: GhcOptions
vanillaCcOpts =
              if Bool
isGhcDynamic
                then -- Dynamic GHC requires C sources to be built
                -- with -fPIC for REPL to work. See #2207.
                  GhcOptions
baseCcOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseCcOpts
            profCcOpts :: GhcOptions
profCcOpts =
              GhcOptions
vanillaCcOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  , ghcOptObjSuffix = toFlag "p_o"
                  }
            sharedCcOpts :: GhcOptions
sharedCcOpts =
              GhcOptions
vanillaCcOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  , ghcOptObjSuffix = toFlag "dyn_o"
                  }
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
vanillaCcOpts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        let runGhcProgIfNeeded :: GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
ccOpts = do
              Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
ccOpts
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg GhcOptions
ccOpts
        GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
vanillaCcOpts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
forceSharedLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
sharedCcOpts)
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
profCcOpts)
      | String
filename <- BuildInfo -> [String]
cSources BuildInfo
libBi
      ]

  -- build any JS sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
not Bool
has_code Bool -> Bool -> Bool
|| Bool -> Bool
not Bool
hasJsSupport Bool -> Bool -> Bool
|| [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
jsSources BuildInfo
libBi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building JS Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let vanillaJsOpts :: GhcOptions
vanillaJsOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentJsGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
libBi
                ComponentLocalBuildInfo
clbi
                String
relLibTargetDir
                String
filename
            profJsOpts :: GhcOptions
profJsOpts =
              GhcOptions
vanillaJsOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  , ghcOptObjSuffix = toFlag "p_o"
                  }
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
vanillaJsOpts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        let runGhcProgIfNeeded :: GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
jsOpts = do
              Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
jsOpts
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg GhcOptions
jsOpts
        GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
vanillaJsOpts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
profJsOpts)
      | String
filename <- BuildInfo -> [String]
jsSources BuildInfo
libBi
      ]

  -- build any ASM sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
not Bool
has_code Bool -> Bool -> Bool
|| [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
asmSources BuildInfo
libBi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building Assembler Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseAsmOpts :: GhcOptions
baseAsmOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentAsmGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
libBi
                ComponentLocalBuildInfo
clbi
                String
relLibTargetDir
                String
filename
            vanillaAsmOpts :: GhcOptions
vanillaAsmOpts =
              if Bool
isGhcDynamic
                then -- Dynamic GHC requires objects to be built
                -- with -fPIC for REPL to work. See #2207.
                  GhcOptions
baseAsmOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseAsmOpts
            profAsmOpts :: GhcOptions
profAsmOpts =
              GhcOptions
vanillaAsmOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  , ghcOptObjSuffix = toFlag "p_o"
                  }
            sharedAsmOpts :: GhcOptions
sharedAsmOpts =
              GhcOptions
vanillaAsmOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  , ghcOptObjSuffix = toFlag "dyn_o"
                  }
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
vanillaAsmOpts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        let runGhcProgIfNeeded :: GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
asmOpts = do
              Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
asmOpts
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg GhcOptions
asmOpts
        GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
vanillaAsmOpts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
forceSharedLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
sharedAsmOpts)
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
profAsmOpts)
      | String
filename <- BuildInfo -> [String]
asmSources BuildInfo
libBi
      ]

  -- build any Cmm sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless (Bool -> Bool
not Bool
has_code Bool -> Bool -> Bool
|| [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cmmSources BuildInfo
libBi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building C-- Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseCmmOpts :: GhcOptions
baseCmmOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCmmGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
libBi
                ComponentLocalBuildInfo
clbi
                String
relLibTargetDir
                String
filename
            vanillaCmmOpts :: GhcOptions
vanillaCmmOpts =
              if Bool
isGhcDynamic
                then -- Dynamic GHC requires C sources to be built
                -- with -fPIC for REPL to work. See #2207.
                  GhcOptions
baseCmmOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseCmmOpts
            profCmmOpts :: GhcOptions
profCmmOpts =
              GhcOptions
vanillaCmmOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  , ghcOptObjSuffix = toFlag "p_o"
                  }
            sharedCmmOpts :: GhcOptions
sharedCmmOpts =
              GhcOptions
vanillaCmmOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  , ghcOptObjSuffix = toFlag "dyn_o"
                  }
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
vanillaCmmOpts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        let runGhcProgIfNeeded :: GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
cmmOpts = do
              Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
cmmOpts
              Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg GhcOptions
cmmOpts
        GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
vanillaCmmOpts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
forceSharedLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
sharedCmmOpts)
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO () -> IO ()
whenProfLib (GhcOptions -> IO ()
runGhcProgIfNeeded GhcOptions
profCmmOpts)
      | String
filename <- BuildInfo -> [String]
cmmSources BuildInfo
libBi
      ]

  -- TODO: problem here is we need the .c files built first, so we can load them
  -- with ghci, but .c files can depend on .h files generated by ghc by ffi
  -- exports.
  (ReplOptions -> IO ()) -> IO ()
forall {b}. (ReplOptions -> IO b) -> IO ()
whenReplLib ((ReplOptions -> IO ()) -> IO ())
-> (ReplOptions -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \ReplOptions
rflags -> do
    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when ([ModuleName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> IO ()
warn Verbosity
verbosity String
"No exposed modules"
    Verbosity
-> ConfiguredProgram
-> Compiler
-> Platform
-> ReplOptions
-> GhcOptions
-> BuildInfo
-> ComponentLocalBuildInfo
-> PackageName
-> IO ()
runReplOrWriteFlags Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform ReplOptions
rflags GhcOptions
replOpts BuildInfo
libBi ComponentLocalBuildInfo
clbi (PackageId -> PackageName
pkgName (PackageDescription -> PackageId
PD.package PackageDescription
pkg_descr))

  -- link:
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
has_code (IO () -> IO ()) -> (IO () -> IO ()) -> IO () -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
forRepl (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Linking..."
    let cLikeProfObjs :: [String]
cLikeProfObjs =
          (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map
            (String -> String -> String
`replaceExtension` (String
"p_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension))
            [String]
cLikeSources
        cLikeSharedObjs :: [String]
cLikeSharedObjs =
          (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map
            (String -> String -> String
`replaceExtension` (String
"dyn_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension))
            [String]
cLikeSources
        compiler_id :: CompilerId
compiler_id = Compiler -> CompilerId
compilerId (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi)
        vanillaLibFilePath :: String
vanillaLibFilePath = String
relLibTargetDir String -> String -> String
</> UnitId -> String
mkLibName UnitId
uid
        profileLibFilePath :: String
profileLibFilePath = String
relLibTargetDir String -> String -> String
</> UnitId -> String
mkProfLibName UnitId
uid
        sharedLibFilePath :: String
sharedLibFilePath =
          String
relLibTargetDir
            String -> String -> String
</> Platform -> CompilerId -> UnitId -> String
mkSharedLibName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) CompilerId
compiler_id UnitId
uid
        staticLibFilePath :: String
staticLibFilePath =
          String
relLibTargetDir
            String -> String -> String
</> Platform -> CompilerId -> UnitId -> String
mkStaticLibName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) CompilerId
compiler_id UnitId
uid
        ghciLibFilePath :: String
ghciLibFilePath = String
relLibTargetDir String -> String -> String
</> UnitId -> String
Internal.mkGHCiLibName UnitId
uid
        ghciProfLibFilePath :: String
ghciProfLibFilePath = String
relLibTargetDir String -> String -> String
</> UnitId -> String
Internal.mkGHCiProfLibName UnitId
uid
        libInstallPath :: String
libInstallPath =
          InstallDirs String -> String
forall dir. InstallDirs dir -> dir
libdir (InstallDirs String -> String) -> InstallDirs String -> String
forall a b. (a -> b) -> a -> b
$
            PackageDescription
-> LocalBuildInfo -> UnitId -> CopyDest -> InstallDirs String
absoluteComponentInstallDirs
              PackageDescription
pkg_descr
              LocalBuildInfo
lbi
              UnitId
uid
              CopyDest
NoCopyDest
        sharedLibInstallPath :: String
sharedLibInstallPath =
          String
libInstallPath
            String -> String -> String
</> Platform -> CompilerId -> UnitId -> String
mkSharedLibName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) CompilerId
compiler_id UnitId
uid

    [String]
stubObjs <-
      [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes
        ([Maybe String] -> [String]) -> IO [Maybe String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [IO (Maybe String)] -> IO [Maybe String]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA
          [ [String] -> [String] -> String -> IO (Maybe String)
findFileWithExtension
            [String
objExtension]
            [String
libTargetDir]
            (ModuleName -> String
ModuleName.toFilePath ModuleName
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_stub")
          | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
2] -- ghc-7.2+ does not make _stub.o files
          , ModuleName
x <- Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi
          ]
    [String]
stubProfObjs <-
      [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes
        ([Maybe String] -> [String]) -> IO [Maybe String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [IO (Maybe String)] -> IO [Maybe String]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA
          [ [String] -> [String] -> String -> IO (Maybe String)
findFileWithExtension
            [String
"p_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension]
            [String
libTargetDir]
            (ModuleName -> String
ModuleName.toFilePath ModuleName
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_stub")
          | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
2] -- ghc-7.2+ does not make _stub.o files
          , ModuleName
x <- Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi
          ]
    [String]
stubSharedObjs <-
      [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes
        ([Maybe String] -> [String]) -> IO [Maybe String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [IO (Maybe String)] -> IO [Maybe String]
forall (t :: * -> *) (f :: * -> *) a.
(Traversable t, Applicative f) =>
t (f a) -> f (t a)
forall (f :: * -> *) a. Applicative f => [f a] -> f [a]
sequenceA
          [ [String] -> [String] -> String -> IO (Maybe String)
findFileWithExtension
            [String
"dyn_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension]
            [String
libTargetDir]
            (ModuleName -> String
ModuleName.toFilePath ModuleName
x String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"_stub")
          | Version
ghcVersion Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
2] -- ghc-7.2+ does not make _stub.o files
          , ModuleName
x <- Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi
          ]

    [String]
hObjs <-
      GhcImplInfo
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> Bool
-> IO [String]
Internal.getHaskellObjects
        GhcImplInfo
implInfo
        Library
lib
        LocalBuildInfo
lbi
        ComponentLocalBuildInfo
clbi
        String
relLibTargetDir
        String
objExtension
        Bool
True
    [String]
hProfObjs <-
      if LocalBuildInfo -> Bool
withProfLib LocalBuildInfo
lbi
        then
          GhcImplInfo
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> Bool
-> IO [String]
Internal.getHaskellObjects
            GhcImplInfo
implInfo
            Library
lib
            LocalBuildInfo
lbi
            ComponentLocalBuildInfo
clbi
            String
relLibTargetDir
            (String
"p_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension)
            Bool
True
        else [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []
    [String]
hSharedObjs <-
      if LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi
        then
          GhcImplInfo
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> Bool
-> IO [String]
Internal.getHaskellObjects
            GhcImplInfo
implInfo
            Library
lib
            LocalBuildInfo
lbi
            ComponentLocalBuildInfo
clbi
            String
relLibTargetDir
            (String
"dyn_" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
objExtension)
            Bool
False
        else [String] -> IO [String]
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return []

    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
hObjs Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
cLikeObjs Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
stubObjs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      NubListR String
rpaths <- LocalBuildInfo -> ComponentLocalBuildInfo -> IO (NubListR String)
getRPaths LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi

      let staticObjectFiles :: [String]
staticObjectFiles =
            [String]
hObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
relLibTargetDir String -> String -> String
</>) [String]
cLikeObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
stubObjs
          profObjectFiles :: [String]
profObjectFiles =
            [String]
hProfObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
relLibTargetDir String -> String -> String
</>) [String]
cLikeProfObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
stubProfObjs
          dynamicObjectFiles :: [String]
dynamicObjectFiles =
            [String]
hSharedObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String
relLibTargetDir String -> String -> String
</>) [String]
cLikeSharedObjs
              [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
stubSharedObjs
          -- After the relocation lib is created we invoke ghc -shared
          -- with the dependencies spelled out as -package arguments
          -- and ghc invokes the linker with the proper library paths
          ghcSharedLinkArgs :: GhcOptions
ghcSharedLinkArgs =
            GhcOptions
forall a. Monoid a => a
mempty
              { ghcOptShared = toFlag True
              , ghcOptDynLinkMode = toFlag GhcDynamicOnly
              , ghcOptInputFiles = toNubListR dynamicObjectFiles
              , ghcOptOutputFile = toFlag sharedLibFilePath
              , ghcOptExtra = hcSharedOptions GHC libBi
              , -- For dynamic libs, Mac OS/X needs to know the install location
                -- at build time. This only applies to GHC < 7.8 - see the
                -- discussion in #1660.
                ghcOptDylibName =
                  if hostOS == OSX
                    && ghcVersion < mkVersion [7, 8]
                    then toFlag sharedLibInstallPath
                    else mempty
              , ghcOptHideAllPackages = toFlag True
              , ghcOptNoAutoLinkPackages = toFlag True
              , ghcOptPackageDBs = withPackageDB lbi
              , ghcOptThisUnitId = case clbi of
                  LibComponentLocalBuildInfo{componentCompatPackageKey :: ComponentLocalBuildInfo -> String
componentCompatPackageKey = String
pk} ->
                    String -> Flag String
forall a. a -> Flag a
toFlag String
pk
                  ComponentLocalBuildInfo
_ -> Flag String
forall a. Monoid a => a
mempty
              , ghcOptThisComponentId = case clbi of
                  LibComponentLocalBuildInfo
                    { componentInstantiatedWith :: ComponentLocalBuildInfo -> [(ModuleName, OpenModule)]
componentInstantiatedWith = [(ModuleName, OpenModule)]
insts
                    } ->
                      if [(ModuleName, OpenModule)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(ModuleName, OpenModule)]
insts
                        then Flag ComponentId
forall a. Monoid a => a
mempty
                        else ComponentId -> Flag ComponentId
forall a. a -> Flag a
toFlag (ComponentLocalBuildInfo -> ComponentId
componentComponentId ComponentLocalBuildInfo
clbi)
                  ComponentLocalBuildInfo
_ -> Flag ComponentId
forall a. Monoid a => a
mempty
              , ghcOptInstantiatedWith = case clbi of
                  LibComponentLocalBuildInfo
                    { componentInstantiatedWith :: ComponentLocalBuildInfo -> [(ModuleName, OpenModule)]
componentInstantiatedWith = [(ModuleName, OpenModule)]
insts
                    } ->
                      [(ModuleName, OpenModule)]
insts
                  ComponentLocalBuildInfo
_ -> []
              , ghcOptPackages =
                  toNubListR $
                    Internal.mkGhcOptPackages mempty clbi
              , ghcOptLinkLibs = extraLibs libBi
              , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs
              , ghcOptLinkFrameworks = toNubListR $ PD.frameworks libBi
              , ghcOptLinkFrameworkDirs =
                  toNubListR $ PD.extraFrameworkDirs libBi
              , ghcOptRPaths = rpaths
              }
          ghcStaticLinkArgs :: GhcOptions
ghcStaticLinkArgs =
            GhcOptions
forall a. Monoid a => a
mempty
              { ghcOptStaticLib = toFlag True
              , ghcOptInputFiles = toNubListR staticObjectFiles
              , ghcOptOutputFile = toFlag staticLibFilePath
              , ghcOptExtra = hcStaticOptions GHC libBi
              , ghcOptHideAllPackages = toFlag True
              , ghcOptNoAutoLinkPackages = toFlag True
              , ghcOptPackageDBs = withPackageDB lbi
              , ghcOptThisUnitId = case clbi of
                  LibComponentLocalBuildInfo{componentCompatPackageKey :: ComponentLocalBuildInfo -> String
componentCompatPackageKey = String
pk} ->
                    String -> Flag String
forall a. a -> Flag a
toFlag String
pk
                  ComponentLocalBuildInfo
_ -> Flag String
forall a. Monoid a => a
mempty
              , ghcOptThisComponentId = case clbi of
                  LibComponentLocalBuildInfo
                    { componentInstantiatedWith :: ComponentLocalBuildInfo -> [(ModuleName, OpenModule)]
componentInstantiatedWith = [(ModuleName, OpenModule)]
insts
                    } ->
                      if [(ModuleName, OpenModule)] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(ModuleName, OpenModule)]
insts
                        then Flag ComponentId
forall a. Monoid a => a
mempty
                        else ComponentId -> Flag ComponentId
forall a. a -> Flag a
toFlag (ComponentLocalBuildInfo -> ComponentId
componentComponentId ComponentLocalBuildInfo
clbi)
                  ComponentLocalBuildInfo
_ -> Flag ComponentId
forall a. Monoid a => a
mempty
              , ghcOptInstantiatedWith = case clbi of
                  LibComponentLocalBuildInfo
                    { componentInstantiatedWith :: ComponentLocalBuildInfo -> [(ModuleName, OpenModule)]
componentInstantiatedWith = [(ModuleName, OpenModule)]
insts
                    } ->
                      [(ModuleName, OpenModule)]
insts
                  ComponentLocalBuildInfo
_ -> []
              , ghcOptPackages =
                  toNubListR $
                    Internal.mkGhcOptPackages mempty clbi
              , ghcOptLinkLibs = extraLibs libBi
              , ghcOptLinkLibPath = toNubListR $ cleanedExtraLibDirs
              }

      Verbosity -> String -> IO ()
info Verbosity
verbosity (NubListR (OpenUnitId, ModuleRenaming) -> String
forall a. Show a => a -> String
show (GhcOptions -> NubListR (OpenUnitId, ModuleRenaming)
ghcOptPackages GhcOptions
ghcSharedLinkArgs))

      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenVanillaLib Bool
False (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        Verbosity -> LocalBuildInfo -> String -> [String] -> IO ()
Ar.createArLibArchive Verbosity
verbosity LocalBuildInfo
lbi String
vanillaLibFilePath [String]
staticObjectFiles
        IO () -> IO ()
whenGHCiLib (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
          (ConfiguredProgram
ldProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ldProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
          Verbosity
-> LocalBuildInfo
-> ConfiguredProgram
-> String
-> [String]
-> IO ()
Ld.combineObjectFiles
            Verbosity
verbosity
            LocalBuildInfo
lbi
            ConfiguredProgram
ldProg
            String
ghciLibFilePath
            [String]
staticObjectFiles

      IO () -> IO ()
whenProfLib (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        Verbosity -> LocalBuildInfo -> String -> [String] -> IO ()
Ar.createArLibArchive Verbosity
verbosity LocalBuildInfo
lbi String
profileLibFilePath [String]
profObjectFiles
        IO () -> IO ()
whenGHCiLib (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
          (ConfiguredProgram
ldProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ldProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
          Verbosity
-> LocalBuildInfo
-> ConfiguredProgram
-> String
-> [String]
-> IO ()
Ld.combineObjectFiles
            Verbosity
verbosity
            LocalBuildInfo
lbi
            ConfiguredProgram
ldProg
            String
ghciProfLibFilePath
            [String]
profObjectFiles

      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenSharedLib Bool
False (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        GhcOptions -> IO ()
runGhcProg GhcOptions
ghcSharedLinkArgs

      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
whenStaticLib Bool
False (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        GhcOptions -> IO ()
runGhcProg GhcOptions
ghcStaticLinkArgs

-- | Start a REPL without loading any source files.
startInterpreter
  :: Verbosity
  -> ProgramDb
  -> Compiler
  -> Platform
  -> PackageDBStack
  -> IO ()
startInterpreter :: Verbosity
-> ProgramDb -> Compiler -> Platform -> [PackageDB] -> IO ()
startInterpreter Verbosity
verbosity ProgramDb
progdb Compiler
comp Platform
platform [PackageDB]
packageDBs = do
  let replOpts :: GhcOptions
replOpts =
        GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptMode = toFlag GhcModeInteractive
          , ghcOptPackageDBs = packageDBs
          }
  Verbosity -> Compiler -> [PackageDB] -> IO ()
checkPackageDbStack Verbosity
verbosity Compiler
comp [PackageDB]
packageDBs
  (ConfiguredProgram
ghcProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ghcProgram ProgramDb
progdb
  Verbosity
-> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ()
runGHC Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform GhcOptions
replOpts

runReplOrWriteFlags
  :: Verbosity
  -> ConfiguredProgram
  -> Compiler
  -> Platform
  -> ReplOptions
  -> GhcOptions
  -> BuildInfo
  -> ComponentLocalBuildInfo
  -> PackageName
  -> IO ()
runReplOrWriteFlags :: Verbosity
-> ConfiguredProgram
-> Compiler
-> Platform
-> ReplOptions
-> GhcOptions
-> BuildInfo
-> ComponentLocalBuildInfo
-> PackageName
-> IO ()
runReplOrWriteFlags Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform ReplOptions
rflags GhcOptions
replOpts BuildInfo
bi ComponentLocalBuildInfo
clbi PackageName
pkg_name =
  case ReplOptions -> Flag String
replOptionsFlagOutput ReplOptions
rflags of
    Flag String
NoFlag -> Verbosity
-> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ()
runGHC Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform GhcOptions
replOpts
    Flag String
out_dir -> do
      String
src_dir <- IO String
getCurrentDirectory
      let uid :: UnitId
uid = ComponentLocalBuildInfo -> UnitId
componentUnitId ComponentLocalBuildInfo
clbi
          this_unit :: String
this_unit = UnitId -> String
forall a. Pretty a => a -> String
prettyShow UnitId
uid
          reexported_modules :: [ModuleName]
reexported_modules = [ModuleName
mn | LibComponentLocalBuildInfo{} <- [ComponentLocalBuildInfo
clbi], IPI.ExposedModule ModuleName
mn (Just{}) <- ComponentLocalBuildInfo -> [ExposedModule]
componentExposedModules ComponentLocalBuildInfo
clbi]
          hidden_modules :: [ModuleName]
hidden_modules = BuildInfo -> [ModuleName]
otherModules BuildInfo
bi
          extra_opts :: [String]
extra_opts =
            [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat ([[String]] -> [String]) -> [[String]] -> [String]
forall a b. (a -> b) -> a -> b
$
              [ [String
"-this-package-name", PackageName -> String
forall a. Pretty a => a -> String
prettyShow PackageName
pkg_name]
              , [String
"-working-dir", String
src_dir]
              ]
                [[String]] -> [[String]] -> [[String]]
forall a. [a] -> [a] -> [a]
++ [ [String
"-reexported-module", ModuleName -> String
forall a. Pretty a => a -> String
prettyShow ModuleName
m] | ModuleName
m <- [ModuleName]
reexported_modules
                   ]
                [[String]] -> [[String]] -> [[String]]
forall a. [a] -> [a] -> [a]
++ [ [String
"-hidden-module", ModuleName -> String
forall a. Pretty a => a -> String
prettyShow ModuleName
m] | ModuleName
m <- [ModuleName]
hidden_modules
                   ]
      -- Create "paths" subdirectory if it doesn't exist. This is where we write
      -- information about how the PATH was augmented.
      Bool -> String -> IO ()
createDirectoryIfMissing Bool
False (String
out_dir String -> String -> String
</> String
"paths")
      -- Write out the PATH information into `paths` subdirectory.
      String -> ByteString -> IO ()
writeFileAtomic (String
out_dir String -> String -> String
</> String
"paths" String -> String -> String
</> String
this_unit) (ConfiguredProgram -> ByteString
forall a. Binary a => a -> ByteString
encode ConfiguredProgram
ghcProg)
      -- Write out options for this component into a file ready for loading into
      -- the multi-repl
      String -> ByteString -> IO ()
writeFileAtomic (String
out_dir String -> String -> String
</> String
this_unit) (ByteString -> IO ()) -> ByteString -> IO ()
forall a b. (a -> b) -> a -> b
$
        String -> ByteString
BS.pack (String -> ByteString) -> String -> ByteString
forall a b. (a -> b) -> a -> b
$
          [String] -> String
escapeArgs ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$
            [String]
extra_opts [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ Compiler -> Platform -> GhcOptions -> [String]
renderGhcOptions Compiler
comp Platform
platform (GhcOptions
replOpts{ghcOptMode = NoFlag})

-- -----------------------------------------------------------------------------
-- Building an executable or foreign library

-- | Build a foreign library
buildFLib
  :: Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> ForeignLib
  -> ComponentLocalBuildInfo
  -> IO ()
buildFLib :: Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> ForeignLib
-> ComponentLocalBuildInfo
-> IO ()
buildFLib Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi = Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> GBuildMode
-> ComponentLocalBuildInfo
-> IO ()
gbuild Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi (GBuildMode -> ComponentLocalBuildInfo -> IO ())
-> (ForeignLib -> GBuildMode)
-> ForeignLib
-> ComponentLocalBuildInfo
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForeignLib -> GBuildMode
GBuildFLib

replFLib
  :: ReplOptions
  -> Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> ForeignLib
  -> ComponentLocalBuildInfo
  -> IO ()
replFLib :: ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> ForeignLib
-> ComponentLocalBuildInfo
-> IO ()
replFLib ReplOptions
replFlags Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi =
  Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> GBuildMode
-> ComponentLocalBuildInfo
-> IO ()
gbuild Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi (GBuildMode -> ComponentLocalBuildInfo -> IO ())
-> (ForeignLib -> GBuildMode)
-> ForeignLib
-> ComponentLocalBuildInfo
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReplOptions -> ForeignLib -> GBuildMode
GReplFLib ReplOptions
replFlags

-- | Build an executable with GHC.
buildExe
  :: Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> Executable
  -> ComponentLocalBuildInfo
  -> IO ()
buildExe :: Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Executable
-> ComponentLocalBuildInfo
-> IO ()
buildExe Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi = Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> GBuildMode
-> ComponentLocalBuildInfo
-> IO ()
gbuild Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi (GBuildMode -> ComponentLocalBuildInfo -> IO ())
-> (Executable -> GBuildMode)
-> Executable
-> ComponentLocalBuildInfo
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Executable -> GBuildMode
GBuildExe

replExe
  :: ReplOptions
  -> Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> Executable
  -> ComponentLocalBuildInfo
  -> IO ()
replExe :: ReplOptions
-> Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> Executable
-> ComponentLocalBuildInfo
-> IO ()
replExe ReplOptions
replFlags Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi =
  Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> GBuildMode
-> ComponentLocalBuildInfo
-> IO ()
gbuild Verbosity
v Flag (Maybe Int)
njobs PackageDescription
pkg LocalBuildInfo
lbi (GBuildMode -> ComponentLocalBuildInfo -> IO ())
-> (Executable -> GBuildMode)
-> Executable
-> ComponentLocalBuildInfo
-> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReplOptions -> Executable -> GBuildMode
GReplExe ReplOptions
replFlags

-- | Building an executable, starting the REPL, and building foreign
-- libraries are all very similar and implemented in 'gbuild'. The
-- 'GBuildMode' distinguishes between the various kinds of operation.
data GBuildMode
  = GBuildExe Executable
  | GReplExe ReplOptions Executable
  | GBuildFLib ForeignLib
  | GReplFLib ReplOptions ForeignLib

gbuildInfo :: GBuildMode -> BuildInfo
gbuildInfo :: GBuildMode -> BuildInfo
gbuildInfo (GBuildExe Executable
exe) = Executable -> BuildInfo
buildInfo Executable
exe
gbuildInfo (GReplExe ReplOptions
_ Executable
exe) = Executable -> BuildInfo
buildInfo Executable
exe
gbuildInfo (GBuildFLib ForeignLib
flib) = ForeignLib -> BuildInfo
foreignLibBuildInfo ForeignLib
flib
gbuildInfo (GReplFLib ReplOptions
_ ForeignLib
flib) = ForeignLib -> BuildInfo
foreignLibBuildInfo ForeignLib
flib

gbuildName :: GBuildMode -> String
gbuildName :: GBuildMode -> String
gbuildName (GBuildExe Executable
exe) = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ Executable -> UnqualComponentName
exeName Executable
exe
gbuildName (GReplExe ReplOptions
_ Executable
exe) = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ Executable -> UnqualComponentName
exeName Executable
exe
gbuildName (GBuildFLib ForeignLib
flib) = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ ForeignLib -> UnqualComponentName
foreignLibName ForeignLib
flib
gbuildName (GReplFLib ReplOptions
_ ForeignLib
flib) = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ ForeignLib -> UnqualComponentName
foreignLibName ForeignLib
flib

gbuildTargetName :: LocalBuildInfo -> GBuildMode -> String
gbuildTargetName :: LocalBuildInfo -> GBuildMode -> String
gbuildTargetName LocalBuildInfo
lbi (GBuildExe Executable
exe) = Platform -> Executable -> String
exeTargetName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) Executable
exe
gbuildTargetName LocalBuildInfo
lbi (GReplExe ReplOptions
_ Executable
exe) = Platform -> Executable -> String
exeTargetName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) Executable
exe
gbuildTargetName LocalBuildInfo
lbi (GBuildFLib ForeignLib
flib) = LocalBuildInfo -> ForeignLib -> String
flibTargetName LocalBuildInfo
lbi ForeignLib
flib
gbuildTargetName LocalBuildInfo
lbi (GReplFLib ReplOptions
_ ForeignLib
flib) = LocalBuildInfo -> ForeignLib -> String
flibTargetName LocalBuildInfo
lbi ForeignLib
flib

exeTargetName :: Platform -> Executable -> String
exeTargetName :: Platform -> Executable -> String
exeTargetName Platform
platform Executable
exe = UnqualComponentName -> String
unUnqualComponentName (Executable -> UnqualComponentName
exeName Executable
exe) String -> String -> String
`withExt` Platform -> String
exeExtension Platform
platform

-- | Target name for a foreign library (the actual file name)
--
-- We do not use mkLibName and co here because the naming for foreign libraries
-- is slightly different (we don't use "_p" or compiler version suffices, and we
-- don't want the "lib" prefix on Windows).
--
-- TODO: We do use `dllExtension` and co here, but really that's wrong: they
-- use the OS used to build cabal to determine which extension to use, rather
-- than the target OS (but this is wrong elsewhere in Cabal as well).
flibTargetName :: LocalBuildInfo -> ForeignLib -> String
flibTargetName :: LocalBuildInfo -> ForeignLib -> String
flibTargetName LocalBuildInfo
lbi ForeignLib
flib =
  case (OS
os, ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib) of
    (OS
Windows, ForeignLibType
ForeignLibNativeShared) -> String
nm String -> String -> String
<.> String
"dll"
    (OS
Windows, ForeignLibType
ForeignLibNativeStatic) -> String
nm String -> String -> String
<.> String
"lib"
    (OS
Linux, ForeignLibType
ForeignLibNativeShared) -> String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nm String -> String -> String
<.> String
versionedExt
    (OS
_other, ForeignLibType
ForeignLibNativeShared) ->
      String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nm String -> String -> String
<.> Platform -> String
dllExtension (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi)
    (OS
_other, ForeignLibType
ForeignLibNativeStatic) ->
      String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nm String -> String -> String
<.> Platform -> String
staticLibExtension (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi)
    (OS
_any, ForeignLibType
ForeignLibTypeUnknown) -> String -> String
forall a. String -> a
cabalBug String
"unknown foreign lib type"
  where
    nm :: String
    nm :: String
nm = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ ForeignLib -> UnqualComponentName
foreignLibName ForeignLib
flib

    os :: OS
    os :: OS
os =
      let (Platform Arch
_ OS
os') = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
       in OS
os'

    -- If a foreign lib foo has lib-version-info 5:1:2 or
    -- lib-version-linux 3.2.1, it should be built as libfoo.so.3.2.1
    -- Libtool's version-info data is translated into library versions in a
    -- nontrivial way: so refer to libtool documentation.
    versionedExt :: String
    versionedExt :: String
versionedExt =
      let nums :: [Int]
nums = ForeignLib -> OS -> [Int]
foreignLibVersion ForeignLib
flib OS
os
       in (String -> String -> String) -> String -> [String] -> String
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl String -> String -> String
(<.>) String
"so" ((Int -> String) -> [Int] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Int -> String
forall a. Show a => a -> String
show [Int]
nums)

-- | Name for the library when building.
--
-- If the `lib-version-info` field or the `lib-version-linux` field of
-- a foreign library target is set, we need to incorporate that
-- version into the SONAME field.
--
-- If a foreign library foo has lib-version-info 5:1:2, it should be
-- built as libfoo.so.3.2.1.  We want it to get soname libfoo.so.3.
-- However, GHC does not allow overriding soname by setting linker
-- options, as it sets a soname of its own (namely the output
-- filename), after the user-supplied linker options.  Hence, we have
-- to compile the library with the soname as its filename.  We rename
-- the compiled binary afterwards.
--
-- This method allows to adjust the name of the library at build time
-- such that the correct soname can be set.
flibBuildName :: LocalBuildInfo -> ForeignLib -> String
flibBuildName :: LocalBuildInfo -> ForeignLib -> String
flibBuildName LocalBuildInfo
lbi ForeignLib
flib
  -- On linux, if a foreign-library has version data, the first digit is used
  -- to produce the SONAME.
  | (OS
os, ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib)
      (OS, ForeignLibType) -> (OS, ForeignLibType) -> Bool
forall a. Eq a => a -> a -> Bool
== (OS
Linux, ForeignLibType
ForeignLibNativeShared) =
      let nums :: [Int]
nums = ForeignLib -> OS -> [Int]
foreignLibVersion ForeignLib
flib OS
os
       in String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nm String -> String -> String
<.> (String -> String -> String) -> String -> [String] -> String
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl String -> String -> String
(<.>) String
"so" ((Int -> String) -> [Int] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Int -> String
forall a. Show a => a -> String
show (Int -> [Int] -> [Int]
forall a. Int -> [a] -> [a]
take Int
1 [Int]
nums))
  | Bool
otherwise = LocalBuildInfo -> ForeignLib -> String
flibTargetName LocalBuildInfo
lbi ForeignLib
flib
  where
    os :: OS
    os :: OS
os =
      let (Platform Arch
_ OS
os') = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
       in OS
os'

    nm :: String
    nm :: String
nm = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ ForeignLib -> UnqualComponentName
foreignLibName ForeignLib
flib

gbuildIsRepl :: GBuildMode -> Bool
gbuildIsRepl :: GBuildMode -> Bool
gbuildIsRepl (GBuildExe Executable
_) = Bool
False
gbuildIsRepl (GReplExe ReplOptions
_ Executable
_) = Bool
True
gbuildIsRepl (GBuildFLib ForeignLib
_) = Bool
False
gbuildIsRepl (GReplFLib ReplOptions
_ ForeignLib
_) = Bool
True

gbuildNeedDynamic :: LocalBuildInfo -> GBuildMode -> Bool
gbuildNeedDynamic :: LocalBuildInfo -> GBuildMode -> Bool
gbuildNeedDynamic LocalBuildInfo
lbi GBuildMode
bm =
  case GBuildMode
bm of
    GBuildExe Executable
_ -> LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi
    GReplExe ReplOptions
_ Executable
_ -> LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi
    GBuildFLib ForeignLib
flib -> ForeignLib -> Bool
withDynFLib ForeignLib
flib
    GReplFLib ReplOptions
_ ForeignLib
flib -> ForeignLib -> Bool
withDynFLib ForeignLib
flib
  where
    withDynFLib :: ForeignLib -> Bool
withDynFLib ForeignLib
flib =
      case ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib of
        ForeignLibType
ForeignLibNativeShared ->
          ForeignLibOption
ForeignLibStandalone ForeignLibOption -> [ForeignLibOption] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`notElem` ForeignLib -> [ForeignLibOption]
foreignLibOptions ForeignLib
flib
        ForeignLibType
ForeignLibNativeStatic ->
          Bool
False
        ForeignLibType
ForeignLibTypeUnknown ->
          String -> Bool
forall a. String -> a
cabalBug String
"unknown foreign lib type"

gbuildModDefFiles :: GBuildMode -> [FilePath]
gbuildModDefFiles :: GBuildMode -> [String]
gbuildModDefFiles (GBuildExe Executable
_) = []
gbuildModDefFiles (GReplExe ReplOptions
_ Executable
_) = []
gbuildModDefFiles (GBuildFLib ForeignLib
flib) = ForeignLib -> [String]
foreignLibModDefFile ForeignLib
flib
gbuildModDefFiles (GReplFLib ReplOptions
_ ForeignLib
flib) = ForeignLib -> [String]
foreignLibModDefFile ForeignLib
flib

-- | "Main" module name when overridden by @ghc-options: -main-is ...@
-- or 'Nothing' if no @-main-is@ flag could be found.
--
-- In case of 'Nothing', 'Distribution.ModuleName.main' can be assumed.
exeMainModuleName :: Executable -> Maybe ModuleName
exeMainModuleName :: Executable -> Maybe ModuleName
exeMainModuleName Executable{buildInfo :: Executable -> BuildInfo
buildInfo = BuildInfo
bnfo} =
  -- GHC honors the last occurrence of a module name updated via -main-is
  --
  -- Moreover, -main-is when parsed left-to-right can update either
  -- the "Main" module name, or the "main" function name, or both,
  -- see also 'decodeMainIsArg'.
  [Maybe ModuleName] -> Maybe ModuleName
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum ([Maybe ModuleName] -> Maybe ModuleName)
-> [Maybe ModuleName] -> Maybe ModuleName
forall a b. (a -> b) -> a -> b
$ [Maybe ModuleName] -> [Maybe ModuleName]
forall a. [a] -> [a]
reverse ([Maybe ModuleName] -> [Maybe ModuleName])
-> [Maybe ModuleName] -> [Maybe ModuleName]
forall a b. (a -> b) -> a -> b
$ (String -> Maybe ModuleName) -> [String] -> [Maybe ModuleName]
forall a b. (a -> b) -> [a] -> [b]
map String -> Maybe ModuleName
decodeMainIsArg ([String] -> [Maybe ModuleName]) -> [String] -> [Maybe ModuleName]
forall a b. (a -> b) -> a -> b
$ [String] -> [String]
findIsMainArgs [String]
ghcopts
  where
    ghcopts :: [String]
ghcopts = CompilerFlavor -> BuildInfo -> [String]
hcOptions CompilerFlavor
GHC BuildInfo
bnfo

    findIsMainArgs :: [String] -> [String]
findIsMainArgs [] = []
    findIsMainArgs (String
"-main-is" : String
arg : [String]
rest) = String
arg String -> [String] -> [String]
forall a. a -> [a] -> [a]
: [String] -> [String]
findIsMainArgs [String]
rest
    findIsMainArgs (String
_ : [String]
rest) = [String] -> [String]
findIsMainArgs [String]
rest

-- | Decode argument to '-main-is'
--
-- Returns 'Nothing' if argument set only the function name.
--
-- This code has been stolen/refactored from GHC's DynFlags.setMainIs
-- function. The logic here is deliberately imperfect as it is
-- intended to be bug-compatible with GHC's parser. See discussion in
-- https://github.com/haskell/cabal/pull/4539#discussion_r118981753.
decodeMainIsArg :: String -> Maybe ModuleName
decodeMainIsArg :: String -> Maybe ModuleName
decodeMainIsArg String
arg
  | String -> (Char -> Bool) -> Bool
headOf String
main_fn Char -> Bool
isLower =
      -- The arg looked like "Foo.Bar.baz"
      ModuleName -> Maybe ModuleName
forall a. a -> Maybe a
Just (String -> ModuleName
forall a. IsString a => String -> a
ModuleName.fromString String
main_mod)
  | String -> (Char -> Bool) -> Bool
headOf String
arg Char -> Bool
isUpper -- The arg looked like "Foo" or "Foo.Bar"
    =
      ModuleName -> Maybe ModuleName
forall a. a -> Maybe a
Just (String -> ModuleName
forall a. IsString a => String -> a
ModuleName.fromString String
arg)
  | Bool
otherwise -- The arg looked like "baz"
    =
      Maybe ModuleName
forall a. Maybe a
Nothing
  where
    headOf :: String -> (Char -> Bool) -> Bool
    headOf :: String -> (Char -> Bool) -> Bool
headOf String
str Char -> Bool
pred' = (Char -> Bool) -> Maybe Char -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Char -> Bool
pred' (String -> Maybe Char
forall a. [a] -> Maybe a
safeHead String
str)

    (String
main_mod, String
main_fn) = String -> (Char -> Bool) -> (String, String)
splitLongestPrefix String
arg (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.')

    splitLongestPrefix :: String -> (Char -> Bool) -> (String, String)
    splitLongestPrefix :: String -> (Char -> Bool) -> (String, String)
splitLongestPrefix String
str Char -> Bool
pred'
      | String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
r_pre = (String
str, [])
      | Bool
otherwise = (String -> String
forall a. [a] -> [a]
reverse (String -> String
forall a. [a] -> [a]
safeTail String
r_pre), String -> String
forall a. [a] -> [a]
reverse String
r_suf)
      where
        -- 'safeTail' drops the char satisfying 'pred'
        (String
r_suf, String
r_pre) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
pred' (String -> String
forall a. [a] -> [a]
reverse String
str)

-- | A collection of:
--    * C input files
--    * C++ input files
--    * GHC input files
--    * GHC input modules
--
-- Used to correctly build and link sources.
data BuildSources = BuildSources
  { BuildSources -> [String]
cSourcesFiles :: [FilePath]
  , BuildSources -> [String]
cxxSourceFiles :: [FilePath]
  , BuildSources -> [String]
inputSourceFiles :: [FilePath]
  , BuildSources -> [ModuleName]
inputSourceModules :: [ModuleName]
  }

-- | Locate and return the 'BuildSources' required to build and link.
gbuildSources
  :: Verbosity
  -> PackageId
  -> CabalSpecVersion
  -> FilePath
  -> GBuildMode
  -> IO BuildSources
gbuildSources :: Verbosity
-> PackageId
-> CabalSpecVersion
-> String
-> GBuildMode
-> IO BuildSources
gbuildSources Verbosity
verbosity PackageId
pkgId CabalSpecVersion
specVer String
tmpDir GBuildMode
bm =
  case GBuildMode
bm of
    GBuildExe Executable
exe -> Executable -> IO BuildSources
exeSources Executable
exe
    GReplExe ReplOptions
_ Executable
exe -> Executable -> IO BuildSources
exeSources Executable
exe
    GBuildFLib ForeignLib
flib -> BuildSources -> IO BuildSources
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildSources -> IO BuildSources)
-> BuildSources -> IO BuildSources
forall a b. (a -> b) -> a -> b
$ ForeignLib -> BuildSources
flibSources ForeignLib
flib
    GReplFLib ReplOptions
_ ForeignLib
flib -> BuildSources -> IO BuildSources
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (BuildSources -> IO BuildSources)
-> BuildSources -> IO BuildSources
forall a b. (a -> b) -> a -> b
$ ForeignLib -> BuildSources
flibSources ForeignLib
flib
  where
    exeSources :: Executable -> IO BuildSources
    exeSources :: Executable -> IO BuildSources
exeSources exe :: Executable
exe@Executable{buildInfo :: Executable -> BuildInfo
buildInfo = BuildInfo
bnfo, modulePath :: Executable -> String
modulePath = String
modPath} = do
      String
main <- Verbosity -> [String] -> String -> IO String
findFileEx Verbosity
verbosity (String
tmpDir String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (SymbolicPath PackageDir SourceDir -> String)
-> [SymbolicPath PackageDir SourceDir] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map SymbolicPath PackageDir SourceDir -> String
forall from to. SymbolicPath from to -> String
getSymbolicPath (BuildInfo -> [SymbolicPath PackageDir SourceDir]
hsSourceDirs BuildInfo
bnfo)) String
modPath
      let mainModName :: ModuleName
mainModName = ModuleName -> Maybe ModuleName -> ModuleName
forall a. a -> Maybe a -> a
fromMaybe ModuleName
ModuleName.main (Maybe ModuleName -> ModuleName) -> Maybe ModuleName -> ModuleName
forall a b. (a -> b) -> a -> b
$ Executable -> Maybe ModuleName
exeMainModuleName Executable
exe
          otherModNames :: [ModuleName]
otherModNames = Executable -> [ModuleName]
exeModules Executable
exe

      -- Scripts have fakePackageId and are always Haskell but can have any extension.
      if String -> Bool
isHaskell String
main Bool -> Bool -> Bool
|| PackageId
pkgId PackageId -> PackageId -> Bool
forall a. Eq a => a -> a -> Bool
== PackageId
fakePackageId
        then
          if CabalSpecVersion
specVer CabalSpecVersion -> CabalSpecVersion -> Bool
forall a. Ord a => a -> a -> Bool
< CabalSpecVersion
CabalSpecV2_0 Bool -> Bool -> Bool
&& (ModuleName
mainModName ModuleName -> [ModuleName] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [ModuleName]
otherModNames)
            then do
              -- The cabal manual clearly states that `other-modules` is
              -- intended for non-main modules.  However, there's at least one
              -- important package on Hackage (happy-1.19.5) which
              -- violates this. We workaround this here so that we don't
              -- invoke GHC with e.g.  'ghc --make Main src/Main.hs' which
              -- would result in GHC complaining about duplicate Main
              -- modules.
              --
              -- Finally, we only enable this workaround for
              -- specVersion < 2, as 'cabal-version:>=2.0' cabal files
              -- have no excuse anymore to keep doing it wrong... ;-)
              Verbosity -> String -> IO ()
warn Verbosity
verbosity (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$
                String
"Enabling workaround for Main module '"
                  String -> String -> String
forall a. [a] -> [a] -> [a]
++ ModuleName -> String
forall a. Pretty a => a -> String
prettyShow ModuleName
mainModName
                  String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"' listed in 'other-modules' illegally!"

              BuildSources -> IO BuildSources
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                BuildSources
                  { cSourcesFiles :: [String]
cSourcesFiles = BuildInfo -> [String]
cSources BuildInfo
bnfo
                  , cxxSourceFiles :: [String]
cxxSourceFiles = BuildInfo -> [String]
cxxSources BuildInfo
bnfo
                  , inputSourceFiles :: [String]
inputSourceFiles = [String
main]
                  , inputSourceModules :: [ModuleName]
inputSourceModules =
                      (ModuleName -> Bool) -> [ModuleName] -> [ModuleName]
forall a. (a -> Bool) -> [a] -> [a]
filter (ModuleName -> ModuleName -> Bool
forall a. Eq a => a -> a -> Bool
/= ModuleName
mainModName) ([ModuleName] -> [ModuleName]) -> [ModuleName] -> [ModuleName]
forall a b. (a -> b) -> a -> b
$
                        Executable -> [ModuleName]
exeModules Executable
exe
                  }
            else
              BuildSources -> IO BuildSources
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                BuildSources
                  { cSourcesFiles :: [String]
cSourcesFiles = BuildInfo -> [String]
cSources BuildInfo
bnfo
                  , cxxSourceFiles :: [String]
cxxSourceFiles = BuildInfo -> [String]
cxxSources BuildInfo
bnfo
                  , inputSourceFiles :: [String]
inputSourceFiles = [String
main]
                  , inputSourceModules :: [ModuleName]
inputSourceModules = Executable -> [ModuleName]
exeModules Executable
exe
                  }
        else
          let ([String]
csf, [String]
cxxsf)
                | String -> Bool
isCxx String
main = (BuildInfo -> [String]
cSources BuildInfo
bnfo, String
main String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
cxxSources BuildInfo
bnfo)
                -- if main is not a Haskell source
                -- and main is not a C++ source
                -- then we assume that it is a C source
                | Bool
otherwise = (String
main String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
cSources BuildInfo
bnfo, BuildInfo -> [String]
cxxSources BuildInfo
bnfo)
           in BuildSources -> IO BuildSources
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
                BuildSources
                  { cSourcesFiles :: [String]
cSourcesFiles = [String]
csf
                  , cxxSourceFiles :: [String]
cxxSourceFiles = [String]
cxxsf
                  , inputSourceFiles :: [String]
inputSourceFiles = []
                  , inputSourceModules :: [ModuleName]
inputSourceModules = Executable -> [ModuleName]
exeModules Executable
exe
                  }

    flibSources :: ForeignLib -> BuildSources
    flibSources :: ForeignLib -> BuildSources
flibSources flib :: ForeignLib
flib@ForeignLib{foreignLibBuildInfo :: ForeignLib -> BuildInfo
foreignLibBuildInfo = BuildInfo
bnfo} =
      BuildSources
        { cSourcesFiles :: [String]
cSourcesFiles = BuildInfo -> [String]
cSources BuildInfo
bnfo
        , cxxSourceFiles :: [String]
cxxSourceFiles = BuildInfo -> [String]
cxxSources BuildInfo
bnfo
        , inputSourceFiles :: [String]
inputSourceFiles = []
        , inputSourceModules :: [ModuleName]
inputSourceModules = ForeignLib -> [ModuleName]
foreignLibModules ForeignLib
flib
        }

    isCxx :: FilePath -> Bool
    isCxx :: String -> Bool
isCxx String
fp = String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem (String -> String
takeExtension String
fp) [String
".cpp", String
".cxx", String
".c++"]

-- | FilePath has a Haskell extension: .hs or .lhs
isHaskell :: FilePath -> Bool
isHaskell :: String -> Bool
isHaskell String
fp = String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem (String -> String
takeExtension String
fp) [String
".hs", String
".lhs"]

replNoLoad :: Ord a => ReplOptions -> NubListR a -> NubListR a
replNoLoad :: forall a. Ord a => ReplOptions -> NubListR a -> NubListR a
replNoLoad ReplOptions
replFlags NubListR a
l
  | ReplOptions -> Flag Bool
replOptionsNoLoad ReplOptions
replFlags Flag Bool -> Flag Bool -> Bool
forall a. Eq a => a -> a -> Bool
== Bool -> Flag Bool
forall a. a -> Flag a
Flag Bool
True = NubListR a
forall a. Monoid a => a
mempty
  | Bool
otherwise = NubListR a
l

-- | Generic build function. See comment for 'GBuildMode'.
gbuild
  :: Verbosity
  -> Flag (Maybe Int)
  -> PackageDescription
  -> LocalBuildInfo
  -> GBuildMode
  -> ComponentLocalBuildInfo
  -> IO ()
gbuild :: Verbosity
-> Flag (Maybe Int)
-> PackageDescription
-> LocalBuildInfo
-> GBuildMode
-> ComponentLocalBuildInfo
-> IO ()
gbuild Verbosity
verbosity Flag (Maybe Int)
numJobs PackageDescription
pkg_descr LocalBuildInfo
lbi GBuildMode
bm ComponentLocalBuildInfo
clbi = do
  (ConfiguredProgram
ghcProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ghcProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
  let replFlags :: ReplOptions
replFlags = case GBuildMode
bm of
        GReplExe ReplOptions
flags Executable
_ -> ReplOptions
flags
        GReplFLib ReplOptions
flags ForeignLib
_ -> ReplOptions
flags
        GBuildExe{} -> ReplOptions
forall a. Monoid a => a
mempty
        GBuildFLib{} -> ReplOptions
forall a. Monoid a => a
mempty
      comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi
      platform :: Platform
platform = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
      implInfo :: GhcImplInfo
implInfo = Compiler -> GhcImplInfo
getImplInfo Compiler
comp
      runGhcProg :: GhcOptions -> IO ()
runGhcProg = Verbosity
-> ConfiguredProgram -> Compiler -> Platform -> GhcOptions -> IO ()
runGHC Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform

  let bnfo :: BuildInfo
bnfo = GBuildMode -> BuildInfo
gbuildInfo GBuildMode
bm

  -- the name that GHC really uses (e.g., with .exe on Windows for executables)
  let targetName :: String
targetName = LocalBuildInfo -> GBuildMode -> String
gbuildTargetName LocalBuildInfo
lbi GBuildMode
bm
  let targetDir :: String
targetDir = LocalBuildInfo -> String
buildDir LocalBuildInfo
lbi String -> String -> String
</> (GBuildMode -> String
gbuildName GBuildMode
bm)
  let tmpDir :: String
tmpDir = String
targetDir String -> String -> String
</> (GBuildMode -> String
gbuildName GBuildMode
bm String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-tmp")
  Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
targetDir
  Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
tmpDir

  -- TODO: do we need to put hs-boot files into place for mutually recursive
  -- modules?  FIX: what about exeName.hi-boot?

  -- Determine if program coverage should be enabled and if so, what
  -- '-hpcdir' should be.
  let isCoverageEnabled :: Bool
isCoverageEnabled = LocalBuildInfo -> Bool
exeCoverage LocalBuildInfo
lbi
      distPref :: String
distPref = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (Flag String -> String) -> Flag String -> String
forall a b. (a -> b) -> a -> b
$ ConfigFlags -> Flag String
configDistPref (ConfigFlags -> Flag String) -> ConfigFlags -> Flag String
forall a b. (a -> b) -> a -> b
$ LocalBuildInfo -> ConfigFlags
configFlags LocalBuildInfo
lbi
      hpcdir :: Way -> Flag String
hpcdir Way
way
        | GBuildMode -> Bool
gbuildIsRepl GBuildMode
bm = Flag String
forall a. Monoid a => a
mempty -- HPC is not supported in ghci
        | Bool
isCoverageEnabled = String -> Flag String
forall a. a -> Flag a
toFlag (String -> Flag String) -> String -> Flag String
forall a b. (a -> b) -> a -> b
$ String -> Way -> String -> String
Hpc.mixDir String
distPref Way
way (GBuildMode -> String
gbuildName GBuildMode
bm)
        | Bool
otherwise = Flag String
forall a. Monoid a => a
mempty

  NubListR String
rpaths <- LocalBuildInfo -> ComponentLocalBuildInfo -> IO (NubListR String)
getRPaths LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi
  BuildSources
buildSources <- Verbosity
-> PackageId
-> CabalSpecVersion
-> String
-> GBuildMode
-> IO BuildSources
gbuildSources Verbosity
verbosity (PackageDescription -> PackageId
package PackageDescription
pkg_descr) (PackageDescription -> CabalSpecVersion
specVersion PackageDescription
pkg_descr) String
tmpDir GBuildMode
bm

  -- ensure extra lib dirs exist before passing to ghc
  [String]
cleanedExtraLibDirs <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesDirectoryExist (BuildInfo -> [String]
extraLibDirs BuildInfo
bnfo)
  [String]
cleanedExtraLibDirsStatic <- (String -> IO Bool) -> [String] -> IO [String]
forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM String -> IO Bool
doesDirectoryExist (BuildInfo -> [String]
extraLibDirsStatic BuildInfo
bnfo)

  let cSrcs :: [String]
cSrcs = BuildSources -> [String]
cSourcesFiles BuildSources
buildSources
      cxxSrcs :: [String]
cxxSrcs = BuildSources -> [String]
cxxSourceFiles BuildSources
buildSources
      inputFiles :: [String]
inputFiles = BuildSources -> [String]
inputSourceFiles BuildSources
buildSources
      inputModules :: [ModuleName]
inputModules = BuildSources -> [ModuleName]
inputSourceModules BuildSources
buildSources
      isGhcDynamic :: Bool
isGhcDynamic = Compiler -> Bool
isDynamic Compiler
comp
      dynamicTooSupported :: Bool
dynamicTooSupported = Compiler -> Bool
supportsDynamicToo Compiler
comp
      cLikeObjs :: [String]
cLikeObjs = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
`replaceExtension` String
objExtension) [String]
cSrcs
      cxxObjs :: [String]
cxxObjs = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> String
`replaceExtension` String
objExtension) [String]
cxxSrcs
      needDynamic :: Bool
needDynamic = LocalBuildInfo -> GBuildMode -> Bool
gbuildNeedDynamic LocalBuildInfo
lbi GBuildMode
bm
      needProfiling :: Bool
needProfiling = LocalBuildInfo -> Bool
withProfExe LocalBuildInfo
lbi

      -- build executables
      baseOpts :: GhcOptions
baseOpts =
        (Verbosity
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> GhcOptions
componentGhcOptions Verbosity
verbosity LocalBuildInfo
lbi BuildInfo
bnfo ComponentLocalBuildInfo
clbi String
tmpDir)
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptMode = toFlag GhcModeMake
            , ghcOptInputFiles =
                toNubListR $
                  if package pkg_descr == fakePackageId
                    then filter isHaskell inputFiles
                    else inputFiles
            , ghcOptInputScripts =
                toNubListR $
                  if package pkg_descr == fakePackageId
                    then filter (not . isHaskell) inputFiles
                    else []
            , ghcOptInputModules = toNubListR inputModules
            }
      staticOpts :: GhcOptions
staticOpts =
        GhcOptions
baseOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptDynLinkMode = toFlag GhcStaticOnly
            , ghcOptHPCDir = hpcdir Hpc.Vanilla
            }
      profOpts :: GhcOptions
profOpts =
        GhcOptions
baseOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptProfilingMode = toFlag True
            , ghcOptProfilingAuto =
                Internal.profDetailLevelFlag
                  False
                  (withProfExeDetail lbi)
            , ghcOptHiSuffix = toFlag "p_hi"
            , ghcOptObjSuffix = toFlag "p_o"
            , ghcOptExtra = hcProfOptions GHC bnfo
            , ghcOptHPCDir = hpcdir Hpc.Prof
            }
      dynOpts :: GhcOptions
dynOpts =
        GhcOptions
baseOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptDynLinkMode = toFlag GhcDynamicOnly
            , -- TODO: Does it hurt to set -fPIC for executables?
              ghcOptFPic = toFlag True
            , ghcOptHiSuffix = toFlag "dyn_hi"
            , ghcOptObjSuffix = toFlag "dyn_o"
            , ghcOptExtra = hcSharedOptions GHC bnfo
            , ghcOptHPCDir = hpcdir Hpc.Dyn
            }
      dynTooOpts :: GhcOptions
dynTooOpts =
        GhcOptions
staticOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptDynLinkMode = toFlag GhcStaticAndDynamic
            , ghcOptDynHiSuffix = toFlag "dyn_hi"
            , ghcOptDynObjSuffix = toFlag "dyn_o"
            , ghcOptHPCDir = hpcdir Hpc.Dyn
            }
      linkerOpts :: GhcOptions
linkerOpts =
        GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptLinkOptions =
              PD.ldOptions bnfo
                ++ [ "-static"
                   | withFullyStaticExe lbi
                   ]
                -- Pass extra `ld-options` given
                -- through to GHC's linker.
                ++ maybe
                  []
                  programOverrideArgs
                  (lookupProgram ldProgram (withPrograms lbi))
          , ghcOptLinkLibs =
              if withFullyStaticExe lbi
                then extraLibsStatic bnfo
                else extraLibs bnfo
          , ghcOptLinkLibPath =
              toNubListR $
                if withFullyStaticExe lbi
                  then cleanedExtraLibDirsStatic
                  else cleanedExtraLibDirs
          , ghcOptLinkFrameworks =
              toNubListR $
                PD.frameworks bnfo
          , ghcOptLinkFrameworkDirs =
              toNubListR $
                PD.extraFrameworkDirs bnfo
          , ghcOptInputFiles =
              toNubListR
                [tmpDir </> x | x <- cLikeObjs ++ cxxObjs]
          }
      dynLinkerOpts :: GhcOptions
dynLinkerOpts =
        GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptRPaths = rpaths
          , ghcOptInputFiles =
              toNubListR
                [tmpDir </> x | x <- cLikeObjs ++ cxxObjs]
          }
      replOpts :: GhcOptions
replOpts =
        GhcOptions
baseOpts
          { ghcOptExtra =
              Internal.filterGhciFlags
                (ghcOptExtra baseOpts)
                <> replOptionsFlags replFlags
          , ghcOptInputModules = replNoLoad replFlags (ghcOptInputModules baseOpts)
          , ghcOptInputFiles = replNoLoad replFlags (ghcOptInputFiles baseOpts)
          }
          -- For a normal compile we do separate invocations of ghc for
          -- compiling as for linking. But for repl we have to do just
          -- the one invocation, so that one has to include all the
          -- linker stuff too, like -l flags and any .o files from C
          -- files etc.
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
linkerOpts
          GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
            { ghcOptMode = toFlag GhcModeInteractive
            , ghcOptOptimisation = toFlag GhcNoOptimisation
            }
      commonOpts :: GhcOptions
commonOpts
        | Bool
needProfiling = GhcOptions
profOpts
        | Bool
needDynamic = GhcOptions
dynOpts
        | Bool
otherwise = GhcOptions
staticOpts
      compileOpts :: GhcOptions
compileOpts
        | Bool
useDynToo = GhcOptions
dynTooOpts
        | Bool
otherwise = GhcOptions
commonOpts
      withStaticExe :: Bool
withStaticExe = Bool -> Bool
not Bool
needProfiling Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
needDynamic

      -- For building exe's that use TH with -prof or -dynamic we actually have
      -- to build twice, once without -prof/-dynamic and then again with
      -- -prof/-dynamic. This is because the code that TH needs to run at
      -- compile time needs to be the vanilla ABI so it can be loaded up and run
      -- by the compiler.
      -- With dynamic-by-default GHC the TH object files loaded at compile-time
      -- need to be .dyn_o instead of .o.
      doingTH :: Bool
doingTH = BuildInfo -> Bool
usesTemplateHaskellOrQQ BuildInfo
bnfo
      -- Should we use -dynamic-too instead of compiling twice?
      useDynToo :: Bool
useDynToo =
        Bool
dynamicTooSupported
          Bool -> Bool -> Bool
&& Bool
isGhcDynamic
          Bool -> Bool -> Bool
&& Bool
doingTH
          Bool -> Bool -> Bool
&& Bool
withStaticExe
          Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (CompilerFlavor -> BuildInfo -> [String]
hcSharedOptions CompilerFlavor
GHC BuildInfo
bnfo)
      compileTHOpts :: GhcOptions
compileTHOpts
        | Bool
isGhcDynamic = GhcOptions
dynOpts
        | Bool
otherwise = GhcOptions
staticOpts
      compileForTH :: Bool
compileForTH
        | GBuildMode -> Bool
gbuildIsRepl GBuildMode
bm = Bool
False
        | Bool
useDynToo = Bool
False
        | Bool
isGhcDynamic = Bool
doingTH Bool -> Bool -> Bool
&& (Bool
needProfiling Bool -> Bool -> Bool
|| Bool
withStaticExe)
        | Bool
otherwise = Bool
doingTH Bool -> Bool -> Bool
&& (Bool
needProfiling Bool -> Bool -> Bool
|| Bool
needDynamic)

  -- Build static/dynamic object files for TH, if needed.
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
compileForTH (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
    GhcOptions -> IO ()
runGhcProg
      GhcOptions
compileTHOpts
        { ghcOptNoLink = toFlag True
        , ghcOptNumJobs = numJobs
        }

  -- Do not try to build anything if there are no input files.
  -- This can happen if the cabal file ends up with only cSrcs
  -- but no Haskell modules.
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless
    ( ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
inputFiles Bool -> Bool -> Bool
&& [ModuleName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [ModuleName]
inputModules)
        Bool -> Bool -> Bool
|| GBuildMode -> Bool
gbuildIsRepl GBuildMode
bm
    )
    (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ GhcOptions -> IO ()
runGhcProg
      GhcOptions
compileOpts
        { ghcOptNoLink = toFlag True
        , ghcOptNumJobs = numJobs
        }

  -- build any C++ sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
cxxSrcs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building C++ Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseCxxOpts :: GhcOptions
baseCxxOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCxxGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
bnfo
                ComponentLocalBuildInfo
clbi
                String
tmpDir
                String
filename
            vanillaCxxOpts :: GhcOptions
vanillaCxxOpts =
              if Bool
isGhcDynamic
                then -- Dynamic GHC requires C++ sources to be built
                -- with -fPIC for REPL to work. See #2207.
                  GhcOptions
baseCxxOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseCxxOpts
            profCxxOpts :: GhcOptions
profCxxOpts =
              GhcOptions
vanillaCxxOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  }
            sharedCxxOpts :: GhcOptions
sharedCxxOpts =
              GhcOptions
vanillaCxxOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  }
            opts :: GhcOptions
opts
              | Bool
needProfiling = GhcOptions
profCxxOpts
              | Bool
needDynamic = GhcOptions
sharedCxxOpts
              | Bool
otherwise = GhcOptions
vanillaCxxOpts
            -- TODO: Placing all Haskell, C, & C++ objects in a single directory
            --       Has the potential for file collisions. In general we would
            --       consider this a user error. However, we should strive to
            --       add a warning if this occurs.
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
opts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
opts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          GhcOptions -> IO ()
runGhcProg GhcOptions
opts
      | String
filename <- [String]
cxxSrcs
      ]

  -- build any C sources
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
cSrcs) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Building C Sources..."
    [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
      [ do
        let baseCcOpts :: GhcOptions
baseCcOpts =
              Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCcGhcOptions
                Verbosity
verbosity
                GhcImplInfo
implInfo
                LocalBuildInfo
lbi
                BuildInfo
bnfo
                ComponentLocalBuildInfo
clbi
                String
tmpDir
                String
filename
            vanillaCcOpts :: GhcOptions
vanillaCcOpts =
              if Bool
isGhcDynamic
                then -- Dynamic GHC requires C sources to be built
                -- with -fPIC for REPL to work. See #2207.
                  GhcOptions
baseCcOpts{ghcOptFPic = toFlag True}
                else GhcOptions
baseCcOpts
            profCcOpts :: GhcOptions
profCcOpts =
              GhcOptions
vanillaCcOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptProfilingMode = toFlag True
                  }
            sharedCcOpts :: GhcOptions
sharedCcOpts =
              GhcOptions
vanillaCcOpts
                GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptFPic = toFlag True
                  , ghcOptDynLinkMode = toFlag GhcDynamicOnly
                  }
            opts :: GhcOptions
opts
              | Bool
needProfiling = GhcOptions
profCcOpts
              | Bool
needDynamic = GhcOptions
sharedCcOpts
              | Bool
otherwise = GhcOptions
vanillaCcOpts
            odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
opts)
        Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
odir
        Bool
needsRecomp <- String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
opts
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
needsRecomp (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
          GhcOptions -> IO ()
runGhcProg GhcOptions
opts
      | String
filename <- [String]
cSrcs
      ]

  -- TODO: problem here is we need the .c files built first, so we can load them
  -- with ghci, but .c files can depend on .h files generated by ghc by ffi
  -- exports.
  case GBuildMode
bm of
    GReplExe ReplOptions
_ Executable
_ -> Verbosity
-> ConfiguredProgram
-> Compiler
-> Platform
-> ReplOptions
-> GhcOptions
-> BuildInfo
-> ComponentLocalBuildInfo
-> PackageName
-> IO ()
runReplOrWriteFlags Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform ReplOptions
replFlags GhcOptions
replOpts BuildInfo
bnfo ComponentLocalBuildInfo
clbi (PackageId -> PackageName
pkgName (PackageDescription -> PackageId
PD.package PackageDescription
pkg_descr))
    GReplFLib ReplOptions
_ ForeignLib
_ -> Verbosity
-> ConfiguredProgram
-> Compiler
-> Platform
-> ReplOptions
-> GhcOptions
-> BuildInfo
-> ComponentLocalBuildInfo
-> PackageName
-> IO ()
runReplOrWriteFlags Verbosity
verbosity ConfiguredProgram
ghcProg Compiler
comp Platform
platform ReplOptions
replFlags GhcOptions
replOpts BuildInfo
bnfo ComponentLocalBuildInfo
clbi (PackageId -> PackageName
pkgName (PackageDescription -> PackageId
PD.package PackageDescription
pkg_descr))
    GBuildExe Executable
_ -> do
      let linkOpts :: GhcOptions
linkOpts =
            GhcOptions
commonOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
linkerOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                { ghcOptLinkNoHsMain = toFlag (null inputFiles)
                }
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` (if LocalBuildInfo -> Bool
withDynExe LocalBuildInfo
lbi then GhcOptions
dynLinkerOpts else GhcOptions
forall a. Monoid a => a
mempty)

      Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Linking..."
      -- Work around old GHCs not relinking in this
      -- situation, see #3294
      let target :: String
target = String
targetDir String -> String -> String
</> String
targetName
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Compiler -> Version
compilerVersion Compiler
comp Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
< [Int] -> Version
mkVersion [Int
7, Int
7]) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        Bool
e <- String -> IO Bool
doesFileExist String
target
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
e (String -> IO ()
removeFile String
target)
      GhcOptions -> IO ()
runGhcProg GhcOptions
linkOpts{ghcOptOutputFile = toFlag target}
    GBuildFLib ForeignLib
flib -> do
      let
        -- Instruct GHC to link against libHSrts.
        rtsLinkOpts :: GhcOptions
        rtsLinkOpts :: GhcOptions
rtsLinkOpts
          | Bool
supportsFLinkRts =
              GhcOptions
forall a. Monoid a => a
mempty
                { ghcOptLinkRts = toFlag True
                }
          | Bool
otherwise =
              GhcOptions
forall a. Monoid a => a
mempty
                { ghcOptLinkLibs = rtsOptLinkLibs
                , ghcOptLinkLibPath = toNubListR $ rtsLibPaths rtsInfo
                }
          where
            threaded :: Bool
threaded = BuildInfo -> Bool
hasThreaded (GBuildMode -> BuildInfo
gbuildInfo GBuildMode
bm)
            supportsFLinkRts :: Bool
supportsFLinkRts = Compiler -> Version
compilerVersion Compiler
comp Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
9, Int
0]
            rtsInfo :: RtsInfo
rtsInfo = LocalBuildInfo -> RtsInfo
extractRtsInfo LocalBuildInfo
lbi
            rtsOptLinkLibs :: [String]
rtsOptLinkLibs =
              [ if Bool
needDynamic
                  then
                    if Bool
threaded
                      then DynamicRtsInfo -> String
dynRtsThreadedLib (RtsInfo -> DynamicRtsInfo
rtsDynamicInfo RtsInfo
rtsInfo)
                      else DynamicRtsInfo -> String
dynRtsVanillaLib (RtsInfo -> DynamicRtsInfo
rtsDynamicInfo RtsInfo
rtsInfo)
                  else
                    if Bool
threaded
                      then StaticRtsInfo -> String
statRtsThreadedLib (RtsInfo -> StaticRtsInfo
rtsStaticInfo RtsInfo
rtsInfo)
                      else StaticRtsInfo -> String
statRtsVanillaLib (RtsInfo -> StaticRtsInfo
rtsStaticInfo RtsInfo
rtsInfo)
              ]

        linkOpts :: GhcOptions
        linkOpts :: GhcOptions
linkOpts = case ForeignLib -> ForeignLibType
foreignLibType ForeignLib
flib of
          ForeignLibType
ForeignLibNativeShared ->
            GhcOptions
commonOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
linkerOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
dynLinkerOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
rtsLinkOpts
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
                { ghcOptLinkNoHsMain = toFlag True
                , ghcOptShared = toFlag True
                , ghcOptFPic = toFlag True
                , ghcOptLinkModDefFiles = toNubListR $ gbuildModDefFiles bm
                }
              -- See Note [RPATH]
              GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` LocalBuildInfo -> GhcOptions -> GhcOptions
forall a. Monoid a => LocalBuildInfo -> a -> a
ifNeedsRPathWorkaround
                LocalBuildInfo
lbi
                GhcOptions
forall a. Monoid a => a
mempty
                  { ghcOptLinkOptions = ["-Wl,--no-as-needed"]
                  , ghcOptLinkLibs = ["ffi"]
                  }
          ForeignLibType
ForeignLibNativeStatic ->
            -- this should be caught by buildFLib
            -- (and if we do implement this, we probably don't even want to call
            -- ghc here, but rather Ar.createArLibArchive or something)
            String -> GhcOptions
forall a. String -> a
cabalBug String
"static libraries not yet implemented"
          ForeignLibType
ForeignLibTypeUnknown ->
            String -> GhcOptions
forall a. String -> a
cabalBug String
"unknown foreign lib type"
      -- We build under a (potentially) different filename to set a
      -- soname on supported platforms.  See also the note for
      -- @flibBuildName@.
      Verbosity -> String -> IO ()
info Verbosity
verbosity String
"Linking..."
      let buildName :: String
buildName = LocalBuildInfo -> ForeignLib -> String
flibBuildName LocalBuildInfo
lbi ForeignLib
flib
      GhcOptions -> IO ()
runGhcProg GhcOptions
linkOpts{ghcOptOutputFile = toFlag (targetDir </> buildName)}
      String -> String -> IO ()
renameFile (String
targetDir String -> String -> String
</> String
buildName) (String
targetDir String -> String -> String
</> String
targetName)

{-
Note [RPATH]
~~~~~~~~~~~~

Suppose that the dynamic library depends on `base`, but not (directly) on
`integer-gmp` (which, however, is a dependency of `base`). We will link the
library as

    gcc ... -lHSbase-4.7.0.2-ghc7.8.4 -lHSinteger-gmp-0.5.1.0-ghc7.8.4 ...

However, on systems (like Ubuntu) where the linker gets called with `-as-needed`
by default, the linker will notice that `integer-gmp` isn't actually a direct
dependency and hence omit the link.

Then when we attempt to link a C program against this dynamic library, the
_static_ linker will attempt to verify that all symbols can be resolved.  The
dynamic library itself does not require any symbols from `integer-gmp`, but
`base` does. In order to verify that the symbols used by `base` can be
resolved, the static linker needs to be able to _find_ integer-gmp.

Finding the `base` dependency is simple, because the dynamic elf header
(`readelf -d`) for the library that we have created looks something like

    (NEEDED) Shared library: [libHSbase-4.7.0.2-ghc7.8.4.so]
    (RPATH)  Library rpath: [/path/to/base-4.7.0.2:...]

However, when it comes to resolving the dependency on `integer-gmp`, it needs
to look at the dynamic header for `base`. On modern ghc (7.8 and higher) this
looks something like

    (NEEDED) Shared library: [libHSinteger-gmp-0.5.1.0-ghc7.8.4.so]
    (RPATH)  Library rpath: [$ORIGIN/../integer-gmp-0.5.1.0:...]

This specifies the location of `integer-gmp` _in terms of_ the location of base
(using the `$ORIGIN`) variable. But here's the crux: when the static linker
attempts to verify that all symbols can be resolved, [**IT DOES NOT RESOLVE
`$ORIGIN`**](http://stackoverflow.com/questions/6323603/ld-using-rpath-origin-inside-a-shared-library-recursive).
As a consequence, it will not be able to resolve the symbols and report the
missing symbols as errors, _even though the dynamic linker **would** be able to
resolve these symbols_. We can tell the static linker not to report these
errors by using `--unresolved-symbols=ignore-all` and all will be fine when we
run the program ([(indeed, this is what the gold linker
does)](https://sourceware.org/ml/binutils/2013-05/msg00038.html), but it makes
the resulting library more difficult to use.

Instead what we can do is make sure that the generated dynamic library has
explicit top-level dependencies on these libraries. This means that the static
linker knows where to find them, and when we have transitive dependencies on
the same libraries the linker will only load them once, so we avoid needing to
look at the `RPATH` of our dependencies. We can do this by passing
`--no-as-needed` to the linker, so that it doesn't omit any libraries.

Note that on older ghc (7.6 and before) the Haskell libraries don't have an
RPATH set at all, which makes it even more important that we make these
top-level dependencies.

Finally, we have to explicitly link against `libffi` for the same reason. For
newer ghc this _happens_ to be unnecessary on many systems because `libffi` is
a library which is not specific to GHC, and when the static linker verifies
that all symbols can be resolved it will find the `libffi` that is globally
installed (completely independent from ghc). Of course, this may well be the
_wrong_ version of `libffi`, but it's quite possible that symbol resolution
happens to work. This is of course the wrong approach, which is why we link
explicitly against `libffi` so that we will find the _right_ version of
`libffi`.
-}

-- | Do we need the RPATH workaround?
--
-- See Note [RPATH].
ifNeedsRPathWorkaround :: Monoid a => LocalBuildInfo -> a -> a
ifNeedsRPathWorkaround :: forall a. Monoid a => LocalBuildInfo -> a -> a
ifNeedsRPathWorkaround LocalBuildInfo
lbi a
a =
  case LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi of
    Platform Arch
_ OS
Linux -> a
a
    Platform
_otherwise -> a
forall a. Monoid a => a
mempty

data DynamicRtsInfo = DynamicRtsInfo
  { DynamicRtsInfo -> String
dynRtsVanillaLib :: FilePath
  , DynamicRtsInfo -> String
dynRtsThreadedLib :: FilePath
  , DynamicRtsInfo -> String
dynRtsDebugLib :: FilePath
  , DynamicRtsInfo -> String
dynRtsEventlogLib :: FilePath
  , DynamicRtsInfo -> String
dynRtsThreadedDebugLib :: FilePath
  , DynamicRtsInfo -> String
dynRtsThreadedEventlogLib :: FilePath
  }

data StaticRtsInfo = StaticRtsInfo
  { StaticRtsInfo -> String
statRtsVanillaLib :: FilePath
  , StaticRtsInfo -> String
statRtsThreadedLib :: FilePath
  , StaticRtsInfo -> String
statRtsDebugLib :: FilePath
  , StaticRtsInfo -> String
statRtsEventlogLib :: FilePath
  , StaticRtsInfo -> String
statRtsThreadedDebugLib :: FilePath
  , StaticRtsInfo -> String
statRtsThreadedEventlogLib :: FilePath
  , StaticRtsInfo -> String
statRtsProfilingLib :: FilePath
  , StaticRtsInfo -> String
statRtsThreadedProfilingLib :: FilePath
  }

data RtsInfo = RtsInfo
  { RtsInfo -> DynamicRtsInfo
rtsDynamicInfo :: DynamicRtsInfo
  , RtsInfo -> StaticRtsInfo
rtsStaticInfo :: StaticRtsInfo
  , RtsInfo -> [String]
rtsLibPaths :: [FilePath]
  }

-- | Extract (and compute) information about the RTS library
--
-- TODO: This hardcodes the name as @HSrts-ghc<version>@. I don't know if we can
-- find this information somewhere. We can lookup the 'hsLibraries' field of
-- 'InstalledPackageInfo' but it will tell us @["HSrts", "Cffi"]@, which
-- doesn't really help.
extractRtsInfo :: LocalBuildInfo -> RtsInfo
extractRtsInfo :: LocalBuildInfo -> RtsInfo
extractRtsInfo LocalBuildInfo
lbi =
  case InstalledPackageIndex
-> PackageName -> [(Version, [InstalledPackageInfo])]
forall a. PackageIndex a -> PackageName -> [(Version, [a])]
PackageIndex.lookupPackageName
    (LocalBuildInfo -> InstalledPackageIndex
installedPkgs LocalBuildInfo
lbi)
    (String -> PackageName
mkPackageName String
"rts") of
    [(Version
_, [InstalledPackageInfo
rts])] -> InstalledPackageInfo -> RtsInfo
aux InstalledPackageInfo
rts
    [(Version, [InstalledPackageInfo])]
_otherwise -> String -> RtsInfo
forall a. HasCallStack => String -> a
error String
"No (or multiple) ghc rts package is registered"
  where
    aux :: InstalledPackageInfo -> RtsInfo
    aux :: InstalledPackageInfo -> RtsInfo
aux InstalledPackageInfo
rts =
      RtsInfo
        { rtsDynamicInfo :: DynamicRtsInfo
rtsDynamicInfo =
            DynamicRtsInfo
              { dynRtsVanillaLib :: String
dynRtsVanillaLib = String -> String
withGhcVersion String
"HSrts"
              , dynRtsThreadedLib :: String
dynRtsThreadedLib = String -> String
withGhcVersion String
"HSrts_thr"
              , dynRtsDebugLib :: String
dynRtsDebugLib = String -> String
withGhcVersion String
"HSrts_debug"
              , dynRtsEventlogLib :: String
dynRtsEventlogLib = String -> String
withGhcVersion String
"HSrts_l"
              , dynRtsThreadedDebugLib :: String
dynRtsThreadedDebugLib = String -> String
withGhcVersion String
"HSrts_thr_debug"
              , dynRtsThreadedEventlogLib :: String
dynRtsThreadedEventlogLib = String -> String
withGhcVersion String
"HSrts_thr_l"
              }
        , rtsStaticInfo :: StaticRtsInfo
rtsStaticInfo =
            StaticRtsInfo
              { statRtsVanillaLib :: String
statRtsVanillaLib = String
"HSrts"
              , statRtsThreadedLib :: String
statRtsThreadedLib = String
"HSrts_thr"
              , statRtsDebugLib :: String
statRtsDebugLib = String
"HSrts_debug"
              , statRtsEventlogLib :: String
statRtsEventlogLib = String
"HSrts_l"
              , statRtsThreadedDebugLib :: String
statRtsThreadedDebugLib = String
"HSrts_thr_debug"
              , statRtsThreadedEventlogLib :: String
statRtsThreadedEventlogLib = String
"HSrts_thr_l"
              , statRtsProfilingLib :: String
statRtsProfilingLib = String
"HSrts_p"
              , statRtsThreadedProfilingLib :: String
statRtsThreadedProfilingLib = String
"HSrts_thr_p"
              }
        , rtsLibPaths :: [String]
rtsLibPaths = InstalledPackageInfo -> [String]
InstalledPackageInfo.libraryDirs InstalledPackageInfo
rts
        }
    withGhcVersion :: String -> String
withGhcVersion = (String -> String -> String
forall a. [a] -> [a] -> [a]
++ (String
"-ghc" String -> String -> String
forall a. [a] -> [a] -> [a]
++ Version -> String
forall a. Pretty a => a -> String
prettyShow (Compiler -> Version
compilerVersion (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi))))

-- | Returns True if the modification date of the given source file is newer than
-- the object file we last compiled for it, or if no object file exists yet.
checkNeedsRecompilation :: FilePath -> GhcOptions -> IO Bool
checkNeedsRecompilation :: String -> GhcOptions -> IO Bool
checkNeedsRecompilation String
filename GhcOptions
opts = String
filename String -> String -> IO Bool
`moreRecentFile` String
oname
  where
    oname :: String
oname = String -> GhcOptions -> String
getObjectFileName String
filename GhcOptions
opts

-- | Finds the object file name of the given source file
getObjectFileName :: FilePath -> GhcOptions -> FilePath
getObjectFileName :: String -> GhcOptions -> String
getObjectFileName String
filename GhcOptions
opts = String
oname
  where
    odir :: String
odir = Flag String -> String
forall a. WithCallStack (Flag a -> a)
fromFlag (GhcOptions -> Flag String
ghcOptObjDir GhcOptions
opts)
    oext :: String
oext = String -> Flag String -> String
forall a. a -> Flag a -> a
fromFlagOrDefault String
"o" (GhcOptions -> Flag String
ghcOptObjSuffix GhcOptions
opts)
    oname :: String
oname = String
odir String -> String -> String
</> String -> String -> String
replaceExtension String
filename String
oext

-- | Calculate the RPATHs for the component we are building.
--
-- Calculates relative RPATHs when 'relocatable' is set.
getRPaths
  :: LocalBuildInfo
  -> ComponentLocalBuildInfo
  -- ^ Component we are building
  -> IO (NubListR FilePath)
getRPaths :: LocalBuildInfo -> ComponentLocalBuildInfo -> IO (NubListR String)
getRPaths LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi | OS -> Bool
supportRPaths OS
hostOS = do
  [String]
libraryPaths <- Bool
-> Bool -> LocalBuildInfo -> ComponentLocalBuildInfo -> IO [String]
depLibraryPaths Bool
False (LocalBuildInfo -> Bool
relocatable LocalBuildInfo
lbi) LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi
  let hostPref :: String
hostPref = case OS
hostOS of
        OS
OSX -> String
"@loader_path"
        OS
_ -> String
"$ORIGIN"
      relPath :: String -> String
relPath String
p = if String -> Bool
isRelative String
p then String
hostPref String -> String -> String
</> String
p else String
p
      rpaths :: NubListR String
rpaths = [String] -> NubListR String
forall a. Ord a => [a] -> NubListR a
toNubListR ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
relPath [String]
libraryPaths)
  NubListR String -> IO (NubListR String)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return NubListR String
rpaths
  where
    (Platform Arch
_ OS
hostOS) = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
    compid :: CompilerId
compid = Compiler -> CompilerId
compilerId (Compiler -> CompilerId)
-> (LocalBuildInfo -> Compiler) -> LocalBuildInfo -> CompilerId
forall b c a. (b -> c) -> (a -> b) -> a -> c
. LocalBuildInfo -> Compiler
compiler (LocalBuildInfo -> CompilerId) -> LocalBuildInfo -> CompilerId
forall a b. (a -> b) -> a -> b
$ LocalBuildInfo
lbi

    -- The list of RPath-supported operating systems below reflects the
    -- platforms on which Cabal's RPATH handling is tested. It does _NOT_
    -- reflect whether the OS supports RPATH.

    -- E.g. when this comment was written, the *BSD operating systems were
    -- untested with regards to Cabal RPATH handling, and were hence set to
    -- 'False', while those operating systems themselves do support RPATH.
    supportRPaths :: OS -> Bool
supportRPaths OS
Linux = Bool
True
    supportRPaths OS
Windows = Bool
False
    supportRPaths OS
OSX = Bool
True
    supportRPaths OS
FreeBSD =
      case CompilerId
compid of
        CompilerId CompilerFlavor
GHC Version
ver | Version
ver Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int] -> Version
mkVersion [Int
7, Int
10, Int
2] -> Bool
True
        CompilerId
_ -> Bool
False
    supportRPaths OS
OpenBSD = Bool
False
    supportRPaths OS
NetBSD = Bool
False
    supportRPaths OS
DragonFly = Bool
False
    supportRPaths OS
Solaris = Bool
False
    supportRPaths OS
AIX = Bool
False
    supportRPaths OS
HPUX = Bool
False
    supportRPaths OS
IRIX = Bool
False
    supportRPaths OS
HaLVM = Bool
False
    supportRPaths OS
IOS = Bool
False
    supportRPaths OS
Android = Bool
False
    supportRPaths OS
Ghcjs = Bool
False
    supportRPaths OS
Wasi = Bool
False
    supportRPaths OS
Hurd = Bool
False
    supportRPaths OS
Haiku = Bool
False
    supportRPaths (OtherOS String
_) = Bool
False
-- Do _not_ add a default case so that we get a warning here when a new OS
-- is added.

getRPaths LocalBuildInfo
_ ComponentLocalBuildInfo
_ = NubListR String -> IO (NubListR String)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return NubListR String
forall a. Monoid a => a
mempty

-- | Determine whether the given 'BuildInfo' is intended to link against the
-- threaded RTS. This is used to determine which RTS to link against when
-- building a foreign library with a GHC without support for @-flink-rts@.
hasThreaded :: BuildInfo -> Bool
hasThreaded :: BuildInfo -> Bool
hasThreaded BuildInfo
bi = String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
elem String
"-threaded" [String]
ghc
  where
    PerCompilerFlavor [String]
ghc [String]
_ = BuildInfo -> PerCompilerFlavor [String]
options BuildInfo
bi

-- | Extracts a String representing a hash of the ABI of a built
-- library.  It can fail if the library has not yet been built.
libAbiHash
  :: Verbosity
  -> PackageDescription
  -> LocalBuildInfo
  -> Library
  -> ComponentLocalBuildInfo
  -> IO String
libAbiHash :: Verbosity
-> PackageDescription
-> LocalBuildInfo
-> Library
-> ComponentLocalBuildInfo
-> IO String
libAbiHash Verbosity
verbosity PackageDescription
_pkg_descr LocalBuildInfo
lbi Library
lib ComponentLocalBuildInfo
clbi = do
  let
    libBi :: BuildInfo
libBi = Library -> BuildInfo
libBuildInfo Library
lib
    comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi
    platform :: Platform
platform = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
    vanillaArgs0 :: GhcOptions
vanillaArgs0 =
      (Verbosity
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> GhcOptions
componentGhcOptions Verbosity
verbosity LocalBuildInfo
lbi BuildInfo
libBi ComponentLocalBuildInfo
clbi (LocalBuildInfo -> ComponentLocalBuildInfo -> String
componentBuildDir LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi))
        GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptMode = toFlag GhcModeAbiHash
          , ghcOptInputModules = toNubListR $ exposedModules lib
          }
    vanillaArgs :: GhcOptions
vanillaArgs =
      -- Package DBs unnecessary, and break ghc-cabal. See #3633
      -- BUT, put at least the global database so that 7.4 doesn't
      -- break.
      GhcOptions
vanillaArgs0
        { ghcOptPackageDBs = [GlobalPackageDB]
        , ghcOptPackages = mempty
        }
    sharedArgs :: GhcOptions
sharedArgs =
      GhcOptions
vanillaArgs
        GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptDynLinkMode = toFlag GhcDynamicOnly
          , ghcOptFPic = toFlag True
          , ghcOptHiSuffix = toFlag "dyn_hi"
          , ghcOptObjSuffix = toFlag "dyn_o"
          , ghcOptExtra = hcSharedOptions GHC libBi
          }
    profArgs :: GhcOptions
profArgs =
      GhcOptions
vanillaArgs
        GhcOptions -> GhcOptions -> GhcOptions
forall a. Monoid a => a -> a -> a
`mappend` GhcOptions
forall a. Monoid a => a
mempty
          { ghcOptProfilingMode = toFlag True
          , ghcOptProfilingAuto =
              Internal.profDetailLevelFlag
                True
                (withProfLibDetail lbi)
          , ghcOptHiSuffix = toFlag "p_hi"
          , ghcOptObjSuffix = toFlag "p_o"
          , ghcOptExtra = hcProfOptions GHC libBi
          }
    ghcArgs :: GhcOptions
ghcArgs
      | LocalBuildInfo -> Bool
withVanillaLib LocalBuildInfo
lbi = GhcOptions
vanillaArgs
      | LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi = GhcOptions
sharedArgs
      | LocalBuildInfo -> Bool
withProfLib LocalBuildInfo
lbi = GhcOptions
profArgs
      | Bool
otherwise = String -> GhcOptions
forall a. HasCallStack => String -> a
error String
"libAbiHash: Can't find an enabled library way"

  (ConfiguredProgram
ghcProg, ProgramDb
_) <- Verbosity
-> Program -> ProgramDb -> IO (ConfiguredProgram, ProgramDb)
requireProgram Verbosity
verbosity Program
ghcProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
  String
hash <-
    Verbosity -> ProgramInvocation -> IO String
getProgramInvocationOutput
      Verbosity
verbosity
      (ConfiguredProgram
-> Compiler -> Platform -> GhcOptions -> ProgramInvocation
ghcInvocation ConfiguredProgram
ghcProg Compiler
comp Platform
platform GhcOptions
ghcArgs)
  String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ((Char -> Bool) -> String -> String
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) String
hash)

componentGhcOptions
  :: Verbosity
  -> LocalBuildInfo
  -> BuildInfo
  -> ComponentLocalBuildInfo
  -> FilePath
  -> GhcOptions
componentGhcOptions :: Verbosity
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> GhcOptions
componentGhcOptions Verbosity
verbosity LocalBuildInfo
lbi =
  Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> GhcOptions
Internal.componentGhcOptions Verbosity
verbosity GhcImplInfo
implInfo LocalBuildInfo
lbi
  where
    comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi
    implInfo :: GhcImplInfo
implInfo = Compiler -> GhcImplInfo
getImplInfo Compiler
comp

componentCcGhcOptions
  :: Verbosity
  -> LocalBuildInfo
  -> BuildInfo
  -> ComponentLocalBuildInfo
  -> FilePath
  -> FilePath
  -> GhcOptions
componentCcGhcOptions :: Verbosity
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
componentCcGhcOptions Verbosity
verbosity LocalBuildInfo
lbi =
  Verbosity
-> GhcImplInfo
-> LocalBuildInfo
-> BuildInfo
-> ComponentLocalBuildInfo
-> String
-> String
-> GhcOptions
Internal.componentCcGhcOptions Verbosity
verbosity GhcImplInfo
implInfo LocalBuildInfo
lbi
  where
    comp :: Compiler
comp = LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi
    implInfo :: GhcImplInfo
implInfo = Compiler -> GhcImplInfo
getImplInfo Compiler
comp

-- -----------------------------------------------------------------------------
-- Installing

-- | Install executables for GHC.
installExe
  :: Verbosity
  -> LocalBuildInfo
  -> FilePath
  -- ^ Where to copy the files to
  -> FilePath
  -- ^ Build location
  -> (FilePath, FilePath)
  -- ^ Executable (prefix,suffix)
  -> PackageDescription
  -> Executable
  -> IO ()
installExe :: Verbosity
-> LocalBuildInfo
-> String
-> String
-> (String, String)
-> PackageDescription
-> Executable
-> IO ()
installExe
  Verbosity
verbosity
  LocalBuildInfo
lbi
  String
binDir
  String
buildPref
  (String
progprefix, String
progsuffix)
  PackageDescription
_pkg
  Executable
exe = do
    Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
binDir
    let exeName' :: String
exeName' = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ Executable -> UnqualComponentName
exeName Executable
exe
        exeFileName :: String
exeFileName = Platform -> Executable -> String
exeTargetName (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi) Executable
exe
        fixedExeBaseName :: String
fixedExeBaseName = String
progprefix String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
exeName' String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
progsuffix
        installBinary :: String -> IO ()
installBinary String
dest = do
          Verbosity -> String -> String -> IO ()
installExecutableFile
            Verbosity
verbosity
            (String
buildPref String -> String -> String
</> String
exeName' String -> String -> String
</> String
exeFileName)
            (String
dest String -> String -> String
<.> Platform -> String
exeExtension (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi))
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LocalBuildInfo -> Bool
stripExes LocalBuildInfo
lbi) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
            Verbosity -> Platform -> ProgramDb -> String -> IO ()
Strip.stripExe
              Verbosity
verbosity
              (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi)
              (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
              (String
dest String -> String -> String
<.> Platform -> String
exeExtension (LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi))
    String -> IO ()
installBinary (String
binDir String -> String -> String
</> String
fixedExeBaseName)

-- | Install foreign library for GHC.
installFLib
  :: Verbosity
  -> LocalBuildInfo
  -> FilePath
  -- ^ install location
  -> FilePath
  -- ^ Build location
  -> PackageDescription
  -> ForeignLib
  -> IO ()
installFLib :: Verbosity
-> LocalBuildInfo
-> String
-> String
-> PackageDescription
-> ForeignLib
-> IO ()
installFLib Verbosity
verbosity LocalBuildInfo
lbi String
targetDir String
builtDir PackageDescription
_pkg ForeignLib
flib =
  Bool -> String -> String -> String -> IO ()
install
    (ForeignLib -> Bool
foreignLibIsShared ForeignLib
flib)
    String
builtDir
    String
targetDir
    (LocalBuildInfo -> ForeignLib -> String
flibTargetName LocalBuildInfo
lbi ForeignLib
flib)
  where
    install :: Bool -> String -> String -> String -> IO ()
install Bool
isShared String
srcDir String
dstDir String
name = do
      let src :: String
src = String
srcDir String -> String -> String
</> String
name
          dst :: String
dst = String
dstDir String -> String -> String
</> String
name
      Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
targetDir
      -- TODO: Should we strip? (stripLibs lbi)
      if Bool
isShared
        then Verbosity -> String -> String -> IO ()
installExecutableFile Verbosity
verbosity String
src String
dst
        else Verbosity -> String -> String -> IO ()
installOrdinaryFile Verbosity
verbosity String
src String
dst
      -- Now install appropriate symlinks if library is versioned
      let (Platform Arch
_ OS
os) = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not ([Int] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (ForeignLib -> OS -> [Int]
foreignLibVersion ForeignLib
flib OS
os))) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (OS
os OS -> OS -> Bool
forall a. Eq a => a -> a -> Bool
/= 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
            -- It should be impossible to get here.
            String
"Can't install foreign-library symlink on non-Linux OS"
#ifndef mingw32_HOST_OS
        -- 'createSymbolicLink file1 file2' creates a symbolic link
        -- named 'file2' which points to the file 'file1'.
        -- Note that we do want a symlink to 'name' rather than
        -- 'dst', because the symlink will be relative to the
        -- directory it's created in.
        -- Finally, we first create the symlinks in a temporary
        -- directory and then rename to simulate 'ln --force'.
        Verbosity -> String -> String -> (String -> IO ()) -> IO ()
forall a. Verbosity -> String -> String -> (String -> IO a) -> IO a
withTempDirectory Verbosity
verbosity String
dstDir String
nm ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
tmpDir -> do
            let link1 :: String
link1 = LocalBuildInfo -> ForeignLib -> String
flibBuildName LocalBuildInfo
lbi ForeignLib
flib
                link2 :: String
link2 = String
"lib" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
nm String -> String -> String
<.> String
"so"
            String -> String -> IO ()
createSymbolicLink String
name (String
tmpDir String -> String -> String
</> String
link1)
            String -> String -> IO ()
renameFile (String
tmpDir String -> String -> String
</> String
link1) (String
dstDir String -> String -> String
</> String
link1)
            String -> String -> IO ()
createSymbolicLink String
name (String
tmpDir String -> String -> String
</> String
link2)
            String -> String -> IO ()
renameFile (String
tmpDir String -> String -> String
</> String
link2) (String
dstDir String -> String -> String
</> String
link2)
      where
        nm :: String
        nm :: String
nm = UnqualComponentName -> String
unUnqualComponentName (UnqualComponentName -> String) -> UnqualComponentName -> String
forall a b. (a -> b) -> a -> b
$ ForeignLib -> UnqualComponentName
foreignLibName ForeignLib
flib
#endif /* mingw32_HOST_OS */

-- | Install for ghc, .hi, .a and, if --with-ghci given, .o
installLib
  :: Verbosity
  -> LocalBuildInfo
  -> FilePath
  -- ^ install location
  -> FilePath
  -- ^ install location for dynamic libraries
  -> FilePath
  -- ^ Build location
  -> PackageDescription
  -> Library
  -> ComponentLocalBuildInfo
  -> IO ()
installLib :: Verbosity
-> LocalBuildInfo
-> String
-> String
-> String
-> PackageDescription
-> Library
-> ComponentLocalBuildInfo
-> IO ()
installLib Verbosity
verbosity LocalBuildInfo
lbi String
targetDir String
dynlibTargetDir String
_builtDir PackageDescription
pkg Library
lib ComponentLocalBuildInfo
clbi = do
  -- copy .hi files over:
  IO () -> IO ()
whenVanilla (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
copyModuleFiles String
"hi"
  IO () -> IO ()
whenProf (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
copyModuleFiles String
"p_hi"
  IO () -> IO ()
whenShared (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
copyModuleFiles String
"dyn_hi"

  -- copy extra compilation artifacts that ghc plugins may produce
  String -> IO ()
copyDirectoryIfExists String
"extra-compilation-artifacts"

  -- copy the built library files over:
  IO () -> IO ()
whenHasCode (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    IO () -> IO ()
whenVanilla (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
        [ String -> String -> String -> IO ()
installOrdinary
          String
builtDir
          String
targetDir
          (String -> String
mkGenericStaticLibName (String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f))
        | String
l <-
            UnitId -> String
getHSLibraryName
              (ComponentLocalBuildInfo -> UnitId
componentUnitId ComponentLocalBuildInfo
clbi)
              String -> [String] -> [String]
forall a. a -> [a] -> [a]
: (BuildInfo -> [String]
extraBundledLibs (Library -> BuildInfo
libBuildInfo Library
lib))
        , String
f <- String
"" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
extraLibFlavours (Library -> BuildInfo
libBuildInfo Library
lib)
        ]
      IO () -> IO ()
whenGHCi (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> String -> String -> IO ()
installOrdinary String
builtDir String
targetDir String
ghciLibName
    IO () -> IO ()
whenProf (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
      String -> String -> String -> IO ()
installOrdinary String
builtDir String
targetDir String
profileLibName
      IO () -> IO ()
whenGHCi (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> String -> String -> IO ()
installOrdinary String
builtDir String
targetDir String
ghciProfLibName
    IO () -> IO ()
whenShared (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
      if
          -- The behavior for "extra-bundled-libraries" changed in version 2.5.0.
          -- See ghc issue #15837 and Cabal PR #5855.
          | PackageDescription -> CabalSpecVersion
specVersion PackageDescription
pkg CabalSpecVersion -> CabalSpecVersion -> Bool
forall a. Ord a => a -> a -> Bool
< CabalSpecVersion
CabalSpecV3_0 -> do
              [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
                [ String -> String -> String -> IO ()
installShared
                  String
builtDir
                  String
dynlibTargetDir
                  (Platform -> CompilerId -> String -> String
mkGenericSharedLibName Platform
platform CompilerId
compiler_id (String
l String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f))
                | String
l <- UnitId -> String
getHSLibraryName UnitId
uid String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
extraBundledLibs (Library -> BuildInfo
libBuildInfo Library
lib)
                , String
f <- String
"" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
extraDynLibFlavours (Library -> BuildInfo
libBuildInfo Library
lib)
                ]
          | Bool
otherwise -> do
              [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
                [ String -> String -> String -> IO ()
installShared
                  String
builtDir
                  String
dynlibTargetDir
                  ( Platform -> CompilerId -> String -> String
mkGenericSharedLibName
                      Platform
platform
                      CompilerId
compiler_id
                      (UnitId -> String
getHSLibraryName UnitId
uid String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
f)
                  )
                | String
f <- String
"" String -> [String] -> [String]
forall a. a -> [a] -> [a]
: BuildInfo -> [String]
extraDynLibFlavours (Library -> BuildInfo
libBuildInfo Library
lib)
                ]
              [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, Monad m) =>
t (m a) -> m ()
sequence_
                [ do
                  [String]
files <- String -> IO [String]
getDirectoryContents String
builtDir
                  let l' :: String
l' =
                        Platform -> CompilerId -> String -> String
mkGenericSharedBundledLibName
                          Platform
platform
                          CompilerId
compiler_id
                          String
l
                  [String] -> (String -> IO ()) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [String]
files ((String -> IO ()) -> IO ()) -> (String -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \String
file ->
                    Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (String
l' String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
file) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                      Bool
isFile <- String -> IO Bool
doesFileExist (String
builtDir String -> String -> String
</> String
file)
                      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
isFile (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
                        String -> String -> String -> IO ()
installShared
                          String
builtDir
                          String
dynlibTargetDir
                          String
file
                | String
l <- BuildInfo -> [String]
extraBundledLibs (Library -> BuildInfo
libBuildInfo Library
lib)
                ]
  where
    builtDir :: String
builtDir = LocalBuildInfo -> ComponentLocalBuildInfo -> String
componentBuildDir LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi

    install :: Bool -> String -> String -> String -> IO ()
install Bool
isShared String
srcDir String
dstDir String
name = do
      let src :: String
src = String
srcDir String -> String -> String
</> String
name
          dst :: String
dst = String
dstDir String -> String -> String
</> String
name

      Verbosity -> Bool -> String -> IO ()
createDirectoryIfMissingVerbose Verbosity
verbosity Bool
True String
dstDir

      if Bool
isShared
        then Verbosity -> String -> String -> IO ()
installExecutableFile Verbosity
verbosity String
src String
dst
        else Verbosity -> String -> String -> IO ()
installOrdinaryFile Verbosity
verbosity String
src String
dst

      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (LocalBuildInfo -> Bool
stripLibs LocalBuildInfo
lbi) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
        Verbosity -> Platform -> ProgramDb -> String -> IO ()
Strip.stripLib
          Verbosity
verbosity
          Platform
platform
          (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
          String
dst

    installOrdinary :: String -> String -> String -> IO ()
installOrdinary = Bool -> String -> String -> String -> IO ()
install Bool
False
    installShared :: String -> String -> String -> IO ()
installShared = Bool -> String -> String -> String -> IO ()
install Bool
True

    copyModuleFiles :: String -> IO ()
copyModuleFiles String
ext =
      Verbosity
-> [String] -> [String] -> [ModuleName] -> IO [(String, String)]
findModuleFilesEx Verbosity
verbosity [String
builtDir] [String
ext] (Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi)
        IO [(String, String)] -> ([(String, String)] -> IO ()) -> IO ()
forall a b. IO a -> (a -> IO b) -> IO b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Verbosity -> String -> [(String, String)] -> IO ()
installOrdinaryFiles Verbosity
verbosity String
targetDir

    copyDirectoryIfExists :: String -> IO ()
copyDirectoryIfExists String
dirName = do
      let src :: String
src = String
builtDir String -> String -> String
</> String
dirName
          dst :: String
dst = String
targetDir String -> String -> String
</> String
dirName
      Bool
dirExists <- String -> IO Bool
doesDirectoryExist String
src
      Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
dirExists (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Verbosity -> String -> String -> IO ()
copyDirectoryRecursive Verbosity
verbosity String
src String
dst

    compiler_id :: CompilerId
compiler_id = Compiler -> CompilerId
compilerId (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi)
    platform :: Platform
platform = LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi
    uid :: UnitId
uid = ComponentLocalBuildInfo -> UnitId
componentUnitId ComponentLocalBuildInfo
clbi
    profileLibName :: String
profileLibName = UnitId -> String
mkProfLibName UnitId
uid
    ghciLibName :: String
ghciLibName = UnitId -> String
Internal.mkGHCiLibName UnitId
uid
    ghciProfLibName :: String
ghciProfLibName = UnitId -> String
Internal.mkGHCiProfLibName UnitId
uid

    hasLib :: Bool
hasLib =
      Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$
        [ModuleName] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (Library -> ComponentLocalBuildInfo -> [ModuleName]
allLibModules Library
lib ComponentLocalBuildInfo
clbi)
          Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cSources (Library -> BuildInfo
libBuildInfo Library
lib))
          Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cxxSources (Library -> BuildInfo
libBuildInfo Library
lib))
          Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
cmmSources (Library -> BuildInfo
libBuildInfo Library
lib))
          Bool -> Bool -> Bool
&& [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
asmSources (Library -> BuildInfo
libBuildInfo Library
lib))
          Bool -> Bool -> Bool
&& ([String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null (BuildInfo -> [String]
jsSources (Library -> BuildInfo
libBuildInfo Library
lib)) Bool -> Bool -> Bool
|| Bool -> Bool
not Bool
hasJsSupport)
    hasJsSupport :: Bool
hasJsSupport = case LocalBuildInfo -> Platform
hostPlatform LocalBuildInfo
lbi of
      Platform Arch
JavaScript OS
_ -> Bool
True
      Platform
_ -> Bool
False
    has_code :: Bool
has_code = Bool -> Bool
not (ComponentLocalBuildInfo -> Bool
componentIsIndefinite ComponentLocalBuildInfo
clbi)
    whenHasCode :: IO () -> IO ()
whenHasCode = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
has_code
    whenVanilla :: IO () -> IO ()
whenVanilla = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
hasLib Bool -> Bool -> Bool
&& LocalBuildInfo -> Bool
withVanillaLib LocalBuildInfo
lbi)
    whenProf :: IO () -> IO ()
whenProf = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
hasLib Bool -> Bool -> Bool
&& LocalBuildInfo -> Bool
withProfLib LocalBuildInfo
lbi Bool -> Bool -> Bool
&& Bool
has_code)
    whenGHCi :: IO () -> IO ()
whenGHCi = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
hasLib Bool -> Bool -> Bool
&& LocalBuildInfo -> Bool
withGHCiLib LocalBuildInfo
lbi Bool -> Bool -> Bool
&& Bool
has_code)
    whenShared :: IO () -> IO ()
whenShared = Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool
hasLib Bool -> Bool -> Bool
&& LocalBuildInfo -> Bool
withSharedLib LocalBuildInfo
lbi Bool -> Bool -> Bool
&& Bool
has_code)

-- -----------------------------------------------------------------------------
-- Registering

hcPkgInfo :: ProgramDb -> HcPkg.HcPkgInfo
hcPkgInfo :: ProgramDb -> HcPkgInfo
hcPkgInfo ProgramDb
progdb =
  HcPkg.HcPkgInfo
    { hcPkgProgram :: ConfiguredProgram
HcPkg.hcPkgProgram = ConfiguredProgram
ghcPkgProg
    , noPkgDbStack :: Bool
HcPkg.noPkgDbStack = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
< [Int
6, Int
9]
    , noVerboseFlag :: Bool
HcPkg.noVerboseFlag = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
< [Int
6, Int
11]
    , flagPackageConf :: Bool
HcPkg.flagPackageConf = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
< [Int
7, Int
5]
    , supportsDirDbs :: Bool
HcPkg.supportsDirDbs = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int
6, Int
8]
    , requiresDirDbs :: Bool
HcPkg.requiresDirDbs = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int
7, Int
10]
    , nativeMultiInstance :: Bool
HcPkg.nativeMultiInstance = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int
7, Int
10]
    , recacheMultiInstance :: Bool
HcPkg.recacheMultiInstance = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int
6, Int
12]
    , suppressFilesCheck :: Bool
HcPkg.suppressFilesCheck = [Int]
v [Int] -> [Int] -> Bool
forall a. Ord a => a -> a -> Bool
>= [Int
6, Int
6]
    }
  where
    v :: [Int]
v = Version -> [Int]
versionNumbers Version
ver
    ghcPkgProg :: ConfiguredProgram
ghcPkgProg = ConfiguredProgram -> Maybe ConfiguredProgram -> ConfiguredProgram
forall a. a -> Maybe a -> a
fromMaybe (String -> ConfiguredProgram
forall a. HasCallStack => String -> a
error String
"GHC.hcPkgInfo: no ghc program") (Maybe ConfiguredProgram -> ConfiguredProgram)
-> Maybe ConfiguredProgram -> ConfiguredProgram
forall a b. (a -> b) -> a -> b
$ Program -> ProgramDb -> Maybe ConfiguredProgram
lookupProgram Program
ghcPkgProgram ProgramDb
progdb
    ver :: Version
ver = Version -> Maybe Version -> Version
forall a. a -> Maybe a -> a
fromMaybe (String -> Version
forall a. HasCallStack => String -> a
error String
"GHC.hcPkgInfo: no ghc version") (Maybe Version -> Version) -> Maybe Version -> Version
forall a b. (a -> b) -> a -> b
$ ConfiguredProgram -> Maybe Version
programVersion ConfiguredProgram
ghcPkgProg

registerPackage
  :: Verbosity
  -> ProgramDb
  -> PackageDBStack
  -> InstalledPackageInfo
  -> HcPkg.RegisterOptions
  -> IO ()
registerPackage :: Verbosity
-> ProgramDb
-> [PackageDB]
-> InstalledPackageInfo
-> RegisterOptions
-> IO ()
registerPackage Verbosity
verbosity ProgramDb
progdb [PackageDB]
packageDbs InstalledPackageInfo
installedPkgInfo RegisterOptions
registerOptions =
  HcPkgInfo
-> Verbosity
-> [PackageDB]
-> InstalledPackageInfo
-> RegisterOptions
-> IO ()
HcPkg.register
    (ProgramDb -> HcPkgInfo
hcPkgInfo ProgramDb
progdb)
    Verbosity
verbosity
    [PackageDB]
packageDbs
    InstalledPackageInfo
installedPkgInfo
    RegisterOptions
registerOptions

pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO FilePath
pkgRoot :: Verbosity -> LocalBuildInfo -> PackageDB -> IO String
pkgRoot Verbosity
verbosity LocalBuildInfo
lbi = PackageDB -> IO String
pkgRoot'
  where
    pkgRoot' :: PackageDB -> IO String
pkgRoot' PackageDB
GlobalPackageDB =
      let ghcProg :: ConfiguredProgram
ghcProg = ConfiguredProgram -> Maybe ConfiguredProgram -> ConfiguredProgram
forall a. a -> Maybe a -> a
fromMaybe (String -> ConfiguredProgram
forall a. HasCallStack => String -> a
error String
"GHC.pkgRoot: no ghc program") (Maybe ConfiguredProgram -> ConfiguredProgram)
-> Maybe ConfiguredProgram -> ConfiguredProgram
forall a b. (a -> b) -> a -> b
$ Program -> ProgramDb -> Maybe ConfiguredProgram
lookupProgram Program
ghcProgram (LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi)
       in (String -> String) -> IO String -> IO String
forall a b. (a -> b) -> IO a -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> String
takeDirectory (Verbosity -> ConfiguredProgram -> IO String
getGlobalPackageDB Verbosity
verbosity ConfiguredProgram
ghcProg)
    pkgRoot' PackageDB
UserPackageDB = do
      String
appDir <- IO String
getGhcAppDir
      let ver :: Version
ver = Compiler -> Version
compilerVersion (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi)
          subdir :: String
subdir =
            String
System.Info.arch
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
'-'
              Char -> String -> String
forall a. a -> [a] -> [a]
: String
System.Info.os
              String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
'-'
              Char -> String -> String
forall a. a -> [a] -> [a]
: Version -> String
forall a. Pretty a => a -> String
prettyShow Version
ver
          rootDir :: String
rootDir = String
appDir String -> String -> String
</> String
subdir
      -- We must create the root directory for the user package database if it
      -- does not yet exists. Otherwise '${pkgroot}' will resolve to a
      -- directory at the time of 'ghc-pkg register', and registration will
      -- fail.
      Bool -> String -> IO ()
createDirectoryIfMissing Bool
True String
rootDir
      String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return String
rootDir
    pkgRoot' (SpecificPackageDB String
fp) = String -> IO String
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> String
takeDirectory String
fp)

-- -----------------------------------------------------------------------------
-- Utils

isDynamic :: Compiler -> Bool
isDynamic :: Compiler -> Bool
isDynamic = String -> Compiler -> Bool
Internal.ghcLookupProperty String
"GHC Dynamic"

supportsDynamicToo :: Compiler -> Bool
supportsDynamicToo :: Compiler -> Bool
supportsDynamicToo = String -> Compiler -> Bool
Internal.ghcLookupProperty String
"Support dynamic-too"

withExt :: FilePath -> String -> FilePath
withExt :: String -> String -> String
withExt String
fp String
ext = String
fp String -> String -> String
<.> if String -> String
takeExtension String
fp String -> String -> Bool
forall a. Eq a => a -> a -> Bool
/= (Char
'.' Char -> String -> String
forall a. a -> [a] -> [a]
: String
ext) then String
ext else String
""