From a862cde738e1c06a347029d960e8abe21b1feb43 Mon Sep 17 00:00:00 2001 From: UebelAndre Date: Thu, 1 Jul 2021 12:56:29 -0700 Subject: [PATCH] Added `rust_stdlib_filegroup` rule, a helper for creating toolchains (#802) * Added `rust_stdlib_filegroup` rule, a helper for creating toolchains * Updated error messaging. * Rewrite the error message * Updated code to reflect messaging * Plugged in docs * Regenerate documentation Co-authored-by: Marcel Hlopko --- docs/BUILD.bazel | 1 + docs/flatten.md | 20 +++++ docs/rust_repositories.md | 20 +++++ docs/symbols.bzl | 2 + rust/defs.bzl | 7 ++ rust/private/common.bzl | 3 +- rust/private/providers.bzl | 17 +++++ rust/private/repository_utils.bzl | 4 +- rust/toolchain.bzl | 118 +++++++++++++++++++++--------- 9 files changed, 154 insertions(+), 38 deletions(-) diff --git a/docs/BUILD.bazel b/docs/BUILD.bazel index acb3adedfb..2637c52433 100644 --- a/docs/BUILD.bazel +++ b/docs/BUILD.bazel @@ -113,6 +113,7 @@ PAGES = dict([ "rust_toolchain", "rust_toolchain_repository", "rust_toolchain_repository_proxy", + "rust_stdlib_filegroup", ], ), page( diff --git a/docs/flatten.md b/docs/flatten.md index 18ca079eb3..475af2850c 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -25,6 +25,7 @@ * [rust_repository_set](#rust_repository_set) * [rust_shared_library](#rust_shared_library) * [rust_static_library](#rust_static_library) +* [rust_stdlib_filegroup](#rust_stdlib_filegroup) * [rust_test](#rust_test) * [rust_test_suite](#rust_test_suite) * [rust_toolchain](#rust_toolchain) @@ -893,6 +894,25 @@ When building the whole binary in Bazel, use `rust_library` instead. | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | + + +## rust_stdlib_filegroup + +
+rust_stdlib_filegroup(name, srcs)
+
+ +A dedicated filegroup-like rule for Rust stdlib artifacts. + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| srcs | The list of targets/files that are components of the rust-stdlib file group | List of labels | required | | + + ## rust_test diff --git a/docs/rust_repositories.md b/docs/rust_repositories.md index 55b0264bc6..9da7eeb0ad 100644 --- a/docs/rust_repositories.md +++ b/docs/rust_repositories.md @@ -6,6 +6,26 @@ * [rust_toolchain](#rust_toolchain) * [rust_toolchain_repository](#rust_toolchain_repository) * [rust_toolchain_repository_proxy](#rust_toolchain_repository_proxy) +* [rust_stdlib_filegroup](#rust_stdlib_filegroup) + + + +## rust_stdlib_filegroup + +
+rust_stdlib_filegroup(name, srcs)
+
+ +A dedicated filegroup-like rule for Rust stdlib artifacts. + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| srcs | The list of targets/files that are components of the rust-stdlib file group | List of labels | required | | + diff --git a/docs/symbols.bzl b/docs/symbols.bzl index fc9a7a2174..f6738eee8f 100644 --- a/docs/symbols.bzl +++ b/docs/symbols.bzl @@ -62,6 +62,7 @@ load( ) load( "@rules_rust//rust:toolchain.bzl", + _rust_stdlib_filegroup = "rust_stdlib_filegroup", _rust_toolchain = "rust_toolchain", ) load( @@ -96,6 +97,7 @@ rust_bindgen_repositories = _rust_bindgen_repositories rust_toolchain = _rust_toolchain rust_proto_toolchain = _rust_proto_toolchain rust_proto_repositories = _rust_proto_repositories +rust_stdlib_filegroup = _rust_stdlib_filegroup cargo_build_script = _cargo_build_script diff --git a/rust/defs.bzl b/rust/defs.bzl index 112086d157..1bf7f17e3c 100644 --- a/rust/defs.bzl +++ b/rust/defs.bzl @@ -14,6 +14,10 @@ """Public entry point to all Rust rules and supported APIs.""" +load( + "//rust:toolchain.bzl", + _rust_stdlib_filegroup = "rust_stdlib_filegroup", +) load( "//rust/private:clippy.bzl", _rust_clippy = "rust_clippy", @@ -111,3 +115,6 @@ rustfmt_aspect = _rustfmt_aspect rustfmt_test = _rustfmt_test # See @rules_rust//rust/private:rustfmt.bzl for a complete description. + +rust_stdlib_filegroup = _rust_stdlib_filegroup +# See @rules_rust//rust:toolchain.bzl for a complete description. diff --git a/rust/private/common.bzl b/rust/private/common.bzl index b4b56f9d63..9e93068130 100644 --- a/rust/private/common.bzl +++ b/rust/private/common.bzl @@ -23,7 +23,7 @@ which exports the `rust_common` struct. In the Bazel lingo, `rust_common` gives the access to the Rust Sandwich API. """ -load(":providers.bzl", "CrateInfo", "DepInfo") +load(":providers.bzl", "CrateInfo", "DepInfo", "StdLibInfo") def _create_crate_info(**kwargs): """A constructor for a `CrateInfo` provider @@ -43,4 +43,5 @@ rust_common = struct( create_crate_info = _create_crate_info, crate_info = CrateInfo, dep_info = DepInfo, + stdlib_info = StdLibInfo, ) diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl index 53bfbc8e14..db5f637c59 100644 --- a/rust/private/providers.bzl +++ b/rust/private/providers.bzl @@ -42,3 +42,20 @@ DepInfo = provider( "transitive_noncrates": "depset[LinkerInput]: All transitive dependencies that aren't crates.", }, ) + +StdLibInfo = provider( + doc = ( + "A collection of files either found within the `rust-stdlib` artifact or " + + "generated based on existing files." + ), + fields = { + "alloc_files": "List[File]: `.a` files related to the `alloc` module.", + "between_alloc_and_core_files": "List[File]: `.a` files related to the `compiler_builtins` module.", + "between_core_and_std_files": "List[File]: `.a` files related to all modules except `adler`, `alloc`, `compiler_builtins`, `core`, and `std`.", + "core_files": "List[File]: `.a` files related to the `core` and `adler` modules", + "dot_a_files": "Depset[File]: Generated `.a` files", + "srcs": "List[Target]: The original `src` attribute.", + "std_files": "Depset[File]: `.a` files associated with the `std` module.", + "std_rlibs": "List[File]: All `.rlib` files", + }, +) diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl index 1560006afa..1be176fc7e 100644 --- a/rust/private/repository_utils.bzl +++ b/rust/private/repository_utils.bzl @@ -138,7 +138,9 @@ def BUILD_for_clippy(target_triple): return _build_file_for_clippy_template.format(binary_ext = system_to_binary_ext(system)) _build_file_for_stdlib_template = """\ -filegroup( +load("@rules_rust//rust:toolchain.bzl", "rust_stdlib_filegroup") + +rust_stdlib_filegroup( name = "rust_lib-{target_triple}", srcs = glob( [ diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index 15c4792bcf..ef2d269fae 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -1,48 +1,32 @@ """The rust_toolchain rule definition and implementation.""" -load( - "//rust/private:utils.bzl", - "find_cc_toolchain", -) +load("//rust/private:common.bzl", "rust_common") +load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain") -def _make_dota(ctx, f): +def _make_dota(ctx, file): """Add a symlink for a file that ends in .a, so it can be used as a staticlib. Args: ctx (ctx): The rule's context object. - f (File): The file to symlink. + file (File): The file to symlink. Returns: The symlink's File. """ - dot_a = ctx.actions.declare_file(f.basename + ".a", sibling = f) - ctx.actions.symlink(output = dot_a, target_file = f) + dot_a = ctx.actions.declare_file(file.basename + ".a", sibling = file) + ctx.actions.symlink(output = dot_a, target_file = file) return dot_a -def _ltl(library, ctx, cc_toolchain, feature_configuration): - return cc_common.create_library_to_link( - actions = ctx.actions, - feature_configuration = feature_configuration, - cc_toolchain = cc_toolchain, - static_library = library, - pic_static_library = library, - ) - -def _make_libstd_and_allocator_ccinfo(ctx, rust_lib, allocator_library): - """Make the CcInfo (if possible) for libstd and allocator libraries. +def _rust_stdlib_filegroup_impl(ctx): + rust_lib = ctx.files.srcs + dot_a_files = [] + between_alloc_and_core_files = [] + core_files = [] + between_core_and_std_files = [] + std_files = [] + alloc_files = [] - Args: - ctx (ctx): The rule's context object. - rust_lib: The rust standard library. - allocator_library: The target to use for providing allocator functions. - - - Returns: - A CcInfo object for the required libraries, or None if no such libraries are available. - """ - cc_toolchain, feature_configuration = find_cc_toolchain(ctx) - link_inputs = [] - std_rlibs = [f for f in rust_lib.files.to_list() if f.basename.endswith(".rlib")] + std_rlibs = [f for f in rust_lib if f.basename.endswith(".rlib")] if std_rlibs: # std depends on everything # @@ -71,26 +55,88 @@ def _make_libstd_and_allocator_ccinfo(ctx, rust_lib, allocator_library): print("File partitioned: {}".format(f.basename)) fail("rust_toolchain couldn't properly partition rlibs in rust_lib. Partitioned {} out of {} files. This is probably a bug in the rule implementation.".format(partitioned_files_len, len(dot_a_files))) + return [ + DefaultInfo( + files = depset(ctx.files.srcs), + ), + rust_common.stdlib_info( + std_rlibs = std_rlibs, + dot_a_files = dot_a_files, + between_alloc_and_core_files = between_alloc_and_core_files, + core_files = core_files, + between_core_and_std_files = between_core_and_std_files, + std_files = std_files, + alloc_files = alloc_files, + ), + ] + +rust_stdlib_filegroup = rule( + doc = "A dedicated filegroup-like rule for Rust stdlib artifacts.", + implementation = _rust_stdlib_filegroup_impl, + attrs = { + "srcs": attr.label_list( + allow_files = True, + doc = "The list of targets/files that are components of the rust-stdlib file group", + mandatory = True, + ), + }, +) + +def _ltl(library, ctx, cc_toolchain, feature_configuration): + return cc_common.create_library_to_link( + actions = ctx.actions, + feature_configuration = feature_configuration, + cc_toolchain = cc_toolchain, + static_library = library, + pic_static_library = library, + ) + +def _make_libstd_and_allocator_ccinfo(ctx, rust_lib, allocator_library): + """Make the CcInfo (if possible) for libstd and allocator libraries. + + Args: + ctx (ctx): The rule's context object. + rust_lib: The rust standard library. + allocator_library: The target to use for providing allocator functions. + + + Returns: + A CcInfo object for the required libraries, or None if no such libraries are available. + """ + cc_toolchain, feature_configuration = find_cc_toolchain(ctx) + link_inputs = [] + + if not rust_common.stdlib_info in ctx.attr.rust_lib: + fail(dedent("""\ + {} -- + The `rust_lib` must be a target providing `rust_common.stdlib_info` + (typically `rust_stdlib_filegroup` rule from @rules_rust//rust:defs.bzl). + See https://github.com/bazelbuild/rules_rust/pull/802 for more information. + + """).format(ctx.label)) + rust_stdlib_info = ctx.attr.rust_lib[rust_common.stdlib_info] + + if rust_stdlib_info.std_rlibs: alloc_inputs = depset( - [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in alloc_files], + [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.alloc_files], ) between_alloc_and_core_inputs = depset( - [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in between_alloc_and_core_files], + [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.between_alloc_and_core_files], transitive = [alloc_inputs], order = "topological", ) core_inputs = depset( - [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in core_files], + [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.core_files], transitive = [between_alloc_and_core_inputs], order = "topological", ) between_core_and_std_inputs = depset( - [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in between_core_and_std_files], + [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.between_core_and_std_files], transitive = [core_inputs], order = "topological", ) std_inputs = depset( - [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in std_files], + [_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.std_files], transitive = [between_core_and_std_inputs], order = "topological", )