+ let (basename, suffix) = splitFilename input_fn
+
+ -- If we were given a -x flag, then use that phase to start from
+ start_phase
+ | Just x_phase <- mb_phase = x_phase
+ | otherwise = startPhase suffix
+
+ -- We want to catch cases of "you can't get there from here" before
+ -- we start the pipeline, because otherwise it will just run off the
+ -- end.
+ --
+ -- There is a partial ordering on phases, where A < B iff A occurs
+ -- before B in a normal compilation pipeline.
+
+ when (not (start_phase `happensBefore` stop_phase)) $
+ throwDyn (UsageError
+ ("cannot compile this file to desired target: "
+ ++ input_fn))
+
+ -- this is a function which will be used to calculate output file names
+ -- as we go along (we partially apply it to some of its inputs here)
+ let get_output_fn = getOutputFilename dflags stop_phase output basename
+
+ -- Execute the pipeline...
+ (dflags', output_fn, maybe_loc) <-
+ pipeLoop dflags start_phase stop_phase input_fn
+ basename suffix get_output_fn maybe_loc
+
+ -- Sometimes, a compilation phase doesn't actually generate any output
+ -- (eg. the CPP phase when -fcpp is not turned on). If we end on this
+ -- stage, but we wanted to keep the output, then we have to explicitly
+ -- copy the file.
+ case output of
+ Temporary ->
+ return (dflags', output_fn)
+ _other ->
+ do final_fn <- get_output_fn stop_phase maybe_loc
+ when (final_fn /= output_fn) $
+ copy dflags ("Copying `" ++ output_fn ++ "' to `" ++ final_fn
+ ++ "'") output_fn final_fn
+ return (dflags', final_fn)
+
+
+
+pipeLoop :: DynFlags -> Phase -> Phase
+ -> FilePath -> String -> Suffix
+ -> (Phase -> Maybe ModLocation -> IO FilePath)
+ -> Maybe ModLocation
+ -> IO (DynFlags, FilePath, Maybe ModLocation)
+
+pipeLoop dflags phase stop_phase
+ input_fn orig_basename orig_suff
+ orig_get_output_fn maybe_loc
+
+ | phase `eqPhase` stop_phase -- All done
+ = return (dflags, input_fn, maybe_loc)
+
+ | not (phase `happensBefore` stop_phase)
+ -- Something has gone wrong. We'll try to cover all the cases when
+ -- this could happen, so if we reach here it is a panic.
+ -- eg. it might happen if the -C flag is used on a source file that
+ -- has {-# OPTIONS -fasm #-}.
+ = panic ("pipeLoop: at phase " ++ show phase ++
+ " but I wanted to stop at phase " ++ show stop_phase)
+
+ | otherwise
+ = do { (next_phase, dflags', maybe_loc, output_fn)
+ <- runPhase phase stop_phase dflags orig_basename
+ orig_suff input_fn orig_get_output_fn maybe_loc
+ ; pipeLoop dflags' next_phase stop_phase output_fn
+ orig_basename orig_suff orig_get_output_fn maybe_loc }
+
+getOutputFilename
+ :: DynFlags -> Phase -> PipelineOutput -> String
+ -> Phase{-next phase-} -> Maybe ModLocation -> IO FilePath
+getOutputFilename dflags stop_phase output basename
+ = func
+ where
+ hcsuf = hcSuf dflags
+ odir = objectDir dflags
+ osuf = objectSuf dflags
+ keep_hc = dopt Opt_KeepHcFiles dflags
+ keep_raw_s = dopt Opt_KeepRawSFiles dflags
+ keep_s = dopt Opt_KeepSFiles dflags
+
+ myPhaseInputExt HCc = hcsuf
+ myPhaseInputExt StopLn = osuf
+ myPhaseInputExt other = phaseInputExt other
+
+ func 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
+ is_last_phase = next_phase `eqPhase` stop_phase
+
+ -- sometimes, we keep output from intermediate stages
+ keep_this_output =
+ case next_phase of
+ StopLn -> True
+ Mangle | keep_raw_s -> True
+ As | keep_s -> True
+ HCc | keep_hc -> True
+ _other -> False
+
+ suffix = myPhaseInputExt next_phase
+
+ -- persistent object files get put in odir
+ persistent_fn
+ | StopLn <- next_phase = return odir_persistent
+ | otherwise = return persistent
+
+ persistent = basename `joinFileExt` suffix
+
+ odir_persistent
+ | Just loc <- maybe_location = ml_obj_file loc
+ | Just d <- odir = d `joinFileName` persistent
+ | otherwise = persistent
+
+
+-- -----------------------------------------------------------------------------
+-- Each phase in the pipeline returns the next phase to execute, and the
+-- name of the file in which the output was placed.
+--
+-- We must do things dynamically this way, because we often don't know
+-- what the rest of the phases will be until part-way through the
+-- compilation: for example, an {-# OPTIONS -fasm #-} at the beginning
+-- of a source file can change the latter stages of the pipeline from
+-- taking the via-C route to using the native code generator.
+
+runPhase :: Phase -- Do this phase first
+ -> Phase -- Stop just before this phase
+ -> DynFlags
+ -> String -- basename of original input source
+ -> String -- its extension
+ -> FilePath -- name of file which contains the input to this phase.
+ -> (Phase -> Maybe ModLocation -> IO FilePath)
+ -- how to calculate the output filename
+ -> Maybe ModLocation -- the ModLocation, if we have one
+ -> IO (Phase, -- next phase
+ DynFlags, -- new dynamic flags
+ Maybe ModLocation, -- the ModLocation, if we have one
+ FilePath) -- output filename
+
+ -- Invariant: the output filename always contains the output
+ -- Interesting case: Hsc when there is no recompilation to do
+ -- Then the output filename is still a .o file