Squashed 'third_party/rules_rust/' content from commit bf59038ca
git-subtree-dir: third_party/rules_rust
git-subtree-split: bf59038cac11798cbaef9f3bf965bad8182b97fa
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
Change-Id: I5a20e403203d670df467ea97dde9a4ac40339a8d
diff --git a/rust/private/rustdoc.bzl b/rust/private/rustdoc.bzl
new file mode 100644
index 0000000..86c2acd
--- /dev/null
+++ b/rust/private/rustdoc.bzl
@@ -0,0 +1,318 @@
+# Copyright 2018 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.
+
+"""Rules for generating documentation with `rustdoc` for Bazel built crates"""
+
+load("//rust/private:common.bzl", "rust_common")
+load("//rust/private:rustc.bzl", "collect_deps", "collect_inputs", "construct_arguments")
+load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain", "find_toolchain")
+
+def _strip_crate_info_output(crate_info):
+ """Set the CrateInfo.output to None for a given CrateInfo provider.
+
+ Args:
+ crate_info (CrateInfo): A provider
+
+ Returns:
+ CrateInfo: A modified CrateInfo provider
+ """
+ return rust_common.create_crate_info(
+ name = crate_info.name,
+ type = crate_info.type,
+ root = crate_info.root,
+ srcs = crate_info.srcs,
+ deps = crate_info.deps,
+ proc_macro_deps = crate_info.proc_macro_deps,
+ aliases = crate_info.aliases,
+ # This crate info should have no output
+ output = None,
+ edition = crate_info.edition,
+ rustc_env = crate_info.rustc_env,
+ is_test = crate_info.is_test,
+ compile_data = crate_info.compile_data,
+ )
+
+def rustdoc_compile_action(
+ ctx,
+ toolchain,
+ crate_info,
+ output = None,
+ rustdoc_flags = [],
+ is_test = False):
+ """Create a struct of information needed for a `rustdoc` compile action based on crate passed to the rustdoc rule.
+
+ Args:
+ ctx (ctx): The rule's context object.
+ toolchain (rust_toolchain): The currently configured `rust_toolchain`.
+ crate_info (CrateInfo): The provider of the crate passed to a rustdoc rule.
+ output (File, optional): An optional output a `rustdoc` action is intended to produce.
+ rustdoc_flags (list, optional): A list of `rustdoc` specific flags.
+ is_test (bool, optional): If True, the action will be configured for `rust_doc_test` targets
+
+ Returns:
+ struct: A struct of some `ctx.actions.run` arguments.
+ """
+
+ # If an output was provided, ensure it's used in rustdoc arguments
+ if output:
+ rustdoc_flags = [
+ "--output",
+ output.path,
+ ] + rustdoc_flags
+
+ cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
+
+ dep_info, build_info, linkstamps = collect_deps(
+ deps = crate_info.deps,
+ proc_macro_deps = crate_info.proc_macro_deps,
+ aliases = crate_info.aliases,
+ )
+
+ compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs, ambiguous_libs = collect_inputs(
+ ctx = ctx,
+ file = ctx.file,
+ files = ctx.files,
+ linkstamps = linkstamps,
+ toolchain = toolchain,
+ cc_toolchain = cc_toolchain,
+ feature_configuration = feature_configuration,
+ crate_info = crate_info,
+ dep_info = dep_info,
+ build_info = build_info,
+ )
+
+ # Since this crate is not actually producing the output described by the
+ # given CrateInfo, this attribute needs to be stripped to allow the rest
+ # of the rustc functionality in `construct_arguments` to avoid generating
+ # arguments expecting to do so.
+ rustdoc_crate_info = _strip_crate_info_output(crate_info)
+
+ args, env = construct_arguments(
+ ctx = ctx,
+ attr = ctx.attr,
+ file = ctx.file,
+ toolchain = toolchain,
+ tool_path = toolchain.rust_doc.short_path if is_test else toolchain.rust_doc.path,
+ cc_toolchain = cc_toolchain,
+ feature_configuration = feature_configuration,
+ crate_info = rustdoc_crate_info,
+ dep_info = dep_info,
+ linkstamp_outs = linkstamp_outs,
+ ambiguous_libs = ambiguous_libs,
+ output_hash = None,
+ rust_flags = rustdoc_flags,
+ out_dir = out_dir,
+ build_env_files = build_env_files,
+ build_flags_files = build_flags_files,
+ emit = [],
+ remap_path_prefix = None,
+ force_link = True,
+ )
+
+ # Because rustdoc tests compile tests outside of the sandbox, the sysroot
+ # must be updated to the `short_path` equivilant as it will now be
+ # a part of runfiles.
+ if is_test:
+ if "SYSROOT" in env:
+ env.update({"SYSROOT": "${{pwd}}/{}".format(toolchain.sysroot_short_path)})
+
+ # `rustdoc` does not support the SYSROOT environment variable. To account
+ # for this, the flag must be explicitly passed to the `rustdoc` binary.
+ args.rustc_flags.add("--sysroot=${{pwd}}/{}".format(toolchain.sysroot_short_path))
+
+ return struct(
+ executable = ctx.executable._process_wrapper,
+ inputs = depset([crate_info.output], transitive = [compile_inputs]),
+ env = env,
+ arguments = args.all,
+ tools = [toolchain.rust_doc],
+ )
+
+def _zip_action(ctx, input_dir, output_zip, crate_label):
+ """Creates an archive of the generated documentation from `rustdoc`
+
+ Args:
+ ctx (ctx): The `rust_doc` rule's context object
+ input_dir (File): A directory containing the outputs from rustdoc
+ output_zip (File): The location of the output archive containing generated documentation
+ crate_label (Label): The label of the crate docs are being generated for.
+ """
+ args = ctx.actions.args()
+ args.add(ctx.executable._zipper)
+ args.add(output_zip)
+ args.add(ctx.bin_dir.path)
+ args.add_all([input_dir], expand_directories = True)
+ ctx.actions.run(
+ executable = ctx.executable._dir_zipper,
+ inputs = [input_dir],
+ outputs = [output_zip],
+ arguments = [args],
+ mnemonic = "RustdocZip",
+ progress_message = "Creating RustdocZip for {}".format(crate_label),
+ tools = [ctx.executable._zipper],
+ )
+
+def _rust_doc_impl(ctx):
+ """The implementation of the `rust_doc` rule
+
+ Args:
+ ctx (ctx): The rule's context object
+ """
+
+ crate = ctx.attr.crate
+ crate_info = crate[rust_common.crate_info]
+
+ output_dir = ctx.actions.declare_directory("{}.rustdoc".format(ctx.label.name))
+
+ # Add the current crate as an extern for the compile action
+ rustdoc_flags = [
+ "--extern",
+ "{}={}".format(crate_info.name, crate_info.output.path),
+ ]
+
+ action = rustdoc_compile_action(
+ ctx = ctx,
+ toolchain = find_toolchain(ctx),
+ crate_info = crate_info,
+ output = output_dir,
+ rustdoc_flags = rustdoc_flags,
+ )
+
+ ctx.actions.run(
+ mnemonic = "Rustdoc",
+ progress_message = "Generating Rustdoc for {}".format(crate.label),
+ outputs = [output_dir],
+ executable = action.executable,
+ inputs = action.inputs,
+ env = action.env,
+ arguments = action.arguments,
+ tools = action.tools,
+ )
+
+ # This rule does nothing without a single-file output, though the directory should've sufficed.
+ _zip_action(ctx, output_dir, ctx.outputs.rust_doc_zip, crate.label)
+
+ return [
+ DefaultInfo(
+ files = depset([ctx.outputs.rust_doc_zip]),
+ ),
+ OutputGroupInfo(
+ rustdoc_dir = depset([output_dir]),
+ rustdoc_zip = depset([ctx.outputs.rust_doc_zip]),
+ ),
+ ]
+
+rust_doc = rule(
+ doc = dedent("""\
+ Generates code documentation.
+
+ Example:
+ Suppose you have the following directory structure for a Rust library crate:
+
+ ```
+ [workspace]/
+ WORKSPACE
+ hello_lib/
+ BUILD
+ src/
+ lib.rs
+ ```
+
+ To build [`rustdoc`][rustdoc] documentation for the `hello_lib` crate, define \
+ a `rust_doc` rule that depends on the the `hello_lib` `rust_library` target:
+
+ [rustdoc]: https://doc.rust-lang.org/book/documentation.html
+
+ ```python
+ package(default_visibility = ["//visibility:public"])
+
+ load("@rules_rust//rust:defs.bzl", "rust_library", "rust_doc")
+
+ rust_library(
+ name = "hello_lib",
+ srcs = ["src/lib.rs"],
+ )
+
+ rust_doc(
+ name = "hello_lib_doc",
+ crate = ":hello_lib",
+ )
+ ```
+
+ Running `bazel build //hello_lib:hello_lib_doc` will build a zip file containing \
+ the documentation for the `hello_lib` library crate generated by `rustdoc`.
+ """),
+ implementation = _rust_doc_impl,
+ attrs = {
+ "crate": attr.label(
+ doc = (
+ "The label of the target to generate code documentation for.\n" +
+ "\n" +
+ "`rust_doc` can generate HTML code documentation for the source files of " +
+ "`rust_library` or `rust_binary` targets."
+ ),
+ providers = [rust_common.crate_info],
+ mandatory = True,
+ ),
+ "html_after_content": attr.label(
+ doc = "File to add in `<body>`, after content.",
+ allow_single_file = [".html", ".md"],
+ ),
+ "html_before_content": attr.label(
+ doc = "File to add in `<body>`, before content.",
+ allow_single_file = [".html", ".md"],
+ ),
+ "html_in_header": attr.label(
+ doc = "File to add to `<head>`.",
+ allow_single_file = [".html", ".md"],
+ ),
+ "markdown_css": attr.label_list(
+ doc = "CSS files to include via `<link>` in a rendered Markdown file.",
+ allow_files = [".css"],
+ ),
+ "_cc_toolchain": attr.label(
+ doc = "In order to use find_cpp_toolchain, you must define the '_cc_toolchain' attribute on your rule or aspect.",
+ default = "@bazel_tools//tools/cpp:current_cc_toolchain",
+ ),
+ "_dir_zipper": attr.label(
+ doc = "A tool that orchestrates the creation of zip archives for rustdoc outputs.",
+ default = Label("//util/dir_zipper"),
+ cfg = "exec",
+ executable = True,
+ ),
+ "_process_wrapper": attr.label(
+ doc = "A process wrapper for running rustdoc on all platforms",
+ default = Label("@rules_rust//util/process_wrapper"),
+ executable = True,
+ allow_single_file = True,
+ cfg = "exec",
+ ),
+ "_zipper": attr.label(
+ doc = "A Bazel provided tool for creating archives",
+ default = Label("@bazel_tools//tools/zip:zipper"),
+ cfg = "exec",
+ executable = True,
+ ),
+ },
+ fragments = ["cpp"],
+ host_fragments = ["cpp"],
+ outputs = {
+ "rust_doc_zip": "%{name}.zip",
+ },
+ toolchains = [
+ str(Label("//rust:toolchain")),
+ "@bazel_tools//tools/cpp:toolchain_type",
+ ],
+ incompatible_use_toolchain_transition = True,
+)