Squashed 'third_party/rules_rust/' changes from 078c6908f..bf9ddeb7c
bf9ddeb7c Release 0.25.1 (#2049)
db5b2fd65 Update tinyjson (#2050)
6a7872ae3 Fix prost proto packages not sanitizing to valid module names (#2044)
c080d7bfa Moved legacy protobuf rules to `proto/protobuf` (#2043)
1281cc051 Remove debug code. (#2048)
cd126be1f Fix build failure finding crate_roots when mixed with generated sources (#2041)
7f751cddd Consolidate rust_prost_library and fix extension-only proto generation. (#2047)
6118c81f2 Release 0.25.0 (#2042)
a6f29fd07 Add Prost and Tonic rules. (#2033)
9442aed8c fix: `crate_type` more accurately corresponds to CC linking actions (#1975)
4f4e2b17b Re-enable zig example on CI (#2030)
2ded0c2f5 Fix flaky coverage test in CI (#2028)
36f8251f9 Exclude .tmp_git_root from globs (#1948)
ca750fa83 Eliminate Rustfmt action in Bindgen rules. Bindgen can run rustfmt (#2025)
c55ec0cfb Allow sysroots from cc_toolchains to be added to bindgen actions (#2024)
9314b1b0c Release 0.24.1 (#2023)
92ea74ade Making rust_std attr in rust_toolchain mandatory (#1984)
a54b8e14b Update `rust_library_group` to use `DepVariantInfo` (#2022)
47644346b Release v0.24.0 (#2020)
a6b0a7f39 Rust library group (#1848)
bc43f4841 Fix crate_universe's `all_crate_deps` and `aliases` functions failing in case the crate's Cargo.toml has condtional dependencies (#2018)
8f27ec7c5 fix: load cargo manifest without resolving abs path of deps (#2017)
23f99bb63 feature: `target_compatible_with` added to `CommonAttrs` (#1976)
11f8c9875 Make `rust_doc_test` inherit it's crate aliases attribute (#2007)
8e848414d Regenerated crate_universe outputs for all packages (#2011)
1b6365131 Don't use startup:windows (#2012)
e80582e75 Fix thumbv* platform resolution (#2010)
367f90ef0 Update bindgen version to 0.65.1 (#2008)
e6ed5bf90 Release 0.23.0 (#2003)
93b230bb8 Fix code coverage collection. (#2001)
0a14bfbb0 Minor CI and test cleanup (#2004)
3e2ee941a Update bindgen rules to build clang from source. (#1998)
5a1a7577d Split up cargo_build_script tests (#2002)
eb6413e83 Update various bash scripts to pipe errors to stderr (#1999)
affe947ac Update stardoc version (#1997)
7073146f8 Add support for armv8-m (#1993)
73a06f130 Added Rust 1.70.0 (#1991)
23c20a93f Fixes crates_vendor workspace name detection when using bzlmod (#1990)
f5813fa08 Set windows flags in platform-specific bazelrc (#1988)
c1632b5b5 Fix up anchor link (#1987)
56e760487 Fix typo in crate_universe-generated defs.bzl comment (#1981)
94cbe4c2c Symlink in the exec-root so that relative paths will work, unchanged. (#1781)
af8ef62eb Release 0.22.0 (#1974)
4aaa6de30 Allow specifying exec and target compatibility constraints (#1971)
f1b19c394 Update rules_apple in tests (#1972)
937e63399 Add T2 support for x86_64-unknown-none (#1967)
66b1bf165 fix: lld-link (MSVC) fix flags including `-l` prefix (#1958)
285dcbbb9 feature: expose `extra_rustc_flags` and `extra_exec_rustc_flags` at `rust_register_toolchains` (#1959)
0f25cb462 Removed `rust_toolchain.os` in favor of `rust_toolchain.exec_triple`. (#1960)
a2a1109dc Add T2 support for thumbv7em-none-eabi (#1957)
80f0eb488 Support for `no_std` mode (#1934)
99aaf0830 Rename crates_vendor_manifests to cvm to shorten windows path lengths (#1944)
0a57da049 Added tests for build script dependencies to crate_universe (#1943)
caffb0a08 Release 0.21.1 (#1936)
c869a17c7 Fix regression in building zlib (#1935)
24b9dea4f Release 0.21.0 (#1933)
7677c617e Add support for rustc flags to `rust_proto_library` (#1932)
fa304ae48 Updated zlib BUILD file to support darwin-arm64 (#1931)
a86313282 Added Rust 1.69.0 (#1930)
f0e12c707 Make BuildInfo provider public (#1920)
c6ad23aba Respect `#[global_allocator]` in `cc_common.link` builds (#1926)
d78752504 Exclude target directory from release tars (#1922)
0339cd18a [wasm-bindgen] Update to v0.2.84 (#1919)
07af5678e Handle corner case for windows architecture detection (#1915)
c56e7660d Fix optional deps by platform (#1911)
4663ff6a3 cc_common_link: also respect --custom_malloc if set (#1912)
dab425760 Add Rust 1.68.2 (#1908)
e4bd39f95 Add empty rustfmt.toml (#1907)
eaf513865 Support bzlmod (#1528)
1074ecbab Release v0.20.0 (#1900)
44aec0a79 ci: fix test config in cc_common_link_ubuntu2004 (#1904)
6571cde64 Adds per_crate_rustc_flag build setting. (#1827)
7a47449df Added Rust 1.68.1 (#1898)
e3bcdbad1 Fixed rustdoc warnings in crate_universe (#1897)
529f45900 Added `rustdoc_flags` attribute to rust_doc rule (#1867)
9e3499405 Have rustdoc return its output directory instead of zip default. (#1868)
9d6741f40 Implement support for optional crates enabled with dep: features (#1885)
fd10963ea Skip adding -lstatic to libtest and libstd on Darwin (#1620)
b3314b45e Release 0.19.1 (#1895)
c1a9fd86f Accumulate all features from cargo tree output (#1884)
206f71c95 Disable zig example (#1893)
1a5d07cd2 Add runfiles support to rust_stdlib_filegroup (#1890)
6996cd550 Deleted unused targets and cleanup docs (#1889)
a85e24e20 Fix triple constraints for iOS and watchOS (#1888)
e13fd3bad Release rules_rust and cargo-bazel (#1882)
9e9853d63 Add support for thumbv7em with hard float (#1871)
b3cd5962e Added Rust 1.68.0 (#1866)
f1b7aedf5 Support sparse indexes (#1857)
7f2dd433a Make fetch_shas work with mktemp from coreutils 8.32 (#1870)
a9cc01230 Update crate_universe dependencies (#1872)
c038e94ae Pipe stderr from cargo tree processes (#1879)
222d60322 Parallelize cargo tree calls (#1874)
cdbbf7131 Add Fuchsia platform support (#1833)
17e5b04c2 Use `_make_link_flags_darwin` when target os is `ios`. (#1843)
d9ecc8df4 crate_universe: Support fetching crates with git branch, tag or rev (#1846)
1c694cd60 Forward `toolchains` to `cargo_build_script` targets (#1862)
9affcbfa7 Skip detecting abi for empty values (#1830)
6193fe823 Re-enable crate_universe MacOS tests (#1861)
c25db95ae Updated Rust to 1.67.1 (#1864)
7b8fd06be Support `[patch]` in crate_universe when using multiple `Cargo.toml`s (#1856)
c645fe399 Silence windows build failure (#1863)
75bba7b50 Make rust_clippy providers match rustfmt_test (#1806)
f09d72755 Fix test assertion for arm64 macs (#1845)
f4113bfe1 Fix tests for new Apple toolchain (#1844)
20ce44e30 fix: use target_triple struct instead of string (#1835)
bdbded181 Fix code example in doc (#1838)
4f4014052 Fix typo: plced -> placed (#1834)
baeb0664d Remove ios/android/wasm support for gen_rust_project deps (#1684)
02557a47a Add `render_config` attribute to `crates_vendor`. (#1832)
4357fb154 Updated rules_rust to version 0.18.0 (#1829)
9adfdca9b Various cleanups (#1828)
4fa412385 Added update known shas to include T1-T2 triples (#1824)
905731ad9 Instructions on how to perform `rustfmt` check (#1822) (#1823)
108b1a187 Encapsulate running cargo into a struct (#1815)
57a099b63 Fixes resolver issue with root packages and another dependency format (#1819)
78ca9ba0a Use env method recently added to cargo_metadata (#1813)
92834930f Updated `rust_toolchain.target_json` to take encoded json strings (#1810)
84f1d0657 support `resolver = "2"` target-specific features (#1710)
a5853fd37 Use correct dynamic link args fro proc-macro crates (#1803)
b656e2553 Added tests for the `triple` constructor (#1811)
ea4a79ad9 Disable job in CI to avoid infrastructure failure. (#1816)
2fc02f030 Delete `rust_toolchain.rusrc_srcs` (#1807)
804d5fc1f Convert `rust_toolchain` attrs `exec_triple` and `target_triple` to structs (#1808)
499a2ca38 Updated platform triple values from strings to structs ("triple") (#1804)
aae1dbdcb Unify functions for computing constraint values for platform triple abi (#1805)
0d6d2b1eb Updated rules_rust version to `0.17.0` (#1800)
88e83f2df Added Rust 1.67.0 (#1799)
6922b5012 rustdoc_test: fix and test OUT_DIR (#1779)
ad01d1b0e [crate_universe] add an annotation to disable pipelining (#1733)
f651cd18f Add `CARGO_BAZEL_REPIN_ONLY` repinning allowlist (#1798)
d7f0debb0 Revert "Disable broken clang and ldd CI jobs (#1785)" (#1796)
96f82aaad Fix `cc_common.link` file output name (#1795)
5079b64d5 Fix use of `rustfmt_toolchain` when `rustc` is not provided (#1794)
23c650f35 Have `--experimental_use_cc_common_link` cover `rust_shared_library` (#1792)
ba0fb5956 Added support for `--nolegacy_external_runfiles` to `rust_doc_test` (#1790)
112242bb7 Prevent crates_vendor from restarting bazel. (#1791)
52231ef9f Added compatibility flags to `.bazelrc` to prevent regressions (#1789)
91cd399a0 Add "crate-name={}" tag to Crate Universe targets (#1787)
1b1dae196 Added Rust 1.66.1 (#1767)
fe17e8b8e Add file:// prefix to env var in docs (#1788)
0fe742bff Updated `rust_bindgen` to use `rustfmt_toolchain` (#1770)
042fd6c1c Update docs on setting Rust versions (#1786)
dddd8a0d4 Updated crate_universe dependencies (#1775)
a1330a71f Download `rustc` in `rustfmt_toolchain_repository` (#1769)
e96aad9aa Updated the ios_build example to use `crates_vendor` (#1778)
e315007df Disable broken clang and ldd CI jobs (#1785)
4e89d52a9 rustdoc_test: substitute the root of the current crate (#1777)
a52041fb5 Support `target_settings` in `rust_repository_set` and `rust_toolchain_repository` (#1758)
49906eb29 Update clippy and rustfmt aspects to require CrateInfo providers (#1772)
85564208e Updated rules_rust version to `0.16.1` (#1761)
614499a5b Fixed inability to deserialize crate_universe lockfiles (#1760)
9803d3034 Fix data and compile_data for rust_doc (#1741)
927a364cb Update Release github pipeline to trigger automatically (#1757)
7d03e05f8 Fix release pipeline (#1756)
cf7ca5dfd Updated rules_rust to version `0.16.0` (#1750)
203fe4b9a Remove unnecessary binary file (#1755)
941c7cca9 Don't propagate `compatible_with` to the underlying `cargo_build_script` `rust_binary` target (#1754)
a31490d9a Make loads from @rules_rust//rust:defs.bzl come out on one line (#1753)
7ebad4d50 Generate only the needed subset of binaries for bindgen and proto (#1751)
4ef3d4aaa Repin examples/crate_universe_unnamed (#1752)
d6e300359 Regenerate BUILD files using serde_starlark renderer (#1746)
e7c8a97d1 Convert BUILD.$name-$version.bazel to serde_starlark (#1743)
c09818d3b Exclude generated files from language stats and collapse in code review (#1747)
26a24f030 Added CI for single toolchain channel workspaces (#1712)
caed7d814 Report context on error failing to get version (#1744)
36b57af7b Add gen_binaries annotation to control which bins to make target for (#1718)
d916a6f52 crate_universe re-pinning now defaults to "workspace" (#1723)
f34661ee1 Propagate `compatible_with` attribute to the underlying `_build_script_run` target (#1745)
92977d1bf Re-pinned all dependencies managed by crate_universe (#1735)
d5289ad1c Added `rustfmt_toolchain` and refactored toolchain repository rules (#1719)
532e60ff0 Collect targets in a deterministic order (#1736)
52e02c25b Eliminate all use of hash-based collections from crate_universe (#1737)
31073ff8e Replace tera template with serde_starlark (#1734)
d4e5586d0 Support the RUNFILES_DIR environment variable. (#1732)
1357b85b1 Addressed clippy warnings from `clippy 0.1.67 (ec56537c 2022-12-15)` (#1717)
8bc9f788d Support dsym_folder output group in tests (#1703)
90c5b6eb7 Added CI for minimum supported Rust version (#1720)
be82ff8bd Match prerelease versions with annotation wildcard (#1716)
36c7f285b Arm Thumb Embedded Targets. (#1721)
5ef52e465 Update current_toolchain_files tests to use a dedicated test rule (#1714)
c75ea6f9e Add `Runfiles::current_repository` to runfiles library (#1713)
2f0511782 Updated rules_rust to version `0.15.0` (#1706)
019f87178 Added Rust 1.66.0 (#1705)
1469cd7cb Fix labels to work with canonical label literals. (#1700)
5826a500a Add riscv32imc and riscv64gc to the known sha targets (#1698)
40dee95ce Fixed typos: normla -> normal (#1699)
8f08e77ac load_arbitrary_tool uses tool_suburl to look up sha256 (#1695)
8faec3060 Fix typos in crate_universe rendered comments (#1691)
bd64711ff Silence flaky test (#1693)
46b7ea5af Added a build setting for toolchain channels (#1671)
70b272aad Updated rules_rust to version `0.14.0` (#1669)
91e597dd1 Updated all crates_vendor outputs (#1687)
9a047b0b9 Updated crate_universe dependencies (#1686)
3a91d2f5b Add RV64GC target (#1683)
d9e752ab4 Add per-toolchain `rustc_flags` (#1635)
56237415e stardoc: Use backtick not `<code>` for attr default values (#1682)
d4b31a494 Allow passing a bazel path to vendor explicitly (#1661)
d51bf9ce0 Updated crate_universe to work with `--nolegacy_external_runfiles` (#1680)
7f40636d1 crate_universe/private/crates_vendor.bzl typo fix (#1678)
025bf7db8 Merge cc toolchain flags into build script env (#1675)
b7c36c051 Fix confusing/misleading crate_universe docs (#1677)
29233e354 Revert #1564 (#1663)
ed32b6de2 Common glob excludes (#1673)
61b99cdd1 fix: add space to crate data exclude list (#1665)
8bb25b8b7 Support Windows ARM64 (aarch64-pc-windows-msvc) (#1664)
ddf2a4c23 Re-render crate BUILD files after #1647 (#1655)
44c7e1588 Group deps and aliases by platform triple rather than by cfg string when generating BUILD files. This avoid bazel errors due to duplicate keys/deps. (#1647)
de18d8bb6 Allow `buildifier` attribute to be a file (#1660)
aa0815dc9 Fix naming of ambiguous libs (#1625)
ff314d4ab Also pass -c opt to tests in opt mode CI (#1626)
ff4e90515 Reenable windows job (#1658)
c45b8e91f Updated rules_rust to version `0.13.0` (#1644)
87d6b6c37 Update `//util/label` to support `+` in packages (#1654)
ab6959db5 fix: Fix issue with wasi-0.11.0+wasi-snapshot-preview1 (#1632)
28c090ed0 Replaced custom platform constraint values with aliases to `@platforms` (#1652)
dfbea4f52 Deprecated `rust_toolchain.rustc_srcs` (#1653)
fd1db4391 Remove deprecated attributes from rust_toolchain and cargo_bootstrap (#1651)
c8ab970c4 Generated rust-project.json files now include sysroot paths (#1641)
0a3e04cf9 Fix vendoring when not in a package (#1646)
aece1e37d Deduplicate expand_location targets in rust-project.json crate creation to avoid a bazel crash (#1639)
03a0b2483 [docs] Fixing typos in CargoConfig doc strings (#1638)
bd4fd2ac5 Upgraded cfg-expr dependency to 0.12.0. (#1636)
330554a13 Disable failing job in CI (#1640)
849f106e6 Consider compilation mode when choosing `pic`/`nopic` object files to link (#1624)
53491d719 Updated rules_rust to version `0.12.0` (#1630)
8e8843724 Remove empty glob (#1628)
1f621a944 Added Rust 1.65.0 (#1627)
c6af4d025 Add `-c opt` mode to CI (#1621)
95320cc8b process_wrapper: print line on error to parse message as json (#1566)
81eaccf39 Fixed CI breakage (#1619)
478fc3a57 Fix ambiguous native dependencies in `proc_macro`s and `staticlib`s (#1611)
9e3d8415e Build deps of _build_script_run in 'exec' mode (#1561)
ea031082b Fixed outdated docs (#1614)
a8c540e49 Restore support for old cargo_build_script load statements (#1613)
295b5ccc7 Renamed `_build_script_run` rule to `cargo_build_script` (#1612)
3778069ec Remove references to Google mirror in docs (#1607)
aad54ba29 Updated crate_universe dependencies (#1606)
c349df2a6 Remove Google mirror from Starlark snippet in release notes (#1604)
0493b998d Avoid rendering a mock root package when possible (#1596)
b04aa053c process_wrapper: Apply substitutions to param files (#1565)
b209b3e15 Updated rules_rust to version `0.11.0`. (#1587)
b1079453b Typo correction on doc (#1593)
ca5678266 Updated crate_universe dependencies (#1591)
a364d448f Fixes crates_vendor labels in remote mode when used from the root workspace (#1575)
1cc37c268 Expose the output directory from cargo_build_script (#1588)
7ffe0a555 Ignore non-utf8 text in build script output (#1583)
c5b38fe00 Merge runfiles from transitive dependencies of rust_test crate attr (#1487)
da3d522d5 Fix build scripts targeting the wrong architecture (#1564)
d288ed634 Add `out_dir` support in `cargo_dep_env` (#1571)
78d6c1b46 fix: incorrect rustfmt edition query (#1582)
48927127e Set CARGO_MANIFEST_DIR at runtime for tests (#1559)
76bd69033 Add an output group for the .rmeta (#1585)
352bfeb05 Cleanup deprecated code (#1577)
86dc561f9 Move crate_root_src to utils (#1570)
beb554eb9 update to wasm-bindgen v0.2.83 (#1567)
73fd1616b Export AbsoluteLabel functionality (#1568)
c57e7a399 Remap $PWD to empty string instead of "." (#1563)
f0cdcedc2 Added Rust 1.64.0 (#1562)
1d326554a Update docs to show release policies and support (#1560)
78c793a0a Fix markdown typo in rust_analyzer.md (#1553)
c13980fb6 Add iOS examples (#1546)
8a5e07e9f Update apple_support (#1549)
6dacd9803 Strip leading '@'s for labels in the splicing manifest (#1547)
f73d1d6fb use crate_info.deps in establish_cc_info (#1543)
4845af6c0 Add android example (#1545)
9570b7aa7 Remove -lgcc from Android builds (#1541)
cb9ca1b81 Fix crate_universe/private/srcs.bzl to work with repo mappings (#1540)
d1fc9accc Minor cleanup of CI pipelines (#1534)
2bb077b3b Updated rules_rust to version 0.10.0 (#1533)
b8751b860 add cc config info to dummy wasm32 cc toolchain (#1532)
f5ed797ee Updates rust_test to use main.rs as the root when use_libtest_harness is false (#1518)
cfcaf21d5 Preserve directory structure of source files when some are generated (#1526)
51c065841 migrating to rbe_preconfig and remove bazel_toolchains (#1524)
055abd402 Fix typo in an example of crates_repository rule (#1520)
8bfed1cd2 Added Rust 1.63.0 (#1512)
3a69ce09b Update wasm_bindgen to 0.2.82 (#1513)
git-subtree-dir: third_party/rules_rust
git-subtree-split: bf9ddeb7c83a9fe8a7d87c76134cdd8e16131b62
Signed-off-by: Adam Snaider <adsnaider@gmail.com>
Change-Id: Id9490c68d6221da66953a915a25042ef8b848505
diff --git a/rust/private/BUILD.bazel b/rust/private/BUILD.bazel
index d175b28..3c963cd 100644
--- a/rust/private/BUILD.bazel
+++ b/rust/private/BUILD.bazel
@@ -1,6 +1,5 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("//rust/private:rust_analyzer.bzl", "rust_analyzer_detect_sysroot")
-load("//rust/private:rustfmt.bzl", "rustfmt_workspace_name")
load("//rust/private:stamp.bzl", "stamp_build_setting")
bzl_library(
@@ -16,8 +15,3 @@
name = "rust_analyzer_detect_sysroot",
visibility = ["//visibility:public"],
)
-
-rustfmt_workspace_name(
- name = "rustfmt_workspace_name",
- visibility = ["//visibility:public"],
-)
diff --git a/rust/private/clippy.bzl b/rust/private/clippy.bzl
index 21f3965..d01c13d 100644
--- a/rust/private/clippy.bzl
+++ b/rust/private/clippy.bzl
@@ -45,7 +45,7 @@
build_setting = config.string_list(flag = True),
)
-def _get_clippy_ready_crate_info(target, aspect_ctx):
+def _get_clippy_ready_crate_info(target, aspect_ctx = None):
"""Check that a target is suitable for clippy and extract the `CrateInfo` provider from it.
Args:
@@ -72,11 +72,13 @@
return None
# Obviously ignore any targets that don't contain `CrateInfo`
- if rust_common.crate_info not in target:
+ if rust_common.crate_info in target:
+ return target[rust_common.crate_info]
+ elif rust_common.test_crate_info in target:
+ return target[rust_common.test_crate_info].crate
+ else:
return None
- return target[rust_common.crate_info]
-
def _clippy_aspect_impl(target, ctx):
crate_info = _get_clippy_ready_crate_info(target, ctx)
if not crate_info:
@@ -215,8 +217,12 @@
doc = "The desired `--error-format` flags for clippy",
default = "//:error_format",
),
- "_extra_rustc_flag": attr.label(default = "//:extra_rustc_flag"),
- "_extra_rustc_flags": attr.label(default = "//:extra_rustc_flags"),
+ "_extra_rustc_flag": attr.label(
+ default = Label("//:extra_rustc_flag"),
+ ),
+ "_per_crate_rustc_flag": attr.label(
+ default = Label("//:experimental_per_crate_rustc_flag"),
+ ),
"_process_wrapper": attr.label(
doc = "A process wrapper for running clippy on all platforms",
default = Label("//util/process_wrapper"),
@@ -225,6 +231,10 @@
),
},
provides = [ClippyInfo],
+ required_providers = [
+ [rust_common.crate_info],
+ [rust_common.test_crate_info],
+ ],
toolchains = [
str(Label("//rust:toolchain_type")),
"@bazel_tools//tools/cpp:toolchain_type",
@@ -272,7 +282,10 @@
attrs = {
"deps": attr.label_list(
doc = "Rust targets to run clippy on.",
- providers = [rust_common.crate_info],
+ providers = [
+ [rust_common.crate_info],
+ [rust_common.test_crate_info],
+ ],
aspects = [rust_clippy_aspect],
),
},
diff --git a/rust/private/common.bzl b/rust/private/common.bzl
index 025c4d7..f6063a0 100644
--- a/rust/private/common.bzl
+++ b/rust/private/common.bzl
@@ -23,7 +23,7 @@
In the Bazel lingo, `rust_common` gives the access to the Rust Sandwich API.
"""
-load(":providers.bzl", "CrateInfo", "DepInfo", "StdLibInfo", "TestCrateInfo")
+load(":providers.bzl", "CrateGroupInfo", "CrateInfo", "DepInfo", "DepVariantInfo", "StdLibInfo", "TestCrateInfo")
# This constant only represents the default value for attributes and macros
# defined in `rules_rust`. Like any attribute public attribute, it can be
@@ -31,7 +31,9 @@
#
# Note: Code in `.github/workflows/crate_universe.yaml` looks for this line, if
# you remove it or change its format, you will also need to update that code.
-DEFAULT_RUST_VERSION = "1.62.1"
+DEFAULT_RUST_VERSION = "1.70.0"
+
+DEFAULT_NIGHTLY_ISO_DATE = "2023-06-01"
def _create_crate_info(**kwargs):
"""A constructor for a `CrateInfo` provider
@@ -57,7 +59,9 @@
create_crate_info = _create_crate_info,
crate_info = CrateInfo,
dep_info = DepInfo,
+ dep_variant_info = DepVariantInfo,
stdlib_info = StdLibInfo,
test_crate_info = TestCrateInfo,
+ crate_group_info = CrateGroupInfo,
default_version = DEFAULT_RUST_VERSION,
)
diff --git a/rust/private/dummy_cc_toolchain/BUILD.bazel b/rust/private/dummy_cc_toolchain/BUILD.bazel
index 004d233..848480f 100644
--- a/rust/private/dummy_cc_toolchain/BUILD.bazel
+++ b/rust/private/dummy_cc_toolchain/BUILD.bazel
@@ -1,4 +1,5 @@
-load(":dummy_cc_toolchain.bzl", "dummy_cc_toolchain")
+load("@rules_cc//cc:defs.bzl", "cc_toolchain")
+load(":dummy_cc_toolchain.bzl", "dummy_cc_config", "dummy_cc_toolchain")
dummy_cc_toolchain(name = "dummy_cc_wasm32")
@@ -8,6 +9,29 @@
toolchain(
name = "dummy_cc_wasm32_toolchain",
target_compatible_with = ["//rust/platform/cpu:wasm32"],
- toolchain = ":dummy_cc_wasm32",
+ toolchain = ":dummy_cc_wasm32_toolchain_cc",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
+
+cc_toolchain(
+ name = "dummy_cc_wasm32_toolchain_cc",
+ all_files = ":empty",
+ compiler_files = ":empty",
+ dwp_files = ":empty",
+ linker_files = ":empty",
+ objcopy_files = ":empty",
+ strip_files = ":empty",
+ supports_param_files = 0,
+ toolchain_config = ":cc_toolchain_config",
+ toolchain_identifier = "dummy_wasm32_cc",
+)
+
+dummy_cc_config(
+ name = "cc_toolchain_config",
+)
+
+filegroup(
+ name = "empty",
+ srcs = [],
+ visibility = ["//:__subpackages__"],
+)
diff --git a/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl b/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
index 8ca8c8f..8cbf617 100644
--- a/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
+++ b/rust/private/dummy_cc_toolchain/dummy_cc_toolchain.bzl
@@ -1,4 +1,5 @@
-# buildifier: disable=module-docstring
+"""Cc toolchain definitions for use on wasm platforms"""
+
def _dummy_cc_toolchain_impl(_ctx):
# The `all_files` attribute is referenced by rustc_compile_action().
return [platform_common.ToolchainInfo(all_files = depset([]))]
@@ -7,3 +8,23 @@
implementation = _dummy_cc_toolchain_impl,
attrs = {},
)
+
+# dummy values from https://bazel.build/tutorials/ccp-toolchain-config#configuring_the_c_toolchain
+def _config_impl(ctx):
+ return cc_common.create_cc_toolchain_config_info(
+ ctx = ctx,
+ toolchain_identifier = "dummy-wasm32-cc-toolchain",
+ host_system_name = "unknown",
+ target_system_name = "unknown",
+ target_cpu = "unknown",
+ target_libc = "unknown",
+ compiler = "unknown",
+ abi_version = "unknown",
+ abi_libc_version = "unknown",
+ )
+
+dummy_cc_config = rule(
+ implementation = _config_impl,
+ attrs = {},
+ provides = [CcToolchainConfigInfo],
+)
diff --git a/rust/private/extensions.bzl b/rust/private/extensions.bzl
new file mode 100644
index 0000000..05f9076
--- /dev/null
+++ b/rust/private/extensions.bzl
@@ -0,0 +1,12 @@
+"""Bzlmod module extensions that are only used internally"""
+
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("//rust/private:repository_utils.bzl", "TINYJSON_KWARGS")
+
+def _internal_deps_impl(_module_ctx):
+ http_archive(**TINYJSON_KWARGS)
+
+internal_deps = module_extension(
+ doc = "Dependencies for rules_rust",
+ implementation = _internal_deps_impl,
+)
diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl
index 464444b..b26cc67 100644
--- a/rust/private/providers.bzl
+++ b/rust/private/providers.bzl
@@ -19,6 +19,7 @@
fields = {
"aliases": "Dict[Label, String]: Renamed and aliased crates",
"compile_data": "depset[File]: Compile data required by this crate.",
+ "compile_data_targets": "depset[Label]: Compile data targets required by this crate.",
"deps": "depset[DepVariantInfo]: This crate's (rust or cc) dependencies' providers.",
"edition": "str: The edition of this crate.",
"is_test": "bool: If the crate is being compiled in a test context",
@@ -56,6 +57,13 @@
},
)
+CrateGroupInfo = provider(
+ doc = "A provider containing a group of crates.",
+ fields = {
+ "dep_variant_infos": "depset[DepVariantInfo]: Dependency information from all crates in the group.",
+ },
+)
+
BuildInfo = provider(
doc = "A provider containing `rustc` build settings for a given Crate.",
fields = {
@@ -71,11 +79,13 @@
DepVariantInfo = provider(
doc = "A wrapper provider for a dependency of a crate. The dependency can be a Rust " +
"dependency, in which case the `crate_info` and `dep_info` fields will be populated, " +
- "a Rust build script dependency, in which case `build_info` will be populated, or a " +
- "C/C++ dependency, in which case `cc_info` will be populated.",
+ "a Rust build script dependency, in which case `build_info` will be populated, a C/C++" +
+ "dependency, in which case `cc_info` will be populated, or a Rust crate group, in which" +
+ "case `crate_group_info` will be populated.",
fields = {
"build_info": "BuildInfo: The BuildInfo of a Rust dependency",
"cc_info": "CcInfo: The CcInfo of a C/C++ dependency",
+ "crate_group_info": "CrateGroupInfo: The CrateGroupInfo of a Rust crate group dependency",
"crate_info": "CrateInfo: The CrateInfo of a Rust dependency",
"dep_info": "DepInfo: The DepInfo of a Rust dependency",
},
@@ -93,6 +103,7 @@
"core_files": "List[File]: `.a` files related to the `core` and `adler` modules",
"dot_a_files": "Depset[File]: Generated `.a` files",
"memchr_files": "Depset[File]: `.a` files associated with the `memchr` module.",
+ "panic_files": "Depset[File]: `.a` files associated with `panic_unwind` and `panic_abort`.",
"self_contained_files": "List[File]: All `.o` files from the `self-contained` directory.",
"srcs": "List[Target]: All targets from the original `srcs` attribute.",
"std_files": "Depset[File]: `.a` files associated with the `std` module.",
diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl
index 86d3f78..1f5a01a 100644
--- a/rust/private/repository_utils.bzl
+++ b/rust/private/repository_utils.bzl
@@ -7,11 +7,22 @@
"system_to_dylib_ext",
"system_to_staticlib_ext",
"system_to_stdlib_linkflags",
- "triple_to_system",
)
+load("//rust/private:common.bzl", "DEFAULT_NIGHTLY_ISO_DATE")
DEFAULT_TOOLCHAIN_NAME_PREFIX = "toolchain_for"
DEFAULT_STATIC_RUST_URL_TEMPLATES = ["https://static.rust-lang.org/dist/{}.tar.gz"]
+DEFAULT_NIGHTLY_VERSION = "nightly/{}".format(DEFAULT_NIGHTLY_ISO_DATE)
+DEFAULT_EXTRA_TARGET_TRIPLES = ["wasm32-unknown-unknown", "wasm32-wasi"]
+
+TINYJSON_KWARGS = dict(
+ name = "rules_rust_tinyjson",
+ sha256 = "9ab95735ea2c8fd51154d01e39cf13912a78071c2d89abc49a7ef102a7dd725a",
+ url = "https://crates.io/api/v1/crates/tinyjson/2.5.1/download",
+ strip_prefix = "tinyjson-2.5.1",
+ type = "tar.gz",
+ build_file = "@rules_rust//util/process_wrapper:BUILD.tinyjson.bazel",
+)
_build_file_for_compiler_template = """\
filegroup(
@@ -51,12 +62,11 @@
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
return _build_file_for_compiler_template.format(
- binary_ext = system_to_binary_ext(system),
- staticlib_ext = system_to_staticlib_ext(system),
- dylib_ext = system_to_dylib_ext(system),
- target_triple = target_triple,
+ binary_ext = system_to_binary_ext(target_triple.system),
+ staticlib_ext = system_to_staticlib_ext(target_triple.system),
+ dylib_ext = system_to_dylib_ext(target_triple.system),
+ target_triple = target_triple.str,
)
_build_file_for_cargo_template = """\
@@ -75,9 +85,8 @@
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
return _build_file_for_cargo_template.format(
- binary_ext = system_to_binary_ext(system),
+ binary_ext = system_to_binary_ext(target_triple.system),
)
_build_file_for_rustfmt_template = """\
@@ -103,9 +112,8 @@
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
return _build_file_for_rustfmt_template.format(
- binary_ext = system_to_binary_ext(system),
+ binary_ext = system_to_binary_ext(target_triple.system),
)
_build_file_for_clippy_template = """\
@@ -116,6 +124,26 @@
)
"""
+_build_file_for_rust_analyzer_proc_macro_srv = """\
+filegroup(
+ name = "rust_analyzer_proc_macro_srv",
+ srcs = ["libexec/rust-analyzer-proc-macro-srv{binary_ext}"],
+ visibility = ["//visibility:public"],
+)
+"""
+
+def BUILD_for_rust_analyzer_proc_macro_srv(exec_triple):
+ """Emits a BUILD file the rust_analyzer_proc_macro_srv archive.
+
+ Args:
+ exec_triple (str): The triple of the exec platform
+ Returns:
+ str: The contents of a BUILD file
+ """
+ return _build_file_for_rust_analyzer_proc_macro_srv.format(
+ binary_ext = system_to_binary_ext(exec_triple.system),
+ )
+
def BUILD_for_clippy(target_triple):
"""Emits a BUILD file the clippy archive.
@@ -125,8 +153,9 @@
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
- return _build_file_for_clippy_template.format(binary_ext = system_to_binary_ext(system))
+ return _build_file_for_clippy_template.format(
+ binary_ext = system_to_binary_ext(target_triple.system),
+ )
_build_file_for_llvm_tools = """\
filegroup(
@@ -146,15 +175,14 @@
"""Emits a BUILD file the llvm-tools binaries.
Args:
- target_triple (str): The triple of the target platform
+ target_triple (struct): The triple of the target platform
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
return _build_file_for_llvm_tools.format(
- binary_ext = system_to_binary_ext(system),
- target_triple = target_triple,
+ binary_ext = system_to_binary_ext(target_triple.system),
+ target_triple = target_triple.str,
)
_build_file_for_stdlib_template = """\
@@ -187,17 +215,16 @@
"""Emits a BUILD file the stdlib archive.
Args:
- target_triple (str): The triple of the target platform
+ target_triple (triple): The triple of the target platform
Returns:
str: The contents of a BUILD file
"""
- system = triple_to_system(target_triple)
return _build_file_for_stdlib_template.format(
- binary_ext = system_to_binary_ext(system),
- staticlib_ext = system_to_staticlib_ext(system),
- dylib_ext = system_to_dylib_ext(system),
- target_triple = target_triple,
+ binary_ext = system_to_binary_ext(target_triple.system),
+ staticlib_ext = system_to_staticlib_ext(target_triple.system),
+ dylib_ext = system_to_dylib_ext(target_triple.system),
+ target_triple = target_triple.str,
)
_build_file_for_rust_toolchain_template = """\
@@ -205,95 +232,98 @@
rust_toolchain(
name = "{toolchain_name}",
- rust_doc = "@{workspace_name}//:rustdoc",
- rust_std = "@{workspace_name}//:rust_std-{target_triple}",
- rustc = "@{workspace_name}//:rustc",
+ rust_doc = "//:rustdoc",
+ rust_std = "//:rust_std-{target_triple}",
+ rustc = "//:rustc",
rustfmt = {rustfmt_label},
- cargo = "@{workspace_name}//:cargo",
- clippy_driver = "@{workspace_name}//:clippy_driver_bin",
+ cargo = "//:cargo",
+ clippy_driver = "//:clippy_driver_bin",
llvm_cov = {llvm_cov_label},
llvm_profdata = {llvm_profdata_label},
- rustc_lib = "@{workspace_name}//:rustc_lib",
- rustc_srcs = {rustc_srcs},
+ rustc_lib = "//:rustc_lib",
allocator_library = {allocator_library},
+ global_allocator_library = {global_allocator_library},
binary_ext = "{binary_ext}",
staticlib_ext = "{staticlib_ext}",
dylib_ext = "{dylib_ext}",
stdlib_linkflags = [{stdlib_linkflags}],
- os = "{system}",
default_edition = "{default_edition}",
exec_triple = "{exec_triple}",
target_triple = "{target_triple}",
visibility = ["//visibility:public"],
+ extra_rustc_flags = {extra_rustc_flags},
+ extra_exec_rustc_flags = {extra_exec_rustc_flags},
)
"""
def BUILD_for_rust_toolchain(
- workspace_name,
name,
exec_triple,
target_triple,
- include_rustc_srcs,
allocator_library,
+ global_allocator_library,
default_edition,
include_rustfmt,
include_llvm_tools,
- stdlib_linkflags = None):
+ stdlib_linkflags = None,
+ extra_rustc_flags = None,
+ extra_exec_rustc_flags = None):
"""Emits a toolchain declaration to match an existing compiler and stdlib.
Args:
- workspace_name (str): The name of the workspace that this toolchain resides in
name (str): The name of the toolchain declaration
- exec_triple (str): The rust-style target that this compiler runs on
- target_triple (str): The rust-style target triple of the tool
- include_rustc_srcs (bool, optional): Whether to download rustc's src code. This is required in order to use rust-analyzer support. Defaults to False.
+ exec_triple (triple): The rust-style target that this compiler runs on
+ target_triple (triple): The rust-style target triple of the tool
allocator_library (str, optional): Target that provides allocator functions when rust_library targets are embedded in a cc_binary.
+ global_allocator_library (str, optional): Target that provides allocator functions when a global allocator is used with cc_common_link.
+ This target is only used in the target configuration; exec builds still use the symbols provided
+ by the `allocator_library` target.
default_edition (str): Default Rust edition.
include_rustfmt (bool): Whether rustfmt is present in the toolchain.
include_llvm_tools (bool): Whether llvm-tools are present in the toolchain.
stdlib_linkflags (list, optional): Overriden flags needed for linking to rust
stdlib, akin to BAZEL_LINKLIBS. Defaults to
None.
-
+ extra_rustc_flags (list, optional): Extra flags to pass to rustc in non-exec configuration.
+ extra_exec_rustc_flags (list, optional): Extra flags to pass to rustc in exec configuration.
Returns:
str: A rendered template of a `rust_toolchain` declaration
"""
- system = triple_to_system(target_triple)
if stdlib_linkflags == None:
- stdlib_linkflags = ", ".join(['"%s"' % x for x in system_to_stdlib_linkflags(system)])
+ stdlib_linkflags = ", ".join(['"%s"' % x for x in system_to_stdlib_linkflags(target_triple.system)])
- rustc_srcs = "None"
- if include_rustc_srcs:
- rustc_srcs = "\"@{workspace_name}//lib/rustlib/src:rustc_srcs\"".format(workspace_name = workspace_name)
rustfmt_label = "None"
if include_rustfmt:
- rustfmt_label = "\"@{workspace_name}//:rustfmt_bin\"".format(workspace_name = workspace_name)
+ rustfmt_label = "\"//:rustfmt_bin\""
llvm_cov_label = "None"
llvm_profdata_label = "None"
if include_llvm_tools:
- llvm_cov_label = "\"@{workspace_name}//:llvm_cov_bin\"".format(workspace_name = workspace_name)
- llvm_profdata_label = "\"@{workspace_name}//:llvm_profdata_bin\"".format(workspace_name = workspace_name)
+ llvm_cov_label = "\"//:llvm_cov_bin\""
+ llvm_profdata_label = "\"//:llvm_profdata_bin\""
allocator_library_label = "None"
if allocator_library:
allocator_library_label = "\"{allocator_library}\"".format(allocator_library = allocator_library)
+ global_allocator_library_label = "None"
+ if global_allocator_library:
+ global_allocator_library_label = "\"{global_allocator_library}\"".format(global_allocator_library = global_allocator_library)
return _build_file_for_rust_toolchain_template.format(
toolchain_name = name,
- workspace_name = workspace_name,
- binary_ext = system_to_binary_ext(system),
- staticlib_ext = system_to_staticlib_ext(system),
- dylib_ext = system_to_dylib_ext(system),
- rustc_srcs = rustc_srcs,
+ binary_ext = system_to_binary_ext(target_triple.system),
+ staticlib_ext = system_to_staticlib_ext(target_triple.system),
+ dylib_ext = system_to_dylib_ext(target_triple.system),
allocator_library = allocator_library_label,
+ global_allocator_library = global_allocator_library_label,
stdlib_linkflags = stdlib_linkflags,
- system = system,
default_edition = default_edition,
- exec_triple = exec_triple,
- target_triple = target_triple,
+ exec_triple = exec_triple.str,
+ target_triple = target_triple.str,
rustfmt_label = rustfmt_label,
llvm_cov_label = llvm_cov_label,
llvm_profdata_label = llvm_profdata_label,
+ extra_rustc_flags = extra_rustc_flags,
+ extra_exec_rustc_flags = extra_exec_rustc_flags,
)
_build_file_for_toolchain_template = """\
@@ -303,6 +333,7 @@
target_compatible_with = {target_constraint_sets_serialized},
toolchain = "{toolchain}",
toolchain_type = "{toolchain_type}",
+ {target_settings}
)
"""
@@ -310,133 +341,149 @@
name,
toolchain,
toolchain_type,
+ target_settings,
target_compatible_with,
exec_compatible_with):
+ target_settings_value = "target_settings = {},".format(json.encode(target_settings)) if target_settings else "# target_settings = []"
+
return _build_file_for_toolchain_template.format(
name = name,
- exec_constraint_sets_serialized = exec_compatible_with,
- target_constraint_sets_serialized = target_compatible_with,
+ exec_constraint_sets_serialized = json.encode(exec_compatible_with),
+ target_constraint_sets_serialized = json.encode(target_compatible_with),
toolchain = toolchain,
toolchain_type = toolchain_type,
+ target_settings = target_settings_value,
)
-def load_rustfmt(ctx):
+def load_rustfmt(ctx, target_triple, version, iso_date):
"""Loads a rustfmt binary and yields corresponding BUILD for it
Args:
- ctx (repository_ctx): The repository rule's context object
+ ctx (repository_ctx): The repository rule's context object.
+ target_triple (struct): The platform triple to download rustfmt for.
+ version (str): The version or channel of rustfmt.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
Returns:
str: The BUILD file contents for this rustfmt binary
"""
- target_triple = ctx.attr.exec_triple
load_arbitrary_tool(
ctx,
- iso_date = ctx.attr.iso_date,
+ iso_date = iso_date,
target_triple = target_triple,
tool_name = "rustfmt",
tool_subdirectories = ["rustfmt-preview"],
- version = ctx.attr.rustfmt_version,
+ version = version,
)
return BUILD_for_rustfmt(target_triple)
-def load_rust_compiler(ctx):
+def load_rust_compiler(ctx, iso_date, target_triple, version):
"""Loads a rust compiler and yields corresponding BUILD for it
Args:
ctx (repository_ctx): A repository_ctx.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
+ target_triple (struct): The Rust-style target that this compiler runs on.
+ version (str): The version of the tool among \"nightly\", \"beta\", or an exact version.
Returns:
str: The BUILD file contents for this compiler and compiler library
"""
- target_triple = ctx.attr.exec_triple
load_arbitrary_tool(
ctx,
- iso_date = ctx.attr.iso_date,
+ iso_date = iso_date,
target_triple = target_triple,
tool_name = "rustc",
tool_subdirectories = ["rustc"],
- version = ctx.attr.version,
+ version = version,
)
return BUILD_for_compiler(target_triple)
-def load_clippy(ctx):
+def load_clippy(ctx, iso_date, target_triple, version):
"""Loads Clippy and yields corresponding BUILD for it
Args:
ctx (repository_ctx): A repository_ctx.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
+ target_triple (struct): The Rust-style target that this compiler runs on.
+ version (str): The version of the tool among \"nightly\", \"beta\", or an exact version.
Returns:
str: The BUILD file contents for Clippy
"""
-
- target_triple = ctx.attr.exec_triple
load_arbitrary_tool(
ctx,
- iso_date = ctx.attr.iso_date,
+ iso_date = iso_date,
target_triple = target_triple,
tool_name = "clippy",
tool_subdirectories = ["clippy-preview"],
- version = ctx.attr.version,
+ version = version,
)
return BUILD_for_clippy(target_triple)
-def load_cargo(ctx):
+def load_cargo(ctx, iso_date, target_triple, version):
"""Loads Cargo and yields corresponding BUILD for it
Args:
ctx (repository_ctx): A repository_ctx.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
+ target_triple (struct): The Rust-style target that this compiler runs on.
+ version (str): The version of the tool among \"nightly\", \"beta\", or an exact version.
Returns:
str: The BUILD file contents for Cargo
"""
- target_triple = ctx.attr.exec_triple
load_arbitrary_tool(
ctx,
- iso_date = ctx.attr.iso_date,
+ iso_date = iso_date,
target_triple = target_triple,
tool_name = "cargo",
tool_subdirectories = ["cargo"],
- version = ctx.attr.version,
+ version = version,
)
return BUILD_for_cargo(target_triple)
-def should_include_rustc_srcs(repository_ctx):
- """Determing whether or not to include rustc sources in the toolchain.
+def includes_rust_analyzer_proc_macro_srv(version, iso_date):
+ """Determine whether or not the rust_analyzer_proc_macro_srv binary in available in the given version of Rust.
Args:
- repository_ctx (repository_ctx): The repository rule's context object
+ version (str): The version of the tool among \"nightly\", \"beta\", or an exact version.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
Returns:
- bool: Whether or not to include rustc source files in a `rustc_toolchain`
+ bool: Whether or not the binary is expected to be included
"""
- # The environment variable will always take precedence over the attribute.
- include_rustc_srcs_env = repository_ctx.os.environ.get("RULES_RUST_TOOLCHAIN_INCLUDE_RUSTC_SRCS")
- if include_rustc_srcs_env != None:
- return include_rustc_srcs_env.lower() in ["true", "1"]
+ if version == "nightly":
+ return iso_date >= "2022-09-21"
+ elif version == "beta":
+ return False
+ elif version >= "1.64.0":
+ return True
- return getattr(repository_ctx.attr, "include_rustc_srcs", False)
+ return False
-def load_rust_src(ctx, sha256 = ""):
+def load_rust_src(ctx, iso_date, version, sha256 = ""):
"""Loads the rust source code. Used by the rust-analyzer rust-project.json generator.
Args:
ctx (ctx): A repository_ctx.
+ version (str): The version of the tool among "nightly", "beta', or an exact version.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
sha256 (str): The sha256 value for the `rust-src` artifact
"""
- tool_suburl = produce_tool_suburl("rust-src", None, ctx.attr.version, ctx.attr.iso_date)
+ tool_suburl = produce_tool_suburl("rust-src", None, version, iso_date)
url = ctx.attr.urls[0].format(tool_suburl)
- tool_path = produce_tool_path("rust-src", None, ctx.attr.version)
- archive_path = tool_path + _get_tool_extension(ctx)
+ tool_path = produce_tool_path("rust-src", version, None)
+ archive_path = tool_path + _get_tool_extension(getattr(ctx.attr, "urls", None))
sha256 = sha256 or getattr(ctx.attr, "sha256s", {}).get(archive_path) or FILE_KEY_TO_SHA.get(archive_path) or ""
ctx.download_and_extract(
url,
@@ -460,14 +507,38 @@
rust_analyzer_toolchain(
name = "{name}",
+ proc_macro_srv = {proc_macro_srv},
+ rustc = "{rustc}",
rustc_srcs = "//lib/rustlib/src:rustc_srcs",
visibility = ["//visibility:public"],
)
"""
-def BUILD_for_rust_analyzer_toolchain(name):
+def BUILD_for_rust_analyzer_toolchain(name, rustc, proc_macro_srv):
return _build_file_for_rust_analyzer_toolchain_template.format(
name = name,
+ rustc = rustc,
+ proc_macro_srv = repr(proc_macro_srv),
+ )
+
+_build_file_for_rustfmt_toolchain_template = """\
+load("@rules_rust//rust:toolchain.bzl", "rustfmt_toolchain")
+
+rustfmt_toolchain(
+ name = "{name}",
+ rustfmt = "{rustfmt}",
+ rustc = "{rustc}",
+ rustc_lib = "{rustc_lib}",
+ visibility = ["//visibility:public"],
+)
+"""
+
+def BUILD_for_rustfmt_toolchain(name, rustfmt, rustc, rustc_lib):
+ return _build_file_for_rustfmt_toolchain_template.format(
+ name = name,
+ rustfmt = rustfmt,
+ rustc = rustc,
+ rustc_lib = rustc_lib,
)
def load_rust_stdlib(ctx, target_triple):
@@ -475,7 +546,7 @@
Args:
ctx (repository_ctx): A repository_ctx.
- target_triple (str): The rust-style target triple of the tool
+ target_triple (struct): The rust-style target triple of the tool
Returns:
str: The BUILD file contents for this stdlib
@@ -486,7 +557,7 @@
iso_date = ctx.attr.iso_date,
target_triple = target_triple,
tool_name = "rust-std",
- tool_subdirectories = ["rust-std-{}".format(target_triple)],
+ tool_subdirectories = ["rust-std-{}".format(target_triple.str)],
version = ctx.attr.version,
)
@@ -550,24 +621,24 @@
"""Produces a fully qualified Rust tool name for URL
Args:
- tool_name: The name of the tool per static.rust-lang.org
- target_triple: The rust-style target triple of the tool
- version: The version of the tool among "nightly", "beta', or an exact version.
- iso_date: The date of the tool (or None, if the version is a specific version).
+ tool_name (str): The name of the tool per `static.rust-lang.org`.
+ target_triple (struct): The rust-style target triple of the tool.
+ version (str): The version of the tool among "nightly", "beta', or an exact version.
+ iso_date (str): The date of the tool (or None, if the version is a specific version).
Returns:
str: The fully qualified url path for the specified tool.
"""
- path = produce_tool_path(tool_name, target_triple, version)
+ path = produce_tool_path(tool_name, version, target_triple)
return iso_date + "/" + path if (iso_date and version in ("beta", "nightly")) else path
-def produce_tool_path(tool_name, target_triple, version):
+def produce_tool_path(tool_name, version, target_triple = None):
"""Produces a qualified Rust tool name
Args:
- tool_name: The name of the tool per static.rust-lang.org
- target_triple: The rust-style target triple of the tool
- version: The version of the tool among "nightly", "beta', or an exact version.
+ tool_name (str): The name of the tool per static.rust-lang.org
+ version (str): The version of the tool among "nightly", "beta', or an exact version.
+ target_triple (struct, optional): The rust-style target triple of the tool
Returns:
str: The qualified path for the specified tool.
@@ -576,7 +647,37 @@
fail("No tool name was provided")
if not version:
fail("No tool version was provided")
- return "-".join([e for e in [tool_name, version, target_triple] if e])
+
+ # Not all tools require a triple. E.g. `rustc_src` (Rust source files for rust-analyzer).
+ platform_triple = None
+ if target_triple:
+ platform_triple = target_triple.str
+
+ return "-".join([e for e in [tool_name, version, platform_triple] if e])
+
+def lookup_tool_sha256(ctx, tool_name, target_triple, version, iso_date, sha256):
+ """Looks up the sha256 hash of a specific tool archive.
+
+ The lookup order is:
+
+ 1. The sha256s dict in the context attributes;
+ 2. The list of sha256 hashes populated in //rust:known_shas.bzl;
+ 3. The sha256 argument to the function
+
+ Args:
+ ctx (repository_ctx): A repository_ctx (no attrs required).
+ tool_name (str): The name of the given tool per the archive naming.
+ target_triple (struct): The rust-style target triple of the tool.
+ version (str): The version of the tool among "nightly", "beta', or an exact version.
+ iso_date (str): The date of the tool (ignored if the version is a specific version).
+ sha256 (str): The expected hash of hash of the Rust tool.
+
+ Returns:
+ str: The sha256 of the tool archive, or an empty string if the hash could not be found.
+ """
+ tool_suburl = produce_tool_suburl(tool_name, target_triple, version, iso_date)
+ archive_path = tool_suburl + _get_tool_extension(getattr(ctx.attr, "urls", None))
+ return getattr(ctx.attr, "sha256s", dict()).get(archive_path) or FILE_KEY_TO_SHA.get(archive_path) or sha256
def load_arbitrary_tool(ctx, tool_name, tool_subdirectories, version, iso_date, target_triple, sha256 = ""):
"""Loads a Rust tool, downloads, and extracts into the common workspace.
@@ -603,7 +704,7 @@
tool_subdirectories = ["clippy-preview", "rustc"]
version (str): The version of the tool among "nightly", "beta', or an exact version.
iso_date (str): The date of the tool (ignored if the version is a specific version).
- target_triple (str): The rust-style target triple of the tool
+ target_triple (struct): The rust-style target triple of the tool.
sha256 (str, optional): The expected hash of hash of the Rust tool. Defaults to "".
"""
check_version_valid(version, iso_date, param_prefix = tool_name + "_")
@@ -618,9 +719,9 @@
if new_url not in urls:
urls.append(new_url)
- tool_path = produce_tool_path(tool_name, target_triple, version)
- archive_path = tool_path + _get_tool_extension(ctx)
- sha256 = getattr(ctx.attr, "sha256s", dict()).get(archive_path) or FILE_KEY_TO_SHA.get(archive_path) or sha256
+ tool_path = produce_tool_path(tool_name, version, target_triple)
+
+ sha256 = lookup_tool_sha256(ctx, tool_name, target_triple, version, iso_date, sha256)
for subdirectory in tool_subdirectories:
# As long as the sha256 value is consistent accross calls here the
@@ -646,11 +747,118 @@
ret[url] = auth
return ret
-def _get_tool_extension(ctx):
- urls = getattr(ctx.attr, "urls", DEFAULT_STATIC_RUST_URL_TEMPLATES)
+def _get_tool_extension(urls = None):
+ if urls == None:
+ urls = DEFAULT_STATIC_RUST_URL_TEMPLATES
if urls[0][-7:] == ".tar.gz":
return ".tar.gz"
elif urls[0][-7:] == ".tar.xz":
return ".tar.xz"
else:
return ""
+
+def select_rust_version(versions):
+ """Select the highest priorty version for a list of Rust versions
+
+ Priority order: `stable > nightly > beta`
+
+ Note that duplicate channels are unexpected in `versions`.
+
+ Args:
+ versions (list): A list of Rust versions. E.g. [`1.66.0`, `nightly/2022-12-15`]
+
+ Returns:
+ str: The highest ranking value from `versions`
+ """
+ if not versions:
+ fail("No versions were provided")
+
+ current = versions[0]
+
+ for ver in versions:
+ if ver.startswith("beta"):
+ if current[0].isdigit() or current.startswith("nightly"):
+ continue
+ if current.startswith("beta") and ver > current:
+ current = ver
+ continue
+
+ current = ver
+ elif ver.startswith("nightly"):
+ if current[0].isdigit():
+ continue
+ if current.startswith("nightly") and ver > current:
+ current = ver
+ continue
+
+ current = ver
+
+ else:
+ current = ver
+
+ return current
+
+_build_file_for_toolchain_hub_template = """
+toolchain(
+ name = "{name}",
+ exec_compatible_with = {exec_constraint_sets_serialized},
+ target_compatible_with = {target_constraint_sets_serialized},
+ toolchain = "{toolchain}",
+ toolchain_type = "{toolchain_type}",
+ visibility = ["//visibility:public"],
+)
+"""
+
+def BUILD_for_toolchain_hub(
+ toolchain_names,
+ toolchain_labels,
+ toolchain_types,
+ target_compatible_with,
+ exec_compatible_with):
+ return "\n".join([_build_file_for_toolchain_hub_template.format(
+ name = toolchain_name,
+ exec_constraint_sets_serialized = json.encode(exec_compatible_with[toolchain_name]),
+ target_constraint_sets_serialized = json.encode(target_compatible_with[toolchain_name]),
+ toolchain = toolchain_labels[toolchain_name],
+ toolchain_type = toolchain_types[toolchain_name],
+ ) for toolchain_name in toolchain_names])
+
+def _toolchain_repository_hub_impl(repository_ctx):
+ repository_ctx.file("WORKSPACE.bazel", """workspace(name = "{}")""".format(
+ repository_ctx.name,
+ ))
+
+ repository_ctx.file("BUILD.bazel", BUILD_for_toolchain_hub(
+ toolchain_names = repository_ctx.attr.toolchain_names,
+ toolchain_labels = repository_ctx.attr.toolchain_labels,
+ toolchain_types = repository_ctx.attr.toolchain_types,
+ target_compatible_with = repository_ctx.attr.target_compatible_with,
+ exec_compatible_with = repository_ctx.attr.exec_compatible_with,
+ ))
+
+toolchain_repository_hub = repository_rule(
+ doc = (
+ "Generates a toolchain-bearing repository that declares a set of other toolchains from other " +
+ "repositories. This exists to allow registering a set of toolchains in one go with the `:all` target."
+ ),
+ attrs = {
+ "exec_compatible_with": attr.string_list_dict(
+ doc = "A list of constraints for the execution platform for this toolchain, keyed by toolchain name.",
+ mandatory = True,
+ ),
+ "target_compatible_with": attr.string_list_dict(
+ doc = "A list of constraints for the target platform for this toolchain, keyed by toolchain name.",
+ mandatory = True,
+ ),
+ "toolchain_labels": attr.string_dict(
+ doc = "The name of the toolchain implementation target, keyed by toolchain name.",
+ mandatory = True,
+ ),
+ "toolchain_names": attr.string_list(mandatory = True),
+ "toolchain_types": attr.string_dict(
+ doc = "The toolchain type of the toolchain to declare, keyed by toolchain name.",
+ mandatory = True,
+ ),
+ },
+ implementation = _toolchain_repository_hub_impl,
+)
diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl
index 571813b..d6f09e8 100644
--- a/rust/private/rust.bzl
+++ b/rust/private/rust.bzl
@@ -12,14 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# buildifier: disable=module-docstring
+"""Rust rule implementations"""
+
load("@bazel_skylib//lib:paths.bzl", "paths")
load("//rust/private:common.bzl", "rust_common")
+load("//rust/private:providers.bzl", "BuildInfo")
load("//rust/private:rustc.bzl", "rustc_compile_action")
load(
"//rust/private:utils.bzl",
"can_build_metadata",
"compute_crate_name",
+ "crate_root_src",
"dedent",
"determine_output_hash",
"expand_dict_value_locations",
@@ -94,7 +97,7 @@
"please file an issue!").format(crate_type))
prefix = "lib"
- if (toolchain.target_triple.find("windows") != -1) and crate_type not in ("lib", "rlib"):
+ if toolchain.target_triple and toolchain.target_os == "windows" and crate_type not in ("lib", "rlib"):
prefix = ""
if toolchain.target_arch == "wasm32" and crate_type == "cdylib":
prefix = ""
@@ -151,9 +154,10 @@
generated_sources = []
generated_root = crate_root
+ package_root = paths.dirname(ctx.build_file_path)
if crate_root and (crate_root.is_source or crate_root.root.path != ctx.bin_dir.path):
- generated_root = ctx.actions.declare_file(crate_root.basename)
+ generated_root = ctx.actions.declare_file(paths.relativize(crate_root.short_path, package_root))
ctx.actions.symlink(
output = generated_root,
target_file = crate_root,
@@ -167,7 +171,7 @@
if src == crate_root:
continue
if src.is_source or src.root.path != ctx.bin_dir.path:
- src_symlink = ctx.actions.declare_file(src.basename)
+ src_symlink = ctx.actions.declare_file(paths.relativize(src.short_path, package_root))
ctx.actions.symlink(
output = src_symlink,
target_file = src,
@@ -179,48 +183,6 @@
return generated_sources, generated_root
-def crate_root_src(name, srcs, crate_type):
- """Determines the source file for the crate root, should it not be specified in `attr.crate_root`.
-
- Args:
- name (str): The name of the target.
- srcs (list): A list of all sources for the target Crate.
- crate_type (str): The type of this crate ("bin", "lib", "rlib", "cdylib", etc).
-
- Returns:
- File: The root File object for a given crate. See the following links for more details:
- - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library
- - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries
- """
- default_crate_root_filename = "main.rs" if crate_type == "bin" else "lib.rs"
-
- crate_root = (
- (srcs[0] if len(srcs) == 1 else None) or
- _shortest_src_with_basename(srcs, default_crate_root_filename) or
- _shortest_src_with_basename(srcs, name + ".rs")
- )
- if not crate_root:
- file_names = [default_crate_root_filename, name + ".rs"]
- fail("No {} source file found.".format(" or ".join(file_names)), "srcs")
- return crate_root
-
-def _shortest_src_with_basename(srcs, basename):
- """Finds the shortest among the paths in srcs that match the desired basename.
-
- Args:
- srcs (list): A list of File objects
- basename (str): The target basename to match against.
-
- Returns:
- File: The File object with the shortest path that matches `basename`
- """
- shortest = None
- for f in srcs:
- if f.basename == basename:
- if not shortest or len(f.dirname) < len(shortest.dirname):
- shortest = f
- return shortest
-
def _rust_library_impl(ctx):
"""The implementation of the `rust_library` rule.
@@ -289,15 +251,16 @@
Returns:
list: A list of providers. See `rustc_compile_action`
"""
-
- srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, getattr(ctx.file, "crate_root", None))
- if not crate_root:
- crate_root = crate_root_src(ctx.attr.name, srcs, "lib")
_assert_no_deprecated_attributes(ctx)
_assert_correct_dep_mapping(ctx)
toolchain = find_toolchain(ctx)
+ crate_root = getattr(ctx.file, "crate_root", None)
+ if not crate_root:
+ crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, crate_type)
+ srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, crate_root)
+
# Determine unique hash for this rlib.
# Note that we don't include a hash for `cdylib` and `staticlib` since they are meant to be consumed externally
# and having a deterministic name is important since it ends up embedded in the executable. This is problematic
@@ -346,6 +309,7 @@
rustc_env_files = ctx.files.rustc_env_files,
is_test = False,
compile_data = depset(ctx.files.compile_data),
+ compile_data_targets = depset(ctx.attr.compile_data),
owner = ctx.label,
),
output_hash = output_hash,
@@ -369,9 +333,10 @@
deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))
- srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, getattr(ctx.file, "crate_root", None))
+ crate_root = getattr(ctx.file, "crate_root", None)
if not crate_root:
- crate_root = crate_root_src(ctx.attr.name, srcs, ctx.attr.crate_type)
+ crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, ctx.attr.crate_type)
+ srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, crate_root)
return rustc_compile_action(
ctx = ctx,
@@ -391,6 +356,7 @@
rustc_env_files = ctx.files.rustc_env_files,
is_test = False,
compile_data = depset(ctx.files.compile_data),
+ compile_data_targets = depset(ctx.attr.compile_data),
owner = ctx.label,
),
)
@@ -409,9 +375,7 @@
toolchain = find_toolchain(ctx)
- srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, getattr(ctx.file, "crate_root", None))
crate_type = "bin"
-
deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))
@@ -428,11 +392,17 @@
),
)
+ srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, getattr(ctx.file, "crate_root", None))
+
# Optionally join compile data
if crate.compile_data:
compile_data = depset(ctx.files.compile_data, transitive = [crate.compile_data])
else:
compile_data = depset(ctx.files.compile_data)
+ if crate.compile_data_targets:
+ compile_data_targets = depset(ctx.attr.compile_data, transitive = [crate.compile_data_targets])
+ else:
+ compile_data_targets = depset(ctx.attr.compile_data)
rustc_env_files = ctx.files.rustc_env_files + crate.rustc_env_files
rustc_env = dict(crate.rustc_env)
rustc_env.update(**ctx.attr.rustc_env)
@@ -452,12 +422,17 @@
rustc_env_files = rustc_env_files,
is_test = True,
compile_data = compile_data,
+ compile_data_targets = compile_data_targets,
wrapped_crate_type = crate.type,
owner = ctx.label,
)
else:
+ crate_root = getattr(ctx.file, "crate_root", None)
+
if not crate_root:
- crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, "lib")
+ crate_root_type = "lib" if ctx.attr.use_libtest_harness else "bin"
+ crate_root = crate_root_src(ctx.attr.name, ctx.files.srcs, crate_root_type)
+ srcs, crate_root = _transform_sources(ctx, ctx.files.srcs, crate_root)
output_hash = determine_output_hash(crate_root, ctx.label)
output = ctx.actions.declare_file(
@@ -483,6 +458,7 @@
rustc_env_files = ctx.files.rustc_env_files,
is_test = True,
compile_data = depset(ctx.files.compile_data),
+ compile_data_targets = depset(ctx.attr.compile_data),
owner = ctx.label,
)
@@ -504,12 +480,55 @@
if not toolchain.llvm_profdata:
fail("toolchain.llvm_profdata is required if toolchain.llvm_cov is set.")
- env["RUST_LLVM_COV"] = toolchain.llvm_cov.path
- env["RUST_LLVM_PROFDATA"] = toolchain.llvm_profdata.path
+ llvm_cov_path = toolchain.llvm_cov.short_path
+ if llvm_cov_path.startswith("../"):
+ llvm_cov_path = llvm_cov_path[len("../"):]
+
+ llvm_profdata_path = toolchain.llvm_profdata.short_path
+ if llvm_profdata_path.startswith("../"):
+ llvm_profdata_path = llvm_profdata_path[len("../"):]
+
+ env["RUST_LLVM_COV"] = llvm_cov_path
+ env["RUST_LLVM_PROFDATA"] = llvm_profdata_path
+ components = "{}/{}".format(ctx.label.workspace_root, ctx.label.package).split("/")
+ env["CARGO_MANIFEST_DIR"] = "/".join([c for c in components if c])
providers.append(testing.TestEnvironment(env))
return providers
+def _rust_library_group_impl(ctx):
+ dep_variant_infos = []
+ dep_variant_transitive_infos = []
+ runfiles = []
+
+ for dep in ctx.attr.deps:
+ if rust_common.crate_info in dep:
+ dep_variant_infos.append(rust_common.dep_variant_info(
+ crate_info = dep[rust_common.crate_info] if rust_common.crate_info in dep else None,
+ dep_info = dep[rust_common.dep_info] if rust_common.crate_info in dep else None,
+ build_info = dep[BuildInfo] if BuildInfo in dep else None,
+ cc_info = dep[CcInfo] if CcInfo in dep else None,
+ crate_group_info = None,
+ ))
+ elif rust_common.crate_group_info in dep:
+ dep_variant_transitive_infos.append(dep[rust_common.crate_group_info].dep_variant_infos)
+ else:
+ fail("crate_group_info targets can only depend on rust_library or rust_library_group targets.")
+
+ if dep[DefaultInfo].default_runfiles != None:
+ runfiles.append(dep[DefaultInfo].default_runfiles)
+
+ return [
+ rust_common.crate_group_info(
+ dep_variant_infos = depset(dep_variant_infos, transitive = dep_variant_transitive_infos),
+ ),
+ DefaultInfo(runfiles = ctx.runfiles().merge_all(runfiles)),
+ coverage_common.instrumented_files_info(
+ ctx,
+ dependency_attributes = ["deps"],
+ ),
+ ]
+
def _stamp_attribute(default_value):
return attr.int(
doc = dedent("""\
@@ -680,11 +699,6 @@
),
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
),
- "_collect_cc_coverage": attr.label(
- default = Label("//util:collect_coverage"),
- executable = True,
- cfg = "exec",
- ),
"_error_format": attr.label(
default = Label("//:error_format"),
),
@@ -710,6 +724,9 @@
"_is_proc_macro_dep_enabled": attr.label(
default = Label("//:is_proc_macro_dep_enabled"),
),
+ "_per_crate_rustc_flag": attr.label(
+ default = Label("//:experimental_per_crate_rustc_flag"),
+ ),
"_process_wrapper": attr.label(
doc = "A process wrapper for running rustc on all platforms.",
default = Label("//util/process_wrapper"),
@@ -723,6 +740,28 @@
),
}
+_coverage_attrs = {
+ "_collect_cc_coverage": attr.label(
+ default = Label("//util:collect_coverage"),
+ executable = True,
+ cfg = "exec",
+ ),
+ # Bazel’s coverage runner
+ # (https://github.com/bazelbuild/bazel/blob/6.0.0/tools/test/collect_coverage.sh)
+ # needs a binary called “lcov_merge.” Its location is passed in the
+ # LCOV_MERGER environmental variable. For builtin rules, this variable
+ # is set automatically based on a magic “$lcov_merger” or
+ # “:lcov_merger” attribute, but it’s not possible to create such
+ # attributes in Starlark. Therefore we specify the variable ourselves.
+ # Note that the coverage runner runs in the runfiles root instead of
+ # the execution root, therefore we use “path” instead of “short_path.”
+ "_lcov_merger": attr.label(
+ default = configuration_field(fragment = "coverage", name = "output_generator"),
+ executable = True,
+ cfg = "exec",
+ ),
+}
+
_experimental_use_cc_common_link_attrs = {
"experimental_use_cc_common_link": attr.int(
doc = (
@@ -736,6 +775,25 @@
values = [-1, 0, 1],
default = -1,
),
+ "malloc": attr.label(
+ default = Label("@bazel_tools//tools/cpp:malloc"),
+ doc = """Override the default dependency on `malloc`.
+
+By default, Rust binaries linked with cc_common.link are linked against
+`@bazel_tools//tools/cpp:malloc"`, which is an empty library and the resulting binary will use
+libc's `malloc`. This label must refer to a `cc_library` rule.
+""",
+ mandatory = False,
+ providers = [[CcInfo]],
+ ), # A late-bound attribute denoting the value of the `--custom_malloc`
+ # command line flag (or None if the flag is not provided).
+ "_custom_malloc": attr.label(
+ default = configuration_field(
+ fragment = "cpp",
+ name = "custom_malloc",
+ ),
+ providers = [[CcInfo]],
+ ),
}
_rust_test_attrs = dict({
@@ -754,10 +812,6 @@
Specifies additional environment variables to set when the test is executed by bazel test.
Values are subject to `$(rootpath)`, `$(execpath)`, location, and
["Make variable"](https://docs.bazel.build/versions/master/be/make-variables.html) substitution.
-
- Execpath returns absolute path, and in order to be able to construct the absolute path we
- need to wrap the test binary in a launcher. Using a launcher comes with complications, such as
- more complicated debugger attachment.
"""),
),
"use_libtest_harness": attr.bool(
@@ -775,7 +829,7 @@
default = Label("@bazel_tools//tools/cpp:grep-includes"),
executable = True,
),
-}.items() + _experimental_use_cc_common_link_attrs.items())
+}.items() + _coverage_attrs.items() + _experimental_use_cc_common_link_attrs.items())
_common_providers = [
rust_common.crate_info,
@@ -894,7 +948,16 @@
rust_shared_library = rule(
implementation = _rust_shared_library_impl,
- attrs = dict(_common_attrs.items()),
+ attrs = dict(
+ _common_attrs.items() + _experimental_use_cc_common_link_attrs.items() + {
+ "_grep_includes": attr.label(
+ allow_single_file = True,
+ cfg = "exec",
+ default = Label("@bazel_tools//tools/cpp:grep-includes"),
+ executable = True,
+ ),
+ }.items(),
+ ),
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
@@ -1225,6 +1288,7 @@
crate = ":hello_lib",
# You may add other deps that are specific to the test configuration
deps = ["//some/dev/dep"],
+ )
```
Run the test with `bazel test //hello_lib:hello_lib_test`. The crate
@@ -1360,3 +1424,48 @@
tests = tests,
tags = kwargs.get("tags", None),
)
+
+rust_library_group = rule(
+ implementation = _rust_library_group_impl,
+ provides = [rust_common.crate_group_info],
+ attrs = {
+ "deps": attr.label_list(
+ doc = "Other dependencies to forward through this crate group.",
+ providers = [[rust_common.crate_group_info], [rust_common.crate_info]],
+ ),
+ },
+ doc = dedent("""\
+ Functions as an alias for a set of dependencies.
+
+ Specifically, the following are equivalent:
+
+ ```starlark
+ rust_library_group(
+ name = "crate_group",
+ deps = [
+ ":crate1",
+ ":crate2",
+ ],
+ )
+
+ rust_library(
+ name = "foobar",
+ deps = [":crate_group"],
+ ...
+ )
+ ```
+
+ and
+
+ ```starlark
+ rust_library(
+ name = "foobar",
+ deps = [
+ ":crate1",
+ ":crate2",
+ ],
+ ...
+ )
+ ```
+ """),
+)
diff --git a/rust/private/rust_analyzer.bzl b/rust/private/rust_analyzer.bzl
index 7515fd7..3eea6c0 100644
--- a/rust/private/rust_analyzer.bzl
+++ b/rust/private/rust_analyzer.bzl
@@ -23,7 +23,13 @@
load("//rust/platform:triple_mappings.bzl", "system_to_dylib_ext", "triple_to_system")
load("//rust/private:common.bzl", "rust_common")
load("//rust/private:rustc.bzl", "BuildInfo")
-load("//rust/private:utils.bzl", "dedent", "find_toolchain")
+load(
+ "//rust/private:utils.bzl",
+ "concat",
+ "dedent",
+ "dedup_expand_location",
+ "find_toolchain",
+)
RustAnalyzerInfo = provider(
doc = "RustAnalyzerInfo holds rust crate metadata for targets",
@@ -38,8 +44,17 @@
},
)
+RustAnalyzerGroupInfo = provider(
+ doc = "RustAnalyzerGroupInfo holds multiple RustAnalyzerInfos",
+ fields = {
+ "deps": "List[RustAnalyzerInfo]: direct dependencies",
+ },
+)
+
def _rust_analyzer_aspect_impl(target, ctx):
- if rust_common.crate_info not in target and rust_common.test_crate_info not in target:
+ if (rust_common.crate_info not in target and
+ rust_common.test_crate_info not in target and
+ rust_common.crate_group_info not in target):
return []
toolchain = find_toolchain(ctx)
@@ -61,14 +76,33 @@
build_info = dep[BuildInfo]
dep_infos = [dep[RustAnalyzerInfo] for dep in ctx.rule.attr.deps if RustAnalyzerInfo in dep]
+ group_infos = [dep[RustAnalyzerGroupInfo] for dep in ctx.rule.attr.deps if RustAnalyzerGroupInfo in dep]
+ for group_info in group_infos:
+ dep_infos.extend(group_info.deps)
+
if hasattr(ctx.rule.attr, "proc_macro_deps"):
dep_infos += [dep[RustAnalyzerInfo] for dep in ctx.rule.attr.proc_macro_deps if RustAnalyzerInfo in dep]
- if hasattr(ctx.rule.attr, "crate") and ctx.rule.attr.crate != None:
- dep_infos.append(ctx.rule.attr.crate[RustAnalyzerInfo])
- if hasattr(ctx.rule.attr, "actual") and ctx.rule.attr.actual != None and RustAnalyzerInfo in ctx.rule.attr.actual:
- dep_infos.append(ctx.rule.attr.actual[RustAnalyzerInfo])
- crate_spec = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_crate_spec")
+ group_infos = [dep[RustAnalyzerGroupInfo] for dep in ctx.rule.attr.proc_macro_deps if RustAnalyzerGroupInfo in dep]
+ for group_info in group_infos:
+ dep_infos.extend(group_info.deps)
+
+ if hasattr(ctx.rule.attr, "crate") and ctx.rule.attr.crate != None:
+ if RustAnalyzerInfo in ctx.rule.attr.crate:
+ dep_infos.append(ctx.rule.attr.crate[RustAnalyzerInfo])
+
+ if RustAnalyzerGroupInfo in ctx.rule.attr.crate:
+ dep_infos.extend(ctx.rule.attr.crate[RustAnalyzerGroupInfo])
+
+ if hasattr(ctx.rule.attr, "actual") and ctx.rule.attr.actual != None:
+ if RustAnalyzerInfo in ctx.rule.attr.actual:
+ dep_infos.append(ctx.rule.attr.actual[RustAnalyzerInfo])
+
+ if RustAnalyzerGroupInfo in ctx.rule.attr.actual:
+ dep_infos.extend(ctx.rule.attr.actul[RustAnalyzerGroupInfo])
+
+ if rust_common.crate_group_info in target:
+ return [RustAnalyzerGroupInfo(deps = dep_infos)]
if rust_common.crate_info in target:
crate_info = target[rust_common.crate_info]
@@ -77,6 +111,8 @@
else:
fail("Unexpected target type: {}".format(target))
+ crate_spec = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_crate_spec")
+
rust_analyzer_info = RustAnalyzerInfo(
crate = crate_info,
cfgs = cfgs,
@@ -184,8 +220,9 @@
# TODO: The only imagined use case is an env var holding a filename in the workspace passed to a
# macro like include_bytes!. Other use cases might exist that require more complex logic.
- expand_targets = getattr(ctx.rule.attr, "data", []) + getattr(ctx.rule.attr, "compile_data", [])
- crate["env"].update({k: ctx.expand_location(v, expand_targets) for k, v in info.env.items()})
+ expand_targets = concat([getattr(ctx.rule.attr, attr, []) for attr in ["data", "compile_data"]])
+
+ crate["env"].update({k: dedup_expand_location(ctx, v, expand_targets) for k, v in info.env.items()})
# Omit when a crate appears to depend on itself (e.g. foo_test crates).
# It can happen a single source file is present in multiple crates - there can
@@ -199,13 +236,15 @@
# common and expected - `rust_test.crate` pointing to the `rust_library`.
crate["deps"] = [_crate_id(dep.crate) for dep in info.deps if _crate_id(dep.crate) != crate_id]
crate["cfg"] = info.cfgs
- crate["target"] = find_toolchain(ctx).target_triple
+ crate["target"] = find_toolchain(ctx).target_triple.str
if info.proc_macro_dylib_path != None:
crate["proc_macro_dylib_path"] = _EXEC_ROOT_TEMPLATE + info.proc_macro_dylib_path
return crate
def _rust_analyzer_toolchain_impl(ctx):
toolchain = platform_common.ToolchainInfo(
+ proc_macro_srv = ctx.executable.proc_macro_srv,
+ rustc = ctx.executable.rustc,
rustc_srcs = ctx.attr.rustc_srcs,
)
@@ -215,6 +254,19 @@
implementation = _rust_analyzer_toolchain_impl,
doc = "A toolchain for [rust-analyzer](https://rust-analyzer.github.io/).",
attrs = {
+ "proc_macro_srv": attr.label(
+ doc = "The path to a `rust_analyzer_proc_macro_srv` binary.",
+ cfg = "exec",
+ executable = True,
+ allow_single_file = True,
+ ),
+ "rustc": attr.label(
+ doc = "The path to a `rustc` binary.",
+ cfg = "exec",
+ executable = True,
+ allow_single_file = True,
+ mandatory = True,
+ ),
"rustc_srcs": attr.label(
doc = "The source code of rustc.",
mandatory = True,
@@ -238,13 +290,30 @@
if rustc_srcs.label.workspace_root:
sysroot_src = _OUTPUT_BASE_TEMPLATE + rustc_srcs.label.workspace_root + "/" + sysroot_src
- sysroot_src_file = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_sysroot_src")
- ctx.actions.write(
- output = sysroot_src_file,
- content = sysroot_src,
+ rustc = rust_analyzer_toolchain.rustc
+ sysroot_dir, _, bin_dir = rustc.dirname.rpartition("/")
+ if bin_dir != "bin":
+ fail("The rustc path is expected to be relative to the sysroot as `bin/rustc`. Instead got: {}".format(
+ rustc.path,
+ ))
+
+ sysroot = "{}/{}".format(
+ _OUTPUT_BASE_TEMPLATE,
+ sysroot_dir,
)
- return [DefaultInfo(files = depset([sysroot_src_file]))]
+ toolchain_info = {
+ "sysroot": sysroot,
+ "sysroot_src": sysroot_src,
+ }
+
+ output = ctx.actions.declare_file(ctx.label.name + ".rust_analyzer_toolchain.json")
+ ctx.actions.write(
+ output = output,
+ content = json.encode_indent(toolchain_info, indent = " " * 4),
+ )
+
+ return [DefaultInfo(files = depset([output]))]
rust_analyzer_detect_sysroot = rule(
implementation = _rust_analyzer_detect_sysroot_impl,
diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl
index 490bfa1..9f3b0c2 100644
--- a/rust/private/rustc.bzl
+++ b/rust/private/rustc.bzl
@@ -14,9 +14,13 @@
"""Functionality for constructing actions that invoke the Rust compiler"""
+load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load(
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
+ "CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME",
"CPP_LINK_EXECUTABLE_ACTION_NAME",
+ "CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME",
+ "CPP_LINK_STATIC_LIBRARY_ACTION_NAME",
)
load("//rust/private:common.bzl", "rust_common")
load("//rust/private:providers.bzl", _BuildInfo = "BuildInfo")
@@ -62,6 +66,11 @@
fields = {"extra_exec_rustc_flags": "List[string] Extra flags to pass to rustc in exec configuration"},
)
+PerCrateRustcFlagsInfo = provider(
+ doc = "Pass each value as an additional flag to non-exec rustc invocations for crates matching the provided filter",
+ fields = {"per_crate_rustc_flags": "List[string] Extra flags to pass to rustc in non-exec configuration"},
+)
+
IsProcMacroDepInfo = provider(
doc = "Records if this is a transitive dependency of a proc-macro.",
fields = {"is_proc_macro_dep": "Boolean"},
@@ -107,9 +116,10 @@
patch, pre = patch.split("-", 1)
else:
pre = ""
+
result = {
- "CARGO_CFG_TARGET_ARCH": toolchain.target_arch,
- "CARGO_CFG_TARGET_OS": toolchain.os,
+ "CARGO_CFG_TARGET_ARCH": "" if toolchain.target_arch == None else toolchain.target_arch,
+ "CARGO_CFG_TARGET_OS": "" if toolchain.target_os == None else toolchain.target_os,
"CARGO_CRATE_NAME": crate_name,
"CARGO_PKG_AUTHORS": "",
"CARGO_PKG_DESCRIPTION": "",
@@ -153,7 +163,7 @@
# attribute is required for compiling linkstamps.
has_grep_includes)
-def _should_use_pic(cc_toolchain, feature_configuration, crate_type):
+def _should_use_pic(cc_toolchain, feature_configuration, crate_type, compilation_mode):
"""Whether or not [PIC][pic] should be enabled
[pic]: https://en.wikipedia.org/wiki/Position-independent_code
@@ -162,12 +172,20 @@
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`.
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
crate_type (str): A Rust target's crate type.
+ compilation_mode: The compilation mode.
Returns:
bool: Whether or not [PIC][pic] should be enabled.
"""
- if crate_type in ("cdylib", "dylib"):
+
+ # We use the same logic to select between `pic` and `nopic` outputs as the C++ rules:
+ # - For shared libraries - we use `pic`. This covers `dylib`, `cdylib` and `proc-macro` crate types.
+ # - In `fastbuild` and `dbg` mode we use `pic` by default.
+ # - In `opt` mode we use `nopic` outputs to build binaries.
+ if crate_type in ("cdylib", "dylib", "proc-macro"):
return cc_toolchain.needs_pic_for_dynamic_libraries(feature_configuration = feature_configuration)
+ elif compilation_mode in ("fastbuild", "dbg"):
+ return True
return False
def _is_proc_macro(crate_info):
@@ -203,8 +221,26 @@
transitive_crate_outputs = []
transitive_metadata_outputs = []
- aliases = {k.label: v for k, v in aliases.items()}
+ crate_deps = []
for dep in depset(transitive = [deps, proc_macro_deps]).to_list():
+ crate_group = None
+
+ if type(dep) == "Target" and rust_common.crate_group_info in dep:
+ crate_group = dep[rust_common.crate_group_info]
+ elif type(dep) == "struct" and hasattr(dep, "crate_group_info") and dep.crate_group_info != None:
+ crate_group = dep.crate_group_info
+ else:
+ crate_deps.append(dep)
+
+ if crate_group:
+ for dep_variant_info in crate_group.dep_variant_infos.to_list():
+ crate_deps.append(struct(
+ crate_info = dep_variant_info.crate_info,
+ dep_info = dep_variant_info.dep_info,
+ ))
+
+ aliases = {k.label: v for k, v in aliases.items()}
+ for dep in crate_deps:
(crate_info, dep_info) = _get_crate_and_dep_info(dep)
cc_info = _get_cc_info(dep)
dep_build_info = _get_build_info(dep)
@@ -335,15 +371,17 @@
"""
return ctx.fragments.cpp.linkopts
-def get_linker_and_args(ctx, attr, cc_toolchain, feature_configuration, rpaths):
+def get_linker_and_args(ctx, attr, crate_type, cc_toolchain, feature_configuration, rpaths, rustdoc = False):
"""Gathers cc_common linker information
Args:
ctx (ctx): The current target's context object
attr (struct): Attributes to use in gathering linker args
+ crate_type (str): The target crate's type (i.e. "bin", "proc-macro", etc.).
cc_toolchain (CcToolchain): cc_toolchain for which we are creating build variables.
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
rpaths (depset): Depset of directories where loader will look for libraries at runtime.
+ rustdoc (bool, optional): Whether to add "bin" link flags to the command regardless of `crate_type`.
Returns:
@@ -354,6 +392,24 @@
"""
user_link_flags = get_cc_user_link_flags(ctx)
+ if crate_type in ("bin") or rustdoc:
+ is_linking_dynamic_library = False
+ action_name = CPP_LINK_EXECUTABLE_ACTION_NAME
+ elif crate_type in ("dylib"):
+ is_linking_dynamic_library = True
+ action_name = CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME
+ elif crate_type in ("staticlib"):
+ is_linking_dynamic_library = False
+ action_name = CPP_LINK_STATIC_LIBRARY_ACTION_NAME
+ elif crate_type in ("cdylib", "proc-macro"):
+ # Proc macros get compiled as shared libraries to be loaded by the compiler.
+ is_linking_dynamic_library = True
+ action_name = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME
+ elif crate_type in ("lib", "rlib"):
+ fail("Invalid `crate_type` for linking action: {}".format(crate_type))
+ else:
+ fail("Unknown `crate_type`: {}".format(crate_type))
+
# Add linkopt's from dependencies. This includes linkopts from transitive
# dependencies since they get merged up.
for dep in getattr(attr, "deps", []):
@@ -364,23 +420,23 @@
link_variables = cc_common.create_link_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
- is_linking_dynamic_library = False,
+ is_linking_dynamic_library = is_linking_dynamic_library,
runtime_library_search_directories = rpaths,
user_link_flags = user_link_flags,
)
link_args = cc_common.get_memory_inefficient_command_line(
feature_configuration = feature_configuration,
- action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
+ action_name = action_name,
variables = link_variables,
)
link_env = cc_common.get_environment_variables(
feature_configuration = feature_configuration,
- action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
+ action_name = action_name,
variables = link_variables,
)
ld = cc_common.get_tool_for_action(
feature_configuration = feature_configuration,
- action_name = CPP_LINK_EXECUTABLE_ACTION_NAME,
+ action_name = action_name,
)
return ld, link_args, link_env
@@ -426,13 +482,19 @@
# Take the absolute value of hash() since it could be negative.
path_hash = abs(hash(lib.path))
- lib_name = get_lib_name_for_windows(lib) if toolchain.os.startswith("windows") else get_lib_name_default(lib)
+ lib_name = get_lib_name_for_windows(lib) if toolchain.target_os.startswith("windows") else get_lib_name_default(lib)
- prefix = "lib"
- extension = ".a"
- if toolchain.os.startswith("windows"):
+ if toolchain.target_os.startswith("windows"):
prefix = ""
extension = ".lib"
+ elif lib_name.endswith(".pic"):
+ # Strip the .pic suffix
+ lib_name = lib_name[:-4]
+ prefix = "lib"
+ extension = ".pic.a"
+ else:
+ prefix = "lib"
+ extension = ".a"
# Ensure the symlink follows the lib<name>.a pattern on Unix-like platforms
# or <name>.lib on Windows.
@@ -489,7 +551,7 @@
if _is_dylib(lib):
continue
artifact = get_preferred_artifact(lib, use_pic)
- name = get_lib_name_for_windows(artifact) if toolchain.os.startswith("windows") else get_lib_name_default(artifact)
+ name = get_lib_name_for_windows(artifact) if toolchain.target_os.startswith("windows") else get_lib_name_default(artifact)
# On Linux-like platforms, normally library base names start with
# `lib`, following the pattern `lib[name].(a|lo)` and we pass
@@ -499,10 +561,10 @@
# FIXME: Under the native-link-modifiers unstable rustc feature,
# we could use -lstatic:+verbatim instead.
needs_symlink_to_standardize_name = (
- (toolchain.os.startswith("linux") or toolchain.os.startswith("mac") or toolchain.os.startswith("darwin")) and
+ toolchain.target_os.startswith(("linux", "mac", "darwin")) and
artifact.basename.endswith(".a") and not artifact.basename.startswith("lib")
) or (
- toolchain.os.startswith("windows") and not artifact.basename.endswith(".lib")
+ toolchain.target_os.startswith("windows") and not artifact.basename.endswith(".lib")
)
# Detect cases where we need to disambiguate library dependencies
@@ -591,20 +653,16 @@
linker_script = getattr(file, "linker_script") if hasattr(file, "linker_script") else None
linker_depset = cc_toolchain.all_files
+ compilation_mode = ctx.var["COMPILATION_MODE"]
- use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type)
+ use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type, compilation_mode)
# Pass linker inputs only for linking-like actions, not for example where
# the output is rlib. This avoids quadratic behavior where transitive noncrates are
# flattened on each transitive rust_library dependency.
additional_transitive_inputs = []
ambiguous_libs = {}
- if crate_info.type in ("staticlib", "proc-macro"):
- additional_transitive_inputs = _collect_libs_from_linker_inputs(
- dep_info.transitive_noncrates.to_list(),
- use_pic,
- )
- elif crate_info.type in ("bin", "dylib", "cdylib"):
+ if crate_info.type not in ("lib", "rlib"):
linker_inputs = dep_info.transitive_noncrates.to_list()
ambiguous_libs = _disambiguate_libs(ctx.actions, toolchain, crate_info, dep_info, use_pic)
additional_transitive_inputs = _collect_libs_from_linker_inputs(linker_inputs, use_pic) + [
@@ -706,9 +764,9 @@
build_flags_files,
emit = ["dep-info", "link"],
force_all_deps_direct = False,
- force_link = False,
+ rustdoc = False,
stamp = False,
- remap_path_prefix = ".",
+ remap_path_prefix = "",
use_json_output = False,
build_metadata = False,
force_depend_on_objects = False):
@@ -734,10 +792,10 @@
emit (list): Values for the --emit flag to rustc.
force_all_deps_direct (bool, optional): Whether to pass the transitive rlibs with --extern
to the commandline as opposed to -L.
- force_link (bool, optional): Whether to add link flags to the command regardless of `emit`.
+ rustdoc (bool, optional): Whether to add "bin" link flags to the command regardless of `emit` and `crate_type`.
stamp (bool, optional): Whether or not workspace status stamping is enabled. For more details see
https://docs.bazel.build/versions/main/user-manual.html#flag--stamp
- remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to a falsey value, no prefix will be set.
+ remap_path_prefix (str, optional): A value used to remap `${pwd}` to. If set to None, no prefix will be set.
use_json_output (bool): Have rustc emit json and process_wrapper parse json messages to output rendered output.
build_metadata (bool): Generate CLI arguments for building *only* .rmeta files. This requires use_json_output.
force_depend_on_objects (bool): Force using `.rlib` object files instead of metadata (`.rmeta`) files even if they are available.
@@ -840,7 +898,7 @@
json = ["artifacts"]
if error_format == "short":
json.append("diagnostic-short")
- elif error_format == "human" and toolchain.os != "windows":
+ elif error_format == "human" and toolchain.target_os != "windows":
# If the os is not windows, we can get colorized output.
json.append("diagnostic-rendered-ansi")
@@ -874,7 +932,7 @@
rustc_flags.add("--codegen=debuginfo=" + compilation_mode.debug_info)
# For determinism to help with build distribution and such
- if remap_path_prefix:
+ if remap_path_prefix != None:
rustc_flags.add("--remap-path-prefix=${{pwd}}={}".format(remap_path_prefix))
if emit:
@@ -895,8 +953,9 @@
rustc_flags.add_all(rust_std_paths, before_each = "-L", format_each = "%s")
rustc_flags.add_all(rust_flags)
+ # Gather data path from crate_info since it is inherited from real crate for rust_doc and rust_test
# Deduplicate data paths due to https://github.com/bazelbuild/bazel/issues/14681
- data_paths = depset(direct = getattr(attr, "data", []) + getattr(attr, "compile_data", [])).to_list()
+ data_paths = depset(direct = getattr(attr, "data", []), transitive = [crate_info.compile_data_targets]).to_list()
rustc_flags.add_all(
expand_list_element_locations(
@@ -908,21 +967,24 @@
add_edition_flags(rustc_flags, crate_info)
# Link!
- if ("link" in emit and crate_info.type not in ["rlib", "lib"]) or force_link:
+ if ("link" in emit and crate_info.type not in ["rlib", "lib"]) or rustdoc:
# Rust's built-in linker can handle linking wasm files. We don't want to attempt to use the cc
# linker since it won't understand.
+ compilation_mode = ctx.var["COMPILATION_MODE"]
if toolchain.target_arch != "wasm32":
if output_dir:
- use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type)
+ use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_info.type, compilation_mode)
rpaths = _compute_rpaths(toolchain, output_dir, dep_info, use_pic)
else:
rpaths = depset([])
- ld, link_args, link_env = get_linker_and_args(ctx, attr, cc_toolchain, feature_configuration, rpaths)
+
+ ld, link_args, link_env = get_linker_and_args(ctx, attr, crate_info.type, cc_toolchain, feature_configuration, rpaths, rustdoc)
+
env.update(link_env)
rustc_flags.add("--codegen=linker=" + ld)
rustc_flags.add_joined("--codegen", link_args, join_with = " ", format_joined = "link-args=%s")
- _add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, ambiguous_libs, crate_info.type, toolchain, cc_toolchain, feature_configuration)
+ _add_native_link_flags(rustc_flags, dep_info, linkstamp_outs, ambiguous_libs, crate_info.type, toolchain, cc_toolchain, feature_configuration, compilation_mode)
use_metadata = _depend_on_metadata(crate_info, force_depend_on_objects)
@@ -962,6 +1024,11 @@
if toolchain._rename_first_party_crates:
env["RULES_RUST_THIRD_PARTY_DIR"] = toolchain._third_party_dir
+ if is_exec_configuration(ctx):
+ rustc_flags.add_all(toolchain.extra_exec_rustc_flags)
+ else:
+ rustc_flags.add_all(toolchain.extra_rustc_flags)
+
# extra_rustc_flags apply to the target configuration, not the exec configuration.
if hasattr(ctx.attr, "_extra_rustc_flags") and not is_exec_configuration(ctx):
rustc_flags.add_all(ctx.attr._extra_rustc_flags[ExtraRustcFlagsInfo].extra_rustc_flags)
@@ -969,12 +1036,19 @@
if hasattr(ctx.attr, "_extra_rustc_flag") and not is_exec_configuration(ctx):
rustc_flags.add_all(ctx.attr._extra_rustc_flag[ExtraRustcFlagsInfo].extra_rustc_flags)
+ if hasattr(ctx.attr, "_per_crate_rustc_flag") and not is_exec_configuration(ctx):
+ per_crate_rustc_flags = ctx.attr._per_crate_rustc_flag[PerCrateRustcFlagsInfo].per_crate_rustc_flags
+ _add_per_crate_rustc_flags(ctx, rustc_flags, crate_info, per_crate_rustc_flags)
+
if hasattr(ctx.attr, "_extra_exec_rustc_flags") and is_exec_configuration(ctx):
rustc_flags.add_all(ctx.attr._extra_exec_rustc_flags[ExtraExecRustcFlagsInfo].extra_exec_rustc_flags)
if hasattr(ctx.attr, "_extra_exec_rustc_flag") and is_exec_configuration(ctx):
rustc_flags.add_all(ctx.attr._extra_exec_rustc_flag[ExtraExecRustcFlagsInfo].extra_exec_rustc_flags)
+ if _is_no_std(ctx, toolchain, crate_info):
+ rustc_flags.add_all(['--cfg=feature="no_std"'])
+
# Create a struct which keeps the arguments separate so each may be tuned or
# replaced where necessary
args = struct(
@@ -1143,7 +1217,7 @@
# For a cdylib that might be added as a dependency to a cc_* target on Windows, it is important to include the
# interface library that rustc generates in the output files.
interface_library = None
- if toolchain.os == "windows" and crate_info.type == "cdylib":
+ if toolchain.target_os == "windows" and crate_info.type == "cdylib":
# Rustc generates the import library with a `.dll.lib` extension rather than the usual `.lib` one that msvc
# expects (see https://github.com/rust-lang/rust/pull/29520 for more context).
interface_library = ctx.actions.declare_file(crate_info.output.basename + ".lib", sibling = crate_info.output)
@@ -1156,11 +1230,11 @@
# types that benefit from having debug information in a separate file.
pdb_file = None
dsym_folder = None
- if crate_info.type in ("cdylib", "bin") and not crate_info.is_test:
- if toolchain.os == "windows":
+ if crate_info.type in ("cdylib", "bin"):
+ if toolchain.target_os == "windows":
pdb_file = ctx.actions.declare_file(crate_info.output.basename[:-len(crate_info.output.extension)] + "pdb", sibling = crate_info.output)
action_outputs.append(pdb_file)
- elif toolchain.os == "darwin":
+ elif toolchain.target_os == "darwin":
dsym_folder = ctx.actions.declare_directory(crate_info.output.basename + ".dSYM", sibling = crate_info.output)
action_outputs.append(dsym_folder)
@@ -1223,8 +1297,14 @@
pic_objects = depset([output_o]),
)
+ malloc_library = ctx.attr._custom_malloc or ctx.attr.malloc
+
# Collect the linking contexts of the standard library and dependencies.
- linking_contexts = [toolchain.libstd_and_allocator_ccinfo.linking_context, toolchain.stdlib_linkflags.linking_context]
+ linking_contexts = [
+ malloc_library[CcInfo].linking_context,
+ _get_std_and_alloc_info(ctx, toolchain, crate_info).linking_context,
+ toolchain.stdlib_linkflags.linking_context,
+ ]
for dep in crate_info.deps.to_list():
if dep.cc_info:
@@ -1247,6 +1327,25 @@
output_relative_to_package = crate_info.output.path[len(package_dir):]
+ # Compile actions that produce shared libraries create output of the form "libfoo.so" for linux and macos;
+ # cc_common.link expects us to pass "foo" to the name parameter. We cannot simply use crate_info.name because
+ # the name of the crate does not always match the name of output file, e.g a crate named foo-bar will produce
+ # a (lib)foo_bar output file.
+ if crate_info.type == "cdylib":
+ output_lib = crate_info.output.basename
+ if toolchain.target_os != "windows":
+ # Strip the leading "lib" prefix
+ output_lib = output_lib[3:]
+
+ # Strip the file extension
+ output_lib = output_lib[:-(1 + len(crate_info.output.extension))]
+
+ # Remove the basename (which contains the undesired 'lib' prefix and the file extension)
+ output_relative_to_package = output_relative_to_package[:-len(crate_info.output.basename)]
+
+ # Append the name of the library
+ output_relative_to_package = output_relative_to_package + output_lib
+
cc_common.link(
actions = ctx.actions,
feature_configuration = feature_configuration,
@@ -1256,6 +1355,7 @@
name = output_relative_to_package,
grep_includes = ctx.file._grep_includes,
stamp = ctx.attr.stamp,
+ output_type = "executable" if crate_info.type == "bin" else "dynamic_library",
)
outputs = [crate_info.output]
@@ -1268,6 +1368,9 @@
files = getattr(ctx.files, "data", []) + coverage_runfiles,
collect_data = True,
)
+ if getattr(ctx.attr, "crate", None):
+ runfiles = runfiles.merge(ctx.attr.crate[DefaultInfo].default_runfiles)
+ runfiles = runfiles.merge(ctx.attr.crate[DefaultInfo].data_runfiles)
# TODO: Remove after some resolution to
# https://github.com/bazelbuild/rules_rust/issues/771
@@ -1303,9 +1406,29 @@
providers.append(OutputGroupInfo(pdb_file = depset([pdb_file])))
if dsym_folder:
providers.append(OutputGroupInfo(dsym_folder = depset([dsym_folder])))
+ if build_metadata:
+ providers.append(OutputGroupInfo(build_metadata = depset([build_metadata])))
return providers
+def _is_no_std(ctx, toolchain, crate_info):
+ if is_exec_configuration(ctx) or crate_info.is_test:
+ return False
+ if toolchain._no_std == "off":
+ return False
+ return True
+
+def _get_std_and_alloc_info(ctx, toolchain, crate_info):
+ if is_exec_configuration(ctx):
+ return toolchain.libstd_and_allocator_ccinfo
+ if toolchain._experimental_use_global_allocator:
+ if _is_no_std(ctx, toolchain, crate_info):
+ return toolchain.nostd_and_global_allocator_cc_info
+ else:
+ return toolchain.libstd_and_global_allocator_ccinfo
+ else:
+ return toolchain.libstd_and_allocator_ccinfo
+
def _is_dylib(dep):
return not bool(dep.static_library or dep.pic_static_library)
@@ -1403,23 +1526,26 @@
toolchain.stdlib_linkflags,
]
- for dep in getattr(attr, "deps", []):
- if CcInfo in dep:
+ # Flattening is okay since crate_info.deps only records direct deps.
+ for dep in crate_info.deps.to_list():
+ if dep.cc_info:
# A Rust staticlib or shared library doesn't need to propagate linker inputs
# of its dependencies, except for shared libraries.
if crate_info.type in ["cdylib", "staticlib"]:
- shared_linker_inputs = _collect_nonstatic_linker_inputs(dep[CcInfo])
+ shared_linker_inputs = _collect_nonstatic_linker_inputs(dep.cc_info)
if shared_linker_inputs:
linking_context = cc_common.create_linking_context(
linker_inputs = depset(shared_linker_inputs),
)
cc_infos.append(CcInfo(linking_context = linking_context))
else:
- cc_infos.append(dep[CcInfo])
+ cc_infos.append(dep.cc_info)
- if crate_info.type in ("rlib", "lib") and toolchain.libstd_and_allocator_ccinfo:
- # TODO: if we already have an rlib in our deps, we could skip this
- cc_infos.append(toolchain.libstd_and_allocator_ccinfo)
+ if crate_info.type in ("rlib", "lib"):
+ libstd_and_allocator_cc_info = _get_std_and_alloc_info(ctx, toolchain, crate_info)
+ if libstd_and_allocator_cc_info:
+ # TODO: if we already have an rlib in our deps, we could skip this
+ cc_infos.append(libstd_and_allocator_cc_info)
return [cc_common.merge_cc_infos(cc_infos = cc_infos)]
@@ -1485,7 +1611,7 @@
# Windows has no rpath equivalent, so always return an empty depset.
# Fuchsia assembles shared libraries during packaging.
- if toolchain.os == "windows" or toolchain.os == "fuchsia":
+ if toolchain.target_os == "windows" or toolchain.target_os == "fuchsia":
return depset([])
dylibs = [
@@ -1501,9 +1627,9 @@
# without a version of Bazel that includes
# https://github.com/bazelbuild/bazel/pull/13427. This is known to not be
# included in Bazel 4.1 and below.
- if toolchain.os != "linux" and toolchain.os != "darwin":
+ if toolchain.target_os != "linux" and toolchain.target_os != "darwin":
fail("Runtime linking is not supported on {}, but found {}".format(
- toolchain.os,
+ toolchain.target_os,
dep_info.transitive_noncrates,
))
@@ -1608,7 +1734,7 @@
"""
return crate.output.dirname
-def _portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name, for_windows):
+def _portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name, for_windows = False, for_darwin = False, flavor_msvc = False):
artifact = get_preferred_artifact(lib, use_pic)
if ambiguous_libs and artifact.path in ambiguous_libs:
artifact = ambiguous_libs[artifact.path]
@@ -1646,11 +1772,24 @@
artifact.basename.startswith("libtest-") or artifact.basename.startswith("libstd-") or
artifact.basename.startswith("test-") or artifact.basename.startswith("std-")
):
- return ["-lstatic=%s" % get_lib_name(artifact)]
- return [
- "-lstatic=%s" % get_lib_name(artifact),
- "-Clink-arg=-l%s" % (get_lib_name(artifact) if not for_windows else artifact.basename),
- ]
+ return [] if for_darwin else ["-lstatic=%s" % get_lib_name(artifact)]
+
+ if for_windows:
+ if flavor_msvc:
+ return [
+ "-lstatic=%s" % get_lib_name(artifact),
+ "-Clink-arg={}".format(artifact.basename),
+ ]
+ else:
+ return [
+ "-lstatic=%s" % get_lib_name(artifact),
+ "-Clink-arg=-l{}".format(artifact.basename),
+ ]
+ else:
+ return [
+ "-lstatic=%s" % get_lib_name(artifact),
+ "-Clink-arg=-l{}".format(get_lib_name(artifact)),
+ ]
elif _is_dylib(lib):
return [
"-ldylib=%s" % get_lib_name(artifact),
@@ -1658,16 +1797,32 @@
return []
-def _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs):
+def _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc):
linker_input, use_pic, ambiguous_libs = linker_input_and_use_pic_and_ambiguous_libs
ret = []
for lib in linker_input.libraries:
if lib.alwayslink:
- ret.extend(["-C", "link-arg=/WHOLEARCHIVE:%s" % get_preferred_artifact(lib, use_pic).path])
+ if flavor_msvc:
+ ret.extend(["-C", "link-arg=/WHOLEARCHIVE:%s" % get_preferred_artifact(lib, use_pic).path])
+ else:
+ ret.extend([
+ "-C",
+ "link-arg=-Wl,--whole-archive",
+ "-C",
+ ("link-arg=%s" % get_preferred_artifact(lib, use_pic).path),
+ "-C",
+ "link-arg=-Wl,--no-whole-archive",
+ ])
else:
- ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_for_windows, for_windows = True))
+ ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_for_windows, for_windows = True, flavor_msvc = flavor_msvc))
return ret
+def _make_link_flags_windows_msvc(linker_input_and_use_pic_and_ambiguous_libs):
+ return _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc = True)
+
+def _make_link_flags_windows_gnu(linker_input_and_use_pic_and_ambiguous_libs):
+ return _make_link_flags_windows(linker_input_and_use_pic_and_ambiguous_libs, flavor_msvc = False)
+
def _make_link_flags_darwin(linker_input_and_use_pic_and_ambiguous_libs):
linker_input, use_pic, ambiguous_libs = linker_input_and_use_pic_and_ambiguous_libs
ret = []
@@ -1678,7 +1833,7 @@
("link-arg=-Wl,-force_load,%s" % get_preferred_artifact(lib, use_pic).path),
])
else:
- ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default, for_windows = False))
+ ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default, for_darwin = True))
return ret
def _make_link_flags_default(linker_input_and_use_pic_and_ambiguous_libs):
@@ -1695,7 +1850,7 @@
"link-arg=-Wl,--no-whole-archive",
])
else:
- ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default, for_windows = False))
+ ret.extend(_portable_link_flags(lib, use_pic, ambiguous_libs, get_lib_name_default))
return ret
def _libraries_dirnames(linker_input_and_use_pic_and_ambiguous_libs):
@@ -1704,7 +1859,7 @@
# De-duplicate names.
return depset([get_preferred_artifact(lib, use_pic).dirname for lib in link_input.libraries]).to_list()
-def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate_type, toolchain, cc_toolchain, feature_configuration):
+def _add_native_link_flags(args, dep_info, linkstamp_outs, ambiguous_libs, crate_type, toolchain, cc_toolchain, feature_configuration, compilation_mode):
"""Adds linker flags for all dependencies of the current target.
Args:
@@ -1716,16 +1871,17 @@
toolchain (rust_toolchain): The current `rust_toolchain`
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`
feature_configuration (FeatureConfiguration): feature configuration to use with cc_toolchain
+ compilation_mode (bool): The compilation mode for this build.
"""
if crate_type in ["lib", "rlib"]:
return
- use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_type)
+ use_pic = _should_use_pic(cc_toolchain, feature_configuration, crate_type, compilation_mode)
- if toolchain.os == "windows":
- make_link_flags = _make_link_flags_windows
+ if toolchain.target_os == "windows":
+ make_link_flags = _make_link_flags_windows_msvc if toolchain.target_triple.abi == "msvc" else _make_link_flags_windows_gnu
get_lib_name = get_lib_name_for_windows
- elif toolchain.os.startswith("mac") or toolchain.os.startswith("darwin"):
+ elif toolchain.target_os.startswith(("mac", "darwin", "ios")):
make_link_flags = _make_link_flags_darwin
get_lib_name = get_lib_name_default
else:
@@ -1784,6 +1940,32 @@
"""
return file.dirname
+def _add_per_crate_rustc_flags(ctx, args, crate_info, per_crate_rustc_flags):
+ """Adds matching per-crate rustc flags to an arguments object reference
+
+ Args:
+ ctx (ctx): The source rule's context object
+ args (Args): A reference to an Args object
+ crate_info (CrateInfo): A CrateInfo provider
+ per_crate_rustc_flags (list): A list of per_crate_rustc_flag values
+ """
+ for per_crate_rustc_flag in per_crate_rustc_flags:
+ at_index = per_crate_rustc_flag.find("@")
+ if at_index == -1:
+ fail("per_crate_rustc_flag '{}' does not follow the expected format: prefix_filter@flag".format(per_crate_rustc_flag))
+
+ prefix_filter = per_crate_rustc_flag[:at_index]
+ flag = per_crate_rustc_flag[at_index + 1:]
+ if not flag:
+ fail("per_crate_rustc_flag '{}' does not follow the expected format: prefix_filter@flag".format(per_crate_rustc_flag))
+
+ label_string = str(ctx.label)
+ label = label_string[1:] if label_string.startswith("@//") else label_string
+ execution_path = crate_info.root.path
+
+ if label.startswith(prefix_filter) or execution_path.startswith(prefix_filter):
+ args.add(flag)
+
def _error_format_impl(ctx):
"""Implementation of the `error_format` rule
@@ -1862,3 +2044,35 @@
implementation = _extra_exec_rustc_flag_impl,
build_setting = config.string(flag = True, allow_multiple = True),
)
+
+def _per_crate_rustc_flag_impl(ctx):
+ return PerCrateRustcFlagsInfo(per_crate_rustc_flags = [f for f in ctx.build_setting_value if f != ""])
+
+per_crate_rustc_flag = rule(
+ doc = (
+ "Add additional rustc_flag to matching crates from the command line with `--@rules_rust//:experimental_per_crate_rustc_flag`. " +
+ "The expected flag format is prefix_filter@flag, where any crate with a label or execution path starting with the prefix filter will be built with the given flag." +
+ "The label matching uses the canonical form of the label (i.e //package:label_name)." +
+ "The execution path is the relative path to your workspace directory including the base name (including extension) of the crate root." +
+ "This flag is only applied to the exec configuration (proc-macros, cargo_build_script, etc)." +
+ "Multiple uses are accumulated."
+ ),
+ implementation = _per_crate_rustc_flag_impl,
+ build_setting = config.string(flag = True, allow_multiple = True),
+)
+
+def _no_std_impl(ctx):
+ value = str(ctx.attr._no_std[BuildSettingInfo].value)
+ if is_exec_configuration(ctx):
+ return [config_common.FeatureFlagInfo(value = "off")]
+ return [config_common.FeatureFlagInfo(value = value)]
+
+no_std = rule(
+ doc = (
+ "No std; we need this so that we can distinguish between host and exec"
+ ),
+ attrs = {
+ "_no_std": attr.label(default = "//:no_std"),
+ },
+ implementation = _no_std_impl,
+)
diff --git a/rust/private/rustdoc.bzl b/rust/private/rustdoc.bzl
index ba3a12c..f06d18e 100644
--- a/rust/private/rustdoc.bzl
+++ b/rust/private/rustdoc.bzl
@@ -43,6 +43,7 @@
rustc_env_files = crate_info.rustc_env_files,
is_test = crate_info.is_test,
compile_data = crate_info.compile_data,
+ compile_data_targets = crate_info.compile_data_targets,
)
def rustdoc_compile_action(
@@ -121,7 +122,7 @@
build_flags_files = build_flags_files,
emit = [],
remap_path_prefix = None,
- force_link = True,
+ rustdoc = True,
force_depend_on_objects = is_test,
)
@@ -131,6 +132,8 @@
if is_test:
if "SYSROOT" in env:
env.update({"SYSROOT": "${{pwd}}/{}".format(toolchain.sysroot_short_path)})
+ if "OUT_DIR" in env:
+ env.update({"OUT_DIR": "${{pwd}}/{}".format(build_info.out_dir.short_path)})
# `rustdoc` does not support the SYSROOT environment variable. To account
# for this, the flag must be explicitly passed to the `rustdoc` binary.
@@ -175,6 +178,12 @@
ctx (ctx): The rule's context object
"""
+ if ctx.attr.rustc_flags:
+ # buildifier: disable=print
+ print("rustc_flags is deprecated in favor of `rustdoc_flags` for rustdoc targets. Please update {}".format(
+ ctx.label,
+ ))
+
crate = ctx.attr.crate
crate_info = crate[rust_common.crate_info]
@@ -186,6 +195,8 @@
"{}={}".format(crate_info.name, crate_info.output.path),
]
+ rustdoc_flags.extend(ctx.attr.rustdoc_flags)
+
action = rustdoc_compile_action(
ctx = ctx,
toolchain = find_toolchain(ctx),
@@ -210,7 +221,7 @@
return [
DefaultInfo(
- files = depset([ctx.outputs.rust_doc_zip]),
+ files = depset([output_dir]),
),
OutputGroupInfo(
rustdoc_dir = depset([output_dir]),
@@ -287,8 +298,11 @@
allow_files = [".css"],
),
"rustc_flags": attr.string_list(
+ doc = "**Deprecated**: use `rustdoc_flags` instead",
+ ),
+ "rustdoc_flags": attr.string_list(
doc = dedent("""\
- List of compiler flags passed to `rustc`.
+ List of flags passed to `rustdoc`.
These strings are subject to Make variable expansion for predefined
source/output path variables like `$location`, `$execpath`, and
diff --git a/rust/private/rustdoc_test.bzl b/rust/private/rustdoc_test.bzl
index 525838e..9fb73e1 100644
--- a/rust/private/rustdoc_test.bzl
+++ b/rust/private/rustdoc_test.bzl
@@ -64,6 +64,9 @@
# Collect and dedupe all of the file roots in a list before appending
# them to args to prevent generating a large amount of identical args
roots = []
+ root = crate_info.output.root.path
+ if not root in roots:
+ roots.append(root)
for dep in crate_info.deps.to_list():
dep_crate_info = getattr(dep, "crate_info", None)
dep_dep_info = getattr(dep, "dep_info", None)
@@ -115,18 +118,19 @@
srcs = crate.srcs,
deps = depset(deps, transitive = [crate.deps]),
proc_macro_deps = crate.proc_macro_deps,
- aliases = {},
+ aliases = crate.aliases,
output = crate.output,
edition = crate.edition,
rustc_env = crate.rustc_env,
rustc_env_files = crate.rustc_env_files,
is_test = True,
compile_data = crate.compile_data,
+ compile_data_targets = crate.compile_data_targets,
wrapped_crate_type = crate.type,
owner = ctx.label,
)
- if toolchain.os == "windows":
+ if toolchain.target_os == "windows":
test_runner = ctx.actions.declare_file(ctx.label.name + ".rustdoc_test.bat")
else:
test_runner = ctx.actions.declare_file(ctx.label.name + ".rustdoc_test.sh")
diff --git a/rust/private/rustfmt.bzl b/rust/private/rustfmt.bzl
index db5ef43..a7e7100 100644
--- a/rust/private/rustfmt.bzl
+++ b/rust/private/rustfmt.bzl
@@ -1,27 +1,42 @@
"""A module defining rustfmt rules"""
load(":common.bzl", "rust_common")
-load(":utils.bzl", "find_toolchain")
-def _find_rustfmtable_srcs(target, aspect_ctx = None):
- """Parse a target for rustfmt formattable sources.
+def _get_rustfmt_ready_crate_info(target):
+ """Check that a target is suitable for rustfmt and extract the `CrateInfo` provider from it.
Args:
target (Target): The target the aspect is running on.
+
+ Returns:
+ CrateInfo, optional: A `CrateInfo` provider if clippy should be run or `None`.
+ """
+
+ # Ignore external targets
+ if target.label.workspace_root.startswith("external"):
+ return None
+
+ # Obviously ignore any targets that don't contain `CrateInfo`
+ if rust_common.crate_info in target:
+ return target[rust_common.crate_info]
+ elif rust_common.test_crate_info in target:
+ return target[rust_common.test_crate_info].crate
+ else:
+ return None
+
+def _find_rustfmtable_srcs(crate_info, aspect_ctx = None):
+ """Parse a `CrateInfo` provider for rustfmt formattable sources.
+
+ Args:
+ crate_info (CrateInfo): A `CrateInfo` provider.
aspect_ctx (ctx, optional): The aspect's context object.
Returns:
list: A list of formattable sources (`File`).
"""
- if rust_common.crate_info not in target:
- return []
- # Ignore external targets
- if target.label.workspace_root.startswith("external"):
- return []
-
+ # Targets with specific tags will not be formatted
if aspect_ctx:
- # Targets with specifc tags will not be formatted
ignore_tags = [
"no-format",
"no-rustfmt",
@@ -32,8 +47,6 @@
if tag in aspect_ctx.rule.attr.tags:
return []
- crate_info = target[rust_common.crate_info]
-
# Filter out any generated files
srcs = [src for src in crate_info.srcs.to_list() if src.is_source]
@@ -55,7 +68,8 @@
return manifest
def _perform_check(edition, srcs, ctx):
- toolchain = find_toolchain(ctx)
+ rustfmt_toolchain = ctx.toolchains[Label("//rust/rustfmt:toolchain_type")]
+
config = ctx.file._config
marker = ctx.actions.declare_file(ctx.label.name + ".rustfmt.ok")
@@ -63,7 +77,7 @@
args.add("--touch-file")
args.add(marker)
args.add("--")
- args.add(toolchain.rustfmt)
+ args.add(rustfmt_toolchain.rustfmt)
args.add("--config-path")
args.add(config)
args.add("--edition")
@@ -75,7 +89,7 @@
executable = ctx.executable._process_wrapper,
inputs = srcs + [config],
outputs = [marker],
- tools = [toolchain.rustfmt],
+ tools = [rustfmt_toolchain.all_files],
arguments = [args],
mnemonic = "Rustfmt",
)
@@ -83,21 +97,23 @@
return marker
def _rustfmt_aspect_impl(target, ctx):
- srcs = _find_rustfmtable_srcs(target, ctx)
+ crate_info = _get_rustfmt_ready_crate_info(target)
+
+ if not crate_info:
+ return []
+
+ srcs = _find_rustfmtable_srcs(crate_info, ctx)
# If there are no formattable sources, do nothing.
if not srcs:
return []
- # Parse the edition to use for formatting from the target
- edition = target[rust_common.crate_info].edition
+ edition = crate_info.edition
- manifest = _generate_manifest(edition, srcs, ctx)
marker = _perform_check(edition, srcs, ctx)
return [
OutputGroupInfo(
- rustfmt_manifest = depset([manifest]),
rustfmt_checks = depset([marker]),
),
]
@@ -109,7 +125,6 @@
Output Groups:
-- `rustfmt_manifest`: A manifest used by rustfmt binaries to provide crate specific settings.
- `rustfmt_checks`: Executes `rustfmt --check` on the specified target.
The build setting `@rules_rust//:rustfmt.toml` is used to control the Rustfmt [configuration settings][cs]
@@ -135,10 +150,52 @@
),
},
incompatible_use_toolchain_transition = True,
+ required_providers = [
+ [rust_common.crate_info],
+ [rust_common.test_crate_info],
+ ],
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
- str(Label("//rust:toolchain_type")),
+ str(Label("//rust/rustfmt:toolchain_type")),
+ ],
+)
+
+def _rustfmt_test_manifest_aspect_impl(target, ctx):
+ crate_info = _get_rustfmt_ready_crate_info(target)
+
+ if not crate_info:
+ return []
+
+ # Parse the edition to use for formatting from the target
+ edition = crate_info.edition
+
+ srcs = _find_rustfmtable_srcs(crate_info, ctx)
+ manifest = _generate_manifest(edition, srcs, ctx)
+
+ return [
+ OutputGroupInfo(
+ rustfmt_manifest = depset([manifest]),
+ ),
+ ]
+
+# This aspect contains functionality split out of `rustfmt_aspect` which broke when
+# `required_providers` was added to it. Aspects which have `required_providers` seems
+# to not function with attributes that also require providers.
+_rustfmt_test_manifest_aspect = aspect(
+ implementation = _rustfmt_test_manifest_aspect_impl,
+ doc = """\
+This aspect is used to gather information about a crate for use in `rustfmt_test`
+
+Output Groups:
+
+- `rustfmt_manifest`: A manifest used by rustfmt binaries to provide crate specific settings.
+""",
+ incompatible_use_toolchain_transition = True,
+ fragments = ["cpp"],
+ host_fragments = ["cpp"],
+ toolchains = [
+ str(Label("//rust/rustfmt:toolchain_type")),
],
)
@@ -158,8 +215,13 @@
is_executable = True,
)
- manifests = depset(transitive = [target[OutputGroupInfo].rustfmt_manifest for target in ctx.attr.targets])
- srcs = [depset(_find_rustfmtable_srcs(target)) for target in ctx.attr.targets]
+ crate_infos = [_get_rustfmt_ready_crate_info(target) for target in ctx.attr.targets]
+ srcs = [depset(_find_rustfmtable_srcs(crate_info)) for crate_info in crate_infos if crate_info]
+
+ # Some targets may be included in tests but tagged as "no-format". In this
+ # case, there will be no manifest.
+ manifests = [getattr(target[OutputGroupInfo], "rustfmt_manifest", None) for target in ctx.attr.targets]
+ manifests = depset(transitive = [manifest for manifest in manifests if manifest])
runfiles = ctx.runfiles(
transitive_files = depset(transitive = srcs + [manifests]),
@@ -192,8 +254,11 @@
attrs = {
"targets": attr.label_list(
doc = "Rust targets to run `rustfmt --check` on.",
- providers = [rust_common.crate_info],
- aspects = [rustfmt_aspect],
+ providers = [
+ [rust_common.crate_info],
+ [rust_common.test_crate_info],
+ ],
+ aspects = [_rustfmt_test_manifest_aspect],
),
"_runner": attr.label(
doc = "The rustfmt test runner",
@@ -205,21 +270,80 @@
test = True,
)
-def _rustfmt_workspace_name_impl(ctx):
- output = ctx.actions.declare_file(ctx.label.name)
+def _rustfmt_toolchain_impl(ctx):
+ make_variables = {
+ "RUSTFMT": ctx.file.rustfmt.path,
+ }
- ctx.actions.write(
- output = output,
- content = "RUSTFMT_WORKSPACE={}".format(
- ctx.workspace_name,
- ),
+ if ctx.attr.rustc:
+ make_variables.update({
+ "RUSTC": ctx.file.rustc.path,
+ })
+
+ make_variable_info = platform_common.TemplateVariableInfo(make_variables)
+
+ all_files = [ctx.file.rustfmt] + ctx.files.rustc_lib
+ if ctx.file.rustc:
+ all_files.append(ctx.file.rustc)
+
+ toolchain = platform_common.ToolchainInfo(
+ rustfmt = ctx.file.rustfmt,
+ rustc = ctx.file.rustc,
+ rustc_lib = depset(ctx.files.rustc_lib),
+ all_files = depset(all_files),
+ make_variables = make_variable_info,
)
- return [DefaultInfo(
- files = depset([output]),
- )]
+ return [
+ toolchain,
+ make_variable_info,
+ ]
-rustfmt_workspace_name = rule(
- implementation = _rustfmt_workspace_name_impl,
- doc = "A rule for detecting the workspace name for Rustfmt runfiles.",
+rustfmt_toolchain = rule(
+ doc = "A toolchain for [rustfmt](https://rust-lang.github.io/rustfmt/)",
+ implementation = _rustfmt_toolchain_impl,
+ incompatible_use_toolchain_transition = True,
+ attrs = {
+ "rustc": attr.label(
+ doc = "The location of the `rustc` binary. Can be a direct source or a filegroup containing one item.",
+ allow_single_file = True,
+ cfg = "exec",
+ ),
+ "rustc_lib": attr.label(
+ doc = "The libraries used by rustc during compilation.",
+ cfg = "exec",
+ ),
+ "rustfmt": attr.label(
+ doc = "The location of the `rustfmt` binary. Can be a direct source or a filegroup containing one item.",
+ allow_single_file = True,
+ cfg = "exec",
+ mandatory = True,
+ ),
+ },
+ toolchains = [
+ str(Label("@rules_rust//rust:toolchain_type")),
+ ],
+)
+
+def _current_rustfmt_toolchain_impl(ctx):
+ toolchain = ctx.toolchains[str(Label("@rules_rust//rust/rustfmt:toolchain_type"))]
+
+ return [
+ toolchain,
+ toolchain.make_variables,
+ DefaultInfo(
+ files = depset([
+ toolchain.rustfmt,
+ ]),
+ runfiles = ctx.runfiles(transitive_files = toolchain.all_files),
+ ),
+ ]
+
+current_rustfmt_toolchain = rule(
+ doc = "A rule for exposing the current registered `rustfmt_toolchain`.",
+ implementation = _current_rustfmt_toolchain_impl,
+ toolchains = [
+ str(Label("@rules_rust//rust/rustfmt:toolchain_type")),
+ ],
+ incompatible_use_toolchain_transition = True,
)
diff --git a/rust/private/toolchain_utils.bzl b/rust/private/toolchain_utils.bzl
index 13c94ac..c89a447 100644
--- a/rust/private/toolchain_utils.bzl
+++ b/rust/private/toolchain_utils.bzl
@@ -81,16 +81,20 @@
def _current_rust_toolchain_impl(ctx):
toolchain = ctx.toolchains[str(Label("@rules_rust//rust:toolchain_type"))]
+ files = [
+ toolchain.rustc,
+ toolchain.rust_doc,
+ toolchain.cargo,
+ ]
+
+ if toolchain.rustfmt:
+ files.append(toolchain.rustfmt)
+
return [
toolchain,
toolchain.make_variables,
DefaultInfo(
- files = depset([
- toolchain.rustc,
- toolchain.rust_doc,
- toolchain.rustfmt,
- toolchain.cargo,
- ]),
+ files = depset(files),
),
]
diff --git a/rust/private/transitions.bzl b/rust/private/transitions.bzl
index 23336f4..cbc6a06 100644
--- a/rust/private/transitions.bzl
+++ b/rust/private/transitions.bzl
@@ -1,26 +1,7 @@
-# buildifier: disable=module-docstring
+"""Internal transition implementations for core Rust rules"""
+
load("//rust:defs.bzl", "rust_common")
-def _wasm_bindgen_transition(_settings, _attr):
- """The implementation of the `wasm_bindgen_transition` transition
-
- Args:
- _settings (dict): A dict {String:Object} of all settings declared
- in the inputs parameter to `transition()`
- _attr (dict): A dict of attributes and values of the rule to which
- the transition is attached
-
- Returns:
- dict: A dict of new build settings values to apply
- """
- return {"//command_line_option:platforms": str(Label("//rust/platform:wasm"))}
-
-wasm_bindgen_transition = transition(
- implementation = _wasm_bindgen_transition,
- inputs = [],
- outputs = ["//command_line_option:platforms"],
-)
-
def _import_macro_dep_bootstrap_transition(_settings, _attr):
"""The implementation of the `import_macro_dep_bootstrap_transition` transition.
diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl
index 583dc6e..879e2b6 100644
--- a/rust/private/utils.bzl
+++ b/rust/private/utils.bzl
@@ -15,7 +15,7 @@
"""Utility functions not specific to the rust toolchain."""
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", find_rules_cc_toolchain = "find_cpp_toolchain")
-load(":providers.bzl", "BuildInfo", "CrateInfo", "DepInfo", "DepVariantInfo")
+load(":providers.bzl", "BuildInfo", "CrateGroupInfo", "CrateInfo", "DepInfo", "DepVariantInfo")
UNSUPPORTED_FEATURES = [
"thin_lto",
@@ -135,7 +135,7 @@
# so the following doesn't work:
# args.add_all(
# cc_toolchain.dynamic_runtime_lib(feature_configuration = feature_configuration),
-# map_each = lambda x: get_lib_name(x, for_windows = toolchain.os.startswith("windows)),
+# map_each = lambda x: get_lib_name(x, for_windows = toolchain.target_os.startswith("windows)),
# format_each = "-ldylib=%s",
# )
def get_lib_name_for_windows(lib):
@@ -223,7 +223,19 @@
library_to_link.dynamic_library
)
-def _expand_location(ctx, env, data):
+# The normal ctx.expand_location, but with an additional deduplication step.
+# We do this to work around a potential crash, see
+# https://github.com/bazelbuild/bazel/issues/16664
+def dedup_expand_location(ctx, input, targets = []):
+ return ctx.expand_location(input, _deduplicate(targets))
+
+def _deduplicate(xs):
+ return {x: True for x in xs}.keys()
+
+def concat(xss):
+ return [x for xs in xss for x in xs]
+
+def _expand_location_for_build_script_runner(ctx, env, data):
"""A trivial helper for `expand_dict_value_locations` and `expand_list_element_locations`
Args:
@@ -240,7 +252,7 @@
env = env.replace(directive, "$${pwd}/" + directive)
return ctx.expand_make_variables(
env,
- ctx.expand_location(env, data),
+ dedup_expand_location(ctx, env, data),
{},
)
@@ -273,7 +285,7 @@
Returns:
dict: A dict of environment variables with expanded location macros
"""
- return dict([(k, _expand_location(ctx, v, data)) for (k, v) in env.items()])
+ return dict([(k, _expand_location_for_build_script_runner(ctx, v, data)) for (k, v) in env.items()])
def expand_list_element_locations(ctx, args, data):
"""Performs location-macro expansion on a list of string values.
@@ -296,7 +308,7 @@
Returns:
list: A list of arguments with expanded location macros
"""
- return [_expand_location(ctx, arg, data) for arg in args]
+ return [_expand_location_for_build_script_runner(ctx, arg, data) for arg in args]
def name_to_crate_name(name):
"""Converts a build target's name into the name of its associated crate.
@@ -463,6 +475,7 @@
dep_info = dep[DepInfo] if DepInfo in dep else None,
build_info = dep[BuildInfo] if BuildInfo in dep else None,
cc_info = dep[CcInfo] if CcInfo in dep else None,
+ crate_group_info = dep[CrateGroupInfo] if CrateGroupInfo in dep else None,
) for dep in deps]
def get_import_macro_deps(ctx):
@@ -667,6 +680,48 @@
# 3) process_wrapper is enabled (this is disabled when compiling process_wrapper itself),
# 4) the crate_type is rlib or lib.
return toolchain._pipelined_compilation and \
- toolchain.os != "windows" and \
+ toolchain.exec_triple.system != "windows" and \
ctx.attr._process_wrapper and \
crate_type in ("rlib", "lib")
+
+def crate_root_src(name, srcs, crate_type):
+ """Determines the source file for the crate root, should it not be specified in `attr.crate_root`.
+
+ Args:
+ name (str): The name of the target.
+ srcs (list): A list of all sources for the target Crate.
+ crate_type (str): The type of this crate ("bin", "lib", "rlib", "cdylib", etc).
+
+ Returns:
+ File: The root File object for a given crate. See the following links for more details:
+ - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#library
+ - https://doc.rust-lang.org/cargo/reference/cargo-targets.html#binaries
+ """
+ default_crate_root_filename = "main.rs" if crate_type == "bin" else "lib.rs"
+
+ crate_root = (
+ (srcs[0] if len(srcs) == 1 else None) or
+ _shortest_src_with_basename(srcs, default_crate_root_filename) or
+ _shortest_src_with_basename(srcs, name + ".rs")
+ )
+ if not crate_root:
+ file_names = [default_crate_root_filename, name + ".rs"]
+ fail("No {} source file found.".format(" or ".join(file_names)), "srcs")
+ return crate_root
+
+def _shortest_src_with_basename(srcs, basename):
+ """Finds the shortest among the paths in srcs that match the desired basename.
+
+ Args:
+ srcs (list): A list of File objects
+ basename (str): The target basename to match against.
+
+ Returns:
+ File: The File object with the shortest path that matches `basename`
+ """
+ shortest = None
+ for f in srcs:
+ if f.basename == basename:
+ if not shortest or len(f.dirname) < len(shortest.dirname):
+ shortest = f
+ return shortest