-
Notifications
You must be signed in to change notification settings - Fork 34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
There's no way to make cargo build
- with no env vars - build redistributable executable
#34
Comments
This came up when discussion packaging and distributing CLI tools, but it might also concern @rust-lang-nursery/cargo |
The impression I get of cargo is that it leaves these kind of policies and practices to the end-user environment to take care which I think I agree with due to this personally feeling like a landmine of issues to try to integrate in. I do think this would be something to consider for cargo-tarball and other packaging tools |
(the following is out of cache for me so could be wrong) Today, one totally can write a build script which is hermetic in a sense that it only touches info explicitly specified in the metadata section of Cargo toml( The problem is that nobody writes such well behaved build scripts. The possible solution here is to write a library, which makes writing well-behaved build scripts easy, and to migrate crates one by one to this new library. I think that this is basically a question of implementation and getting sufficient mind-share of the community to make such library a default standard. However, Cargo has an unstable feature to make this even easier: Metabuild is beasically: “use this package as build.rs”. That Metabuild is supposed to read input from Cargo.toml metadata(not to be confused with Cargo metadata) to make it actually do different things for different crate. So the way forward here is to catch up on meta build discussion and implementing a Metabuild crate which works via metabuild Cargo feature on nightly and via “put fn main() {metabuild::main()} in build.rs” on stable. |
Hm, re-reading this, it seems like metabuild won’t actually help here, because it does not introduce new mechanism for passing info from the top-level project to build scripts of the dependencies. This indeed seems like a missing feature for Cargo! I think adding a key in .cargo/config to override env vars of build scripts could be a welcome solution. Using .cargo/config here because this is what is used to override rustflags. |
I've seen projects include
So I do agree some feature is missing here. There's a need for a project-wide configuration, with variants of the config for each target platform. If you were planning to add custom user profiles (rather than fixed debug/release/bench/test), then it'd be nice to also have them here. I think it'd be OK if it was another section in How about: # have profile config per target, following same pattern as deps
[target.'cfg(windows)'.profile.release]
# map more Rust flags to "native" Cargo profile options
crt = "static" |
and then some way to specify feature flags and other config for dependencies that are several layers deep. Perhaps similarly to the way # select crate to configure
[configuration.crates-io.some_crate]
# enable extra features
features = ["foo", "bar"]
# the rest will be passed as ENV vars to its build script:
key = "value" # sets SOME_CRATE_KEY="value" |
Isn't what you set the variables to dependent on whom you are building for? For example, creating a tarball for distributing vs packaging for distributions? To me, it seems like this would belong in the packaging layer, like cargo-tarball. |
I think it's more complex than that. There are project-specific, target-specific and packaging-specific requirements for dependency configuration and building. They overlap. Ideally, the end result should be more of a negotiation between all of them. As an example, whether a dependency should be dynamic or static is something that almost all
So if you go with opinion of only one of them, something won't work. For example On macOS So in the end I'd probably need to have a way to specify project-specific quirks and exceptions, which then a packaging tool could read, combine with its own policy, and use that to configure dependencies. It would be great if that was part of Cargo, not specific packaging tools, so that if I make my project work with |
To be clear, cargo-tarball is going to cover zip for windows but I get your point. You could have cargo-tarball, cargo-deb, cargo-wix, .... Each will have its own requirements. Some will overlap. Keeping all up to date will be interesting. |
Anything that depends on the global configuration (aka 'environment') of the build machine is inherently broken and will inevitably be incapable of reproducible builds (reproducible here means even timestamps are controlled, such that the resultant binary is byte-for-byte identical). The real solution here is the same as it has been for decades; one ships profile files, one for each build variant, that specify every possible switch and setting that the developer of the binary supports and can vouch for (eg with testing). In practice, though, profile files usually end up being shell scripts because of the mix of configuration and grep-awk-sed required - and that in itself makes an application build difficult to audit. As an additional, such profiles should always be for cross-compilation - even when the target is the same OS and arch as the current machine. Such an approach is hard to do in practice, however, whenever a package depends either on libc or another C library; the C 'build' systems are brittle, broken, fragmented and frankly, crap. All of them. Primarily because they do feature detection (GNU auto-cruft) or use the local C compiler (all of which hard code a billion assumptions and paths, particularly). All are hard to make reproducible (if not impossible). I can say this quite legitimately as the developer of Libertine Linux - an attempt to have a build-from-source-in-git, auditable, reproducible build of Linux. |
Cargo and many sys creates depend on environmental variables for configuration, but there's no standard way to configure default env vars for a project.
Most of this configuration (such as target-cpu, crt-static and whether libraries should be linked statically) is absolutely critical for making high quality redistributable executables.
For example, forgetting about
set RUSTFLAGS="-C target-feature=+crt-static"
on Windows makes executables that don't work without the latest Visual Studio runtime, which is not available on Windows by default. Users get a scary warning about missing DLL, and googling DLL's name finds lots of shady sites trying serve adware/malware.Similarly, forgetting to set all dependencies static on macOS with Homebrew means sys creates will use
pkg-config
, which will hardcode Homebrew-specific paths in the executable, and the executable won't run on other people's computers. "Works only on developers' machines" problem is not easy to spot before getting complaints from users for shipping a broken executable.Env vars are also shared global mutable state, so even if you remember to set them, they make switching between projects harder and more error-prone.
Cargo should use
Cargo.toml
for all configuration, so thatgit clone; cargo build
can be made to do the right thing, instead of having to wrap cargo in another build process and remember to use it every time instead of the usual, simplest — but invalid —cargo build
by mistake.The features mechanism should be extended, or another mechanism added, to correctly support selection of static vs dynamic linking of libraries. (e.g. you use
foo-rs
crate, but want to configurefoo-sys
to use static linking).If "Cargo-native" changes to
Cargo.toml
are undesirable and env vars are here to stay, thenCargo.toml
should at least have a section for specifying env vars for the project, when it's build as the top-level project (i.e. not as a dependency. Dependencies setting global variables would be bad).The text was updated successfully, but these errors were encountered: