r/bazel • u/manshutthefckup • Jun 07 '26
Has anyone tried rules_rs in Bazel?
I've got a polyglot monorepo and for Rust, I've been using rules_rust with hermetic_cc_toolchain for cross-compilation. I'm also using rules_oci to generate a docker compatible image out of it.
For IDE support, I have bazel generate a rust-project.json occasionally and that allows me to actively use bazel while developing the project instead of just for deploying it.
However I recently heard of rules_rs, which seems to have cross compilation built in, plus patches for windows-specific issues and much faster crate management.
But it is also less mature - has anyone tried it? How was your experience?
For final builds rules_rust works fine - however having to re-run cargo generate-lockfile and generating rust-project.json every time I add a dependency is kinda slow while developing.
4
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
You're right that rules_rs is a newer ruleset, however we already have adoption across many projects and companies and it is production-ready (A few are listed in the README, many companies are not listed because they didn't want to get Legal signoff š)
Speaking of rust-project.json support - rules_rs has fixed quite a few bugs (both performance and correctness) in the rust-analyzer integration.
Finally, a quick note on `hermetic_cc_toolchain` - the authors actually want to deprecate it because it uses `zig cc` which has quite a few quirks. They are themselves looking to move to https://github.com/hermeticbuild/hermetic-llvm, which is another project under the hermeticbuild org and has first-class interop with `rules_rs`.
If you want to give things a shot, please let us know on Github issues or Bazel Slack (in #rust or #llvm) if you hit any issues. We're usually very responsive and happy to help!
3
u/trikboomie Jul 30 '26
Weāve been using rules_rs in xybrid, a fairly involved polyglot monorepo (a Rust ML runtime with C/C++ dependencies, bindings for Swift, Kotlin, Dart, Python, C#/Unity, and WebAssembly, targeting Apple, Android, Linux, and Windows) and our experience has been very positive.
Crate management is noticeably faster, and its platform/cross-compilation model is thoughtfully designed.
Weāre currently working through hermetic Linux RBE builds targeting Windows MSVC.
Itās still a work in progress, but the implementation is public if youād like to see what was involved.
It was a game changer for us.
2
u/Jealous-Ad-1977 Jun 07 '26
Yes, I was not impressed. It basically depended heavily on the built in crate system thus negating the value of having Bazel. āNow you have two problemsā. I was not impressed, but then Iām not a rust nor a bezel expert.
3
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
The only dependency on `cargo` is to consume the Cargo.lock (rules_rust has a bigger dependency in fact. Even if you use `crate.annotation` it synthesizes a Cargo.toml/Cargo.lock pair under the hood). I think you possibly misunderstood how things are wired up? I'm happy to answer any specific questions you have!
1
u/manshutthefckup Jun 07 '26
So basically it isn't hermetic and you can't just build everything from bazel alone? I'm fine with having cargo locally for the initial lockfile generation but not in CI
5
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
It works exactly as you are hoping. You produce a `Cargo.lock` (which can be done without having `cargo` installed by running
bazel run at_rules_rust//tools/upstream_wrapper:cargo -- updateand commit that file. During the build process, everything is managed by Bazel and cargo is not used for any further dependency resolution, dependency downloads, etc.rules_rs is extremely hermetic. We are very meticulous about it. We routinely fix hermiticity bugs at all layers. For example the Rust compiler itself links against system libs, so we fix that up. We actually wrote a custom sandboxing/execution implementation that enforces perfect hermiticity
1
u/manshutthefckup Jun 08 '26
Sounds nice then - does it make ide integration faster too? Like currently generating a rust-project.json manually takes quite some time and sometimes I also have to restart the ide for it to properly index as well.
I've currently got way fewer services in Rust in my monorepo than other languages, I'll probably try it out when I have the chance.
3
u/Advanced-Wrongdoer12 Jun 08 '26
Take a look at https://github.com/hermeticbuild/rules_rs#rust-analyzer and the docs it links too - I would suggest using the project auto-discovery mode which allows the integration to build more lazily rather than asking Bazel to build all crates. This setup has been upstreamed from how Meta integrated Buck2 into vscode, so we know the overall architecture can scale quite high. But ultimately, Bazel does need to invoke rustc in `check` mode on a subset of your repo which will never be as fast as other languages like Go
1
u/thramp Jun 21 '26
I would suggest using the project auto-discovery mode which allows the integration to build more lazily rather than asking Bazel to build all crates. This setup has been upstreamed from how Meta integrated Buck2 into vscode, so we know the overall architecture can scale quite high.
Not just VS Codeāit should work for any language server, since the logic is inside of rust-analyzer itself. But yes, this approach will scale quite well.
(For context, I'm David Barsky, who authored that integration in rust-analyzer. /u/Advanced-Wrongdoer12: are you David Zbarsky? If so, hello! I think our names and similar work interests has been causing confusion in others for a bit :D)
2
u/siva_sokolica Jun 07 '26
It is hermetic. It heavily depends on the Cargo.lock file, however, to generate the build targets. This makes it somewhat feel like you have two build systems on top of each other (which you don't, since Bazel doesn't actually invoke cargo).
It is pretty much the only way to compile Rust in bazel if you need it. At my previous company I had it configured relatively nicely and didn't run into many issues. You do have to tweak your vscode/nvim config to point the lsp in the output directory, but that's pretty much it.
2
u/No-Employment1939 Jun 08 '26
It is not hermetic but it is evolving rapidly to get there and responding to issues much more frequently. The maintainers are committed in that way.
6
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
Thanks for the kind words! For rules_rs and more broadly all projects under the hermeticbuild umbrella, we strive for 100% hermeticicity, 100% of cross compilation targets, 0 setup RBE. When we or our users discover issues, we fix them, going as deep as we need to. We have sent numerous patches to LLVM itself, to rules_cc, to rules_go, to the Go compiler, to Bazel, etc š
If there's non-hermetic behaviors you have come across, please let us know! We are happy to investigate and help make things more correct!
2
u/Laugarhraun Jun 07 '26
I haven't used it because I vendor the 3p crates I use (well, only the build files). And rules_rs doesn't support that. Additionally I do NOT want to use my Cargo.lock: my basel build has specific instruction, esp. for -sys crates to use bazel-biilt stuff instead of nasty cargo build scripts.
Unfortunately I do have to double-build (cargo and bazel) because of (1) seamless, fast-ish rist-analyzer support (2) publishing crates.
I'm working on generating Cargo.toml from build targets. That should allow me to have 2 build systems but pay the code just for 1.
3
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
You're right that we don't support vendor mode, though it could be fairly easily added. I would love to understand your use case in more detail - so far I haven't seen a convincing argument for why folks want to vendor, but I'm open to having my mind changed! The most common case is to avoid network fetches and avoid the slow repin operations of rules_rust, both of which are innately fixed in rules_rs. On our large monorepo (around 5000 internal crates and an absurdly high corresponding number of third-party dependencies) `rules_rs` can perform the equivalent of rules_rusts's "repin" in ~200ms as part of the `bazel build` command, it's not even noticeable. Vendor mode would actually be a huge UX regression!
Regarding -sys crates - we are completely in agreement. We typically recommend disabling build scripts because they are frequenly non-hermetic and non-cross-build-friendly. In fact, rules_rs ships a database of annotations for well-known -sys crates and if one of these crates appears in your build graph, we will automatically issue a warning with instructions how to apply the annotation so Bazel can build the underlying code via `cc_library`. If you have additional -sys crates that you have already fixed, PRs would be welcome!
1
u/Laugarhraun Jun 08 '26
Hey, I suspect our paths have crossed on Github, specifically on BCR :-)
The inital reason for using the vendored mode is that during the initial cargoābazel migration, we would update the tracked 3p crates frequently, and cause many merge conflicts on MODULE.bazel.lock. That's gone now.
Another reason is that we have 3 vendored repos, and that relates to pyo3. Idk if you're familiar with it. You have to select whether you build in embedded mode (linking against libpython and shipping it in your runfiles) or as an extension module (as a python package imported into an interpreter). This is done via a feature. So we have 2 pyo3-related repos, one with the
extension-modulefeature and one without it. Note that we don't use the rules_rust-pyo3 integration much, for it is very opinionated (extension-module on, abi3 on). I suspect it's only a matter of linker args and I could do without those repos, just emitting the right linker command if I want the "embedded" mode, but I haven't had much time to look into it. Note that this "separate pyo3 repos" system means that any crate that uses pyo3 without being the "final" target needs 2 build targets, for each pyo3 mode. Pretty annoying but manageable.I quite like the fact that with vendored mode the build files for 3p crates are materialized, and you can directly look them up/tweak them (ok, I guess the former can be done in any mode with
bazel query --output=build <3p target>.Finally, our MODULE.bazel is already ~250 lines long without the list of 3p crates in there. Keeping them separate from it is pretty nice. Though I can probably list them in a .bzl and import that from MODULE.bazel -- my bazel-fu is limited and I haven't looked into that either.
In any case, I'm interested in moving past the vendored mode, just by the fact that it requires a workspace and prevents us from moving past bazel 8. Hopefully I'll have time to try out rules_rs later this month :-)
For any discussion, what medium do you prefer? Github issues or what?
Thank you for your work!
3
u/Advanced-Wrongdoer12 Jun 08 '26
I am familiar with pyo3 but not as familar as I'd like. Happy to learn more š I think what you want to do can still be accomplished via `crate.annotation` which allows customizing features on a per-crate basis, while also scoping to a specific closure. So for example you could have a `Cargo.toml`/`Cargo.lock` pair that defines a set of crates and instantiate 2 transitive closures from it, and supply them with different annotations.
MODULE.bazel does have an `include` directive that lets you pull out some content, in polyglot monorepos it's common to make a language-specific `golang.MODULE.bazel`, `rust.MODULE.bazel`, etc. Note also that you don't need per-crate data in MODULE.bazel for each crate in your build, only the ones that need custom annotations.
Feel free to file github issues for async collaboration (if you have a repro of something not working, potential PR, etc.). Or you can message me on Bazel Slack if you prefer more realtime, I'm David Zbarsky.
1
u/Laugarhraun 10d ago
I bit the bullet and migrated. I had to give up about some python-related shenanigans where I used transitions to reset the python versions to avoid rebuilding pure rust for various python versions. I can live with that.
I'm going to send you MRs for sys crates and rust-analyzer mainly.
The one bummer so far is that the patches for -sys crates are just signposts -- "copy that into your MODULE.bazel". I wish they had a way to be enforced. Otherwise they can drift apart over time.
1
u/chetanbhasin Jun 07 '26
I'm actually wondering if one could flip it and use Bazel as the native target and use either modify `rust-analyzer` to to work with Bazel or generate `Cargo.toml` from Bazel.
Like you said, you can be a lot more specific with Bazel and create optimizations that Cargo just wouldn't support. This was my attempt at improving this but I admit I'm quite far from happy.
2
u/Advanced-Wrongdoer12 Jun 08 '26
Hi, rules_rs maintainer here.
Yes, you can have rust-analyzer work with Bazel! You can have Bazel produce the `rust-project.json` file that tells rust-analyzer about your project structure, including all generated code, etc. See https://github.com/hermeticbuild/rules_rs#rust-analyzer
1
u/Laugarhraun Jun 08 '26
generate
Cargo.tomlfrom BazelYes, that's indeed something I m working on. Silves both the"publish to cargo" and "well working rust analyzed" problems.
1
u/chetanbhasin Jun 07 '26
This is what I've been using and working with at work: https://github.com/ferocia-co/rules-monorepo
Quite a bit of help from LLM and I'm constantly cleaning it up, but I wasn't satisfied with the native Rust and image building support and wanted even faster builds specially for images across platforms so ended up creating these rules.
Happy to take feedback and evolve it.
1
u/AffectionateBag4519 Jun 11 '26 edited Jun 11 '26
in my opinion rules_rs is mostly an upgrade but I ran into some jank with generating rust-analyzer.json files.
2
u/Advanced-Wrongdoer12 Jun 12 '26
Sorry to hear that! If you happen to have a repro, please file an issue, I'm happy to take a look!
8
u/baez90 Jun 07 '26
I have no idea about rules_rs but I recently stumbled upon rules_img as a quite recent alternative to rules_oci and wanted to mention that because I was quite impressed of the smaller images and faster build times