Setting a base target directory

tl;dr Want to be able to globally configure cargo to build everything on a ram drive; getting tired of typing --target-dir and/or adding wrapper scripts to repos.


I build as much as I can on ram drives to limit wear and tear on my persistent storage. I type --target-dir a lot, to the point where I've started adding build.sh, build.ps1 and run.sh and run.ps1 scripts to most larger projects. But lately I've had to add additional scripts or make them more elaborate because I'm running other cargo commands that depend on the build target directory.

I'm wondering if there' s a way this could be done globally, on a user/machine basis. Say a "WorkBaseDir" was added to $CARGO_HOME/config. This has the obvious problem that it may case collisions for build directories. One idea to solve this could be to use the taget directory $WorkBaseDir/$ProjectName-$UniqueString where $UniqueString expands to a hash of the directory of the source code root directory (or whatever that is deterministic and not very likely to collide).

Is there any way to accomplish this already? If not, is this something anyone else wants?

1 Like

Is the environment variable $env:CARGO_TARGET_DIR what you're looking for?

Not really, unless I'm missing something -- the primary thing I want to accomplish is globally configure cargo to build everything under a specified location (specifically, in my case, on a ram drive), but target-dir does not appear to append a project-specific directory, and using the same target directory for multiple projects will lead to undesirable results.

The CARGO_TARGET_DIR variable, if I'm reading it correctly, does the same thing as --target-dir, so what CARGO_TARGET_DIR saves me is having to type --target-dir when I'm rebuilding a project I just built earlier, but this is essentially no different than what command line history provides me with. But I'm working on several projects I'll need to keep changing CARGO_TARGET_DIR, or add a bunch of scripts to explicitly set the target build directory. This is what I've been doing, and it's gotten to the point where I realize I'm doing a lot of things the tools could be doing for me.

Perhaps I should have been phrased it as: Setting the target build directory isn't the issue -- being able to set it once, and not have to change it when switching projects, is what I want to accomplish.

If CARGO_TARGET_DIR supported recursive expansion and execution of sub-commands it could be used to accomplish what I want, but I doubt it supports that [on all platforms].

Cargo actually works exceedingly well with sharing the target dir between workspaces -- if you're worried about different workspaces trampling on each other, don't be. I've been using a globally set target dir for over a year now and it works seamlessly.

All of the produced artifacts are already tagged (via hash) with the version and feature set of the crate you're compiling.

The one thing I wish for is being able to keep producing the final binary into the local directory rather than my build cache :sweat_smile:

3 Likes

Yeah, I've been using a shared CARGO_TARGET_DIR for quite a while as well, with no issues. Have you (OP) run into issues trying using a shared target dir?

But I'm working on several projects I'll need to keep changing CARGO_TARGET_DIR, or add a bunch of scripts to explicitly set the target build directory. […] being able to set it once , and not have to change it when switching projects, is what I want to accomplish.

You can put the target-dir option in your ~/.cargo/config, à la

[build]
target-dir = "/<...>/target"

Or, if you prefer, the Cargo reference indicates that you can put a .cargo/config anywhere up to the root of your filesystem. For example, if you have a group of repositories who can share a target dir, you can just keep them in the same directory and configure that specific directory.

[…] target-dir does not appear to append a project-specific directory, and using the same target directory for multiple projects will lead to undesirable results.

The first part of this is correct—a target will just contain debug, release, etc., basically teleporting the usual target directory from each of your projects to a common path—but I'm not sure about the assertion that sharing these leads to undesirable results. As has been noted, rustc and cargo use hashing to ensure that build artifacts from different versions can't get mixed. However, certain operations like cargo clean will just delete the entire target directory, which prevents you from cleaning for a specific project.

The final binaries will.clobber each other if one has the same name as another. For newly added projects I run a simple script that creates a .cargo/config file and adds build.target-dir.

It would be nice if there was an option to automatically scope the projects target dir to their own subfolder.

2 Likes

Yeah, the problem is that Cargo has one target dir for both final build products and intermediate temporary files.

  • If you don't point Cargo target dir to a shared temp dir, you get your project directory burdened with temporary files.

  • If you do point Cargo target dir at a shared temp dir, it moves your build products away from your project, where they're harder to access and may be clobbered.

It's a situation that cannot be won, because one dir is used for two different purposes with incompatible requirements.

IMHO CARGO_TARGET_DIR should stay as it is, but Cargo needs to have a new config option like CARGO_TEMP_JUNK_DIR that would be used for build directories of dependencies, cache of incremental compilation, and all the other compiler and cargo internals that users shouldn't touch directly.

6 Likes

I very much like this idea. Although maybe I'd be inclined to bikeshed the name to make it a bit clearer what it does. Looking at the config page I'd amend the [build] section to something like this:

[build]
target-dir = "target"   # path of where to place the final artifacts
cache-dir = "target"    # path of where to place intermediary build artifacts

By default they'd both point to the same directory so as to be consistent with the current behaviour.

Looking at Cargo's code I'm uncertain how easy this would be to implement. There's already some infrastructure to support the unstable --out-dir option but that appears to only copy the files after they're produced which doesn't properly solve this issue.

Edit summary

changed build-cache-dir to simply cache-dir because it makes more sense than build.build_cache_dir

5 Likes