diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 7642ff7448..03320fb7f6 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -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 diff --git a/.gitignore b/.gitignore index 08edefd772..8038bb64e1 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,10 @@ MODULE.bazel.lock .vscode *.code-workspace +# JetBrains +.idea +.idea/** + # BazelCI bazelci.py diff --git a/examples/bzlmod/.bazelversion b/examples/bzlmod/.bazelversion new file mode 100644 index 0000000000..468c41f93c --- /dev/null +++ b/examples/bzlmod/.bazelversion @@ -0,0 +1 @@ +7.2.1 \ No newline at end of file diff --git a/examples/bzlmod/all_crate_deps/.bazelversion b/examples/bzlmod/all_crate_deps/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/all_crate_deps/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/all_crate_deps/.gitignore b/examples/bzlmod/all_crate_deps/.gitignore index a6ef824c1f..e28b710ff7 100644 --- a/examples/bzlmod/all_crate_deps/.gitignore +++ b/examples/bzlmod/all_crate_deps/.gitignore @@ -1 +1,2 @@ /bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/.bazelversion b/examples/bzlmod/all_deps_vendor/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/.gitignore b/examples/bzlmod/all_deps_vendor/.gitignore new file mode 100644 index 0000000000..e28b710ff7 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/.gitignore @@ -0,0 +1,2 @@ +/bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/BUILD.bazel b/examples/bzlmod/all_deps_vendor/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/bzlmod/all_deps_vendor/MODULE.bazel b/examples/bzlmod/all_deps_vendor/MODULE.bazel new file mode 100644 index 0000000000..fed1e7b81c --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/MODULE.bazel @@ -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") diff --git a/examples/bzlmod/all_deps_vendor/README.md b/examples/bzlmod/all_deps_vendor/README.md new file mode 100644 index 0000000000..465c8dc5ea --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/README.md @@ -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. \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/WORKSPACE.bzlmod b/examples/bzlmod/all_deps_vendor/WORKSPACE.bzlmod new file mode 100644 index 0000000000..191a57311d --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/WORKSPACE.bzlmod @@ -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() \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/BUILD.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/BUILD.bazel new file mode 100644 index 0000000000..7ac4b7731c --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/BUILD.bazel @@ -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"], +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/Cargo.Bazel.lock b/examples/bzlmod/all_deps_vendor/basic/3rdparty/Cargo.Bazel.lock new file mode 100644 index 0000000000..da60a81809 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/Cargo.Bazel.lock @@ -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" diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bazel new file mode 100644 index 0000000000..b9e9dd4618 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bazel @@ -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"], +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-0.3.3.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-0.3.3.bazel new file mode 100644 index 0000000000..92dd3edef6 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-0.3.3.bazel @@ -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", + ], +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-sys-0.1.11+1.0.8.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-sys-0.1.11+1.0.8.bazel new file mode 100644 index 0000000000..71ef37305c --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.bzip2-sys-0.1.11+1.0.8.bazel @@ -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"], +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.cc-1.0.77.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.cc-1.0.77.bazel new file mode 100644 index 0000000000..e8213a93f2 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.cc-1.0.77.bazel @@ -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", +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.libc-0.2.137.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.libc-0.2.137.bazel new file mode 100644 index 0000000000..d984f47dd2 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.libc-0.2.137.bazel @@ -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", +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.pkg-config-0.3.26.bazel b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.pkg-config-0.3.26.bazel new file mode 100644 index 0000000000..38633d7852 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/BUILD.pkg-config-0.3.26.bazel @@ -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", +) diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/alias_rules.bzl b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/alias_rules.bzl new file mode 100644 index 0000000000..14b04c1272 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/alias_rules.bzl @@ -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") diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/crates.bzl b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/crates.bzl new file mode 100644 index 0000000000..7e8eb93e1e --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/crates.bzl @@ -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 diff --git a/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/defs.bzl b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/defs.bzl new file mode 100644 index 0000000000..03baa059a2 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/3rdparty/crates/defs.bzl @@ -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), + ] diff --git a/examples/bzlmod/all_deps_vendor/basic/BUILD.bazel b/examples/bzlmod/all_deps_vendor/basic/BUILD.bazel new file mode 100644 index 0000000000..3e746b5279 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/BUILD.bazel @@ -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"], +) diff --git a/examples/bzlmod/all_deps_vendor/basic/src/main.rs b/examples/bzlmod/all_deps_vendor/basic/src/main.rs new file mode 100644 index 0000000000..3af2e01f48 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/basic/src/main.rs @@ -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 { + stream: R, + count: usize, +} + +impl CountingStream { + fn new(stream: R) -> Self { + CountingStream { stream, count: 0 } + } +} + +impl Read for CountingStream { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let result = self.stream.read(buf); + if let Ok(read_bytes) = result { + self.count += read_bytes; + } + result + } +} \ No newline at end of file diff --git a/examples/bzlmod/all_deps_vendor/sys_deps.bzl b/examples/bzlmod/all_deps_vendor/sys_deps.bzl new file mode 100644 index 0000000000..3b73d69411 --- /dev/null +++ b/examples/bzlmod/all_deps_vendor/sys_deps.bzl @@ -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() diff --git a/examples/bzlmod/cross_compile/.bazelrc b/examples/bzlmod/compile_opt/.bazelrc similarity index 66% rename from examples/bzlmod/cross_compile/.bazelrc rename to examples/bzlmod/compile_opt/.bazelrc index 2b777be545..e74339bd98 100644 --- a/examples/bzlmod/cross_compile/.bazelrc +++ b/examples/bzlmod/compile_opt/.bazelrc @@ -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 diff --git a/examples/bzlmod/compile_opt/.bazelversion b/examples/bzlmod/compile_opt/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/compile_opt/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/compile_opt/.gitignore b/examples/bzlmod/compile_opt/.gitignore new file mode 100644 index 0000000000..e28b710ff7 --- /dev/null +++ b/examples/bzlmod/compile_opt/.gitignore @@ -0,0 +1,2 @@ +/bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/compile_opt/BUILD.bazel b/examples/bzlmod/compile_opt/BUILD.bazel new file mode 100644 index 0000000000..ed9b5e7a0e --- /dev/null +++ b/examples/bzlmod/compile_opt/BUILD.bazel @@ -0,0 +1,6 @@ +config_setting( + name = "release", + values = { + "compilation_mode": "opt", + }, +) diff --git a/examples/bzlmod/compile_opt/MODULE.bazel b/examples/bzlmod/compile_opt/MODULE.bazel new file mode 100644 index 0000000000..03dd51ecf5 --- /dev/null +++ b/examples/bzlmod/compile_opt/MODULE.bazel @@ -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") diff --git a/examples/bzlmod/compile_opt/README.md b/examples/bzlmod/compile_opt/README.md new file mode 100644 index 0000000000..b229f7607a --- /dev/null +++ b/examples/bzlmod/compile_opt/README.md @@ -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 //...` diff --git a/examples/bzlmod/compile_opt/hello_comp_opt/BUILD.bazel b/examples/bzlmod/compile_opt/hello_comp_opt/BUILD.bazel new file mode 100644 index 0000000000..a12ba0761d --- /dev/null +++ b/examples/bzlmod/compile_opt/hello_comp_opt/BUILD.bazel @@ -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 = [], +) diff --git a/examples/bzlmod/compile_opt/hello_comp_opt/src/main.rs b/examples/bzlmod/compile_opt/hello_comp_opt/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/examples/bzlmod/compile_opt/hello_comp_opt/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/examples/bzlmod/cross_compile/.bazelversion b/examples/bzlmod/cross_compile/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/cross_compile/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/cross_compile/.gitignore b/examples/bzlmod/cross_compile/.gitignore index a6ef824c1f..e28b710ff7 100644 --- a/examples/bzlmod/cross_compile/.gitignore +++ b/examples/bzlmod/cross_compile/.gitignore @@ -1 +1,2 @@ /bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/cross_compile/BUILD.bazel b/examples/bzlmod/cross_compile/BUILD.bazel index e12afa89e1..51ef4130f4 100644 --- a/examples/bzlmod/cross_compile/BUILD.bazel +++ b/examples/bzlmod/cross_compile/BUILD.bazel @@ -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 = [], +) + +rust_binary( + name = "hello_world_aarch64", + srcs = ["src/main.rs"], + platform = "//build/platforms:linux-aarch64", 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"), - ] -] - -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", ], ) diff --git a/examples/bzlmod/cross_compile/LLVM_Troubleshooting.md b/examples/bzlmod/cross_compile/LLVM_Troubleshooting.md new file mode 100644 index 0000000000..56c11c87e0 --- /dev/null +++ b/examples/bzlmod/cross_compile/LLVM_Troubleshooting.md @@ -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) \ No newline at end of file diff --git a/examples/bzlmod/cross_compile/MODULE.bazel b/examples/bzlmod/cross_compile/MODULE.bazel index 90ed67dccc..50457ab537 100644 --- a/examples/bzlmod/cross_compile/MODULE.bazel +++ b/examples/bzlmod/cross_compile/MODULE.bazel @@ -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 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"], +) -# rules_rust still needs a cpp toolchain, so provide a cross-compiling one here +# 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") -register_toolchains("@llvm_toolchain//:all") +# 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") -bazel_dep(name = "rules_rust", version = "0.0.0") -local_path_override( - module_name = "rules_rust", - path = "../../..", +# +# 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") + +# 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") diff --git a/examples/bzlmod/cross_compile/README.md b/examples/bzlmod/cross_compile/README.md index 14171f31c1..4405860371 100644 --- a/examples/bzlmod/cross_compile/README.md +++ b/examples/bzlmod/cross_compile/README.md @@ -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` diff --git a/examples/bzlmod/cross_compile/WORKSPACE.bzlmod b/examples/bzlmod/cross_compile/WORKSPACE.bzlmod index a32aab232e..8e081c0b59 100644 --- a/examples/bzlmod/cross_compile/WORKSPACE.bzlmod +++ b/examples/bzlmod/cross_compile/WORKSPACE.bzlmod @@ -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"), -) \ No newline at end of file +# Intentionally blank; enable strict mode for bzlmod diff --git a/examples/bzlmod/cross_compile/build/platforms/BUILD.bazel b/examples/bzlmod/cross_compile/build/platforms/BUILD.bazel new file mode 100644 index 0000000000..aa0ce9125c --- /dev/null +++ b/examples/bzlmod/cross_compile/build/platforms/BUILD.bazel @@ -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", + ], +) diff --git a/examples/bzlmod/cross_compile/src/main.rs b/examples/bzlmod/cross_compile/src/main.rs index 317f564583..d1641c6185 100644 --- a/examples/bzlmod/cross_compile/src/main.rs +++ b/examples/bzlmod/cross_compile/src/main.rs @@ -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!"); } diff --git a/examples/bzlmod/cross_compile/hello_world_test.sh b/examples/bzlmod/cross_compile/test_hello_world.sh similarity index 74% rename from examples/bzlmod/cross_compile/hello_world_test.sh rename to examples/bzlmod/cross_compile/test_hello_world.sh index a5b887c722..e41ce4e3c7 100755 --- a/examples/bzlmod/cross_compile/hello_world_test.sh +++ b/examples/bzlmod/cross_compile/test_hello_world.sh @@ -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}" \ No newline at end of file diff --git a/examples/bzlmod/cross_compile/test_platform.sh b/examples/bzlmod/cross_compile/test_platform.sh new file mode 100755 index 0000000000..2ba0d24ee1 --- /dev/null +++ b/examples/bzlmod/cross_compile/test_platform.sh @@ -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 \ No newline at end of file diff --git a/examples/bzlmod/ffi/.bazelrc b/examples/bzlmod/ffi/.bazelrc new file mode 100644 index 0000000000..28c961e396 --- /dev/null +++ b/examples/bzlmod/ffi/.bazelrc @@ -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 diff --git a/examples/bzlmod/ffi/.bazelversion b/examples/bzlmod/ffi/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/ffi/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/ffi/.gitignore b/examples/bzlmod/ffi/.gitignore new file mode 100644 index 0000000000..e28b710ff7 --- /dev/null +++ b/examples/bzlmod/ffi/.gitignore @@ -0,0 +1,2 @@ +/bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/ffi/BUILD.bazel b/examples/bzlmod/ffi/BUILD.bazel new file mode 100644 index 0000000000..e69de29bb2 diff --git a/examples/bzlmod/ffi/MODULE.bazel b/examples/bzlmod/ffi/MODULE.bazel new file mode 100644 index 0000000000..e3dc485feb --- /dev/null +++ b/examples/bzlmod/ffi/MODULE.bazel @@ -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") diff --git a/examples/bzlmod/ffi/README.md b/examples/bzlmod/ffi/README.md new file mode 100644 index 0000000000..7d125a4521 --- /dev/null +++ b/examples/bzlmod/ffi/README.md @@ -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 //...` + + + diff --git a/examples/bzlmod/ffi/WORKSPACE.bzlmod b/examples/bzlmod/ffi/WORKSPACE.bzlmod new file mode 100644 index 0000000000..c52a352ebb --- /dev/null +++ b/examples/bzlmod/ffi/WORKSPACE.bzlmod @@ -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", +) \ No newline at end of file diff --git a/examples/bzlmod/ffi/ffi/BUILD.bazel b/examples/bzlmod/ffi/ffi/BUILD.bazel new file mode 100644 index 0000000000..edead77ff9 --- /dev/null +++ b/examples/bzlmod/ffi/ffi/BUILD.bazel @@ -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", +) diff --git a/examples/bzlmod/ffi/ffi/c/cc_library.cc b/examples/bzlmod/ffi/ffi/c/cc_library.cc new file mode 100644 index 0000000000..8d9d4497ab --- /dev/null +++ b/examples/bzlmod/ffi/ffi/c/cc_library.cc @@ -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; } \ No newline at end of file diff --git a/examples/bzlmod/ffi/ffi/src/rust_shared_lib_with_static_dep.rs b/examples/bzlmod/ffi/ffi/src/rust_shared_lib_with_static_dep.rs new file mode 100644 index 0000000000..3138b859e3 --- /dev/null +++ b/examples/bzlmod/ffi/ffi/src/rust_shared_lib_with_static_dep.rs @@ -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() + } + ); +} \ No newline at end of file diff --git a/examples/bzlmod/hello_world/.bazelversion b/examples/bzlmod/hello_world/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/hello_world/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/hello_world/.gitignore b/examples/bzlmod/hello_world/.gitignore index a6ef824c1f..e28b710ff7 100644 --- a/examples/bzlmod/hello_world/.gitignore +++ b/examples/bzlmod/hello_world/.gitignore @@ -1 +1,2 @@ /bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/hello_world_no_cargo/.bazelversion b/examples/bzlmod/hello_world_no_cargo/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/hello_world_no_cargo/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/hello_world_no_cargo/.gitignore b/examples/bzlmod/hello_world_no_cargo/.gitignore index a6ef824c1f..e28b710ff7 100644 --- a/examples/bzlmod/hello_world_no_cargo/.gitignore +++ b/examples/bzlmod/hello_world_no_cargo/.gitignore @@ -1 +1,2 @@ /bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/override_target/.bazelversion b/examples/bzlmod/override_target/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/override_target/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/override_target/.gitignore b/examples/bzlmod/override_target/.gitignore index a6ef824c1f..e28b710ff7 100644 --- a/examples/bzlmod/override_target/.gitignore +++ b/examples/bzlmod/override_target/.gitignore @@ -1 +1,2 @@ /bazel-* +.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/proto/.bazelrc b/examples/bzlmod/proto/.bazelrc new file mode 100644 index 0000000000..eb97032bb9 --- /dev/null +++ b/examples/bzlmod/proto/.bazelrc @@ -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 diff --git a/examples/bzlmod/proto/.bazelversion b/examples/bzlmod/proto/.bazelversion new file mode 120000 index 0000000000..b332604979 --- /dev/null +++ b/examples/bzlmod/proto/.bazelversion @@ -0,0 +1 @@ +../.bazelversion \ No newline at end of file diff --git a/examples/bzlmod/proto/.gitignore b/examples/bzlmod/proto/.gitignore new file mode 100644 index 0000000000..c29ff2bab2 --- /dev/null +++ b/examples/bzlmod/proto/.gitignore @@ -0,0 +1,5 @@ +/bazel-* +.DS_Store +/proto/.DS_Store +/proto/grpc_server/.DS_Store +/proto/proto_bindings/.DS_Store \ No newline at end of file diff --git a/examples/bzlmod/proto/BUILD.bazel b/examples/bzlmod/proto/BUILD.bazel new file mode 100644 index 0000000000..ed9b5e7a0e --- /dev/null +++ b/examples/bzlmod/proto/BUILD.bazel @@ -0,0 +1,6 @@ +config_setting( + name = "release", + values = { + "compilation_mode": "opt", + }, +) diff --git a/examples/bzlmod/proto/Cargo.toml b/examples/bzlmod/proto/Cargo.toml new file mode 100644 index 0000000000..3f3017dac4 --- /dev/null +++ b/examples/bzlmod/proto/Cargo.toml @@ -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 diff --git a/examples/bzlmod/proto/MODULE.bazel b/examples/bzlmod/proto/MODULE.bazel new file mode 100644 index 0000000000..fc6cd78459 --- /dev/null +++ b/examples/bzlmod/proto/MODULE.bazel @@ -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") diff --git a/examples/bzlmod/proto/README.md b/examples/bzlmod/proto/README.md new file mode 100644 index 0000000000..8ce7fc6125 --- /dev/null +++ b/examples/bzlmod/proto/README.md @@ -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). diff --git a/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel b/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel new file mode 100644 index 0000000000..1075543a16 --- /dev/null +++ b/examples/bzlmod/proto/build/prost_toolchain/BUILD.bazel @@ -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", +) diff --git a/examples/bzlmod/proto/grpc_client/BUILD.bazel b/examples/bzlmod/proto/grpc_client/BUILD.bazel new file mode 100644 index 0000000000..94b11e926d --- /dev/null +++ b/examples/bzlmod/proto/grpc_client/BUILD.bazel @@ -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"], +) diff --git a/examples/bzlmod/proto/grpc_client/Cargo.toml b/examples/bzlmod/proto/grpc_client/Cargo.toml new file mode 100644 index 0000000000..357a3919c2 --- /dev/null +++ b/examples/bzlmod/proto/grpc_client/Cargo.toml @@ -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 } diff --git a/examples/bzlmod/proto/grpc_client/src/main.rs b/examples/bzlmod/proto/grpc_client/src/main.rs new file mode 100644 index 0000000000..4b7cdd3f93 --- /dev/null +++ b/examples/bzlmod/proto/grpc_client/src/main.rs @@ -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> { + 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(()) +} diff --git a/examples/bzlmod/proto/grpc_server/BUILD.bazel b/examples/bzlmod/proto/grpc_server/BUILD.bazel new file mode 100644 index 0000000000..27e0b43e45 --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/BUILD.bazel @@ -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 + ], +) diff --git a/examples/bzlmod/proto/grpc_server/Cargo.toml b/examples/bzlmod/proto/grpc_server/Cargo.toml new file mode 100644 index 0000000000..3c7c6a2fde --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/Cargo.toml @@ -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 } \ No newline at end of file diff --git a/examples/bzlmod/proto/grpc_server/src/main.rs b/examples/bzlmod/proto/grpc_server/src/main.rs new file mode 100644 index 0000000000..6f22bfac0c --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/src/main.rs @@ -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> { + 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(()) +} diff --git a/examples/bzlmod/proto/grpc_server/src/server.rs b/examples/bzlmod/proto/grpc_server/src/server.rs new file mode 100644 index 0000000000..a1d457326c --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/src/server.rs @@ -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, + ) -> Result, Status> { + println!("Got a request from {:?}", request.remote_addr()); + + let reply = HelloReply { + message: format!("Hello {}!", request.into_inner().name), + }; + Ok(Response::new(reply)) + } +} diff --git a/examples/bzlmod/proto/grpc_server/src/shutdown_utils.rs b/examples/bzlmod/proto/grpc_server/src/shutdown_utils.rs new file mode 100644 index 0000000000..20d60e1b8c --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/src/shutdown_utils.rs @@ -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."), + } +} diff --git a/examples/bzlmod/proto/grpc_server/tests/demo_tests.rs b/examples/bzlmod/proto/grpc_server/tests/demo_tests.rs new file mode 100644 index 0000000000..f12bef408b --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/tests/demo_tests.rs @@ -0,0 +1,4 @@ +#[test] +fn demo_test() { + assert_eq!(4 + 4, 8); +} diff --git a/examples/bzlmod/proto/grpc_server/tests/mod.rs b/examples/bzlmod/proto/grpc_server/tests/mod.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/examples/bzlmod/proto/grpc_server/tests/mod.rs @@ -0,0 +1 @@ + diff --git a/examples/bzlmod/proto/proto_bindings/BUILD.bazel b/examples/bzlmod/proto/proto_bindings/BUILD.bazel new file mode 100644 index 0000000000..d2f9e24f1e --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/BUILD.bazel @@ -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"], +) diff --git a/examples/bzlmod/proto/proto_bindings/Cargo.lock b/examples/bzlmod/proto/proto_bindings/Cargo.lock new file mode 100644 index 0000000000..9d1ef987af --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/Cargo.lock @@ -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" diff --git a/examples/bzlmod/proto/proto_bindings/Cargo.toml b/examples/bzlmod/proto/proto_bindings/Cargo.toml new file mode 100644 index 0000000000..95255c32ca --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/Cargo.toml @@ -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 } diff --git a/examples/bzlmod/proto/proto_bindings/build.rs b/examples/bzlmod/proto/proto_bindings/build.rs new file mode 100644 index 0000000000..e1da7552bf --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/build.rs @@ -0,0 +1,6 @@ +fn main() -> Result<(), Box> { + tonic_build::configure() + .compile(&["proto/helloworld.proto"], &["proto"]) + .expect("Failed to compile proto specification"); + Ok(()) +} diff --git a/examples/bzlmod/proto/proto_bindings/proto/helloworld.proto b/examples/bzlmod/proto/proto_bindings/proto/helloworld.proto new file mode 100644 index 0000000000..e838ddc9ec --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/proto/helloworld.proto @@ -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; +} \ No newline at end of file diff --git a/examples/bzlmod/proto/proto_bindings/src/lib.rs b/examples/bzlmod/proto/proto_bindings/src/lib.rs new file mode 100644 index 0000000000..860d77e5a1 --- /dev/null +++ b/examples/bzlmod/proto/proto_bindings/src/lib.rs @@ -0,0 +1,3 @@ +pub mod proto { + tonic::include_proto!("proto"); +} diff --git a/rust/platform/triple_mappings.bzl b/rust/platform/triple_mappings.bzl index f8c5956153..567f1f8406 100644 --- a/rust/platform/triple_mappings.bzl +++ b/rust/platform/triple_mappings.bzl @@ -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