Skip to content

Add a conditional implicit dependency on the import macro. #1151

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ load(
"determine_output_hash",
"expand_dict_value_locations",
"find_toolchain",
"get_import_macro_deps",
"transform_deps",
)

Expand Down Expand Up @@ -263,7 +264,7 @@ def _rust_library_common(ctx, crate_type):
rust_lib = ctx.actions.declare_file(rust_lib_name)

deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))

return rustc_compile_action(
ctx = ctx,
Expand Down Expand Up @@ -303,7 +304,7 @@ def _rust_binary_impl(ctx):
output = ctx.actions.declare_file(ctx.label.name + toolchain.binary_ext)

deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))

return rustc_compile_action(
ctx = ctx,
Expand Down Expand Up @@ -344,7 +345,7 @@ def _rust_test_common(ctx, toolchain, output):
crate_type = "bin"

deps = transform_deps(ctx.attr.deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps)
proc_macro_deps = transform_deps(ctx.attr.proc_macro_deps + get_import_macro_deps(ctx))

if ctx.attr.crate:
# Target is building the crate in `test` config
Expand Down Expand Up @@ -591,6 +592,9 @@ _common_attrs = {
"_error_format": attr.label(default = "//:error_format"),
"_extra_exec_rustc_flags": attr.label(default = "//:extra_exec_rustc_flags"),
"_extra_rustc_flags": attr.label(default = "//:extra_rustc_flags"),
"_import_macro_dep": attr.label(
default = "@rules_rust//util/import",
),
"_process_wrapper": attr.label(
default = Label("//util/process_wrapper"),
executable = True,
Expand Down
46 changes: 46 additions & 0 deletions rust/private/transitions.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# buildifier: disable=module-docstring
load("//rust:defs.bzl", "rust_common")

def _wasm_bindgen_transition(_settings, _attr):
"""The implementation of the `wasm_bindgen_transition` transition

Expand All @@ -18,3 +20,47 @@ wasm_bindgen_transition = transition(
inputs = [],
outputs = ["//command_line_option:platforms"],
)

def _import_macro_dep_bootstrap_transition(_settings, _attr):
"""The implementation of the `import_macro_dep_bootstrap_transition` transition.

This transition modifies the config to start using the fake macro
implementation, so that the macro itself can be bootstrapped without
creating a dependency cycle, even while every Rust target has an implicit
dependency on the "import" macro (either real or fake).

Args:
_settings (dict): a dict {String:Object} of all settings declared in the
inputs parameter to `transition()`.
_attr (dict): A dict of attributes and values of the rule to which the
transition is attached.

Returns:
dict: A dict of new build settings values to apply.
"""
return {"@rules_rust//rust/settings:use_real_import_macro": False}

import_macro_dep_bootstrap_transition = transition(
implementation = _import_macro_dep_bootstrap_transition,
inputs = [],
outputs = ["@rules_rust//rust/settings:use_real_import_macro"],
)

def _with_import_macro_bootstrapping_mode_impl(ctx):
target = ctx.attr.target[0]
return [target[rust_common.crate_info], target[rust_common.dep_info]]

with_import_macro_bootstrapping_mode = rule(
implementation = _with_import_macro_bootstrapping_mode_impl,
attrs = {
"target": attr.label(
cfg = import_macro_dep_bootstrap_transition,
allow_single_file = True,
mandatory = True,
executable = False,
),
"_allowlist_function_transition": attr.label(
default = Label("//tools/allowlists/function_transition_allowlist"),
),
},
)
15 changes: 15 additions & 0 deletions rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,21 @@ def transform_deps(deps):
cc_info = dep[CcInfo] if CcInfo in dep else None,
) for dep in deps]

def get_import_macro_deps(ctx):
"""Returns a list of targets to be added to proc_macro_deps.

Args:
ctx (struct): the ctx of the current target.

Returns:
list of Targets. Either empty (if the fake import macro implementation
is being used), or a singleton list with the real implementation.
"""
if ctx.attr._import_macro_dep.label.name == "fake_import_macro_impl":
return []

return [ctx.attr._import_macro_dep]

def should_encode_label_in_crate_name(workspace_name, label, third_party_dir):
"""Determines if the crate's name should include the Bazel label, encoded.

Expand Down
7 changes: 7 additions & 0 deletions rust/settings/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ string_flag(
build_setting_default = "//third_party/rust",
)

# A flag to control whether rust_library and rust_binary targets should
# implicitly depend on the *real* import macro, or on a no-op target.
bool_flag(
name = "use_real_import_macro",
build_setting_default = False,
)

bzl_library(
name = "bzl_lib",
srcs = glob(["**/*.bzl"]),
Expand Down
33 changes: 31 additions & 2 deletions util/import/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
load("//rust:defs.bzl", "rust_library", "rust_proc_macro", "rust_test")

# buildifier: disable=bzl-visibility
load("//rust/private:transitions.bzl", "with_import_macro_bootstrapping_mode")

with_import_macro_bootstrapping_mode(
name = "import_macro",
target = "import_macro_impl",
)

rust_proc_macro(
name = "import",
name = "import_macro_impl",
srcs = [
"import.rs",
],
visibility = ["//visibility:public"],
crate_name = "import",
deps = [
":import_internal",
"//util/import/raze:syn",
Expand Down Expand Up @@ -34,3 +42,24 @@ rust_test(
"//util/import/raze:quickcheck",
],
)

alias(
name = "import",
actual = select({
":use_fake_import_macro": ":fake_import_macro_impl",
"//conditions:default": ":import_macro",
}),
visibility = ["//visibility:public"],
)

config_setting(
name = "use_fake_import_macro",
flag_values = {
"@rules_rust//rust/settings:use_real_import_macro": "False",
},
)

sh_binary(
name = "fake_import_macro_impl",
srcs = ["fake_import_macro_impl.sh"],
)
3 changes: 3 additions & 0 deletions util/import/fake_import_macro_impl.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

# Does nothing.