# Pre-RFC: CARGO\_TARGET\_DIR environment variable

**URL:** <https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034>\
**Category:** cargo\
**Created:** [June 15, 2024, 8:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034 "2024-06-15T20:26:41Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 15, 2024, 8:26pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/1 "2024-06-15T20:26:41Z")

</div>

this is a simple extension to the cargo build script interface to allow build scripts to reliably produce things such as shell completions.

this would be simply set to the value of the variable that `--target-dir` controls (eg. if `cargo build` is run without arguments, it will be `$PWD/target/debug`).

however, to prevent misuse (and namespace collisions), _it will only be set for the top-level binary crate_. this will allow easier integration with external build systems (eg. a Makefile can install the completions generated by a `build.rs` using `clap-complete`, while letting the build script produce the completions in the same place when _not_ being run by a makefile)

this variable will be set when compiling a crate's build script and when compiling the crate itself, but only if that crate:

1. produces a binary `--crate-type=bin`
2. is not somehow itself being built as a dependency of another crate

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 15, 2024, 11:04pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/2 "2024-06-15T23:04:18Z")

</div>

Shouldn’t these kinds of artifacts go to the (unstable) `--out-dir` not the target dir?

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 15, 2024, 11:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/3 "2024-06-15T23:06:35Z")

</div>

well, `OUT_DIR` is already used, and i'm not really sure of the details of how `--out-dir` works, since unstable documentation is a bit hard to find.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 15, 2024, 11:09pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/4 "2024-06-15T23:09:29Z")

</div>

Interesting, it actually got renamed since I last looked at it, a lot of the cargo unstable features are well documented on this page:

[https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dir](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dir)

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 15, 2024, 11:28pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/5 "2024-06-15T23:28:12Z")

</div>

`--artifact-dir` does throw a wrench in things. there's a few possibilites:

1. just make it so files output to `$CARGO_TARGET_DIR` don't get put in `--artifact-dir`
2. make it so these files get put _directly_ into `--artifact-dir` and not `target/debug` (this is awkward since usually `--artifact-dir` results in a _copy_, not a _move_)
3. provide an interface for build scripts to notify cargo of their outputs so they can be moved to `--artifact-dir`

i'm leaning towards implementing #1 and leaving #3 as a future possibility.

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [June 19, 2024, 4:02pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/6 "2024-06-19T16:02:16Z")

</div>

