{-
-----------------------------------------------------------------------------
--
-- (c) The University of Glasgow 2001-2003
--
-- Access to system tools: gcc, cp, rm etc
--
-----------------------------------------------------------------------------
-}

{-# LANGUAGE CPP, MultiWayIf, ScopedTypeVariables #-}

module SysTools (
        -- * Initialisation
        initSysTools,
        initLlvmConfig,

        -- * Interface to system tools
        module SysTools.Tasks,
        module SysTools.Info,

        linkDynLib,

        copy,
        copyWithHeader,

        -- * General utilities
        Option(..),
        expandTopDir,

        -- * Platform-specifics
        libmLinkOpts,

        -- * Mac OS X frameworks
        getPkgFrameworkOpts,
        getFrameworkOpts
 ) where

#include "HsVersions.h"

import GhcPrelude

import Module
import Packages
import Config
import Outputable
import ErrUtils
import Platform
import Util
import DynFlags
import Fingerprint

import System.FilePath
import System.IO
import System.Directory
import SysTools.ExtraObj
import SysTools.Info
import SysTools.Tasks
import SysTools.BaseDir

{-
Note [How GHC finds toolchain utilities]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SysTools.initSysProgs figures out exactly where all the auxiliary programs
are, and initialises mutable variables to make it easy to call them.
To do this, it makes use of definitions in Config.hs, which is a Haskell
file containing variables whose value is figured out by the build system.

Config.hs contains two sorts of things

  cGCC,         The *names* of the programs
  cCPP            e.g.  cGCC = gcc
  cUNLIT                cCPP = gcc -E
  etc           They do *not* include paths


  cUNLIT_DIR   The *path* to the directory containing unlit, split etc
  cSPLIT_DIR   *relative* to the root of the build tree,
                   for use when running *in-place* in a build tree (only)


---------------------------------------------
NOTES for an ALTERNATIVE scheme (i.e *not* what is currently implemented):

Another hair-brained scheme for simplifying the current tool location
nightmare in GHC: Simon originally suggested using another
configuration file along the lines of GCC's specs file - which is fine
except that it means adding code to read yet another configuration
file.  What I didn't notice is that the current package.conf is
general enough to do this:

Package
    {name = "tools",    import_dirs = [],  source_dirs = [],
     library_dirs = [], hs_libraries = [], extra_libraries = [],
     include_dirs = [], c_includes = [],   package_deps = [],
     extra_ghc_opts = ["-pgmc/usr/bin/gcc","-pgml${topdir}/bin/unlit", ... etc.],
     extra_cc_opts = [], extra_ld_opts = []}

Which would have the advantage that we get to collect together in one
place the path-specific package stuff with the path-specific tool
stuff.
                End of NOTES
---------------------------------------------

************************************************************************
*                                                                      *
\subsection{Initialisation}
*                                                                      *
************************************************************************
-}

initLlvmConfig :: String
               -> IO LlvmConfig
initLlvmConfig :: String -> IO LlvmConfig
initLlvmConfig top_dir :: String
top_dir
  = do
      [(String, LlvmTarget)]
targets <- String
-> ((String, String, String) -> LlvmTarget)
-> IO [(String, LlvmTarget)]
forall (f :: * -> *) (f :: * -> *) a b.
(Read (f (f a)), Functor f, Functor f) =>
String -> (a -> b) -> IO (f (f b))
readAndParse "llvm-targets" (String, String, String) -> LlvmTarget
mkLlvmTarget
      [(Int, String)]
passes <- String -> (String -> String) -> IO [(Int, String)]
forall (f :: * -> *) (f :: * -> *) a b.
(Read (f (f a)), Functor f, Functor f) =>
String -> (a -> b) -> IO (f (f b))
readAndParse "llvm-passes" String -> String
forall a. a -> a
id
      LlvmConfig -> IO LlvmConfig
forall (m :: * -> *) a. Monad m => a -> m a
return ([(String, LlvmTarget)]
targets, [(Int, String)]
passes)
  where
    readAndParse :: String -> (a -> b) -> IO (f (f b))
readAndParse name :: String
name builder :: a -> b
builder =
      do let llvmConfigFile :: String
llvmConfigFile = String
top_dir String -> String -> String
</> String
name
         String
llvmConfigStr <- String -> IO String
readFile String
llvmConfigFile
         case String -> Maybe (f (f a))
forall a. Read a => String -> Maybe a
maybeReadFuzzy String
llvmConfigStr of
           Just s :: f (f a)
s -> f (f b) -> IO (f (f b))
forall (m :: * -> *) a. Monad m => a -> m a
return ((a -> b) -> f a -> f b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
builder (f a -> f b) -> f (f a) -> f (f b)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> f (f a)
s)
           Nothing -> String -> IO (f (f b))
forall a. String -> a
pgmError ("Can't parse " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
llvmConfigFile)

    mkLlvmTarget :: (String, String, String) -> LlvmTarget
    mkLlvmTarget :: (String, String, String) -> LlvmTarget
mkLlvmTarget (dl :: String
dl, cpu :: String
cpu, attrs :: String
attrs) = String -> String -> [String] -> LlvmTarget
LlvmTarget String
dl String
cpu (String -> [String]
words String
attrs)


initSysTools :: String          -- TopDir path
             -> IO Settings     -- Set all the mutable variables above, holding
                                --      (a) the system programs
                                --      (b) the package-config file
                                --      (c) the GHC usage message
initSysTools :: String -> IO Settings
initSysTools top_dir :: String
top_dir
  = do       -- see Note [topdir: How GHC finds its files]
             -- NB: top_dir is assumed to be in standard Unix
             -- format, '/' separated
       Maybe String
mtool_dir <- String -> IO (Maybe String)
findToolDir String
top_dir
             -- see Note [tooldir: How GHC finds mingw and perl on Windows]

       let installed :: FilePath -> FilePath
           installed :: String -> String
installed file :: String
file = String
top_dir String -> String -> String
</> String
file
           libexec :: FilePath -> FilePath
           libexec :: String -> String
libexec file :: String
file = String
top_dir String -> String -> String
</> "bin" String -> String -> String
</> String
file
           settingsFile :: String
settingsFile = String -> String
installed "settings"
           platformConstantsFile :: String
platformConstantsFile = String -> String
installed "platformConstants"

       String
settingsStr <- String -> IO String
readFile String
settingsFile
       String
platformConstantsStr <- String -> IO String
readFile String
platformConstantsFile
       [(String, String)]
mySettings <- case String -> Maybe [(String, String)]
forall a. Read a => String -> Maybe a
maybeReadFuzzy String
settingsStr of
                     Just s :: [(String, String)]
s ->
                         [(String, String)] -> IO [(String, String)]
forall (m :: * -> *) a. Monad m => a -> m a
return [(String, String)]
s
                     Nothing ->
                         String -> IO [(String, String)]
forall a. String -> a
pgmError ("Can't parse " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
settingsFile)
       PlatformConstants
platformConstants <- case String -> Maybe PlatformConstants
forall a. Read a => String -> Maybe a
maybeReadFuzzy String
platformConstantsStr of
                            Just s :: PlatformConstants
s ->
                                PlatformConstants -> IO PlatformConstants
forall (m :: * -> *) a. Monad m => a -> m a
return PlatformConstants
s
                            Nothing ->
                                String -> IO PlatformConstants
forall a. String -> a
pgmError ("Can't parse " String -> String -> String
forall a. [a] -> [a] -> [a]
++
                                          String -> String
forall a. Show a => a -> String
show String
platformConstantsFile)
       let getSetting :: String -> m String
getSetting key :: String
key = case String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
key [(String, String)]
mySettings of
                            Just xs :: String
xs -> String -> m String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> m String) -> String -> m String
forall a b. (a -> b) -> a -> b
$ String -> String -> String
expandTopDir String
top_dir String
xs
                            Nothing -> String -> m String
