-----------------------------------------------------------------------------
--- $Id: DriverPipeline.hs,v 1.43 2000/12/18 15:17:46 simonmar Exp $
+-- $Id: DriverPipeline.hs,v 1.53 2001/03/06 15:00:25 rrt Exp $
--
-- GHC Driver
--
--
-----------------------------------------------------------------------------
+#include "../includes/config.h"
+
module DriverPipeline (
-- interfaces for the batch-mode driver
GhcMode(..), getGhcMode, v_GhcMode,
- genPipeline, runPipeline,
+ genPipeline, runPipeline, pipeLoop,
-- interfaces for the compilation manager (interpreted/batch-mode)
preprocess, compile, CompResult(..),
-- batch-mode linking interface
- doLink
+ doLink,
+ -- DLL building
+ doMkDLL
) where
#include "HsVersions.h"
-import CmStaticInfo ( GhciMode(..) )
+import CmStaticInfo
import CmTypes
import GetImports
import DriverState
import DriverFlags
import HscMain
import TmpFiles
+import Finder
import HscTypes
import Outputable
import Module
import Monad
import Maybe
+import PackedString
+import MatchPS
+
-----------------------------------------------------------------------------
-- GHC modes of operation
data GhcMode
= DoMkDependHS -- ghc -M
- | DoMkDLL -- ghc -mk-dll
+ | DoMkDLL -- ghc --mk-dll
| StopBefore Phase -- ghc -E | -C | -S | -c
| DoMake -- ghc --make
| DoInteractive -- ghc --interactive
modeFlag :: String -> Maybe GhcMode
modeFlag "-M" = Just $ DoMkDependHS
+modeFlag "--mk-dll" = Just $ DoMkDLL
modeFlag "-E" = Just $ StopBefore Hsc
modeFlag "-C" = Just $ StopBefore HCc
modeFlag "-S" = Just $ StopBefore As
([(flag,one)], rest) -> return (rest, one, flag)
(_ , _ ) ->
throwDyn (OtherError
- "only one of the flags -M, -E, -C, -S, -c, --make, --interactive is allowed")
+ "only one of the flags -M, -E, -C, -S, -c, --make, --interactive, -mk-dll is allowed")
-----------------------------------------------------------------------------
-- genPipeline
--
-- Herein is all the magic about which phases to run in which order, whether
--- the intermediate files should be in /tmp or in the current directory,
+-- the intermediate files should be in TMPDIR or in the current directory,
-- what the suffix of the intermediate files should be, etc.
-- The following compilation pipeline algorithm is fairly hacky. A
----------- ----- ---- --- -- -- - - -
(_basename, suffix) = splitFilename filename
- start_phase = startPhase suffix
+ start = startPhase suffix
+
+ -- special case for mkdependHS: .hspp files go through MkDependHS
+ start_phase | todo == DoMkDependHS && start == Hsc = MkDependHS
+ | otherwise = start
haskellish = haskellish_suffix suffix
cish = cish_suffix suffix
- -- for a .hc file we need to force lang to HscC
+ -- for a .hc file we need to force lang to HscC
real_lang | start_phase == HCc = HscC
| otherwise = lang
HscJava | split -> not_valid
| otherwise -> error "not implemented: compiling via Java"
+#ifdef ILX
+ HscILX | split -> not_valid
+ | otherwise -> [ Unlit, Cpp, Hsc ]
+#endif
| cish = [ Cc, As ]
++ filename))
else do
- -- if we can't find the phase we're supposed to stop before,
- -- something has gone wrong.
- case todo of
- StopBefore phase ->
- when (phase /= Ln
- && phase `notElem` pipeline
- && not (phase == As && SplitAs `elem` pipeline)) $
- throwDyn (OtherError
- ("flag " ++ stop_flag
- ++ " is incompatible with source file `" ++ filename ++ "'"))
- _ -> return ()
-
let
----------- ----- ---- --- -- -- - - -
myPhaseInputExt Ln = case osuf of Nothing -> phaseInputExt Ln
phase_ne p (p1,_,_) = (p1 /= p)
----------- ----- ---- --- -- -- - - -
- return $
- dropWhile (phase_ne start_phase) .
- foldr (\p ps -> if phase_ne stop_phase p then p:ps else []) []
- $ annotated_pipeline
+ -- if we can't find the phase we're supposed to stop before,
+ -- something has gone wrong. This test carefully avoids the
+ -- case where we aren't supposed to do any compilation, because the file
+ -- is already in linkable form (for example).
+ if start_phase `elem` pipeline &&
+ (stop_phase /= Ln && stop_phase `notElem` pipeline)
+ then throwDyn (OtherError
+ ("flag " ++ stop_flag
+ ++ " is incompatible with source file `" ++ filename ++ "'"))
+ else do
+
+ return (
+ takeWhile (phase_ne stop_phase ) $
+ dropWhile (phase_ne start_phase) $
+ annotated_pipeline
+ )
runPipeline
++ ": static flags are not allowed in {-# OPTIONS #-} pragmas:\n\t"
++ unwords unhandled_flags)) (ExitFailure 1))
- do_cpp <- readState cpp_flag
+ do_cpp <- dynFlag cppFlag
if do_cpp
then do
cpp <- readIORef v_Pgm_P
++ pkg_include_dirs)
verb <- getVerbFlag
+ (md_c_flags, _) <- machdepCCOpts
runSomething "C pre-processor"
(unwords
- (["echo '{-# LINE 1 \"" ++ input_fn ++ "\" -}'", ">", output_fn, "&&",
+ (["echo '{-# LINE 1 \"" ++ input_fn ++ "\" #-}'", ">", output_fn, "&&",
cpp, verb]
++ include_paths
++ hs_src_cpp_opts
++ hscpp_opts
+ ++ md_c_flags
++ [ "-x", "c", input_fn, ">>", output_fn ]
))
else do
runSomething "Ineffective C pre-processor"
- ("echo '{-# LINE 1 \"" ++ input_fn ++ "\" -}' > "
+ ("echo '{-# LINE 1 \"" ++ input_fn ++ "\" #-}' > "
++ output_fn ++ " && cat " ++ input_fn
++ " >> " ++ output_fn)
return True
then return True
else return False
- -- build a ModuleLocation to pass to hscMain.
- let location = ModuleLocation {
- ml_hs_file = Nothing,
- ml_hspp_file = Just input_fn,
- ml_hi_file = Just hifile,
- ml_obj_file = Just o_file
- }
+ -- build a ModuleLocation to pass to hscMain.
+ modsrc <- readFile input_fn
+ let (srcimps,imps,mod_name) = getImports modsrc
+
+ Just (mod, location)
+ <- mkHomeModuleLocn mod_name basename (basename ++ '.':suff)
-- get the DynFlags
dyn_flags <- readIORef v_DynFlags
pcs <- initPersistentCompilerState
result <- hscMain OneShot
dyn_flags{ hscOutName = output_fn }
+ mod
+ location{ ml_hspp_file=Just input_fn }
source_unchanged
- location
Nothing -- no iface
emptyModuleEnv -- HomeSymbolTable
emptyModuleEnv -- HomeIfaceTable
++ pkg_include_dirs)
c_includes <- getPackageCIncludes
- cmdline_includes <- readState cmdline_hc_includes -- -#include options
+ cmdline_includes <- dynFlag cmdlineHcIncludes -- -#include options
let cc_injects | hcc = unlines (map mk_include
(c_includes ++ reverse cmdline_includes))
mangler_opts <- getOpts opt_m
machdep_opts <-
if (prefixMatch "i386" cTARGETPLATFORM)
- then do n_regs <- readState stolen_x86_regs
+ then do n_regs <- dynFlag stolen_x86_regs
return [ show n_regs ]
else return []
runSomething "Assembly Mangler"
#ifdef mingw32_TARGET_OS
let extra_os = if static || no_hs_main
then []
--- else [ head (lib_paths (head rts_pkg)) ++ "/Main.dll_o",
--- head (lib_paths (head std_pkg)) ++ "/PrelMain.dll_o" ]
- else []
+ else [ head (library_dirs (head rts_pkg)) ++ "/Main.dll_o",
+ head (library_dirs (head std_pkg)) ++ "/PrelMain.dll_o" ]
#endif
(md_c_flags, _) <- machdepCCOpts
runSomething "Linker"
)
-----------------------------------------------------------------------------
+-- Making a DLL
+
+-- only for Win32, but bits that are #ifdefed in doLn are still #ifdefed here
+-- in a vain attempt to aid future portability
+doMkDLL :: [String] -> IO ()
+doMkDLL o_files = do
+ ln <- readIORef v_Pgm_dll
+ verb <- getVerbFlag
+ static <- readIORef v_Static
+ let imp = if static then "" else "_imp"
+ no_hs_main <- readIORef v_NoHsMain
+
+ o_file <- readIORef v_Output_file
+ let output_fn = case o_file of { Just s -> s; Nothing -> "HSdll.dll"; }
+
+ pkg_lib_paths <- getPackageLibraryPath
+ let pkg_lib_path_opts = map ("-L"++) pkg_lib_paths
+
+ lib_paths <- readIORef v_Library_paths
+ let lib_path_opts = map ("-L"++) lib_paths
+
+ pkg_libs <- getPackageLibraries
+ let pkg_lib_opts = map (\lib -> "-l" ++ lib ++ imp) pkg_libs
+
+ libs <- readIORef v_Cmdline_libraries
+ let lib_opts = map ("-l"++) (reverse libs)
+ -- reverse because they're added in reverse order from the cmd line
+
+ pkg_extra_ld_opts <- getPackageExtraLdOpts
+
+ -- probably _stub.o files
+ extra_ld_inputs <- readIORef v_Ld_inputs
+
+ -- opts from -optdll-<blah>
+ extra_ld_opts <- getStaticOpts v_Opt_dll
+
+ rts_pkg <- getPackageDetails ["rts"]
+ std_pkg <- getPackageDetails ["std"]
+#ifdef mingw32_TARGET_OS
+ let extra_os = if static || no_hs_main
+ then []
+ else [ head (library_dirs (head rts_pkg)) ++ "/Main.dll_o",
+ head (library_dirs (head std_pkg)) ++ "/PrelMain.dll_o" ]
+#endif
+ (md_c_flags, _) <- machdepCCOpts
+ runSomething "DLL creator"
+ (unwords
+ ([ ln, verb, "-o", output_fn ]
+ ++ md_c_flags
+ ++ o_files
+#ifdef mingw32_TARGET_OS
+ ++ extra_os
+ ++ [ "--target=i386-mingw32" ]
+#endif
+ ++ extra_ld_inputs
+ ++ lib_path_opts
+ ++ lib_opts
+ ++ pkg_lib_path_opts
+ ++ pkg_lib_opts
+ ++ pkg_extra_ld_opts
+ ++ (case findPS (packString (concat extra_ld_opts)) (packString "--def") of
+ Nothing -> [ "--export-all" ]
+ Just _ -> [ "" ])
+ ++ extra_ld_opts
+ )
+ )
+
+-----------------------------------------------------------------------------
-- Just preprocess a file, put the result in a temp. file (used by the
-- compilation manager during the summary phase).
preprocess :: FilePath -> IO FilePath
preprocess filename =
ASSERT(haskellish_file filename)
- do init_driver_state <- readIORef v_InitDriverState
- writeIORef v_Driver_state init_driver_state
-
+ do init_dyn_flags <- readIORef v_InitDynFlags
+ writeIORef v_DynFlags init_dyn_flags
pipeline <- genPipeline (StopBefore Hsc) ("preprocess") False
defaultHscLang filename
runPipeline pipeline filename False{-no linking-} False{-no -o flag-}
-
-----------------------------------------------------------------------------
-- Compile a single module, under the control of the compilation manager.
--
compile ghci_mode summary source_unchanged old_iface hst hit pcs = do
init_dyn_flags <- readIORef v_InitDynFlags
writeIORef v_DynFlags init_dyn_flags
- init_driver_state <- readIORef v_InitDriverState
- writeIORef v_Driver_state init_driver_state
showPass init_dyn_flags
(showSDoc (text "Compiling" <+> ppr (name_of_summary summary)))
HscAsm -> newTempName (phaseInputExt As)
HscC -> newTempName (phaseInputExt HCc)
HscJava -> newTempName "java" -- ToDo
+#ifdef ILX
+ HscILX -> newTempName (phaseInputExt Ilx)
+#endif
HscInterpreted -> return (error "no output file")
-- run the compiler
hsc_result <- hscMain ghci_mode dyn_flags{ hscOutName = output_fn }
- source_unchanged
- location old_iface hst hit pcs
+ (ms_mod summary) location
+ source_unchanged old_iface hst hit pcs
case hsc_result of
HscFail pcs -> return (CompErrs pcs)