From 8a86a208e26b9c8b4b202166e090839986cd0dd4 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 7 Feb 2022 14:08:12 +0100 Subject: [PATCH 1/4] add an example using rustc_driver --- WORKSPACE.bazel | 7 ++++++- test/rustc_driver_symlink_example/BUILD.bazel | 10 ++++++++++ test/rustc_driver_symlink_example/bin.rs | 5 +++++ 3 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 test/rustc_driver_symlink_example/BUILD.bazel create mode 100644 test/rustc_driver_symlink_example/bin.rs diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel index 316052975e..0bd34857c3 100644 --- a/WORKSPACE.bazel +++ b/WORKSPACE.bazel @@ -4,7 +4,12 @@ load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_regi rules_rust_dependencies() -rust_register_toolchains(include_rustc_srcs = True) +rust_register_toolchains( + dev_components = True, + include_rustc_srcs = True, + iso_date = "2022-01-09", + version = "nightly", +) load("@rules_rust//proto:repositories.bzl", "rust_proto_repositories") diff --git a/test/rustc_driver_symlink_example/BUILD.bazel b/test/rustc_driver_symlink_example/BUILD.bazel new file mode 100644 index 0000000000..abd7316639 --- /dev/null +++ b/test/rustc_driver_symlink_example/BUILD.bazel @@ -0,0 +1,10 @@ +load("//rust:defs.bzl", "rust_binary") + +package(default_visibility = ["//visibility:public"]) + +rust_binary( + name = "bin", + srcs = [ + "bin.rs", + ], +) diff --git a/test/rustc_driver_symlink_example/bin.rs b/test/rustc_driver_symlink_example/bin.rs new file mode 100644 index 0000000000..14fa2f7b5b --- /dev/null +++ b/test/rustc_driver_symlink_example/bin.rs @@ -0,0 +1,5 @@ +#![feature(rustc_private)] + +extern crate rustc_driver; + +fn main() {} From 61426888d47fef50979fd784627018d9a43a0d78 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 7 Feb 2022 14:09:04 +0100 Subject: [PATCH 2/4] patch https://github.com/bazelbuild/rules_rust/pull/1119 --- docs/flatten.md | 7 +- docs/rust_repositories.md | 7 +- rust/private/rustc.bzl | 8 +- rust/private/rustdoc_test.bzl | 5 + rust/private/toolchain_utils.bzl | 166 +++++++++++++++++++++++++++++++ rust/toolchain.bzl | 47 +++++---- 6 files changed, 211 insertions(+), 29 deletions(-) diff --git a/docs/flatten.md b/docs/flatten.md index 10df0a0f48..787d0a87a5 100644 --- a/docs/flatten.md +++ b/docs/flatten.md @@ -1110,9 +1110,9 @@ Run the test with `bazel build //hello_lib:hello_lib_test`.
 rust_toolchain(name, allocator_library, binary_ext, cargo, clippy_driver, debug_info,
-               default_edition, dylib_ext, exec_triple, opt_level, os, rust_doc, rust_lib, rust_std,
-               rustc, rustc_lib, rustc_srcs, rustfmt, staticlib_ext, stdlib_linkflags, target_json,
-               target_triple)
+               default_edition, dylib_ext, exec_triple, llvm_tools, opt_level, os, rust_doc, rust_lib,
+               rust_std, rustc, rustc_lib, rustc_srcs, rustfmt, staticlib_ext, stdlib_linkflags,
+               target_json, target_triple)
 
