From a862cde738e1c06a347029d960e8abe21b1feb43 Mon Sep 17 00:00:00 2001 From: UebelAndre Date: Thu, 1 Jul 2021 12:56:29 -0700 Subject: [PATCH 1/2] 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", ) From 4bf51b3c790c4c3d0ee8c28c15b7307b64a7069a Mon Sep 17 00:00:00 2001 From: RS Date: Thu, 1 Jul 2021 13:02:28 -0700 Subject: [PATCH 2/2] Expand arg location in rustc_flags attribute (#809) Expand locations in rustc_flags. Fixes #801. --- cargo/cargo_build_script.bzl | 4 +- docs/defs.md | 14 ++--- docs/flatten.md | 14 ++--- examples/flag_locations/BUILD.bazel | 23 ++++++++ examples/flag_locations/main.rs | 9 ++++ rust/private/rust.bzl | 13 +++-- rust/private/rustc.bzl | 19 ++++--- rust/private/utils.bzl | 25 ++++++++- test/unit/location_expansion/BUILD.bazel | 4 ++ .../location_expansion_test.bzl | 54 +++++++++++++++++++ test/unit/location_expansion/mylibrary.rs | 1 + util/launcher/launcher_main.rs | 2 +- 12 files changed, 155 insertions(+), 27 deletions(-) create mode 100644 examples/flag_locations/BUILD.bazel create mode 100644 examples/flag_locations/main.rs create mode 100644 test/unit/location_expansion/BUILD.bazel create mode 100644 test/unit/location_expansion/location_expansion_test.bzl create mode 100644 test/unit/location_expansion/mylibrary.rs diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index 1ac0f0dddd..7500920435 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -8,7 +8,7 @@ load("//rust:rust.bzl", "rust_binary") load("//rust/private:rustc.bzl", "BuildInfo", "get_compilation_mode_opts", "get_linker_and_args") # buildifier: disable=bzl-visibility -load("//rust/private:utils.bzl", "expand_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name") +load("//rust/private:utils.bzl", "expand_dict_value_locations", "find_cc_toolchain", "find_toolchain", "name_to_crate_name") def get_cc_compile_env(cc_toolchain, feature_configuration): """Gather cc environment variables from the given `cc_toolchain` @@ -117,7 +117,7 @@ def _build_script_impl(ctx): for f in ctx.attr.crate_features: env["CARGO_FEATURE_" + f.upper().replace("-", "_")] = "1" - env.update(expand_locations( + env.update(expand_dict_value_locations( ctx, ctx.attr.build_script_env, getattr(ctx.attr, "data", []) + diff --git a/docs/defs.md b/docs/defs.md index e486b30605..6a846d27a1 100644 --- a/docs/defs.md +++ b/docs/defs.md @@ -112,7 +112,7 @@ Run the benchmark test using: `bazel run //fibonacci:fibonacci_bench`. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -230,7 +230,7 @@ Hello world | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -325,7 +325,7 @@ INFO: Elapsed time: 1.245s, Critical Path: 1.01s | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -359,7 +359,7 @@ Builds a Rust proc-macro crate. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -401,7 +401,7 @@ When building the whole binary in Bazel, use `rust_library` instead. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -443,7 +443,7 @@ When building the whole binary in Bazel, use `rust_library` instead. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -605,7 +605,7 @@ Run the test with `bazel build //hello_lib:hello_lib_test`. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | use_libtest_harness | Whether to use libtest. | Boolean | optional | True | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | diff --git a/docs/flatten.md b/docs/flatten.md index 475af2850c..d6ae3a08aa 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -203,7 +203,7 @@ Run the benchmark test using: `bazel run //fibonacci:fibonacci_bench`. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -321,7 +321,7 @@ Hello world | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -671,7 +671,7 @@ INFO: Elapsed time: 1.245s, Critical Path: 1.01s | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -705,7 +705,7 @@ Builds a Rust proc-macro crate. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -847,7 +847,7 @@ When building the whole binary in Bazel, use `rust_library` instead. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -889,7 +889,7 @@ When building the whole binary in Bazel, use `rust_library` instead. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | @@ -1070,7 +1070,7 @@ Run the test with `bazel build //hello_lib:hello_lib_test`. | proc_macro_deps | List of rust_library targets with kind proc-macro used to help build this library target. | List of labels | optional | [] | | rustc_env | Dictionary of additional "key": "value" environment variables to set for rustc.

