rustc: Support output filenames for each emit type
Currently the compiler supports the ability to emit multiple output types as part of one compilation (e.g. asm, LLVM IR, bytecode, link, dep-info, etc). It does not, however, support the ability to customize the output filename for each of these output types. The `-o` flag is ignored if multiple emit types are specified (and the compiler emits a warning about this). Normally this doesn't matter too much, but in the case of `dep-info` it can lead to a number of problems (e.g. see #28716). By allowing customization of the output filename for each emit type we're able to solve the problems in that issue. This commit adds support for the `--emit` option to the compiler to look like: rustc foo.rs --emit dep-info=.deps/foo.d,link This indicates that the `dep-info` output type will be placed at `.deps/foo.d` and the `link` output type will otherwise be determined via the `--out-dir` and `-o` flags. Closes #28716
This commit is contained in:
parent
3e6d7243ae
commit
8c963c07a8
@ -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.
|
||||
@ -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.
|
||||
|
@ -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};
|
||||
@ -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)]
|
||||
@ -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.
|
||||
@ -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,
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
@ -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,
|
||||
@ -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);
|
||||
@ -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 {
|
||||
@ -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,
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
@ -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,
|
||||
@ -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", ||
|
||||
@ -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);
|
||||
@ -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
|
||||
@ -1012,11 +997,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
|
||||
@ -1035,6 +1024,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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -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 {
|
||||
@ -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
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
@ -12,7 +12,7 @@ use back::lto;
|
||||
use back::link::{get_linker, remove};
|
||||
use session::config::{OutputFilenames, Passes, SomePasses, AllPasses};
|
||||
use session::Session;
|
||||
use session::config;
|
||||
use session::config::{self, OutputType};
|
||||
use llvm;
|
||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
|
||||
use llvm::SMDiagnosticRef;
|
||||
@ -23,9 +23,10 @@ use syntax::codemap;
|
||||
use syntax::diagnostic;
|
||||
use syntax::diagnostic::{Emitter, Handler, Level};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
use std::str;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -33,15 +34,6 @@ use std::sync::mpsc::channel;
|
||||
use std::thread;
|
||||
use libc::{self, c_uint, c_int, c_void};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, PartialOrd, Ord, Eq)]
|
||||
pub enum OutputType {
|
||||
OutputTypeBitcode,
|
||||
OutputTypeAssembly,
|
||||
OutputTypeLlvmAssembly,
|
||||
OutputTypeObject,
|
||||
OutputTypeExe,
|
||||
}
|
||||
|
||||
pub fn llvm_err(handler: &diagnostic::Handler, msg: String) -> ! {
|
||||
unsafe {
|
||||
let cstr = llvm::LLVMRustGetLastError();
|
||||
@ -571,7 +563,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||
|
||||
pub fn run_passes(sess: &Session,
|
||||
trans: &CrateTranslation,
|
||||
output_types: &[config::OutputType],
|
||||
output_types: &HashMap<OutputType, Option<PathBuf>>,
|
||||
crate_output: &OutputFilenames) {
|
||||
// It's possible that we have `codegen_units > 1` but only one item in
|
||||
// `trans.modules`. We could theoretically proceed and do LTO in that
|
||||
@ -611,32 +603,32 @@ pub fn run_passes(sess: &Session,
|
||||
// archive in order to allow LTO against it.
|
||||
let needs_crate_bitcode =
|
||||
sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
|
||||
sess.opts.output_types.contains(&config::OutputTypeExe);
|
||||
sess.opts.output_types.contains_key(&OutputType::Exe);
|
||||
let needs_crate_object =
|
||||
sess.opts.output_types.contains(&config::OutputTypeExe);
|
||||
sess.opts.output_types.contains_key(&OutputType::Exe);
|
||||
if needs_crate_bitcode {
|
||||
modules_config.emit_bc = true;
|
||||
}
|
||||
|
||||
for output_type in output_types {
|
||||
for output_type in output_types.keys() {
|
||||
match *output_type {
|
||||
config::OutputTypeBitcode => { modules_config.emit_bc = true; },
|
||||
config::OutputTypeLlvmAssembly => { modules_config.emit_ir = true; },
|
||||
config::OutputTypeAssembly => {
|
||||
OutputType::Bitcode => { modules_config.emit_bc = true; },
|
||||
OutputType::LlvmAssembly => { modules_config.emit_ir = true; },
|
||||
OutputType::Assembly => {
|
||||
modules_config.emit_asm = true;
|
||||
// If we're not using the LLVM assembler, this function
|
||||
// could be invoked specially with output_type_assembly, so
|
||||
// in this case we still want the metadata object file.
|
||||
if !sess.opts.output_types.contains(&config::OutputTypeAssembly) {
|
||||
if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
|
||||
metadata_config.emit_obj = true;
|
||||
}
|
||||
},
|
||||
config::OutputTypeObject => { modules_config.emit_obj = true; },
|
||||
config::OutputTypeExe => {
|
||||
OutputType::Object => { modules_config.emit_obj = true; },
|
||||
OutputType::Exe => {
|
||||
modules_config.emit_obj = true;
|
||||
metadata_config.emit_obj = true;
|
||||
},
|
||||
config::OutputTypeDepInfo => {}
|
||||
OutputType::DepInfo => {}
|
||||
}
|
||||
}
|
||||
|
||||
@ -686,8 +678,9 @@ pub fn run_passes(sess: &Session,
|
||||
}
|
||||
};
|
||||
|
||||
let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| {
|
||||
// Three cases:
|
||||
let copy_if_one_unit = |ext: &str,
|
||||
output_type: OutputType,
|
||||
keep_numbered: bool| {
|
||||
if sess.opts.cg.codegen_units == 1 {
|
||||
// 1) Only one codegen unit. In this case it's no difficulty
|
||||
// to copy `foo.0.x` to `foo.x`.
|
||||
@ -697,17 +690,20 @@ pub fn run_passes(sess: &Session,
|
||||
// The user just wants `foo.x`, not `foo.0.x`.
|
||||
remove(sess, &crate_output.with_extension(ext));
|
||||
}
|
||||
} else if crate_output.outputs.contains_key(&output_type) {
|
||||
// 2) Multiple codegen units, with `--emit foo=some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.warn(&format!("ignoring emit path because multiple .{} files \
|
||||
were produced", ext));
|
||||
} else if crate_output.single_output_file.is_some() {
|
||||
// 3) Multiple codegen units, with `-o some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.warn(&format!("ignoring -o because multiple .{} files \
|
||||
were produced", ext));
|
||||
} else {
|
||||
if crate_output.single_output_file.is_some() {
|
||||
// 2) Multiple codegen units, with `-o some_name`. We have
|
||||
// no good solution for this case, so warn the user.
|
||||
sess.warn(&format!("ignoring -o because multiple .{} files were produced",
|
||||
ext));
|
||||
} else {
|
||||
// 3) Multiple codegen units, but no `-o some_name`. We
|
||||
// just leave the `foo.0.x` files in place.
|
||||
// (We don't have to do any work in this case.)
|
||||
}
|
||||
// 4) Multiple codegen units, but no explicit name. We
|
||||
// just leave the `foo.0.x` files in place.
|
||||
// (We don't have to do any work in this case.)
|
||||
}
|
||||
};
|
||||
|
||||
@ -716,27 +712,27 @@ pub fn run_passes(sess: &Session,
|
||||
// to get rid of it.
|
||||
let mut user_wants_bitcode = false;
|
||||
let mut user_wants_objects = false;
|
||||
for output_type in output_types {
|
||||
for output_type in output_types.keys() {
|
||||
match *output_type {
|
||||
config::OutputTypeBitcode => {
|
||||
OutputType::Bitcode => {
|
||||
user_wants_bitcode = true;
|
||||
// Copy to .bc, but always keep the .0.bc. There is a later
|
||||
// check to figure out if we should delete .0.bc files, or keep
|
||||
// them for making an rlib.
|
||||
copy_if_one_unit("0.bc", config::OutputTypeBitcode, true);
|
||||
copy_if_one_unit("0.bc", OutputType::Bitcode, true);
|
||||
}
|
||||
config::OutputTypeLlvmAssembly => {
|
||||
copy_if_one_unit("0.ll", config::OutputTypeLlvmAssembly, false);
|
||||
OutputType::LlvmAssembly => {
|
||||
copy_if_one_unit("0.ll", OutputType::LlvmAssembly, false);
|
||||
}
|
||||
config::OutputTypeAssembly => {
|
||||
copy_if_one_unit("0.s", config::OutputTypeAssembly, false);
|
||||
OutputType::Assembly => {
|
||||
copy_if_one_unit("0.s", OutputType::Assembly, false);
|
||||
}
|
||||
config::OutputTypeObject => {
|
||||
OutputType::Object => {
|
||||
user_wants_objects = true;
|
||||
copy_if_one_unit("0.o", config::OutputTypeObject, true);
|
||||
copy_if_one_unit("0.o", OutputType::Object, true);
|
||||
}
|
||||
config::OutputTypeExe |
|
||||
config::OutputTypeDepInfo => {}
|
||||
OutputType::Exe |
|
||||
OutputType::DepInfo => {}
|
||||
}
|
||||
}
|
||||
let user_wants_bitcode = user_wants_bitcode;
|
||||
@ -913,8 +909,8 @@ fn run_work_multithreaded(sess: &Session,
|
||||
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||
let (pname, mut cmd) = get_linker(sess);
|
||||
|
||||
cmd.arg("-c").arg("-o").arg(&outputs.path(config::OutputTypeObject))
|
||||
.arg(&outputs.temp_path(config::OutputTypeAssembly));
|
||||
cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
|
||||
.arg(&outputs.temp_path(OutputType::Assembly));
|
||||
debug!("{:?}", cmd);
|
||||
|
||||
match cmd.output() {
|
||||
|
@ -23,7 +23,7 @@ use std::sync::{Arc, Mutex};
|
||||
use testing;
|
||||
use rustc_lint;
|
||||
use rustc::session::{self, config};
|
||||
use rustc::session::config::get_unstable_features_setting;
|
||||
use rustc::session::config::{get_unstable_features_setting, OutputType};
|
||||
use rustc::session::search_paths::{SearchPaths, PathKind};
|
||||
use rustc_front::lowering::lower_crate;
|
||||
use rustc_back::tempdir::TempDir;
|
||||
@ -163,13 +163,15 @@ fn runtest(test: &str, cratename: &str, libs: SearchPaths,
|
||||
// never wrap the test in `fn main() { ... }`
|
||||
let test = maketest(test, Some(cratename), as_test_harness, opts);
|
||||
let input = config::Input::Str(test.to_string());
|
||||
let mut outputs = HashMap::new();
|
||||
outputs.insert(OutputType::Exe, None);
|
||||
|
||||
let sessopts = config::Options {
|
||||
maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
|
||||
.parent().unwrap().to_path_buf()),
|
||||
search_paths: libs,
|
||||
crate_types: vec!(config::CrateTypeExecutable),
|
||||
output_types: vec!(config::OutputTypeExe),
|
||||
output_types: outputs,
|
||||
externs: externs,
|
||||
cg: config::CodegenOptions {
|
||||
prefer_dynamic: true,
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(rustc_private, path, convert)]
|
||||
#![feature(rustc_private)]
|
||||
|
||||
extern crate rustc;
|
||||
extern crate rustc_driver;
|
||||
@ -16,7 +16,7 @@ extern crate rustc_lint;
|
||||
extern crate syntax;
|
||||
|
||||
use rustc::session::{build_session, Session};
|
||||
use rustc::session::config::{basic_options, build_configuration, Input, OutputTypeExe};
|
||||
use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
|
||||
use rustc_driver::driver::{compile_input, CompileController};
|
||||
use syntax::diagnostics::registry::Registry;
|
||||
|
||||
@ -46,7 +46,7 @@ fn main() {
|
||||
|
||||
fn basic_sess(sysroot: PathBuf) -> Session {
|
||||
let mut opts = basic_options();
|
||||
opts.output_types = vec![OutputTypeExe];
|
||||
opts.output_types.insert(OutputType::Exe, None);
|
||||
opts.maybe_sysroot = Some(sysroot);
|
||||
|
||||
let descriptions = Registry::new(&rustc::DIAGNOSTICS);
|
||||
|
@ -23,45 +23,83 @@ all:
|
||||
rm -f $(TMPDIR)/bar.pdb
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=asm -o $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit asm -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit asm=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=llvm-bc -o $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit llvm-bc -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit llvm-bc=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=llvm-ir -o $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit llvm-ir -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=obj -o $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit obj -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --emit obj=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=link -o $(TMPDIR)/$(call BIN,foo)
|
||||
$(RUSTC) foo.rs --emit link -o $(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
$(RUSTC) foo.rs --emit link=$(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
rm -f $(TMPDIR)/foo.pdb
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --crate-type=rlib -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --crate-type=rlib --emit link=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --crate-type=dylib -o $(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
$(RUSTC) foo.rs --crate-type=dylib --emit link=$(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
rm -f $(TMPDIR)/foo.{exp,lib,pdb}
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --crate-type=staticlib -o $(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
$(RUSTC) foo.rs --crate-type=staticlib --emit link=$(TMPDIR)/foo
|
||||
rm $(TMPDIR)/foo
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --crate-type=bin -o $(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
$(RUSTC) foo.rs --crate-type=bin --emit link=$(TMPDIR)/$(call BIN,foo)
|
||||
rm $(TMPDIR)/$(call BIN,foo)
|
||||
rm -f $(TMPDIR)/foo.pdb
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit llvm-ir=$(TMPDIR)/ir \
|
||||
--emit link \
|
||||
--crate-type=rlib
|
||||
rm $(TMPDIR)/ir
|
||||
rm $(TMPDIR)/libbar.rlib
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit asm=$(TMPDIR)/asm \
|
||||
--emit llvm-ir=$(TMPDIR)/ir \
|
||||
--emit llvm-bc=$(TMPDIR)/bc \
|
||||
--emit obj=$(TMPDIR)/obj \
|
||||
--emit link=$(TMPDIR)/link \
|
||||
--crate-type=staticlib
|
||||
rm $(TMPDIR)/asm
|
||||
rm $(TMPDIR)/ir
|
||||
rm $(TMPDIR)/bc
|
||||
rm $(TMPDIR)/obj
|
||||
rm $(TMPDIR)/link
|
||||
[ "$$(ls -1 $(TMPDIR) | wc -l)" -eq "0" ]
|
||||
|
||||
$(RUSTC) foo.rs --emit=asm,llvm-ir,llvm-bc,obj,link --crate-type=staticlib
|
||||
rm $(TMPDIR)/bar.ll
|
||||
rm $(TMPDIR)/bar.s
|
||||
|
Loading…
Reference in New Issue
Block a user