module DriverPipeline (
oneShot, compileFile,
linkBinary,
preprocess,
compile, compile',
link,
) where
#include "HsVersions.h"
import Packages
import HeaderInfo
import DriverPhases
import SysTools
import HscMain
import Finder
import HscTypes
import Outputable
import Module
import UniqFM ( eltsUFM )
import ErrUtils
import DynFlags
import StaticFlags ( v_Ld_inputs, opt_PIC, opt_Static, WayName(..) )
import Config
import Panic
import Util
import StringBuffer ( hGetStringBuffer )
import BasicTypes ( SuccessFlag(..) )
import Maybes ( expectJust )
import ParserCoreUtils ( getCoreModuleName )
import SrcLoc
import FastString
import LlvmCodeGen ( llvmFixupAsm )
import MonadUtils
import Platform
import Exception
import Data.IORef ( readIORef )
import System.Directory
import System.FilePath
import System.IO
import Control.Monad
import Data.List ( isSuffixOf )
import Data.Maybe
import System.Environment
import Data.Char
preprocess :: HscEnv
-> (FilePath, Maybe Phase)
-> IO (DynFlags, FilePath)
preprocess hsc_env (filename, mb_phase) =
ASSERT2(isJust mb_phase || isHaskellSrcFilename filename, text filename)
runPipeline anyHsc hsc_env (filename, mb_phase)
Nothing Temporary Nothing Nothing
compile :: HscEnv
-> ModSummary
-> Int
-> Int
-> Maybe ModIface
-> Maybe Linkable
-> SourceModified
-> IO HomeModInfo
compile = compile' (hscCompileNothing, hscCompileInteractive, hscCompileBatch)
compile' ::
(Compiler (HscStatus, ModIface, ModDetails),
Compiler (InteractiveStatus, ModIface, ModDetails),
Compiler (HscStatus, ModIface, ModDetails))
-> HscEnv
-> ModSummary
-> Int
-> Int
-> Maybe ModIface
-> Maybe Linkable
-> SourceModified
-> IO HomeModInfo
compile' (nothingCompiler, interactiveCompiler, batchCompiler)
hsc_env0 summary mod_index nmods mb_old_iface maybe_old_linkable
source_modified0
= do
let dflags0 = ms_hspp_opts summary
this_mod = ms_mod summary
src_flavour = ms_hsc_src summary
location = ms_location summary
input_fn = expectJust "compile:hs" (ml_hs_file location)
input_fnpp = ms_hspp_file summary
debugTraceMsg dflags0 2 (text "compile: input file" <+> text input_fnpp)
let basename = dropExtension input_fn
let current_dir = case takeDirectory basename of
"" -> "."
d -> d
old_paths = includePaths dflags0
dflags = dflags0 { includePaths = current_dir : old_paths }
hsc_env = hsc_env0 {hsc_dflags = dflags}
let hsc_lang = hscTarget dflags
let next_phase = hscPostBackendPhase dflags src_flavour hsc_lang
output_fn <- getOutputFilename next_phase
Temporary basename dflags next_phase (Just location)
let dflags' = dflags { hscTarget = hsc_lang,
hscOutName = output_fn,
extCoreName = basename ++ ".hcr" }
let hsc_env' = hsc_env { hsc_dflags = dflags' }
let force_recomp = dopt Opt_ForceRecomp dflags
source_modified
| force_recomp || isNothing maybe_old_linkable = SourceModified
| otherwise = source_modified0
object_filename = ml_obj_file location
let handleBatch HscNoRecomp
= ASSERT (isJust maybe_old_linkable)
return maybe_old_linkable
handleBatch (HscRecomp hasStub _)
| isHsBoot src_flavour
= do when (isObjectTarget hsc_lang) $
liftIO $ touchObjectFile dflags' object_filename
return maybe_old_linkable
| otherwise
= do (hs_unlinked, unlinked_time) <-
case hsc_lang of
HscNothing ->
return ([], ms_hs_date summary)
_other -> do
maybe_stub_o <- case hasStub of
Nothing -> return Nothing
Just stub_c -> do
stub_o <- compileStub hsc_env' stub_c
return (Just stub_o)
_ <- runPipeline StopLn hsc_env' (output_fn,Nothing)
(Just basename)
Persistent
(Just location)
maybe_stub_o
o_time <- getModificationTime object_filename
return ([DotO object_filename], o_time)
let linkable = LM unlinked_time this_mod hs_unlinked
return (Just linkable)
handleInterpreted HscNoRecomp
= ASSERT (isJust maybe_old_linkable)
return maybe_old_linkable
handleInterpreted (HscRecomp _hasStub Nothing)
= ASSERT (isHsBoot src_flavour)
return maybe_old_linkable
handleInterpreted (HscRecomp hasStub (Just (comp_bc, modBreaks)))
= do stub_o <- case hasStub of
Nothing -> return []
Just stub_c -> do
stub_o <- compileStub hsc_env' stub_c
return [DotO stub_o]
let hs_unlinked = [BCOs comp_bc modBreaks]
unlinked_time = ms_hs_date summary
let linkable = LM unlinked_time this_mod
(hs_unlinked ++ stub_o)
return (Just linkable)
let
runCompiler compiler handle
= do (result, iface, details)
<- compiler hsc_env' summary source_modified mb_old_iface
(Just (mod_index, nmods))
linkable <- handle result
return (HomeModInfo{ hm_details = details,
hm_iface = iface,
hm_linkable = linkable })
case hsc_lang of
HscInterpreted -> runCompiler interactiveCompiler handleInterpreted
HscNothing -> runCompiler nothingCompiler handleBatch
_other -> runCompiler batchCompiler handleBatch
compileStub :: HscEnv -> FilePath -> IO FilePath
compileStub hsc_env stub_c = do
(_, stub_o) <- runPipeline StopLn hsc_env (stub_c,Nothing) Nothing
Temporary Nothing Nothing
return stub_o
link :: GhcLink
-> DynFlags
-> Bool
-> HomePackageTable
-> IO SuccessFlag
link LinkInMemory _ _ _
= if cGhcWithInterpreter == "YES"
then
return Succeeded
else panicBadLink LinkInMemory
link NoLink _ _ _
= return Succeeded
link LinkBinary dflags batch_attempt_linking hpt
= link' dflags batch_attempt_linking hpt
link LinkDynLib dflags batch_attempt_linking hpt
= link' dflags batch_attempt_linking hpt
panicBadLink :: GhcLink -> a
panicBadLink other = panic ("link: GHC not built to link this way: " ++
show other)
link' :: DynFlags
-> Bool
-> HomePackageTable
-> IO SuccessFlag
link' dflags batch_attempt_linking hpt
| batch_attempt_linking
= do
let
home_mod_infos = eltsUFM hpt
pkg_deps = concatMap (map fst . dep_pkgs . mi_deps . hm_iface) home_mod_infos
linkables = map (expectJust "link".hm_linkable) home_mod_infos
debugTraceMsg dflags 3 (text "link: linkables are ..." $$ vcat (map ppr linkables))
if isNoLink (ghcLink dflags)
then do debugTraceMsg dflags 3 (text "link(batch): linking omitted (-c flag given).")
return Succeeded
else do
let getOfiles (LM _ _ us) = map nameOfObject (filter isObject us)
obj_files = concatMap getOfiles linkables
exe_file = exeFileName dflags
linking_needed <- linkingNeeded dflags linkables pkg_deps
if not (dopt Opt_ForceRecomp dflags) && not linking_needed
then do debugTraceMsg dflags 2 (text exe_file <+> ptext (sLit "is up to date, linking not required."))
return Succeeded
else do
compilationProgressMsg dflags $ showSDoc $
(ptext (sLit "Linking") <+> text exe_file <+> text "...")
let link = case ghcLink dflags of
LinkBinary -> linkBinary
LinkDynLib -> linkDynLib
other -> panicBadLink other
link dflags obj_files pkg_deps
debugTraceMsg dflags 3 (text "link: done")
return Succeeded
| otherwise
= do debugTraceMsg dflags 3 (text "link(batch): upsweep (partially) failed OR" $$
text " Main.main not exported; not linking.")
return Succeeded
linkingNeeded :: DynFlags -> [Linkable] -> [PackageId] -> IO Bool
linkingNeeded dflags linkables pkg_deps = do
let exe_file = exeFileName dflags
e_exe_time <- tryIO $ getModificationTime exe_file
case e_exe_time of
Left _ -> return True
Right t -> do
extra_ld_inputs <- readIORef v_Ld_inputs
e_extra_times <- mapM (tryIO . getModificationTime) extra_ld_inputs
let (errs,extra_times) = splitEithers e_extra_times
let obj_times = map linkableTime linkables ++ extra_times
if not (null errs) || any (t <) obj_times
then return True
else do
let pkg_map = pkgIdMap (pkgState dflags)
pkg_hslibs = [ (libraryDirs c, lib)
| Just c <- map (lookupPackage pkg_map) pkg_deps,
lib <- packageHsLibs dflags c ]
pkg_libfiles <- mapM (uncurry findHSLib) pkg_hslibs
if any isNothing pkg_libfiles then return True else do
e_lib_times <- mapM (tryIO . getModificationTime)
(catMaybes pkg_libfiles)
let (lib_errs,lib_times) = splitEithers e_lib_times
if not (null lib_errs) || any (t <) lib_times
then return True
else checkLinkInfo dflags pkg_deps exe_file
checkLinkInfo :: DynFlags -> [PackageId] -> FilePath -> IO Bool
checkLinkInfo dflags pkg_deps exe_file
| not (platformSupportsSavingLinkOpts (platformOS (targetPlatform dflags)))
= return False
| otherwise
= do
link_info <- getLinkInfo dflags pkg_deps
debugTraceMsg dflags 3 $ text ("Link info: " ++ link_info)
m_exe_link_info <- readElfSection dflags ghcLinkInfoSectionName exe_file
debugTraceMsg dflags 3 $ text ("Exe link info: " ++ show m_exe_link_info)
return (Just link_info /= m_exe_link_info)
platformSupportsSavingLinkOpts :: OS -> Bool
platformSupportsSavingLinkOpts os
| os == OSSolaris2 = False
| otherwise = osElfTarget os
ghcLinkInfoSectionName :: String
ghcLinkInfoSectionName = ".debug-ghc-link-info"
findHSLib :: [String] -> String -> IO (Maybe FilePath)
findHSLib dirs lib = do
let batch_lib_file = "lib" ++ lib <.> "a"
found <- filterM doesFileExist (map (</> batch_lib_file) dirs)
case found of
[] -> return Nothing
(x:_) -> return (Just x)
oneShot :: HscEnv -> Phase -> [(String, Maybe Phase)] -> IO ()
oneShot hsc_env stop_phase srcs = do
o_files <- mapM (compileFile hsc_env stop_phase) srcs
doLink (hsc_dflags hsc_env) stop_phase o_files
compileFile :: HscEnv -> Phase -> (FilePath, Maybe Phase) -> IO FilePath
compileFile hsc_env stop_phase (src, mb_phase) = do
exists <- doesFileExist src
when (not exists) $
ghcError (CmdLineError ("does not exist: " ++ src))
let
dflags = hsc_dflags hsc_env
split = dopt Opt_SplitObjs dflags
mb_o_file = outputFile dflags
ghc_link = ghcLink dflags
output
| StopLn <- stop_phase, not (isNoLink ghc_link) = Persistent
| Just o_file <- mb_o_file = SpecificFile o_file
| otherwise = Persistent
stop_phase' = case stop_phase of
As | split -> SplitAs
_ -> stop_phase
( _, out_file) <- runPipeline stop_phase' hsc_env
(src, mb_phase) Nothing output
Nothing Nothing
return out_file
doLink :: DynFlags -> Phase -> [FilePath] -> IO ()
doLink dflags stop_phase o_files
| not (isStopLn stop_phase)
= return ()
| otherwise
= case ghcLink dflags of
NoLink -> return ()
LinkBinary -> linkBinary dflags o_files []
LinkDynLib -> linkDynLib dflags o_files []
other -> panicBadLink other
data PipelineOutput
= Temporary
| Persistent
| SpecificFile FilePath
runPipeline
:: Phase
-> HscEnv
-> (FilePath,Maybe Phase)
-> Maybe FilePath
-> PipelineOutput
-> Maybe ModLocation
-> Maybe FilePath
-> IO (DynFlags, FilePath)
runPipeline stop_phase hsc_env0 (input_fn, mb_phase)
mb_basename output maybe_loc maybe_stub_o
= do
let dflags0 = hsc_dflags hsc_env0
(input_basename, suffix) = splitExtension input_fn
suffix' = drop 1 suffix
basename | Just b <- mb_basename = b
| otherwise = input_basename
dflags = dflags0 { dumpPrefix = Just (basename ++ ".") }
hsc_env = hsc_env0 {hsc_dflags = dflags}
start_phase = fromMaybe (startPhase suffix') mb_phase
when (not (start_phase `happensBefore` stop_phase)) $
ghcError (UsageError
("cannot compile this file to desired target: "
++ input_fn))
let get_output_fn = getOutputFilename stop_phase output basename
let env = PipeEnv{ stop_phase,
src_basename = basename,
src_suffix = suffix',
output_spec = output }
state = PipeState{ hsc_env, maybe_loc, maybe_stub_o = maybe_stub_o }
(state', output_fn) <- unP (pipeLoop start_phase input_fn) env state
let PipeState{ hsc_env=hsc_env', maybe_loc } = state'
dflags' = hsc_dflags hsc_env'
case output of
Temporary ->
return (dflags', output_fn)
_other ->
do final_fn <- get_output_fn dflags' stop_phase maybe_loc
when (final_fn /= output_fn) $ do
let msg = ("Copying `" ++ output_fn ++"' to `" ++ final_fn ++ "'")
line_prag = Just ("{-# LINE 1 \"" ++ input_fn ++ "\" #-}\n")
copyWithHeader dflags msg line_prag output_fn final_fn
return (dflags', final_fn)
data PipeEnv = PipeEnv {
stop_phase :: Phase,
src_basename :: String,
src_suffix :: String,
output_spec :: PipelineOutput
}
data PipeState = PipeState {
hsc_env :: HscEnv,
maybe_loc :: Maybe ModLocation,
maybe_stub_o :: Maybe FilePath
}
getPipeEnv :: CompPipeline PipeEnv
getPipeEnv = P $ \env state -> return (state, env)
getPipeState :: CompPipeline PipeState
getPipeState = P $ \_env state -> return (state, state)
getDynFlags :: CompPipeline DynFlags
getDynFlags = P $ \_env state -> return (state, hsc_dflags (hsc_env state))
setDynFlags :: DynFlags -> CompPipeline ()
setDynFlags dflags = P $ \_env state ->
return (state{hsc_env= (hsc_env state){ hsc_dflags = dflags }}, ())
setModLocation :: ModLocation -> CompPipeline ()
setModLocation loc = P $ \_env state ->
return (state{ maybe_loc = Just loc }, ())
setStubO :: FilePath -> CompPipeline ()
setStubO stub_o = P $ \_env state ->
return (state{ maybe_stub_o = Just stub_o }, ())
newtype CompPipeline a = P { unP :: PipeEnv -> PipeState -> IO (PipeState, a) }
instance Monad CompPipeline where
return a = P $ \_env state -> return (state, a)
P m >>= k = P $ \env state -> do (state',a) <- m env state
unP (k a) env state'
io :: IO a -> CompPipeline a
io m = P $ \_env state -> do a <- m; return (state, a)
phaseOutputFilename :: Phase -> CompPipeline FilePath
phaseOutputFilename next_phase = do
PipeEnv{stop_phase, src_basename, output_spec} <- getPipeEnv
PipeState{maybe_loc, hsc_env} <- getPipeState
let dflags = hsc_dflags hsc_env
io $ getOutputFilename stop_phase output_spec
src_basename dflags next_phase maybe_loc
pipeLoop :: Phase -> FilePath -> CompPipeline FilePath
pipeLoop phase input_fn = do
PipeEnv{stop_phase} <- getPipeEnv
PipeState{hsc_env} <- getPipeState
case () of
_ | phase `eqPhase` stop_phase
-> return input_fn
| not (phase `happensBefore` stop_phase)
-> panic ("pipeLoop: at phase " ++ show phase ++
" but I wanted to stop at phase " ++ show stop_phase)
| otherwise
-> do io $ debugTraceMsg (hsc_dflags hsc_env) 4
(ptext (sLit "Running phase") <+> ppr phase)
dflags <- getDynFlags
(next_phase, output_fn) <- runPhase phase input_fn dflags
pipeLoop next_phase output_fn
getOutputFilename
:: Phase -> PipelineOutput -> String
-> DynFlags -> Phase -> Maybe ModLocation -> IO FilePath
getOutputFilename stop_phase output basename
= func
where
func dflags next_phase maybe_location
| is_last_phase, Persistent <- output = persistent_fn
| is_last_phase, SpecificFile f <- output = return f
| keep_this_output = persistent_fn
| otherwise = newTempName dflags suffix
where
hcsuf = hcSuf dflags
odir = objectDir dflags
osuf = objectSuf dflags
keep_hc = dopt Opt_KeepHcFiles dflags
keep_s = dopt Opt_KeepSFiles dflags
keep_bc = dopt Opt_KeepLlvmFiles dflags
myPhaseInputExt HCc = hcsuf
myPhaseInputExt MergeStub = osuf
myPhaseInputExt StopLn = osuf
myPhaseInputExt other = phaseInputExt other
is_last_phase = next_phase `eqPhase` stop_phase
keep_this_output =
case next_phase of
As | keep_s -> True
LlvmOpt | keep_bc -> True
HCc | keep_hc -> True
_other -> False
suffix = myPhaseInputExt next_phase
persistent_fn
| StopLn <- next_phase = return odir_persistent
| otherwise = return persistent
persistent = basename <.> suffix
odir_persistent
| Just loc <- maybe_location = ml_obj_file loc
| Just d <- odir = d </> persistent
| otherwise = persistent
runPhase :: Phase
-> FilePath
-> DynFlags
-> CompPipeline (Phase,
FilePath)
runPhase (Unlit sf) input_fn dflags
= do
output_fn <- phaseOutputFilename (Cpp sf)
let unlit_flags = getOpts dflags opt_L
flags = map SysTools.Option unlit_flags ++
[
SysTools.Option "-h"
, SysTools.Option $ escape $ normalise input_fn
, SysTools.FileOption "" input_fn
, SysTools.FileOption "" output_fn
]
io $ SysTools.runUnlit dflags flags
return (Cpp sf, output_fn)
where
escape ('\\':cs) = '\\':'\\': escape cs
escape ('\"':cs) = '\\':'\"': escape cs
escape ('\'':cs) = '\\':'\'': escape cs
escape (c:cs) = c : escape cs
escape [] = []
runPhase (Cpp sf) input_fn dflags0
= do
src_opts <- io $ getOptionsFromFile dflags0 input_fn
(dflags1, unhandled_flags, warns)
<- io $ parseDynamicFilePragma dflags0 src_opts
setDynFlags dflags1
io $ checkProcessArgsResult unhandled_flags
if not (xopt Opt_Cpp dflags1) then do
unless (dopt Opt_Pp dflags1) $ io $ handleFlagWarnings dflags1 warns
return (HsPp sf, input_fn)
else do
output_fn <- phaseOutputFilename (HsPp sf)
io $ doCpp dflags1 True False input_fn output_fn
src_opts <- io $ getOptionsFromFile dflags0 output_fn
(dflags2, unhandled_flags, warns)
<- io $ parseDynamicFilePragma dflags0 src_opts
io $ checkProcessArgsResult unhandled_flags
unless (dopt Opt_Pp dflags2) $ io $ handleFlagWarnings dflags2 warns
setDynFlags dflags2
return (HsPp sf, output_fn)
runPhase (HsPp sf) input_fn dflags
= do
if not (dopt Opt_Pp dflags) then
return (Hsc sf, input_fn)
else do
let hspp_opts = getOpts dflags opt_F
PipeEnv{src_basename, src_suffix} <- getPipeEnv
let orig_fn = src_basename <.> src_suffix
output_fn <- phaseOutputFilename (Hsc sf)
io $ SysTools.runPp dflags
( [ SysTools.Option orig_fn
, SysTools.Option input_fn
, SysTools.FileOption "" output_fn
] ++
map SysTools.Option hspp_opts
)
src_opts <- io $ getOptionsFromFile dflags output_fn
(dflags1, unhandled_flags, warns)
<- io $ parseDynamicFilePragma dflags src_opts
setDynFlags dflags1
io $ checkProcessArgsResult unhandled_flags
io $ handleFlagWarnings dflags1 warns
return (Hsc sf, output_fn)
runPhase (Hsc src_flavour) input_fn dflags0
= do
PipeEnv{ stop_phase=stop,
src_basename=basename,
src_suffix=suff } <- getPipeEnv
let current_dir = case takeDirectory basename of
"" -> "."
d -> d
paths = includePaths dflags0
dflags = dflags0 { includePaths = current_dir : paths }
setDynFlags dflags
(hspp_buf,mod_name,imps,src_imps) <- io $
case src_flavour of
ExtCoreFile -> do
m <- getCoreModuleName input_fn
return (Nothing, mkModuleName m, [], [])
_ -> do
buf <- hGetStringBuffer input_fn
(src_imps,imps,L _ mod_name) <- getImports dflags buf input_fn (basename <.> suff)
return (Just buf, mod_name, imps, src_imps)
location1 <- io $ mkHomeModLocation2 dflags mod_name basename suff
let location2 | isHsBoot src_flavour = addBootSuffixLocn location1
| otherwise = location1
let ohi = outputHi dflags
location3 | Just fn <- ohi = location2{ ml_hi_file = fn }
| otherwise = location2
let expl_o_file = outputFile dflags
location4 | Just ofile <- expl_o_file
, isNoLink (ghcLink dflags)
= location3 { ml_obj_file = ofile }
| otherwise = location3
o_file = ml_obj_file location4
setModLocation location4
src_timestamp <- io $ getModificationTime (basename <.> suff)
let hsc_lang = hscTarget dflags
source_unchanged <- io $
if not (isStopLn stop)
then return SourceModified
else do o_file_exists <- doesFileExist o_file
if not o_file_exists
then return SourceModified
else do t2 <- getModificationTime o_file
if t2 > src_timestamp
then return SourceUnmodified
else return SourceModified
let next_phase = hscPostBackendPhase dflags src_flavour hsc_lang
output_fn <- phaseOutputFilename next_phase
let dflags' = dflags { hscTarget = hsc_lang,
hscOutName = output_fn,
extCoreName = basename ++ ".hcr" }
setDynFlags dflags'
PipeState{hsc_env=hsc_env'} <- getPipeState
mod <- io $ addHomeModuleToFinder hsc_env' mod_name location4
let
mod_summary = ModSummary { ms_mod = mod,
ms_hsc_src = src_flavour,
ms_hspp_file = input_fn,
ms_hspp_opts = dflags,
ms_hspp_buf = hspp_buf,
ms_location = location4,
ms_hs_date = src_timestamp,
ms_obj_date = Nothing,
ms_textual_imps = imps,
ms_srcimps = src_imps }
result <- io $ hscCompileOneShot hsc_env'
mod_summary source_unchanged
Nothing
Nothing
case result of
HscNoRecomp
-> do io $ touchObjectFile dflags' o_file
return (StopLn, o_file)
(HscRecomp hasStub _)
-> do case hasStub of
Nothing -> return ()
Just stub_c ->
do stub_o <- io $ compileStub hsc_env' stub_c
setStubO stub_o
when (isHsBoot src_flavour) $
io $ touchObjectFile dflags' o_file
return (next_phase, output_fn)
runPhase CmmCpp input_fn dflags
= do
output_fn <- phaseOutputFilename Cmm
io $ doCpp dflags False True
input_fn output_fn
return (Cmm, output_fn)
runPhase Cmm input_fn dflags
= do
PipeEnv{src_basename} <- getPipeEnv
let hsc_lang = hscTarget dflags
let next_phase = hscPostBackendPhase dflags HsSrcFile hsc_lang
output_fn <- phaseOutputFilename next_phase
let dflags' = dflags { hscTarget = hsc_lang,
hscOutName = output_fn,
extCoreName = src_basename ++ ".hcr" }
setDynFlags dflags'
PipeState{hsc_env} <- getPipeState
io $ hscCompileCmmFile hsc_env input_fn
return (next_phase, output_fn)
runPhase cc_phase input_fn dflags
| any (cc_phase `eqPhase`) [Cc, Ccpp, HCc, Cobjc, Cobjcpp]
= do
let platform = targetPlatform dflags
cc_opts = getOpts dflags opt_c
hcc = cc_phase `eqPhase` HCc
let cmdline_include_paths = includePaths dflags
pkgs <- if hcc then io $ getHCFilePackages input_fn else return []
pkg_include_dirs <- io $ getPackageIncludePath dflags pkgs
let include_paths = foldr (\ x xs -> "-I" : x : xs) []
(cmdline_include_paths ++ pkg_include_dirs)
let gcc_extra_viac_flags = extraGccViaCFlags dflags
let pic_c_flags = picCCOpts dflags
let verbFlags = getVerbFlags dflags
pkg_extra_cc_opts <- io $
if cc_phase `eqPhase` HCc
then return []
else getPackageExtraCcOpts dflags pkgs
framework_paths <-
case platformOS platform of
OSDarwin ->
do pkgFrameworkPaths <- io $ getPackageFrameworkPath dflags pkgs
let cmdlineFrameworkPaths = frameworkPaths dflags
return $ map ("-F"++)
(cmdlineFrameworkPaths ++ pkgFrameworkPaths)
_ ->
return []
let split_objs = dopt Opt_SplitObjs dflags
split_opt | hcc && split_objs = [ "-DUSE_SPLIT_MARKERS" ]
| otherwise = [ ]
let cc_opt | optLevel dflags >= 2 = "-O2"
| otherwise = "-O"
let next_phase = As
output_fn <- phaseOutputFilename next_phase
let
more_hcc_opts =
(if platformArch platform == ArchX86 &&
not (dopt Opt_ExcessPrecision dflags)
then [ "-ffloat-store" ]
else []) ++
["-fno-strict-aliasing"]
let gcc_lang_opt | cc_phase `eqPhase` Ccpp = "c++"
| cc_phase `eqPhase` Cobjc = "objective-c"
| cc_phase `eqPhase` Cobjcpp = "objective-c++"
| otherwise = "c"
io $ SysTools.runCc dflags (
[ SysTools.Option "-x", SysTools.Option gcc_lang_opt
, SysTools.FileOption "" input_fn
, SysTools.Option "-o"
, SysTools.FileOption "" output_fn
]
++ map SysTools.Option (
pic_c_flags
++ (if platformOS platform == OSMinGW32 &&
thisPackage dflags == basePackageId
then [ "-DCOMPILING_BASE_PACKAGE" ]
else [])
++ (if platformArch platform == ArchSPARC
then ["-mcpu=v9"]
else [])
++ (if hcc
then gcc_extra_viac_flags ++ more_hcc_opts
else [])
++ verbFlags
++ [ "-S", "-Wimplicit", cc_opt ]
++ [ "-D__GLASGOW_HASKELL__="++cProjectVersionInt ]
++ framework_paths
++ cc_opts
++ split_opt
++ include_paths
++ pkg_extra_cc_opts
))
return (next_phase, output_fn)
runPhase Splitter input_fn dflags
= do
split_s_prefix <- io $ SysTools.newTempName dflags "split"
let n_files_fn = split_s_prefix
io $ SysTools.runSplit dflags
[ SysTools.FileOption "" input_fn
, SysTools.FileOption "" split_s_prefix
, SysTools.FileOption "" n_files_fn
]
s <- io $ readFile n_files_fn
let n_files = read s :: Int
dflags' = dflags { splitInfo = Just (split_s_prefix, n_files) }
setDynFlags dflags'
io $ addFilesToClean dflags' [ split_s_prefix ++ "__" ++ show n ++ ".s"
| n <- [1..n_files]]
return (SplitAs,
"**splitter**")
runPhase As input_fn dflags
= do
let whichAsProg | hscTarget dflags == HscLlvm &&
platformOS (targetPlatform dflags) == OSDarwin
= do
llvmVer <- io $ figureLlvmVersion dflags
return $ case llvmVer of
Just n | n >= 30 ->
(SysTools.runClang, cGccLinkerOpts)
_ -> (SysTools.runAs, getOpts dflags opt_a)
| otherwise
= return (SysTools.runAs, getOpts dflags opt_a)
(as_prog, as_opts) <- whichAsProg
let cmdline_include_paths = includePaths dflags
next_phase <- maybeMergeStub
output_fn <- phaseOutputFilename next_phase
io $ createDirectoryIfMissing True (takeDirectory output_fn)
io $ as_prog dflags
(map SysTools.Option as_opts
++ [ SysTools.Option ("-I" ++ p) | p <- cmdline_include_paths ]
++ (if platformArch (targetPlatform dflags) == ArchSPARC
then [SysTools.Option "-mcpu=v9"]
else [])
++ [ SysTools.Option "-c"
, SysTools.FileOption "" input_fn
, SysTools.Option "-o"
, SysTools.FileOption "" output_fn
])
return (next_phase, output_fn)
runPhase SplitAs _input_fn dflags
= do
let next_phase = StopLn
output_fn <- phaseOutputFilename next_phase
let base_o = dropExtension output_fn
osuf = objectSuf dflags
split_odir = base_o ++ "_" ++ osuf ++ "_split"
io $ createDirectoryIfMissing True split_odir
fs <- io $ getDirectoryContents split_odir
io $ mapM_ removeFile $
map (split_odir </>) $ filter (osuf `isSuffixOf`) fs
let as_opts = getOpts dflags opt_a
let (split_s_prefix, n) = case splitInfo dflags of
Nothing -> panic "No split info"
Just x -> x
let split_s n = split_s_prefix ++ "__" ++ show n <.> "s"
split_obj :: Int -> FilePath
split_obj n = split_odir </>
takeFileName base_o ++ "__" ++ show n <.> osuf
let assemble_file n
= SysTools.runAs dflags
(map SysTools.Option as_opts ++
(if platformArch (targetPlatform dflags) == ArchSPARC
then [SysTools.Option "-mcpu=v9"]
else []) ++
[ SysTools.Option "-c"
, SysTools.Option "-o"
, SysTools.FileOption "" (split_obj n)
, SysTools.FileOption "" (split_s n)
])
io $ mapM_ assemble_file [1..n]
PipeState{maybe_stub_o} <- getPipeState
case maybe_stub_o of
Nothing -> return ()
Just stub_o -> io $ do
tmp_split_1 <- newTempName dflags osuf
let split_1 = split_obj 1
copyFile split_1 tmp_split_1
removeFile split_1
joinObjectFiles dflags [tmp_split_1, stub_o] split_1
io $ joinObjectFiles dflags (map split_obj [1..n]) output_fn
return (next_phase, output_fn)
runPhase LlvmOpt input_fn dflags
= do
let lo_opts = getOpts dflags opt_lo
let opt_lvl = max 0 (min 2 $ optLevel dflags)
let optFlag = if null lo_opts
then [SysTools.Option (llvmOpts !! opt_lvl)]
else []
output_fn <- phaseOutputFilename LlvmLlc
io $ SysTools.runLlvmOpt dflags
([ SysTools.FileOption "" input_fn,
SysTools.Option "-o",
SysTools.FileOption "" output_fn]
++ optFlag
++ map SysTools.Option lo_opts)
return (LlvmLlc, output_fn)
where
llvmOpts = ["-mem2reg", "-O1", "-O2"]
runPhase LlvmLlc input_fn dflags
= do
let lc_opts = getOpts dflags opt_lc
opt_lvl = max 0 (min 2 $ optLevel dflags)
rmodel | opt_PIC = "pic"
| not opt_Static = "dynamic-no-pic"
| otherwise = "static"
let next_phase = case dopt Opt_NoLlvmMangler dflags of
False -> LlvmMangle
True | dopt Opt_SplitObjs dflags -> Splitter
True -> As
output_fn <- phaseOutputFilename next_phase
io $ SysTools.runLlvmLlc dflags
([ SysTools.Option (llvmOpts !! opt_lvl),
SysTools.Option $ "-relocation-model=" ++ rmodel,
SysTools.FileOption "" input_fn,
SysTools.Option "-o", SysTools.FileOption "" output_fn]
++ map SysTools.Option lc_opts
++ map SysTools.Option fpOpts)
return (next_phase, output_fn)
where
llvmOpts = if platformOS (targetPlatform dflags) == OSDarwin
then ["-O1", "-O2", "-O2"]
else ["-O1", "-O2", "-O3"]
fpOpts = case platformArch (targetPlatform dflags) of
ArchARM ARMv7 ext -> if (elem VFPv3 ext)
then ["-mattr=+v7,+vfp3"]
else if (elem VFPv3D16 ext)
then ["-mattr=+v7,+vfp3,+d16"]
else []
_ -> []
runPhase LlvmMangle input_fn dflags
= do
let next_phase = if dopt Opt_SplitObjs dflags then Splitter else As
output_fn <- phaseOutputFilename next_phase
io $ llvmFixupAsm dflags input_fn output_fn
return (next_phase, output_fn)
runPhase MergeStub input_fn dflags
= do
PipeState{maybe_stub_o} <- getPipeState
output_fn <- phaseOutputFilename StopLn
case maybe_stub_o of
Nothing ->
panic "runPhase(MergeStub): no stub"
Just stub_o -> do
io $ joinObjectFiles dflags [input_fn, stub_o] output_fn
return (StopLn, output_fn)
runPhase other _input_fn _dflags =
panic ("runPhase: don't know how to run phase " ++ show other)
maybeMergeStub :: CompPipeline Phase
maybeMergeStub
= do
PipeState{maybe_stub_o} <- getPipeState
if isJust maybe_stub_o then return MergeStub else return StopLn
runPhase_MoveBinary :: DynFlags -> FilePath -> IO Bool
runPhase_MoveBinary dflags input_fn
| WayPar `elem` (wayNames dflags) && not opt_Static =
panic ("Don't know how to combine PVM wrapper and dynamic wrapper")
| WayPar `elem` (wayNames dflags) = do
let sysMan = pgm_sysman dflags
pvm_root <- getEnv "PVM_ROOT"
pvm_arch <- getEnv "PVM_ARCH"
let
pvm_executable_base = "=" ++ input_fn
pvm_executable = pvm_root ++ "/bin/" ++ pvm_arch ++ "/" ++ pvm_executable_base
_ <- tryIO (removeFile pvm_executable)
copy dflags "copying PVM executable" input_fn pvm_executable
writeFile input_fn (mk_pvm_wrapper_script pvm_executable pvm_executable_base sysMan)
return True
| otherwise = return True
mkExtraObj :: DynFlags -> Suffix -> String -> IO FilePath
mkExtraObj dflags extn xs
= do cFile <- newTempName dflags extn
oFile <- newTempName dflags "o"
writeFile cFile xs
let rtsDetails = getPackageDetails (pkgState dflags) rtsPackageId
SysTools.runCc dflags
([Option "-c",
FileOption "" cFile,
Option "-o",
FileOption "" oFile]
++ map SysTools.Option (getOpts dflags opt_c)
++ map (FileOption "-I") (includeDirs rtsDetails))
return oFile
mkExtraObjToLinkIntoBinary :: DynFlags -> IO FilePath
mkExtraObjToLinkIntoBinary dflags = do
let have_rts_opts_flags =
isJust (rtsOpts dflags) || case rtsOptsEnabled dflags of
RtsOptsSafeOnly -> False
_ -> True
when (dopt Opt_NoHsMain dflags && have_rts_opts_flags) $ do
hPutStrLn stderr $ "Warning: -rtsopts and -with-rtsopts have no effect with -no-hs-main.\n" ++
" Call hs_init_ghc() from your main() function to set these options."
mkExtraObj dflags "c" (showSDoc main)
where
main
| dopt Opt_NoHsMain dflags = empty
| otherwise = vcat [
ptext (sLit "#include \"Rts.h\""),
ptext (sLit "extern StgClosure ZCMain_main_closure;"),
ptext (sLit "int main(int argc, char *argv[])"),
char '{',
ptext (sLit " RtsConfig __conf = defaultRtsConfig;"),
ptext (sLit " __conf.rts_opts_enabled = ")
<> text (show (rtsOptsEnabled dflags)) <> semi,
case rtsOpts dflags of
Nothing -> empty
Just opts -> ptext (sLit " __conf.rts_opts= ") <>
text (show opts) <> semi,
ptext (sLit " return hs_main(argc, argv, &ZCMain_main_closure,__conf);"),
char '}',
char '\n'
]
mkNoteObjsToLinkIntoBinary :: DynFlags -> [PackageId] -> IO [FilePath]
mkNoteObjsToLinkIntoBinary dflags dep_packages = do
link_info <- getLinkInfo dflags dep_packages
if (platformSupportsSavingLinkOpts (platformOS (targetPlatform dflags)))
then fmap (:[]) $ mkExtraObj dflags "s" (showSDoc (link_opts link_info))
else return []
where
link_opts info = hcat [
text "\t.section ", text ghcLinkInfoSectionName,
text ",\"\",",
text elfSectionNote,
text "\n",
text "\t.ascii \"", info', text "\"\n" ]
where
info' = text $ escape info
escape :: String -> String
escape = concatMap (charToC.fromIntegral.ord)
elfSectionNote :: String
elfSectionNote = case platformArch (targetPlatform dflags) of
ArchARM _ _ -> "%note"
_ -> "@note"
getLinkInfo :: DynFlags -> [PackageId] -> IO String
getLinkInfo dflags dep_packages = do
package_link_opts <- getPackageLinkOpts dflags dep_packages
pkg_frameworks <- case platformOS (targetPlatform dflags) of
OSDarwin -> getPackageFrameworks dflags dep_packages
_ -> return []
extra_ld_inputs <- readIORef v_Ld_inputs
let
link_info = (package_link_opts,
pkg_frameworks,
rtsOpts dflags,
rtsOptsEnabled dflags,
dopt Opt_NoHsMain dflags,
extra_ld_inputs,
getOpts dflags opt_l)
return (show link_info)
mk_pvm_wrapper_script :: String -> String -> String -> String
mk_pvm_wrapper_script pvm_executable pvm_executable_base sysMan = unlines $
[
"eval 'exec perl -S $0 ${1+\"$@\"}'",
" if $running_under_some_shell;",
"# =!=!=!=!=!=!=!=!=!=!=!",
"# This script is automatically generated: DO NOT EDIT!!!",
"# Generated by Glasgow Haskell Compiler",
"# ngoqvam choHbogh vaj' vIHoHnISbej !!!!",
"#",
"$pvm_executable = '" ++ pvm_executable ++ "';",
"$pvm_executable_base = '" ++ pvm_executable_base ++ "';",
"$SysMan = '" ++ sysMan ++ "';",
"",
"",
"# Now, run the real binary; process the args first",
"$ENV{'PE'} = $pvm_executable_base;",
"$debug = '';",
"$nprocessors = 0; # the default: as many PEs as machines in PVM config",
"@nonPVM_args = ();",
"$in_RTS_args = 0;",
"",
"args: while ($a = shift(@ARGV)) {",
" if ( $a eq '+RTS' ) {",
" $in_RTS_args = 1;",
" } elsif ( $a eq '-RTS' ) {",
" $in_RTS_args = 0;",
" }",
" if ( $a eq '-d' && $in_RTS_args ) {",
" $debug = '-';",
" } elsif ( $a =~ /^-qN(\\d+)/ && $in_RTS_args ) {",
" $nprocessors = $1;",
" } elsif ( $a =~ /^-qp(\\d+)/ && $in_RTS_args ) {",
" $nprocessors = $1;",
" } else {",
" push(@nonPVM_args, $a);",
" }",
"}",
"",
"local($return_val) = 0;",
"# Start the parallel execution by calling SysMan",
"system(\"$SysMan $debug $pvm_executable $nprocessors @nonPVM_args\");",
"$return_val = $?;",
"# ToDo: fix race condition moving files and flushing them!!",
"system(\"cp $ENV{'HOME'}/$pvm_executable_base.???.gr .\") if -f \"$ENV{'HOME'}/$pvm_executable_base.002.gr\";",
"exit($return_val);"
]
getHCFilePackages :: FilePath -> IO [PackageId]
getHCFilePackages filename =
Exception.bracket (openFile filename ReadMode) hClose $ \h -> do
l <- hGetLine h
case l of
'/':'*':' ':'G':'H':'C':'_':'P':'A':'C':'K':'A':'G':'E':'S':rest ->
return (map stringToPackageId (words rest))
_other ->
return []
linkBinary :: DynFlags -> [FilePath] -> [PackageId] -> IO ()
linkBinary dflags o_files dep_packages = do
let platform = targetPlatform dflags
verbFlags = getVerbFlags dflags
output_fn = exeFileName dflags
pkg_lib_paths <- getPackageLibraryPath dflags dep_packages
let pkg_lib_path_opts = concat (map get_pkg_lib_path_opts pkg_lib_paths)
get_pkg_lib_path_opts l
| osElfTarget (platformOS platform) &&
dynLibLoader dflags == SystemDependent &&
not opt_Static
= ["-L" ++ l, "-Wl,-rpath", "-Wl," ++ l]
| otherwise = ["-L" ++ l]
let lib_paths = libraryPaths dflags
let lib_path_opts = map ("-L"++) lib_paths
extraLinkObj <- mkExtraObjToLinkIntoBinary dflags
noteLinkObjs <- mkNoteObjsToLinkIntoBinary dflags dep_packages
pkg_link_opts <- getPackageLinkOpts dflags dep_packages
pkg_framework_path_opts <-
case platformOS platform of
OSDarwin ->
do pkg_framework_paths <- getPackageFrameworkPath dflags dep_packages
return $ map ("-F" ++) pkg_framework_paths
_ ->
return []
framework_path_opts <-
case platformOS platform of
OSDarwin ->
do let framework_paths = frameworkPaths dflags
return $ map ("-F" ++) framework_paths
_ ->
return []
pkg_framework_opts <-
case platformOS platform of
OSDarwin ->
do pkg_frameworks <- getPackageFrameworks dflags dep_packages
return $ concat [ ["-framework", fw] | fw <- pkg_frameworks ]
_ ->
return []
framework_opts <-
case platformOS platform of
OSDarwin ->
do let frameworks = cmdlineFrameworks dflags
return $ concat [ ["-framework", fw] | fw <- reverse frameworks ]
_ ->
return []
extra_ld_inputs <- readIORef v_Ld_inputs
let extra_ld_opts = getOpts dflags opt_l
let ways = wayNames dflags
let
debug_opts | WayDebug `elem` ways = [
#if defined(HAVE_LIBBFD)
"-lbfd", "-liberty"
#endif
]
| otherwise = []
let
thread_opts | WayThreaded `elem` ways = [
#if !defined(mingw32_TARGET_OS) && !defined(freebsd_TARGET_OS) && !defined(openbsd_TARGET_OS) && !defined(netbsd_TARGET_OS) && !defined(haiku_TARGET_OS)
"-lpthread"
#endif
#if defined(osf3_TARGET_OS)
, "-lexc"
#endif
]
| otherwise = []
rc_objs <- maybeCreateManifest dflags output_fn
SysTools.runLink dflags (
map SysTools.Option verbFlags
++ [ SysTools.Option "-o"
, SysTools.FileOption "" output_fn
]
++ map SysTools.Option (
[]
++ (if platformOS platform == OSMinGW32
then ["-Wl,--enable-auto-import"]
else [])
++ (if cLdHasNoCompactUnwind == "YES" &&
platformOS platform == OSDarwin &&
platformArch platform `elem` [ArchX86, ArchX86_64]
then ["-Wl,-no_compact_unwind"]
else [])
++ (if platformOS platform == OSDarwin &&
platformArch platform == ArchX86
then ["-Wl,-read_only_relocs,suppress"]
else [])
++ o_files
++ extra_ld_inputs
++ lib_path_opts
++ extra_ld_opts
++ rc_objs
++ framework_path_opts
++ framework_opts
++ pkg_lib_path_opts
++ extraLinkObj:noteLinkObjs
++ pkg_link_opts
++ pkg_framework_path_opts
++ pkg_framework_opts
++ debug_opts
++ thread_opts
))
success <- runPhase_MoveBinary dflags output_fn
if success then return ()
else ghcError (InstallationError ("cannot move binary"))
exeFileName :: DynFlags -> FilePath
exeFileName dflags
| Just s <- outputFile dflags =
if platformOS (targetPlatform dflags) == OSMinGW32
then if null (takeExtension s)
then s <.> "exe"
else s
else s
| otherwise =
if platformOS (targetPlatform dflags) == OSMinGW32
then "main.exe"
else "a.out"
maybeCreateManifest
:: DynFlags
-> FilePath
-> IO [FilePath]
maybeCreateManifest dflags exe_filename
| platformOS (targetPlatform dflags) == OSMinGW32 &&
dopt Opt_GenManifest dflags
= do let manifest_filename = exe_filename <.> "manifest"
writeFile manifest_filename $
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n"++
" <assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">\n"++
" <assemblyIdentity version=\"1.0.0.0\"\n"++
" processorArchitecture=\"X86\"\n"++
" name=\"" ++ dropExtension exe_filename ++ "\"\n"++
" type=\"win32\"/>\n\n"++
" <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n"++
" <security>\n"++
" <requestedPrivileges>\n"++
" <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"/>\n"++
" </requestedPrivileges>\n"++
" </security>\n"++
" </trustInfo>\n"++
"</assembly>\n"
if not (dopt Opt_EmbedManifest dflags) then return [] else do
rc_filename <- newTempName dflags "rc"
rc_obj_filename <- newTempName dflags (objectSuf dflags)
writeFile rc_filename $
"1 24 MOVEABLE PURE " ++ show manifest_filename ++ "\n"
let wr_opts = getOpts dflags opt_windres
runWindres dflags $ map SysTools.Option $
["--input="++rc_filename,
"--output="++rc_obj_filename,
"--output-format=coff"]
++ wr_opts
removeFile manifest_filename
return [rc_obj_filename]
| otherwise = return []
linkDynLib :: DynFlags -> [String] -> [PackageId] -> IO ()
linkDynLib dflags o_files dep_packages = do
let verbFlags = getVerbFlags dflags
let o_file = outputFile dflags
pkgs <- getPreloadPackagesAnd dflags dep_packages
let pkg_lib_paths = collectLibraryPaths pkgs
let pkg_lib_path_opts = concatMap get_pkg_lib_path_opts pkg_lib_paths
get_pkg_lib_path_opts l
| osElfTarget (platformOS (targetPlatform dflags)) &&
dynLibLoader dflags == SystemDependent &&
not opt_Static
= ["-L" ++ l, "-Wl,-rpath", "-Wl," ++ l]
| otherwise = ["-L" ++ l]
let lib_paths = libraryPaths dflags
let lib_path_opts = map ("-L"++) lib_paths
let pkgs_no_rts = case platformOS (targetPlatform dflags) of
OSMinGW32 ->
pkgs
_ ->
filter ((/= rtsPackageId) . packageConfigId) pkgs
let pkg_link_opts = collectLinkOpts dflags pkgs_no_rts
extra_ld_inputs <- readIORef v_Ld_inputs
let extra_ld_opts = getOpts dflags opt_l
#if defined(mingw32_HOST_OS)
let output_fn = case o_file of { Just s -> s; Nothing -> "HSdll.dll"; }
SysTools.runLink dflags (
map SysTools.Option verbFlags
++ [ SysTools.Option "-o"
, SysTools.FileOption "" output_fn
, SysTools.Option "-shared"
] ++
[ SysTools.FileOption "-Wl,--out-implib=" (output_fn ++ ".a")
| dopt Opt_SharedImplib dflags
]
++ map (SysTools.FileOption "") o_files
++ map SysTools.Option (
["-Wl,--enable-auto-import"]
++ extra_ld_inputs
++ lib_path_opts
++ extra_ld_opts
++ pkg_lib_path_opts
++ pkg_link_opts
))
#elif defined(darwin_TARGET_OS)
let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }
instName <- case dylibInstallName dflags of
Just n -> return n
Nothing -> do
pwd <- getCurrentDirectory
return $ pwd `combine` output_fn
SysTools.runLink dflags (
map SysTools.Option verbFlags
++ [ SysTools.Option "-dynamiclib"
, SysTools.Option "-o"
, SysTools.FileOption "" output_fn
]
++ map SysTools.Option (
o_files
++ [ "-undefined", "dynamic_lookup", "-single_module",
#if !defined(x86_64_TARGET_ARCH)
"-Wl,-read_only_relocs,suppress",
#endif
"-install_name", instName ]
++ extra_ld_inputs
++ lib_path_opts
++ extra_ld_opts
++ pkg_lib_path_opts
++ pkg_link_opts
))
#else
let output_fn = case o_file of { Just s -> s; Nothing -> "a.out"; }
let buildingRts = thisPackage dflags == rtsPackageId
let bsymbolicFlag = if buildingRts
then
[]
else
["-Wl,-Bsymbolic"]
SysTools.runLink dflags (
map SysTools.Option verbFlags
++ [ SysTools.Option "-o"
, SysTools.FileOption "" output_fn
]
++ map SysTools.Option (
o_files
++ [ "-shared" ]
++ bsymbolicFlag
++ [ "-Wl,-h," ++ takeFileName output_fn ]
++ extra_ld_inputs
++ lib_path_opts
++ extra_ld_opts
++ pkg_lib_path_opts
++ pkg_link_opts
))
#endif
doCpp :: DynFlags -> Bool -> Bool -> FilePath -> FilePath -> IO ()
doCpp dflags raw include_cc_opts input_fn output_fn = do
let hscpp_opts = getOpts dflags opt_P
let cmdline_include_paths = includePaths dflags
pkg_include_dirs <- getPackageIncludePath dflags []
let include_paths = foldr (\ x xs -> "-I" : x : xs) []
(cmdline_include_paths ++ pkg_include_dirs)
let verbFlags = getVerbFlags dflags
let cc_opts
| include_cc_opts = getOpts dflags opt_c
| otherwise = []
let cpp_prog args | raw = SysTools.runCpp dflags args
| otherwise = SysTools.runCc dflags (SysTools.Option "-E" : args)
let target_defs =
[ "-D" ++ HOST_OS ++ "_BUILD_OS=1",
"-D" ++ HOST_ARCH ++ "_BUILD_ARCH=1",
"-D" ++ TARGET_OS ++ "_HOST_OS=1",
"-D" ++ TARGET_ARCH ++ "_HOST_ARCH=1" ]
cpp_prog ( map SysTools.Option verbFlags
++ map SysTools.Option include_paths
++ map SysTools.Option hsSourceCppOpts
++ map SysTools.Option target_defs
++ map SysTools.Option hscpp_opts
++ map SysTools.Option cc_opts
++ [ SysTools.Option "-x"
, SysTools.Option "c"
, SysTools.Option input_fn
, SysTools.Option "-o"
, SysTools.FileOption "" output_fn
])
hsSourceCppOpts :: [String]
hsSourceCppOpts =
[ "-D__GLASGOW_HASKELL__="++cProjectVersionInt ]
joinObjectFiles :: DynFlags -> [FilePath] -> FilePath -> IO ()
joinObjectFiles dflags o_files output_fn = do
let ld_r args = SysTools.runLink dflags ([
SysTools.Option "-nostdlib",
SysTools.Option "-nodefaultlibs",
SysTools.Option "-Wl,-r"
]
++ (if platformArch (targetPlatform dflags) == ArchSPARC
then [SysTools.Option "-Wl,-no-relax"]
else [])
++ [
SysTools.Option ld_build_id,
SysTools.Option "-o",
SysTools.FileOption "" output_fn ]
++ args)
ld_build_id | cLdHasBuildId == "YES" = "-Wl,--build-id=none"
| otherwise = ""
if cLdIsGNULd == "YES"
then do
script <- newTempName dflags "ldscript"
writeFile script $ "INPUT(" ++ unwords o_files ++ ")"
ld_r [SysTools.FileOption "" script]
else do
ld_r (map (SysTools.FileOption "") o_files)
hscPostBackendPhase :: DynFlags -> HscSource -> HscTarget -> Phase
hscPostBackendPhase _ HsBootFile _ = StopLn
hscPostBackendPhase dflags _ hsc_lang =
case hsc_lang of
HscC -> HCc
HscAsm | dopt Opt_SplitObjs dflags -> Splitter
| otherwise -> As
HscLlvm -> LlvmOpt
HscNothing -> StopLn
HscInterpreted -> StopLn
touchObjectFile :: DynFlags -> FilePath -> IO ()
touchObjectFile dflags path = do
createDirectoryIfMissing True $ takeDirectory path
SysTools.touch dflags "Touching object file" path