Skip to content

Commit

Permalink
Split rust_library and add //rust:defs.bzl
Browse files Browse the repository at this point in the history
This PR splits rust_library into multiple smaller rules:

* rust_library: rust_library will represent a non-transitive library
  similar to how cc_library, java_library and others behave. It will
  always provide CrateInfo, and depending on it will always mean you can
  access the crate from source. Once we support dynamic linking we can
  consider producing both rlib and dylib from rust_library, but let's
  leave that for another discussion.
* rust_static_library: this will only provide CcInfo and it will
  represent an archive of all transitive objects, both Rustc-made and
  native.
* rust_shared_library: this will only provide CcInfo and it will
  represent an shared library of all transitive objects, both Rustc-made
  and native.
* rust_proc_macro: similar to rust_library, but with different
  crate_type passed to rustc and different validation logic for its
  attributes.

I this this makes sense based on these observations:
* Right now rust_library covers all possible crate types except `bin`.
* rust_library always provides CrateInfo, rust_libraries can depend on
  other rust_libraries.
* When the crate type is `cdylib` or `staticlib`, rust_library provides
  CcInfo.
* When the crate type is `cdylib` or `staticlib`, Rust code will not be
  able to access the crate by `extern crate Foo` in the source; the
  behavior will be similar to depending on a CcInfo providing rule.

I believe smaller rules will make them less confusing and
will allow us to have more focused implementations.

This PR is mostly backwards compatible. //rust:rust.bzl#rust_library is
a macro. If the crate_type attribute is present, macro dispatches to
the right new rule. If it's not present, macro will choose the new
rust_library. New rules are added, so people can migrate at
their own pace.

