cargo icon indicating copy to clipboard operation
cargo copied to clipboard

Support for cargo wrapper

Open marcbowes opened this issue 4 years ago • 5 comments

Describe the problem you are trying to solve For enterprise integration, it is desirable to control which version of cargo is being run and with what environment. This can be fixed by the user setting up an environment and then running the correct cargo binary. However, there are many touch points to this, including IDE integration and so on.

Here are some things we commonly need to do:

  • set CARGO_HOME in the environment
  • set PATH & LD_LIBRARY_PATH so that cargo can even be executed
  • run a specific version of cargo, which may not be the latest stable

Describe the solution you'd like Gradle has the concept of the wrapper. Cargo already supports build.rustc-wrapper. I think it would be logical to support wrappers for cargo itself. I don't know that we need to support everything Gradle does (such as downloading the right version). To me, it would just need to be something that re-execs cargo. Here's how I imagine it going.

In some .cargo/config, a setting says "here is the cargo-wrapper". When cargo boots, it loads the config as normal and sees that setting. It then execs that wrapper (replaces the current process) with the exact same arguments and environment, modulo something that prevents recursion (either an env var or a CLI flag or something that looks at ARGV[0]). This means that a user that runs cargo foo will actually run $cargo_wrapper foo.

For the case where the user doesn't even have a working copy of cargo in their $PATH, they would be able to run the wrapper directly. It'd be nice, but not necessary, if that didn't immediately re-exec itself.

Notes

I did try to search to see if this was previously discussed but couldn't find anything.

marcbowes avatar Apr 30 '20 22:04 marcbowes

Rustup seems to be what you're looking for: https://github.com/rust-lang/rustup#the-toolchain-file

sfackler avatar Apr 30 '20 23:04 sfackler

Thanks for the link, I wasn't aware of the toolchain file. However, the docs say:

They may not name custom toolchains, nor host-specific toolchains.

I think that's my issue. Conceptually, each package has its own toolchain. A toolchain that has the exact environment required to build that package.

In our build system, we model additional dependencies (than just cargo ones). So for example, C libraries would be made available by the build system and the right env vars would be set. Building a different package might also require that same library, but perhaps a different version of it.

marcbowes avatar Apr 30 '20 23:04 marcbowes

A toolchain that has the exact environment required to build that package.

That's not what "toolchain" means to rustup. That sentence is just saying that the toolchain file specifies the version of Rust only (e.g. "stable" or "1.43.0"), not a specific target architecture (e.g. "1.43.0-x86_64-unknown-linux-musl").

At least in my experience of using the gradle wrapper, the same thing goes there. The wrapper makes sure everyone is using specifically Gradle 6.3 or Gradle 5.6.2 or whatever. The logic of how the project should be built is in the build.gradle/settings.gradle/etc files.

Building a different package might also require that same library, but perhaps a different version of it.

That's typically a decision made by the build script for the Rust crate that provides an interface to the C library. They can typically be configured via environment variables, and also have their logic overridden entirely if necessary.

sfackler avatar May 01 '20 00:05 sfackler

That's not what "toolchain" means to rustup. That sentence is just saying that the toolchain file specifies the version of Rust only (e.g. "stable" or "1.43.0"), not a specific target architecture (e.g. "1.43.0-x86_64-unknown-linux-musl").

Oh yeah, I understand that. I was just trying to apply your suggestion.

That's typically a decision made by the build script for the Rust crate that provides an interface to the C library. They can typically be configured via environment variables, and also have their logic overridden entirely if necessary.

That's not true. The build script is only part of the solution. The other part of the solution is the action users take to setup their environment so that the build script can find what it needs. An example might be yum install openssl-devel. The build script doesn't provide openssl, but has logic to find it and tell the compiler about it.

The build system we have is able to model these dependencies too. What it's not able to do is change the existing build script such that it asks our system where it placed the libs. So the pattern we have is we have a shim that will get our build system to provide openssl and then we'll export the right environment variables such that the build.rs can find it!

Meanwhile, users have IntelliJ or vim or something running and that setup typically just runs vanilla cargo. It doesn't know to run the setup first.

Furthermore, our build system models cargo itself. We don't use rustup for that. Our developers aren't doing rustup install stable. They're saying "do the build", and that is able to provide them with everything they need.

This is all kind of whacky, I get that. We're trying to fit a new build system in with a really old one. So if something I'm saying doesn't make sense please let me know.

marcbowes avatar May 01 '20 03:05 marcbowes

It seems like rustup will take care of running the right toolchain already so the only thing that's missing here is the bootstrap scripts and the tasks to create those.

hakanai avatar Jul 30 '22 06:07 hakanai