forall a. String -> a
pgmError ("No entry for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ " in " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
settingsFile)
           getToolSetting :: String -> f String
getToolSetting key :: String
key = Maybe String -> String -> String
expandToolDir Maybe String
mtool_dir (String -> String) -> f String -> f String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> f String
forall (m :: * -> *). Monad m => String -> m String
getSetting String
key
           getBooleanSetting :: String -> m Bool
getBooleanSetting key :: String
key = case String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
key [(String, String)]
mySettings of
                                   Just "YES" -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True
                                   Just "NO" -> Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False
                                   Just xs :: String
xs -> String -> m Bool
forall a. String -> a
pgmError ("Bad value for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ ": " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
xs)
                                   Nothing -> String -> m Bool
forall a. String -> a
pgmError ("No entry for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ " in " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
settingsFile)
           readSetting :: String -> m a
readSetting key :: String
key = case String -> [(String, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup String
key [(String, String)]
mySettings of
                             Just xs :: String
xs ->
                                 case String -> Maybe a
forall a. Read a => String -> Maybe a
maybeRead String
xs of
                                 Just v :: a
v -> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
v
                                 Nothing -> String -> m a
forall a. String -> a
pgmError ("Failed to read " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ " value " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
xs)
                             Nothing -> String -> m a
forall a. String -> a
pgmError ("No entry for " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
key String -> String -> String
forall a. [a] -> [a] -> [a]
++ " in " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
forall a. Show a => a -> String
show String
settingsFile)
       Bool
crossCompiling <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "cross compiling"
       Arch
targetArch <- String -> IO Arch
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target arch"
       OS
targetOS <- String -> IO OS
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target os"
       Int
targetWordSize <- String -> IO Int
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target word size"
       Bool
targetUnregisterised <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "Unregisterised"
       Bool
targetHasGnuNonexecStack <- String -> IO Bool
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target has GNU nonexec stack"
       Bool
targetHasIdentDirective <- String -> IO Bool
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target has .ident directive"
       Bool
targetHasSubsectionsViaSymbols <- String -> IO Bool
forall a (m :: * -> *). (Read a, Monad m) => String -> m a
readSetting "target has subsections via symbols"
       String
myExtraGccViaCFlags <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "GCC extra via C opts"
       -- On Windows, mingw is distributed with GHC,
       -- so we look in TopDir/../mingw/bin,
       -- as well as TopDir/../../mingw/bin for hadrian.
       -- It would perhaps be nice to be able to override this
       -- with the settings file, but it would be a little fiddly
       -- to make that possible, so for now you can't.
       String
gcc_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "C compiler command"
       String
gcc_args_str <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "C compiler flags"
       Bool
gccSupportsNoPie <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "C compiler supports -no-pie"
       String
cpp_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "Haskell CPP command"
       String
cpp_args_str <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "Haskell CPP flags"
       let unreg_gcc_args :: [String]
unreg_gcc_args = if Bool
targetUnregisterised
                            then ["-DNO_REGS", "-DUSE_MINIINTERPRETER"]
                            else []
           -- TABLES_NEXT_TO_CODE affects the info table layout.
           tntc_gcc_args :: [String]
tntc_gcc_args
            | Bool -> Bool
mkTablesNextToCode Bool
targetUnregisterised
               = ["-DTABLES_NEXT_TO_CODE"]
            | Bool
otherwise = []
           cpp_args :: [Option]
cpp_args= (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option (String -> [String]
words String
cpp_args_str)
           gcc_args :: [Option]
gcc_args = (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option (String -> [String]
words String
gcc_args_str
                               [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
unreg_gcc_args
                               [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
tntc_gcc_args)
       Bool
ldSupportsCompactUnwind <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "ld supports compact unwind"
       Bool
ldSupportsBuildId       <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "ld supports build-id"
       Bool
ldSupportsFilelist      <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "ld supports filelist"
       Bool
ldIsGnuLd               <- String -> IO Bool
forall (m :: * -> *). Monad m => String -> m Bool
getBooleanSetting "ld is GNU ld"
       String
perl_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "perl command"

       let pkgconfig_path :: String
pkgconfig_path = String -> String
installed "package.conf.d"
           ghc_usage_msg_path :: String
ghc_usage_msg_path  = String -> String
installed "ghc-usage.txt"
           ghci_usage_msg_path :: String
ghci_usage_msg_path = String -> String
installed "ghci-usage.txt"

             -- For all systems, unlit, split, mangle are GHC utilities
             -- architecture-specific stuff is done when building Config.hs
           unlit_path :: String
unlit_path = String -> String
libexec String
cGHC_UNLIT_PGM

             -- split is a Perl script
           split_script :: String
split_script  = String -> String
libexec String
cGHC_SPLIT_PGM

       String
windres_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "windres command"
       String
libtool_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "libtool command"
       String
ar_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "ar command"
       String
ranlib_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "ranlib command"

       String
tmpdir <- IO String
getTemporaryDirectory

       String
touch_path <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "touch command"

       let -- On Win32 we don't want to rely on #!/bin/perl, so we prepend
           -- a call to Perl to get the invocation of split.
           -- On Unix, scripts are invoked using the '#!' method.  Binary
           -- installations of GHC on Unix place the correct line on the
           -- front of the script at installation time, so we don't want
           -- to wire-in our knowledge of $(PERL) on the host system here.
           (split_prog :: String
split_prog,  split_args :: [Option]
split_args)
             | Bool
isWindowsHost = (String
perl_path,    [String -> Option
Option String
split_script])
             | Bool
otherwise     = (String
split_script, [])
       String
mkdll_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getToolSetting "dllwrap command"
       let mkdll_args :: [a]
mkdll_args = []

       -- cpp is derived from gcc on all platforms
       -- HACK, see setPgmP below. We keep 'words' here to remember to fix
       -- Config.hs one day.


       -- Other things being equal, as and ld are simply gcc
       String
gcc_link_args_str <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "C compiler link flags"
       let   as_prog :: String
as_prog  = String
gcc_prog
             as_args :: [Option]
as_args  = [Option]
gcc_args
             ld_prog :: String
ld_prog  = String
gcc_prog
             ld_args :: [Option]
ld_args  = [Option]
gcc_args [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option (String -> [String]
words String
gcc_link_args_str)

       -- We just assume on command line
       String
lc_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "LLVM llc command"
       String
lo_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "LLVM opt command"
       String
lcc_prog <- String -> IO String
forall (m :: * -> *). Monad m => String -> m String
getSetting "LLVM clang command"

       let iserv_prog :: String
iserv_prog = String -> String
libexec "ghc-iserv"

       let platform :: Platform
platform = $WPlatform :: Arch
-> OS -> Int -> Bool -> Bool -> Bool -> Bool -> Bool -> Platform
Platform {
                          platformArch :: Arch
platformArch = Arch
targetArch,
                          platformOS :: OS
platformOS   = OS
targetOS,
                          platformWordSize :: Int
platformWordSize = Int
targetWordSize,
                          platformUnregisterised :: Bool
platformUnregisterised = Bool
targetUnregisterised,
                          platformHasGnuNonexecStack :: Bool
platformHasGnuNonexecStack = Bool
targetHasGnuNonexecStack,
                          platformHasIdentDirective :: Bool
platformHasIdentDirective = Bool
targetHasIdentDirective,
                          platformHasSubsectionsViaSymbols :: Bool
platformHasSubsectionsViaSymbols = Bool
targetHasSubsectionsViaSymbols,
                          platformIsCrossCompiling :: Bool
platformIsCrossCompiling = Bool
crossCompiling
                      }

       Settings -> IO Settings
forall (m :: * -> *) a. Monad m => a -> m a
return (Settings -> IO Settings) -> Settings -> IO Settings
forall a b. (a -> b) -> a -> b
$ Settings :: Platform
-> String
-> String
-> Maybe String
-> String
-> String
-> String
-> String
-> [(String, String)]
-> [String]
-> String
-> Bool
-> Bool
-> Bool
-> Bool
-> Bool
-> String
-> (String, [Option])
-> String
-> (String, [Option])
-> (String, [Option])
-> (String, [Option])
-> (String, [Option])
-> (String, [Option])
-> String
-> String
-> String
-> String
-> String
-> (String, [Option])
-> (String, [Option])
-> (String, [Option])
-> String
-> [String]
-> [String]
-> Fingerprint
-> [String]
-> [String]
-> [String]
-> [String]
-> [String]
-> [String]
-> [String]
-> [String]
-> [String]
-> PlatformConstants
-> Settings
Settings {
                    sTargetPlatform :: Platform
sTargetPlatform = Platform
platform,
                    sTmpDir :: String
sTmpDir         = String -> String
normalise String
tmpdir,
                    sGhcUsagePath :: String
sGhcUsagePath   = String
ghc_usage_msg_path,
                    sGhciUsagePath :: String
sGhciUsagePath  = String
ghci_usage_msg_path,
                    sToolDir :: Maybe String
sToolDir        = Maybe String
mtool_dir,
                    sTopDir :: String
sTopDir         = String
top_dir,
                    sRawSettings :: [(String, String)]
sRawSettings    = [(String, String)]
mySettings,
                    sExtraGccViaCFlags :: [String]
sExtraGccViaCFlags = String -> [String]
words String
myExtraGccViaCFlags,
                    sSystemPackageConfig :: String
sSystemPackageConfig = String
pkgconfig_path,
                    sLdSupportsCompactUnwind :: Bool
sLdSupportsCompactUnwind = Bool
ldSupportsCompactUnwind,
                    sLdSupportsBuildId :: Bool
sLdSupportsBuildId       = Bool
ldSupportsBuildId,
                    sLdSupportsFilelist :: Bool
sLdSupportsFilelist      = Bool
ldSupportsFilelist,
                    sLdIsGnuLd :: Bool
sLdIsGnuLd               = Bool
ldIsGnuLd,
                    sGccSupportsNoPie :: Bool
sGccSupportsNoPie        = Bool
gccSupportsNoPie,
                    sProgramName :: String
sProgramName             = "ghc",
                    sProjectVersion :: String
sProjectVersion          = String
cProjectVersion,
                    sPgm_L :: String
sPgm_L   = String
unlit_path,
                    sPgm_P :: (String, [Option])
sPgm_P   = (String
cpp_prog, [Option]
cpp_args),
                    sPgm_F :: String
sPgm_F   = "",
                    sPgm_c :: (String, [Option])
sPgm_c   = (String
gcc_prog, [Option]
gcc_args),
                    sPgm_s :: (String, [Option])
sPgm_s   = (String
split_prog,[Option]
split_args),
                    sPgm_a :: (String, [Option])
sPgm_a   = (String
as_prog, [Option]
as_args),
                    sPgm_l :: (String, [Option])
sPgm_l   = (String
ld_prog, [Option]
ld_args),
                    sPgm_dll :: (String, [Option])
sPgm_dll = (String
mkdll_prog,[Option]
forall a. [a]
mkdll_args),
                    sPgm_T :: String
sPgm_T   = String
touch_path,
                    sPgm_windres :: String
sPgm_windres = String
windres_path,
                    sPgm_libtool :: String
sPgm_libtool = String
libtool_path,
                    sPgm_ar :: String
sPgm_ar = String
ar_path,
                    sPgm_ranlib :: String
sPgm_ranlib = String
ranlib_path,
                    sPgm_lo :: (String, [Option])
sPgm_lo  = (String
lo_prog,[]),
                    sPgm_lc :: (String, [Option])
sPgm_lc  = (String
lc_prog,[]),
                    sPgm_lcc :: (String, [Option])
sPgm_lcc = (String
lcc_prog,[]),
                    sPgm_i :: String
sPgm_i   = String
iserv_prog,
                    sOpt_L :: [String]
sOpt_L       = [],
                    sOpt_P :: [String]
sOpt_P       = [],
                    sOpt_P_fingerprint :: Fingerprint
sOpt_P_fingerprint = Fingerprint
fingerprint0,
                    sOpt_F :: [String]
sOpt_F       = [],
                    sOpt_c :: [String]
sOpt_c       = [],
                    sOpt_a :: [String]
sOpt_a       = [],
                    sOpt_l :: [String]
sOpt_l       = [],
                    sOpt_windres :: [String]
sOpt_windres = [],
                    sOpt_lcc :: [String]
sOpt_lcc     = [],
                    sOpt_lo :: [String]
sOpt_lo      = [],
                    sOpt_lc :: [String]
sOpt_lc      = [],
                    sOpt_i :: [String]
sOpt_i       = [],
                    sPlatformConstants :: PlatformConstants
sPlatformConstants = PlatformConstants
platformConstants
             }


{- Note [Windows stack usage]

See: Trac #8870 (and #8834 for related info) and #12186

On Windows, occasionally we need to grow the stack. In order to do
this, we would normally just bump the stack pointer - but there's a
catch on Windows.

If the stack pointer is bumped by more than a single page, then the
pages between the initial pointer and the resulting location must be
properly committed by the Windows virtual memory subsystem. This is
only needed in the event we bump by more than one page (i.e 4097 bytes
or more).

Windows compilers solve this by emitting a call to a special function
called _chkstk, which does this committing of the pages for you.

The reason this was causing a segfault was because due to the fact the
new code generator tends to generate larger functions, we needed more
stack space in GHC itself. In the x86 codegen, we needed approximately
~12kb of stack space in one go, which caused the process to segfault,
as the intervening pages were not committed.

GCC can emit such a check for us automatically but only when the flag
-fstack-check is used.

See https://gcc.gnu.org/onlinedocs/gnat_ugn/Stack-Overflow-Checking.html
for more information.

-}

copy :: DynFlags -> String -> FilePath -> FilePath -> IO ()
copy :: DynFlags -> String -> String -> String -> IO ()
copy dflags :: DynFlags
dflags purpose :: String
purpose from :: String
from to :: String
to = DynFlags -> String -> Maybe String -> String -> String -> IO ()
copyWithHeader DynFlags
dflags String
purpose Maybe String
forall a. Maybe a
Nothing String
from String
to

copyWithHeader :: DynFlags -> String -> Maybe String -> FilePath -> FilePath
               -> IO ()
copyWithHeader :: DynFlags -> String -> Maybe String -> String -> String -> IO ()
copyWithHeader dflags :: DynFlags
dflags purpose :: String
purpose maybe_header :: Maybe String
maybe_header from :: String
from to :: String
to = do
  DynFlags -> String -> IO ()
showPass DynFlags
dflags String
purpose

  Handle
hout <- String -> IOMode -> IO Handle
openBinaryFile String
to   IOMode
WriteMode
  Handle
hin  <- String -> IOMode -> IO Handle
openBinaryFile String
from IOMode
ReadMode
  String
ls <- Handle -> IO String
hGetContents Handle
hin -- inefficient, but it'll do for now. ToDo: speed up
  IO () -> (String -> IO ()) -> Maybe String -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) (Handle -> String -> IO ()
header Handle
hout) Maybe String
maybe_header
  Handle -> String -> IO ()
hPutStr Handle
hout String
ls
  Handle -> IO ()
hClose Handle
hout
  Handle -> IO ()
hClose Handle
hin
 where
  -- write the header string in UTF-8.  The header is something like
  --   {-# LINE "foo.hs" #-}
  -- and we want to make sure a Unicode filename isn't mangled.
  header :: Handle -> String -> IO ()
header h :: Handle
h str :: String
str = do
   Handle -> TextEncoding -> IO ()
hSetEncoding Handle
h TextEncoding
utf8
   Handle -> String -> IO ()
hPutStr Handle
h String
str
   Handle -> Bool -> IO ()
hSetBinaryMode Handle
h Bool
True

{-
************************************************************************
*                                                                      *
\subsection{Support code}
*                                                                      *
************************************************************************
-}

linkDynLib :: DynFlags -> [String] -> [InstalledUnitId] -> IO ()
linkDynLib :: DynFlags -> [String] -> [InstalledUnitId] -> IO ()
linkDynLib dflags0 :: DynFlags
dflags0 o_files :: [String]
o_files dep_packages :: [InstalledUnitId]
dep_packages
 = do
    let -- This is a rather ugly hack to fix dynamically linked
        -- GHC on Windows. If GHC is linked with -threaded, then
        -- it links against libHSrts_thr. But if base is linked
        -- against libHSrts, then both end up getting loaded,
        -- and things go wrong. We therefore link the libraries
        -- with the same RTS flags that we link GHC with.
        dflags1 :: DynFlags
dflags1 = if Bool
cGhcThreaded then Way -> DynFlags -> DynFlags
addWay' Way
WayThreaded DynFlags
dflags0
                                  else                     DynFlags
dflags0
        dflags2 :: DynFlags
dflags2 = if Bool
cGhcDebugged then Way -> DynFlags -> DynFlags
addWay' Way
WayDebug DynFlags
dflags1
                                  else                  DynFlags
dflags1
        dflags :: DynFlags
dflags = DynFlags -> DynFlags
updateWays DynFlags
dflags2

        verbFlags :: [String]
verbFlags = DynFlags -> [String]
getVerbFlags DynFlags
dflags
        o_file :: Maybe String
o_file = DynFlags -> Maybe String
outputFile DynFlags
dflags

    [PackageConfig]
pkgs <- DynFlags -> [InstalledUnitId] -> IO [PackageConfig]
getPreloadPackagesAnd DynFlags
dflags [InstalledUnitId]
dep_packages

    let pkg_lib_paths :: [String]
pkg_lib_paths = DynFlags -> [PackageConfig] -> [String]
collectLibraryPaths DynFlags
dflags [PackageConfig]
pkgs
    let pkg_lib_path_opts :: [String]
pkg_lib_path_opts = (String -> [String]) -> [String] -> [String]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap String -> [String]
get_pkg_lib_path_opts [String]
pkg_lib_paths
        get_pkg_lib_path_opts :: String -> [String]
get_pkg_lib_path_opts l :: String
l
         | ( OS -> Bool
osElfTarget (Platform -> OS
platformOS (DynFlags -> Platform
targetPlatform DynFlags
dflags)) Bool -> Bool -> Bool
||
             OS -> Bool
osMachOTarget (Platform -> OS
platformOS (DynFlags -> Platform
targetPlatform DynFlags
dflags)) ) Bool -> Bool -> Bool
&&
           DynFlags -> DynLibLoader
dynLibLoader DynFlags
dflags DynLibLoader -> DynLibLoader -> Bool
forall a. Eq a => a -> a -> Bool
== DynLibLoader
SystemDependent Bool -> Bool -> Bool
&&
           Way
WayDyn Way -> [Way] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` DynFlags -> [Way]
ways DynFlags
dflags
            = ["-L" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
l, "-Xlinker", "-rpath", "-Xlinker", String
l]
              -- See Note [-Xlinker -rpath vs -Wl,-rpath]
         | Bool
otherwise = ["-L" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
l]

    let lib_paths :: [String]
lib_paths = DynFlags -> [String]
libraryPaths DynFlags
dflags
    let lib_path_opts :: [String]
lib_path_opts = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ("-L"String -> String -> String
forall a. [a] -> [a] -> [a]
++) [String]
lib_paths

    -- We don't want to link our dynamic libs against the RTS package,
    -- because the RTS lib comes in several flavours and we want to be
    -- able to pick the flavour when a binary is linked.
    -- On Windows we need to link the RTS import lib as Windows does
    -- not allow undefined symbols.
    -- The RTS library path is still added to the library search path
    -- above in case the RTS is being explicitly linked in (see #3807).
    let platform :: Platform
platform = DynFlags -> Platform
targetPlatform DynFlags
dflags
        os :: OS
os = Platform -> OS
platformOS Platform
platform
        pkgs_no_rts :: [PackageConfig]
pkgs_no_rts = case OS
os of
                      OSMinGW32 ->
                          [PackageConfig]
pkgs
                      _ ->
                          (PackageConfig -> Bool) -> [PackageConfig] -> [PackageConfig]
forall a. (a -> Bool) -> [a] -> [a]
filter ((UnitId -> UnitId -> Bool
forall a. Eq a => a -> a -> Bool
/= UnitId
rtsUnitId) (UnitId -> Bool)
-> (PackageConfig -> UnitId) -> PackageConfig -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageConfig -> UnitId
packageConfigId) [PackageConfig]
pkgs
    let pkg_link_opts :: [String]
pkg_link_opts = let (package_hs_libs :: [String]
package_hs_libs, extra_libs :: [String]
extra_libs, other_flags :: [String]
other_flags) = DynFlags -> [PackageConfig] -> ([String], [String], [String])
collectLinkOpts DynFlags
dflags [PackageConfig]
pkgs_no_rts
                        in  [String]
package_hs_libs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
extra_libs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
other_flags

        -- probably _stub.o files
        -- and last temporary shared object file
    let extra_ld_inputs :: [Option]
extra_ld_inputs = DynFlags -> [Option]
ldInputs DynFlags
dflags

    -- frameworks
    [String]
pkg_framework_opts <- DynFlags -> Platform -> [InstalledUnitId] -> IO [String]
getPkgFrameworkOpts DynFlags
dflags Platform
platform
                                              ((PackageConfig -> InstalledUnitId)
-> [PackageConfig] -> [InstalledUnitId]
forall a b. (a -> b) -> [a] -> [b]
map PackageConfig -> InstalledUnitId
forall compid srcpkgid srcpkgname instunitid unitid modulename mod.
InstalledPackageInfo
  compid srcpkgid srcpkgname instunitid unitid modulename mod
-> instunitid
unitId [PackageConfig]
pkgs)
    let framework_opts :: [String]
framework_opts = DynFlags -> Platform -> [String]
getFrameworkOpts DynFlags
dflags Platform
platform

    case OS
os of
        OSMinGW32 -> do
            -------------------------------------------------------------
            -- Making a DLL
            -------------------------------------------------------------
            let output_fn :: String
output_fn = case Maybe String
o_file of
                            Just s :: String
s -> String
s
                            Nothing -> "HSdll.dll"

            DynFlags -> [Option] -> IO ()
runLink DynFlags
dflags (
                    (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
verbFlags
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-o"
                    , String -> String -> Option
FileOption "" String
output_fn
                    , String -> Option
Option "-shared"
                    ] [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++
                    [ String -> String -> Option
FileOption "-Wl,--out-implib=" (String
output_fn String -> String -> String
forall a. [a] -> [a] -> [a]
++ ".a")
                    | GeneralFlag -> DynFlags -> Bool
gopt GeneralFlag
Opt_SharedImplib DynFlags
dflags
                    ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map (String -> String -> Option
FileOption "") [String]
o_files

                 -- Permit the linker to auto link _symbol to _imp_symbol
                 -- This lets us link against DLLs without needing an "import library"
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [String -> Option
Option "-Wl,--enable-auto-import"]

                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
extra_ld_inputs
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option (
                    [String]
lib_path_opts
                 [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
pkg_lib_path_opts
                 [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
pkg_link_opts
                ))
        _ | OS
os OS -> OS -> Bool
forall a. Eq a => a -> a -> Bool
== OS
OSDarwin -> do
            -------------------------------------------------------------------
            -- Making a darwin dylib
            -------------------------------------------------------------------
            -- About the options used for Darwin:
            -- -dynamiclib
            --   Apple's way of saying -shared
            -- -undefined dynamic_lookup:
            --   Without these options, we'd have to specify the correct
            --   dependencies for each of the dylibs. Note that we could
            --   (and should) do without this for all libraries except
            --   the RTS; all we need to do is to pass the correct
            --   HSfoo_dyn.dylib files to the link command.
            --   This feature requires Mac OS X 10.3 or later; there is
            --   a similar feature, -flat_namespace -undefined suppress,
            --   which works on earlier versions, but it has other
            --   disadvantages.
            -- -single_module
            --   Build the dynamic library as a single "module", i.e. no
            --   dynamic binding nonsense when referring to symbols from
            --   within the library. The NCG assumes that this option is
            --   specified (on i386, at least).
            -- -install_name
            --   Mac OS/X stores the path where a dynamic library is (to
            --   be) installed in the library itself.  It's called the
            --   "install name" of the library. Then any library or
            --   executable that links against it before it's installed
            --   will search for it in its ultimate install location.
            --   By default we set the install name to the absolute path
            --   at build time, but it can be overridden by the
            --   -dylib-install-name option passed to ghc. Cabal does
            --   this.
            -------------------------------------------------------------------

            let output_fn :: String
output_fn = case Maybe String
o_file of { Just s :: String
s -> String
s; Nothing -> "a.out"; }

            String
instName <- case DynFlags -> Maybe String
dylibInstallName DynFlags
dflags of
                Just n :: String
n -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
n
                Nothing -> String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return (String -> IO String) -> String -> IO String
forall a b. (a -> b) -> a -> b
$ "@rpath" String -> String -> String
`combine` (String -> String
takeFileName String
output_fn)
            DynFlags -> [Option] -> IO ()
runLink DynFlags
dflags (
                    (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
verbFlags
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-dynamiclib"
                    , String -> Option
Option "-o"
                    , String -> String -> Option
FileOption "" String
output_fn
                    ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
o_files
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-undefined",
                      String -> Option
Option "dynamic_lookup",
                      String -> Option
Option "-single_module" ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (if Platform -> Arch
platformArch Platform
platform Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
== Arch
ArchX86_64
                     then [ ]
                     else [ String -> Option
Option "-Wl,-read_only_relocs,suppress" ])
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-install_name", String -> Option
Option String
instName ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
lib_path_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
extra_ld_inputs
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
framework_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
pkg_lib_path_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
pkg_link_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
pkg_framework_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-Wl,-dead_strip_dylibs" ]
              )
        _ -> do
            -------------------------------------------------------------------
            -- Making a DSO
            -------------------------------------------------------------------

            let output_fn :: String
output_fn = case Maybe String
o_file of { Just s :: String
s -> String
s; Nothing -> "a.out"; }
                unregisterised :: Bool
unregisterised = Platform -> Bool
platformUnregisterised (DynFlags -> Platform
targetPlatform DynFlags
dflags)
            let bsymbolicFlag :: [String]
bsymbolicFlag = -- we need symbolic linking to resolve
                                -- non-PIC intra-package-relocations for
                                -- performance (where symbolic linking works)
                                -- See Note [-Bsymbolic assumptions by GHC]
                                ["-Wl,-Bsymbolic" | Bool -> Bool
not Bool
unregisterised]

            DynFlags -> [Option] -> IO ()
runLink DynFlags
dflags (
                    (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
verbFlags
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
libmLinkOpts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-o"
                    , String -> String -> Option
FileOption "" String
output_fn
                    ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
o_files
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option "-shared" ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
bsymbolicFlag
                    -- Set the library soname. We use -h rather than -soname as
                    -- Solaris 10 doesn't support the latter:
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [ String -> Option
Option ("-Wl,-h," String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
takeFileName String
output_fn) ]
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
extra_ld_inputs
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
lib_path_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
pkg_lib_path_opts
                 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [String]
pkg_link_opts
              )

-- | Some platforms require that we explicitly link against @libm@ if any
-- math-y things are used (which we assume to include all programs). See #14022.
libmLinkOpts :: [Option]
libmLinkOpts :: [Option]
libmLinkOpts =
#if defined(HAVE_LIBM)
  [String -> Option
Option "-lm"]
#else
  []
#endif

getPkgFrameworkOpts :: DynFlags -> Platform -> [InstalledUnitId] -> IO [String]
getPkgFrameworkOpts :: DynFlags -> Platform -> [InstalledUnitId] -> IO [String]
getPkgFrameworkOpts dflags :: DynFlags
dflags platform :: Platform
platform dep_packages :: [InstalledUnitId]
dep_packages
  | Platform -> Bool
platformUsesFrameworks Platform
platform = do
    [String]
pkg_framework_path_opts <- do
        [String]
pkg_framework_paths <- DynFlags -> [InstalledUnitId] -> IO [String]
getPackageFrameworkPath DynFlags
dflags [InstalledUnitId]
dep_packages
        [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ("-F" String -> String -> String
forall a. [a] -> [a] -> [a]
++) [String]
pkg_framework_paths

    [String]
pkg_framework_opts <- do
        [String]
pkg_frameworks <- DynFlags -> [InstalledUnitId] -> IO [String]
getPackageFrameworks DynFlags
dflags [InstalledUnitId]
dep_packages
        [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ ["-framework", String
fw] | String
fw <- [String]
pkg_frameworks ]

    [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
pkg_framework_path_opts [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
pkg_framework_opts)

  | Bool
otherwise = [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return []

getFrameworkOpts :: DynFlags -> Platform -> [String]
getFrameworkOpts :: DynFlags -> Platform -> [String]
getFrameworkOpts dflags :: DynFlags
dflags platform :: Platform
platform
  | Platform -> Bool
platformUsesFrameworks Platform
platform = [String]
framework_path_opts [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
framework_opts
  | Bool
otherwise = []
  where
    framework_paths :: [String]
framework_paths     = DynFlags -> [String]
frameworkPaths DynFlags
dflags
    framework_path_opts :: [String]
framework_path_opts = (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map ("-F" String -> String -> String
forall a. [a] -> [a] -> [a]
++) [String]
framework_paths

    frameworks :: [String]
frameworks     = DynFlags -> [String]
cmdlineFrameworks DynFlags
dflags
    -- reverse because they're added in reverse order from the cmd line:
    framework_opts :: [String]
framework_opts = [[String]] -> [String]
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [ ["-framework", String
fw]
                            | String
fw <- [String] -> [String]
forall a. [a] -> [a]
reverse [String]
frameworks ]

{-
Note [-Bsymbolic assumptions by GHC]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GHC has a few assumptions about interaction of relocations in NCG and linker:

1. -Bsymbolic resolves internal references when the shared library is linked,
   which is important for performance.
2. When there is a reference to data in a shared library from the main program,
   the runtime linker relocates the data object into the main program using an
   R_*_COPY relocation.
3. If we used -Bsymbolic, then this results in multiple copies of the data
   object, because some references have already been resolved to point to the
   original instance. This is bad!

We work around [3.] for native compiled code by avoiding the generation of
R_*_COPY relocations.

Unregisterised compiler can't evade R_*_COPY relocations easily thus we disable
-Bsymbolic linking there.

See related Trac tickets: #4210, #15338
-}