Bazel
Crubit is a Bazel module named rules_crubit. It provides both directions of
bindings:
cpp_api_from_rustgenerates a C++ library from arust_library. Load it from@rules_crubit//bazel:cpp_api_from_rust.bzl.rust_api_from_cppgenerates a Rust library from acc_library. Load it from@rules_crubit//bazel:rust_api_from_cpp.bzl.
The
examples/build_systems/bazel
project is the reference setup. You can see Crubit in action by running:
git clone https://github.com/google/crubit.git
cd crubit/examples/build_systems/bazel
bazelisk run //:main
Set up your module
Add rules_crubit to your MODULE.bazel, together with the Rust and LLVM
toolchains. The example project’s MODULE.bazel shows the exact versions that
Crubit is tested with:
module(
name = "demo_project",
version = "0.0.1",
)
bazel_dep(name = "rules_crubit", version = "0.0.1")
local_path_override(
module_name = "rules_crubit",
path = "../../..",
)
bazel_dep(name = "rules_rust", version = "0.71.3")
bazel_dep(name = "rules_cc", version = "0.2.25")
bazel_dep(name = "toolchains_llvm", version = "1.9.0")
crate = use_extension("@rules_rust//crate_universe:extensions.bzl", "crate")
crate.from_cargo(
name = "crates",
manifests = [
"//:rust_lib/Cargo.toml",
],
)
use_repo(crate, "crates")
crubit_toolchains = use_extension("@rules_crubit//bazel:extensions.bzl", "crubit_toolchains")
crubit_toolchains.configure(
llvm_version = "23.1.0",
rust_version = "nightly/2026-09-29",
)
use_repo(crubit_toolchains, "llvm_toolchain", "rust_toolchains")
register_toolchains(
"@rust_toolchains//:all",
"@llvm_toolchain//:all",
)
The example uses local_path_override because it lives inside the Crubit
repository. In your own project, use git_override instead, and pin a commit
(for example, the one the
latest tag points to):
git_override(
module_name = "rules_crubit",
remote = "https://github.com/google/crubit.git",
commit = "<commit SHA>",
)
crubit_toolchains.configure configures the Rust and LLVM toolchains for the
build. See Toolchain requirements for
the versions that work.
Also copy the example’s
.bazelrc.
It sets the Rust channel and the C++20 and Clang flags that Crubit expects.
C++ bindings for a Rust library
Add a cpp_api_from_rust target for your rust_library, and depend on that
target from C++:
load("@rules_cc//cc:cc_binary.bzl", "cc_binary")
load(
"@rules_crubit//bazel:cpp_api_from_rust.bzl",
"cpp_api_from_rust",
)
load("@rules_rust//rust:rust_library.bzl", "rust_library")
cc_binary(
name = "main",
srcs = ["main.cpp"],
deps = [
":lib_cc_api",
],
)
rust_library(
name = "lib",
srcs = ["rust_lib/src/lib.rs"],
edition = "2024",
deps = [
"@crates//base64",
],
)
cpp_api_from_rust(
name = "lib_cc_api",
crate = ":lib",
)
The header name is the Rust target’s name with .h appended, and the
namespace is the target name:
#include <iostream>
#include <string_view>
#include "lib.h"
#include "support/rs_std/rs_std.h"
int main() {
// Test we can successfully use a type from a Rust dependency.
base64::engine::GeneralPurpose engine = lib::make_engine();
std::cout << "Successfully linked crubit generated C++ api: "
<< lib::add(1, 2) << std::endl;
// Test we can use bindings generated from the Rust standard library.
rs::std::path::PathBuf temp_dir = rs::std::env::temp_dir();
lib::Gymnastics g = lib::Gymnastics::new_(temp_dir);
std::string_view temp_dir_str = g.as_str();
std::cout << "Successfully used Rust std::env::temp_dir(): " << temp_dir_str
<< std::endl;
return 0;
}
See C++ bindings for Rust libraries for what the generated API looks like, and how to customize it.
Rust bindings for a C++ library
Define a rust_api_from_cpp target next to the cc_library, and add its
automatically generated <name>.hint to the cc_library’s aspect_hints:
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_crubit//bazel:rust_api_from_cpp.bzl", "rust_api_from_cpp")
load("@rules_rust//rust:rust_binary.bzl", "rust_binary")
cc_library(
name = "foo",
hdrs = ["foo.h"],
srcs = ["foo.cc"],
aspect_hints = [":foo_rust.hint"],
)
rust_api_from_cpp(
name = "foo_rust",
cpp_target = ":foo",
)
rust_binary(
name = "main",
srcs = ["main.rs"], # use foo_rust::...;
deps = [":foo_rust"],
)
See Rust bindings for C++ libraries for what the generated API looks like, and how to customize it.