{-# LANGUAGE ScopedTypeVariables #-}
module GHC.SysTools.Info where
import GHC.Utils.Exception
import GHC.Utils.Error
import GHC.Driver.Session
import GHC.Utils.Outputable
import GHC.Utils.Misc
import GHC.Utils.Logger
import Data.List ( isInfixOf, isPrefixOf )
import Data.IORef
import System.IO
import GHC.Platform
import GHC.Prelude
import GHC.SysTools.Process
neededLinkArgs :: LinkerInfo -> [Option]
neededLinkArgs :: LinkerInfo -> [Option]
neededLinkArgs (GnuLD [Option]
o) = [Option]
o
neededLinkArgs (Mold [Option]
o) = [Option]
o
neededLinkArgs (GnuGold [Option]
o) = [Option]
o
neededLinkArgs (LlvmLLD [Option]
o) = [Option]
o
neededLinkArgs (DarwinLD [Option]
o) = [Option]
o
neededLinkArgs (SolarisLD [Option]
o) = [Option]
o
neededLinkArgs (AixLD [Option]
o) = [Option]
o
neededLinkArgs LinkerInfo
UnknownLD = []
getLinkerInfo :: Logger -> DynFlags -> IO LinkerInfo
getLinkerInfo :: Logger -> DynFlags -> IO LinkerInfo
getLinkerInfo Logger
logger 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 LinkerInfo
v -> LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
v
Maybe LinkerInfo
Nothing -> do
LinkerInfo
v <- Logger -> DynFlags -> IO LinkerInfo
getLinkerInfo' Logger
logger 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 a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
v
getLinkerInfo' :: Logger -> DynFlags -> IO LinkerInfo
getLinkerInfo' :: Logger -> DynFlags -> IO LinkerInfo
getLinkerInfo' Logger
logger DynFlags
dflags = do
let platform :: Platform
platform = DynFlags -> Platform
targetPlatform DynFlags
dflags
os :: OS
os = Platform -> OS
platformOS Platform
platform
(String
pgm,[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 (f :: * -> *) a. Foldable f => f a -> Bool
notNull ((Option -> String) -> [Option] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Option -> String
showOpt [Option]
args2)
parseLinkerInfo :: [String] -> [String] -> ExitCode -> IO LinkerInfo
parseLinkerInfo [String]
stdo [String]
_stde ExitCode
_exitc
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"GNU ld" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stdo =
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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 [
String
"-Wl,--no-as-needed"])
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"mold" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stdo =
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Option] -> LinkerInfo
Mold ([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 [
String
"-Wl,--no-as-needed"])
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"GNU gold" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stdo =
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([Option] -> LinkerInfo
GnuGold [String -> Option
Option String
"-Wl,--no-as-needed"])
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (\String
line -> String
"LLD" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
line Bool -> Bool -> Bool
|| String
"LLD" String -> [String] -> Bool
forall a. Eq a => a -> [a] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String -> [String]
words String
line) [String]
stdo =
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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 [
String
"-Wl,--no-as-needed" | OS -> Bool
osElfTarget OS
os Bool -> Bool -> Bool
|| OS
os OS -> OS -> Bool
forall a. Eq a => a -> a -> Bool
== OS
OSMinGW32 ])
| Bool
otherwise = String -> IO LinkerInfo
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"invalid --version output, or linker is unsupported"
IO LinkerInfo -> (IOException -> IO LinkerInfo) -> IO LinkerInfo
forall a. IO a -> (IOException -> IO a) -> IO a
catchIO (
case OS
os of
OS
OSSolaris2 ->
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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 []
OS
OSAIX ->
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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 []
OS
OSDarwin ->
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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 []
OS
OSMinGW32 ->
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
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
[
String
"-fstack-check"
]
OS
_ -> do
(ExitCode
exitc, String
stdo, String
stde) <- String
-> [String] -> (String, String) -> IO (ExitCode, String, String)
readProcessEnvWithExitCode String
pgm
([String
"-Wl,--version"] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
args3)
(String, String)
c_locale_env
[String] -> [String] -> ExitCode -> IO LinkerInfo
parseLinkerInfo (String -> [String]
lines String
stdo) (String -> [String]
lines String
stde) ExitCode
exitc
)
(\IOException
err -> do
Logger -> Int -> SDoc -> IO ()
debugTraceMsg Logger
logger Int
2
(String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Error (figuring out linker information):" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+>
String -> SDoc
forall doc. IsLine doc => String -> doc
text (IOException -> String
forall a. Show a => a -> String
show IOException
err))
Logger -> SDoc -> IO ()
errorMsg Logger
logger (SDoc -> IO ()) -> SDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ SDoc -> Int -> SDoc -> SDoc
hang (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Warning:") Int
9 (SDoc -> SDoc) -> SDoc -> SDoc
forall a b. (a -> b) -> a -> b
$
String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Couldn't figure out linker information!" SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$
String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Make sure you're using GNU ld, GNU gold" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+>
String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"or the built in OS X linker, etc."
LinkerInfo -> IO LinkerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return LinkerInfo
UnknownLD
)
getCompilerInfo :: Logger -> DynFlags -> IO CompilerInfo
getCompilerInfo :: Logger -> DynFlags -> IO CompilerInfo
getCompilerInfo Logger
logger 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 CompilerInfo
v -> CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
Maybe CompilerInfo
Nothing -> do
let pgm :: String
pgm = DynFlags -> String
pgm_c DynFlags
dflags
CompilerInfo
v <- Logger -> String -> IO CompilerInfo
getCompilerInfo' Logger
logger String
pgm
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 a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
getAssemblerInfo :: Logger -> DynFlags -> IO CompilerInfo
getAssemblerInfo :: Logger -> DynFlags -> IO CompilerInfo
getAssemblerInfo Logger
logger DynFlags
dflags = do
Maybe CompilerInfo
info <- IORef (Maybe CompilerInfo) -> IO (Maybe CompilerInfo)
forall a. IORef a -> IO a
readIORef (DynFlags -> IORef (Maybe CompilerInfo)
rtasmInfo DynFlags
dflags)
case Maybe CompilerInfo
info of
Just CompilerInfo
v -> CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
Maybe CompilerInfo
Nothing -> do
let (String
pgm, [Option]
_) = DynFlags -> (String, [Option])
pgm_a DynFlags
dflags
CompilerInfo
v <- Logger -> String -> IO CompilerInfo
getCompilerInfo' Logger
logger String
pgm
IORef (Maybe CompilerInfo) -> Maybe CompilerInfo -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef (DynFlags -> IORef (Maybe CompilerInfo)
rtasmInfo DynFlags
dflags) (CompilerInfo -> Maybe CompilerInfo
forall a. a -> Maybe a
Just CompilerInfo
v)
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
v
getCompilerInfo' :: Logger -> String -> IO CompilerInfo
getCompilerInfo' :: Logger -> String -> IO CompilerInfo
getCompilerInfo' Logger
logger String
pgm = do
let
parseCompilerInfo :: [String] -> [String] -> ExitCode -> IO CompilerInfo
parseCompilerInfo [String]
_stdo [String]
stde ExitCode
_exitc
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"gcc version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
GCC
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
Clang
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"FreeBSD clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isInfixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
Clang
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"Apple LLVM version 5.1" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang51
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"Apple LLVM version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang
| (String -> Bool) -> [String] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any (String
"Apple clang version" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf`) [String]
stde =
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
AppleClang
| Bool
otherwise = String -> IO CompilerInfo
forall a. String -> IO a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail (String -> IO CompilerInfo) -> String -> IO CompilerInfo
forall a b. (a -> b) -> a -> b
$ String
"invalid -v output, or compiler is unsupported (" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
pgm String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"): " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
unlines [String]
stde
IO CompilerInfo
-> (IOException -> IO CompilerInfo) -> IO CompilerInfo
forall a. IO a -> (IOException -> IO a) -> IO a
catchIO (do
(ExitCode
exitc, String
stdo, String
stde) <-
String
-> [String] -> (String, String) -> IO (ExitCode, String, String)
readProcessEnvWithExitCode String
pgm [String
"-v"] (String, String)
c_locale_env
[String] -> [String] -> ExitCode -> IO CompilerInfo
parseCompilerInfo (String -> [String]
lines String
stdo) (String -> [String]
lines String
stde) ExitCode
exitc
)
(\IOException
err -> do
Logger -> Int -> SDoc -> IO ()
debugTraceMsg Logger
logger Int
2
(String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Error (figuring out C compiler information):" SDoc -> SDoc -> SDoc
forall doc. IsLine doc => doc -> doc -> doc
<+>
String -> SDoc
forall doc. IsLine doc => String -> doc
text (IOException -> String
forall a. Show a => a -> String
show IOException
err))
Logger -> SDoc -> IO ()
errorMsg Logger
logger (SDoc -> IO ()) -> SDoc -> IO ()
forall a b. (a -> b) -> a -> b
$ SDoc -> Int -> SDoc -> SDoc
hang (String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Warning:") Int
9 (SDoc -> SDoc) -> SDoc -> SDoc
forall a b. (a -> b) -> a -> b
$
String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Couldn't figure out C compiler information!" SDoc -> SDoc -> SDoc
forall doc. IsDoc doc => doc -> doc -> doc
$$
String -> SDoc
forall doc. IsLine doc => String -> doc
text String
"Make sure you're using GNU gcc, or clang"
CompilerInfo -> IO CompilerInfo
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return CompilerInfo
UnknownCC
)