upstream wrappers for cargo, rustc, cargo-clippy (#2703)

...and a bazel_env example.

As discussed in
https://bazelbuild.slack.com/archives/CSV56UT0F/p1718207171652029?thread_ts=1718182474.631279&cid=CSV56UT0F
This commit is contained in:
Peter Kolloch 2024-06-25 13:34:39 +02:00 committed by GitHub
parent c888ebdd9a
commit c1ab10aaad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
32 changed files with 490 additions and 63 deletions

View File

@ -5,3 +5,4 @@ crate_universe/private/bootstrap
test/bzlmod_repo_mapping
test/cc_common_link
test/no_std
.direnv

View File

@ -1132,7 +1132,7 @@ Run the test with `bazel test //hello_lib:greeting_test`.
## rust_toolchain
<pre>
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-cargo_clippy">cargo_clippy</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-experimental_link_std_dylib">experimental_link_std_dylib</a>,
<a href="#rust_toolchain-experimental_use_cc_common_link">experimental_use_cc_common_link</a>, <a href="#rust_toolchain-extra_exec_rustc_flags">extra_exec_rustc_flags</a>, <a href="#rust_toolchain-extra_rustc_flags">extra_rustc_flags</a>,
<a href="#rust_toolchain-extra_rustc_flags_for_crate_types">extra_rustc_flags_for_crate_types</a>, <a href="#rust_toolchain-global_allocator_library">global_allocator_library</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>,
@ -1192,6 +1192,7 @@ See `@rules_rust//rust:repositories.bzl` for examples of defining the `@rust_cpu
| <a id="rust_toolchain-allocator_library"></a>allocator_library | Target that provides allocator functions when rust_library targets are embedded in a cc_binary. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `"@rules_rust//ffi/cc/allocator_library"` |
| <a id="rust_toolchain-binary_ext"></a>binary_ext | The extension for binaries created from rustc. | String | required | |
| <a id="rust_toolchain-cargo"></a>cargo | The location of the `cargo` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-cargo_clippy"></a>cargo_clippy | The location of the `cargo_clippy` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-clippy_driver"></a>clippy_driver | The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-debug_info"></a>debug_info | Rustc debug info levels per opt level | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{"dbg": "2", "fastbuild": "0", "opt": "0"}` |
| <a id="rust_toolchain-default_edition"></a>default_edition | The edition to use for rust_* rules that don't specify an edition. If absent, every rule is required to specify its `edition` attribute. | String | optional | `""` |

View File

@ -36,7 +36,7 @@ A dedicated filegroup-like rule for Rust stdlib artifacts.
## rust_toolchain
<pre>
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
rust_toolchain(<a href="#rust_toolchain-name">name</a>, <a href="#rust_toolchain-allocator_library">allocator_library</a>, <a href="#rust_toolchain-binary_ext">binary_ext</a>, <a href="#rust_toolchain-cargo">cargo</a>, <a href="#rust_toolchain-cargo_clippy">cargo_clippy</a>, <a href="#rust_toolchain-clippy_driver">clippy_driver</a>, <a href="#rust_toolchain-debug_info">debug_info</a>,
<a href="#rust_toolchain-default_edition">default_edition</a>, <a href="#rust_toolchain-dylib_ext">dylib_ext</a>, <a href="#rust_toolchain-env">env</a>, <a href="#rust_toolchain-exec_triple">exec_triple</a>, <a href="#rust_toolchain-experimental_link_std_dylib">experimental_link_std_dylib</a>,
<a href="#rust_toolchain-experimental_use_cc_common_link">experimental_use_cc_common_link</a>, <a href="#rust_toolchain-extra_exec_rustc_flags">extra_exec_rustc_flags</a>, <a href="#rust_toolchain-extra_rustc_flags">extra_rustc_flags</a>,
<a href="#rust_toolchain-extra_rustc_flags_for_crate_types">extra_rustc_flags_for_crate_types</a>, <a href="#rust_toolchain-global_allocator_library">global_allocator_library</a>, <a href="#rust_toolchain-llvm_cov">llvm_cov</a>, <a href="#rust_toolchain-llvm_profdata">llvm_profdata</a>,
@ -96,6 +96,7 @@ See `@rules_rust//rust:repositories.bzl` for examples of defining the `@rust_cpu
| <a id="rust_toolchain-allocator_library"></a>allocator_library | Target that provides allocator functions when rust_library targets are embedded in a cc_binary. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `"@rules_rust//ffi/cc/allocator_library"` |
| <a id="rust_toolchain-binary_ext"></a>binary_ext | The extension for binaries created from rustc. | String | required | |
| <a id="rust_toolchain-cargo"></a>cargo | The location of the `cargo` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-cargo_clippy"></a>cargo_clippy | The location of the `cargo_clippy` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-clippy_driver"></a>clippy_driver | The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item. | <a href="https://bazel.build/concepts/labels">Label</a> | optional | `None` |
| <a id="rust_toolchain-debug_info"></a>debug_info | Rustc debug info levels per opt level | <a href="https://bazel.build/rules/lib/dict">Dictionary: String -> String</a> | optional | `{"dbg": "2", "fastbuild": "0", "opt": "0"}` |
| <a id="rust_toolchain-default_edition"></a>default_edition | The edition to use for rust_* rules that don't specify an edition. If absent, every rule is required to specify its `edition` attribute. | String | optional | `""` |

View File

@ -1,4 +1,5 @@
android
bazel_env
bzlmod
cargo_manifest_dir/external_crate
crate_universe

View File

@ -0,0 +1 @@
.direnv

View File

@ -0,0 +1,15 @@
# Required on windows
common --enable_platform_specific_config
startup --windows_enable_symlinks
build:windows --enable_runfiles
build --experimental_enable_bzlmod
# 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
# Required for cargo_build_script support before Bazel 7
build --incompatible_merge_fixed_and_default_shell_env
# Do not import the PATH etc. from the host environment
common --incompatible_strict_action_env

View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
# ^^^ make IDEs happy
watch_file bazel-out/bazel_env-opt/bin/env/env/bin
PATH_add bazel-out/bazel_env-opt/bin/env/env/bin
if [[ ! -d bazel-out/bazel_env-opt/bin/env/env/bin ]]; then
log_error "ERROR[bazel_env.bzl]: Run 'bazel run //env:env' to regenerate bazel-out/bazel_env-opt/bin/env/env/bin"
fi

1
examples/bazel_env/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/bazel-*

View File

@ -0,0 +1,50 @@
"Tests for upstream wrappers."
sh_test(
name = "upstream_cargo_test",
size = "small",
srcs = ["cargo_test.sh"],
args = [
"$(rlocationpath @rules_rust//tools/upstream_wrapper:cargo)",
],
data = [
"Cargo.lock",
"Cargo.toml",
"//rust/hello_world:Cargo.toml",
"//rust/hello_world:src/main.rs",
"@rules_rust//tools/upstream_wrapper:cargo",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)
sh_test(
name = "upstream_rustc_test",
size = "small",
srcs = ["rustc_test.sh"],
args = [
"$(rlocationpath @rules_rust//tools/upstream_wrapper:rustc)",
],
data = [
"@rules_rust//tools/upstream_wrapper:rustc",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)
sh_test(
name = "upstream_rustfmt_test",
size = "small",
srcs = ["rustfmt_test.sh"],
args = [
"$(rlocationpath @rules_rust//tools/upstream_wrapper:rustfmt)",
],
data = [
"@rules_rust//tools/upstream_wrapper:rustfmt",
],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
)

7
examples/bazel_env/Cargo.lock generated Normal file
View File

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

View File

@ -0,0 +1,5 @@
[workspace]
resolver = "2"
members = [
"rust/hello_world"
]

View File

@ -0,0 +1,44 @@
"""bazelbuild/rules_rust - bazel_env/bzlmod example
See https://github.com/buildbuddy-io/bazel_env.bzl.
"""
module(
name = "all_crate_deps_bzlmod_example",
version = "0.0.0",
)
bazel_dep(name = "platforms", version = "0.0.9")
bazel_dep(
name = "rules_rust",
version = "0.0.0",
)
local_path_override(
module_name = "rules_rust",
path = "../..",
)
rust = use_extension("@rules_rust//rust:extensions.bzl", "rust")
rust.toolchain(edition = "2021")
use_repo(
rust,
"rust_toolchains",
)
register_toolchains("@rust_toolchains//:all")
crate = use_extension(
"@rules_rust//crate_universe:extension.bzl",
"crate",
)
crate.from_cargo(
name = "crates",
cargo_lockfile = "//:Cargo.lock",
manifests = [
"//:Cargo.toml",
"//rust/hello_world:Cargo.toml",
],
)
use_repo(crate, "crates")
bazel_dep(name = "bazel_env.bzl", version = "0.1.1")

View File

@ -0,0 +1,11 @@
# rules_rust with bazel_env
This example uses [bazel_env.bzl](https://github.com/buildbuddy-io/bazel_env.bzl) to
provide `cargo`, `cargo-clippy`, `rustc` and `rustfmt` from the bazel toolchains
to the user. They will be available directly in the PATH when the user
enters this directory and has [direnv](https://direnv.net/) set up.
Advantages:
- The user doesn't have to install the toolchains themselves.
- The tool versions will always match exactly those that bazel uses.

View File

@ -0,0 +1 @@
# Intentionally blank; using bzlmod

View File

@ -0,0 +1 @@
# Intentionally blank; enable strict mode for bzlmod

View File

@ -0,0 +1,46 @@
#!/usr/bin/env bash
# --- begin runfiles.bash initialization v3 ---
# Copy-pasted from the Bazel Bash runfiles library v3.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---
set -euo pipefail
# MARK - Functions
fail() {
echo >&2 "$@"
exit 1
}
# MARK - Args
if [[ "$#" -lt 1 ]]; then
fail "Usage: $0 /path/to/bin <args>"
fi
CARGO="$(rlocation "$1")"
# MARK - Test
# simulate bazel run with setting BUILD_WORKING_DIRECTORY
export BUILD_WORKING_DIRECTORY="$PWD"
# Run hello_world, invoking rustc
OUTPUT="$("${CARGO}" run)"
EXPECTED_OUTPUT="Hello, world!"
[[ "${OUTPUT}" == "${EXPECTED_OUTPUT}" ]] ||
fail 'Expected "'"${EXPECTED_OUTPUT}"'", but was' "${OUTPUT}"
# Crash tests, no error
${CARGO} clippy ||
fail "couldn't execute \"cargo clippy\""

13
examples/bazel_env/env/BUILD.bazel vendored Normal file
View File

@ -0,0 +1,13 @@
load("@bazel_env.bzl", "bazel_env")
package(default_visibility = ["//visibility:public"])
bazel_env(
name = "env",
tools = {
"cargo": "@rules_rust//tools/upstream_wrapper:cargo",
"cargo-clippy": "@rules_rust//tools/upstream_wrapper:cargo_clippy",
"rustc": "@rules_rust//tools/upstream_wrapper:rustc",
"rustfmt": "@rules_rust//tools/upstream_wrapper:rustfmt",
},
)

BIN
examples/bazel_env/hello Executable file

Binary file not shown.

View File

@ -0,0 +1,15 @@
load("@crates//:defs.bzl", "all_crate_deps")
load("@rules_rust//rust:defs.bzl", "rust_binary")
package(default_visibility = ["//visibility:public"])
exports_files([
"Cargo.toml",
"src/main.rs",
])
rust_binary(
name = "hello_world",
srcs = ["src/main.rs"],
deps = all_crate_deps(normal = True),
)

View File

@ -0,0 +1,8 @@
[package]
name = "hello_world"
version = "0.0.0"
edition = "2021"
publish = false
[lib]
path = "/dev/null"

View File

@ -0,0 +1,17 @@
// Copyright 2015 The Bazel Authors. 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.
fn main() {
println!("Hello, world!");
}

View File

@ -0,0 +1,40 @@
#!/usr/bin/env bash
# --- begin runfiles.bash initialization v3 ---
# Copy-pasted from the Bazel Bash runfiles library v3.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---
set -euo pipefail
# MARK - Functions
fail() {
echo >&2 "$@"
exit 1
}
# MARK - Args
if [[ "$#" -lt 1 ]]; then
fail "Usage: $0 /path/to/bin <args>"
fi
RUSTC="$(rlocation "$1")"
# MARK - Test
DIR=$(mktemp -d "rustc-test-XXXXXXX")
set -x
echo "fn main() {}" >"$DIR/main.rs"
cd "$DIR"
# simulate bazel run with setting BUILD_WORKING_DIRECTORY
export BUILD_WORKING_DIRECTORY="$PWD"
"$RUSTC" "main.rs" ||
fail "Couldn't compile main.rs"

View File

@ -0,0 +1,41 @@
#!/usr/bin/env bash
# --- begin runfiles.bash initialization v3 ---
# Copy-pasted from the Bazel Bash runfiles library v3.
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
# --- end runfiles.bash initialization v3 ---
set -euo pipefail
# MARK - Functions
fail() {
echo >&2 "$@"
exit 1
}
# MARK - Args
if [[ "$#" -lt 1 ]]; then
fail "Usage: $0 /path/to/bin <args>"
fi
RUSTFMT="$(rlocation "$1")"
# MARK - Test
# simulate bazel run with setting BUILD_WORKING_DIRECTORY
export BUILD_WORKING_DIRECTORY="$PWD"
OUTPUT="$(echo -e "fn main() {\n\n}" | "$RUSTFMT")"
# without newlines in body
EXPECTED_OUTPUT="fn main() {}"
[[ "${OUTPUT}" == "${EXPECTED_OUTPUT}" ]] ||
fail 'Expected "'"${EXPECTED_OUTPUT}"'", but was' "${OUTPUT}"

View File

@ -122,14 +122,6 @@ def BUILD_for_rustfmt(target_triple):
binary_ext = system_to_binary_ext(target_triple.system),
)
_build_file_for_clippy_template = """\
filegroup(
name = "clippy_driver_bin",
srcs = ["bin/clippy-driver{binary_ext}"],
visibility = ["//visibility:public"],
)
"""
_build_file_for_rust_analyzer_proc_macro_srv = """\
filegroup(
name = "rust_analyzer_proc_macro_srv",
@ -150,6 +142,19 @@ def BUILD_for_rust_analyzer_proc_macro_srv(exec_triple):
binary_ext = system_to_binary_ext(exec_triple.system),
)
_build_file_for_clippy_template = """\
filegroup(
name = "clippy_driver_bin",
srcs = ["bin/clippy-driver{binary_ext}"],
visibility = ["//visibility:public"],
)
filegroup(
name = "cargo_clippy_bin",
srcs = ["bin/cargo-clippy{binary_ext}"],
visibility = ["//visibility:public"],
)
"""
def BUILD_for_clippy(target_triple):
"""Emits a BUILD file the clippy archive.
@ -244,6 +249,7 @@ rust_toolchain(
rustfmt = {rustfmt_label},
cargo = "//:cargo",
clippy_driver = "//:clippy_driver_bin",
cargo_clippy = "//:cargo_clippy_bin",
llvm_cov = {llvm_cov_label},
llvm_profdata = {llvm_profdata_label},
rustc_lib = "//:rustc_lib",

View File

@ -13,6 +13,16 @@ def _toolchain_files_impl(ctx):
],
transitive_files = toolchain.rustc_lib,
)
elif ctx.attr.tool == "cargo-clippy":
files = depset([toolchain.cargo_clippy])
runfiles = ctx.runfiles(
files = [
toolchain.cargo_clippy,
toolchain.clippy_driver,
toolchain.rustc,
],
transitive_files = toolchain.rustc_lib,
)
elif ctx.attr.tool == "clippy":
files = depset([toolchain.clippy_driver])
runfiles = ctx.runfiles(
@ -60,6 +70,7 @@ toolchain_files = rule(
doc = "The desired tool to get form the current rust_toolchain",
values = [
"cargo",
"cargo-clippy",
"clippy",
"rust_lib",
"rust_std",

View File

@ -377,6 +377,7 @@ def _generate_sysroot(
rustc_lib,
cargo = None,
clippy = None,
cargo_clippy = None,
llvm_tools = None,
rust_std = None,
rustfmt = None):
@ -388,6 +389,7 @@ def _generate_sysroot(
rustdoc (File): The path to a `rustdoc` executable.
rustc_lib (Target): A collection of Files containing dependencies of `rustc`.
cargo (File, optional): The path to a `cargo` executable.
cargo_clippy (File, optional): The path to a `cargo-clippy` executable.
clippy (File, optional): The path to a `clippy-driver` executable.
llvm_tools (Target, optional): A collection of llvm tools used by `rustc`.
rust_std (Target, optional): A collection of Files containing Rust standard library components.
@ -428,6 +430,12 @@ def _generate_sysroot(
sysroot_cargo = _symlink_sysroot_bin(ctx, name, "bin", cargo)
direct_files.extend([sysroot_cargo])
# Cargo-clippy
sysroot_cargo_clippy = None
if cargo_clippy:
sysroot_cargo_clippy = _symlink_sysroot_bin(ctx, name, "bin", cargo_clippy)
direct_files.extend([sysroot_cargo_clippy])
# Rustfmt
sysroot_rustfmt = None
if rustfmt:
@ -453,6 +461,7 @@ def _generate_sysroot(
content = "\n".join([
"cargo: {}".format(cargo),
"clippy: {}".format(clippy),
"cargo-clippy: {}".format(cargo_clippy),
"llvm_tools: {}".format(llvm_tools),
"rust_std: {}".format(rust_std),
"rustc_lib: {}".format(rustc_lib),
@ -469,6 +478,7 @@ def _generate_sysroot(
all_files = all_files,
cargo = sysroot_cargo,
clippy = sysroot_clippy,
cargo_clippy = sysroot_cargo_clippy,
rust_std = sysroot_rust_std,
rustc = sysroot_rustc,
rustc_lib = sysroot_rustc_lib,
@ -529,6 +539,7 @@ def _rust_toolchain_impl(ctx):
rustfmt = ctx.file.rustfmt,
clippy = ctx.file.clippy_driver,
cargo = ctx.file.cargo,
cargo_clippy = ctx.file.cargo_clippy,
llvm_tools = ctx.attr.llvm_tools,
)
@ -571,6 +582,7 @@ def _rust_toolchain_impl(ctx):
"RUSTDOC": sysroot.rustdoc.path,
"RUST_DEFAULT_EDITION": ctx.attr.default_edition or "",
"RUST_SYSROOT": sysroot_path,
"RUST_SYSROOT_SHORT": sysroot_short_path,
}
if sysroot.cargo:
@ -631,6 +643,7 @@ def _rust_toolchain_impl(ctx):
binary_ext = ctx.attr.binary_ext,
cargo = sysroot.cargo,
clippy_driver = sysroot.clippy,
cargo_clippy = sysroot.cargo_clippy,
compilation_mode_opts = compilation_mode_opts,
crosstool_files = ctx.files._cc_toolchain,
default_edition = ctx.attr.default_edition,
@ -702,6 +715,11 @@ rust_toolchain = rule(
allow_single_file = True,
cfg = "exec",
),
"cargo_clippy": attr.label(
doc = "The location of the `cargo_clippy` binary. Can be a direct source or a filegroup containing one item.",
allow_single_file = True,
cfg = "exec",
),
"clippy_driver": attr.label(
doc = "The location of the `clippy-driver` binary. Can be a direct source or a filegroup containing one item.",
allow_single_file = True,

View File

@ -13,6 +13,11 @@ toolchain_files(
tool = "clippy",
)
toolchain_files(
name = "current_cargo_clippy_files",
tool = "cargo-clippy",
)
toolchain_files(
name = "current_rustc_files",
tool = "rustc",

View File

@ -36,7 +36,7 @@ rust_library(
alias(
name = "rustfmt",
actual = ":target_aware_rustfmt",
deprecation = "Prefer //tools/rustfmt:target_aware_rustfmt",
deprecation = "Prefer //tools/upstream_wrapper:rustfmt",
visibility = ["//visibility:public"],
)
@ -85,20 +85,10 @@ rust_clippy(
],
)
# This is a small wrapper around the raw upstream rustfmt binary which can be `bazel run`.
rust_binary(
# Deprecated but present for compatibility.
alias(
name = "upstream_rustfmt",
srcs = [
"src/upstream_rustfmt_wrapper.rs",
],
data = ["//rust/toolchain:current_rustfmt_toolchain_for_target"],
edition = "2018",
rustc_env = {
"RUSTFMT": "$(rlocationpath //rust/toolchain:current_rustfmt_toolchain_for_target)",
},
toolchains = ["@rules_rust//rust/toolchain:current_rust_toolchain"],
actual = "//tools/upstream_wrapper:rustfmt",
deprecation = "Prefer //tools/upstream_wrapper:rustfmt",
visibility = ["//visibility:public"],
deps = [
"//tools/runfiles",
],
)

View File

@ -1,38 +0,0 @@
use std::path::PathBuf;
use std::process::{exit, Command};
fn main() {
let runfiles = runfiles::Runfiles::create().unwrap();
let rustfmt = runfiles::rlocation!(runfiles, env!("RUSTFMT"));
if !rustfmt.exists() {
panic!("rustfmt does not exist at: {}", rustfmt.display());
}
let working_directory = std::env::var_os("BUILD_WORKING_DIRECTORY")
.map(PathBuf::from)
.unwrap_or_else(|| std::env::current_dir().expect("Failed to get working directory"));
let status = Command::new(rustfmt)
.current_dir(&working_directory)
.args(std::env::args_os().skip(1))
.status()
.expect("Failed to run rustfmt");
if let Some(exit_code) = status.code() {
exit(exit_code);
}
exit_for_signal(&status);
panic!("Child rustfmt process didn't exit or get a signal - don't know how to handle it");
}
#[cfg(target_family = "unix")]
fn exit_for_signal(status: &std::process::ExitStatus) {
use std::os::unix::process::ExitStatusExt;
if let Some(signal) = status.signal() {
exit(signal);
}
}
#[cfg(not(target_family = "unix"))]
#[allow(unused)]
fn exit_for_signal(status: &std::process::ExitStatus) {}

View File

@ -0,0 +1,33 @@
load("//rust:defs.bzl", "rust_binary")
tools = {
"cargo": "//rust/toolchain:current_cargo_files",
"cargo_clippy": "//rust/toolchain:current_cargo_clippy_files",
"rustc": "//rust/toolchain:current_rustc_files",
"rustfmt": "//rust/toolchain:current_rustfmt_toolchain_for_target",
}
all_tools = [target for target in tools.values()]
[
rust_binary(
name = tool_name,
srcs = [
"src/main.rs",
],
# Cargo calls out to the other tools.
# Make sure that they are included in the runfiles.
data = all_tools if tool_name == "cargo" else [target],
edition = "2018",
rustc_env = {
"WRAPPED_TOOL_NAME": tool_name,
"WRAPPED_TOOL_TARGET": "$(rlocationpath {})".format(target),
},
toolchains = ["@rules_rust//rust/toolchain:current_rust_toolchain"],
visibility = ["//visibility:public"],
deps = [
"//tools/runfiles",
],
)
for (tool_name, target) in tools.items()
]

View File

@ -0,0 +1,15 @@
# upstream_wrapper
Wrap the binaries from the current toolchain so that
they can be easily invoked with `bazel run`:
```bash
bazel run @rules_rust//tools/upstream_wrapper:cargo
bazel run @rules_rust//tools/upstream_wrapper:cargo -- clippy
bazel run @rules_rust//tools/upstream_wrapper:cargo -- fmt
bazel run @rules_rust//tools/upstream_wrapper:rustc -- main.rs
bazel run @rules_rust//tools/upstream_wrapper:rustfmt
```
Alternatively, look at the [bazel_env example](../../examples/bazel_env/)
to include them in the users path with direnv.

View File

@ -0,0 +1,59 @@
use std::ffi::OsString;
use std::path::PathBuf;
use std::process::{exit, Command};
const WRAPPED_TOOL_NAME: &str = env!("WRAPPED_TOOL_NAME");
const WRAPPED_TOOL_TARGET: &str = env!("WRAPPED_TOOL_TARGET");
#[cfg(not(target_os = "windows"))]
const PATH_SEPARATOR: &str = ":";
#[cfg(target_os = "windows")]
const PATH_SEPARATOR: &str = ";";
fn main() {
let runfiles = runfiles::Runfiles::create().unwrap();
let wrapped_tool_path = runfiles::rlocation!(runfiles, WRAPPED_TOOL_TARGET);
if !wrapped_tool_path.exists() {
panic!(
"{WRAPPED_TOOL_NAME} does not exist at: {}",
wrapped_tool_path.display()
);
}
let tool_directory = wrapped_tool_path
.parent()
.expect("parent directory of tool binary");
let old_path = std::env::var_os("PATH").unwrap_or_default();
let mut new_path = OsString::from(tool_directory);
new_path.push(PATH_SEPARATOR);
new_path.push(&old_path);
let working_directory = std::env::var_os("BUILD_WORKING_DIRECTORY")
.map(PathBuf::from)
.unwrap_or_else(|| std::env::current_dir().expect("Failed to get working directory"));
let status = Command::new(wrapped_tool_path)
.current_dir(&working_directory)
.args(std::env::args_os().skip(1))
.env("PATH", new_path)
.status()
.unwrap_or_else(|e| panic!("Failed to run {WRAPPED_TOOL_NAME} {:#}", e));
if let Some(exit_code) = status.code() {
exit(exit_code);
}
exit_for_signal(&status);
panic!("Child rustfmt process didn't exit or get a signal - don't know how to handle it");
}
#[cfg(target_family = "unix")]
fn exit_for_signal(status: &std::process::ExitStatus) {
use std::os::unix::process::ExitStatusExt;
if let Some(signal) = status.signal() {
exit(signal);
}
}
#[cfg(not(target_family = "unix"))]
#[allow(unused)]
fn exit_for_signal(status: &std::process::ExitStatus) {}