Skip to content

Commit

Permalink
auto merge of #11155 : SiegeLord/rust/early_deps, r=pcwalton
Browse files Browse the repository at this point in the history
The `--dep-info` command line option allows a nice way to generate make-style dependencies, but it currently does so alongside building of the output binary. This isn't a problem for make, as it mixes dependency graph generation and actual building, but it is problematic for other tools (e.g. CMake) which keep them separate.

To play more nicely with those tools, I've moved the --dep-info output from phase 6 (linking) up to after phase 2 (expansion of macros). Also, since there was no prior option to do so, I added a command line switch (`--no-analysis`) to stop compilation just before phase 3 (type-checking) which speeds this up even further.

Here's the beginning of a CMake function which is enabled by this change:

~~~cmake
function(get_rust_deps root_file out_var)
	execute_process(COMMAND rustc ${RUSTC_FLAGS} --no-analysis --dep-info "${CMAKE_BINARY_DIR}/.deps" "${root_file}")
	
	# Read and parse the dependency information
	file(READ "${CMAKE_BINARY_DIR}/.deps" crate_deps)
	file(REMOVE "${CMAKE_BINARY_DIR}/.deps")
	# parsing follows...
~~~
  • Loading branch information
bors committed Dec 31, 2013
2 parents 5ff7b28 + cbe8c61 commit 8ec03b3
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 31 deletions.
89 changes: 59 additions & 30 deletions src/librustc/driver/driver.rs
Expand Up @@ -392,14 +392,56 @@ pub fn phase_5_run_llvm_passes(sess: Session,
/// This should produce either a finished executable or library.
pub fn phase_6_link_output(sess: Session,
trans: &CrateTranslation,
input: &input,
outputs: &OutputFilenames) {
let outputs = time(sess.time_passes(), "linking", (), |_|
time(sess.time_passes(), "linking", (), |_|
link::link_binary(sess,
trans,
&outputs.obj_filename,
&outputs.out_filename,
&trans.link));
}

pub fn stop_after_phase_3(sess: Session) -> bool {
if sess.opts.no_trans {
debug!("invoked with --no-trans, returning early from compile_input");
return true;
}
return false;
}

pub fn stop_after_phase_1(sess: Session) -> bool {
if sess.opts.parse_only {
debug!("invoked with --parse-only, returning early from compile_input");
return true;
}
return false;
}

pub fn stop_after_phase_2(sess: Session) -> bool {
if sess.opts.no_analysis {
debug!("invoked with --no-analysis, returning early from compile_input");
return true;
}
return false;
}

pub fn stop_after_phase_5(sess: Session) -> bool {
if sess.opts.output_type != link::output_type_exe {
debug!("not building executable, returning early from compile_input");
return true;
}
return false;
}

fn write_out_deps(sess: Session, input: &input, outputs: &OutputFilenames, crate: &ast::Crate)
{
let lm = link::build_link_meta(sess, crate.attrs, &outputs.obj_filename,
&mut ::util::sha2::Sha256::new());

let sess_outputs = sess.outputs.borrow();
let out_filenames = sess_outputs.get().iter()
.map(|&output| link::filename_for_input(&sess, output, &lm, &outputs.out_filename))
.to_owned_vec();

// Write out dependency rules to the dep-info file if requested with --dep-info
let deps_filename = match sess.opts.write_dependency_info {
Expand All @@ -409,7 +451,7 @@ pub fn phase_6_link_output(sess: Session,
(true, None) => match *input {
file_input(ref input_path) => {
let filestem = input_path.filestem().expect("input file must have stem");
let filename = outputs[0].dir_path().join(filestem).with_extension("d");
let filename = out_filenames[0].dir_path().join(filestem).with_extension("d");
filename
},
str_input(..) => {
Expand All @@ -419,40 +461,17 @@ pub fn phase_6_link_output(sess: Session,
},
_ => return,
};

// Build a list of files used to compile the output and
// write Makefile-compatible dependency rules
let files: ~[@str] = sess.codemap.files.iter()
.filter_map(|fmap| if fmap.is_real_file() { Some(fmap.name) } else { None })
.collect();
let mut file = io::File::create(&deps_filename);
for output in outputs.iter() {
for path in out_filenames.iter() {
write!(&mut file as &mut Writer,
"{}: {}\n\n", output.display(), files.connect(" "));
}
}

pub fn stop_after_phase_3(sess: Session) -> bool {
if sess.opts.no_trans {
debug!("invoked with --no-trans, returning early from compile_input");
return true;
}
return false;
}

pub fn stop_after_phase_1(sess: Session) -> bool {
if sess.opts.parse_only {
debug!("invoked with --parse-only, returning early from compile_input");
return true;
"{}: {}\n\n", path.display(), files.connect(" "));
}
return false;
}

pub fn stop_after_phase_5(sess: Session) -> bool {
if sess.opts.output_type != link::output_type_exe {
debug!("not building executable, returning early from compile_input");
return true;
}
return false;
}

pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
Expand All @@ -468,6 +487,11 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
};
let outputs = build_output_filenames(input, outdir, output,
expanded_crate.attrs, sess);

write_out_deps(sess, input, outputs, &expanded_crate);

if stop_after_phase_2(sess) { return; }

let analysis = phase_3_run_analysis_passes(sess, &expanded_crate);
if stop_after_phase_3(sess) { return; }
let trans = phase_4_translate_to_llvm(sess, expanded_crate,
Expand All @@ -476,7 +500,7 @@ pub fn compile_input(sess: Session, cfg: ast::CrateConfig, input: &input,
};
phase_5_run_llvm_passes(sess, &trans, outputs);
if stop_after_phase_5(sess) { return; }
phase_6_link_output(sess, &trans, input, outputs);
phase_6_link_output(sess, &trans, outputs);
}

struct IdentifiedAnnotation {
Expand Down Expand Up @@ -683,6 +707,7 @@ pub fn build_session_options(binary: @str,

let parse_only = matches.opt_present("parse-only");
let no_trans = matches.opt_present("no-trans");
let no_analysis = matches.opt_present("no-analysis");

let lint_levels = [lint::allow, lint::warn,
lint::deny, lint::forbid];
Expand Down Expand Up @@ -836,6 +861,7 @@ pub fn build_session_options(binary: @str,
test: test,
parse_only: parse_only,
no_trans: no_trans,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
android_cross_path: android_cross_path,
write_dependency_info: write_dependency_info,
Expand Down Expand Up @@ -929,6 +955,9 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] {
optflag("", "ls", "List the symbols defined by a library crate"),
optflag("", "no-trans",
"Run all passes except translation; no output"),
optflag("", "no-analysis",
"Parse and expand the output, but run no analysis or produce \
output"),
optflag("O", "", "Equivalent to --opt-level=2"),
optopt("o", "", "Write output to <filename>", "FILENAME"),
optopt("", "opt-level",
Expand Down
2 changes: 2 additions & 0 deletions src/librustc/driver/session.rs
Expand Up @@ -167,6 +167,7 @@ pub struct options {
test: bool,
parse_only: bool,
no_trans: bool,
no_analysis: bool,
debugging_opts: uint,
android_cross_path: Option<~str>,
/// Whether to write dependency files. It's (enabled, optional filename).
Expand Down Expand Up @@ -398,6 +399,7 @@ pub fn basic_options() -> @options {
test: false,
parse_only: false,
no_trans: false,
no_analysis: false,
debugging_opts: 0u,
android_cross_path: None,
write_dependency_info: (false, None),
Expand Down
2 changes: 1 addition & 1 deletion src/librustpkg/util.rs
Expand Up @@ -405,7 +405,7 @@ pub fn compile_crate_from_input(input: &Path,
// -c
if driver::stop_after_phase_5(sess)
|| stop_before == Link || stop_before == Assemble { return Some(outputs.out_filename); }
driver::phase_6_link_output(sess, &translation, &file_input, outputs);
driver::phase_6_link_output(sess, &translation, outputs);

// Register dependency on the source file
// FIXME (#9639): This needs to handle non-utf8 paths
Expand Down

0 comments on commit 8ec03b3

Please sign in to comment.