Bazelmod documentation and code examples. (#2713)

This PR provides documentation of Bazelmod and several code examples
that addresses a number of issues related to Bazelmod.

Preview of the documentation:
https://github.com/marvin-hansen/rules_rust/blob/main/docs/crate_universe_bzlmod.md

First and foremost it paves the way for a meaningful update the Bazelmod
documentation that references these and existing code examples. This
touches at least the following issues:
* #2670
* #2181


The compile_opt example addresses or resolves:
*  #515
* #2701

The musl_cross_compilling example addresses or resolves
* #390 
* #276

The oci_container does not relate to any open issue, 
although the tokio example in it gives a nice end to end example so 
this definitely helps those looking for something non-trivial.

The proto example addresses or resolves:
*  #2668
*  #302
* #2534
* Possibly a few more if I were to search longer

Formalities
* I've signed the CLA
* I've signed all commits

---------

Signed-off-by: Marvin Hansen <marvin.hansen@gmail.com>
Co-authored-by: Daniel Wagner-Hall <dawagner@gmail.com>
This commit is contained in:
Marvin Hansen 2024-07-12 20:31:00 +08:00 committed by GitHub
parent b3fe74cc97
commit c177ccc1a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
85 changed files with 3267 additions and 83 deletions

View File

@ -668,6 +668,40 @@ tasks:
- "//:nix_cross_compiling"
test_targets:
- "//..."
bzlmod_all_crate_deps:
name: Cargo dependencies with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/all_crate_deps
build_targets:
- "//..."
bzlmod_all_deps_vendor:
name: Vendored dependencies with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/all_deps_vendor
run_targets:
- "//basic/3rdparty:crates_vendor"
build_targets:
- "//..."
bzlmod_compile_opt:
name: Compiler optimization with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/compile_opt
build_targets:
- "//..."
bzlmod_cross_compile:
name: Cross compilation with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/cross_compile
build_targets:
- "//:all"
test_targets:
- "//..."
bzlmod_ffi:
name: FFI with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/ffi
build_targets:
- "//..."
ubuntu2004_bzlmod_bcr:
name: bzlmod BCR presubmit
platform: ubuntu2004
@ -725,6 +759,12 @@ tasks:
- "//..."
test_targets:
- "//..."
bzlmod_proto:
name: Proto and Prost with bzlmod
platform: ubuntu2004
working_directory: examples/bzlmod/proto
build_targets:
- "//..."
compile_one_dependency:
name: --compile_one_dependency flag
platform: ubuntu2004

4
.gitignore vendored
View File

@ -30,6 +30,10 @@ MODULE.bazel.lock
.vscode
*.code-workspace
# JetBrains
.idea
.idea/**
# BazelCI
bazelci.py

View File

@ -0,0 +1 @@
7.2.1

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -1 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -0,0 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1,36 @@
module(
name = "deps_vendored",
version = "0.0.0",
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/bazel-skylib/releases/
bazel_dep(name = "bazel_skylib", version = "1.7.1")
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
###############################################################################
# R U S T C R A T E S
###############################################################################
use_extension("@rules_rust//crate_universe:extension.bzl", "crate")

View File

@ -0,0 +1,178 @@
# Vendored Rust Dependencies
This example shows how to vendor Rust dependencies and use those vendored dependencies in a binary target.
You can run the example vendoring target:
`bazel run //basic/3rdparty:crates_vendor`
And the build target:
`bazel build //...`
## Setup
For the setup,
you need to add the skylib in addition to the rust rules to your MODUE.bazel.
```starlark
module(
name = "deps_vendored",
version = "0.0.0"
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/bazel-skylib/releases/
bazel_dep(name = "bazel_skylib", version = "1.7.1")
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
###############################################################################
# R U S T C R A T E S
###############################################################################
crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
```
Note, it is important to load the crate_universe rules otherwise you will get an error
as the rule set is needed in the vendored target.
Assuming you have a package called `basic` in which you want to vendor dependencies,
then you create a folder `basic/3rdparty`. The folder name can be arbitrary,
but by convention, its either thirdparty or 3rdparty to indicate vendored dependencies.
In the 3rdparty folder, you add a target crates_vendor to declare your dependencies to vendor. In the example, we vendor a specific version of bzip2.
```starlark
load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor")
crates_vendor(
name = "crates_vendor",
annotations = {
"bzip2-sys": [crate.annotation(
gen_build_script = True,
)],
},
cargo_lockfile = "Cargo.Bazel.lock",
generate_build_scripts = False,
mode = "remote",
packages = {
"bzip2": crate.spec(
version = "=0.3.3",
),
},
repository_name = "basic",
tags = ["manual"],
)
```
Next, you have to run `Cargo build` to generate a Cargo.lock file with all resolved dependencies.
Then, you rename Cargo.lock to Cargo.Bazel.lock and place it inside the `basic/3rdparty` folder.
At this point, you have the following folder and files:
```
basic
├── 3rdparty
│ ├── BUILD.bazel
│ ├── Cargo.Bazel.lock
```
Now you can run the `crates_vendor` target:
`bazel run //basic/3rdparty:crates_vendor`
This generates a crate folders with all configurations for the vendored dependencies.
```
basic
├── 3rdparty
│ ├── cratea
│ ├── BUILD.bazel
│ ├── Cargo.Bazel.lock
```
## Usage
Suppose you have an application in `basic/src` that is defined in `basic/BUILD.bazel` and
that depends on a vendored dependency. You find a list of all available vendored dependencies
in the BUILD file of the generated folder: `basic/3rdparty/crates/BUILD.bazel`
You declare a vendored dependency in you target as following:
```starlark
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "hello_sys",
srcs = ["src/main.rs"],
# Note the `crate_unvierse` dependencies here need to have been loaded
# in the WORKSPACE file. See `//:sys_deps.bzl` for more details.
deps = ["//basic/3rdparty/crates:bzip2"],
visibility = ["//visibility:public"],
)
```
Note, the vendored dependency is not yet accessible.
Before you can build, you have to define how to load the vendored dependencies. For that,
you first create a file `sys_deps.bzl` and add the following content:
```starlark
# rename the default name "crate_repositories" in case you import multiple vendored folders.
load("//basic/3rdparty/crates:defs.bzl", basic_crate_repositories = "crate_repositories")
def sys_deps():
"""
This macro loads dependencies for the `basic` crate examples
Commonly `*-sys` crates are built on top of some existing library and
will have a number of dependencies. The examples here use
[crate_universe](https://bazelbuild.github.io/rules_rust/crate_universe.html)
to gather these dependencies and make them available in the workspace.
"""
# Load the vendored dependencies
basic_crate_repositories()
```
This is straightforward, you import the generated crate_repositories from the crates folder,
rename it to avoid name clashes in case you import from multiple vendored folders, and then
just load the vendored dependencies.
In a WORKSPACE configuration, you would just load and call sys_deps(), but in a MODULE configuration, you cannot do that. Instead, you create a new file `WORKSPACE.bzlmod` and add the following content.
```starlark
load("//:sys_deps.bzl", "sys_deps")
sys_deps()
```
Now, you can build the project as usual:
`bazel build //...`
If you ever see an error referring to some cyclical dependencies in a WORKSPACE, it
is caused because you did not load the bazel_skylib at the top of the MODULE.bazel file.
To fix this error, make sure to have the following entry in your MODULE.bazel file:
```starlark
# ...
# https://github.com/bazelbuild/bazel-skylib/releases/
bazel_dep(name = "bazel_skylib", version = "1.7.1")
# ....
```
Your build will complete once skylib loads.

View File

@ -0,0 +1,10 @@
###############################################################################
# Bzlmod and WORKSPACE can work side by side, which allows migrating dependencies
# from the WORKSPACE file to Bzlmod to be a gradual process.
# https://bazel.build/external/migration#hybrid-mode
###############################################################################
# rule http_archive
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("//:sys_deps.bzl", "sys_deps")
sys_deps()

View File

@ -0,0 +1,20 @@
load("@rules_rust//crate_universe:defs.bzl", "crate", "crates_vendor")
crates_vendor(
name = "crates_vendor",
annotations = {
"bzip2-sys": [crate.annotation(
gen_build_script = True,
)],
},
cargo_lockfile = "Cargo.Bazel.lock",
generate_build_scripts = False,
mode = "remote",
packages = {
"bzip2": crate.spec(
version = "=0.3.3",
),
},
repository_name = "basic",
tags = ["manual"],
)

View File

@ -0,0 +1,49 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bzip2"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
dependencies = [
"bzip2-sys",
"libc",
]
[[package]]
name = "bzip2-sys"
version = "0.1.11+1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc"
dependencies = [
"cc",
"libc",
"pkg-config",
]
[[package]]
name = "cc"
version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]]
name = "direct-cargo-bazel-deps"
version = "0.0.1"
dependencies = [
"bzip2",
]
[[package]]
name = "libc"
version = "0.2.137"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
[[package]]
name = "pkg-config"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"

View File

@ -0,0 +1,38 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
package(default_visibility = ["//visibility:public"])
exports_files(
[
"cargo-bazel.json",
"crates.bzl",
"defs.bzl",
] + glob(
include = ["*.bazel"],
allow_empty = True,
),
)
filegroup(
name = "srcs",
srcs = glob(
include = [
"*.bazel",
"*.bzl",
],
allow_empty = True,
),
)
# Workspace Member Dependencies
alias(
name = "bzip2",
actual = "@basic__bzip2-0.3.3//:bzip2",
tags = ["manual"],
)

View File

@ -0,0 +1,85 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "bzip2",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
compile_data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
crate_root = "src/lib.rs",
edition = "2015",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=bzip2",
"manual",
"noclippy",
"norustfmt",
],
target_compatible_with = select({
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
"@rules_rust//rust/platform:aarch64-apple-ios": [],
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
"@rules_rust//rust/platform:aarch64-fuchsia": [],
"@rules_rust//rust/platform:aarch64-linux-android": [],
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:i686-apple-darwin": [],
"@rules_rust//rust/platform:i686-linux-android": [],
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
"@rules_rust//rust/platform:wasm32-wasi": [],
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
"@rules_rust//rust/platform:x86_64-apple-ios": [],
"@rules_rust//rust/platform:x86_64-fuchsia": [],
"@rules_rust//rust/platform:x86_64-linux-android": [],
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-none": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "0.3.3",
deps = [
"@basic__bzip2-sys-0.1.11-1.0.8//:bzip2_sys",
"@basic__libc-0.2.137//:libc",
],
)

View File

@ -0,0 +1,133 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "bzip2_sys",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
compile_data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
crate_root = "lib.rs",
edition = "2015",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=bzip2-sys",
"manual",
"noclippy",
"norustfmt",
],
target_compatible_with = select({
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
"@rules_rust//rust/platform:aarch64-apple-ios": [],
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
"@rules_rust//rust/platform:aarch64-fuchsia": [],
"@rules_rust//rust/platform:aarch64-linux-android": [],
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:i686-apple-darwin": [],
"@rules_rust//rust/platform:i686-linux-android": [],
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
"@rules_rust//rust/platform:wasm32-wasi": [],
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
"@rules_rust//rust/platform:x86_64-apple-ios": [],
"@rules_rust//rust/platform:x86_64-fuchsia": [],
"@rules_rust//rust/platform:x86_64-linux-android": [],
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-none": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "0.1.11+1.0.8",
deps = [
"@basic__bzip2-sys-0.1.11-1.0.8//:build_script_build",
"@basic__libc-0.2.137//:libc",
],
)
cargo_build_script(
name = "_bs",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
crate_name = "build_script_build",
crate_root = "build.rs",
data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
edition = "2015",
links = "bzip2",
pkg_name = "bzip2-sys",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=bzip2-sys",
"manual",
"noclippy",
"norustfmt",
],
version = "0.1.11+1.0.8",
visibility = ["//visibility:private"],
deps = [
"@basic__cc-1.0.77//:cc",
"@basic__pkg-config-0.3.26//:pkg_config",
],
)
alias(
name = "build_script_build",
actual = ":_bs",
tags = ["manual"],
)

View File

@ -0,0 +1,81 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "cc",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
compile_data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
crate_root = "src/lib.rs",
edition = "2018",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=cc",
"manual",
"noclippy",
"norustfmt",
],
target_compatible_with = select({
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
"@rules_rust//rust/platform:aarch64-apple-ios": [],
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
"@rules_rust//rust/platform:aarch64-fuchsia": [],
"@rules_rust//rust/platform:aarch64-linux-android": [],
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:i686-apple-darwin": [],
"@rules_rust//rust/platform:i686-linux-android": [],
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
"@rules_rust//rust/platform:wasm32-wasi": [],
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
"@rules_rust//rust/platform:x86_64-apple-ios": [],
"@rules_rust//rust/platform:x86_64-fuchsia": [],
"@rules_rust//rust/platform:x86_64-linux-android": [],
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-none": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "1.0.77",
)

View File

@ -0,0 +1,85 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "libc",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
compile_data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
crate_features = [
"default",
"std",
],
crate_root = "src/lib.rs",
edition = "2015",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=libc",
"manual",
"noclippy",
"norustfmt",
],
target_compatible_with = select({
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
"@rules_rust//rust/platform:aarch64-apple-ios": [],
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
"@rules_rust//rust/platform:aarch64-fuchsia": [],
"@rules_rust//rust/platform:aarch64-linux-android": [],
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:i686-apple-darwin": [],
"@rules_rust//rust/platform:i686-linux-android": [],
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
"@rules_rust//rust/platform:wasm32-wasi": [],
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
"@rules_rust//rust/platform:x86_64-apple-ios": [],
"@rules_rust//rust/platform:x86_64-fuchsia": [],
"@rules_rust//rust/platform:x86_64-linux-android": [],
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-none": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "0.2.137",
)

View File

@ -0,0 +1,81 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
load("@rules_rust//rust:defs.bzl", "rust_library")
package(default_visibility = ["//visibility:public"])
rust_library(
name = "pkg_config",
srcs = glob(
include = ["**/*.rs"],
allow_empty = False,
),
compile_data = glob(
include = ["**"],
allow_empty = True,
exclude = [
"**/* *",
".tmp_git_root/**/*",
"BUILD",
"BUILD.bazel",
"WORKSPACE",
"WORKSPACE.bazel",
],
),
crate_root = "src/lib.rs",
edition = "2015",
rustc_flags = [
"--cap-lints=allow",
],
tags = [
"cargo-bazel",
"crate-name=pkg-config",
"manual",
"noclippy",
"norustfmt",
],
target_compatible_with = select({
"@rules_rust//rust/platform:aarch64-apple-darwin": [],
"@rules_rust//rust/platform:aarch64-apple-ios": [],
"@rules_rust//rust/platform:aarch64-apple-ios-sim": [],
"@rules_rust//rust/platform:aarch64-fuchsia": [],
"@rules_rust//rust/platform:aarch64-linux-android": [],
"@rules_rust//rust/platform:aarch64-pc-windows-msvc": [],
"@rules_rust//rust/platform:aarch64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:aarch64-unknown-nto-qnx710": [],
"@rules_rust//rust/platform:arm-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:armv7-linux-androideabi": [],
"@rules_rust//rust/platform:armv7-unknown-linux-gnueabi": [],
"@rules_rust//rust/platform:i686-apple-darwin": [],
"@rules_rust//rust/platform:i686-linux-android": [],
"@rules_rust//rust/platform:i686-pc-windows-msvc": [],
"@rules_rust//rust/platform:i686-unknown-freebsd": [],
"@rules_rust//rust/platform:i686-unknown-linux-gnu": [],
"@rules_rust//rust/platform:powerpc-unknown-linux-gnu": [],
"@rules_rust//rust/platform:riscv32imc-unknown-none-elf": [],
"@rules_rust//rust/platform:riscv64gc-unknown-none-elf": [],
"@rules_rust//rust/platform:s390x-unknown-linux-gnu": [],
"@rules_rust//rust/platform:thumbv7em-none-eabi": [],
"@rules_rust//rust/platform:thumbv8m.main-none-eabi": [],
"@rules_rust//rust/platform:wasm32-unknown-unknown": [],
"@rules_rust//rust/platform:wasm32-wasi": [],
"@rules_rust//rust/platform:x86_64-apple-darwin": [],
"@rules_rust//rust/platform:x86_64-apple-ios": [],
"@rules_rust//rust/platform:x86_64-fuchsia": [],
"@rules_rust//rust/platform:x86_64-linux-android": [],
"@rules_rust//rust/platform:x86_64-pc-windows-msvc": [],
"@rules_rust//rust/platform:x86_64-unknown-freebsd": [],
"@rules_rust//rust/platform:x86_64-unknown-linux-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-nixos-gnu": [],
"@rules_rust//rust/platform:x86_64-unknown-none": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
version = "0.3.26",
)

View File

@ -0,0 +1,47 @@
"""Alias that transitions its target to `compilation_mode=opt`. Use `transition_alias="opt"` to enable."""
load("@rules_cc//cc:defs.bzl", "CcInfo")
load("@rules_rust//rust:rust_common.bzl", "COMMON_PROVIDERS")
def _transition_alias_impl(ctx):
# `ctx.attr.actual` is a list of 1 item due to the transition
providers = [ctx.attr.actual[0][provider] for provider in COMMON_PROVIDERS]
if CcInfo in ctx.attr.actual[0]:
providers.append(ctx.attr.actual[0][CcInfo])
return providers
def _change_compilation_mode(compilation_mode):
def _change_compilation_mode_impl(_settings, _attr):
return {
"//command_line_option:compilation_mode": compilation_mode,
}
return transition(
implementation = _change_compilation_mode_impl,
inputs = [],
outputs = [
"//command_line_option:compilation_mode",
],
)
def _transition_alias_rule(compilation_mode):
return rule(
implementation = _transition_alias_impl,
provides = COMMON_PROVIDERS,
attrs = {
"actual": attr.label(
mandatory = True,
doc = "`rust_library()` target to transition to `compilation_mode=opt`.",
providers = COMMON_PROVIDERS,
cfg = _change_compilation_mode(compilation_mode),
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
doc = "Transitions a Rust library crate to the `compilation_mode=opt`.",
)
transition_alias_dbg = _transition_alias_rule("dbg")
transition_alias_fastbuild = _transition_alias_rule("fastbuild")
transition_alias_opt = _transition_alias_rule("opt")

View File

@ -0,0 +1,31 @@
###############################################################################
# @generated
# This file is auto-generated by the cargo-bazel tool.
#
# DO NOT MODIFY: Local changes may be replaced in future executions.
###############################################################################
"""Rules for defining repositories for remote `crates_vendor` repositories"""
# buildifier: disable=bzl-visibility
load("@//basic/3rdparty/crates:defs.bzl", _crate_repositories = "crate_repositories")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
# buildifier: disable=bzl-visibility
load("@rules_rust//crate_universe/private:crates_vendor.bzl", "crates_vendor_remote_repository")
def crate_repositories():
"""Generates repositories for vendored crates.
Returns:
A list of repos visible to the module through the module extension.
"""
maybe(
crates_vendor_remote_repository,
name = "basic",
build_file = Label("@//basic/3rdparty/crates:BUILD.bazel"),
defs_module = Label("@//basic/3rdparty/crates:defs.bzl"),
)
direct_deps = [struct(repo = "basic", is_dev_dep = False)]
direct_deps.extend(_crate_repositories())
return direct_deps

View File

@ -0,0 +1,457 @@
###############################################################################
# @generated
# DO NOT MODIFY: This file is auto-generated by a crate_universe tool. To
# regenerate this file, run the following:
#
# bazel run @@//basic/3rdparty:crates_vendor
###############################################################################
"""
# `crates_repository` API
- [aliases](#aliases)
- [crate_deps](#crate_deps)
- [all_crate_deps](#all_crate_deps)
- [crate_repositories](#crate_repositories)
"""
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
###############################################################################
# MACROS API
###############################################################################
# An identifier that represent common dependencies (unconditional).
_COMMON_CONDITION = ""
def _flatten_dependency_maps(all_dependency_maps):
"""Flatten a list of dependency maps into one dictionary.
Dependency maps have the following structure:
```python
DEPENDENCIES_MAP = {
# The first key in the map is a Bazel package
# name of the workspace this file is defined in.
"workspace_member_package": {
# Not all dependencies are supported for all platforms.
# the condition key is the condition required to be true
# on the host platform.
"condition": {
# An alias to a crate target. # The label of the crate target the
# Aliases are only crate names. # package name refers to.
"package_name": "@full//:label",
}
}
}
```
Args:
all_dependency_maps (list): A list of dicts as described above
Returns:
dict: A dictionary as described above
"""
dependencies = {}
for workspace_deps_map in all_dependency_maps:
for pkg_name, conditional_deps_map in workspace_deps_map.items():
if pkg_name not in dependencies:
non_frozen_map = dict()
for key, values in conditional_deps_map.items():
non_frozen_map.update({key: dict(values.items())})
dependencies.setdefault(pkg_name, non_frozen_map)
continue
for condition, deps_map in conditional_deps_map.items():
# If the condition has not been recorded, do so and continue
if condition not in dependencies[pkg_name]:
dependencies[pkg_name].setdefault(condition, dict(deps_map.items()))
continue
# Alert on any miss-matched dependencies
inconsistent_entries = []
for crate_name, crate_label in deps_map.items():
existing = dependencies[pkg_name][condition].get(crate_name)
if existing and existing != crate_label:
inconsistent_entries.append((crate_name, existing, crate_label))
dependencies[pkg_name][condition].update({crate_name: crate_label})
return dependencies
def crate_deps(deps, package_name = None):
"""Finds the fully qualified label of the requested crates for the package where this macro is called.
Args:
deps (list): The desired list of crate targets.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()`.
Returns:
list: A list of labels to generated rust targets (str)
"""
if not deps:
return []
if package_name == None:
package_name = native.package_name()
# Join both sets of dependencies
dependencies = _flatten_dependency_maps([
_NORMAL_DEPENDENCIES,
_NORMAL_DEV_DEPENDENCIES,
_PROC_MACRO_DEPENDENCIES,
_PROC_MACRO_DEV_DEPENDENCIES,
_BUILD_DEPENDENCIES,
_BUILD_PROC_MACRO_DEPENDENCIES,
]).pop(package_name, {})
# Combine all conditional packages so we can easily index over a flat list
# TODO: Perhaps this should actually return select statements and maintain
# the conditionals of the dependencies
flat_deps = {}
for deps_set in dependencies.values():
for crate_name, crate_label in deps_set.items():
flat_deps.update({crate_name: crate_label})
missing_crates = []
crate_targets = []
for crate_target in deps:
if crate_target not in flat_deps:
missing_crates.append(crate_target)
else:
crate_targets.append(flat_deps[crate_target])
if missing_crates:
fail("Could not find crates `{}` among dependencies of `{}`. Available dependencies were `{}`".format(
missing_crates,
package_name,
dependencies,
))
return crate_targets
def all_crate_deps(
normal = False,
normal_dev = False,
proc_macro = False,
proc_macro_dev = False,
build = False,
build_proc_macro = False,
package_name = None):
"""Finds the fully qualified label of all requested direct crate dependencies \
for the package where this macro is called.
If no parameters are set, all normal dependencies are returned. Setting any one flag will
otherwise impact the contents of the returned list.
Args:
normal (bool, optional): If True, normal dependencies are included in the
output list.
normal_dev (bool, optional): If True, normal dev dependencies will be
included in the output list..
proc_macro (bool, optional): If True, proc_macro dependencies are included
in the output list.
proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are
included in the output list.
build (bool, optional): If True, build dependencies are included
in the output list.
build_proc_macro (bool, optional): If True, build proc_macro dependencies are
included in the output list.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()` when unset.
Returns:
list: A list of labels to generated rust targets (str)
"""
if package_name == None:
package_name = native.package_name()
# Determine the relevant maps to use
all_dependency_maps = []
if normal:
all_dependency_maps.append(_NORMAL_DEPENDENCIES)
if normal_dev:
all_dependency_maps.append(_NORMAL_DEV_DEPENDENCIES)
if proc_macro:
all_dependency_maps.append(_PROC_MACRO_DEPENDENCIES)
if proc_macro_dev:
all_dependency_maps.append(_PROC_MACRO_DEV_DEPENDENCIES)
if build:
all_dependency_maps.append(_BUILD_DEPENDENCIES)
if build_proc_macro:
all_dependency_maps.append(_BUILD_PROC_MACRO_DEPENDENCIES)
# Default to always using normal dependencies
if not all_dependency_maps:
all_dependency_maps.append(_NORMAL_DEPENDENCIES)
dependencies = _flatten_dependency_maps(all_dependency_maps).pop(package_name, None)
if not dependencies:
if dependencies == None:
fail("Tried to get all_crate_deps for package " + package_name + " but that package had no Cargo.toml file")
else:
return []
crate_deps = list(dependencies.pop(_COMMON_CONDITION, {}).values())
for condition, deps in dependencies.items():
crate_deps += selects.with_or({
tuple(_CONDITIONS[condition]): deps.values(),
"//conditions:default": [],
})
return crate_deps
def aliases(
normal = False,
normal_dev = False,
proc_macro = False,
proc_macro_dev = False,
build = False,
build_proc_macro = False,
package_name = None):
"""Produces a map of Crate alias names to their original label
If no dependency kinds are specified, `normal` and `proc_macro` are used by default.
Setting any one flag will otherwise determine the contents of the returned dict.
Args:
normal (bool, optional): If True, normal dependencies are included in the
output list.
normal_dev (bool, optional): If True, normal dev dependencies will be
included in the output list..
proc_macro (bool, optional): If True, proc_macro dependencies are included
in the output list.
proc_macro_dev (bool, optional): If True, dev proc_macro dependencies are
included in the output list.
build (bool, optional): If True, build dependencies are included
in the output list.
build_proc_macro (bool, optional): If True, build proc_macro dependencies are
included in the output list.
package_name (str, optional): The package name of the set of dependencies to look up.
Defaults to `native.package_name()` when unset.
Returns:
dict: The aliases of all associated packages
"""
if package_name == None:
package_name = native.package_name()
# Determine the relevant maps to use
all_aliases_maps = []
if normal:
all_aliases_maps.append(_NORMAL_ALIASES)
if normal_dev:
all_aliases_maps.append(_NORMAL_DEV_ALIASES)
if proc_macro:
all_aliases_maps.append(_PROC_MACRO_ALIASES)
if proc_macro_dev:
all_aliases_maps.append(_PROC_MACRO_DEV_ALIASES)
if build:
all_aliases_maps.append(_BUILD_ALIASES)
if build_proc_macro:
all_aliases_maps.append(_BUILD_PROC_MACRO_ALIASES)
# Default to always using normal aliases
if not all_aliases_maps:
all_aliases_maps.append(_NORMAL_ALIASES)
all_aliases_maps.append(_PROC_MACRO_ALIASES)
aliases = _flatten_dependency_maps(all_aliases_maps).pop(package_name, None)
if not aliases:
return dict()
common_items = aliases.pop(_COMMON_CONDITION, {}).items()
# If there are only common items in the dictionary, immediately return them
if not len(aliases.keys()) == 1:
return dict(common_items)
# Build a single select statement where each conditional has accounted for the
# common set of aliases.
crate_aliases = {"//conditions:default": dict(common_items)}
for condition, deps in aliases.items():
condition_triples = _CONDITIONS[condition]
for triple in condition_triples:
if triple in crate_aliases:
crate_aliases[triple].update(deps)
else:
crate_aliases.update({triple: dict(deps.items() + common_items)})
return select(crate_aliases)
###############################################################################
# WORKSPACE MEMBER DEPS AND ALIASES
###############################################################################
_NORMAL_DEPENDENCIES = {
"": {
_COMMON_CONDITION: {
"bzip2": Label("@basic__bzip2-0.3.3//:bzip2"),
},
},
}
_NORMAL_ALIASES = {
"": {
_COMMON_CONDITION: {
},
},
}
_NORMAL_DEV_DEPENDENCIES = {
"": {
},
}
_NORMAL_DEV_ALIASES = {
"": {
},
}
_PROC_MACRO_DEPENDENCIES = {
"": {
},
}
_PROC_MACRO_ALIASES = {
"": {
},
}
_PROC_MACRO_DEV_DEPENDENCIES = {
"": {
},
}
_PROC_MACRO_DEV_ALIASES = {
"": {
},
}
_BUILD_DEPENDENCIES = {
"": {
},
}
_BUILD_ALIASES = {
"": {
},
}
_BUILD_PROC_MACRO_DEPENDENCIES = {
"": {
},
}
_BUILD_PROC_MACRO_ALIASES = {
"": {
},
}
_CONDITIONS = {
"aarch64-apple-darwin": ["@rules_rust//rust/platform:aarch64-apple-darwin"],
"aarch64-apple-ios": ["@rules_rust//rust/platform:aarch64-apple-ios"],
"aarch64-apple-ios-sim": ["@rules_rust//rust/platform:aarch64-apple-ios-sim"],
"aarch64-fuchsia": ["@rules_rust//rust/platform:aarch64-fuchsia"],
"aarch64-linux-android": ["@rules_rust//rust/platform:aarch64-linux-android"],
"aarch64-pc-windows-msvc": ["@rules_rust//rust/platform:aarch64-pc-windows-msvc"],
"aarch64-unknown-linux-gnu": ["@rules_rust//rust/platform:aarch64-unknown-linux-gnu"],
"aarch64-unknown-nixos-gnu": ["@rules_rust//rust/platform:aarch64-unknown-nixos-gnu"],
"aarch64-unknown-nto-qnx710": ["@rules_rust//rust/platform:aarch64-unknown-nto-qnx710"],
"arm-unknown-linux-gnueabi": ["@rules_rust//rust/platform:arm-unknown-linux-gnueabi"],
"armv7-linux-androideabi": ["@rules_rust//rust/platform:armv7-linux-androideabi"],
"armv7-unknown-linux-gnueabi": ["@rules_rust//rust/platform:armv7-unknown-linux-gnueabi"],
"i686-apple-darwin": ["@rules_rust//rust/platform:i686-apple-darwin"],
"i686-linux-android": ["@rules_rust//rust/platform:i686-linux-android"],
"i686-pc-windows-msvc": ["@rules_rust//rust/platform:i686-pc-windows-msvc"],
"i686-unknown-freebsd": ["@rules_rust//rust/platform:i686-unknown-freebsd"],
"i686-unknown-linux-gnu": ["@rules_rust//rust/platform:i686-unknown-linux-gnu"],
"powerpc-unknown-linux-gnu": ["@rules_rust//rust/platform:powerpc-unknown-linux-gnu"],
"riscv32imc-unknown-none-elf": ["@rules_rust//rust/platform:riscv32imc-unknown-none-elf"],
"riscv64gc-unknown-none-elf": ["@rules_rust//rust/platform:riscv64gc-unknown-none-elf"],
"s390x-unknown-linux-gnu": ["@rules_rust//rust/platform:s390x-unknown-linux-gnu"],
"thumbv7em-none-eabi": ["@rules_rust//rust/platform:thumbv7em-none-eabi"],
"thumbv8m.main-none-eabi": ["@rules_rust//rust/platform:thumbv8m.main-none-eabi"],
"wasm32-unknown-unknown": ["@rules_rust//rust/platform:wasm32-unknown-unknown"],
"wasm32-wasi": ["@rules_rust//rust/platform:wasm32-wasi"],
"x86_64-apple-darwin": ["@rules_rust//rust/platform:x86_64-apple-darwin"],
"x86_64-apple-ios": ["@rules_rust//rust/platform:x86_64-apple-ios"],
"x86_64-fuchsia": ["@rules_rust//rust/platform:x86_64-fuchsia"],
"x86_64-linux-android": ["@rules_rust//rust/platform:x86_64-linux-android"],
"x86_64-pc-windows-msvc": ["@rules_rust//rust/platform:x86_64-pc-windows-msvc"],
"x86_64-unknown-freebsd": ["@rules_rust//rust/platform:x86_64-unknown-freebsd"],
"x86_64-unknown-linux-gnu": ["@rules_rust//rust/platform:x86_64-unknown-linux-gnu"],
"x86_64-unknown-nixos-gnu": ["@rules_rust//rust/platform:x86_64-unknown-nixos-gnu"],
"x86_64-unknown-none": ["@rules_rust//rust/platform:x86_64-unknown-none"],
}
###############################################################################
def crate_repositories():
"""A macro for defining repositories for all generated crates.
Returns:
A list of repos visible to the module through the module extension.
"""
maybe(
http_archive,
name = "basic__bzip2-0.3.3",
sha256 = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b",
type = "tar.gz",
urls = ["https://static.crates.io/crates/bzip2/0.3.3/download"],
strip_prefix = "bzip2-0.3.3",
build_file = Label("@//basic/3rdparty/crates:BUILD.bzip2-0.3.3.bazel"),
)
maybe(
http_archive,
name = "basic__bzip2-sys-0.1.11-1.0.8",
sha256 = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc",
type = "tar.gz",
urls = ["https://static.crates.io/crates/bzip2-sys/0.1.11+1.0.8/download"],
strip_prefix = "bzip2-sys-0.1.11+1.0.8",
build_file = Label("@//basic/3rdparty/crates:BUILD.bzip2-sys-0.1.11+1.0.8.bazel"),
)
maybe(
http_archive,
name = "basic__cc-1.0.77",
sha256 = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4",
type = "tar.gz",
urls = ["https://static.crates.io/crates/cc/1.0.77/download"],
strip_prefix = "cc-1.0.77",
build_file = Label("@//basic/3rdparty/crates:BUILD.cc-1.0.77.bazel"),
)
maybe(
http_archive,
name = "basic__libc-0.2.137",
sha256 = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89",
type = "tar.gz",
urls = ["https://static.crates.io/crates/libc/0.2.137/download"],
strip_prefix = "libc-0.2.137",
build_file = Label("@//basic/3rdparty/crates:BUILD.libc-0.2.137.bazel"),
)
maybe(
http_archive,
name = "basic__pkg-config-0.3.26",
sha256 = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160",
type = "tar.gz",
urls = ["https://static.crates.io/crates/pkg-config/0.3.26/download"],
strip_prefix = "pkg-config-0.3.26",
build_file = Label("@//basic/3rdparty/crates:BUILD.pkg-config-0.3.26.bazel"),
)
return [
struct(repo = "basic__bzip2-0.3.3", is_dev_dep = False),
]

View File

@ -0,0 +1,10 @@
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "hello_sys",
srcs = ["src/main.rs"],
visibility = ["//visibility:public"],
# Note the `crate_unvierse` dependencies here need to have been loaded
# in the WORKSPACE file. See `//:sys_deps.bzl` for more details.
deps = ["//basic/3rdparty/crates:bzip2"],
)

View File

@ -0,0 +1,57 @@
// Copyright 2024 The Bazel examples and tutorials Authors & Contributors. // All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use bzip2::read::BzEncoder;
use bzip2::Compression;
use std::io::Read;
fn main() {
let stdin = std::io::stdin();
let stdin = stdin.lock();
let mut raw_counter = CountingStream::new(stdin);
let compressed_count = {
let compressor = BzEncoder::new(&mut raw_counter, Compression::Best);
let mut compressed_counter = CountingStream::new(compressor);
std::io::copy(&mut compressed_counter, &mut std::io::sink()).unwrap();
compressed_counter.count
};
println!(
"Compressed {} to {} bytes",
raw_counter.count, compressed_count
);
}
struct CountingStream<R: Read> {
stream: R,
count: usize,
}
impl<R: Read> CountingStream<R> {
fn new(stream: R) -> Self {
CountingStream { stream, count: 0 }
}
}
impl<R: Read> Read for CountingStream<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
let result = self.stream.read(buf);
if let Ok(read_bytes) = result {
self.count += read_bytes;
}
result
}
}

