-----------------------------------------------------------------------------
--- $Id: DriverPipeline.hs,v 1.50 2001/02/05 17:52:49 rrt Exp $
+-- $Id: DriverPipeline.hs,v 1.57 2001/03/23 16:36:20 simonmar Exp $
--
-- GHC Driver
--
import DriverFlags
import HscMain
import TmpFiles
+import Finder
import HscTypes
import Outputable
import Module
-- 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
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 ]
| otherwise = [ ] -- just pass this file through to the linker
-- ToDo: this is somewhat cryptic
+
not_valid = throwDyn (OtherError ("invalid option combination"))
----------- ----- ---- --- -- -- - - -
StopBefore phase -> phase
DoMkDependHS -> Ln
DoLink -> Ln
- annotated_pipeline = annotatePipeline (pipeline ++ [ Ln ]) stop_phase
+
+ annotated_pipeline = annotatePipeline (pipeline ++ [Ln]) stop_phase
phase_ne p (p1,_,_) = (p1 /= p)
----------- ----- ---- --- -- -- - - -
run_phase Cpp basename suff input_fn output_fn
= do src_opts <- getOptionsFromSource input_fn
unhandled_flags <- processArgs dynamic_flags src_opts []
-
- when (not (null unhandled_flags))
- (throwDyn (OtherError (
- basename ++ "." ++ suff
- ++ ": static flags are not allowed in {-# OPTIONS #-} pragmas:\n\t"
- ++ unwords unhandled_flags)) (ExitFailure 1))
+ checkProcessArgsResult unhandled_flags basename suff
do_cpp <- dynFlag cppFlag
if do_cpp
Nothing -> basename ++ '.':hisuf
Just fn -> fn
+ -- figure out which header files to #include in a generated .hc file
+ c_includes <- getPackageCIncludes
+ cmdline_includes <- dynFlag cmdlineHcIncludes -- -#include options
+
+ let cc_injects = unlines (map mk_include
+ (c_includes ++ reverse cmdline_includes))
+ mk_include h_file =
+ case h_file of
+ '"':_{-"-} -> "#include "++h_file
+ '<':_ -> "#include "++h_file
+ _ -> "#include \""++h_file++"\""
+
+ writeIORef v_HCHeader cc_injects
+
-- figure out if the source has changed, for recompilation avoidance.
-- only do this if we're eventually going to generate a .o file.
-- (ToDo: do when generating .hc files too?)
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
+ False
Nothing -- no iface
emptyModuleEnv -- HomeSymbolTable
emptyModuleEnv -- HomeIfaceTable
-- we don't support preprocessing .c files (with -E) now. Doing so introduces
-- way too many hacks, and I can't say I've ever used it anyway.
-run_phase cc_phase _basename _suff input_fn output_fn
+run_phase cc_phase basename suff input_fn output_fn
| cc_phase == Cc || cc_phase == HCc
= do cc <- readIORef v_Pgm_c
cc_opts <- (getOpts opt_c)
let include_paths = map (\p -> "-I"++p) (cmdline_include_dirs
++ pkg_include_dirs)
- c_includes <- getPackageCIncludes
- cmdline_includes <- dynFlag cmdlineHcIncludes -- -#include options
-
- let cc_injects | hcc = unlines (map mk_include
- (c_includes ++ reverse cmdline_includes))
- | otherwise = ""
- mk_include h_file =
- case h_file of
- '"':_{-"-} -> "#include "++h_file
- '<':_ -> "#include "++h_file
- _ -> "#include \""++h_file++"\""
-
- cc_help <- newTempName "c"
- h <- openFile cc_help WriteMode
- hPutStr h cc_injects
- hPutStrLn h ("#include \"" ++ input_fn ++ "\"\n")
- hClose h
-
- ccout <- newTempName "ccout"
-
mangle <- readIORef v_Do_asm_mangling
(md_c_flags, md_regd_c_flags) <- machdepCCOpts
excessPrecision <- readIORef v_Excess_precision
runSomething "C Compiler"
- (unwords ([ cc, "-x", "c", cc_help, "-o", output_fn ]
+ (unwords ([ cc, "-x", "c", input_fn, "-o", output_fn ]
++ md_c_flags
++ (if cc_phase == HCc && mangle
then md_regd_c_flags
++ (if excessPrecision then [] else [ "-ffloat-store" ])
++ include_paths
++ pkg_extra_cc_opts
--- ++ [">", ccout]
))
return True
return True
-----------------------------------------------------------------------------
+-- MoveBinary sort-of-phase
+-- After having produced a binary, move it somewhere else and generate a
+-- wrapper script calling the binary. Currently, we need this only in
+-- a parallel way (i.e. in GUM), because PVM expects the binary in a
+-- central directory.
+-- This is called from doLink below, after linking. I haven't made it
+-- a separate phase to minimise interfering with other modules, and
+-- we don't need the generality of a phase (MoveBinary is always
+-- done after linking and makes only sense in a parallel setup) -- HWL
+
+run_phase_MoveBinary input_fn
+ = do
+ top_dir <- readIORef v_TopDir
+ 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
+ sysMan = top_dir ++ "/ghc/rts/parallel/SysMan";
+ -- nuke old binary; maybe use configur'ed names for cp and rm?
+ system ("rm -f " ++ pvm_executable)
+ -- move the newly created binary into PVM land
+ system ("cp -p " ++ input_fn ++ " " ++ pvm_executable)
+ -- generate a wrapper script for running a parallel prg under PVM
+ writeFile input_fn (mk_pvm_wrapper_script pvm_executable pvm_executable_base sysMan)
+ return True
+
+-- generates a Perl skript starting a parallel prg under PVM
+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 ++ "';",
+ "",
+ {- ToDo: add the magical shortcuts again iff we actually use them -- HWL
+ "# first, some magical shortcuts to run "commands" on the binary",
+ "# (which is hidden)",
+ "if ($#ARGV == 1 && $ARGV[0] eq '+RTS' && $ARGV[1] =~ /^--((size|file|strip|rm|nm).*)/ ) {",
+ " local($cmd) = $1;",
+ " system("$cmd $pvm_executable");",
+ " exit(0); # all done",
+ "}", -}
+ "",
+ "# Now, run the real binary; process the args first",
+ "$ENV{'PE'} = $pvm_executable_base;", -- ++ 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);"
+ ]
+
+-----------------------------------------------------------------------------
+-- Complain about non-dynamic flags in OPTIONS pragmas
+
+checkProcessArgsResult flags basename suff
+ = do when (not (null flags)) (throwDyn (OtherError (
+ basename ++ "." ++ suff
+ ++ ": static flags are not allowed in {-# OPTIONS #-} pragmas:\n\t"
+ ++ unwords flags)) (ExitFailure 1))
+
+-----------------------------------------------------------------------------
-- Linking
doLink :: [String] -> IO ()
#endif
)
)
+ -- parallel only: move binary to another dir -- HWL
+ ways_ <- readIORef v_Ways
+ when (WayPar `elem` ways_) (do
+ success <- run_phase_MoveBinary output_fn
+ if success then return ()
+ else throwDyn (OtherError ("cannot move binary to PVM dir")))
-----------------------------------------------------------------------------
-- Making a DLL
compile :: GhciMode -- distinguish batch from interactive
-> ModSummary -- summary, including source
- -> Bool -- source unchanged?
+ -> Bool -- True <=> source unchanged
+ -> Bool -- True <=> have object
-> Maybe ModIface -- old interface, if available
-> HomeSymbolTable -- for home module ModDetails
-> HomeIfaceTable -- for home module Ifaces
| CompErrs PersistentCompilerState -- updated PCS
-compile ghci_mode summary source_unchanged old_iface hst hit pcs = do
+compile ghci_mode summary source_unchanged have_object
+ old_iface hst hit pcs = do
init_dyn_flags <- readIORef v_InitDynFlags
writeIORef v_DynFlags init_dyn_flags
HscAsm -> newTempName (phaseInputExt As)
HscC -> newTempName (phaseInputExt HCc)
HscJava -> newTempName "java" -- ToDo
+#ifdef ILX
+ HscILX -> newTempName "ilx" -- ToDo
+#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 have_object old_iface hst hit pcs
case hsc_result of
HscFail pcs -> return (CompErrs pcs)