Skip to content

Commit 2d097c1

Browse files
Rollup merge of rust-lang#83846 - torhovland:issue-10971, r=davidtwco
Added the --temps-dir option Fixes rust-lang#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.
2 parents 8daad74 + 857b19d commit 2d097c1

File tree

10 files changed

+69
-4
lines changed

10 files changed

+69
-4
lines changed

compiler/rustc_driver/src/lib.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,15 @@ fn run_compiler(
216216

217217
let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg"));
218218
let (odir, ofile) = make_output(&matches);
219+
let temps_dir = make_temps_dir(&matches);
219220
let mut config = interface::Config {
220221
opts: sopts,
221222
crate_cfg: cfg,
222223
input: Input::File(PathBuf::new()),
223224
input_path: None,
224225
output_file: ofile,
225226
output_dir: odir,
227+
temps_dir,
226228
file_loader,
227229
diagnostic_output,
228230
stderr: None,
@@ -268,6 +270,7 @@ fn run_compiler(
268270
None,
269271
&compiler.output_dir(),
270272
&compiler.output_file(),
273+
&compiler.temps_dir(),
271274
);
272275

273276
if should_stop == Compilation::Stop {
@@ -296,6 +299,7 @@ fn run_compiler(
296299
Some(compiler.input()),
297300
compiler.output_dir(),
298301
compiler.output_file(),
302+
compiler.temps_dir(),
299303
)
300304
.and_then(|| {
301305
RustcDefaultCalls::list_metadata(
@@ -461,6 +465,11 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<PathBuf>)
461465
(odir, ofile)
462466
}
463467

468+
// Extract temporary directory from matches.
469+
fn make_temps_dir(matches: &getopts::Matches) -> Option<PathBuf> {
470+
matches.opt_str("temps-dir").map(|o| PathBuf::from(&o))
471+
}
472+
464473
// Extract input (string or file and optional path) from matches.
465474
fn make_input(
466475
error_format: ErrorOutputType,
@@ -650,6 +659,7 @@ impl RustcDefaultCalls {
650659
input: Option<&Input>,
651660
odir: &Option<PathBuf>,
652661
ofile: &Option<PathBuf>,
662+
temps_dir: &Option<PathBuf>,
653663
) -> Compilation {
654664
use rustc_session::config::PrintRequest::*;
655665
// PrintRequest::NativeStaticLibs is special - printed during linking
@@ -691,7 +701,7 @@ impl RustcDefaultCalls {
691701
});
692702
let attrs = attrs.as_ref().unwrap();
693703
let t_outputs = rustc_interface::util::build_output_filenames(
694-
input, odir, ofile, attrs, sess,
704+
input, odir, ofile, temps_dir, attrs, sess,
695705
);
696706
let id = rustc_session::output::find_crate_name(sess, attrs, input);
697707
if *req == PrintRequest::CrateName {

compiler/rustc_interface/src/interface.rs

+7
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct Compiler {
3535
pub(crate) input_path: Option<PathBuf>,
3636
pub(crate) output_dir: Option<PathBuf>,
3737
pub(crate) output_file: Option<PathBuf>,
38+
pub(crate) temps_dir: Option<PathBuf>,
3839
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
3940
pub(crate) override_queries:
4041
Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::Providers)>,
@@ -56,6 +57,9 @@ impl Compiler {
5657
pub fn output_file(&self) -> &Option<PathBuf> {
5758
&self.output_file
5859
}
60+
pub fn temps_dir(&self) -> &Option<PathBuf> {
61+
&self.temps_dir
62+
}
5963
pub fn register_lints(&self) -> &Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>> {
6064
&self.register_lints
6165
}
@@ -68,6 +72,7 @@ impl Compiler {
6872
&self.input,
6973
&self.output_dir,
7074
&self.output_file,
75+
&self.temps_dir,
7176
&attrs,
7277
&sess,
7378
)
@@ -134,6 +139,7 @@ pub struct Config {
134139
pub input_path: Option<PathBuf>,
135140
pub output_dir: Option<PathBuf>,
136141
pub output_file: Option<PathBuf>,
142+
pub temps_dir: Option<PathBuf>,
137143
pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>,
138144
pub diagnostic_output: DiagnosticOutput,
139145

@@ -195,6 +201,7 @@ pub fn create_compiler_and_run<R>(config: Config, f: impl FnOnce(&Compiler) -> R
195201
input_path: config.input_path,
196202
output_dir: config.output_dir,
197203
output_file: config.output_file,
204+
temps_dir: config.temps_dir,
198205
register_lints: config.register_lints,
199206
override_queries: config.override_queries,
200207
};

compiler/rustc_interface/src/passes.rs

+8
Original file line numberDiff line numberDiff line change
@@ -709,6 +709,7 @@ pub fn prepare_outputs(
709709
&compiler.input,
710710
&compiler.output_dir,
711711
&compiler.output_file,
712+
&compiler.temps_dir,
712713
&krate.attrs,
713714
sess,
714715
);
@@ -739,6 +740,13 @@ pub fn prepare_outputs(
739740
}
740741
}
741742

743+
if let Some(ref dir) = compiler.temps_dir {
744+
if fs::create_dir_all(dir).is_err() {
745+
sess.err("failed to find or create the directory specified by `--temps-dir`");
746+
return Err(ErrorReported);
747+
}
748+
}
749+
742750
write_out_deps(sess, boxed_resolver, &outputs, &output_paths);
743751

744752
let only_dep_info = sess.opts.output_types.contains_key(&OutputType::DepInfo)

compiler/rustc_interface/src/util.rs

+3
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,7 @@ pub fn build_output_filenames(
636636
input: &Input,
637637
odir: &Option<PathBuf>,
638638
ofile: &Option<PathBuf>,
639+
temps_dir: &Option<PathBuf>,
639640
attrs: &[ast::Attribute],
640641
sess: &Session,
641642
) -> OutputFilenames {
@@ -658,6 +659,7 @@ pub fn build_output_filenames(
658659
dirpath,
659660
stem,
660661
None,
662+
temps_dir.clone(),
661663
sess.opts.cg.extra_filename.clone(),
662664
sess.opts.output_types.clone(),
663665
)
@@ -686,6 +688,7 @@ pub fn build_output_filenames(
686688
out_file.parent().unwrap_or_else(|| Path::new("")).to_path_buf(),
687689
out_file.file_stem().unwrap_or_default().to_str().unwrap().to_string(),
688690
ofile,
691+
temps_dir.clone(),
689692
sess.opts.cg.extra_filename.clone(),
690693
sess.opts.output_types.clone(),
691694
)

compiler/rustc_session/src/config.rs

+20-3
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,7 @@ pub struct OutputFilenames {
563563
pub out_directory: PathBuf,
564564
filestem: String,
565565
pub single_output_file: Option<PathBuf>,
566+
pub temps_directory: Option<PathBuf>,
566567
pub outputs: OutputTypes,
567568
}
568569

@@ -577,12 +578,14 @@ impl OutputFilenames {
577578
out_directory: PathBuf,
578579
out_filestem: String,
579580
single_output_file: Option<PathBuf>,
581+
temps_directory: Option<PathBuf>,
580582
extra: String,
581583
outputs: OutputTypes,
582584
) -> Self {
583585
OutputFilenames {
584586
out_directory,
585587
single_output_file,
588+
temps_directory,
586589
outputs,
587590
filestem: format!("{}{}", out_filestem, extra),
588591
}
@@ -593,7 +596,14 @@ impl OutputFilenames {
593596
.get(&flavor)
594597
.and_then(|p| p.to_owned())
595598
.or_else(|| self.single_output_file.clone())
596-
.unwrap_or_else(|| self.temp_path(flavor, None))
599+
.unwrap_or_else(|| self.output_path(flavor))
600+
}
601+
602+
/// Gets the output path where a compilation artifact of the given type
603+
/// should be placed on disk.
604+
pub fn output_path(&self, flavor: OutputType) -> PathBuf {
605+
let extension = flavor.extension();
606+
self.with_directory_and_extension(&self.out_directory, &extension)
597607
}
598608

599609
/// Gets the path where a compilation artifact of the given type for the
@@ -628,11 +638,17 @@ impl OutputFilenames {
628638
extension.push_str(ext);
629639
}
630640

631-
self.with_extension(&extension)
641+
let temps_directory = self.temps_directory.as_ref().unwrap_or(&self.out_directory);
642+
643+
self.with_directory_and_extension(&temps_directory, &extension)
632644
}
633645

634646
pub fn with_extension(&self, extension: &str) -> PathBuf {
635-
let mut path = self.out_directory.join(&self.filestem);
647+
self.with_directory_and_extension(&self.out_directory, extension)
648+
}
649+
650+
fn with_directory_and_extension(&self, directory: &PathBuf, extension: &str) -> PathBuf {
651+
let mut path = directory.join(&self.filestem);
636652
path.set_extension(extension);
637653
path
638654
}
@@ -1072,6 +1088,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
10721088
in <dir>",
10731089
"DIR",
10741090
),
1091+
opt::opt_s("", "temps-dir", "Write temporary output files to <dir>", "DIR"),
10751092
opt::opt_s(
10761093
"",
10771094
"explain",

src/doc/rustc/src/command-line-arguments.md

+9
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ This flag controls the output filename.
194194
The outputted crate will be written to this directory. This flag is ignored if
195195
the [`-o` flag](#option-o-output) is used.
196196

197+
<a id="option-temps-dir"></a>
198+
## `--temps-dir`: directory to write the intermediate files in
199+
200+
Intermediate files will be written to this directory. If not set, the output
201+
directory is used. This option is useful if you are running more than one
202+
instance of `rustc` (e.g. with different `--crate-type` settings), and you
203+
need to make sure they are not overwriting each other's intermediate files.
204+
No files are kept unless `-C save-temps=yes` is also set.
205+
197206
<a id="option-explain"></a>
198207
## `--explain`: provide a detailed explanation of an error message
199208

src/librustdoc/core.rs

+1
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ crate fn create_config(
259259
input_path: cpath,
260260
output_file: None,
261261
output_dir: None,
262+
temps_dir: None,
262263
file_loader: None,
263264
diagnostic_output: DiagnosticOutput::Default,
264265
stderr: None,

src/librustdoc/doctest.rs

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ crate fn run(options: Options) -> Result<(), ErrorReported> {
9292
input_path: None,
9393
output_file: None,
9494
output_dir: None,
95+
temps_dir: None,
9596
file_loader: None,
9697
diagnostic_output: DiagnosticOutput::Default,
9798
stderr: None,

src/test/run-make-fulldeps/issue-19371/foo.rs

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) {
5353
input_path: None,
5454
output_file: Some(output),
5555
output_dir: None,
56+
temps_dir: None,
5657
file_loader: None,
5758
diagnostic_output: DiagnosticOutput::Default,
5859
stderr: None,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Regression test for issue #10971
2+
# Running two invocations in parallel would overwrite each other's temp files.
3+
4+
all:
5+
touch $(TMPDIR)/lib.rs
6+
7+
$(RUSTC) --crate-type=lib --temps-dir=$(TMPDIR)/temp1 --out-dir=$(TMPDIR) $(TMPDIR)/lib.rs \
8+
& $(RUSTC) --crate-type=cdylib --temps-dir=$(TMPDIR)/temp2 --out-dir=$(TMPDIR) $(TMPDIR)/lib.rs

0 commit comments

Comments
 (0)