{-# LANGUAGE ScopedTypeVariables #-}
module SysTools.Info where
import Exception
import ErrUtils
import DynFlags
import Outputable
import Util
import Data.List
import Data.IORef
import System.IO
import Platform
import GhcPrelude
import SysTools.Process
neededLinkArgs :: LinkerInfo -> [Option]
neededLinkArgs :: LinkerInfo -> [Option]
neededLinkArgs (GnuLD o :: [Option]
o) = [Option]
o
neededLinkArgs (GnuGold o :: [Option]
o) = [Option]
o
neededLinkArgs (LlvmLLD o :: [Option]
o) = [Option]
o
neededLinkArgs (DarwinLD o :: [Option]
o) = [Option]
o
neededLinkArgs (SolarisLD o :: [Option]
o) = [Option]
o
neededLinkArgs (AixLD o :: [Option]
o) = [Option]
o
neededLinkArgs UnknownLD = []
getLinkerInfo :: DynFlags -> IO LinkerInfo
getLinkerInfo :: DynFlags -> IO LinkerInfo
getLinkerInfo dflags :: DynFlags
dflags = do
Maybe LinkerInfo
info <- IORef (Maybe LinkerInfo) -> IO (Maybe LinkerInfo)
forall a. IORef a -> IO a
readIORef (DynFlags -> IORef (Maybe LinkerInfo)
rtldInfo DynFlags
dflags)
case Maybe LinkerInfo
info of
Just v :: LinkerInfo
v -> LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
v
Nothing -> do
LinkerInfo
v <- DynFlags -> IO LinkerInfo
getLinkerInfo' DynFlags
dflags
IORef (Maybe LinkerInfo) -> Maybe LinkerInfo -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (DynFlags -> IORef (Maybe LinkerInfo)
rtldInfo DynFlags
dflags) (LinkerInfo -> Maybe LinkerInfo
forall a. a -> Maybe a
Just LinkerInfo
v)
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
v
getLinkerInfo' :: DynFlags -> IO LinkerInfo
getLinkerInfo' :: DynFlags -> IO LinkerInfo
getLinkerInfo' dflags :: DynFlags
dflags = do
let platform :: Platform
platform = DynFlags -> Platform
targetPlatform DynFlags
dflags
os :: OS
os = Platform -> OS
platformOS Platform
platform
(pgm :: String
pgm,args0 :: [Option]
args0) = DynFlags -> (String, [Option])
pgm_l DynFlags
dflags
args1 :: [Option]
args1 = (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option (DynFlags -> (DynFlags -> [String]) -> [String]
forall a. DynFlags -> (DynFlags -> [a]) -> [a]
getOpts DynFlags
dflags DynFlags -> [String]
opt_l)
args2 :: [Option]
args2 = [Option]
args0 [Option] -> [Option] -> [Option]
forall a. [a] -> [a] -> [a]
++ [Option]
args1
args3 :: [String]
args3 = (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter String -> Bool
forall a. [a] -> Bool
notNull ((Option -> String) -> [Option] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Option -> String
showOpt [Option]
args2)
parseLinkerInfo :: t String -> p -> p -> m LinkerInfo
parseLinkerInfo stdo :: t String
stdo _stde :: p
_stde _exitc :: p
_exitc
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("GNU ld" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stdo =
LinkerInfo -> m LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return ([Option] -> LinkerInfo
GnuLD ([Option] -> LinkerInfo) -> [Option] -> LinkerInfo
forall a b. (a -> b) -> a -> b
$ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option ["-Wl,--hash-size=31",
"-Wl,--reduce-memory-overheads",
"-Wl,--no-as-needed"])
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("GNU gold" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stdo =
LinkerInfo -> m LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return ([Option] -> LinkerInfo
GnuGold [String -> Option
Option "-Wl,--no-as-needed"])
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("LLD" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stdo =
LinkerInfo -> m LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return ([Option] -> LinkerInfo
LlvmLLD ([Option] -> LinkerInfo) -> [Option] -> LinkerInfo
forall a b. (a -> b) -> a -> b
$ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option [
"-Wl,--no-as-needed"])
| Bool
otherwise = String -> m LinkerInfo
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "invalid --version output, or linker is unsupported"
LinkerInfo
info <- IO LinkerInfo -> (IOException -> IO LinkerInfo) -> IO LinkerInfo
forall a. IO a -> (IOException -> IO a) -> IO a
catchIO (do
case OS
os of
OSSolaris2 ->
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (LinkerInfo -> IO LinkerInfo) -> LinkerInfo -> IO LinkerInfo
forall a b. (a -> b) -> a -> b
$ [Option] -> LinkerInfo
SolarisLD []
OSAIX ->
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (LinkerInfo -> IO LinkerInfo) -> LinkerInfo -> IO LinkerInfo
forall a b. (a -> b) -> a -> b
$ [Option] -> LinkerInfo
AixLD []
OSDarwin ->
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (LinkerInfo -> IO LinkerInfo) -> LinkerInfo -> IO LinkerInfo
forall a b. (a -> b) -> a -> b
$ [Option] -> LinkerInfo
DarwinLD []
OSMinGW32 ->
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return (LinkerInfo -> IO LinkerInfo) -> LinkerInfo -> IO LinkerInfo
forall a b. (a -> b) -> a -> b
$ [Option] -> LinkerInfo
GnuLD ([Option] -> LinkerInfo) -> [Option] -> LinkerInfo
forall a b. (a -> b) -> a -> b
$ (String -> Option) -> [String] -> [Option]
forall a b. (a -> b) -> [a] -> [b]
map String -> Option
Option
[
"-Wl,--hash-size=31"
, "-Wl,--reduce-memory-overheads"
, "-fstack-check"
, "-static-libgcc" ]
_ -> do
(exitc :: ExitCode
exitc, stdo :: String
stdo, stde :: String
stde) <- String
-> [String] -> (String, String) -> IO (ExitCode, String, String)
readProcessEnvWithExitCode String
pgm
(["-Wl,--version"] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
args3)
(String, String)
c_locale_env
[String] -> [String] -> ExitCode -> IO LinkerInfo
forall (t :: * -> *) (m :: * -> *) p p.
(Foldable t, MonadFail m) =>
t String -> p -> p -> m LinkerInfo
parseLinkerInfo (String -> [String]
lines String
stdo) (String -> [String]
lines String
stde) ExitCode
exitc
)
(\err :: IOException
err -> do
DynFlags -> Int -> MsgDoc -> IO ()
debugTraceMsg DynFlags
dflags 2
(String -> MsgDoc
text "Error (figuring out linker information):" MsgDoc -> MsgDoc -> MsgDoc
<+>
String -> MsgDoc
text (IOException -> String
forall a. Show a => a -> String
show IOException
err))
DynFlags -> MsgDoc -> IO ()
errorMsg DynFlags
dflags (MsgDoc -> IO ()) -> MsgDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ MsgDoc -> Int -> MsgDoc -> MsgDoc
hang (String -> MsgDoc
text "Warning:") 9 (MsgDoc -> MsgDoc) -> MsgDoc -> MsgDoc
forall a b. (a -> b) -> a -> b
$
String -> MsgDoc
text "Couldn't figure out linker information!" MsgDoc -> MsgDoc -> MsgDoc
$$
String -> MsgDoc
text "Make sure you're using GNU ld, GNU gold" MsgDoc -> MsgDoc -> MsgDoc
<+>
String -> MsgDoc
text "or the built in OS X linker, etc."
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
UnknownLD)
LinkerInfo -> IO LinkerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
info
getCompilerInfo :: DynFlags -> IO CompilerInfo
getCompilerInfo :: DynFlags -> IO CompilerInfo
getCompilerInfo dflags :: DynFlags
dflags = do
Maybe CompilerInfo
info <- IORef (Maybe CompilerInfo) -> IO (Maybe CompilerInfo)
forall a. IORef a -> IO a
readIORef (DynFlags -> IORef (Maybe CompilerInfo)
rtccInfo DynFlags
dflags)
case Maybe CompilerInfo
info of
Just v :: CompilerInfo
v -> CompilerInfo -> IO CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
Nothing -> do
CompilerInfo
v <- DynFlags -> IO CompilerInfo
getCompilerInfo' DynFlags
dflags
IORef (Maybe CompilerInfo) -> Maybe CompilerInfo -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (DynFlags -> IORef (Maybe CompilerInfo)
rtccInfo DynFlags
dflags) (CompilerInfo -> Maybe CompilerInfo
forall a. a -> Maybe a
Just CompilerInfo
v)
CompilerInfo -> IO CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
getCompilerInfo' :: DynFlags -> IO CompilerInfo
getCompilerInfo' :: DynFlags -> IO CompilerInfo
getCompilerInfo' dflags :: DynFlags
dflags = do
let (pgm :: String
pgm,_) = DynFlags -> (String, [Option])
pgm_c DynFlags
dflags
parseCompilerInfo :: p -> t String -> p -> m CompilerInfo
parseCompilerInfo _stdo :: p
_stdo stde :: t String
stde _exitc :: p
_exitc
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("gcc version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
GCC
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
Clang
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("FreeBSD clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
Clang
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("Apple LLVM version 5.1" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang51
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("Apple LLVM version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang
| (String -> Bool) -> t String -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any ("Apple clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) t String
stde =
CompilerInfo -> m CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang
| Bool
otherwise = String -> m CompilerInfo
forall (m :: * -> *) a. MonadFail m => String -> m a
fail "invalid -v output, or compiler is unsupported"
CompilerInfo
info <- IO CompilerInfo
-> (IOException -> IO CompilerInfo) -> IO CompilerInfo
forall a. IO a -> (IOException -> IO a) -> IO a
catchIO (do
(exitc :: ExitCode
exitc, stdo :: String
stdo, stde :: String
stde) <-
String
-> [String] -> (String, String) -> IO (ExitCode, String, String)
readProcessEnvWithExitCode String
pgm ["-v"] (String, String)
c_locale_env
[String] -> [String] -> ExitCode -> IO CompilerInfo
forall (t :: * -> *) (m :: * -> *) p p.
(Foldable t, MonadFail m) =>
p -> t String -> p -> m CompilerInfo
parseCompilerInfo (String -> [String]
lines String
stdo) (String -> [String]
lines String
stde) ExitCode
exitc
)
(\err :: IOException
err -> do
DynFlags -> Int -> MsgDoc -> IO ()
debugTraceMsg DynFlags
dflags 2
(String -> MsgDoc
text "Error (figuring out C compiler information):" MsgDoc -> MsgDoc -> MsgDoc
<+>
String -> MsgDoc
text (IOException -> String
forall a. Show a => a -> String
show IOException
err))
DynFlags -> MsgDoc -> IO ()
errorMsg DynFlags
dflags (MsgDoc -> IO ()) -> MsgDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ MsgDoc -> Int -> MsgDoc -> MsgDoc
hang (String -> MsgDoc
text "Warning:") 9 (MsgDoc -> MsgDoc) -> MsgDoc -> MsgDoc
forall a b. (a -> b) -> a -> b
$
String -> MsgDoc
text "Couldn't figure out C compiler information!" MsgDoc -> MsgDoc -> MsgDoc
$$
String -> MsgDoc
text "Make sure you're using GNU gcc, or clang"
CompilerInfo -> IO CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
UnknownCC)
CompilerInfo -> IO CompilerInfo
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
info