diff --git a/extensions/prost/private/prost.bzl b/extensions/prost/private/prost.bzl index 4eecf85a06..59408bca8f 100644 --- a/extensions/prost/private/prost.bzl +++ b/extensions/prost/private/prost.bzl @@ -196,7 +196,7 @@ def _compile_rust( extension = ".rmeta", ) rmeta = ctx.actions.declare_file(rmeta_name) - rustc_rmeta_output = generate_output_diagnostics(ctx, rmeta) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rmeta) metadata_supports_pipelining = can_use_metadata_for_pipelining(toolchain, "rlib") providers = rustc_compile_action( diff --git a/extensions/protobuf/proto.bzl b/extensions/protobuf/proto.bzl index 8c67a39ecb..3956487b07 100644 --- a/extensions/protobuf/proto.bzl +++ b/extensions/protobuf/proto.bzl @@ -211,7 +211,7 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr crate_name, output_hash, )) - rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rust_metadata) metadata_supports_pipelining = can_use_metadata_for_pipelining(toolchain, "rlib") # Gather all dependencies for compilation diff --git a/extensions/wasm_bindgen/private/wasm_bindgen_test.bzl b/extensions/wasm_bindgen/private/wasm_bindgen_test.bzl index 8a2dcb5738..2abf61f624 100644 --- a/extensions/wasm_bindgen/private/wasm_bindgen_test.bzl +++ b/extensions/wasm_bindgen/private/wasm_bindgen_test.bzl @@ -123,7 +123,7 @@ def _rust_wasm_bindgen_test_impl(ctx): proc_macro_deps = depset(proc_macro_deps, transitive = [crate.proc_macro_deps]).to_list(), aliases = {}, output = output, - rustc_output = generate_output_diagnostics(ctx, output), + rustc_output = generate_output_diagnostics(ctx, toolchain, output), edition = crate.edition, rustc_env = rustc_env, rustc_env_files = rustc_env_files, diff --git a/rust/private/BUILD.bazel b/rust/private/BUILD.bazel index d18e895493..09b8a6535c 100644 --- a/rust/private/BUILD.bazel +++ b/rust/private/BUILD.bazel @@ -1,4 +1,5 @@ load("@bazel_skylib//:bzl_library.bzl", "bzl_library") +load("@bazel_skylib//rules:common_settings.bzl", "bool_setting") load("//rust/private:rust_analyzer.bzl", "rust_analyzer_detect_sysroot") load("//rust/private:rustc.bzl", "is_proc_macro_dep", "is_proc_macro_dep_enabled") load("//rust/private:stamp.bzl", "stamp_build_setting") @@ -57,3 +58,26 @@ rust_analyzer_detect_sysroot( name = "rust_analyzer_detect_sysroot", visibility = ["//visibility:public"], ) + +# This setting lets us configure a bootstrap toolchain to build the process_wrapper +# and a "full" toolchain (that uses process_wrapper) to build user code. +bool_setting( + name = "bootstrap_setting", + build_setting_default = False, +) + +config_setting( + name = "bootstrapped", + flag_values = { + ":bootstrap_setting": "0", + }, + visibility = ["//visibility:public"], +) + +config_setting( + name = "bootstrapping", + flag_values = { + ":bootstrap_setting": "1", + }, + visibility = ["//visibility:public"], +) diff --git a/rust/private/repository_utils.bzl b/rust/private/repository_utils.bzl index 05b741947d..0d3c385f08 100644 --- a/rust/private/repository_utils.bzl +++ b/rust/private/repository_utils.bzl @@ -348,6 +348,39 @@ rust_toolchain( strip_level = {strip_level}, tags = ["rust_version={version}"], ) + +rust_toolchain( + name = "{toolchain_name}_bootstrap", + bootstrapping = True, + rust_doc = "//:rustdoc", + rust_std = "//:rust_std-{target_triple}", + rustc = "//:rustc", + linker = {linker_label}, + linker_type = {linker_type}, + rustfmt = {rustfmt_label}, + cargo = "//:cargo", + clippy_driver = "//:clippy_driver_bin", + cargo_clippy = "//:cargo_clippy_bin", + llvm_cov = {llvm_cov_label}, + llvm_profdata = {llvm_profdata_label}, + llvm_lib = {llvm_lib_label}, + 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}], + 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}, + opt_level = {opt_level}, + strip_level = {strip_level}, + tags = ["rust_version={version}"], +) """ def BUILD_for_rust_toolchain( @@ -449,7 +482,20 @@ toolchain( target_compatible_with = {target_constraint_sets_serialized}, toolchain = "{toolchain}", toolchain_type = "{toolchain_type}", - {target_settings} + target_settings = [ + "@rules_rust//rust/private:bootstrapped",{target_settings} + ], +) + +toolchain( + name = "{name}_bootstrap", + exec_compatible_with = {exec_constraint_sets_serialized}, + target_compatible_with = {target_constraint_sets_serialized}, + toolchain = "{toolchain}_bootstrap", + toolchain_type = "{toolchain_type}", + target_settings = [ + "@rules_rust//rust/private:bootstrapping",{target_settings} + ], ) """ @@ -460,7 +506,7 @@ def BUILD_for_toolchain( target_settings, target_compatible_with, exec_compatible_with): - target_settings_value = "target_settings = {},".format(json.encode(target_settings)) if target_settings else "# target_settings = []" + target_settings_value = ",\n ".join([repr(setting) for setting in target_settings]) return _build_file_for_toolchain_template.format( name = name, diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index 6ba4c361e1..a94b91efdf 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -209,7 +209,7 @@ def _rust_library_common(ctx, crate_type): paths.replace_extension(rust_lib_name, ".rmeta"), sibling = rust_lib, ) - rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rust_metadata) metadata_supports_pipelining = ( can_use_metadata_for_pipelining(toolchain, crate_type) and not ctx.attr.disable_pipelining @@ -232,7 +232,7 @@ def _rust_library_common(ctx, crate_type): proc_macro_deps = proc_macro_deps, aliases = ctx.attr.aliases, output = rust_lib, - rustc_output = generate_output_diagnostics(ctx, rust_lib), + rustc_output = generate_output_diagnostics(ctx, toolchain, rust_lib), metadata = rust_metadata, metadata_supports_pipelining = metadata_supports_pipelining, rustc_rmeta_output = rustc_rmeta_output, @@ -282,7 +282,7 @@ def _rust_binary_impl(ctx): paths.replace_extension("lib" + crate_name, ".rmeta"), sibling = output, ) - rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rust_metadata) providers = rustc_compile_action( ctx = ctx, @@ -297,7 +297,7 @@ def _rust_binary_impl(ctx): proc_macro_deps = proc_macro_deps, aliases = ctx.attr.aliases, output = output, - rustc_output = generate_output_diagnostics(ctx, output), + rustc_output = generate_output_diagnostics(ctx, toolchain, output), metadata = rust_metadata, rustc_rmeta_output = rustc_rmeta_output, edition = get_edition(ctx.attr, toolchain, ctx.label), @@ -394,7 +394,7 @@ def _rust_test_impl(ctx): paths.replace_extension("lib" + crate_name, ".rmeta"), sibling = output, ) - rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rust_metadata) # Need to consider all src files together when transforming srcs = depset(ctx.files.srcs, transitive = [crate.srcs]).to_list() @@ -429,7 +429,7 @@ def _rust_test_impl(ctx): proc_macro_deps = depset(proc_macro_deps, transitive = [crate.proc_macro_deps]).to_list(), aliases = aliases, output = output, - rustc_output = generate_output_diagnostics(ctx, output), + rustc_output = generate_output_diagnostics(ctx, toolchain, output), metadata = rust_metadata, rustc_rmeta_output = rustc_rmeta_output, edition = crate.edition, @@ -473,7 +473,7 @@ def _rust_test_impl(ctx): paths.replace_extension("lib" + crate_name, ".rmeta"), sibling = output, ) - rustc_rmeta_output = generate_output_diagnostics(ctx, rust_metadata) + rustc_rmeta_output = generate_output_diagnostics(ctx, toolchain, rust_metadata) if ctx.attr.rustc_env: rustc_env = expand_dict_value_locations( @@ -495,7 +495,7 @@ def _rust_test_impl(ctx): proc_macro_deps = proc_macro_deps, aliases = ctx.attr.aliases, output = output, - rustc_output = generate_output_diagnostics(ctx, output), + rustc_output = generate_output_diagnostics(ctx, toolchain, output), metadata = rust_metadata, rustc_rmeta_output = rustc_rmeta_output, edition = get_edition(ctx.attr, toolchain, ctx.label), @@ -645,13 +645,6 @@ RUSTC_ATTRS = { "_per_crate_rustc_flag": attr.label( default = Label("//rust/settings:experimental_per_crate_rustc_flag"), ), - "_process_wrapper": attr.label( - doc = "A process wrapper for running rustc on all platforms.", - default = Label("//util/process_wrapper"), - executable = True, - allow_single_file = True, - cfg = "exec", - ), "_rustc_output_diagnostics": attr.label( default = Label("//rust/settings:rustc_output_diagnostics"), ), @@ -1318,21 +1311,6 @@ rust_binary = rule( def _common_attrs_for_binary_without_process_wrapper(attrs): new_attr = dict(attrs) - # use a fake process wrapper - new_attr["_process_wrapper"] = attr.label( - default = None, - executable = True, - allow_single_file = True, - cfg = "exec", - ) - - new_attr["_bootstrap_process_wrapper"] = attr.label( - default = Label("//util/process_wrapper:bootstrap_process_wrapper"), - executable = True, - allow_single_file = True, - cfg = "exec", - ) - # fix stamp = 0 new_attr["stamp"] = attr.int( doc = dedent("""\ @@ -1350,20 +1328,31 @@ _RustBuiltWithoutProcessWrapperInfo = provider( fields = {}, ) +def _bootstrap_process_wrapper_transition_impl(_settings, _attr): + return {str(Label("//rust/private:bootstrap_setting")): True} + +_bootstrap_process_wrapper_transition = transition( + implementation = _bootstrap_process_wrapper_transition_impl, + inputs = [], + outputs = [str(Label("//rust/private:bootstrap_setting"))], +) + def _rust_binary_without_process_wrapper_impl(ctx): providers = _rust_binary_impl(ctx) return providers + [_RustBuiltWithoutProcessWrapperInfo()] -# Provides an internal rust_{binary,library} to use that we can use to build the process -# wrapper, this breaks the dependency of rust_* on the process wrapper by -# setting it to None, which the functions in rustc detect and build accordingly. rust_binary_without_process_wrapper = rule( implementation = _rust_binary_without_process_wrapper_impl, doc = "A variant of `rust_binary` that uses a minimal process wrapper for `Rustc` actions.", provides = COMMON_PROVIDERS + [_RustBuiltWithoutProcessWrapperInfo], - attrs = _common_attrs_for_binary_without_process_wrapper(_common_attrs | _rust_binary_attrs), + attrs = _common_attrs_for_binary_without_process_wrapper(_common_attrs | _rust_binary_attrs) | { + "_allowlist_function_transition": attr.label( + default = Label("//tools/allowlists/function_transition_allowlist"), + ), + }, executable = True, fragments = ["cpp"], + cfg = _bootstrap_process_wrapper_transition, toolchains = [ str(Label("//rust:toolchain_type")), config_common.toolchain_type("@bazel_tools//tools/cpp:toolchain_type", mandatory = False), diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index a28ad50b78..ebc53b96f8 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -1502,10 +1502,12 @@ def rustc_compile_action( dsym_folder = ctx.actions.declare_directory(crate_info.output.basename + ".dSYM", sibling = crate_info.output) action_outputs.append(dsym_folder) - if ctx.executable._process_wrapper: + process_wrapper = toolchain.process_wrapper + + if process_wrapper: # Run as normal ctx.actions.run( - executable = ctx.executable._process_wrapper, + executable = process_wrapper, inputs = compile_inputs, outputs = action_outputs, env = env, @@ -1523,7 +1525,7 @@ def rustc_compile_action( ) if args_metadata: ctx.actions.run( - executable = ctx.executable._process_wrapper, + executable = process_wrapper, inputs = compile_inputs, outputs = [build_metadata] + [x for x in [rustc_rmeta_output] if x], env = env, @@ -1538,12 +1540,12 @@ def rustc_compile_action( ), toolchain = "@rules_rust//rust:toolchain_type", ) - elif hasattr(ctx.executable, "_bootstrap_process_wrapper"): + else: # Run without process_wrapper if build_env_files or build_flags_files or stamp or build_metadata: fail("build_env_files, build_flags_files, stamp, build_metadata are not supported when building without process_wrapper") ctx.actions.run( - executable = ctx.executable._bootstrap_process_wrapper, + executable = toolchain.bootstrap_process_wrapper, inputs = compile_inputs, outputs = action_outputs, env = env, @@ -1559,8 +1561,6 @@ def rustc_compile_action( toolchain = "@rules_rust//rust:toolchain_type", resource_set = get_rustc_resource_set(toolchain), ) - else: - fail("No process wrapper was defined for {}".format(ctx.label)) if experimental_use_cc_common_link: # Wrap the main `.o` file into a compilation output suitable for diff --git a/rust/private/unpretty.bzl b/rust/private/unpretty.bzl index be111c83a3..7edb363f6d 100644 --- a/rust/private/unpretty.bzl +++ b/rust/private/unpretty.bzl @@ -213,7 +213,7 @@ def _rust_unpretty_aspect_impl(target, ctx): args.rustc_flags.add("-Zunpretty={}".format(mode)) ctx.actions.run( - executable = ctx.executable._process_wrapper, + executable = toolchain.process_wrapper, inputs = compile_inputs, outputs = [unpretty_out], env = env, diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index 8a82126d53..f835cf224f 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -736,7 +736,7 @@ def can_build_metadata(toolchain, ctx, crate_type, *, disable_pipelining = False # 2) either: # * always_enable_metadata_output_groups is set # * this target can use metadata for pipelined compilation - return bool(ctx.attr._process_wrapper) and ( + return bool(toolchain.process_wrapper) and ( ctx.attr._always_enable_metadata_output_groups[AlwaysEnableMetadataOutputGroupsInfo].always_enable_metadata_output_groups or (not disable_pipelining and can_use_metadata_for_pipelining(toolchain, crate_type)) @@ -943,11 +943,12 @@ def _symlink_for_non_generated_source(ctx, src_file, package_root): else: return src_file -def generate_output_diagnostics(ctx, sibling, require_process_wrapper = True): +def generate_output_diagnostics(ctx, toolchain, sibling, require_process_wrapper = True): """Generates a .rustc-output file if it's required. Args: ctx: (ctx): The current rule's context object + toolchain: (Rust toolchain): The current rust toolchain sibling: (File): The file to generate the diagnostics for. require_process_wrapper: (bool): Whether to require the process wrapper in order to generate the .rustc-output file. @@ -958,7 +959,7 @@ def generate_output_diagnostics(ctx, sibling, require_process_wrapper = True): # Since this feature requires error_format=json, we usually need # process_wrapper, since it can write the json here, then convert it to the # regular error format so the user can see the error properly. - if require_process_wrapper and not ctx.attr._process_wrapper: + if require_process_wrapper and not toolchain.process_wrapper: return None provider = ctx.attr._rustc_output_diagnostics[RustcOutputDiagnosticsInfo] if not provider.rustc_output_diagnostics: diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index 91e3032166..90e962a50d 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -367,6 +367,12 @@ def _expand_flags(ctx, attr_name, targets, make_variables): expanded_flags.append(flag) return expanded_flags +def _process_wrapper_default(bootstrapping): + return None if bootstrapping else Label("@rules_rust//util/process_wrapper") + +def _bootstrap_process_wrapper_default(bootstrapping): + return Label("@rules_rust//util/process_wrapper:bootstrap_process_wrapper") if bootstrapping else None + def _rust_toolchain_impl(ctx): """The rust_toolchain implementation @@ -598,6 +604,8 @@ def _rust_toolchain_impl(ctx): extra_rustc_flags = expanded_extra_rustc_flags, extra_rustc_flags_for_crate_types = ctx.attr.extra_rustc_flags_for_crate_types, extra_exec_rustc_flags = expanded_extra_exec_rustc_flags, + process_wrapper = ctx.executable._process_wrapper if ctx.attr._process_wrapper else None, + bootstrap_process_wrapper = ctx.executable._bootstrap_process_wrapper if ctx.attr._bootstrap_process_wrapper else None, per_crate_rustc_flags = ctx.attr.per_crate_rustc_flags, sysroot = sysroot_path, sysroot_short_path = sysroot_short_path, @@ -642,6 +650,9 @@ rust_toolchain = rule( doc = "The extension for binaries created from rustc.", mandatory = True, ), + "bootstrapping": attr.bool( + doc = "Internal attribute, set when bootstrapping process_wrapper. Do not use.", + ), "cargo": attr.label( doc = "The location of the `cargo` binary. Can be a direct source or a filegroup containing one item.", allow_single_file = True, @@ -833,6 +844,13 @@ rust_toolchain = rule( "For more details see: https://docs.bazel.build/versions/master/skylark/rules.html#configurations" ), ), + "_bootstrap_process_wrapper": attr.label( + doc = "A bootstrap process wrapper for building the process wrapper", + default = _bootstrap_process_wrapper_default, + executable = True, + allow_single_file = True, + cfg = "exec", + ), "_codegen_units": attr.label( default = Label("//rust/settings:codegen_units"), ), @@ -870,6 +888,13 @@ rust_toolchain = rule( "_pipelined_compilation": attr.label( default = Label("//rust/settings:pipelined_compilation"), ), + "_process_wrapper": attr.label( + doc = "A process wrapper for running rustc on all platforms.", + default = _process_wrapper_default, + executable = True, + allow_single_file = True, + cfg = "exec", + ), "_rename_first_party_crates": attr.label( default = Label("//rust/settings:rename_first_party_crates"), ), diff --git a/test/toolchain/toolchain_test.bzl b/test/toolchain/toolchain_test.bzl index 3140064b32..31e468f0ee 100644 --- a/test/toolchain/toolchain_test.bzl +++ b/test/toolchain/toolchain_test.bzl @@ -201,6 +201,7 @@ def _define_targets(): name = "extra_flags_toolchain", toolchain = ":rust_extra_flags_toolchain", toolchain_type = "@rules_rust//rust:toolchain", + target_settings = ["@rules_rust//rust/private:bootstrapped"], ) extra_toolchain_wrapper( diff --git a/util/process_wrapper/BUILD.bazel b/util/process_wrapper/BUILD.bazel index af56264e4c..1f160480c0 100644 --- a/util/process_wrapper/BUILD.bazel +++ b/util/process_wrapper/BUILD.bazel @@ -43,6 +43,10 @@ rust_binary_without_process_wrapper( ":opt_macos": ["-Cstrip=debuginfo"], "//conditions:default": [], }), + target_compatible_with = select({ + "@rules_rust//rust/private:bootstrapping": [], + "//conditions:default": ["@platforms//:incompatible"], + }), visibility = ["//visibility:public"], deps = [ "@rules_rust_tinyjson//:tinyjson",