Auto merge of #83846 - torhovland:issue-10971, r=davidtwco

Added the --temps-dir option

Fixes #10971.

The new `--temps-dir` option puts intermediate files in a user-specified directory. This provides a fix for the issue where parallel invocations of rustc would overwrite each other's intermediate files.

No files are kept in the intermediate directory unless `-C save-temps=yes`.

If additional files are specifically requested using `--emit asm,llvm-bc,llvm-ir,obj,metadata,link,dep-info,mir`, these will be put in the output directory rather than the intermediate directory.

This is a backward-compatible change, i.e. if `--temps-dir` is not specified, the behavior is the same as before.
This commit is contained in:
bors 2021-11-11 02:52:32 +00:00
commit 9dbbbb12c0
9 changed files with 72 additions and 5 deletions

View File

@ -267,6 +267,7 @@ fn run_compiler(
None,
compiler.output_dir(),
compiler.output_file(),
compiler.temps_dir(),
);
if should_stop == Compilation::Stop {
@ -295,6 +296,7 @@ fn run_compiler(
Some(compiler.input()),
compiler.output_dir(),
compiler.output_file(),
compiler.temps_dir(),
)
.and_then(|| {
RustcDefaultCalls::list_metadata(
@ -647,6 +649,7 @@ fn print_crate_info(
input: Option<&Input>,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
temps_dir: &Option<PathBuf>,
) -> Compilation {
use rustc_session::config::PrintRequest::*;
// PrintRequest::NativeStaticLibs is special - printed during linking
@ -685,7 +688,7 @@ fn print_crate_info(
});
let attrs = attrs.as_ref().unwrap();
let t_outputs = rustc_interface::util::build_output_filenames(
input, odir, ofile, attrs, sess,
input, odir, ofile, temps_dir, attrs, sess,
);
let id = rustc_session::output::find_crate_name(sess, attrs, input);
if *req == PrintRequest::CrateName {

View File

@ -36,6 +36,7 @@ pub struct Compiler {
pub(crate) input_path: Option<PathBuf>,
pub(crate) output_dir: Option<PathBuf>,
pub(crate) output_file: Option<PathBuf>,
pub(crate) temps_dir: Option<PathBuf>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
pub(crate) override_queries:
Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
@ -57,6 +58,9 @@ pub fn output_dir(&self) -> &Option<PathBuf> {
pub fn output_file(&self) -> &Option<PathBuf> {
&self.output_file
}
pub fn temps_dir(&self) -> &Option<PathBuf> {
&self.temps_dir
}
pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
&self.register_lints
}
@ -65,7 +69,14 @@ pub fn build_output_filenames(
sess: &Session,
attrs: &[ast::Attribute],
) -> OutputFilenames {
util::build_output_filenames(&self.input, &self.output_dir, &self.output_file, attrs, sess)
util::build_output_filenames(
&self.input,
&self.output_dir,
&self.output_file,
&self.temps_dir,
attrs,
sess,
)
}
}
@ -186,6 +197,8 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
);
}
let temps_dir = sess.opts.debugging_opts.temps_dir.as_ref().map(|o| PathBuf::from(&o));
let compiler = Compiler {
sess,
codegen_backend,
@ -193,6 +206,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
input_path: config.input_path,
output_dir: config.output_dir,
output_file: config.output_file,
temps_dir,
register_lints: config.register_lints,
override_queries: config.override_queries,
};

View File

@ -692,6 +692,7 @@ pub fn prepare_outputs(
&compiler.input,
&compiler.output_dir,
&compiler.output_file,
&compiler.temps_dir,
&krate.attrs,
sess,
);
@ -722,6 +723,13 @@ pub fn prepare_outputs(
}
}
if let Some(ref dir) = compiler.temps_dir {
if fs::create_dir_all(dir).is_err() {
sess.err("failed to find or create the directory specified by `--temps-dir`");
return Err(ErrorReported);
}
}
write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)

View File

@ -685,6 +685,7 @@ macro_rules! untracked {
untracked!(span_debug, true);
untracked!(span_free_formats, true);
untracked!(strip, Strip::Debuginfo);
untracked!(temps_dir, Some(String::from("abc")));
untracked!(terminal_width, Some(80));
untracked!(threads, 99);
untracked!(time, true);

View File

@ -604,6 +604,7 @@ pub fn build_output_filenames(
input: &Input,
odir: &Option<PathBuf>,
ofile: &Option<PathBuf>,
temps_dir: &Option<PathBuf>,
attrs: &[ast::Attribute],
sess: &Session,
) -> OutputFilenames {
@ -626,6 +627,7 @@ pub fn build_output_filenames(
dirpath,
stem,
None,
temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)
@ -654,6 +656,7 @@ pub fn build_output_filenames(
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
ofile,
temps_dir.clone(),
sess.opts.cg.extra_filename.clone(),
sess.opts.output_types.clone(),
)

View File

@ -578,6 +578,7 @@ pub struct OutputFilenames {
pub out_directory: PathBuf,
filestem: String,
pub single_output_file: Option<PathBuf>,
pub temps_directory: Option<PathBuf>,
pub outputs: OutputTypes,
}
@ -592,12 +593,14 @@ pub fn new(
out_directory: PathBuf,
out_filestem: String,
single_output_file: Option<PathBuf>,
temps_directory: Option<PathBuf>,
extra: String,
outputs: OutputTypes,
) -> Self {
OutputFilenames {
out_directory,
single_output_file,
temps_directory,
outputs,
filestem: format!("{}{}", out_filestem, extra),
}
@ -608,7 +611,14 @@ pub fn path(&self, flavor: OutputType) -> PathBuf {
.get(&flavor)
.and_then(|p| p.to_owned())
.or_else(|| self.single_output_file.clone())
.unwrap_or_else(|| self.temp_path(flavor, None))
.unwrap_or_else(|| self.output_path(flavor))
}
/// Gets the output path where a compilation artifact of the given type
/// should be placed on disk.
pub fn output_path(&self, flavor: OutputType) -> PathBuf {
let extension = flavor.extension();
self.with_directory_and_extension(&self.out_directory, &extension)
}
/// Gets the path where a compilation artifact of the given type for the
@ -643,11 +653,17 @@ pub fn temp_path_ext(&self, ext: &str, codegen_unit_name: Option<&str>) -> PathB
extension.push_str(ext);
}
self.with_extension(&extension)
let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
self.with_directory_and_extension(&temps_directory, &extension)
}
pub fn with_extension(&self, extension: &str) -> PathBuf {
let mut path = self.out_directory.join(&self.filestem);
self.with_directory_and_extension(&self.out_directory, extension)
}
fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
let mut path = directory.join(&self.filestem);
path.set_extension(extension);
path
}

View File

@ -1331,6 +1331,8 @@ mod parse {
"which mangling version to use for symbol names ('legacy' (default) or 'v0')"),
teach: bool = (false, parse_bool, [TRACKED],
"show extended diagnostic help (default: no)"),
temps_dir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"the directory the intermediate files are written to"),
terminal_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current terminal width"),
tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED],

View File

@ -0,0 +1,10 @@
# `temps-dir`
--------------------
The `-Ztemps-dir` compiler flag specifies the directory to write the
intermediate files in. If not set, the output directory is used. This option is
useful if you are running more than one instance of `rustc` (e.g. with different
`--crate-type` settings), and you need to make sure they are not overwriting
each other's intermediate files. No files are kept unless `-C save-temps=yes` is
also set.

View File

@ -0,0 +1,10 @@
-include ../../run-make-fulldeps/tools.mk
# Regression test for issue #10971
# Running two invocations in parallel would overwrite each other's temp files.
all:
touch $(TMPDIR)/lib.rs
$(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \
$(RUSTC) --crate-type=staticlib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs