Skip to content

Conversation

@madsmtm
Copy link
Contributor

@madsmtm madsmtm commented Dec 23, 2025

Fixes #16427.

What does this PR try to resolve?

Build scripts, procedural macros, the linker and even the compiler itself1 may output temporary files to std::env::temp_dir() during compilation. It is possible to request that programs use a different temporary directory by setting the TMPDIR (Unix) or TMP and TEMP (Windows) environment variables.

This PR makes Cargo set these environment variables to a temporary directory within the target directory.

This is useful when debugging, as it allows more easily inspecting the state the compiler was working with when something went wrong, especially if using -Csave-temps=yes, as relevant files can more easily be found in the project directory instead of being bundled in /tmp with everything else. It also makes it easier to clean up after compilation is finished (cargo clean would remove temporary files as well, instead of the user having to reboot for /tmp to be cleared).

Additionally, this is useful for preventing information leakage: /tmp is global and world readable2, and this means that a different user on the same machine could figure out possibly sensitive details about the project you were building. This is even an issue on macOS where the temporary directory is scoped to the current user (getconf DARWIN_USER_TEMP_DIR), since you'd still be susceptible to Man-in-the-middle attacks by less privileged processes by the same user.

Finally, this makes build scripts and proc-macros more self-contained, which is useful when sandboxing them, such as that which I'm working on in cargo-sandbox.

Implementation notes

When running build scripts, the temporary directory we request is /path/to/target/{debug,release}/build/PKG-HASH/tmp (same as $OUT_DIR/../tmp). For rustc/rustdoc invocations, the directory we request is /path/to/target/tmp (same as $CARGO_TARGET_TMPDIR), see #9814 for breakage introduced in the past by trying to make it /path/to/target/{debug,release}/tmp.

I had a look at the standard library's implementation of std::env::temp_dir, it seems that only Hermit and Motor OS don't respect any environment variable when considering the temporary directory, so the test that I've added should work on all host platforms but those (I'd argue the onus is on those niche platforms to figure out a standard environment variable that they want to use for this, but I can submit bugs upstream if you want me to?)

How to test and review this PR?

  1. Run a build script like:
    fn main() {
        fs::write(std::env::temp_dir().join("foo.txt"), b"Lorem ipsum").unwrap();
    }
    And verify that the file shows up in the project-local folder.
  2. Do something similar in a proc-macro.
  3. Run cargo rustc -- -Csave-temps=yes, and verify that the symbols.o file shows up in the project-local temporary directory.

Footnotes

  1. Cargo has a pretty good understanding of which files the compiler outputs, though it is incomplete in certain areas, especially areas that the compiler doesn't (yet) want to make public, such as the symbols.o trick. Such files are placed in the temporary directory.

  2. Though often only writable by the same user that created the file.

@rustbot rustbot added A-build-execution Area: anything dealing with executing the compiler A-build-scripts Area: build.rs scripts A-layout Area: target output directory layout, naming, and organization S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Dec 23, 2025
@rustbot
Copy link
Collaborator

rustbot commented Dec 23, 2025

r? @ehuss

rustbot has assigned @ehuss.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

When invoking rustc, rustdoc and build scripts, set `TMP` and `TEMP`
(on Windows) or `TMPDIR` (everywhere else) to a project-local temporary
directory.
Comment on lines +392 to +397
/// Returns the directory which build scripts should use for temporary
/// files.
/// `/path/to/target/{debug,release}/build/PKG-HASH/tmp`
pub fn build_script_tmp_dir(&self, unit: &Unit) -> PathBuf {
self.build_script_run_dir(unit).join("tmp")
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option here would be to simply use self.build_script_run_dir(unit) given that people using std::env::temp_dir() already know that they have to generate a unique name for anything they want to write there.

@epage
Copy link
Contributor

epage commented Dec 23, 2025

Note that our contribution process asks that things like this be discussed and approved in issues before starting work on PRs.

@madsmtm
Copy link
Contributor Author

madsmtm commented Dec 23, 2025

Note that our contribution process asks that things like this be discussed and approved in issues before starting work on PRs.

Right, sorry. Do you want me to open an issue so we can discuss it there first?

@epage
Copy link
Contributor

epage commented Dec 23, 2025

Yes.

@madsmtm madsmtm marked this pull request as draft December 23, 2025 12:27
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Dec 23, 2025
@madsmtm
Copy link
Contributor Author

madsmtm commented Dec 23, 2025

I opened #16427, and marked this PR as a draft.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-build-execution Area: anything dealing with executing the compiler A-build-scripts Area: build.rs scripts A-layout Area: target output directory layout, naming, and organization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Set TMPDIR for build scripts and rustc

4 participants