1
Fork 0

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:
bors 2023-06-09 09:45:40 +00:00
commit 343ad6f059
32 changed files with 439 additions and 101 deletions

View file

@ -8,7 +8,7 @@ use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_fs_util::fix_windows_verbatim_for_gcc;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
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::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
@ -68,6 +68,7 @@ pub fn link_binary<'a>(
) -> Result<(), ErrorGuaranteed> {
let _timer = sess.timer("link_binary");
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() {
// 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())
@ -97,12 +98,15 @@ pub fn link_binary<'a>(
.tempdir()
.unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
let out_filename = out_filename(
let output = out_filename(
sess,
crate_type,
outputs,
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 {
CrateType::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 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
// be kept.
if !sess.opts.output_types.should_link() {

View file

@ -23,12 +23,13 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc_incremental::{
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_middle::dep_graph::{WorkProduct, WorkProductId};
use rustc_middle::middle::exported_symbols::SymbolExportInfo;
use rustc_middle::ty::TyCtxt;
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::Session;
use rustc_span::source_map::SourceMap;
@ -535,9 +536,16 @@ fn produce_final_output_artifacts(
let mut user_wants_objects = false;
// Produce final compile outputs.
let copy_gracefully = |from: &Path, to: &Path| {
if let Err(e) = fs::copy(from, to) {
sess.emit_err(errors::CopyPath::new(from, to, e));
let copy_gracefully = |from: &Path, to: &OutFileName| match to {
OutFileName::Stdout => {
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`.
let module_name = Some(&compiled_modules.modules[0].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 {
// The user just wants `foo.x`, not `foo.#module-name#.x`.
ensure_removed(sess.diagnostic(), &path);

View file

@ -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)]
#[diag(codegen_ssa_ignoring_emit_path)]
pub struct IgnoringEmitPath {