Skip to content

Commit e650491

Browse files
committed
Auto merge of #28768 - alexcrichton:dep-info++, r=brson
This PR closes out #28716 and #28735 by making two changes to the compiler: 1. The `--emit` flag to the compiler now supports the ability to specify the output file name of a partuclar emit type. For example `--emit dep-info=bar.d,asm=foo.s,link` is now accepted. 2. The dep-info emission now emits a dummy target for all input file names to protect against deleted files.
2 parents 17a2cb4 + 1741962 commit e650491

File tree

11 files changed

+194
-145
lines changed

11 files changed

+194
-145
lines changed

man/rustc.1

+5-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ Comma separated list of types of crates for the compiler to emit.
5353
Specify the name of the crate being built.
5454
.TP
5555
\fB\-\-emit\fR [asm|llvm\-bc|llvm\-ir|obj|link|dep\-info]
56-
Configure the output that \fBrustc\fR will produce.
56+
Configure the output that \fBrustc\fR will produce. Each option may also be of
57+
the form KIND=PATH to specify the explicit output location for that particular
58+
emission kind.
5759
.TP
5860
\fB\-\-print\fR [crate\-name|file\-names|sysroot]
5961
Comma separated list of compiler information to print on stdout.
@@ -66,7 +68,8 @@ Equivalent to \fI\-C\ opt\-level=2\fR.
6668
.TP
6769
\fB\-o\fR \fIFILENAME\fR
6870
Write output to \fIFILENAME\fR.
69-
Ignored if multiple \fI\-\-emit\fR outputs are specified.
71+
Ignored if multiple \fI\-\-emit\fR outputs are specified which don't have an
72+
explicit path otherwise.
7073
.TP
7174
\fB\-\-out\-dir\fR \fIDIR\fR
7275
Write output to compiler\[hy]chosen filename in \fIDIR\fR.

src/librustc/session/config.rs

+34-42
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ pub use self::EntryFnType::*;
1515
pub use self::CrateType::*;
1616
pub use self::Passes::*;
1717
pub use self::OptLevel::*;
18-
pub use self::OutputType::*;
1918
pub use self::DebugInfoLevel::*;
2019

2120
use session::{early_error, early_warn, Session};
@@ -62,14 +61,14 @@ pub enum DebugInfoLevel {
6261
FullDebugInfo,
6362
}
6463

65-
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
64+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
6665
pub enum OutputType {
67-
OutputTypeBitcode,
68-
OutputTypeAssembly,
69-
OutputTypeLlvmAssembly,
70-
OutputTypeObject,
71-
OutputTypeExe,
72-
OutputTypeDepInfo,
66+
Bitcode,
67+
Assembly,
68+
LlvmAssembly,
69+
Object,
70+
Exe,
71+
DepInfo,
7372
}
7473