View File

@ -0,0 +1,17 @@
"""This module loads dependencies for the `basic` crate examples"""
# rename the default name "crate_repositories" in case you import multiple vendored folders.
load("//basic/3rdparty/crates:defs.bzl", basic_crate_repositories = "crate_repositories")
def sys_deps():
"""
This macro loads dependencies for the `basic` crate examples
Commonly `*-sys` crates are built on top of some existing library and
will have a number of dependencies. The examples here use
[crate_universe](https://bazelbuild.github.io/rules_rust/crate_universe.html)
to gather these dependencies and make them available in the workspace.
"""
# Load the vendored dependencies
basic_crate_repositories()

View File

@ -1,4 +1,7 @@
build --experimental_enable_bzlmod
# Required on windows
common --enable_platform_specific_config
startup --windows_enable_symlinks
build:windows --enable_runfiles
# This isn't currently the defaut in Bazel, but we enable it to test we'll be ready if/when it flips.
build --incompatible_disallow_empty_glob

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -0,0 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1,6 @@
config_setting(
name = "release",
values = {
"compilation_mode": "opt",
},
)

View File

@ -0,0 +1,28 @@
module(
name = "comp_opt",
version = "0.0.0",
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")

View File

@ -0,0 +1,51 @@
# Hello World with compiler optimization
Each binary target can have its own compiler options, and these can be customised differently for different optimisation levels.
This takes three steps:
1) In your root folder BUILD.bazel, add the following entry:
```Starlark
config_setting(
name = "release",
values = {
"compilation_mode": "opt",
},
)
```
2) In your binary target, add the optimization flags & strip settings prefixed with -C.
For a complete list of Rust compiler optimization flag, please read the
[official cargo documentation](https://doc.rust-lang.org/cargo/reference/profiles.html).
```Starlark
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "bin",
srcs = ["src/main.rs"],
deps = [],
rustc_flags = select({
"//:release": [
"-Clto=true",
"-Ccodegen-units=1",
"-Cpanic=abort",
"-Copt-level=3",
"-Cstrip=symbols",
],
"//conditions:default":
[
"-Copt-level=0",
],
}),
visibility = ["//visibility:public"],
)
```
Build with optimization:
`bazel build -c opt //...`
And run the optimized binary:
`bazel run -c opt //...`

View File

@ -0,0 +1,20 @@
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "bin",
srcs = ["src/main.rs"],
rustc_flags = select({
"//:release": [
"-Clto",
"-Ccodegen-units=1",
"-Cpanic=abort",
"-Copt-level=3",
"-Cstrip=symbols",
],
"//conditions:default": [
"-Copt-level=0",
],
}),
visibility = ["//visibility:public"],
deps = [],
)