defs.bzl is the bzl file that we now expect people to load. Bazel docs
recommend to store public rules in defs.bzl
(https://docs.bazel.build/versions/master/skylark/deploying.html#repository-content).

This change was first socialized at
https://groups.google.com/g/rules_rust/c/kGMg6haEF44.
  • Loading branch information
hlopko committed Feb 17, 2021
1 parent 38cba05 commit c7529ca
Show file tree
Hide file tree
Showing 4 changed files with 240 additions and 86 deletions.
87 changes: 87 additions & 0 deletions rust/defs.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# 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.

"""Public entry point to all Rust rules and supported APIs."""

load(
"//rust/private:clippy.bzl",
_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",
_rust_binary = "rust_binary",
_rust_library = "rust_library",
_rust_static_library = "rust_static_library",
_rust_shared_library = "rust_shared_library",
_rust_proc_macro = "rust_proc_macro",
_rust_test = "rust_test",
_rust_test_binary = "rust_test_binary",
)
load(
"//rust/private:rustc.bzl",
_error_format = "error_format",
)
load(
"//rust/private:rustdoc.bzl",
_rust_doc = "rust_doc",
)
load(
"//rust/private:rustdoc_test.bzl",
_rust_doc_test = "rust_doc_test",
)

rust_library = _rust_library
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_static_library = _rust_static_library
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_shared_library = _rust_shared_library
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_proc_macro = _rust_proc_macro
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_binary = _rust_binary
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_test = _rust_test
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_test_binary = _rust_test_binary
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_benchmark = _rust_benchmark
# See @rules_rust//rust/private:rust.bzl for a complete description.

rust_doc = _rust_doc
# See @rules_rust//rust/private:rustdoc.bzl for a complete description.

rust_doc_test = _rust_doc_test
# See @rules_rust//rust/private:rustdoc_test.bzl for a complete description.

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

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

error_format = _error_format
# See @rules_rust//rust/private:rustc.bzl for a complete description.

rust_common = _rust_common
# See @rules_rust//rust/private:common.bzl for a complete description.
143 changes: 115 additions & 28 deletions rust/private/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def _determine_lib_name(name, crate_type, toolchain, lib_hash = ""):
Args:
name (str): The name of the current target
crate_type (str): The `crate_type` attribute from a `rust_library`
crate_type (str): The `crate_type`
toolchain (rust_toolchain): The current `rust_toolchain`
lib_hash (str, optional): The hashed crate root path. Defaults to "".
Expand Down Expand Up @@ -136,11 +136,56 @@ def _shortest_src_with_basename(srcs, basename):
return shortest

def _rust_library_impl(ctx):
"""The implementation of the `rust_library` rule
"""The implementation of the `rust_library` rule.
Args:
ctx (ctx): The rule's context object
Returns:
list: A list of providers.
"""
return _rust_library_common(ctx, "rlib")

def _rust_static_library_impl(ctx):
"""The implementation of the `rust_static_library` rule.
Args:
ctx (ctx): The rule's context object
Returns:
list: A list of providers.
"""
return _rust_library_common(ctx, "staticlib")

def _rust_shared_library_impl(ctx):
"""The implementation of the `rust_shared_library` rule.
Args:
ctx (ctx): The rule's context object
Returns:
list: A list of providers.
"""
return _rust_library_common(ctx, "cdylib")

def _rust_proc_macro_impl(ctx):
"""The implementation of the `rust_proc_macro` rule.
Args:
ctx (ctx): The rule's context object
Returns:
list: A list of providers.
"""
return _rust_library_common(ctx, "proc-macro")

def _rust_library_common(ctx, crate_type):
"""The common implementation of the library-like rules.
Args:
ctx (ctx): The rule's context object
crate_type (String): one of lib|rlib|dylib|staticlib|cdylib|proc-macro
Returns:
list: A list of providers. See `rustc_compile_action`
"""
Expand All @@ -155,7 +200,6 @@ def _rust_library_impl(ctx):
output_hash = determine_output_hash(crate_root)

crate_name = name_to_crate_name(ctx.label.name)
crate_type = getattr(ctx.attr, "crate_type")
rust_lib_name = _determine_lib_name(
crate_name,
crate_type,
Expand Down Expand Up @@ -198,16 +242,14 @@ def _rust_binary_impl(ctx):

output = ctx.actions.declare_file(ctx.label.name + toolchain.binary_ext)

crate_type = getattr(ctx.attr, "crate_type")

return rustc_compile_action(
ctx = ctx,
toolchain = toolchain,
crate_type = crate_type,
crate_type = "bin",
crate_info = rust_common.crate_info(
name = crate_name,
type = crate_type,
root = crate_root_src(ctx.attr, ctx.files.srcs, crate_type),
type = "bin",
root = crate_root_src(ctx.attr, ctx.files.srcs, crate_type="bin"),
srcs = ctx.files.srcs,
deps = ctx.attr.deps,
proc_macro_deps = ctx.attr.proc_macro_deps,
Expand Down Expand Up @@ -575,18 +617,6 @@ _common_attrs = {
),
}

_rust_library_attrs = {
"crate_type": attr.string(
doc = _tidy("""
The type of linkage to use for building this library.
Options include `"lib"`, `"rlib"`, `"dylib"`, `"cdylib"`, `"staticlib"`, and `"proc-macro"`.
The exact output file will depend on the toolchain used.
"""),
default = "rlib",
),
}

_rust_test_attrs = {
"crate": attr.label(
mandatory = False,
Expand Down Expand Up @@ -626,8 +656,7 @@ _rust_test_attrs = {

rust_library = rule(
implementation = _rust_library_impl,
attrs = dict(_common_attrs.items() +
_rust_library_attrs.items()),
attrs = dict(_common_attrs.items()),
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
Expand Down Expand Up @@ -700,10 +729,68 @@ INFO: Elapsed time: 1.245s, Critical Path: 1.01s
""",
)

rust_static_library = rule(
implementation = _rust_static_library_impl,
attrs = dict(_common_attrs.items()),
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
str(Label("//rust:toolchain")),
"@bazel_tools//tools/cpp:toolchain_type",
],
doc = """\
Builds a Rust static library.
This static library will contain all transitively reachable crates and native objects.
It is meant to be used when producing an artifact that is then consumed by some other build system
(for example to produce an archive that Python program links against).
This rule provides CcInfo, so it can be used everywhere Bazel expects C++ rules.
When building the whole binary in Bazel, use rust_library instead.
```
""",
)