Declares a Rust toolchain for use. @@ -1170,6 +1170,7 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r | default_edition | The edition to use for rust_* rules that don't specify an edition. | String | optional | "2018" | | dylib_ext | The extension for dynamic libraries created from rustc. | String | required | | | exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | | +| llvm_tools | llvm-tools | List of labels | optional | [] | | opt_level | Rustc optimization levels. | Dictionary: String -> String | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} | | os | The operating system for the current toolchain | String | required | | | rust_doc | The location of the rustdoc binary. Can be a direct source or a filegroup containing one item. | Label | required | | diff --git a/docs/rust_repositories.md b/docs/rust_repositories.md index d912ba7759..a98729d149 100644 --- a/docs/rust_repositories.md +++ b/docs/rust_repositories.md @@ -35,9 +35,9 @@ A dedicated filegroup-like rule for Rust stdlib artifacts.
 rust_toolchain(name, allocator_library, binary_ext, cargo, clippy_driver, debug_info,
-               default_edition, dylib_ext, exec_triple, opt_level, os, rust_doc, rust_lib, rust_std,
-               rustc, rustc_lib, rustc_srcs, rustfmt, staticlib_ext, stdlib_linkflags, target_json,
-               target_triple)
+               default_edition, dylib_ext, exec_triple, llvm_tools, opt_level, os, rust_doc, rust_lib,
+               rust_std, rustc, rustc_lib, rustc_srcs, rustfmt, staticlib_ext, stdlib_linkflags,
+               target_json, target_triple)
 