rust_test()/rust_binary() rules can use $(rootpath //package:target) to pass in the location of a generated file or external tool. Cargo build scripts that wish to expand locations should use cargo_build_script()'s build_script_env argument instead, as build scripts are run in a different environment - see cargo_build_script()'s documentation for more. | Dictionary: String -> String | optional | {} | | rustc_env_files | Files containing additional environment variables to set for rustc.

These files should contain a single variable per line, of format NAME=value, and newlines may be included in a value by ending a line with a trailing back-slash (\).

The order that these files will be processed is unspecified, so multiple definitions of a particular variable are discouraged. | List of labels | optional | [] | -| rustc_flags | List of compiler flags passed to rustc. | List of strings | optional | [] | +| rustc_flags | List of compiler flags passed to rustc.

These strings are subject to Make variable expansion for predefined source/output path variables like $location, $execpath, and $rootpath. This expansion is useful if you wish to pass a generated file of arguments to rustc: @$(location //package:target). | List of strings | optional | [] | | srcs | List of Rust .rs source files used to build the library.

If srcs contains more than one file, then there must be a file either named lib.rs. Otherwise, crate_root must be set to the source file that is the root of the crate to be passed to rustc to build this crate. | List of labels | optional | [] | | use_libtest_harness | Whether to use libtest. | Boolean | optional | True | | version | A version to inject in the cargo environment variable. | String | optional | "0.0.0" | diff --git a/examples/flag_locations/BUILD.bazel b/examples/flag_locations/BUILD.bazel new file mode 100644 index 0000000000..ed54cdae4c --- /dev/null +++ b/examples/flag_locations/BUILD.bazel @@ -0,0 +1,23 @@ +load( + "@rules_rust//rust:rust.bzl", + "rust_test", +) + +# generate a file containing cfg flags +genrule( + name = "flag_generator", + outs = ["generated_flag.data"], + cmd = "echo --cfg=test_flag > $@", +) + +rust_test( + name = "test", + srcs = [ + "main.rs", + ], + data = [":flag_generator"], + edition = "2018", + rustc_flags = [ + "@$(location :flag_generator)", + ], +) diff --git a/examples/flag_locations/main.rs b/examples/flag_locations/main.rs new file mode 100644 index 0000000000..cee1077015 --- /dev/null +++ b/examples/flag_locations/main.rs @@ -0,0 +1,9 @@ +#[test] +fn test() { + // we should be able to read rustc args from a generated file + if cfg!(test_flag) { + return; + } + + unreachable!(); +} diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index 45a429997d..0a154274fc 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -20,7 +20,7 @@ load( "crate_name_from_attr", "dedent", "determine_output_hash", - "expand_locations", + "expand_dict_value_locations", "find_toolchain", ) @@ -340,7 +340,7 @@ def _create_test_launcher(ctx, toolchain, output, providers): # Expand the environment variables and write them to a file environ_file = ctx.actions.declare_file(launcher_filename + ".launchfiles/env") - environ = expand_locations( + environ = expand_dict_value_locations( ctx, getattr(ctx.attr, "env", {}), data, @@ -620,7 +620,14 @@ _common_attrs = { """), ), "rustc_flags": attr.string_list( - doc = "List of compiler flags passed to `rustc`.", + doc = dedent("""\ + List of compiler flags passed to `rustc`. + + These strings are subject to Make variable expansion for predefined + source/output path variables like `$location`, `$execpath`, and `$rootpath`. + This expansion is useful if you wish to pass a generated file of + arguments to rustc: `@$(location //package:target)`. + """), ), # TODO(stardoc): How do we provide additional documentation to an inherited attribute? # "name": attr.string( diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 367474d403..55a07ab3c4 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -21,7 +21,8 @@ load("//rust/private:common.bzl", "rust_common") load( "//rust/private:utils.bzl", "crate_name_from_attr", - "expand_locations", + "expand_dict_value_locations", + "expand_list_element_locations", "find_cc_toolchain", "get_lib_name", "get_preferred_artifact", @@ -438,9 +439,16 @@ def construct_arguments( # Tell Rustc where to find the standard library args.add_all(rust_lib_paths, before_each = "-L", format_each = "%s") - args.add_all(rust_flags) - args.add_all(getattr(attr, "rustc_flags", [])) + + data_paths = getattr(attr, "data", []) + getattr(attr, "compile_data", []) + args.add_all( + expand_list_element_locations( + ctx, + getattr(attr, "rustc_flags", []), + data_paths, + ), + ) add_edition_flags(args, crate_info) # Link! @@ -471,11 +479,10 @@ def construct_arguments( env["CARGO_BIN_EXE_" + dep_crate_info.output.basename] = dep_crate_info.output.short_path # Update environment with user provided variables. - env.update(expand_locations( + env.update(expand_dict_value_locations( ctx, crate_info.rustc_env, - getattr(attr, "data", []) + - getattr(attr, "compile_data", []), + data_paths, )) # This empty value satisfies Clippy, which otherwise complains about the diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index 7d22208d63..30b8aee1c2 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -152,7 +152,7 @@ def _expand_location(ctx, env, data): env = env.replace(directive, "${pwd}/" + directive) return ctx.expand_location(env, data) -def expand_locations(ctx, env, data): +def expand_dict_value_locations(ctx, env, data): """Performs location-macro expansion on string values. $(execroot ...) and $(location ...) are prefixed with ${pwd}, @@ -167,6 +167,8 @@ def expand_locations(ctx, env, data): as compilation happens in a separate sandbox folder, so when it comes time to read the file at runtime, the path is no longer valid. + See [`expand_location`](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#expand_location) for detailed documentation. + Args: ctx (ctx): The rule's context object env (dict): A dict whose values we iterate over @@ -179,6 +181,27 @@ def expand_locations(ctx, env, data): """ return dict([(k, _expand_location(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. + + $(execroot ...) and $(location ...) are prefixed with ${pwd}, + which process_wrapper and build_script_runner will expand at run time + to the absolute path. + + See [`expand_location`](https://docs.bazel.build/versions/main/skylark/lib/ctx.html#expand_location) for detailed documentation. + + Args: + ctx (ctx): The rule's context object + args (list): A list we iterate over + data (sequence of Targets): The targets which may be referenced by + location macros. This is expected to be the `data` attribute of + the target, though may have other targets or attributes mixed in. + + Returns: + list: A list of arguments with expanded location macros + """ + return [_expand_location(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. diff --git a/test/unit/location_expansion/BUILD.bazel b/test/unit/location_expansion/BUILD.bazel new file mode 100644 index 0000000000..83bf6c6ed1 --- /dev/null +++ b/test/unit/location_expansion/BUILD.bazel @@ -0,0 +1,4 @@ +load(":location_expansion_test.bzl", "location_expansion_test_suite") + +############################ UNIT TESTS ############################# +location_expansion_test_suite(name = "location_expansion_test_suite") diff --git a/test/unit/location_expansion/location_expansion_test.bzl b/test/unit/location_expansion/location_expansion_test.bzl new file mode 100644 index 0000000000..c2aa1940e6 --- /dev/null +++ b/test/unit/location_expansion/location_expansion_test.bzl @@ -0,0 +1,54 @@ +"""Unittest to verify location expansion in rustc flags""" + +load("@bazel_skylib//lib:unittest.bzl", "analysistest") +load("//rust:defs.bzl", "rust_library") +load("//test/unit:common.bzl", "assert_action_mnemonic", "assert_argv_contains") + +def _location_expansion_rustc_flags_test(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env) + action = tut.actions[0] + argv = action.argv + assert_action_mnemonic(env, action, "Rustc") + assert_argv_contains(env, action, "test/unit/location_expansion/mylibrary.rs") + expected = "@${pwd}/" + ctx.bin_dir.path + "/test/unit/location_expansion/generated_flag.data" + assert_argv_contains(env, action, expected) + return analysistest.end(env) + +location_expansion_rustc_flags_test = analysistest.make(_location_expansion_rustc_flags_test) + +def _location_expansion_test(): + native.genrule( + name = "flag_generator", + outs = ["generated_flag.data"], + cmd = "echo --cfg=test_flag > $@", + ) + + rust_library( + name = "mylibrary", + srcs = ["mylibrary.rs"], + rustc_flags = [ + "@$(location :flag_generator)", + ], + compile_data = [":flag_generator"], + ) + + location_expansion_rustc_flags_test( + name = "location_expansion_rustc_flags_test", + target_under_test = ":mylibrary", + ) + +def location_expansion_test_suite(name): + """Entry-point macro called from the BUILD file. + + Args: + name: Name of the macro. + """ + _location_expansion_test() + + native.test_suite( + name = name, + tests = [ + ":location_expansion_rustc_flags_test", + ], + ) diff --git a/test/unit/location_expansion/mylibrary.rs b/test/unit/location_expansion/mylibrary.rs new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/test/unit/location_expansion/mylibrary.rs @@ -0,0 +1 @@ + diff --git a/util/launcher/launcher_main.rs b/util/launcher/launcher_main.rs index 10a2a09ff8..02ffbf2d7d 100644 --- a/util/launcher/launcher_main.rs +++ b/util/launcher/launcher_main.rs @@ -22,7 +22,7 @@ fn environ() -> BTreeMap { let file = File::open(env_path).expect("Failed to load the environment file"); // Variables will have the `${pwd}` variable replaced which is rendered by - // `@rules_rust//rust/private:util.bzl::expand_locations` + // `@rules_rust//rust/private:util.bzl::expand_dict_value_locations` let pwd = std::env::current_dir().expect("Failed to get current working directory"); let pwd_str = pwd.to_string_lossy();