rust_shared_library = rule(
implementation = _rust_shared_library_impl,
attrs = dict(_common_attrs.items()),
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
str(Label("//rust:toolchain")),
"@bazel_tools//tools/cpp:toolchain_type",
],
doc = """\
Builds a Rust shared library.
This shared library will contain all transitively reachable crates and native objects.
It is meant to be used when producing an artifact that is then consumed by some other build system
(for example to produce a shared library that Python program links against).
This rule provides CcInfo, so it can be used everywhere Bazel expects C++ rules.
When building the whole binary in Bazel, use rust_library instead.
```
""",
)

rust_proc_macro = rule(
implementation = _rust_proc_macro_impl,
attrs = dict(_common_attrs.items()),
fragments = ["cpp"],
host_fragments = ["cpp"],
toolchains = [
str(Label("//rust:toolchain")),
"@bazel_tools//tools/cpp:toolchain_type",
],
doc = """\
Builds a Rust proc-macro crate.
```
""",
)

_rust_binary_attrs = {
"crate_type": attr.string(
default = "bin",
),
"linker_script": attr.label(
doc = _tidy("""
Link script to forward into linker via rustc options.
Expand Down Expand Up @@ -874,7 +961,7 @@ only depends on the `hello_lib` `rust_library` target:
```python
package(default_visibility = ["//visibility:public"])
load("@rules_rust//rust:rust.bzl", "rust_library", "rust_test")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
rust_library(
name = "hello_lib",
Expand Down Expand Up @@ -941,7 +1028,7 @@ with `greeting.rs` in `srcs` and a dependency on the `hello_lib` target:
```python
package(default_visibility = ["//visibility:public"])
load("@rules_rust//rust:rust.bzl", "rust_library", "rust_test")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_test")
rust_library(
name = "hello_lib",
Expand Down Expand Up @@ -1057,7 +1144,7 @@ To build the benchmark test, add a `rust_benchmark` target:
```python
package(default_visibility = ["//visibility:public"])
load("@rules_rust//rust:rust.bzl", "rust_library", "rust_benchmark")
load("@rules_rust//rust:defs.bzl", "rust_library", "rust_benchmark")
rust_library(
name = "fibonacci",
Expand Down
56 changes: 34 additions & 22 deletions rust/rust.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,49 @@
# See the License for the specific language governing permissions and
# limitations under the License.

"""Public entry point to all Rust rules and supported APIs."""
"""Deprecated, please use //rust:defs.bzl."""

load(
"//rust/private:clippy.bzl",
_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:defs.bzl",
_error_format = "error_format",
_rust_benchmark = "rust_benchmark",
_rust_binary = "rust_binary",
_rust_clippy = "rust_clippy",
_rust_clippy_aspect = "rust_clippy_aspect",
_rust_common = "rust_common",
_rust_doc = "rust_doc",
_rust_doc_test = "rust_doc_test",
_rust_library = "rust_library",
_rust_proc_macro = "rust_proc_macro",
_rust_shared_library = "rust_shared_library",
_rust_static_library = "rust_static_library",
_rust_test = "rust_test",
_rust_test_binary = "rust_test_binary",
)
load(
"//rust/private:rustc.bzl",
_error_format = "error_format",
)
load(
"//rust/private:rustdoc.bzl",
_rust_doc = "rust_doc",
)
load(
"//rust/private:rustdoc_test.bzl",
_rust_doc_test = "rust_doc_test",
)

rust_library = _rust_library
# See @rules_rust//rust/private:rust.bzl for a complete description.
def rust_library(**args):
"""Deprecated. Use the version from "@rules_rust//rust:defs.bzl" instead.
Args:
**args: args to pass to the relevant rule.
Returns:
a target.
"""
if "crate_type" in args:
crate_type = args.pop("crate_type")
if crate_type in ["lib", "rlib", "dylib"]:
return _rust_library(**args)
elif crate_type == "cdylib":
return _rust_shared_library(**args)
elif crate_type == "staticlib":
return _rust_static_library(**args)
elif crate_type == "proc-macro":
return _rust_proc_macro(**args)
else:
fail("Unexpected crate_type: " + crate_type)
else:
return _rust_library(**args)

rust_binary = _rust_binary
# See @rules_rust//rust/private:rust.bzl for a complete description.
Expand Down
Loading

0 comments on commit c7529ca

Please sign in to comment.