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

@ -4,6 +4,9 @@ metadata_as_needed_compatibility =
metadata_bad_panic_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 =
linking modifier `bundle` is only compatible with `static` linking kind
@ -63,6 +66,9 @@ metadata_fail_seek_file =
metadata_fail_write_file =
failed to write to the file: {$err}
metadata_failed_copy_to_stdout =
failed to copy {$filename} to stdout: {$err}
metadata_failed_create_encoded_metadata =
failed to create encoded metadata from file: {$err}

View file

@ -395,6 +395,17 @@ pub struct FailedWriteError {
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)]
#[diag(metadata_missing_native_library)]
pub struct MissingNativeLibrary<'a> {

View file

@ -1,18 +1,19 @@
use crate::errors::{
FailedCreateEncodedMetadata, FailedCreateFile, FailedCreateTempdir, FailedWriteError,
BinaryOutputToTty, FailedCopyToStdout, FailedCreateEncodedMetadata, FailedCreateFile,
FailedCreateTempdir, FailedWriteError,
};
use crate::{encode_metadata, EncodedMetadata};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_hir::def_id::LOCAL_CRATE;
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::{MetadataKind, Session};
use tempfile::Builder as TempFileBuilder;
use std::fs;
use std::path::{Path, PathBuf};
use std::{fs, io};
// FIXME(eddyb) maybe include the crate name in this?
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.
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
let (metadata_filename, metadata_tmpdir) = if need_metadata_file {
if let Err(err) = non_durable_rename(&metadata_filename, &out_filename) {
tcx.sess.emit_fatal(FailedWriteError { filename: out_filename, err });
}
let filename = match out_filename {
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 {
tcx.sess
.parse_sess
.span_diagnostic
.emit_artifact_notification(&out_filename, "metadata");
.emit_artifact_notification(&out_filename.as_path(), "metadata");
}
(out_filename, None)
(filename, None)
} else {
(metadata_filename, Some(metadata_tmpdir))
};
// Load metadata back to memory: codegen may need to include it in object files.
let metadata =
EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| {
let metadata = EncodedMetadata::from_path(metadata_filename.clone(), metadata_tmpdir)
.unwrap_or_else(|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);
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(())
}