Skip to content

rustc: Improve the dep-info experience #28768

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 2, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions man/rustc.1
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ Comma separated list of types of crates for the compiler to emit.
Specify the name of the crate being built.
.TP
\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info]
Configure the output that \fBrustc\fR will produce.
Configure the output that \fBrustc\fR will produce. Each option may also be of
the form KIND=PATH to specify the explicit output location for that particular
emission kind.
.TP
\fB\-\-print\fR [crate\-name|file\-names|sysroot]
Comma separated list of compiler information to print on stdout.
Expand All @@ -66,7 +68,8 @@ Equivalent to \fI\-C\ opt\-level=2\fR.
.TP
\fB\-o\fR \fIFILENAME\fR
Write output to \fIFILENAME\fR.
Ignored if multiple \fI\-\-emit\fR outputs are specified.
Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an
explicit path otherwise.
.TP
\fB\-\-out\-dir\fR \fIDIR\fR
Write output to compiler\[hy]chosen filename in \fIDIR\fR.
Expand Down
76 changes: 34 additions & 42 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ pub use self::EntryFnType::*;
pub use self::CrateType::*;
pub use self::Passes::*;
pub use self::OptLevel::*;
pub use self::OutputType::*;
pub use self::DebugInfoLevel::*;

use session::{early_error, early_warn, Session};
Expand Down Expand Up @@ -62,14 +61,14 @@ pub enum DebugInfoLevel {
FullDebugInfo,
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub enum OutputType {
OutputTypeBitcode,
OutputTypeAssembly,
OutputTypeLlvmAssembly,
OutputTypeObject,
OutputTypeExe,
OutputTypeDepInfo,
Bitcode,
Assembly,
LlvmAssembly,
Object,
Exe,
DepInfo,
}

#[derive(Clone)]
Expand All @@ -85,7 +84,7 @@ pub struct Options {
pub lint_opts: Vec<(String, lint::Level)>,
pub lint_cap: Option<lint::Level>,
pub describe_lints: bool,
pub output_types: Vec<OutputType>,
pub output_types: HashMap<OutputType, Option<PathBuf>>,
// This was mutable for rustpkg, which updates search paths based on the
// parsed code. It remains mutable in case its replacements wants to use
// this.
Expand All @@ -105,8 +104,6 @@ pub struct Options {
pub always_build_mir: bool,
pub no_analysis: bool,
pub debugging_opts: DebuggingOptions,
/// Whether to write dependency files. It's (enabled, optional filename).
pub write_dependency_info: (bool, Option<PathBuf>),
pub prints: Vec<PrintRequest>,
pub cg: CodegenOptions,
pub color: ColorConfig,
Expand Down Expand Up @@ -151,26 +148,25 @@ pub struct OutputFilenames {
pub out_filestem: String,
pub single_output_file: Option<PathBuf>,
pub extra: String,
pub outputs: HashMap<OutputType, Option<PathBuf>>,
}

impl OutputFilenames {
pub fn path(&self, flavor: OutputType) -> PathBuf {
match self.single_output_file {
Some(ref path) => return path.clone(),
None => {}
}
self.temp_path(flavor)
self.outputs.get(&flavor).and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
.unwrap_or_else(|| self.temp_path(flavor))
}

pub fn temp_path(&self, flavor: OutputType) -> PathBuf {
let base = self.out_directory.join(&self.filestem());
match flavor {
OutputTypeBitcode => base.with_extension("bc"),
OutputTypeAssembly => base.with_extension("s"),
OutputTypeLlvmAssembly => base.with_extension("ll"),
OutputTypeObject => base.with_extension("o"),
OutputTypeDepInfo => base.with_extension("d"),
OutputTypeExe => base,
OutputType::Bitcode => base.with_extension("bc"),
OutputType::Assembly => base.with_extension("s"),
OutputType::LlvmAssembly => base.with_extension("ll"),
OutputType::Object => base.with_extension("o"),
OutputType::DepInfo => base.with_extension("d"),
OutputType::Exe => base,
}
}

Expand Down Expand Up @@ -206,7 +202,7 @@ pub fn basic_options() -> Options {
lint_opts: Vec::new(),
lint_cap: None,
describe_lints: false,
output_types: Vec::new(),
output_types: HashMap::new(),
search_paths: SearchPaths::new(),
maybe_sysroot: None,
target_triple: host_triple().to_string(),
Expand All @@ -218,7 +214,6 @@ pub fn basic_options() -> Options {
always_build_mir: false,
no_analysis: false,
debugging_opts: basic_debugging_options(),
write_dependency_info: (false, None),
prints: Vec::new(),
cg: basic_codegen_options(),
color: Auto,
Expand Down Expand Up @@ -907,31 +902,30 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
unsafe { llvm::LLVMSetDebug(1); }
}

let mut output_types = Vec::new();
let mut output_types = HashMap::new();
if !debugging_opts.parse_only && !no_trans {
let unparsed_output_types = matches.opt_strs("emit");
for unparsed_output_type in &unparsed_output_types {
for part in unparsed_output_type.split(',') {
let output_type = match part {
"asm" => OutputTypeAssembly,
"llvm-ir" => OutputTypeLlvmAssembly,
"llvm-bc" => OutputTypeBitcode,
"obj" => OutputTypeObject,
"link" => OutputTypeExe,
"dep-info" => OutputTypeDepInfo,
_ => {
for list in matches.opt_strs("emit") {
for output_type in list.split(',') {
let mut parts = output_type.splitn(2, '=');
let output_type = match parts.next().unwrap() {
"asm" => OutputType::Assembly,
"llvm-ir" => OutputType::LlvmAssembly,
"llvm-bc" => OutputType::Bitcode,
"obj" => OutputType::Object,
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
part => {
early_error(color, &format!("unknown emission type: `{}`",
part))
}
};
output_types.push(output_type)
let path = parts.next().map(PathBuf::from);
output_types.insert(output_type, path);
}
}
};
output_types.sort();
output_types.dedup();
if output_types.is_empty() {
output_types.push(OutputTypeExe);
output_types.insert(OutputType::Exe, None);
}

let cg = build_codegen_options(matches, color);
Expand Down Expand Up @@ -1004,7 +998,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {

let cfg = parse_cfgspecs(matches.opt_strs("cfg"));
let test = matches.opt_present("test");
let write_dependency_info = (output_types.contains(&OutputTypeDepInfo), None);

let prints = matches.opt_strs("print").into_iter().map(|s| {
match &*s {
Expand Down Expand Up @@ -1059,7 +1052,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
always_build_mir: always_build_mir,
no_analysis: no_analysis,
debugging_opts: debugging_opts,
write_dependency_info: write_dependency_info,
prints: prints,
cg: cg,
color: color,
Expand Down
61 changes: 29 additions & 32 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc::front;
use rustc::front::map as hir_map;
use rustc_mir as mir;
use rustc::session::Session;
use rustc::session::config::{self, Input, OutputFilenames};
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
use rustc::session::search_paths::PathKind;
use rustc::lint;
use rustc::metadata;
Expand All @@ -36,6 +36,7 @@ use super::Compilation;

use serialize::json;

use std::collections::HashMap;
use std::env;
use std::ffi::{OsString, OsStr};
use std::fs;
Expand Down Expand Up @@ -117,7 +118,7 @@ pub fn compile_input(sess: Session,
let arenas = ty::CtxtArenas::new();
let ast_map = make_map(&sess, &mut hir_forest);

write_out_deps(&sess, input, &outputs, &id[..]);
write_out_deps(&sess, &outputs, &id);

controller_entry_point!(after_write_deps,
sess,
Expand Down Expand Up @@ -807,16 +808,16 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
trans: &trans::CrateTranslation,
outputs: &OutputFilenames) {
if sess.opts.cg.no_integrated_as {
let output_type = config::OutputTypeAssembly;

let mut map = HashMap::new();
map.insert(OutputType::Assembly, None);
time(sess.time_passes(), "LLVM passes", ||
write::run_passes(sess, trans, &[output_type], outputs));
write::run_passes(sess, trans, &map, outputs));

write::run_assembler(sess, outputs);

// Remove assembly source, unless --save-temps was specified
if !sess.opts.cg.save_temps {
fs::remove_file(&outputs.temp_path(config::OutputTypeAssembly)).unwrap();
fs::remove_file(&outputs.temp_path(OutputType::Assembly)).unwrap();
}
} else {
time(sess.time_passes(), "LLVM passes", ||
Expand Down Expand Up @@ -847,16 +848,12 @@ fn escape_dep_filename(filename: &str) -> String {
filename.replace(" ", "\\ ")
}

fn write_out_deps(sess: &Session,
input: &Input,
outputs: &OutputFilenames,
id: &str) {

fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
let mut out_filenames = Vec::new();
for output_type in &sess.opts.output_types {
for output_type in sess.opts.output_types.keys() {
let file = outputs.path(*output_type);
match *output_type {
config::OutputTypeExe => {
OutputType::Exe => {
for output in sess.crate_types.borrow().iter() {
let p = link::filename_for_input(sess, *output, id,
outputs);
Expand All @@ -867,23 +864,11 @@ fn write_out_deps(sess: &Session,
}
}

// Write out dependency rules to the dep-info file if requested with
// --dep-info
let deps_filename = match sess.opts.write_dependency_info {
// Use filename from --dep-file argument if given
(true, Some(ref filename)) => filename.clone(),
// Use default filename: crate source filename with extension replaced
// by ".d"
(true, None) => match *input {
Input::File(..) => outputs.with_extension("d"),
Input::Str(..) => {
sess.warn("can not write --dep-info without a filename \
when compiling stdin.");
return
},
},
_ => return,
};
// Write out dependency rules to the dep-info file if requested
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
return
}
let deps_filename = outputs.path(OutputType::DepInfo);

let result = (|| -> io::Result<()> {
// Build a list of files used to compile the output and
Expand All @@ -896,9 +881,16 @@ fn write_out_deps(sess: &Session,
.collect();
let mut file = try!(fs::File::create(&deps_filename));
for path in &out_filenames {
try!(write!(&mut file,
try!(write!(file,
"{}: {}\n\n", path.display(), files.join(" ")));
}

// Emit a fake target for each input file to the compilation. This
// prevents `make` from spitting out an error if a file is later
// deleted. For more info see #28735
for path in files {
try!(writeln!(file, "{}:", path));
}
Ok(())
})();

Expand Down Expand Up @@ -1012,11 +1004,15 @@ pub fn build_output_filenames(input: &Input,
out_filestem: stem,
single_output_file: None,
extra: sess.opts.cg.extra_filename.clone(),
outputs: sess.opts.output_types.clone(),
}
}

Some(ref out_file) => {
let ofile = if sess.opts.output_types.len() > 1 {
let unnamed_output_types = sess.opts.output_types.values()
.filter(|a| a.is_none())
.count();
let ofile = if unnamed_output_types > 1 {
sess.warn("ignoring specified output filename because multiple \
outputs were requested");
None
Expand All @@ -1035,6 +1031,7 @@ pub fn build_output_filenames(input: &Input,
.to_str().unwrap().to_string(),
single_output_file: ofile,
extra: sess.opts.cg.extra_filename.clone(),
outputs: sess.opts.output_types.clone(),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_driver/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ use rustc_resolve as resolve;
use rustc_trans::back::link;
use rustc_trans::save;
use rustc::session::{config, Session, build_session};
use rustc::session::config::{Input, PrintRequest};
use rustc::session::config::{Input, PrintRequest, OutputType};
use rustc::lint::Lint;
use rustc::lint;
use rustc::metadata;
Expand Down Expand Up @@ -382,7 +382,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
control.after_analysis.stop = Compilation::Stop;
}

if !sess.opts.output_types.iter().any(|&i| i == config::OutputTypeExe) {
if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
control.after_llvm.stop = Compilation::Stop;
}

Expand Down
18 changes: 10 additions & 8 deletions src/librustc_trans/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use super::msvc;
use super::svh::Svh;
use session::config;
use session::config::NoDebugInfo;
use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject};
use session::config::{OutputFilenames, Input, OutputType};
use session::search_paths::PathKind;
use session::Session;
use metadata::common::LinkMeta;
Expand Down Expand Up @@ -486,7 +486,7 @@ pub fn filename_for_input(sess: &Session,
}
config::CrateTypeExecutable => {
let suffix = &sess.target.target.options.exe_suffix;
let out_filename = outputs.path(OutputTypeExe);
let out_filename = outputs.path(OutputType::Exe);
if suffix.is_empty() {
out_filename.to_path_buf()
} else {
Expand Down Expand Up @@ -527,10 +527,12 @@ fn link_binary_output(sess: &Session,
outputs: &OutputFilenames,
crate_name: &str) -> PathBuf {
let objects = object_filenames(sess, outputs);
let out_filename = match outputs.single_output_file {
Some(ref file) => file.clone(),
None => filename_for_input(sess, crate_type, crate_name, outputs),
};
let default_filename = filename_for_input(sess, crate_type, crate_name,
outputs);
let out_filename = outputs.outputs.get(&OutputType::Exe)
.and_then(|s| s.to_owned())
.or_else(|| outputs.single_output_file.clone())
.unwrap_or(default_filename);

// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
// check this already -- however, the Linux linker will happily overwrite a
Expand Down Expand Up @@ -571,7 +573,7 @@ fn link_binary_output(sess: &Session,
fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec<PathBuf> {
(0..sess.opts.cg.codegen_units).map(|i| {
let ext = format!("{}.o", i);
outputs.temp_path(OutputTypeObject).with_extension(&ext)
outputs.temp_path(OutputType::Object).with_extension(&ext)
}).collect()
}

Expand Down Expand Up @@ -718,7 +720,7 @@ fn link_rlib<'a>(sess: &'a Session,
// See the bottom of back::write::run_passes for an explanation
// of when we do and don't keep .0.bc files around.
let user_wants_numbered_bitcode =
sess.opts.output_types.contains(&OutputTypeBitcode) &&
sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
sess.opts.cg.codegen_units > 1;
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
remove(sess, &bc_filename);
Expand Down
Loading