Auto merge of #111626 - pjhades:output, r=b-naber
Write to stdout if `-` is given as output file With this PR, if `-o -` or `--emit KIND=-` is provided, output will be written to stdout instead. Binary output (those of type `obj`, `llvm-bc`, `link` and `metadata`) being written this way will result in an error unless stdout is not a tty. Multiple output types going to stdout will trigger an error too, as they will all be mixded together. This implements https://github.com/rust-lang/compiler-team/issues/431 The idea behind the changes is to introduce an `OutFileName` enum that represents the output - be it a real path or stdout - and to use this enum along the code paths that handle different output types.
This commit is contained in:
commit
343ad6f059
32 changed files with 439 additions and 101 deletions
|
@ -3595,6 +3595,7 @@ dependencies = [
|
||||||
name = "rustc_interface"
|
name = "rustc_interface"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atty",
|
||||||
"libloading",
|
"libloading",
|
||||||
"rustc-rayon",
|
"rustc-rayon",
|
||||||
"rustc-rayon-core",
|
"rustc-rayon-core",
|
||||||
|
@ -4059,6 +4060,7 @@ dependencies = [
|
||||||
name = "rustc_session"
|
name = "rustc_session"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atty",
|
||||||
"getopts",
|
"getopts",
|
||||||
"libc",
|
"libc",
|
||||||
"rustc_ast",
|
"rustc_ast",
|
||||||
|
|
|
@ -9,6 +9,8 @@ codegen_ssa_archive_build_failure =
|
||||||
|
|
||||||
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
|
codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
|
||||||
|
|
||||||
|
codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty
|
||||||
|
|
||||||
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
|
codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
|
||||||
|
|
||||||
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
|
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, Handler};
|
||||||
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
use rustc_fs_util::fix_windows_verbatim_for_gcc;
|
||||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_metadata::find_native_static_library;
|
use rustc_metadata::find_native_static_library;
|
||||||
use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME};
|
use rustc_metadata::fs::{copy_to_stdout, emit_wrapper_file, METADATA_FILENAME};
|
||||||
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
|
||||||
use rustc_middle::middle::dependency_format::Linkage;
|
use rustc_middle::middle::dependency_format::Linkage;
|
||||||
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
use rustc_middle::middle::exported_symbols::SymbolExportKind;
|
||||||
|
@ -68,6 +68,7 @@ pub fn link_binary<'a>(
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
let _timer = sess.timer("link_binary");
|
let _timer = sess.timer("link_binary");
|
||||||
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||||
|
let mut tempfiles_for_stdout_output: Vec<PathBuf> = Vec::new();
|
||||||
for &crate_type in sess.crate_types().iter() {
|
for &crate_type in sess.crate_types().iter() {
|
||||||
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
// Ignore executable crates if we have -Z no-codegen, as they will error.
|
||||||
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
|
if (sess.opts.unstable_opts.no_codegen || !sess.opts.output_types.should_codegen())
|
||||||
|
@ -97,12 +98,15 @@ pub fn link_binary<'a>(
|
||||||
.tempdir()
|
.tempdir()
|
||||||
.unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
|
.unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
|
||||||
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
|
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
|
||||||
let out_filename = out_filename(
|
let output = out_filename(
|
||||||
sess,
|
sess,
|
||||||
crate_type,
|
crate_type,
|
||||||
outputs,
|
outputs,
|
||||||
codegen_results.crate_info.local_crate_name,
|
codegen_results.crate_info.local_crate_name,
|
||||||
);
|
);
|
||||||
|
let crate_name = format!("{}", codegen_results.crate_info.local_crate_name);
|
||||||
|
let out_filename =
|
||||||
|
output.file_for_writing(outputs, OutputType::Exe, Some(crate_name.as_str()));
|
||||||
match crate_type {
|
match crate_type {
|
||||||
CrateType::Rlib => {
|
CrateType::Rlib => {
|
||||||
let _timer = sess.timer("link_rlib");
|
let _timer = sess.timer("link_rlib");
|
||||||
|
@ -152,6 +156,17 @@ pub fn link_binary<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if output.is_stdout() {
|
||||||
|
if output.is_tty() {
|
||||||
|
sess.emit_err(errors::BinaryOutputToTty {
|
||||||
|
shorthand: OutputType::Exe.shorthand(),
|
||||||
|
});
|
||||||
|
} else if let Err(e) = copy_to_stdout(&out_filename) {
|
||||||
|
sess.emit_err(errors::CopyPath::new(&out_filename, output.as_path(), e));
|
||||||
|
}
|
||||||
|
tempfiles_for_stdout_output.push(out_filename);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,6 +204,11 @@ pub fn link_binary<'a>(
|
||||||
remove_temps_from_module(allocator_module);
|
remove_temps_from_module(allocator_module);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the temporary files if output goes to stdout
|
||||||
|
for temp in tempfiles_for_stdout_output {
|
||||||
|
ensure_removed(sess.diagnostic(), &temp);
|
||||||
|
}
|
||||||
|
|
||||||
// If no requested outputs require linking, then the object temporaries should
|
// If no requested outputs require linking, then the object temporaries should
|
||||||
// be kept.
|
// be kept.
|
||||||
if !sess.opts.output_types.should_link() {
|
if !sess.opts.output_types.should_link() {
|
||||||
|
|
|
@ -23,12 +23,13 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||||
use rustc_incremental::{
|
use rustc_incremental::{
|
||||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||||
};
|
};
|
||||||
|
use rustc_metadata::fs::copy_to_stdout;
|
||||||
use rustc_metadata::EncodedMetadata;
|
use rustc_metadata::EncodedMetadata;
|
||||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||||
use rustc_middle::middle::exported_symbols::SymbolExportInfo;
|
use rustc_middle::middle::exported_symbols::SymbolExportInfo;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
|
use rustc_session::cgu_reuse_tracker::CguReuseTracker;
|
||||||
use rustc_session::config::{self, CrateType, Lto, OutputFilenames, OutputType};
|
use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType};
|
||||||
use rustc_session::config::{Passes, SwitchWithOptPath};
|
use rustc_session::config::{Passes, SwitchWithOptPath};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::source_map::SourceMap;
|
use rustc_span::source_map::SourceMap;
|
||||||
|
@ -535,9 +536,16 @@ fn produce_final_output_artifacts(
|
||||||
let mut user_wants_objects = false;
|
let mut user_wants_objects = false;
|
||||||
|
|
||||||
// Produce final compile outputs.
|
// Produce final compile outputs.
|
||||||
let copy_gracefully = |from: &Path, to: &Path| {
|
let copy_gracefully = |from: &Path, to: &OutFileName| match to {
|
||||||
if let Err(e) = fs::copy(from, to) {
|
OutFileName::Stdout => {
|
||||||
sess.emit_err(errors::CopyPath::new(from, to, e));
|
if let Err(e) = copy_to_stdout(from) {
|
||||||
|
sess.emit_err(errors::CopyPath::new(from, to.as_path(), e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutFileName::Real(path) => {
|
||||||
|
if let Err(e) = fs::copy(from, path) {
|
||||||
|
sess.emit_err(errors::CopyPath::new(from, path, e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -547,7 +555,12 @@ fn produce_final_output_artifacts(
|
||||||
// to copy `foo.0.x` to `foo.x`.
|
// to copy `foo.0.x` to `foo.x`.
|
||||||
let module_name = Some(&compiled_modules.modules[0].name[..]);
|
let module_name = Some(&compiled_modules.modules[0].name[..]);
|
||||||
let path = crate_output.temp_path(output_type, module_name);
|
let path = crate_output.temp_path(output_type, module_name);
|
||||||
copy_gracefully(&path, &crate_output.path(output_type));
|
let output = crate_output.path(output_type);
|
||||||
|
if !output_type.is_text_output() && output.is_tty() {
|
||||||
|
sess.emit_err(errors::BinaryOutputToTty { shorthand: output_type.shorthand() });
|
||||||
|
} else {
|
||||||
|
copy_gracefully(&path, &output);
|
||||||
|
}
|
||||||
if !sess.opts.cg.save_temps && !keep_numbered {
|
if !sess.opts.cg.save_temps && !keep_numbered {
|
||||||
// The user just wants `foo.x`, not `foo.#module-name#.x`.
|
// The user just wants `foo.x`, not `foo.#module-name#.x`.
|
||||||
ensure_removed(sess.diagnostic(), &path);
|
ensure_removed(sess.diagnostic(), &path);
|
||||||
|
|
|
@ -82,6 +82,12 @@ impl IntoDiagnosticArg for DebugArgPath<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(codegen_ssa_binary_output_to_tty)]
|
||||||
|
pub struct BinaryOutputToTty {
|
||||||
|
pub shorthand: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(codegen_ssa_ignoring_emit_path)]
|
#[diag(codegen_ssa_ignoring_emit_path)]
|
||||||
pub struct IgnoringEmitPath {
|
pub struct IgnoringEmitPath {
|
||||||
|
|
|
@ -34,7 +34,9 @@ use rustc_interface::{interface, Queries};
|
||||||
use rustc_lint::LintStore;
|
use rustc_lint::LintStore;
|
||||||
use rustc_metadata::locator;
|
use rustc_metadata::locator;
|
||||||
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
|
||||||
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
|
use rustc_session::config::{
|
||||||
|
ErrorOutputType, Input, OutFileName, OutputType, PrintRequest, TrimmedDefPaths,
|
||||||
|
};
|
||||||
use rustc_session::cstore::MetadataLoader;
|
use rustc_session::cstore::MetadataLoader;
|
||||||
use rustc_session::getopts::{self, Matches};
|
use rustc_session::getopts::{self, Matches};
|
||||||
use rustc_session::lint::{Lint, LintId};
|
use rustc_session::lint::{Lint, LintId};
|
||||||
|
@ -454,9 +456,12 @@ fn run_compiler(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract output directory and file from matches.
|
// Extract output directory and file from matches.
|
||||||
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>) {
|
fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileName>) {
|
||||||
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
|
let odir = matches.opt_str("out-dir").map(|o| PathBuf::from(&o));
|
||||||
let ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
|
let ofile = matches.opt_str("o").map(|o| match o.as_str() {
|
||||||
|
"-" => OutFileName::Stdout,
|
||||||
|
path => OutFileName::Real(PathBuf::from(path)),
|
||||||
|
});
|
||||||
(odir, ofile)
|
(odir, ofile)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -702,7 +707,7 @@ fn print_crate_info(
|
||||||
for &style in &crate_types {
|
for &style in &crate_types {
|
||||||
let fname =
|
let fname =
|
||||||
rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
|
rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
|
||||||
safe_println!("{}", fname.file_name().unwrap().to_string_lossy());
|
safe_println!("{}", fname.as_path().file_name().unwrap().to_string_lossy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Cfg => {
|
Cfg => {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use rustc_hir_pretty as pprust_hir;
|
||||||
use rustc_middle::hir::map as hir_map;
|
use rustc_middle::hir::map as hir_map;
|
||||||
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use rustc_session::config::{PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
use rustc_session::config::{OutFileName, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode};
|
||||||
use rustc_session::Session;
|
use rustc_session::Session;
|
||||||
use rustc_span::symbol::Ident;
|
use rustc_span::symbol::Ident;
|
||||||
use rustc_span::FileName;
|
use rustc_span::FileName;
|
||||||
|
@ -359,8 +359,8 @@ fn get_source(sess: &Session) -> (String, FileName) {
|
||||||
|
|
||||||
fn write_or_print(out: &str, sess: &Session) {
|
fn write_or_print(out: &str, sess: &Session) {
|
||||||
match &sess.io.output_file {
|
match &sess.io.output_file {
|
||||||
None => print!("{out}"),
|
None | Some(OutFileName::Stdout) => print!("{out}"),
|
||||||
Some(p) => {
|
Some(OutFileName::Real(p)) => {
|
||||||
if let Err(e) = std::fs::write(p, out) {
|
if let Err(e) = std::fs::write(p, out) {
|
||||||
sess.emit_fatal(UnprettyDumpFail {
|
sess.emit_fatal(UnprettyDumpFail {
|
||||||
path: p.display().to_string(),
|
path: p.display().to_string(),
|
||||||
|
|
|
@ -6,6 +6,7 @@ edition = "2021"
|
||||||
[lib]
|
[lib]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
atty = "0.2.13"
|
||||||
libloading = "0.7.1"
|
libloading = "0.7.1"
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
rustc-rayon-core = { version = "0.5.0", optional = true }
|
rustc-rayon-core = { version = "0.5.0", optional = true }
|
||||||
|
|
|
@ -33,6 +33,7 @@ interface_mixed_proc_macro_crate =
|
||||||
interface_multiple_output_types_adaption =
|
interface_multiple_output_types_adaption =
|
||||||
due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
|
due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
|
||||||
|
|
||||||
|
interface_multiple_output_types_to_stdout = can't use option `-o` or `--emit` to write multiple output types to stdout
|
||||||
interface_out_dir_error =
|
interface_out_dir_error =
|
||||||
failed to find or create the directory specified by `--out-dir`
|
failed to find or create the directory specified by `--out-dir`
|
||||||
|
|
||||||
|
|
|
@ -108,3 +108,7 @@ pub struct IgnoringExtraFilename;
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(interface_ignoring_out_dir)]
|
#[diag(interface_ignoring_out_dir)]
|
||||||
pub struct IgnoringOutDir;
|
pub struct IgnoringOutDir;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(interface_multiple_output_types_to_stdout)]
|
||||||
|
pub struct MultipleOutputTypesToStdout;
|
||||||
|
|
|
@ -14,7 +14,7 @@ use rustc_middle::{bug, ty};
|
||||||
use rustc_parse::maybe_new_parser_from_source_str;
|
use rustc_parse::maybe_new_parser_from_source_str;
|
||||||
use rustc_query_impl::QueryCtxt;
|
use rustc_query_impl::QueryCtxt;
|
||||||
use rustc_query_system::query::print_query_stack;
|
use rustc_query_system::query::print_query_stack;
|
||||||
use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
|
use rustc_session::config::{self, ErrorOutputType, Input, OutFileName, OutputFilenames};
|
||||||
use rustc_session::config::{CheckCfg, ExpectedValues};
|
use rustc_session::config::{CheckCfg, ExpectedValues};
|
||||||
use rustc_session::lint;
|
use rustc_session::lint;
|
||||||
use rustc_session::parse::{CrateConfig, ParseSess};
|
use rustc_session::parse::{CrateConfig, ParseSess};
|
||||||
|
@ -252,7 +252,7 @@ pub struct Config {
|
||||||
|
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub output_dir: Option<PathBuf>,
|
pub output_dir: Option<PathBuf>,
|
||||||
pub output_file: Option<PathBuf>,
|
pub output_file: Option<OutFileName>,
|
||||||
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
|
||||||
pub locale_resources: &'static [&'static str],
|
pub locale_resources: &'static [&'static str],
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_a
|
||||||
use rustc_passes::{self, hir_stats, layout_test};
|
use rustc_passes::{self, hir_stats, layout_test};
|
||||||
use rustc_plugin_impl as plugin;
|
use rustc_plugin_impl as plugin;
|
||||||
use rustc_resolve::Resolver;
|
use rustc_resolve::Resolver;
|
||||||
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
|
use rustc_session::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||||
use rustc_session::cstore::{MetadataLoader, Untracked};
|
use rustc_session::cstore::{MetadataLoader, Untracked};
|
||||||
use rustc_session::output::filename_for_input;
|
use rustc_session::output::filename_for_input;
|
||||||
use rustc_session::search_paths::PathKind;
|
use rustc_session::search_paths::PathKind;
|
||||||
|
@ -373,19 +373,23 @@ fn generated_output_paths(
|
||||||
) -> Vec<PathBuf> {
|
) -> Vec<PathBuf> {
|
||||||
let mut out_filenames = Vec::new();
|
let mut out_filenames = Vec::new();
|
||||||
for output_type in sess.opts.output_types.keys() {
|
for output_type in sess.opts.output_types.keys() {
|
||||||
let file = outputs.path(*output_type);
|
let out_filename = outputs.path(*output_type);
|
||||||
|
let file = out_filename.as_path().to_path_buf();
|
||||||
match *output_type {
|
match *output_type {
|
||||||
// If the filename has been overridden using `-o`, it will not be modified
|
// If the filename has been overridden using `-o`, it will not be modified
|
||||||
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
|
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
|
||||||
OutputType::Exe if !exact_name => {
|
OutputType::Exe if !exact_name => {
|
||||||
for crate_type in sess.crate_types().iter() {
|
for crate_type in sess.crate_types().iter() {
|
||||||
let p = filename_for_input(sess, *crate_type, crate_name, outputs);
|
let p = filename_for_input(sess, *crate_type, crate_name, outputs);
|
||||||
out_filenames.push(p);
|
out_filenames.push(p.as_path().to_path_buf());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => {
|
OutputType::DepInfo if sess.opts.unstable_opts.dep_info_omit_d_target => {
|
||||||
// Don't add the dep-info output when omitting it from dep-info targets
|
// Don't add the dep-info output when omitting it from dep-info targets
|
||||||
}
|
}
|
||||||
|
OutputType::DepInfo if out_filename.is_stdout() => {
|
||||||
|
// Don't add the dep-info output when it goes to stdout
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
out_filenames.push(file);
|
out_filenames.push(file);
|
||||||
}
|
}
|
||||||
|
@ -452,7 +456,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
||||||
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
|
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let deps_filename = outputs.path(OutputType::DepInfo);
|
let deps_output = outputs.path(OutputType::DepInfo);
|
||||||
|
let deps_filename = deps_output.as_path();
|
||||||
|
|
||||||
let result: io::Result<()> = try {
|
let result: io::Result<()> = try {
|
||||||
// Build a list of files used to compile the output and
|
// Build a list of files used to compile the output and
|
||||||
|
@ -515,7 +520,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut file = BufWriter::new(fs::File::create(&deps_filename)?);
|
let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> {
|
||||||
for path in out_filenames {
|
for path in out_filenames {
|
||||||
writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
|
writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
|
||||||
}
|
}
|
||||||
|
@ -544,6 +549,20 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
|
||||||
writeln!(file)?;
|
writeln!(file)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
match deps_output {
|
||||||
|
OutFileName::Stdout => {
|
||||||
|
let mut file = BufWriter::new(io::stdout());
|
||||||
|
write_deps_to_file(&mut file)?;
|
||||||
|
}
|
||||||
|
OutFileName::Real(ref path) => {
|
||||||
|
let mut file = BufWriter::new(fs::File::create(path)?);
|
||||||
|
write_deps_to_file(&mut file)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_session::config::InstrumentXRay;
|
||||||
use rustc_session::config::TraitSolver;
|
use rustc_session::config::TraitSolver;
|
||||||
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
BranchProtection, Externs, OomStrategy, OutputType, OutputTypes, PAuthKey, PacRet,
|
BranchProtection, Externs, OomStrategy, OutFileName, OutputType, OutputTypes, PAuthKey, PacRet,
|
||||||
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
|
ProcMacroExecutionStrategy, SymbolManglingVersion, WasiExecModel,
|
||||||
};
|
};
|
||||||
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
use rustc_session::config::{CFGuard, ExternEntry, LinkerPluginLto, LtoCli, SwitchWithOptPath};
|
||||||
|
@ -167,8 +167,14 @@ fn test_output_types_tracking_hash_different_paths() {
|
||||||
let mut v2 = Options::default();
|
let mut v2 = Options::default();
|
||||||
let mut v3 = Options::default();
|
let mut v3 = Options::default();
|
||||||
|
|
||||||
v1.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("./some/thing")))]);
|
v1.output_types = OutputTypes::new(&[(
|
||||||
v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
|
OutputType::Exe,
|
||||||
|
Some(OutFileName::Real(PathBuf::from("./some/thing"))),
|
||||||
|
)]);
|
||||||
|
v2.output_types = OutputTypes::new(&[(
|
||||||
|
OutputType::Exe,
|
||||||
|
Some(OutFileName::Real(PathBuf::from("/some/thing"))),
|
||||||
|
)]);
|
||||||
v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
|
v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
|
||||||
|
|
||||||
assert_non_crate_hash_different(&v1, &v2);
|
assert_non_crate_hash_different(&v1, &v2);
|
||||||
|
@ -182,13 +188,13 @@ fn test_output_types_tracking_hash_different_construction_order() {
|
||||||
let mut v2 = Options::default();
|
let mut v2 = Options::default();
|
||||||
|
|
||||||
v1.output_types = OutputTypes::new(&[
|
v1.output_types = OutputTypes::new(&[
|
||||||
(OutputType::Exe, Some(PathBuf::from("./some/thing"))),
|
(OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))),
|
||||||
(OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
|
(OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
v2.output_types = OutputTypes::new(&[
|
v2.output_types = OutputTypes::new(&[
|
||||||
(OutputType::Bitcode, Some(PathBuf::from("./some/thing.bc"))),
|
(OutputType::Bitcode, Some(OutFileName::Real(PathBuf::from("./some/thing.bc")))),
|
||||||
(OutputType::Exe, Some(PathBuf::from("./some/thing"))),
|
(OutputType::Exe, Some(OutFileName::Real(PathBuf::from("./some/thing")))),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
assert_same_hash(&v1, &v2);
|
assert_same_hash(&v1, &v2);
|
||||||
|
|
|
@ -11,7 +11,7 @@ use rustc_parse::validate_attr;
|
||||||
use rustc_session as session;
|
use rustc_session as session;
|
||||||
use rustc_session::config::CheckCfg;
|
use rustc_session::config::CheckCfg;
|
||||||
use rustc_session::config::{self, CrateType};
|
use rustc_session::config::{self, CrateType};
|
||||||
use rustc_session::config::{ErrorOutputType, OutputFilenames};
|
use rustc_session::config::{ErrorOutputType, OutFileName, OutputFilenames, OutputTypes};
|
||||||
use rustc_session::filesearch::sysroot_candidates;
|
use rustc_session::filesearch::sysroot_candidates;
|
||||||
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
|
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
|
||||||
use rustc_session::parse::CrateConfig;
|
use rustc_session::parse::CrateConfig;
|
||||||
|
@ -500,7 +500,36 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
|
||||||
base
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn multiple_output_types_to_stdout(
|
||||||
|
output_types: &OutputTypes,
|
||||||
|
single_output_file_is_stdout: bool,
|
||||||
|
) -> bool {
|
||||||
|
if atty::is(atty::Stream::Stdout) {
|
||||||
|
// If stdout is a tty, check if multiple text output types are
|
||||||
|
// specified by `--emit foo=- --emit bar=-` or `-o - --emit foo,bar`
|
||||||
|
let named_text_types = output_types
|
||||||
|
.iter()
|
||||||
|
.filter(|(f, o)| f.is_text_output() && *o == &Some(OutFileName::Stdout))
|
||||||
|
.count();
|
||||||
|
let unnamed_text_types =
|
||||||
|
output_types.iter().filter(|(f, o)| f.is_text_output() && o.is_none()).count();
|
||||||
|
named_text_types > 1 || unnamed_text_types > 1 && single_output_file_is_stdout
|
||||||
|
} else {
|
||||||
|
// Otherwise, all the output types should be checked
|
||||||
|
let named_types =
|
||||||
|
output_types.values().filter(|o| *o == &Some(OutFileName::Stdout)).count();
|
||||||
|
let unnamed_types = output_types.values().filter(|o| o.is_none()).count();
|
||||||
|
named_types > 1 || unnamed_types > 1 && single_output_file_is_stdout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames {
|
pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> OutputFilenames {
|
||||||
|
if multiple_output_types_to_stdout(
|
||||||
|
&sess.opts.output_types,
|
||||||
|
sess.io.output_file == Some(OutFileName::Stdout),
|
||||||
|
) {
|
||||||
|
sess.emit_fatal(errors::MultipleOutputTypesToStdout);
|
||||||
|
}
|
||||||
match sess.io.output_file {
|
match sess.io.output_file {
|
||||||
None => {
|
None => {
|
||||||
// "-" as input file will cause the parser to read from stdin so we
|
// "-" as input file will cause the parser to read from stdin so we
|
||||||
|
@ -544,7 +573,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
|
||||||
|
|
||||||
OutputFilenames::new(
|
OutputFilenames::new(
|
||||||
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
|
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
|
||||||
out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
|
out_file.filestem().unwrap_or_default().to_str().unwrap().to_string(),
|
||||||
ofile,
|
ofile,
|
||||||
sess.io.temps_dir.clone(),
|
sess.io.temps_dir.clone(),
|
||||||
sess.opts.cg.extra_filename.clone(),
|
sess.opts.cg.extra_filename.clone(),
|
||||||
|
|
|
@ -4,6 +4,9 @@ metadata_as_needed_compatibility =
|
||||||
metadata_bad_panic_strategy =
|
metadata_bad_panic_strategy =
|
||||||
the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
|
the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
|
||||||
|
|
||||||
|
metadata_binary_output_to_tty =
|
||||||
|
option `-o` or `--emit` is used to write binary output type `metadata` to stdout, but stdout is a tty
|
||||||
|
|
||||||
metadata_bundle_needs_static =
|
metadata_bundle_needs_static =
|
||||||
linking modifier `bundle` is only compatible with `static` linking kind
|
linking modifier `bundle` is only compatible with `static` linking kind
|
||||||
|
|
||||||
|
@ -63,6 +66,9 @@ metadata_fail_seek_file =
|
||||||
metadata_fail_write_file =
|
metadata_fail_write_file =
|
||||||
failed to write to the file: {$err}
|
failed to write to the file: {$err}
|
||||||
|
|
||||||
|
metadata_failed_copy_to_stdout =
|
||||||
|
failed to copy {$filename} to stdout: {$err}
|
||||||
|
|
||||||
metadata_failed_create_encoded_metadata =
|
metadata_failed_create_encoded_metadata =
|
||||||
failed to create encoded metadata from file: {$err}
|
failed to create encoded metadata from file: {$err}
|
||||||
|
|
||||||
|
|
|
@ -395,6 +395,17 @@ pub struct FailedWriteError {
|
||||||
pub err: Error,
|
pub err: Error,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(metadata_failed_copy_to_stdout)]
|
||||||
|
pub struct FailedCopyToStdout {
|
||||||
|
pub filename: PathBuf,
|
||||||
|
pub err: Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(metadata_binary_output_to_tty)]
|
||||||
|
pub struct BinaryOutputToTty;
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(metadata_missing_native_library)]
|
#[diag(metadata_missing_native_library)]
|
||||||
pub struct MissingNativeLibrary<'a> {
|
pub struct MissingNativeLibrary<'a> {
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError,
|
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
|
||||||
|
FailedCreateTempdir, FailedWriteError,
|
||||||
};
|
};
|
||||||
use crate::{encode_metadata, EncodedMetadata};
|
use crate::{encode_metadata, EncodedMetadata};
|
||||||
|
|
||||||
use rustc_data_structures::temp_dir::MaybeTempDir;
|
use rustc_data_structures::temp_dir::MaybeTempDir;
|
||||||
use rustc_hir::def_id::LOCAL_CRATE;
|
use rustc_hir::def_id::LOCAL_CRATE;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::OutputType;
|
use rustc_session::config::{OutFileName, OutputType};
|
||||||
use rustc_session::output::filename_for_metadata;
|
use rustc_session::output::filename_for_metadata;
|
||||||
use rustc_session::{MetadataKind, Session};
|
use rustc_session::{MetadataKind, Session};
|
||||||
use tempfile::Builder as TempFileBuilder;
|
use tempfile::Builder as TempFileBuilder;
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::{fs, io};
|
||||||
|
|
||||||
// FIXME(eddyb) maybe include the crate name in this?
|
// FIXME(eddyb) maybe include the crate name in this?
|
||||||
pub const METADATA_FILENAME: &str = "lib.rmeta";
|
pub const METADATA_FILENAME: &str = "lib.rmeta";
|
||||||
|
@ -74,23 +75,37 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
|
||||||
// this file always exists.
|
// this file always exists.
|
||||||
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
|
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
|
||||||
let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
|
let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
|
||||||
if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) {
|
let filename = match out_filename {
|
||||||
tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err });
|
OutFileName::Real(ref path) => {
|
||||||
|
if let Err(err) = non_durable_rename(&metadata_filename, path) {
|
||||||
|
tcx.sess.emit_fatal(FailedWriteError { filename: path.to_path_buf(), err });
|
||||||
}
|
}
|
||||||
|
path.clone()
|
||||||
|
}
|
||||||
|
OutFileName::Stdout => {
|
||||||
|
if out_filename.is_tty() {
|
||||||
|
tcx.sess.emit_err(BinaryOutputToTty);
|
||||||
|
} else if let Err(err) = copy_to_stdout(&metadata_filename) {
|
||||||
|
tcx.sess
|
||||||
|
.emit_err(FailedCopyToStdout { filename: metadata_filename.clone(), err });
|
||||||
|
}
|
||||||
|
metadata_filename
|
||||||
|
}
|
||||||
|
};
|
||||||
if tcx.sess.opts.json_artifact_notifications {
|
if tcx.sess.opts.json_artifact_notifications {
|
||||||
tcx.sess
|
tcx.sess
|
||||||
.parse_sess
|
.parse_sess
|
||||||
.span_diagnostic
|
.span_diagnostic
|
||||||
.emit_artifact_notification(&out_filename, "metadata");
|
.emit_artifact_notification(&out_filename.as_path(), "metadata");
|
||||||
}
|
}
|
||||||
(out_filename, None)
|
(filename, None)
|
||||||
} else {
|
} else {
|
||||||
(metadata_filename, Some(metadata_tmpdir))
|
(metadata_filename, Some(metadata_tmpdir))
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load metadata back to memory: codegen may need to include it in object files.
|
// Load metadata back to memory: codegen may need to include it in object files.
|
||||||
let metadata =
|
let metadata = EncodedMetadata::from_path(metadata_filename.clone(), metadata_tmpdir)
|
||||||
EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err });
|
tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -116,3 +131,11 @@ pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
|
||||||
let _ = std::fs::remove_file(dst);
|
let _ = std::fs::remove_file(dst);
|
||||||
std::fs::rename(src, dst)
|
std::fs::rename(src, dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn copy_to_stdout(from: &Path) -> io::Result<()> {
|
||||||
|
let file = fs::File::open(from)?;
|
||||||
|
let mut reader = io::BufReader::new(file);
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
io::copy(&mut reader, &mut stdout)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::MirPass;
|
||||||
use rustc_middle::mir::write_mir_pretty;
|
use rustc_middle::mir::write_mir_pretty;
|
||||||
use rustc_middle::mir::Body;
|
use rustc_middle::mir::Body;
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use rustc_session::config::OutputType;
|
use rustc_session::config::{OutFileName, OutputType};
|
||||||
|
|
||||||
pub struct Marker(pub &'static str);
|
pub struct Marker(pub &'static str);
|
||||||
|
|
||||||
|
@ -20,8 +20,15 @@ impl<'tcx> MirPass<'tcx> for Marker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
|
pub fn emit_mir(tcx: TyCtxt<'_>) -> io::Result<()> {
|
||||||
let path = tcx.output_filenames(()).path(OutputType::Mir);
|
match tcx.output_filenames(()).path(OutputType::Mir) {
|
||||||
|
OutFileName::Stdout => {
|
||||||
|
let mut f = io::stdout();
|
||||||
|
write_mir_pretty(tcx, None, &mut f)?;
|
||||||
|
}
|
||||||
|
OutFileName::Real(path) => {
|
||||||
let mut f = io::BufWriter::new(File::create(&path)?);
|
let mut f = io::BufWriter::new(File::create(&path)?);
|
||||||
write_mir_pretty(tcx, None, &mut f)?;
|
write_mir_pretty(tcx, None, &mut f)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ version = "0.0.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
atty = "0.2.13"
|
||||||
getopts = "0.2"
|
getopts = "0.2"
|
||||||
rustc_macros = { path = "../rustc_macros" }
|
rustc_macros = { path = "../rustc_macros" }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
|
|
@ -30,6 +30,7 @@ use std::collections::btree_map::{
|
||||||
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
|
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
|
||||||
};
|
};
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
@ -335,7 +336,7 @@ impl OutputType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shorthand(&self) -> &'static str {
|
pub fn shorthand(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
OutputType::Bitcode => "llvm-bc",
|
OutputType::Bitcode => "llvm-bc",
|
||||||
OutputType::Assembly => "asm",
|
OutputType::Assembly => "asm",
|
||||||
|
@ -388,6 +389,18 @@ impl OutputType {
|
||||||
OutputType::Exe => "",
|
OutputType::Exe => "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_text_output(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
OutputType::Assembly
|
||||||
|
| OutputType::LlvmAssembly
|
||||||
|
| OutputType::Mir
|
||||||
|
| OutputType::DepInfo => true,
|
||||||
|
OutputType::Bitcode | OutputType::Object | OutputType::Metadata | OutputType::Exe => {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The type of diagnostics output to generate.
|
/// The type of diagnostics output to generate.
|
||||||
|
@ -440,14 +453,14 @@ pub enum ResolveDocLinks {
|
||||||
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
|
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
|
||||||
/// should only depend on the output types, not the paths they're written to.
|
/// should only depend on the output types, not the paths they're written to.
|
||||||
#[derive(Clone, Debug, Hash, HashStable_Generic)]
|
#[derive(Clone, Debug, Hash, HashStable_Generic)]
|
||||||
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
|
pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
|
||||||
|
|
||||||
impl OutputTypes {
|
impl OutputTypes {
|
||||||
pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
|
pub fn new(entries: &[(OutputType, Option<OutFileName>)]) -> OutputTypes {
|
||||||
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
|
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
|
pub fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
|
||||||
self.0.get(key)
|
self.0.get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,11 +468,15 @@ impl OutputTypes {
|
||||||
self.0.contains_key(key)
|
self.0.contains_key(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<PathBuf>> {
|
pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> {
|
||||||
|
self.0.iter()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> BTreeMapKeysIter<'_, OutputType, Option<OutFileName>> {
|
||||||
self.0.keys()
|
self.0.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
|
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
|
||||||
self.0.values()
|
self.0.values()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,11 +679,71 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Debug, HashStable_Generic, PartialEq)]
|
||||||
|
pub enum OutFileName {
|
||||||
|
Real(PathBuf),
|
||||||
|
Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutFileName {
|
||||||
|
pub fn parent(&self) -> Option<&Path> {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(ref path) => path.parent(),
|
||||||
|
OutFileName::Stdout => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn filestem(&self) -> Option<&OsStr> {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(ref path) => path.file_stem(),
|
||||||
|
OutFileName::Stdout => Some(OsStr::new("stdout")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_stdout(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(_) => false,
|
||||||
|
OutFileName::Stdout => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_tty(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(_) => false,
|
||||||
|
OutFileName::Stdout => atty::is(atty::Stream::Stdout),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_path(&self) -> &Path {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(ref path) => path.as_ref(),
|
||||||
|
OutFileName::Stdout => &Path::new("stdout"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For a given output filename, return the actual name of the file that
|
||||||
|
/// can be used to write codegen data of type `flavor`. For real-path
|
||||||
|
/// output filenames, this would be trivial as we can just use the path.
|
||||||
|
/// Otherwise for stdout, return a temporary path so that the codegen data
|
||||||
|
/// may be later copied to stdout.
|
||||||
|
pub fn file_for_writing(
|
||||||
|
&self,
|
||||||
|
outputs: &OutputFilenames,
|
||||||
|
flavor: OutputType,
|
||||||
|
codegen_unit_name: Option<&str>,
|
||||||
|
) -> PathBuf {
|
||||||
|
match *self {
|
||||||
|
OutFileName::Real(ref path) => path.clone(),
|
||||||
|
OutFileName::Stdout => outputs.temp_path(flavor, codegen_unit_name),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Hash, Debug, HashStable_Generic)]
|
#[derive(Clone, Hash, Debug, HashStable_Generic)]
|
||||||
pub struct OutputFilenames {
|
pub struct OutputFilenames {
|
||||||
pub out_directory: PathBuf,
|
pub out_directory: PathBuf,
|
||||||
filestem: String,
|
filestem: String,
|
||||||
pub single_output_file: Option<PathBuf>,
|
pub single_output_file: Option<OutFileName>,
|
||||||
pub temps_directory: Option<PathBuf>,
|
pub temps_directory: Option<PathBuf>,
|
||||||
pub outputs: OutputTypes,
|
pub outputs: OutputTypes,
|
||||||
}
|
}
|
||||||
|
@ -679,7 +756,7 @@ impl OutputFilenames {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
out_directory: PathBuf,
|
out_directory: PathBuf,
|
||||||
out_filestem: String,
|
out_filestem: String,
|
||||||
single_output_file: Option<PathBuf>,
|
single_output_file: Option<OutFileName>,
|
||||||
temps_directory: Option<PathBuf>,
|
temps_directory: Option<PathBuf>,
|
||||||
extra: String,
|
extra: String,
|
||||||
outputs: OutputTypes,
|
outputs: OutputTypes,
|
||||||
|
@ -693,12 +770,12 @@ impl OutputFilenames {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path(&self, flavor: OutputType) -> PathBuf {
|
pub fn path(&self, flavor: OutputType) -> OutFileName {
|
||||||
self.outputs
|
self.outputs
|
||||||
.get(&flavor)
|
.get(&flavor)
|
||||||
.and_then(|p| p.to_owned())
|
.and_then(|p| p.to_owned())
|
||||||
.or_else(|| self.single_output_file.clone())
|
.or_else(|| self.single_output_file.clone())
|
||||||
.unwrap_or_else(|| self.output_path(flavor))
|
.unwrap_or_else(|| OutFileName::Real(self.output_path(flavor)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the output path where a compilation artifact of the given type
|
/// Gets the output path where a compilation artifact of the given type
|
||||||
|
@ -1825,7 +1902,10 @@ fn parse_output_types(
|
||||||
for output_type in list.split(',') {
|
for output_type in list.split(',') {
|
||||||
let (shorthand, path) = match output_type.split_once('=') {
|
let (shorthand, path) = match output_type.split_once('=') {
|
||||||
None => (output_type, None),
|
None => (output_type, None),
|
||||||
Some((shorthand, path)) => (shorthand, Some(PathBuf::from(path))),
|
Some((shorthand, "-")) => (shorthand, Some(OutFileName::Stdout)),
|
||||||
|
Some((shorthand, path)) => {
|
||||||
|
(shorthand, Some(OutFileName::Real(PathBuf::from(path))))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
|
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
|
||||||
early_error(
|
early_error(
|
||||||
|
@ -2909,7 +2989,7 @@ pub(crate) mod dep_tracking {
|
||||||
use super::{
|
use super::{
|
||||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||||
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
||||||
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
||||||
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
|
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
|
||||||
TraitSolver, TrimmedDefPaths,
|
TraitSolver, TrimmedDefPaths,
|
||||||
};
|
};
|
||||||
|
@ -3007,6 +3087,7 @@ pub(crate) mod dep_tracking {
|
||||||
SourceFileHashAlgorithm,
|
SourceFileHashAlgorithm,
|
||||||
TrimmedDefPaths,
|
TrimmedDefPaths,
|
||||||
Option<LdImpl>,
|
Option<LdImpl>,
|
||||||
|
OutFileName,
|
||||||
OutputType,
|
OutputType,
|
||||||
RealFileName,
|
RealFileName,
|
||||||
LocationDetail,
|
LocationDetail,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//! Related to out filenames of compilation (e.g. save analysis, binaries).
|
//! Related to out filenames of compilation (e.g. save analysis, binaries).
|
||||||
use crate::config::{CrateType, Input, OutputFilenames, OutputType};
|
use crate::config::{CrateType, Input, OutFileName, OutputFilenames, OutputType};
|
||||||
use crate::errors::{
|
use crate::errors::{
|
||||||
CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
|
CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
|
||||||
InvalidCharacterInCrateName,
|
InvalidCharacterInCrateName,
|
||||||
|
@ -8,14 +8,14 @@ use crate::Session;
|
||||||
use rustc_ast::{self as ast, attr};
|
use rustc_ast::{self as ast, attr};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn out_filename(
|
pub fn out_filename(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
crate_type: CrateType,
|
crate_type: CrateType,
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
crate_name: Symbol,
|
crate_name: Symbol,
|
||||||
) -> PathBuf {
|
) -> OutFileName {
|
||||||
let default_filename = 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
|
let out_filename = outputs
|
||||||
.outputs
|
.outputs
|
||||||
|
@ -24,7 +24,9 @@ pub fn out_filename(
|
||||||
.or_else(|| outputs.single_output_file.clone())
|
.or_else(|| outputs.single_output_file.clone())
|
||||||
.unwrap_or(default_filename);
|
.unwrap_or(default_filename);
|
||||||
|
|
||||||
check_file_is_writeable(&out_filename, sess);
|
if let OutFileName::Real(ref path) = out_filename {
|
||||||
|
check_file_is_writeable(path, sess);
|
||||||
|
}
|
||||||
|
|
||||||
out_filename
|
out_filename
|
||||||
}
|
}
|
||||||
|
@ -112,7 +114,7 @@ pub fn filename_for_metadata(
|
||||||
sess: &Session,
|
sess: &Session,
|
||||||
crate_name: Symbol,
|
crate_name: Symbol,
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
) -> PathBuf {
|
) -> OutFileName {
|
||||||
// If the command-line specified the path, use that directly.
|
// If the command-line specified the path, use that directly.
|
||||||
if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
|
if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
|
||||||
return out_filename.clone();
|
return out_filename.clone();
|
||||||
|
@ -120,12 +122,13 @@ pub fn filename_for_metadata(
|
||||||
|
|
||||||
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
||||||
|
|
||||||
let out_filename = outputs
|
let out_filename = outputs.single_output_file.clone().unwrap_or_else(|| {
|
||||||
.single_output_file
|
OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rmeta")))
|
||||||
.clone()
|
});
|
||||||
.unwrap_or_else(|| outputs.out_directory.join(&format!("lib{libname}.rmeta")));
|
|
||||||
|
|
||||||
check_file_is_writeable(&out_filename, sess);
|
if let OutFileName::Real(ref path) = out_filename {
|
||||||
|
check_file_is_writeable(path, sess);
|
||||||
|
}
|
||||||
|
|
||||||
out_filename
|
out_filename
|
||||||
}
|
}
|
||||||
|
@ -135,23 +138,33 @@ pub fn filename_for_input(
|
||||||
crate_type: CrateType,
|
crate_type: CrateType,
|
||||||
crate_name: Symbol,
|
crate_name: Symbol,
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
) -> PathBuf {
|
) -> OutFileName {
|
||||||
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
||||||
|
|
||||||
match crate_type {
|
match crate_type {
|
||||||
CrateType::Rlib => outputs.out_directory.join(&format!("lib{libname}.rlib")),
|
CrateType::Rlib => {
|
||||||
|
OutFileName::Real(outputs.out_directory.join(&format!("lib{libname}.rlib")))
|
||||||
|
}
|
||||||
CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
|
CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => {
|
||||||
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
|
let (prefix, suffix) = (&sess.target.dll_prefix, &sess.target.dll_suffix);
|
||||||
outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
|
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
|
||||||
}
|
}
|
||||||
CrateType::Staticlib => {
|
CrateType::Staticlib => {
|
||||||
let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix);
|
let (prefix, suffix) = (&sess.target.staticlib_prefix, &sess.target.staticlib_suffix);
|
||||||
outputs.out_directory.join(&format!("{prefix}{libname}{suffix}"))
|
OutFileName::Real(outputs.out_directory.join(&format!("{prefix}{libname}{suffix}")))
|
||||||
}
|
}
|
||||||
CrateType::Executable => {
|
CrateType::Executable => {
|
||||||
let suffix = &sess.target.exe_suffix;
|
let suffix = &sess.target.exe_suffix;
|
||||||
let out_filename = outputs.path(OutputType::Exe);
|
let out_filename = outputs.path(OutputType::Exe);
|
||||||
if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) }
|
if let OutFileName::Real(ref path) = out_filename {
|
||||||
|
if suffix.is_empty() {
|
||||||
|
out_filename
|
||||||
|
} else {
|
||||||
|
OutFileName::Real(path.with_extension(&suffix[1..]))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
out_filename
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ use crate::cgu_reuse_tracker::CguReuseTracker;
|
||||||
use crate::code_stats::CodeStats;
|
use crate::code_stats::CodeStats;
|
||||||
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
||||||
use crate::config::Input;
|
use crate::config::Input;
|
||||||
use crate::config::{self, CrateType, InstrumentCoverage, OptLevel, OutputType, SwitchWithOptPath};
|
use crate::config::{
|
||||||
|
self, CrateType, InstrumentCoverage, OptLevel, OutFileName, OutputType, SwitchWithOptPath,
|
||||||
|
};
|
||||||
use crate::errors;
|
use crate::errors;
|
||||||
use crate::parse::{add_feature_diagnostics, ParseSess};
|
use crate::parse::{add_feature_diagnostics, ParseSess};
|
||||||
use crate::search_paths::{PathKind, SearchPath};
|
use crate::search_paths::{PathKind, SearchPath};
|
||||||
|
@ -133,7 +135,7 @@ pub struct Limits {
|
||||||
pub struct CompilerIO {
|
pub struct CompilerIO {
|
||||||
pub input: Input,
|
pub input: Input,
|
||||||
pub output_dir: Option<PathBuf>,
|
pub output_dir: Option<PathBuf>,
|
||||||
pub output_file: Option<PathBuf>,
|
pub output_file: Option<OutFileName>,
|
||||||
pub temps_dir: Option<PathBuf>,
|
pub temps_dir: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,12 @@ flag](codegen-options/index.md#extra-filename). The files are written to the
|
||||||
current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each
|
current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each
|
||||||
emission type may also specify the output filename with the form `KIND=PATH`,
|
emission type may also specify the output filename with the form `KIND=PATH`,
|
||||||
which takes precedence over the `-o` flag.
|
which takes precedence over the `-o` flag.
|
||||||
|
Specifying `-o -` or `--emit KIND=-` asks rustc to emit to stdout.
|
||||||
|
Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to
|
||||||
|
stdout despite it being a tty or not. This will result in an error if any
|
||||||
|
binary output type is written to stdout that is a tty.
|
||||||
|
This will also result in an error if multiple output types
|
||||||
|
would be written to stdout, because they would be all mixed together.
|
||||||
|
|
||||||
[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
|
[LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html
|
||||||
[LLVM IR]: https://llvm.org/docs/LangRef.html
|
[LLVM IR]: https://llvm.org/docs/LangRef.html
|
||||||
|
|
|
@ -62,7 +62,7 @@ impl CodegenBackend for TheBackend {
|
||||||
codegen_results: CodegenResults,
|
codegen_results: CodegenResults,
|
||||||
outputs: &OutputFilenames,
|
outputs: &OutputFilenames,
|
||||||
) -> Result<(), ErrorGuaranteed> {
|
) -> Result<(), ErrorGuaranteed> {
|
||||||
use rustc_session::{config::CrateType, output::out_filename};
|
use rustc_session::{config::{CrateType, OutFileName}, output::out_filename};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let crate_name = codegen_results.crate_info.local_crate_name;
|
let crate_name = codegen_results.crate_info.local_crate_name;
|
||||||
for &crate_type in sess.opts.crate_types.iter() {
|
for &crate_type in sess.opts.crate_types.iter() {
|
||||||
|
@ -70,9 +70,17 @@ impl CodegenBackend for TheBackend {
|
||||||
sess.fatal(format!("Crate type is {:?}", crate_type));
|
sess.fatal(format!("Crate type is {:?}", crate_type));
|
||||||
}
|
}
|
||||||
let output_name = out_filename(sess, crate_type, &outputs, crate_name);
|
let output_name = out_filename(sess, crate_type, &outputs, crate_name);
|
||||||
let mut out_file = ::std::fs::File::create(output_name).unwrap();
|
match output_name {
|
||||||
|
OutFileName::Real(ref path) => {
|
||||||
|
let mut out_file = ::std::fs::File::create(path).unwrap();
|
||||||
write!(out_file, "This has been \"compiled\" successfully.").unwrap();
|
write!(out_file, "This has been \"compiled\" successfully.").unwrap();
|
||||||
}
|
}
|
||||||
|
OutFileName::Stdout => {
|
||||||
|
let mut stdout = std::io::stdout();
|
||||||
|
write!(stdout, "This has been \"compiled\" successfully.").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ extern crate rustc_session;
|
||||||
extern crate rustc_span;
|
extern crate rustc_span;
|
||||||
|
|
||||||
use rustc_interface::interface;
|
use rustc_interface::interface;
|
||||||
use rustc_session::config::{Input, Options, OutputType, OutputTypes};
|
use rustc_session::config::{Input, Options, OutFileName, OutputType, OutputTypes};
|
||||||
use rustc_span::source_map::FileName;
|
use rustc_span::source_map::FileName;
|
||||||
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
@ -50,7 +50,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
|
||||||
crate_cfg: Default::default(),
|
crate_cfg: Default::default(),
|
||||||
crate_check_cfg: Default::default(),
|
crate_check_cfg: Default::default(),
|
||||||
input,
|
input,
|
||||||
output_file: Some(output),
|
output_file: Some(OutFileName::Real(output)),
|
||||||
output_dir: None,
|
output_dir: None,
|
||||||
file_loader: None,
|
file_loader: None,
|
||||||
locale_resources: &[],
|
locale_resources: &[],
|
||||||
|
|
51
tests/run-make/emit-to-stdout/Makefile
Normal file
51
tests/run-make/emit-to-stdout/Makefile
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
include ../tools.mk
|
||||||
|
|
||||||
|
SRC=test.rs
|
||||||
|
OUT=$(TMPDIR)/out
|
||||||
|
|
||||||
|
all: asm llvm-ir dep-info mir llvm-bc obj metadata link multiple-types multiple-types-option-o
|
||||||
|
|
||||||
|
asm: $(OUT)
|
||||||
|
$(RUSTC) --emit asm=$(OUT)/$@ $(SRC)
|
||||||
|
$(RUSTC) --emit asm=- $(SRC) | diff - $(OUT)/$@
|
||||||
|
llvm-ir: $(OUT)
|
||||||
|
$(RUSTC) --emit llvm-ir=$(OUT)/$@ $(SRC)
|
||||||
|
$(RUSTC) --emit llvm-ir=- $(SRC) | diff - $(OUT)/$@
|
||||||
|
dep-info: $(OUT)
|
||||||
|
$(RUSTC) -Z dep-info-omit-d-target=yes --emit dep-info=$(OUT)/$@ $(SRC)
|
||||||
|
$(RUSTC) --emit dep-info=- $(SRC) | diff - $(OUT)/$@
|
||||||
|
mir: $(OUT)
|
||||||
|
$(RUSTC) --emit mir=$(OUT)/$@ $(SRC)
|
||||||
|
$(RUSTC) --emit mir=- $(SRC) | diff - $(OUT)/$@
|
||||||
|
|
||||||
|
llvm-bc: $(OUT)
|
||||||
|
$(RUSTC) --emit llvm-bc=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true
|
||||||
|
diff $(OUT)/$@ emit-llvm-bc.stderr
|
||||||
|
obj: $(OUT)
|
||||||
|
$(RUSTC) --emit obj=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true
|
||||||
|
diff $(OUT)/$@ emit-obj.stderr
|
||||||
|
|
||||||
|
# For metadata output, a temporary directory will be created to hold the temporary
|
||||||
|
# metadata file. But when output is stdout, the temporary directory will be located
|
||||||
|
# in the same place as $(SRC), which is mounted as read-only in the tests. Thus as
|
||||||
|
# a workaround, $(SRC) is copied to the test output directory $(OUT) and we compile
|
||||||
|
# it there.
|
||||||
|
metadata: $(OUT)
|
||||||
|
cp $(SRC) $(OUT)
|
||||||
|
(cd $(OUT); $(RUSTC) --emit metadata=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true)
|
||||||
|
diff $(OUT)/$@ emit-metadata.stderr
|
||||||
|
|
||||||
|
link: $(OUT)
|
||||||
|
$(RUSTC) --emit link=- $(SRC) 1>/dev/ptmx 2>$(OUT)/$@ || true
|
||||||
|
diff $(OUT)/$@ emit-link.stderr
|
||||||
|
|
||||||
|
multiple-types: $(OUT)
|
||||||
|
$(RUSTC) --emit asm=- --emit llvm-ir=- --emit dep-info=- --emit mir=- $(SRC) 2>$(OUT)/$@ || true
|
||||||
|
diff $(OUT)/$@ emit-multiple-types.stderr
|
||||||
|
|
||||||
|
multiple-types-option-o: $(OUT)
|
||||||
|
$(RUSTC) -o - --emit asm,llvm-ir,dep-info,mir $(SRC) 2>$(OUT)/$@ || true
|
||||||
|
diff $(OUT)/$@ emit-multiple-types.stderr
|
||||||
|
|
||||||
|
$(OUT):
|
||||||
|
mkdir -p $(OUT)
|
4
tests/run-make/emit-to-stdout/emit-link.stderr
Normal file
4
tests/run-make/emit-to-stdout/emit-link.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: option `-o` or `--emit` is used to write binary output type `link` to stdout, but stdout is a tty
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
4
tests/run-make/emit-to-stdout/emit-llvm-bc.stderr
Normal file
4
tests/run-make/emit-to-stdout/emit-llvm-bc.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: option `-o` or `--emit` is used to write binary output type `llvm-bc` to stdout, but stdout is a tty
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
4
tests/run-make/emit-to-stdout/emit-metadata.stderr
Normal file
4
tests/run-make/emit-to-stdout/emit-metadata.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: option `-o` or `--emit` is used to write binary output type `metadata` to stdout, but stdout is a tty
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
4
tests/run-make/emit-to-stdout/emit-multiple-types.stderr
Normal file
4
tests/run-make/emit-to-stdout/emit-multiple-types.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: can't use option `-o` or `--emit` to write multiple output types to stdout
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
4
tests/run-make/emit-to-stdout/emit-obj.stderr
Normal file
4
tests/run-make/emit-to-stdout/emit-obj.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: option `-o` or `--emit` is used to write binary output type `obj` to stdout, but stdout is a tty
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
1
tests/run-make/emit-to-stdout/test.rs
Normal file
1
tests/run-make/emit-to-stdout/test.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#![crate_type = "rlib"]
|
Loading…
Add table
Add a link
Reference in a new issue