Declares a Rust toolchain for use. @@ -95,6 +95,7 @@ See @rules_rust//rust:repositories.bzl for examples of defining the @rust_cpuX r | default_edition | The edition to use for rust_* rules that don't specify an edition. | String | optional | "2018" | | dylib_ext | The extension for dynamic libraries created from rustc. | String | required | | | exec_triple | The platform triple for the toolchains execution environment. For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations | String | required | | +| llvm_tools | llvm-tools | List of labels | optional | [] | | opt_level | Rustc optimization levels. | Dictionary: String -> String | optional | {"dbg": "0", "fastbuild": "0", "opt": "3"} | | os | The operating system for the current toolchain | String | required | | | rust_doc | The location of the rustdoc binary. Can be a direct source or a filegroup containing one item. | Label | required | | diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index ffa3929ca0..6c63f0d47e 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -407,19 +407,16 @@ def collect_inputs( nolinkstamp_compile_inputs = depset( getattr(files, "data", []) + - [toolchain.rustc] + - toolchain.crosstool_files + ([build_info.rustc_env, build_info.flags] if build_info else []) + ([toolchain.target_json] if toolchain.target_json else []) + ([] if linker_script == None else [linker_script]), transitive = [ - toolchain.rustc_lib, - toolchain.rust_std, linker_depset, crate_info.srcs, dep_info.transitive_crate_outputs, depset(additional_transitive_inputs), crate_info.compile_data, + toolchain.all_files, ], ) @@ -681,8 +678,9 @@ def construct_arguments( data_paths, )) - # Set the SYSROOT to the directory of the rust_std files passed to the toolchain + # Ensure the sysroot is set for the target platform env["SYSROOT"] = toolchain.sysroot + rustc_flags.add("--sysroot", "${pwd}/" + toolchain.sysroot) # 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): diff --git a/rust/private/rustdoc_test.bzl b/rust/private/rustdoc_test.bzl index a73a0c7d50..163c72e086 100644 --- a/rust/private/rustdoc_test.bzl +++ b/rust/private/rustdoc_test.bzl @@ -56,6 +56,11 @@ def _construct_writer_arguments(ctx, test_runner, action, crate_info, rust_toolc for var in action.env.keys(): writer_args.add("--action_env={}".format(var)) + # Ensure the rustdoc binary is always accessed via a relative path + writer_args.add("--strip_substring={}/".format( + rust_toolchain.rust_doc.root.path, + )) + # Since the test runner will be running from a runfiles directory, the # paths originally generated for the build action will not map to any # files. To ensure rustdoc can find the appropriate dependencies, the diff --git a/rust/private/toolchain_utils.bzl b/rust/private/toolchain_utils.bzl index fcd4fb7029..2aabb80e8c 100644 --- a/rust/private/toolchain_utils.bzl +++ b/rust/private/toolchain_utils.bzl @@ -1,5 +1,171 @@ """A module defining toolchain utilities""" +def _symlink_sysroot_tree(ctx, name, target): + """Generate a set of symlinks to files from another target + + Args: + ctx (ctx): The toolchain's context object + name (str): The name of the sysroot directory (typically `ctx.label.name`) + target (Target): A target owning files to symlink + + Returns: + depset[File]: A depset of the generated symlink files + """ + tree_files = [] + for file in target.files.to_list(): + # Parse the path to the file relative to the workspace root so a + # symlink matching this path can be created within the sysroot. + + # The code blow attempts to parse any workspace names out of the + # path. For local targets, this code is a noop. + if target.label.workspace_root: + file_path = file.path.split(target.label.workspace_root, 1)[-1] + else: + file_path = file.path + + symlink = ctx.actions.declare_file("{}/{}".format(name, file_path.lstrip("/"))) + + ctx.actions.symlink( + output = symlink, + target_file = file, + ) + + tree_files.append(symlink) + + return depset(tree_files) + +def _symlink_sysroot_bin(ctx, name, dir, target): + """Crete a symlink to a target file. + + Args: + ctx (ctx): The rule's context object + name (str): A common name for the output directory + dir (str): The directory under `name` to put the file in + target (File): A File object to symlink to + + Returns: + File: A newly generated symlink file + """ + symlink = ctx.actions.declare_file("{}/{}/{}".format( + name, + dir.lstrip("/"), + target.basename, + )) + + ctx.actions.symlink( + output = symlink, + target_file = target, + is_executable = True, + ) + + return symlink + +def generate_sysroot( + ctx, + rustc, + rustdoc, + rustc_lib, + cargo = None, + clippy = None, + llvm_tools = None, + rust_std = None, + rustfmt = None): + """Generate a rust sysroot from an exec and target toolchain + + Args: + ctx (ctx): A context object from a `rust_toolchain` rule. + rustc (File): The path to a `rustc` executable. + rustdoc (File): The path to a `rustdoc` executable. + rustc_lib (Target): A collection of Files containing dependencies of `rustc`. + cargo (File, optional): The path to a `cargo` executable. + clippy (File, optional): The path to a `clippy-driver` executable. + llvm_tools (Target, optional): A collection of llvm tools used by `rustc`. + rust_std (Target, optional): A collection of Files containing Rust standard library components. + rustfmt (File, optional): The path to a `rustfmt` executable. + + Returns: + struct: A struct of generated files representing the new sysroot + """ + name = ctx.label.name + + # Define runfiles + direct_files = [] + transitive_file_sets = [] + + # Rustc + sysroot_rustc = _symlink_sysroot_bin(ctx, name, "/bin", rustc) + direct_files.extend([sysroot_rustc, rustc]) + + # Rustc dependencies + sysroot_rustc_lib = _symlink_sysroot_tree(ctx, name, rustc_lib) if rustc_lib else None + if sysroot_rustc_lib: + transitive_file_sets.extend([sysroot_rustc_lib, rustc_lib.files]) + + # Rustdoc + sysroot_rustdoc = _symlink_sysroot_bin(ctx, name, "/bin", rustdoc) + direct_files.extend([sysroot_rustdoc, rustdoc]) + + # Clippy + sysroot_clippy = _symlink_sysroot_bin(ctx, name, "/bin", clippy) if clippy else None + if sysroot_clippy: + direct_files.extend([sysroot_clippy, clippy]) + + # Cargo + sysroot_cargo = _symlink_sysroot_bin(ctx, name, "/bin", cargo) if cargo else None + if sysroot_cargo: + direct_files.extend([sysroot_cargo, cargo]) + + # Rustfmt + sysroot_rustfmt = _symlink_sysroot_bin(ctx, name, "/bin", rustfmt) if rustfmt else None + if sysroot_rustfmt: + direct_files.extend([sysroot_rustfmt, rustfmt]) + + # Llvm tools + sysroot_llvm_tools = _symlink_sysroot_tree(ctx, name, llvm_tools) if llvm_tools else None + if sysroot_llvm_tools: + transitive_file_sets.extend([sysroot_llvm_tools, llvm_tools.files]) + + # Rust standard library + sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std) if rust_std else None + if sysroot_rust_std: + transitive_file_sets.extend([sysroot_rust_std, rust_std.files]) + + # Symlink rust-stdlib + sysroot_rust_std = _symlink_sysroot_tree(ctx, name, rust_std) if rust_std else None + if sysroot_rust_std: + transitive_file_sets.extend([sysroot_rust_std, rust_std.files]) + + # Declare a file in the root of the sysroot to make locating the sysroot easy + sysroot_anchor = ctx.actions.declare_file("{}/rust.sysroot".format(name)) + ctx.actions.write( + output = sysroot_anchor, + content = "\n".join([ + "cargo: {}".format(cargo), + "clippy: {}".format(clippy), + "llvm_tools: {}".format(llvm_tools), + "rust_std: {}".format(rust_std), + "rustc_lib: {}".format(rustc_lib), + "rustc: {}".format(rustc), + "rustdoc: {}".format(rustdoc), + "rustfmt: {}".format(rustfmt), + ]), + ) + + # Create a depset of all sysroot files (symlinks and their real paths) + all_files = depset(direct_files, transitive = transitive_file_sets) + + return struct( + all_files = all_files, + cargo = sysroot_cargo, + clippy = sysroot_clippy, + rust_std = sysroot_rust_std, + rustc = sysroot_rustc, + rustc_lib = sysroot_rustc_lib, + rustdoc = sysroot_rustdoc, + rustfmt = sysroot_rustfmt, + sysroot_anchor = sysroot_anchor, + ) + def _toolchain_files_impl(ctx): toolchain = ctx.toolchains[str(Label("//rust:toolchain"))] diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index d3cb8f43bc..c078c75d92 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -2,6 +2,7 @@ load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") load("//rust/private:common.bzl", "rust_common") +load("//rust/private:toolchain_utils.bzl", "generate_sysroot") load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain", "make_static_lib_symlink") load("//rust/settings:incompatible.bzl", "IncompatibleFlagInfo") @@ -246,6 +247,18 @@ def _rust_toolchain_impl(ctx): else: rust_std = ctx.attr.rust_std + sysroot = generate_sysroot( + ctx = ctx, + rustc = ctx.file.rustc, + rustdoc = ctx.file.rust_doc, + rustc_lib = ctx.attr.rustc_lib, + rust_std = rust_std, + rustfmt = ctx.file.rustfmt, + clippy = ctx.file.clippy_driver, + cargo = ctx.file.cargo, + llvm_tools = ctx.attr.llvm_tools, + ) + expanded_stdlib_linkflags = [] for flag in ctx.attr.stdlib_linkflags: expanded_stdlib_linkflags.append( @@ -268,29 +281,23 @@ def _rust_toolchain_impl(ctx): linking_context = linking_context, ) - # In cases where the toolchain uses the Rust standard library, calculate sysroot path - sysroot_path = None - if rust_std: - # Calculate the rustc sysroot path by using a file from the rust-std bundle - rust_std_files_list = rust_std.files.to_list() - if not rust_std_files_list: - fail("The `rust_std` cannot be represented by an empty list") - sysroot_path = rust_std_files_list[0].dirname + all_files = depset(ctx.files._crosstool, transitive = [sysroot.all_files]) toolchain = platform_common.ToolchainInfo( - rustc = ctx.file.rustc, - rust_doc = ctx.file.rust_doc, - rustfmt = ctx.file.rustfmt, - cargo = ctx.file.cargo, - clippy_driver = ctx.file.clippy_driver, + all_files = all_files, + rustc = sysroot.rustc, + rust_doc = sysroot.rustdoc, + rustfmt = sysroot.rustfmt, + cargo = sysroot.cargo, + clippy_driver = sysroot.clippy, target_json = ctx.file.target_json, target_flag_value = ctx.file.target_json.path if ctx.file.target_json else ctx.attr.target_triple, - rustc_lib = depset(ctx.files.rustc_lib), + rustc_lib = sysroot.rustc_lib, rustc_srcs = ctx.attr.rustc_srcs, - rust_std = rust_std.files, - rust_std_paths = depset([file.dirname for file in rust_std_files_list]), - rust_lib = rust_std.files, # `rust_lib` is deprecated and only exists for legacy support. - sysroot = sysroot_path, + rust_std = sysroot.rust_std, + rust_std_paths = depset([file.dirname for file in sysroot.rust_std.to_list()]), + rust_lib = sysroot.rust_std, # `rust_lib` is deprecated and only exists for legacy support. + sysroot = sysroot.sysroot_anchor.dirname, binary_ext = ctx.attr.binary_ext, staticlib_ext = ctx.attr.staticlib_ext, dylib_ext = ctx.attr.dylib_ext, @@ -358,6 +365,10 @@ rust_toolchain = rule( ), mandatory = True, ), + "llvm_tools": attr.label_list( + doc = "llvm-tools", + allow_files = True, + ), "opt_level": attr.string_dict( doc = "Rustc optimization levels.", default = { From ea51aa7ee64050875552655ab38134510c78e746 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 7 Feb 2022 14:34:11 +0100 Subject: [PATCH 3/4] move example --- .../BUILD.bazel | 8 ++++++++ .../bin.rs | 0 2 files changed, 8 insertions(+) rename {test/rustc_driver_symlink_example => rustc_driver_symlink_example}/BUILD.bazel (54%) rename {test/rustc_driver_symlink_example => rustc_driver_symlink_example}/bin.rs (100%) diff --git a/test/rustc_driver_symlink_example/BUILD.bazel b/rustc_driver_symlink_example/BUILD.bazel similarity index 54% rename from test/rustc_driver_symlink_example/BUILD.bazel rename to rustc_driver_symlink_example/BUILD.bazel index abd7316639..397e178f73 100644 --- a/test/rustc_driver_symlink_example/BUILD.bazel +++ b/rustc_driver_symlink_example/BUILD.bazel @@ -1,4 +1,5 @@ load("//rust:defs.bzl", "rust_binary") +load("@bazel_skylib//rules:build_test.bzl", "build_test") package(default_visibility = ["//visibility:public"]) @@ -8,3 +9,10 @@ rust_binary( "bin.rs", ], ) + +build_test( + name = "build_test", + targets = [ + ":bin", + ], +) diff --git a/test/rustc_driver_symlink_example/bin.rs b/rustc_driver_symlink_example/bin.rs similarity index 100% rename from test/rustc_driver_symlink_example/bin.rs rename to rustc_driver_symlink_example/bin.rs From 30a8b30fe40a73df02e98470ec700766bf0edeb8 Mon Sep 17 00:00:00 2001 From: Krasimir Georgiev Date: Mon, 7 Feb 2022 14:45:13 +0100 Subject: [PATCH 4/4] move to examples/ --- examples/WORKSPACE.bazel | 7 ++++++- .../rustc_driver_symlink_example}/BUILD.bazel | 2 +- .../rustc_driver_symlink_example}/bin.rs | 0 3 files changed, 7 insertions(+), 2 deletions(-) rename {rustc_driver_symlink_example => examples/rustc_driver_symlink_example}/BUILD.bazel (84%) rename {rustc_driver_symlink_example => examples/rustc_driver_symlink_example}/bin.rs (100%) diff --git a/examples/WORKSPACE.bazel b/examples/WORKSPACE.bazel index 47dec43a65..eff06832c1 100644 --- a/examples/WORKSPACE.bazel +++ b/examples/WORKSPACE.bazel @@ -12,7 +12,12 @@ load("@rules_rust//rust:repositories.bzl", "rules_rust_dependencies", "rust_regi rules_rust_dependencies() -rust_register_toolchains(include_rustc_srcs = True) +rust_register_toolchains( + dev_components = True, + include_rustc_srcs = True, + iso_date = "2022-01-09", + version = "nightly", +) load("@rules_rust//bindgen:repositories.bzl", "rust_bindgen_repositories") diff --git a/rustc_driver_symlink_example/BUILD.bazel b/examples/rustc_driver_symlink_example/BUILD.bazel similarity index 84% rename from rustc_driver_symlink_example/BUILD.bazel rename to examples/rustc_driver_symlink_example/BUILD.bazel index 397e178f73..44b1b56e60 100644 --- a/rustc_driver_symlink_example/BUILD.bazel +++ b/examples/rustc_driver_symlink_example/BUILD.bazel @@ -1,4 +1,4 @@ -load("//rust:defs.bzl", "rust_binary") +load("@rules_rust//rust:defs.bzl", "rust_binary") load("@bazel_skylib//rules:build_test.bzl", "build_test") package(default_visibility = ["//visibility:public"]) diff --git a/rustc_driver_symlink_example/bin.rs b/examples/rustc_driver_symlink_example/bin.rs similarity index 100% rename from rustc_driver_symlink_example/bin.rs rename to examples/rustc_driver_symlink_example/bin.rs