Skip to content

Commit

Permalink
Introduce rust_common struct (bazelbuild#575)
Browse files Browse the repository at this point in the history
This PR introduces a `rust_common` struct that will be used to access the Rust Sandwich API (the term first introduced in https://bazel.build/designs/2016/08/04/extensibility-for-native-rules.html and used ever since, for example https://blog.bazel.build/2017/03/07/java-sandwich.html :)

The motivation for this change:
* to provide a single place for other rule authors where they can see what APIs are available.
* to enable rule authors to make their custom rules interacting with Rust rules backwards and forwards compatible using the `hasattr` function. `hassattr` only works on struct fields, not on globals.

The plan is to eventually refactor uses of all private APIs to go trough `rust_common`.

Credit goes to brave owners of `rules_swift` who discovered how useful this approach is the hard way.
  • Loading branch information
hlopko authored Feb 3, 2021
1 parent acfce01 commit d468cfa
Show file tree
Hide file tree
Showing 9 changed files with 64 additions and 30 deletions.
4 changes: 2 additions & 2 deletions proto/proto.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ load(
_generate_proto = "rust_generate_proto",
_generated_file_stem = "generated_file_stem",
)
load("//rust:common.bzl", "CrateInfo")
load("//rust:rust.bzl", "rust_common")

# buildifier: disable=bzl-visibility
load("//rust/private:rustc.bzl", "rustc_compile_action")
Expand Down Expand Up @@ -217,7 +217,7 @@ def _rust_proto_compile(protos, descriptor_sets, imports, crate_name, ctx, is_gr
return rustc_compile_action(
ctx = ctx,
toolchain = find_toolchain(ctx),
crate_info = CrateInfo(
crate_info = rust_common.crate_info(
name = crate_name,
type = "rlib",
root = lib_rs,
Expand Down
6 changes: 3 additions & 3 deletions rust/private/clippy.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

# buildifier: disable=module-docstring
load("//rust:common.bzl", "CrateInfo")
load("//rust/private:common.bzl", "rust_common")
load(
"//rust/private:rust.bzl",
"crate_root_src",
Expand Down Expand Up @@ -43,12 +43,12 @@ def _rust_sources(target, rule):
return [src for src in srcs if src.extension in _rust_extensions]

def _clippy_aspect_impl(target, ctx):
if CrateInfo not in target:
if rust_common.crate_info not in target:
return []
rust_srcs = _rust_sources(target, ctx.rule)

toolchain = find_toolchain(ctx)
crate_info = target[CrateInfo]
crate_info = target[rust_common.crate_info]

if crate_info.is_test:
root = crate_info.root
Expand Down
30 changes: 30 additions & 0 deletions rust/private/common.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A resilient API layer wrapping compilation and other logic for Rust rules.
This module is meant to be used by custom rules that need to compile Rust code
and cannot simply rely on writing a macro that wraps `rust_library`. This module
provides the lower-level interface to Rust providers, actions, and functions.
Do not load this file directly; instead, load the top-level `rust.bzl` file,
which exports the `rust_common` struct.
In the Bazel lingo, `rust_common` gives the access to the Rust Sandwich API.
"""

load(":providers.bzl", "CrateInfo")

rust_common = struct(
crate_info = CrateInfo,
)
4 changes: 2 additions & 2 deletions rust/common.bzl → rust/private/providers.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2015 The Bazel Authors. All rights reserved.
# Copyright 2021 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module with Rust definitions required to write custom Rust rules."""
"""Module containing definitions of all Rust providers."""

CrateInfo = provider(
doc = "A provider containing general Crate information.",
Expand Down
14 changes: 7 additions & 7 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

# buildifier: disable=module-docstring
load("//rust:common.bzl", "CrateInfo")
load("//rust/private:common.bzl", "rust_common")
load("//rust/private:rustc.bzl", "rustc_compile_action")
load("//rust/private:utils.bzl", "determine_output_hash", "find_toolchain")

Expand Down Expand Up @@ -166,7 +166,7 @@ def _rust_library_impl(ctx):
return rustc_compile_action(
ctx = ctx,
toolchain = toolchain,
crate_info = CrateInfo(
crate_info = rust_common.crate_info(
name = crate_name,
type = ctx.attr.crate_type,
root = crate_root,
Expand Down Expand Up @@ -201,7 +201,7 @@ def _rust_binary_impl(ctx):
return rustc_compile_action(
ctx = ctx,
toolchain = toolchain,
crate_info = CrateInfo(
crate_info = rust_common.crate_info(
name = crate_name,
type = crate_type,
root = crate_root_src(ctx.attr, ctx.files.srcs, crate_type),
Expand Down Expand Up @@ -234,8 +234,8 @@ def _rust_test_common(ctx, toolchain, output):
if ctx.attr.crate:
# Target is building the crate in `test` config
# Build the test binary using the dependency's srcs.
crate = ctx.attr.crate[CrateInfo]
target = CrateInfo(
crate = ctx.attr.crate[rust_common.crate_info]
target = rust_common.crate_info(
name = crate_name,
type = crate.type,
root = crate.root,
Expand All @@ -250,7 +250,7 @@ def _rust_test_common(ctx, toolchain, output):
)
else:
# Target is a standalone crate. Build the test binary as its own crate.
target = CrateInfo(
target = rust_common.crate_info(
name = crate_name,
type = "lib",
root = crate_root_src(ctx.attr, ctx.files.srcs, "lib"),
Expand Down Expand Up @@ -430,7 +430,7 @@ _common_attrs = {
List of `rust_library` targets with kind `proc-macro` used to help build this library target.
"""),
cfg = "exec",
providers = [CrateInfo],
providers = [rust_common.crate_info],
),
"rustc_env": attr.string_dict(
doc = _tidy("""
Expand Down
18 changes: 9 additions & 9 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ load(
"CPP_LINK_EXECUTABLE_ACTION_NAME",
)
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//rust:common.bzl", "CrateInfo")
load("//rust/private:common.bzl", "rust_common")
load(
"//rust/private:utils.bzl",
"expand_locations",
Expand Down Expand Up @@ -128,16 +128,16 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain):
"""

for dep in deps:
if CrateInfo in dep:
if dep[CrateInfo].type == "proc-macro":
if rust_common.crate_info in dep:
if dep[rust_common.crate_info].type == "proc-macro":
fail(
"{} listed {} in its deps, but it is a proc-macro. It should instead be in the bazel property proc_macro_deps.".format(
label,
dep.label,
),
)
for dep in proc_macro_deps:
type = dep[CrateInfo].type
type = dep[rust_common.crate_info].type
if type != "proc-macro":
fail(
"{} listed {} in its proc_macro_deps, but it is not proc-macro, it is a {}. It should probably instead be listed in deps.".format(
Expand All @@ -156,15 +156,15 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain):

aliases = {k.label: v for k, v in aliases.items()}
for dep in deps + proc_macro_deps:
if CrateInfo in dep:
if rust_common.crate_info in dep:
# This dependency is a rust_library
direct_dep = dep[CrateInfo]
direct_dep = dep[rust_common.crate_info]
direct_crates.append(AliasableDepInfo(
name = aliases.get(dep.label, direct_dep.name),
dep = direct_dep,
))

transitive_crates.append(depset([dep[CrateInfo]], transitive = [dep[DepInfo].transitive_crates]))
transitive_crates.append(depset([dep[rust_common.crate_info]], transitive = [dep[DepInfo].transitive_crates]))
transitive_dylibs.append(dep[DepInfo].transitive_dylibs)
transitive_staticlibs.append(dep[DepInfo].transitive_staticlibs)
transitive_build_infos.append(dep[DepInfo].transitive_build_infos)
Expand Down Expand Up @@ -519,8 +519,8 @@ def construct_arguments(

# Make bin crate data deps available to tests.
for data in getattr(ctx.attr, "data", []):
if CrateInfo in data:
dep_crate_info = data[CrateInfo]
if rust_common.crate_info in data:
dep_crate_info = data[rust_common.crate_info]
if dep_crate_info.type == "bin":
env["CARGO_BIN_EXE_" + dep_crate_info.output.basename] = dep_crate_info.output.short_path

Expand Down
6 changes: 3 additions & 3 deletions rust/private/rustdoc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

# buildifier: disable=module-docstring
load("//rust:common.bzl", "CrateInfo")
load("//rust/private:common.bzl", "rust_common")
load("//rust/private:rustc.bzl", "DepInfo", "add_crate_link_flags", "add_edition_flags")
load("//rust/private:utils.bzl", "find_toolchain")

Expand Down Expand Up @@ -62,10 +62,10 @@ def _rust_doc_impl(ctx):
Args:
ctx (ctx): The rule's context object
"""
if CrateInfo not in ctx.attr.dep:
if rust_common.crate_info not in ctx.attr.dep:
fail("Expected rust_library or rust_binary.", "dep")

crate = ctx.attr.dep[CrateInfo]
crate = ctx.attr.dep[rust_common.crate_info]
dep_info = ctx.attr.dep[DepInfo]

toolchain = find_toolchain(ctx)
Expand Down
8 changes: 4 additions & 4 deletions rust/private/rustdoc_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
# limitations under the License.

# buildifier: disable=module-docstring
load("//rust:common.bzl", "CrateInfo")
load("//rust/private:common.bzl", "rust_common")
load("//rust/private:rustc.bzl", "DepInfo")
load("//rust/private:utils.bzl", "find_toolchain", "get_lib_name")

Expand All @@ -26,10 +26,10 @@ def _rust_doc_test_impl(ctx):
Returns:
list: A list containing a DefaultInfo provider
"""
if CrateInfo not in ctx.attr.dep:
if rust_common.crate_info not in ctx.attr.dep:
fail("Expected rust library or binary.", "dep")

crate = ctx.attr.dep[CrateInfo]
crate = ctx.attr.dep[rust_common.crate_info]

toolchain = find_toolchain(ctx)

Expand Down Expand Up @@ -193,7 +193,7 @@ rust_doc_test = rule(
"`rust_library` or `rust_binary` targets."
),
mandatory = True,
providers = [CrateInfo],
providers = [rust_common.crate_info],
),
},
executable = True,
Expand Down
4 changes: 4 additions & 0 deletions rust/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ load(
_rust_clippy = "rust_clippy",
_rust_clippy_aspect = "rust_clippy_aspect",
)
load("//rust/private:common.bzl", _rust_common = "rust_common")
load(
"//rust/private:rust.bzl",
_rust_benchmark = "rust_benchmark",
Expand Down Expand Up @@ -61,3 +62,6 @@ rust_clippy_aspect = _rust_clippy_aspect

rust_clippy = _rust_clippy
# See @rules_rust//rust/private:clippy.bzl for a complete description.

rust_common = _rust_common
# See @rules_rust//rust/private:common.bzl for a complete description.

0 comments on commit d468cfa

Please sign in to comment.