Note that discussion for this is at [Need a reliable way to get the target dir from the build script · Issue #9661 · rust-lang/cargo · GitHub](https://github.com/rust-lang/cargo/issues/9661) and [better support for generation and access of associated files · Issue #13663 · rust-lang/cargo · GitHub](https://github.com/rust-lang/cargo/issues/13663). Summary is at [Need a reliable way to get the target dir from the build script · Issue #9661 · rust-lang/cargo · GitHub](https://github.com/rust-lang/cargo/issues/9661#issuecomment-2159267601)

It helps to limit the scope but that also difficult to define "top-level binary crate". There can be multiple binary targets per package and multiple binaries per workspace.

Overall, I would lean instead towards having a `CARGO_STAGING_DIR` that is given to each build script and we then have rules about how the content of the staging dir gets copied to the `--artifact-dir`. Or maybe there could be a build script directive to register something in `OUT_DIR` to do the same. There are still a lot of details to work out (like collisions).

---

<div class="post-metadata">

**Author:** ![Vorpal](https://avatars.discourse-cdn.com/v4/letter/v/aca169/32.png) [@Vorpal](https://internals.rust-lang.org/u/Vorpal)\
**Post date:** [June 19, 2024, 4:23pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/7 "2024-06-19T16:23:27Z")

</div>

> [@epage](#):
>
> There are still a lot of details to work out (like collisions).

The easy and obvious answer to collisions in this staged approach would be to error.

> [@epage](#):
>
> Overall, I would lean instead towards having a `CARGO_STAGING_DIR` that is given to each build script and we then have rules about how the content of the staging dir gets copied to the `--artifact-dir`.

I assume you mean "copied or reflinked"? Several modern file systems support COW copies these days, and that saves on disk space and SSD wear. Cargo should absolutely take advantage of that when possible.

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [June 19, 2024, 7:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/8 "2024-06-19T19:15:47Z")

</div>

> The easy and obvious answer to collisions in this staged approach would be to error.

That is _an_ answer but its something that would have to be carefully considered.

> I assume you mean "copied or reflinked"? Several modern file systems support COW copies these days, and that saves on disk space and SSD wear. Cargo should absolutely take advantage of that when possible.

We don't make use of reflink yet in Cargo but its something that could be considered.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 21, 2024, 4:57pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/9 "2024-06-21T16:57:48Z")

</div>

> [@epage](#):
>
> It helps to limit the scope but that also difficult to define "top-level binary crate". There can be multiple binary targets per package and multiple binaries per workspace.

whether a crate is "top-level" is not a property of the crate itself, but rather a property of a specific dependency graph being built. basically, if a crate is only being built because it is a dependency of another crate, it is not top-level.

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [June 21, 2024, 5:15pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/10 "2024-06-21T17:15:05Z")

</div>

If you run `cargo build --workspace` with both bins and libs (which people are likely to do out of simplicity), you made all workspace members "top-level", even if they are also dependencies. So the dependency graph doesn't say everything.

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 21, 2024, 5:20pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/11 "2024-06-21T17:20:40Z")

</div>

that's why the additional qualification of needing to be a binary crate is there. i'm not even sure if it's possible to depend on a binary crate (you can depend on a `lib+bin` package, but those are technically two different crates, and you would only depend on the `lib` side, i think)

---

<div class="post-metadata">

**Author:** ![epage](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/epage/32/3171_2.png) [@epage](https://internals.rust-lang.org/u/epage)\
**Post date:** [June 21, 2024, 5:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/12 "2024-06-21T17:29:44Z")

</div>

What about cdylibs?

---

<div class="post-metadata">

**Author:** ![binarycat](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/binarycat/32/12210_2.png) [@binarycat](https://internals.rust-lang.org/u/binarycat)\
**Post date:** [June 21, 2024, 5:32pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/13 "2024-06-21T17:32:50Z")

</div>

I would just put them under a "future possibilities" section for now. I can't say much about them since I've never had to use them.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 21, 2024, 8:05pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/14 "2024-06-21T20:05:53Z")

</div>

I’ve long wondered if it would be possible to retrofit `cdylib` etc. as binary crate types, leaving `[lib]` to only mean `rlib` (and do something with proc-macros). That seems cleaner conceptually as it keeps `[lib]` just for what participates in Cargo’s dependency graph, and `[[bin]]` for final artifacts (and artifact-dependencies).

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 21, 2024, 8:30pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/15 "2024-06-21T20:30:37Z")

</div>

> [@binarycat](#):
>
> i'm not even sure if it's possible to depend on a binary crate

It is with [artifact-dependencies](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#artifact-dependencies). My guess would be that additional artifacts should also be put in the `CARGO_<ARTIFACT-TYPE>_DIR_<DEP>` for them.

I could see these being useful for non-`bin` crate types too (both as artifact-dependencies and top-level builds); generating a `.h` for a `cdylib` for example.

---

<div class="post-metadata">

**Author:** ![bjorn3](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/bjorn3/32/2736_2.png) [@bjorn3](https://internals.rust-lang.org/u/bjorn3)\
**Post date:** [June 21, 2024, 10:37pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/16 "2024-06-21T22:37:24Z")

</div>

> [@Nemo157](#):
>
> I’ve long wondered if it would be possible to retrofit `cdylib` etc. as binary crate types

It is possible for a crate to be compiled as rlib, staticlib and cdylib at the same time. For example because you want it to be usable both from Rust and C. Or you are making an app which has to work on iOS and Android. For iOS you would use the bin crate type, while for Android you would use cdylib. The easiest way to handle that is having a lib target produce both an rlib and cdylib and export the iOS main function to Rust and mark the Android main function as no\_mangle. Then in the bin target you call the main function from the rlib for iOS and directly use the cdylib for Android.

---

<div class="post-metadata">

**Author:** ![Nemo157](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nemo157/32/11585_2.png) [@Nemo157](https://internals.rust-lang.org/u/Nemo157)\
**Post date:** [June 21, 2024, 10:51pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/17 "2024-06-21T22:51:41Z")

</div>

Yes, and I’ve run into issues from crates doing that because they have `#[no_mangle]` functions for the `cdylib` that also then get exported from the `rlib` and cause linker issues when using it as a rust dependency. If you really want to have such a setup you can just have `path = "src/lib.rs"` on a `cdylib` binary target. But in the majority of cases that I’ve seen it makes more sense to have a separate crate defining the public C api on top of the pure rust library.

---

<div class="post-metadata">

**Author:** ![steffahn](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/steffahn/32/13288_2.png) [@steffahn](https://internals.rust-lang.org/u/steffahn)\
**Post date:** [December 13, 2025, 10:52pm UTC](https://internals.rust-lang.org/t/pre-rfc-cargo-target-dir-environment-variable/21034/18 "2025-12-13T22:52:20Z")

</div>

Closed on December 13, 2025, 10:52pm UTC

This topic was automatically closed 540 days after the last reply. New replies are no longer allowed.