7574
#[derive(Clone)]
@@ -85,7 +84,7 @@ pub struct Options {
8584
pub lint_opts: Vec<(String, lint::Level)>,
8685
pub lint_cap: Option<lint::Level>,
8786
pub describe_lints: bool,
88-
pub output_types: Vec<OutputType>,
87+
pub output_types: HashMap<OutputType, Option<PathBuf>>,
8988
// This was mutable for rustpkg, which updates search paths based on the
9089
// parsed code. It remains mutable in case its replacements wants to use
9190
// this.
@@ -105,8 +104,6 @@ pub struct Options {
105104
pub always_build_mir: bool,
106105
pub no_analysis: bool,
107106
pub debugging_opts: DebuggingOptions,
108-
/// Whether to write dependency files. It's (enabled, optional filename).
109-
pub write_dependency_info: (bool, Option<PathBuf>),
110107
pub prints: Vec<PrintRequest>,
111108
pub cg: CodegenOptions,
112109
pub color: ColorConfig,
@@ -151,26 +148,25 @@ pub struct OutputFilenames {
151148
pub out_filestem: String,
152149
pub single_output_file: Option<PathBuf>,
153150
pub extra: String,
151+
pub outputs: HashMap<OutputType, Option<PathBuf>>,
154152
}
155153

156154
impl OutputFilenames {
157155
pub fn path(&self, flavor: OutputType) -> PathBuf {
158-
match self.single_output_file {
159-
Some(ref path) => return path.clone(),
160-
None => {}
161-
}
162-
self.temp_path(flavor)
156+
self.outputs.get(&flavor).and_then(|p| p.to_owned())
157+
.or_else(|| self.single_output_file.clone())
158+
.unwrap_or_else(|| self.temp_path(flavor))
163159
}
164160

165161
pub fn temp_path(&self, flavor: OutputType) -> PathBuf {
166162
let base = self.out_directory.join(&self.filestem());
167163
match flavor {
168-
OutputTypeBitcode => base.with_extension("bc"),
169-
OutputTypeAssembly => base.with_extension("s"),
170-
OutputTypeLlvmAssembly => base.with_extension("ll"),
171-
OutputTypeObject => base.with_extension("o"),
172-
OutputTypeDepInfo => base.with_extension("d"),
173-
OutputTypeExe => base,
164+
OutputType::Bitcode => base.with_extension("bc"),
165+
OutputType::Assembly => base.with_extension("s"),
166+
OutputType::LlvmAssembly => base.with_extension("ll"),
167+
OutputType::Object => base.with_extension("o"),
168+
OutputType::DepInfo => base.with_extension("d"),
169+
OutputType::Exe => base,
174170
}
175171
}
176172

@@ -206,7 +202,7 @@ pub fn basic_options() -> Options {
206202
lint_opts: Vec::new(),
207203
lint_cap: None,
208204
describe_lints: false,
209-
output_types: Vec::new(),
205+
output_types: HashMap::new(),
210206
search_paths: SearchPaths::new(),
211207
maybe_sysroot: None,
212208
target_triple: host_triple().to_string(),
@@ -218,7 +214,6 @@ pub fn basic_options() -> Options {
218214
always_build_mir: false,
219215
no_analysis: false,
220216
debugging_opts: basic_debugging_options(),
221-
write_dependency_info: (false, None),
222217
prints: Vec::new(),
223218
cg: basic_codegen_options(),
224219
color: Auto,
@@ -907,31 +902,30 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
907902
unsafe { llvm::LLVMSetDebug(1); }
908903
}
909904

910-
let mut output_types = Vec::new();
905+
let mut output_types = HashMap::new();
911906
if !debugging_opts.parse_only && !no_trans {
912-
let unparsed_output_types = matches.opt_strs("emit");
913-
for unparsed_output_type in &unparsed_output_types {
914-
for part in unparsed_output_type.split(',') {
915-
let output_type = match part {
916-
"asm" => OutputTypeAssembly,
917-
"llvm-ir" => OutputTypeLlvmAssembly,
918-
"llvm-bc" => OutputTypeBitcode,
919-
"obj" => OutputTypeObject,
920-
"link" => OutputTypeExe,
921-
"dep-info" => OutputTypeDepInfo,
922-
_ => {
907+
for list in matches.opt_strs("emit") {
908+
for output_type in list.split(',') {
909+
let mut parts = output_type.splitn(2, '=');
910+
let output_type = match parts.next().unwrap() {
911+
"asm" => OutputType::Assembly,
912+
"llvm-ir" => OutputType::LlvmAssembly,
913+
"llvm-bc" => OutputType::Bitcode,
914+
"obj" => OutputType::Object,
915+
"link" => OutputType::Exe,
916+
"dep-info" => OutputType::DepInfo,
917+
part => {
923918
early_error(color, &format!("unknown emission type: `{}`",
924919
part))
925920
}
926921
};
927-
output_types.push(output_type)
922+
let path = parts.next().map(PathBuf::from);
923+
output_types.insert(output_type, path);
928924
}
929925
}
930926
};
931-
output_types.sort();
932-
output_types.dedup();
933927
if output_types.is_empty() {
934-
output_types.push(OutputTypeExe);
928+
output_types.insert(OutputType::Exe, None);
935929
}
936930

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

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

10091002
let prints = matches.opt_strs("print").into_iter().map(|s| {
10101003
match &*s {
@@ -1059,7 +1052,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
10591052
always_build_mir: always_build_mir,
10601053
no_analysis: no_analysis,
10611054
debugging_opts: debugging_opts,
1062-
write_dependency_info: write_dependency_info,
10631055
prints: prints,
10641056
cg: cg,
10651057
color: color,

src/librustc_driver/driver.rs

+29-32
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc::front;
1212
use rustc::front::map as hir_map;
1313
use rustc_mir as mir;
1414
use rustc::session::Session;
15-
use rustc::session::config::{self, Input, OutputFilenames};
15+
use rustc::session::config::{self, Input, OutputFilenames, OutputType};
1616
use rustc::session::search_paths::PathKind;
1717
use rustc::lint;
1818
use rustc::metadata;
@@ -36,6 +36,7 @@ use super::Compilation;
3636

3737
use serialize::json;
3838

39+
use std::collections::HashMap;
3940
use std::env;
4041
use std::ffi::{OsString, OsStr};
4142
use std::fs;
@@ -117,7 +118,7 @@ pub fn compile_input(sess: Session,
117118
let arenas = ty::CtxtArenas::new();
118119
let ast_map = make_map(&sess, &mut hir_forest);
119120

120-
write_out_deps(&sess, input, &outputs, &id[..]);
121+
write_out_deps(&sess, &outputs, &id);
121122

122123
controller_entry_point!(after_write_deps,
123124
sess,
@@ -807,16 +808,16 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
807808
trans: &trans::CrateTranslation,
808809
outputs: &OutputFilenames) {
809810
if sess.opts.cg.no_integrated_as {
810-
let output_type = config::OutputTypeAssembly;
811-
811+
let mut map = HashMap::new();
812+
map.insert(OutputType::Assembly, None);
812813
time(sess.time_passes(), "LLVM passes", ||
813-
write::run_passes(sess, trans, &[output_type], outputs));
814+
write::run_passes(sess, trans, &map, outputs));
814815

815816
write::run_assembler(sess, outputs);
816817

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

850-
fn write_out_deps(sess: &Session,
851-
input: &Input,
852-
outputs: &OutputFilenames,
853-
id: &str) {
854-
851+
fn write_out_deps(sess: &Session, outputs: &OutputFilenames, id: &str) {
855852
let mut out_filenames = Vec::new();
856-
for output_type in &sess.opts.output_types {
853+
for output_type in sess.opts.output_types.keys() {
857854
let file = outputs.path(*output_type);
858855
match *output_type {
859-
config::OutputTypeExe => {
856+
OutputType::Exe => {
860857
for output in sess.crate_types.borrow().iter() {
861858
let p = link::filename_for_input(sess, *output, id,
862859
outputs);
@@ -867,23 +864,11 @@ fn write_out_deps(sess: &Session,
867864
}
868865
}
869866

870-
// Write out dependency rules to the dep-info file if requested with
871-
// --dep-info
872-
let deps_filename = match sess.opts.write_dependency_info {
873-
// Use filename from --dep-file argument if given
874-
(true, Some(ref filename)) => filename.clone(),
875-
// Use default filename: crate source filename with extension replaced
876-
// by ".d"
877-
(true, None) => match *input {
878-
Input::File(..) => outputs.with_extension("d"),
879-
Input::Str(..) => {
880-
sess.warn("can not write --dep-info without a filename \
881-
when compiling stdin.");
882-
return
883-
},
884-
},
885-
_ => return,
886-
};
867+
// Write out dependency rules to the dep-info file if requested
868+
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
869+
return
870+
}
871+
let deps_filename = outputs.path(OutputType::DepInfo);
887872

888873
let result = (|| -> io::Result<()> {
889874
// Build a list of files used to compile the output and
@@ -896,9 +881,16 @@ fn write_out_deps(sess: &Session,
896881
.collect();
897882
let mut file = try!(fs::File::create(&deps_filename));
898883
for path in &out_filenames {
899-
try!(write!(&mut file,
884+
try!(write!(file,
900885
"{}: {}\n\n", path.display(), files.join(" ")));
901886
}
887+
888+
// Emit a fake target for each input file to the compilation. This
889+
// prevents `make` from spitting out an error if a file is later
890+
// deleted. For more info see #28735
891+
for path in files {
892+
try!(writeln!(file, "{}:", path));
893+
}
902894
Ok(())
903895
})();
904896

@@ -1012,11 +1004,15 @@ pub fn build_output_filenames(input: &Input,
10121004
out_filestem: stem,
10131005
single_output_file: None,
10141006
extra: sess.opts.cg.extra_filename.clone(),
1007+
outputs: sess.opts.output_types.clone(),
10151008
}
10161009
}
10171010

10181011
Some(ref out_file) => {
1019-
let ofile = if sess.opts.output_types.len() > 1 {
1012+
let unnamed_output_types = sess.opts.output_types.values()
1013+
.filter(|a| a.is_none())
1014+
.count();
1015+
let ofile = if unnamed_output_types > 1 {
10201016
sess.warn("ignoring specified output filename because multiple \
10211017
outputs were requested");
10221018
None
@@ -1035,6 +1031,7 @@ pub fn build_output_filenames(input: &Input,
10351031
.to_str().unwrap().to_string(),
10361032
single_output_file: ofile,
10371033
extra: sess.opts.cg.extra_filename.clone(),
1034+
outputs: sess.opts.output_types.clone(),
10381035
}
10391036
}
10401037
}

src/librustc_driver/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use rustc_resolve as resolve;
6363
use rustc_trans::back::link;
6464
use rustc_trans::save;
6565
use rustc::session::{config, Session, build_session};
66-
use rustc::session::config::{Input, PrintRequest};
66+
use rustc::session::config::{Input, PrintRequest, OutputType};
6767
use rustc::lint::Lint;
6868
use rustc::lint;
6969
use rustc::metadata;
@@ -382,7 +382,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
382382
control.after_analysis.stop = Compilation::Stop;
383383
}
384384

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

src/librustc_trans/back/link.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use super::msvc;
1616
use super::svh::Svh;
1717
use session::config;
1818
use session::config::NoDebugInfo;
19-
use session::config::{OutputFilenames, Input, OutputTypeBitcode, OutputTypeExe, OutputTypeObject};
19+
use session::config::{OutputFilenames, Input, OutputType};
2020
use session::search_paths::PathKind;
2121
use session::Session;
2222
use metadata::common::LinkMeta;
@@ -491,7 +491,7 @@ pub fn filename_for_input(sess: &Session,
491491
}
492492
config::CrateTypeExecutable => {
493493
let suffix = &sess.target.target.options.exe_suffix;
494-
let out_filename = outputs.path(OutputTypeExe);
494+
let out_filename = outputs.path(OutputType::Exe);
495495
if suffix.is_empty() {
496496
out_filename.to_path_buf()
497497
} else {
@@ -532,10 +532,12 @@ fn link_binary_output(sess: &Session,
532532
outputs: &OutputFilenames,
533533
crate_name: &str) -> PathBuf {
534534
let objects = object_filenames(sess, outputs);
535-
let out_filename = match outputs.single_output_file {
536-
Some(ref file) => file.clone(),
537-
None => filename_for_input(sess, crate_type, crate_name, outputs),
538-
};
535+
let default_filename = filename_for_input(sess, crate_type, crate_name,
536+
outputs);
537+
let out_filename = outputs.outputs.get(&OutputType::Exe)
538+
.and_then(|s| s.to_owned())
539+
.or_else(|| outputs.single_output_file.clone())
540+
.unwrap_or(default_filename);
539541

540542
// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
541543
// check this already -- however, the Linux linker will happily overwrite a
@@ -576,7 +578,7 @@ fn link_binary_output(sess: &Session,
576578
fn object_filenames(sess: &Session, outputs: &OutputFilenames) -> Vec<PathBuf> {
577579
(0..sess.opts.cg.codegen_units).map(|i| {
578580
let ext = format!("{}.o", i);
579-
outputs.temp_path(OutputTypeObject).with_extension(&ext)
581+
outputs.temp_path(OutputType::Object).with_extension(&ext)
580582
}).collect()
581583
}
582584

@@ -723,7 +725,7 @@ fn link_rlib<'a>(sess: &'a Session,
723725
// See the bottom of back::write::run_passes for an explanation
724726
// of when we do and don't keep .0.bc files around.
725727
let user_wants_numbered_bitcode =
726-
sess.opts.output_types.contains(&OutputTypeBitcode) &&
728+
sess.opts.output_types.contains_key(&OutputType::Bitcode) &&
727729
sess.opts.cg.codegen_units > 1;
728730
if !sess.opts.cg.save_temps && !user_wants_numbered_bitcode {
729731
remove(sess, &bc_filename);

0 commit comments

Comments
 (0)