Write to stdout if -
is given as output file
If `-o -` or `--emit KIND=-` is provided, output will be written to stdout instead. Binary output (`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 commit is contained in:
parent
1221e43bdf
commit
9b1a1e1d95
32 changed files with 456 additions and 101 deletions
|
@ -4,6 +4,7 @@ version = "0.0.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
atty = "0.2.13"
|
||||
getopts = "0.2"
|
||||
rustc_macros = { path = "../rustc_macros" }
|
||||
tracing = "0.1"
|
||||
|
|
|
@ -30,6 +30,7 @@ use std::collections::btree_map::{
|
|||
Iter as BTreeMapIter, Keys as BTreeMapKeysIter, Values as BTreeMapValuesIter,
|
||||
};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
use std::ffi::OsStr;
|
||||
use std::fmt;
|
||||
use std::hash::Hash;
|
||||
use std::iter;
|
||||
|
@ -333,7 +334,7 @@ impl OutputType {
|
|||
}
|
||||
}
|
||||
|
||||
fn shorthand(&self) -> &'static str {
|
||||
pub fn shorthand(&self) -> &'static str {
|
||||
match *self {
|
||||
OutputType::Bitcode => "llvm-bc",
|
||||
OutputType::Assembly => "asm",
|
||||
|
@ -386,6 +387,18 @@ impl OutputType {
|
|||
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.
|
||||
|
@ -438,14 +451,14 @@ pub enum ResolveDocLinks {
|
|||
/// 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.
|
||||
#[derive(Clone, Debug, Hash, HashStable_Generic)]
|
||||
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
|
||||
pub struct OutputTypes(BTreeMap<OutputType, Option<OutFileName>>);
|
||||
|
||||
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()))))
|
||||
}
|
||||
|
||||
pub fn get(&self, key: &OutputType) -> Option<&Option<PathBuf>> {
|
||||
pub fn get(&self, key: &OutputType) -> Option<&Option<OutFileName>> {
|
||||
self.0.get(key)
|
||||
}
|
||||
|
||||
|
@ -453,11 +466,15 @@ impl OutputTypes {
|
|||
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()
|
||||
}
|
||||
|
||||
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<PathBuf>> {
|
||||
pub fn values(&self) -> BTreeMapValuesIter<'_, OutputType, Option<OutFileName>> {
|
||||
self.0.values()
|
||||
}
|
||||
|
||||
|
@ -658,11 +675,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)]
|
||||
pub struct OutputFilenames {
|
||||
pub out_directory: PathBuf,
|
||||
filestem: String,
|
||||
pub single_output_file: Option<PathBuf>,
|
||||
pub single_output_file: Option<OutFileName>,
|
||||
pub temps_directory: Option<PathBuf>,
|
||||
pub outputs: OutputTypes,
|
||||
}
|
||||
|
@ -675,7 +752,7 @@ impl OutputFilenames {
|
|||
pub fn new(
|
||||
out_directory: PathBuf,
|
||||
out_filestem: String,
|
||||
single_output_file: Option<PathBuf>,
|
||||
single_output_file: Option<OutFileName>,
|
||||
temps_directory: Option<PathBuf>,
|
||||
extra: String,
|
||||
outputs: OutputTypes,
|
||||
|
@ -689,12 +766,12 @@ impl OutputFilenames {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn path(&self, flavor: OutputType) -> PathBuf {
|
||||
pub fn path(&self, flavor: OutputType) -> OutFileName {
|
||||
self.outputs
|
||||
.get(&flavor)
|
||||
.and_then(|p| p.to_owned())
|
||||
.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
|
||||
|
@ -1821,7 +1898,10 @@ fn parse_output_types(
|
|||
for output_type in list.split(',') {
|
||||
let (shorthand, path) = match output_type.split_once('=') {
|
||||
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(|| {
|
||||
early_error(
|
||||
|
@ -2892,7 +2972,7 @@ pub(crate) mod dep_tracking {
|
|||
use super::{
|
||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
||||
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
||||
OomStrategy, OptLevel, OutFileName, OutputType, OutputTypes, Passes, ResolveDocLinks,
|
||||
SourceFileHashAlgorithm, SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion,
|
||||
TraitSolver, TrimmedDefPaths,
|
||||
};
|
||||
|
@ -2990,6 +3070,7 @@ pub(crate) mod dep_tracking {
|
|||
SourceFileHashAlgorithm,
|
||||
TrimmedDefPaths,
|
||||
Option<LdImpl>,
|
||||
OutFileName,
|
||||
OutputType,
|
||||
RealFileName,
|
||||
LocationDetail,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//! 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::{
|
||||
CrateNameDoesNotMatch, CrateNameEmpty, CrateNameInvalid, FileIsNotWriteable,
|
||||
InvalidCharacterInCrateName,
|
||||
|
@ -8,14 +8,14 @@ use crate::Session;
|
|||
use rustc_ast::{self as ast, attr};
|
||||
use rustc_span::symbol::sym;
|
||||
use rustc_span::{Span, Symbol};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
|
||||
pub fn out_filename(
|
||||
sess: &Session,
|
||||
crate_type: CrateType,
|
||||
outputs: &OutputFilenames,
|
||||
crate_name: Symbol,
|
||||
) -> PathBuf {
|
||||
) -> OutFileName {
|
||||
let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
|
||||
let out_filename = outputs
|
||||
.outputs
|
||||
|
@ -24,7 +24,9 @@ pub fn out_filename(
|
|||
.or_else(|| outputs.single_output_file.clone())
|
||||
.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
|
||||
}
|
||||
|
@ -112,7 +114,7 @@ pub fn filename_for_metadata(
|
|||
sess: &Session,
|
||||
crate_name: Symbol,
|
||||
outputs: &OutputFilenames,
|
||||
) -> PathBuf {
|
||||
) -> OutFileName {
|
||||
// If the command-line specified the path, use that directly.
|
||||
if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) {
|
||||
return out_filename.clone();
|
||||
|
@ -120,12 +122,13 @@ pub fn filename_for_metadata(
|
|||
|
||||
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
||||
|
||||
let out_filename = outputs
|
||||
.single_output_file
|
||||
.clone()
|
||||
.unwrap_or_else(|| outputs.out_directory.join(&format!("lib{libname}.rmeta")));
|
||||
let out_filename = outputs.single_output_file.clone().unwrap_or_else(|| {
|
||||
OutFileName::Real(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
|
||||
}
|
||||
|
@ -135,23 +138,33 @@ pub fn filename_for_input(
|
|||
crate_type: CrateType,
|
||||
crate_name: Symbol,
|
||||
outputs: &OutputFilenames,
|
||||
) -> PathBuf {
|
||||
) -> OutFileName {
|
||||
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
|
||||
|
||||
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 => {
|
||||
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 => {
|
||||
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 => {
|
||||
let suffix = &sess.target.exe_suffix;
|
||||
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;
|
||||
pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo};
|
||||
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::parse::{add_feature_diagnostics, ParseSess};
|
||||
use crate::search_paths::{PathKind, SearchPath};
|
||||
|
@ -135,7 +137,7 @@ pub struct Limits {
|
|||
pub struct CompilerIO {
|
||||
pub input: Input,
|
||||
pub output_dir: Option<PathBuf>,
|
||||
pub output_file: Option<PathBuf>,
|
||||
pub output_file: Option<OutFileName>,
|
||||
pub temps_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue