Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Write to stdout if - is given as output file #111626

Merged
merged 2 commits into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,7 @@ dependencies = [
name = "rustc_interface"
version = "0.0.0"
dependencies = [
"atty",
"libloading",
"rustc-rayon",
"rustc-rayon-core",
Expand Down Expand Up @@ -4166,6 +4167,7 @@ dependencies = [
name = "rustc_session"
version = "0.0.0"
dependencies = [
"atty",
"getopts",
"libc",
"rustc_ast",
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_codegen_ssa/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ codegen_ssa_archive_build_failure =
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_copy_path = could not copy {$from} to {$to}: {$error}
Expand Down
24 changes: 22 additions & 2 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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())
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
}
}
}

Expand Down Expand Up @@ -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() {
Expand Down
23 changes: 18 additions & 5 deletions compiler/rustc_codegen_ssa/src/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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));
}
}
};

Expand All @@ -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);
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_ssa/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
use rustc_metadata::locator;
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::getopts::{self, Matches};
use rustc_session::lint::{Lint, LintId};
Expand Down Expand Up @@ -437,9 +439,12 @@ fn run_compiler(
}

// 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 ofile = matches.opt_str("o").map(|o| PathBuf::from(&o));
let ofile = matches.opt_str("o").map(|o| match o.as_str() {
"-" => OutFileName::Stdout,
pjhades marked this conversation as resolved.
Show resolved Hide resolved
path => OutFileName::Real(PathBuf::from(path)),
});
(odir, ofile)
}

Expand Down Expand Up @@ -685,7 +690,7 @@ fn print_crate_info(
for &style in &crate_types {
let fname =
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 => {
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_driver_impl/src/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_hir_pretty as pprust_hir;
use rustc_middle::hir::map as hir_map;
use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty};
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_span::symbol::Ident;
use rustc_span::FileName;
Expand Down Expand Up @@ -359,8 +359,8 @@ fn get_source(sess: &Session) -> (String, FileName) {

fn write_or_print(out: &str, sess: &Session) {
match &sess.io.output_file {
None => print!("{out}"),
Some(p) => {
None | Some(OutFileName::Stdout) => print!("{out}"),
Some(OutFileName::Real(p)) => {
if let Err(e) = std::fs::write(p, out) {
sess.emit_fatal(UnprettyDumpFail {
path: p.display().to_string(),
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
[lib]

[dependencies]
atty = "0.2.13"
libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = { version = "0.5.0", optional = true }
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_interface/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface_mixed_proc_macro_crate =
interface_multiple_output_types_adaption =
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 =
failed to find or create the directory specified by `--out-dir`
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_interface/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,7 @@ pub struct IgnoringExtraFilename;
#[derive(Diagnostic)]
#[diag(interface_ignoring_out_dir)]
pub struct IgnoringOutDir;

#[derive(Diagnostic)]
#[diag(interface_multiple_output_types_to_stdout)]
pub struct MultipleOutputTypesToStdout;
4 changes: 2 additions & 2 deletions compiler/rustc_interface/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
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::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
Expand Down Expand Up @@ -252,7 +252,7 @@ pub struct Config {

pub input: Input,
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 locale_resources: &'static [&'static str],

Expand Down
75 changes: 47 additions & 28 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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_plugin_impl as plugin;
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::output::filename_for_input;
use rustc_session::search_paths::PathKind;
Expand Down Expand Up @@ -373,19 +373,23 @@ fn generated_output_paths(
) -> Vec<PathBuf> {
let mut out_filenames = Vec::new();
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 {
// If the filename has been overridden using `-o`, it will not be modified
// by appending `.rlib`, `.exe`, etc., so we can skip this transformation.
OutputType::Exe if !exact_name => {
for crate_type in sess.crate_types().iter() {
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 => {
// 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
pjhades marked this conversation as resolved.
Show resolved Hide resolved
}
_ => {
out_filenames.push(file);
}
Expand Down Expand Up @@ -452,7 +456,8 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
if !sess.opts.output_types.contains_key(&OutputType::DepInfo) {
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 {
// Build a list of files used to compile the output and
Expand Down Expand Up @@ -515,33 +520,47 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
}
}

let mut file = BufWriter::new(fs::File::create(&deps_filename)?);
for path in out_filenames {
writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
}
let write_deps_to_file = |file: &mut dyn Write| -> io::Result<()> {
for path in out_filenames {
writeln!(file, "{}: {}\n", path.display(), files.join(" "))?;
}

// Emit a fake target for each input file to the compilation. This
// prevents `make` from spitting out an error if a file is later
// deleted. For more info see #28735
for path in files {
writeln!(file, "{path}:")?;
}
// Emit a fake target for each input file to the compilation. This
// prevents `make` from spitting out an error if a file is later
// deleted. For more info see #28735
for path in files {
writeln!(file, "{path}:")?;
}

// Emit special comments with information about accessed environment variables.
let env_depinfo = sess.parse_sess.env_depinfo.borrow();
if !env_depinfo.is_empty() {
let mut envs: Vec<_> = env_depinfo
.iter()
.map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
.collect();
envs.sort_unstable();
writeln!(file)?;
for (k, v) in envs {
write!(file, "# env-dep:{k}")?;
if let Some(v) = v {
write!(file, "={v}")?;
}
// Emit special comments with information about accessed environment variables.
let env_depinfo = sess.parse_sess.env_depinfo.borrow();
if !env_depinfo.is_empty() {
let mut envs: Vec<_> = env_depinfo
.iter()
.map(|(k, v)| (escape_dep_env(*k), v.map(escape_dep_env)))
.collect();
envs.sort_unstable();
writeln!(file)?;
for (k, v) in envs {
write!(file, "# env-dep:{k}")?;
if let Some(v) = v {
write!(file, "={v}")?;
}
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)?;
}
}
};
Expand Down
Loading