View File

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -1 +1,2 @@
/bazel-*
.DS_Store

View File

@ -2,53 +2,79 @@ load("@rules_rust//rust:defs.bzl", "rust_binary")
package(default_visibility = ["//visibility:public"])
filegroup(
name = "all",
srcs = [
":hello_world_aarch64",
":hello_world_host",
":hello_world_x86_64",
],
)
rust_binary(
name = "hello_world_aarch64",
name = "hello_world_host",
srcs = ["src/main.rs"],
platform = ":linux-aarch64",
deps = [],
)
rust_binary(
name = "hello_world_x86_64",
srcs = ["src/main.rs"],
platform = ":linux-x86_64",
platform = "//build/platforms:linux-x86_64",
deps = [],
)
[
sh_test(
name = "hello_world_{}_test".format(target),
srcs = ["hello_world_test.sh"],
args = [
"$(rlocationpath :hello_world_{})".format(target),
arch_string,
],
data = [
":hello_world_{}".format(target),
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)
for (target, arch_string) in [
("aarch64", "AArch64"),
("x86_64", "X86-64"),
]
]
rust_binary(
name = "hello_world_aarch64",
srcs = ["src/main.rs"],
platform = "//build/platforms:linux-aarch64",
deps = [],
)
platform(
name = "linux-aarch64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
# Test if the host binary works.
# Note, we cannot test for platform since Bazel determines the host platform automatically
sh_test(
name = "test_hello_world_host",
srcs = ["test_hello_world.sh"],
args = [
"$(rlocationpath :hello_world_host)",
],
data = [
":hello_world_host",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)
platform(
name = "linux-x86_64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
# Test the for x86_64 architecture
sh_test(
name = "test_linux_x86_64",
srcs = ["test_platform.sh"],
args = [
"$(rootpath :hello_world_x86_64)",
"x86_64",
],
data = [
":hello_world_x86_64",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)
# Test for ARM architecture
sh_test(
name = "test_linux_arm64",
srcs = ["test_platform.sh"],
args = [
"$(rootpath :hello_world_aarch64)",
"aarch64",
],
data = [
":hello_world_aarch64",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)

View File

@ -0,0 +1,29 @@
### LLVM Troubleshooting
On older linux distributions (Ubuntu 16.04) you may encounter an error that C++ versions before C++ 14 are no longer
supported. In this case, just install gcc version 7 or newer. This is rare corner case, but there are gcc backports for
older distributions, so please upgrade your compiler if you ever see this error.
On Ubuntu 20.04 you may see an error that a shared library called libtinfo.so.5 is missing. In that case, just install
libtinfo via apt-get since its in the official 20.04 repo. To so, open a terminal and type:
`
apt update && apt install -y libtinfo5
`
The libtinfo5 library may have different package names on other distributions, but it is a well known
issue. [See this SO discussion](https://stackoverflow.com/questions/48674104/clang-error-while-loading-shared-libraries-libtinfo-so-5-cannot-open-shared-o)
for various solutions.
On MacOX, it is sufficient to have the Apple Clang compiler installed.
I don't recommend installing the full Xcode package unless you're developing software for an Apple device. Instead, the
Xcode Command Line Tools provide everything you need at a much smaller download size. In most cases, a simple:
`xcode-select --install`
From a terminal triggers the installation process. For details and alternative
options, [read this article on freebootcamp.](https://www.freecodecamp.org/news/install-xcode-command-line-tools/)
Windows is not directly supported, but you can use Linux on Windows with WSL to setup an Ubuntu environment within
Windows. Please refer to
the [official WSL documentation for details.](https://learn.microsoft.com/en-us/windows/wsl/install)

View File

@ -1,38 +1,110 @@
"""bazelbuild/rules_rust - bzlmod cross-compilation example"""
module(
name = "cross_compile_example",
name = "hello_cross",
version = "0.0.0",
)
bazel_dep(name = "bazel_skylib", version = "1.5.0")
bazel_dep(name = "platforms", version = "0.0.8")
bazel_dep(name = "toolchains_llvm", version = "0.10.3")
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
# rules_rust still needs a cpp toolchain, so provide a cross-compiling one here
# Rules for cross compilation
bazel_dep(name = "toolchains_musl", version = "0.1.16", dev_dependency = True)
# https://github.com/bazelbuild/platforms/releases
bazel_dep(name = "platforms", version = "0.0.10")
# https://github.com/bazel-contrib/toolchains_llvm
bazel_dep(name = "toolchains_llvm", version = "1.0.0")
# https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/repo/http.bzl
http_archive = use_repo_rule("@bazel_tools//:http.bzl", "http_archive")
# Both, cross compilation and MUSL still need a C/C++ toolchain with sysroot.
_BUILD_FILE_CONTENT = """
filegroup(
name = "{name}",
srcs = glob(["*/**"]),
visibility = ["//visibility:public"],
)
"""
# Download sysroot
# https://commondatastorage.googleapis.com/chrome-linux-sysroot/
http_archive(
name = "org_chromium_sysroot_linux_x64",
build_file_content = _BUILD_FILE_CONTENT.format(name = "sysroot"),
sha256 = "f6b758d880a6df264e2581788741623320d548508f07ffc2ae6a29d0c13d647d",
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/2e7ada854015a4cc60fc812112d261af44213ed0/debian_bullseye_amd64_sysroot.tar.xz"],
)
http_archive(
name = "org_chromium_sysroot_linux_aarch64",
build_file_content = _BUILD_FILE_CONTENT.format(name = "sysroot"),
sha256 = "902d1a40a5fd8c3764a36c8d377af5945a92e3d264c6252855bda4d7ef81d3df",
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/41a6c8dec4c4304d6509e30cbaf9218dffb4438e/debian_bullseye_arm64_sysroot.tar.xz"],
)
# LLVM setup
# https://github.com/bazel-contrib/toolchains_llvm/tree/0d302de75f6ace071ac616fb274481eedcc20e5a?tab=readme-ov-file#sysroots
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
# LLVM Versions and platforms
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/toolchain/internal/llvm_distributions.bzl
LLVM_VERSIONS = {
"": "16.0.0",
"darwin-aarch64": "16.0.3",
"darwin-x86_64": "15.0.7",
}
# Host LLVM toolchain.
llvm.toolchain(
name = "llvm_toolchain",
llvm_version = "16.0.0",
sysroot = {"linux-aarch64": "@@org_chromium_sysroot_linux_aarch64//:sysroot"},
llvm_versions = LLVM_VERSIONS,
)
use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm")
# X86 LLVM Toolchain with sysroot.
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/WORKSPACE.bzlmod
llvm.toolchain(
name = "llvm_toolchain_x86_with_sysroot",
llvm_versions = LLVM_VERSIONS,
)
llvm.sysroot(
name = "llvm_toolchain_x86_with_sysroot",
label = "@org_chromium_sysroot_linux_x64//:sysroot",
targets = ["linux-x86_64"],
)
use_repo(llvm, "llvm_toolchain_x86_with_sysroot")
#
# ARM (aarch64) LLVM Toolchain with sysroot.
# https://github.com/bazelbuild/rules_rust/blob/main/examples/bzlmod/cross_compile/WORKSPACE.bzlmod
llvm.toolchain(
name = "llvm_toolchain_aarch64_with_sysroot",
llvm_versions = LLVM_VERSIONS,
)
llvm.sysroot(
name = "llvm_toolchain_aarch64_with_sysroot",
label = "@org_chromium_sysroot_linux_aarch64//:sysroot",
targets = ["linux-aarch64"],
)
use_repo(llvm, "llvm_toolchain_aarch64_with_sysroot")
# Register all LLVM toolchains
register_toolchains("@llvm_toolchain//:all")
bazel_dep(name = "rules_rust", version = "0.0.0")
local_path_override(
module_name = "rules_rust",
path = "../../..",
)
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = "2021",
edition = RUST_EDITION,
extra_target_triples = [
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
],
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")

View File

@ -1,6 +1,288 @@
# bzlmod cross-compile example
# Cross Compilation
This example shows how to use `rules_rust` through bzlmod to invoke Rust cross-compilation.
For cross compilation, you have to specify a custom platform to let Bazel know that you are compiling for a different platform than the default host platform.
It should be possible to `bazel build //:hello_world_aarch64` and `bazel build //:hello_world_x86_64` regardless of your
host platform (as long as it is supported by Bazel and rustc).
The example code is setup to cross compile from the following hosts to the the following targets:
* {linux, x86_64} -> {linux, aarch64}
* {darwin, x86_64} -> {linux, x86_64}
* {darwin, x86_64} -> {linux, aarch64}
* {darwin, aarch64 (Apple Silicon)} -> {linux, x86_64}
* {darwin, aarch64 (Apple Silicon)} -> {linux, aarch64}
You cross-compile by calling the target.
`bazel build //:hello_world_x86_64`
or
`bazel build //:hello_world_aarch64`
You can also build all targets at once:
`bazel build //...`
And you can run all test with:
`bazel test //...`
## Setup
The setup requires three steps, first declare dependencies and toolchains in your MODULE.bazel, second configure LLVM and Rust for cross compilation, and third the configuration of the cross compilation platforms so you can use it binary targets.
### Dependencies Configuration
You add the required rules for cross compilation to your MODULE.bazel as shown below.
```Starlark
# Rules for cross compilation
# https://github.com/bazelbuild/platforms/releases
bazel_dep(name = "platforms", version = "0.0.10")
# https://github.com/bazel-contrib/toolchains_llvm
bazel_dep(name = "toolchains_llvm", version = "1.0.0")
```
## LLVM Configuration
Next, you have to configure the LLVM toolchain because rules_rust still needs a cpp toolchain for cross compilation and
you have to add the specific platform triplets to the Rust toolchain. Suppose you want to compile a Rust binary that
supports linux on both, X86 and ARM. In that case, you have to setup three LLVM toolchains:
1) LLVM for the host
2) LLVM for X86
3) LLVM for ARM (aarch64)
For the host LLVM, you just specify a LLVM version and then register the toolchain as usual. The target LLVM toolchains,
however, have dependencies on system libraries for the target platform. Therefore, it is required to download a so-
called sysroot that contains a root file system with all those system libraries for the specific target platform.
To do so, please add the following to your MODULE.bazel
```Starlark
# https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/repo/http.bzl
http_archive = use_repo_rule("@bazel_tools//:http.bzl", "http_archive")
# Both, cross compilation and MUSL still need a C/C++ toolchain with sysroot.
_BUILD_FILE_CONTENT = """
filegroup(
name = "{name}",
srcs = glob(["*/**"]),
visibility = ["//visibility:public"],
)
"""
# Download sysroot
# https://commondatastorage.googleapis.com/chrome-linux-sysroot/
http_archive(
name = "org_chromium_sysroot_linux_x64",
build_file_content = _BUILD_FILE_CONTENT.format(name = "sysroot"),
sha256 = "f6b758d880a6df264e2581788741623320d548508f07ffc2ae6a29d0c13d647d",
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/2e7ada854015a4cc60fc812112d261af44213ed0/debian_bullseye_amd64_sysroot.tar.xz"],
)
http_archive(
name = "org_chromium_sysroot_linux_aarch64",
build_file_content = _BUILD_FILE_CONTENT.format(name = "sysroot"),
sha256 = "902d1a40a5fd8c3764a36c8d377af5945a92e3d264c6252855bda4d7ef81d3df",
urls = ["https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/41a6c8dec4c4304d6509e30cbaf9218dffb4438e/debian_bullseye_arm64_sysroot.tar.xz"],
)
```
Here, we declare to new http downloads that retrieve the sysroot for linux_x64 (Intel/AMD) and linux_aarch64 (ARM/Apple Silicon). Note, these are only
sysroots, that means you have to configure LLVM next to use these files. As mentioned earlier, three LLVM toolchains
needs to be configured and to do that, please add the following to your MODULE.bazel
```Starlark
LLVM_VERSIONS = {
"": "16.0.0",
}
# Host LLVM toolchain.
llvm.toolchain(
name = "llvm_toolchain",
llvm_versions = LLVM_VERSIONS,
)
use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm")
# X86 LLVM Toolchain with sysroot.
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/WORKSPACE.bzlmod
llvm.toolchain(
name = "llvm_toolchain_x86_with_sysroot",
llvm_versions = LLVM_VERSIONS,
)
llvm.sysroot(
name = "llvm_toolchain_x86_with_sysroot",
label = "@org_chromium_sysroot_linux_x64//:sysroot",
targets = ["linux-x86_64"],
)
use_repo(llvm, "llvm_toolchain_x86_with_sysroot")
#
# ARM (aarch64) LLVM Toolchain with sysroot.
# https://github.com/bazelbuild/rules_rust/blob/main/examples/bzlmod/cross_compile/WORKSPACE.bzlmod
llvm.toolchain(
name = "llvm_toolchain_aarch64_with_sysroot",
llvm_versions = LLVM_VERSIONS,
)
llvm.sysroot(
name = "llvm_toolchain_aarch64_with_sysroot",
label = "@org_chromium_sysroot_linux_aarch64//:sysroot",
targets = ["linux-aarch64"],
)
use_repo(llvm, "llvm_toolchain_aarch64_with_sysroot")
# Register all LLVM toolchains
register_toolchains("@llvm_toolchain//:all")
```
For simplicity, all toolchains are pinned to version LLVM 16 because it is one of the few releases that supports the
host (apple-darwin / Ubuntu), and the two targets. For a
complete [list off all LLVM releases and supported platforms, see this list.](https://github.com/bazel-contrib/toolchains_llvm/blob/master/toolchain/internal/llvm_distributions.bzl)
It is possible to pin different targets to different LLVM
versions; [see the documentation for details](https://github.com/bazel-contrib/toolchains_llvm/tree/master?tab=readme-ov-file#per-host-architecture-llvm-version).
If you face difficulties with building LLVM on older linux distros or your CI,
please take a look at the [LLVM Troubleshooting guide](LLVM_Troubleshooting.md) for known issues.
**Rust Toolchain Configuration**
The Rust toolchain only need to know the additional platform triplets to download the matching toolchains. To do so, add
or or modify your MODULE.bazel with the following entry:
```Starlark
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
extra_target_triples = [
"aarch64-unknown-linux-gnu",
"x86_64-unknown-linux-gnu",
],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
```
You find the exact platform triplets in
the [Rust platform support documentation](https://doc.rust-lang.org/nightly/rustc/platform-support.html).
Next, you have to configure the target platform.
**Platform Configuration**
Once the dependencies are loaded, create an empty BUILD file to define the cross compilation toolchain targets.
As mentioned earlier, it is best practice to put all custom rules, toolchains, and platform into one folder.
Suppose you have the empty BUILD file in the following path:
`build/platforms/BUILD.bazel`
Then you add the following content to the BUILD file:
```Starlark
package(default_visibility = ["//visibility:public"])
platform(
name = "linux-aarch64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
],
)
platform(
name = "linux-x86_64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
)
```
The default visibility at the top of the file means that all targets in this BUILD file will be public by default, which
is sensible because cross-compilation targets are usually used across the entire project.
It is important to recognize that the platform rules use the constraint values to map those constraints to the target
triplets of the Rust toolchain. If you somehow see errors that says some crate couldn't be found with triple xyz, then
one of two things happened.
Either you forgot to add a triple to the Rust toolchain. Unfortunately, the error message
doesn't always tell you the correct triple that is missing. However, in that case you have to double check if for each
specified platform a corresponding Rust extra_target_triples has been added. If one is missing, add it and the error
goes away.
A second source of error is if the platform declaration contains a typo, for example,
cpu:arch64 instead of cpu:aarch64. You have to be meticulous in the platform declaration to make everything work
smoothly.
With the platform configuration out of the way, you are free to configure your binary targets for the specified
platforms.
## Usage
Suppose you have a simple hello world that is defined in a single main.rs file. Conventionally, you declare a minimum
binary target as shown below.
```Starlark
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "hello_world_host",
srcs = ["src/main.rs"],
deps = [],
)
```
Bazel compiles this target to the same platform as the host. To cross-compile the same source file to a different
platform, you simply add one of the platforms previously declared, as shown below.
```Starlark
load("@rules_rust//rust:defs.bzl", "rust_binary")
rust_binary(
name = "hello_world_x86_64",
srcs = ["src/main.rs"],
platform = "//build/platforms:linux-x86_64",
deps = [],
)
rust_binary(
name = "hello_world_aarch64",
srcs = ["src/main.rs"],
platform = "//build/platforms:linux-aarch64",
deps = [],
)
```
You then cross-compile by calling the target.
`bazel build //:hello_world_x86_64`
or
`bazel build //:hello_world_aarch64`
You may have to make the target public when see an access error.
However, when you build for multiple targets, it is sensible to group all of them in a filegroup.
```Starlark
filegroup(
name = "all",
srcs = [
":hello_world_host",
":hello_world_x86_64",
":hello_world_aarch64",
],
visibility = ["//visibility:public"],
)
```
Then you build for all platforms by calling the filegroup target:
`bazel build //:all`

View File

@ -1,17 +1 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
_BUILD_FILE_CONTENT = """filegroup(
name = "{name}",
srcs = glob(["*/**"]),
visibility = ["//visibility:public"],
)
"""
http_archive(
name = "org_chromium_sysroot_linux_aarch64",
sha256 = "902d1a40a5fd8c3764a36c8d377af5945a92e3d264c6252855bda4d7ef81d3df",
url = "https://commondatastorage.googleapis.com/chrome-linux-sysroot/toolchain/{}".format(
"41a6c8dec4c4304d6509e30cbaf9218dffb4438e/debian_bullseye_arm64_sysroot.tar.xz",
),
build_file_content = _BUILD_FILE_CONTENT.format(name = "sysroot"),
)
# Intentionally blank; enable strict mode for bzlmod

View File

@ -0,0 +1,17 @@
package(default_visibility = ["//visibility:public"])
platform(
name = "linux-aarch64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
],
)
platform(
name = "linux-x86_64",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
)

View File

@ -1,4 +1,4 @@
// Copyright 2015 The Bazel Authors. All rights reserved.
// Copyright 2024 The Bazel examples and tutorials Authors & Contributors. // All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
fn main() {
println!("Hello, world!");
println!("Hello, cross compiled world!");
}

View File

@ -23,16 +23,13 @@ fail() {
# MARK - Args
if [[ "$#" -ne 2 ]]; then
fail "Usage: $0 /path/to/hello_world expected_arch"
if [[ "$#" -ne 1 ]]; then
fail "Usage: $0 /path/to/hello_world"
fi
HELLO_WORLD="$(rlocation "$1")"
ARCH_STRING="$2"
# MARK - Test
OUTPUT="$(readelf -h "${HELLO_WORLD}")"
# Match the architecture string with grep.
echo "${OUTPUT}" | grep -E "Machine:(.+)${ARCH_STRING}" ||
fail "Expected '${ARCH_STRING}' in ${OUTPUT}"
OUTPUT="$("${HELLO_WORLD}")"
[[ "${OUTPUT}" == "Hello, cross compiled world!" ]] ||
fail 'Expected "Hello, world!", but was' "${OUTPUT}"

View File

@ -0,0 +1,18 @@
#!/bin/bash
set -euo pipefail
if [[ $# -ne 2 ]]; then
echo >&2 "Usage: $0 /path/to/binary file-output"
exit 1
fi
binary="$1"
want_file_output="$2"
out="$(file -L "${binary}")"
if [[ "${out}" != *"${want_file_output}"* ]]; then
echo >&2 "Wrong file type: ${out}"
exit 1
fi

View File

@ -0,0 +1,78 @@
###############################################################################
## Bazel Configuration Flags
##
## `.bazelrc` is a Bazel configuration file.
## https://bazel.build/docs/best-practices#bazelrc-file
###############################################################################
###############################################################################
## Windows configuration
###############################################################################
# https://bazel.build/reference/command-line-reference#flag--enable_platform_specific_config
common --enable_platform_specific_config
# https://bazel.build/docs/windows#symlink
startup --windows_enable_symlinks
build:windows --enable_runfiles
###############################################################################
## Build configuration
###############################################################################
# Don't create bazel-* symlinks in the WORKSPACE directory.
# Instead, set a prefix and put it in .gitignore
# build --symlink_prefix=target-bzl/
###############################################################################
## Test configuration
###############################################################################
# Reduce test output to just error cases
test --test_output=errors
test --verbose_failures
###############################################################################
## Common configuration
###############################################################################
# Enable Bzlmod for every Bazel command
common --enable_bzlmod
# Write build outputs in a platform-specific directory;
# avoid outputs being wiped and rewritten when switching between platforms.
common --experimental_platform_in_output_dir
# Enable misc. performance optimizations.
common --nolegacy_important_outputs
common --verbose_failures
common --reuse_sandbox_directories
common --noexperimental_merged_skyframe_analysis_execution
# Enable a more detailed performance profile
common --noslim_profile
common --experimental_profile_include_target_label
common --experimental_profile_include_primary_output
###############################################################################
## Rust configuration
###############################################################################
# Enable rustfmt for all targets in the workspace
build:rustfmt --aspects=@rules_rust//rust:defs.bzl%rustfmt_aspect
build:rustfmt --output_groups=+rustfmt_checks
# Enable clippy for all targets in the workspace
build:clippy --aspects=@rules_rust//rust:defs.bzl%rust_clippy_aspect
build:clippy --output_groups=+clippy_checks
###############################################################################
## Custom user flags
##
## This should always be the last thing in the `.bazelrc` file to ensure
## consistent behavior when setting flags in that file as `.bazelrc` files are
## evaluated top to bottom.
###############################################################################
try-import %workspace%/user.bazelrc

View File

@ -0,0 +1 @@
../.bazelversion

2
examples/bzlmod/ffi/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/bazel-*
.DS_Store

View File

View File

@ -0,0 +1,28 @@
module(
name = "ffi",
version = "0.0.0",
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")

View File

@ -0,0 +1,137 @@
# Rust FFI
In case of an existing C++, Rust can call into the C++ function via FFI.
With Bazel, this is straightforward. However, your C++ API needs an extern "C"
declaration to generate the C compatibility required for FFI.
## Setup
The setup is twofold, the Rust rules are declared in the MODULE file,
but the rules_cc are not yet available in the Bazelmod format and thus are declared in
the WORKSPACE.bzlmod file.
In your MODULE.bazel file, ensure to have the following entry:
```starlark
module(
name = "ffi",
version = "0.0.0"
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
```
Then, create or open the WORKSPACE.bzlmod file and add the CC rules:
```starlark
###############################################################################
# Bzlmod and WORKSPACE can work side by side, which allows migrating dependencies
# from the WORKSPACE file to Bzlmod to be a gradual process.
# https://bazel.build/external/migration#hybrid-mode
###############################################################################
# rule http_archive
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# rules_cc
# https://github.com/bazelbuild/rules_cc/releases
http_archive(
name = "rules_cc",
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.10-rc1/rules_cc-0.0.10-rc1.tar.gz"],
sha256 = "d75a040c32954da0d308d3f2ea2ba735490f49b3a7aa3e4b40259ca4b814f825",
)
```
## C++ Target
Assuming you have a C++ library that defines a simple func() you declare it as a regular CC library in the BUILD file:
```starlark
load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library")
cc_library(
name = "nonstandard_name_cc_lib",
srcs = ["c/cc_library.cc"],
)
```
In some cases, you have to deal with non standard naming. In that case you define a
custom gen_rule to take of that and then define a cc_import.
```starlark
load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library")
genrule(
name = "nonstandard_name_gen",
srcs = [":nonstandard_name_cc_lib"],
outs = ["nonstandard_name_gen.a"],
# Copy the first member (libnonstandard_name_cc_lib.a) from the srcs to the
# output nonstandard_name_gen.a.
cmd = "cp $$(awk '{print $$1}' <<< '$(SRCS)') $@",
)
cc_import(
name = "static_cclib",
static_library = "nonstandard_name_gen.a",
)
```
## Rust Callsite
On the Rust side, interestingly, you just declare the cc_import as a dependency of
your Rust target.
```starlark
load("@rules_rust//rust:defs.bzl", "rust_shared_library")
# A rust_shared_library (forcing the use of pic) that depends on a native
# linker library with only a static_library member.
rust_shared_library(
name = "rust_shared_lib_with_static_dep",
srcs = ["src/rust_shared_lib_with_static_dep.rs"],
deps = [":static_cclib"],
)
```
Then in your Rust source file, your create a FFI binding and wrap the call to it into unsafe. You can do that because the Rust standard library provides all the c raw types for FFI so you just import them and unsafe informs the Rust borrow checker to hold off certain checks. The public Rust function f() can then be used in regular Rust code.
```rust
use std::os::raw::c_int;
extern "C" {
pub fn func() -> c_int;
}
pub fn f() {
println!("hi {}",
unsafe {
func()
}
);
}
```
And with that, you build your FFI target as usual:
`bazel build //...`

View File

@ -0,0 +1,15 @@
###############################################################################
# Bzlmod and WORKSPACE can work side by side, which allows migrating dependencies
# from the WORKSPACE file to Bzlmod to be a gradual process.
# https://bazel.build/external/migration#hybrid-mode
###############################################################################
# rule http_archive
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
# rules_cc
# https://github.com/bazelbuild/rules_cc/releases
http_archive(
name = "rules_cc",
urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.0.10-rc1/rules_cc-0.0.10-rc1.tar.gz"],
sha256 = "d75a040c32954da0d308d3f2ea2ba735490f49b3a7aa3e4b40259ca4b814f825",
)

View File

@ -0,0 +1,29 @@
load("@rules_cc//cc:defs.bzl", "cc_import", "cc_library")
load("@rules_rust//rust:defs.bzl", "rust_shared_library")
# A rust_shared_library (forcing the use of pic) that depends on a native
# linker library with only a static_library member.
rust_shared_library(
name = "rust_shared_lib_with_static_dep",
srcs = ["src/rust_shared_lib_with_static_dep.rs"],
deps = [":static_cclib"],
)
cc_library(
name = "nonstandard_name_cc_lib",
srcs = ["c/cc_library.cc"],
)
genrule(
name = "nonstandard_name_gen",
srcs = [":nonstandard_name_cc_lib"],
outs = ["nonstandard_name_gen.a"],
# Copy the first member (libnonstandard_name_cc_lib.a) from the srcs to the
# output nonstandard_name_gen.a.
cmd = "cp $$(awk '{print $$1}' <<< '$(SRCS)') $@",
)
cc_import(
name = "static_cclib",
static_library = "nonstandard_name_gen.a",
)

View File

@ -0,0 +1,16 @@
// Copyright 2024 The Bazel examples and tutorials Authors & Contributors.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
extern "C" int func() { return 123; }

View File

@ -0,0 +1,28 @@
// Copyright 2024 The Bazel examples and tutorials Authors & Contributors. // All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use std::os::raw::c_int;
extern "C" {
pub fn func() -> c_int;
}
pub fn f() {
println!("hi {}",
unsafe {
func()
}
);
}

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -1 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -1 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1 @@
../.bazelversion

View File

@ -1 +1,2 @@
/bazel-*
.DS_Store

View File

@ -0,0 +1,7 @@
# Required on windows
common --enable_platform_specific_config
startup --windows_enable_symlinks
build:windows --enable_runfiles
# Required for cargo_build_script support before Bazel 7
build --incompatible_merge_fixed_and_default_shell_env

View File

@ -0,0 +1 @@
../.bazelversion

5
examples/bzlmod/proto/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/bazel-*
.DS_Store
/proto/.DS_Store
/proto/grpc_server/.DS_Store
/proto/proto_bindings/.DS_Store

View File

@ -0,0 +1,6 @@
config_setting(
name = "release",
values = {
"compilation_mode": "opt",
},
)

View File

@ -0,0 +1,42 @@
[workspace]
resolver = "2"
members = [
"proto_bindings",
"grpc_server",
"grpc_client",
]
[workspace.package]
edition = "2021"
rust-version = "1.78.0"
readme = "README.md"
[workspace.dependencies]
# Internal crates
proto_bindings = { path = "proto_bindings" }
# External crates
prost = { version = "0.12.6" }
prost-types = { version = "0.12.6", default-features = false }
tonic = { version = "0.11.0", features = ["transport"] }
tonic-build = "0.11.0"
tokio = { version = "1.38", default-features = false, features = ["macros", "net", "rt-multi-thread", "signal"] }
# Optimize all crates
[profile.release]
opt-level = 3
strip = true # Automatically strip debug symbols from the binary
lto = true # Enable Link Time Optimization (LTO)
codegen-units = 1 # Reduce Parallel Code Generation Units to Increase Optimization
# There's a Cargo feature named profile-overrides
# that lets you override the optimization level of dependencies.
# https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html
[profile.release.package."*"]
opt-level = 3
strip = 'debuginfo' # Automatically strip debug infos from the binary to reduce size
codegen-units = 1 # Reduce Parallel Code Generation Units to Increase Optimization

View File

@ -0,0 +1,129 @@
module(
name = "grpc-client-server",
version = "0.0.0",
)
###############################################################################
# B A Z E L C E N T R A L R E G I S T R Y # https://registry.bazel.build/
###############################################################################
# https://github.com/bazelbuild/rules_rust/releases
bazel_dep(name = "rules_rust", version = "0.46.0")
#
# Rules for protobuf / gRPC
# https://github.com/bazelbuild/rules_proto/releases
bazel_dep(name = "rules_proto", version = "6.0.2")
# https://github.com/aspect-build/toolchains_protoc/releases
bazel_dep(name = "toolchains_protoc", version = "0.3.1")
# https://registry.bazel.build/modules/protobuf
bazel_dep(name = "protobuf", version = "27.1")
# https://github.com/bazel-contrib/toolchains_llvm
bazel_dep(name = "toolchains_llvm", version = "1.0.0")
###############################################################################
# L L V M
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/MODULE.bazel
###############################################################################
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
# LLVM Versions and platforms
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/toolchain/internal/llvm_distributions.bzl
LLVM_VERSIONS = {
"": "16.0.0",
"darwin-aarch64": "16.0.3",
"darwin-x86_64": "15.0.7",
}
# Host LLVM toolchain.
llvm.toolchain(
name = "llvm_toolchain",
llvm_versions = LLVM_VERSIONS,
)
use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm")
register_toolchains("@llvm_toolchain//:all")
###############################################################################
# T O O L C H A I N S
###############################################################################
# Rust toolchain
RUST_EDITION = "2021"
RUST_VERSION = "1.79.0"
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(
edition = RUST_EDITION,
versions = [RUST_VERSION],
)
use_repo(rust, "rust_toolchains")
register_toolchains("@rust_toolchains//:all")
# Proto toolchain
register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain")
# Custom Prost toolchain
register_toolchains("@//build/prost_toolchain")
###############################################################################
# R U S T C R A T E S
###############################################################################
crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
#
# protobuf / gRPC dependencies
crate.spec(
package = "prost",
version = "0.12",
)
crate.spec(
default_features = False,
package = "prost-types",
version = "0.12",
)
crate.spec(
features = ["transport"],
package = "tonic",
version = "0.11",
)
crate.spec(
package = "tonic-build",
version = "0.11",
)
crate.spec(
package = "protoc-gen-prost",
version = "0.3.1",
)
crate.annotation(
crate = "protoc-gen-prost",
gen_binaries = ["protoc-gen-prost"],
)
crate.spec(
package = "protoc-gen-tonic",
version = "0.4.0",
)
crate.annotation(
crate = "protoc-gen-tonic",
gen_binaries = ["protoc-gen-tonic"],
)
#
# External crates
crate.spec(
default_features = False,
features = [
"macros",
"net",
"rt-multi-thread",
"signal",
],
package = "tokio",
version = "1.38",
)
crate.from_specs()
use_repo(crate, "crates")

View File

@ -0,0 +1,221 @@
# gRPC Client & Server
This example shows how to build a gRPC server and client in Rust with Bazel.
There is a Cargo Workspace configuration and a Bazelmod configuration. Furthermore,
all binary targets apply optimization from the [compiler optimization example](../03-comp-opt).
To run the example with Cargo, open one terminal and start the server with:
`
cargo run --bin grpc_server
`
And, in a second terminal, to run the client:
`
cargo run --bin grpc_client
`
The equivalent Bazel targets are:
Server:
`bazel run //grpc_server:bin`
Client:
`bazel run //grpc_client:bin`
## Setup
The Prost and Tonic rules do not specify a default toolchain in order to avoid mismatched dependency issues.
While the Tonic toolchain works out of the box when its dependencies are matched, however,
Prost requires a custom toolchain that you have to define.
The setup requires three steps to complete:
1. Configure rules and dependencies in MODULE.bazel
2. Configure a custom Prost toolchain
3. Register custom Prost toolchain.
To keep the build hermetic, we use the LLVM Clang compiler to compile all C/C++ dependencies.
### 1) Configure rules and dependencies
In your MODULE.bazel, you add the following:
```starlark
# rules for proto
###############################################################################
# https://github.com/bazelbuild/rules_proto/releases
bazel_dep(name = "rules_proto", version = "6.0.2")
# https://github.com/aspect-build/toolchains_protoc/releases
bazel_dep(name = "toolchains_protoc", version = "0.3.1")
# https://registry.bazel.build/modules/protobuf
bazel_dep(name = "protobuf", version = "27.1")
# rules for LLVM
# https://github.com/bazel-contrib/toolchains_llvm
bazel_dep(name = "toolchains_llvm", version = "1.0.0")
# 1 Register LLVM
###############################################################################
# L L V M
# https://github.com/bazel-contrib/toolchains_llvm/blob/master/tests/MODULE.bazel
###############################################################################
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
LLVM_VERSIONS = { "": "16.0.0",}
# LLVM toolchain.
llvm.toolchain(
name = "llvm_toolchain",
llvm_versions = LLVM_VERSIONS,
)
use_repo(llvm, "llvm_toolchain", "llvm_toolchain_llvm")
register_toolchains("@llvm_toolchain//:all")
# 2 Register Proto toolchain
###############################################################################
# Proto toolchain
register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain")
# Custom Prost toolchain will be added later. See next section
# 3 Register proto / prost / tonic crates
###############################################################################
crate = use_extension("@rules_rust//crate_universe:extension.bzl", "crate")
# protobufs / gRPC
crate.spec(
package = "prost",
version = "0.12",
)
crate.spec(
default_features = False,
package = "prost-types",
version = "0.12",
)
crate.spec(
features = ["transport"],
package = "tonic",
version = "0.11",
)
crate.spec(
package = "tonic-build",
version = "0.11",
)
crate.spec(
package = "protoc-gen-prost",
version = "0.3.1",
)
crate.annotation(
crate = "protoc-gen-prost",
gen_binaries = ["protoc-gen-prost"],
)
crate.spec(
package = "protoc-gen-tonic",
version = "0.4.0",
)
crate.annotation(
crate = "protoc-gen-tonic",
gen_binaries = ["protoc-gen-tonic"],
)
# Other Rust dependencies ...
crate.from_specs()
use_repo(crate, "crates")
```
### 2) Configure a custom Prost toolchain
Configuring a custom Prost toolchain is straightforward, you create a new folder with an empty BUILD.bazl file, and add
the toolchain definition.
As your Bazel setup grows over time, it is a best practice to put all custom macros, rules, and toolchains in a
dedicated folder, for example: `build/`.
Suppose you have your BUILD.bazl file in `build/prost_toolchain/BUILD.bazel`, then add the following content:
```starlark
load("@rules_rust//proto/prost:defs.bzl", "rust_prost_toolchain")
load("@rules_rust//rust:defs.bzl", "rust_library_group")
rust_library_group(
name = "prost_runtime",
deps = [
"@crates//:prost",
],
)
rust_library_group(
name = "tonic_runtime",
deps = [
":prost_runtime",
"@crates//:tonic",
],
)
rust_prost_toolchain(
name = "prost_toolchain_impl",
prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost",
prost_runtime = ":prost_runtime",
prost_types = "@crates//:prost-types",
proto_compiler = "@protobuf//:protoc",
tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic",
tonic_runtime = ":tonic_runtime",
)
toolchain(
name = "prost_toolchain",
toolchain = "prost_toolchain_impl",
toolchain_type = "@rules_rust//proto/prost:toolchain_type",
)
```
The Prost and Tonic dependencies are pulled from the previously configured
crate dependencies in the MODULE file. With this custom toolchain in place, the last step is to register it.
### 3. Register custom Prost toolchain.
In your MODULE.bazel file, locate your toolchains and add the following entry right below the proto toolchain.
```starlark
# 2 Register Proto toolchain
###############################################################################
# Proto toolchain
register_toolchains("@rules_rust//proto/protobuf:default-proto-toolchain")
# Custom Prost toolchain
register_toolchains("@//build/prost_toolchain")
```
Pay attention to the path, `build/prost_toolchain` because if your toolchain
is in a different folder, you have to update this path to make the build work.
## Usage
Once the setup has been completed, you use the proto & prost targets as you normally do. For example, to configure rust
bindings for a proto file, just add the target:
```starlark
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_rust//proto/prost:defs.bzl", "rust_prost_library")
# Build proto files
# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library
proto_library(
name = "proto_bindings",
srcs = [
"proto/helloworld.proto",
],
)
# Generate Rust bindings from the generated proto files
# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library
rust_prost_library(
name = "rust_proto",
proto = ":proto_bindings",
visibility = ["//visibility:public"],
)
```
From there, you
just [follow the target documentation](https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library).

View File

@ -0,0 +1,33 @@
load("@rules_rust//proto/prost:defs.bzl", "rust_prost_toolchain")
load("@rules_rust//rust:defs.bzl", "rust_library_group")
rust_library_group(
name = "prost_runtime",
deps = [
"@crates//:prost",
],
)
rust_library_group(
name = "tonic_runtime",
deps = [
":prost_runtime",
"@crates//:tonic",
],
)
rust_prost_toolchain(
name = "prost_toolchain_impl",
prost_plugin = "@crates//:protoc-gen-prost__protoc-gen-prost",
prost_runtime = ":prost_runtime",
prost_types = "@crates//:prost-types",
proto_compiler = "@protobuf//:protoc",
tonic_plugin = "@crates//:protoc-gen-tonic__protoc-gen-tonic",
tonic_runtime = ":tonic_runtime",
)
toolchain(
name = "prost_toolchain",
toolchain = "prost_toolchain_impl",
toolchain_type = "@rules_rust//proto/prost:toolchain_type",
)

View File

@ -0,0 +1,47 @@
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_doc_test")
# Build binary
# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary
rust_binary(
name = "bin",
srcs = glob([
"src/*.rs",
]),
crate_root = "src/main.rs",
rustc_flags = select({
"//:release": [
"-Clto",
"-Ccodegen-units=1",
"-Cpanic=abort",
"-Copt-level=3",
"-Cstrip=symbols",
],
"//conditions:default": [
"-Copt-level=0",
],
}),
visibility = ["//visibility:public"],
deps = [
# Internal crates
"//proto_bindings:rust_proto",
# External crates
"@crates//:tokio",
"@crates//:tonic",
],
)
# Build documentation
# https://bazelbuild.github.io/rules_rust/rust_doc.html
rust_doc(
name = "client_doc",
crate = ":bin",
visibility = ["//visibility:public"],
)
# Test documentation
# https://bazelbuild.github.io/rules_rust/rust_doc.html#rust_doc_test
rust_doc_test(
name = "client_doc_test",
crate = ":bin",
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,19 @@
[package]
name = "grpc_client"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
readme.workspace = true
[[bin]]
name = "grpc_client"
path = "src/main.rs"
[dependencies]
# Internal crates
proto_bindings = { workspace = true }
# External crates
tokio = { workspace = true }
tonic = { workspace = true }

View File

@ -0,0 +1,23 @@
use proto_bindings::proto::greeter_client::GreeterClient;
use proto_bindings::proto::HelloRequest;
// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/client.rs
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut client = GreeterClient::connect("http://[::1]:5042")
.await
.expect("[Client]: Failed to connect to server.");
let request = tonic::Request::new(HelloRequest {
name: "Hello gRPC".into(),
});
let response = client
.say_hello(request)
.await
.expect("[Client]: Failed to get a response from the server");
println!("RESPONSE={:?}", response);
Ok(())
}

View File

@ -0,0 +1,61 @@
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_doc", "rust_doc_test", "rust_test_suite")
# Build binary
# https://bazelbuild.github.io/rules_rust/defs.html#rust_binary
rust_binary(
name = "bin",
srcs = glob([
"src/*.rs",
]),
crate_root = "src/main.rs",
rustc_flags = select({
"//:release": [
"-Clto",
"-Ccodegen-units=1",
"-Cpanic=abort",
"-Copt-level=3",
"-Cstrip=symbols",
],
"//conditions:default": [
"-Copt-level=0",
],
}),
visibility = ["//visibility:public"],
deps = [
# Internal crates
"//proto_bindings:rust_proto",
# External crates
"@crates//:tokio",
"@crates//:tonic",
],
)
# Build documentation
# https://bazelbuild.github.io/rules_rust/rust_doc.html
rust_doc(
name = "server_doc",
crate = ":bin",
visibility = ["//visibility:public"],
)
# Test documentation
# https://bazelbuild.github.io/rules_rust/rust_doc.html#rust_doc_test
rust_doc_test(
name = "server_doc_test",
crate = ":bin",
visibility = ["//visibility:public"],
)
rust_test_suite(
name = "demo_tests",
srcs = glob([
"tests/*_tests.rs",
]),
tags = ["unit"],
visibility = ["//visibility:public"],
deps = [
# Crate to test
"//proto_bindings:rust_proto",
# External crates
],
)

View File

@ -0,0 +1,19 @@
[package]
name = "grpc_server"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
readme.workspace = true
[[bin]]
name = "grpc_server"
path = "src/main.rs"
[dependencies]
# Internal crates
proto_bindings = { workspace = true }
# External crates
tokio = { workspace = true }
tonic = { workspace = true }

View File

@ -0,0 +1,40 @@
use std::error::Error;
use tonic::transport::Server;
use proto_bindings::proto::greeter_server::GreeterServer;
use crate::server::MyGreeter;
mod server;
mod shutdown_utils;
// https://github.com/hyperium/tonic/blob/master/examples/src/helloworld/server.rs
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let addr = "[::1]:5042"
.parse()
.expect("[Server]: Failed to parse socket address");
let grpc_svc = GreeterServer::new(MyGreeter::new());
// Shutdown signal handler
let signal = shutdown_utils::signal_handler("gRPC Greeter server");
let grpc_server = Server::builder()
.add_service(grpc_svc)
.serve_with_shutdown(addr, signal);
let grpc_handle = tokio::spawn(grpc_server);
println!("GreeterServer listening on {}", addr);
match tokio::try_join!(grpc_handle) {
Ok(_) => {}
Err(e) => {
println!("[Server]: Error: Failed to start gRPC Greeter server.");
println!("[Server]: Error: {:?}", e);
}
}
Ok(())
}

View File

@ -0,0 +1,28 @@
use tonic::{Request, Response, Status};
use proto_bindings::proto::greeter_server::Greeter;
use proto_bindings::proto::{HelloReply, HelloRequest};
#[derive(Copy, Clone)]
pub struct MyGreeter {}
impl MyGreeter {
pub fn new() -> Self {
Self {}
}
}
#[tonic::async_trait]
impl Greeter for MyGreeter {
async fn say_hello(
&self,
request: Request<HelloRequest>,
) -> Result<Response<HelloReply>, Status> {
println!("Got a request from {:?}", request.remote_addr());
let reply = HelloReply {
message: format!("Hello {}!", request.into_inner().name),
};
Ok(Response::new(reply))
}
}

View File

@ -0,0 +1,54 @@
//
/// Registers a signal handler that waits for a signal that indicates a shutdown request.
// https://stackoverflow.com/questions/77585473/rust-tokio-how-to-handle-more-signals-than-just-sigint-i-e-sigquit?noredirect=1#comment136778587_77585473
pub async fn signal_handler(svc: &str) {
wait_for_signal_impl(svc).await
}
/// Waits for a signal that requests a graceful shutdown. Supports the following signals on unix:
/// * SIGTERM
/// * SIGINT (Ctrl-C)
/// * SIGQUIT
/// * SIGHUP
#[cfg(unix)]
async fn wait_for_signal_impl(svc: &str) {
use tokio::signal::unix::{signal, SignalKind};
// Docs: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html
let mut signal_terminate = signal(SignalKind::terminate()).unwrap();
let mut signal_interrupt = signal(SignalKind::interrupt()).unwrap();
let mut signal_quit = signal(SignalKind::quit()).unwrap();
let mut signal_hang = signal(SignalKind::hangup()).unwrap();
// https://docs.rs/tokio/latest/tokio/macro.select.html
tokio::select! {
_ = signal_terminate.recv() => println!("* {svc} received SIGTERM"),
_ = signal_interrupt.recv() => println!("* {svc} received SIGINT"),
_ = signal_quit.recv() => println!("* {svc} received SIGQUIT"),
_ = signal_hang.recv() => println!(" * {svc} received SIGHUP"),
}
}
/// Waits for a signal that requests a graceful shutdown. Supports the following signals on Windows:
/// * ctrl_c
/// * ctrl_break
/// * ctrl_close
/// * ctrl_shutdown
#[cfg(windows)]
async fn wait_for_signal_impl(svc: &str) {
use tokio::signal::windows;
// Docs: https://learn.microsoft.com/en-us/windows/console/handlerroutine
let mut signal_c = windows::ctrl_c().unwrap();
let mut signal_break = windows::ctrl_break().unwrap();
let mut signal_close = windows::ctrl_close().unwrap();
let mut signal_shutdown = windows::ctrl_shutdown().unwrap();
// https://docs.rs/tokio/latest/tokio/macro.select.html
tokio::select! {
_ = signal_c.recv() => println!("* {svc} received CTRL_C."),
_ = signal_break.recv() => println!("* {svc} received CTRL_BREAK."),
_ = signal_close.recv() => println!("* {svc} received CTRL_CLOSE."),
_ = signal_shutdown.recv() => println!("* {svc} received CTRL_SHUTDOWN."),
}
}

View File

@ -0,0 +1,4 @@
#[test]
fn demo_test() {
assert_eq!(4 + 4, 8);
}

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,19 @@
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_rust//proto/prost:defs.bzl", "rust_prost_library")
# Build proto files
# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_proto_library
proto_library(
name = "proto_bindings",
srcs = [
"proto/helloworld.proto",
],
)
# Generate Rust bindings from the generated proto files
# https://bazelbuild.github.io/rules_rust/rust_proto.html#rust_prost_library
rust_prost_library(
name = "rust_proto",
proto = ":proto_bindings",
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "proto_bindings"
version = "0.1.0"

View File

@ -0,0 +1,21 @@
[package]
name = "proto_bindings"
version = "0.1.0"
edition.workspace = true
rust-version.workspace = true
readme.workspace = true
[lib]
name = "proto_bindings"
path = "src/lib.rs"
[dependencies]
tonic = { workspace = true }
prost = { workspace = true }
[build-dependencies]
tonic-build = { workspace = true }

View File

@ -0,0 +1,6 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
tonic_build::configure()
.compile(&["proto/helloworld.proto"], &["proto"])
.expect("Failed to compile proto specification");
Ok(())
}

View File

@ -0,0 +1,34 @@
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
// https://github.com/hyperium/tonic/blob/master/examples/proto/helloworld/helloworld.proto
package proto;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello(HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}

View File

@ -0,0 +1,3 @@
pub mod proto {
tonic::include_proto!("proto");
}

View File

@ -263,16 +263,23 @@ def abi_to_constraints(abi, *, arch = None, system = None):
List: A list of labels to constraint values
"""
all_abi_constraints = []
# add constraints for MUSL static compilation and linking
# to separate the MUSL from the non-MUSL toolchain on x86_64
# if abi == "musl" and system == "linux" and arch == "x86_64":
# all_abi_constraints.append("//rust/platform/constraints:musl_on")
# add constraints for iOS + watchOS simulator and device triples
if system in ["ios", "watchos"]:
if arch == "x86_64" or abi == "sim":
return ["@build_bazel_apple_support//constraints:simulator"]
all_abi_constraints.append("@build_bazel_apple_support//constraints:simulator")
else:
return ["@build_bazel_apple_support//constraints:device"]
all_abi_constraints.append("@build_bazel_apple_support//constraints:device")
# TODO(bazelbuild/platforms#38): Implement when C++ toolchain is more mature and we
# figure out how they're doing this
return []
return all_abi_constraints
def triple_to_system(target_triple):
"""Returns a system name for a given platform triple