diff --git a/rust/private/providers.bzl b/rust/private/providers.bzl index 746370bc70..143ec0ad3a 100644 --- a/rust/private/providers.bzl +++ b/rust/private/providers.bzl @@ -36,6 +36,7 @@ CrateInfo = provider( "rustc_rmeta_output": "File: The rmeta file produced for this crate. It is optional.", "srcs": "depset[File]: All source Files that are part of the crate.", "std_dylib": "File: libstd.so file", + "crate_features": "[str]: A list of feature enabled for this crate.", "type": ( "str: The type of this crate " + "(see [rustc --crate-type](https://doc.rust-lang.org/rustc/command-line-arguments.html#--crate-type-a-list-of-types-of-crates-for-the-compiler-to-emit))." diff --git a/rust/private/rust.bzl b/rust/private/rust.bzl index 74d458eef9..2596630ba1 100644 --- a/rust/private/rust.bzl +++ b/rust/private/rust.bzl @@ -206,6 +206,7 @@ def _rust_library_common(ctx, crate_type): compile_data = depset(compile_data), compile_data_targets = depset(ctx.attr.compile_data), owner = ctx.label, + crate_features = ctx.attr.crate_features, ), ) @@ -258,6 +259,7 @@ def _rust_binary_impl(ctx): compile_data = depset(compile_data), compile_data_targets = depset(ctx.attr.compile_data), owner = ctx.label, + crate_features = ctx.attr.crate_features, ), ) @@ -422,6 +424,7 @@ def _rust_test_impl(ctx): compile_data = depset(compile_data), compile_data_targets = depset(ctx.attr.compile_data), owner = ctx.label, + crate_features = [], ) providers = rustc_compile_action( diff --git a/rust/private/rustdoc.bzl b/rust/private/rustdoc.bzl index 67845c34ca..bf1ffb5805 100644 --- a/rust/private/rustdoc.bzl +++ b/rust/private/rustdoc.bzl @@ -236,6 +236,9 @@ def _rust_doc_impl(ctx): rustdoc_flags.extend(ctx.attr.rustdoc_flags) + if ctx.attr.include_features: + rustdoc_flags.extend(["--cfg=feature=\"{}\"".format(feature) for feature in crate_info.crate_features]) + action = rustdoc_compile_action( ctx = ctx, toolchain = find_toolchain(ctx), @@ -350,6 +353,10 @@ rust_doc = rule( file of arguments to rustc: `@$(location //package:target)`. """), ), + "include_features": attr.bool( + doc = "Include the features defined by `crate_features` when building the doc tests.", + default = True, + ), "_dir_zipper": attr.label( doc = "A tool that orchestrates the creation of zip archives for rustdoc outputs.", default = Label("//rust/private/rustdoc/dir_zipper"), diff --git a/rust/private/rustdoc_test.bzl b/rust/private/rustdoc_test.bzl index a338518038..6b724103fa 100644 --- a/rust/private/rustdoc_test.bzl +++ b/rust/private/rustdoc_test.bzl @@ -129,6 +129,7 @@ def _rust_doc_test_impl(ctx): compile_data = crate.compile_data, compile_data_targets = crate.compile_data_targets, wrapped_crate_type = crate.type, + crate_features = crate.crate_features, owner = ctx.label, ) @@ -150,6 +151,9 @@ def _rust_doc_test_impl(ctx): "--test", ] + if ctx.attr.include_features: + rustdoc_flags.extend(["--cfg=feature=\"{}\"".format(feature) for feature in crate_info.crate_features]) + action = rustdoc_compile_action( ctx = ctx, toolchain = toolchain, @@ -228,6 +232,10 @@ rust_doc_test = rule( default = Label("//rust/private/rustdoc:rustdoc_test_writer"), executable = True, ), + "include_features": attr.bool( + doc = "Include the features defined by `crate_features` when building the doc tests.", + default = True, + ), }, test = True, fragments = ["cpp"], diff --git a/test/unit/rustdoc/rustdoc_features.rs b/test/unit/rustdoc/rustdoc_features.rs new file mode 100644 index 0000000000..c99361c73a --- /dev/null +++ b/test/unit/rustdoc/rustdoc_features.rs @@ -0,0 +1,29 @@ +// Copyright 2022 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. + +#![cfg_attr(not(no_feature_test), deny(rustdoc::broken_intra_doc_links))] +#![cfg_attr(no_feature_test, allow(rustdoc::broken_intra_doc_links))] + +//! +//! Checkout [inc] +//! + +#[cfg(all(no_feature_test, feature = "docs"))] +compiler_error!("cannot have both no_feature_test and feature=\"docs\" enabled"); + +/// Increments the input. +#[cfg(feature = "docs")] +pub fn inc(n: u32) -> u32 { + n + 1 +} diff --git a/test/unit/rustdoc/rustdoc_unit_test.bzl b/test/unit/rustdoc/rustdoc_unit_test.bzl index aa1f9b2f02..27e4ed8986 100644 --- a/test/unit/rustdoc/rustdoc_unit_test.bzl +++ b/test/unit/rustdoc/rustdoc_unit_test.bzl @@ -97,6 +97,30 @@ def _rustdoc_for_bin_with_transitive_proc_macro_test_impl(ctx): return analysistest.end(env) +def _rustdoc_for_lib_with_features_test_impl(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env) + + _common_rustdoc_checks(env, tut) + + action = _get_rustdoc_action(env, tut) + + assert_argv_contains(env, action, "--cfg=feature=\"docs\"") + + return analysistest.end(env) + +def _rustdoc_for_lib_without_features_test_impl(ctx): + env = analysistest.begin(ctx) + tut = analysistest.target_under_test(env) + + _common_rustdoc_checks(env, tut) + + action = _get_rustdoc_action(env, tut) + + assert_argv_contains_prefix_not(env, action, "--cfg=feature") + + return analysistest.end(env) + def _rustdoc_for_lib_with_cc_lib_test_impl(ctx): env = analysistest.begin(ctx) tut = analysistest.target_under_test(env) @@ -164,6 +188,8 @@ rustdoc_for_lib_with_proc_macro_in_docs_test = analysistest.make(_rustdoc_for_li rustdoc_for_bin_with_transitive_proc_macro_test = analysistest.make(_rustdoc_for_bin_with_transitive_proc_macro_test_impl) rustdoc_for_lib_with_cc_lib_test = analysistest.make(_rustdoc_for_lib_with_cc_lib_test_impl) rustdoc_with_args_test = analysistest.make(_rustdoc_with_args_test_impl) +rustdoc_for_lib_with_features_test = analysistest.make(_rustdoc_for_lib_with_features_test_impl) +rustdoc_for_lib_without_features_test = analysistest.make(_rustdoc_for_lib_without_features_test_impl) rustdoc_zip_output_test = analysistest.make(_rustdoc_zip_output_test_impl) rustdoc_with_json_error_format_test = analysistest.make(_rustdoc_with_json_error_format_test_impl, config_settings = { str(Label("//rust/settings:error_format")): "json", @@ -283,6 +309,34 @@ def _define_targets(): crate_features = ["with_proc_macro"], ) + _target_maker( + rust_library, + name = "lib_with_features", + srcs = ["rustdoc_features.rs"], + crate_features = ["docs"], + ) + + rust_doc( + name = "rustdoc_lib_with_features", + crate = ":lib_with_features", + ) + + _target_maker( + rust_library, + name = "lib_without_features", + srcs = ["rustdoc_features.rs"], + crate_features = ["docs"], + ) + + rust_doc( + name = "rustdoc_lib_without_features", + crate = ":lib_with_features", + include_features = False, + rustdoc_flags = [ + "--cfg=no_feature_test" + ] + ) + cc_library( name = "cc_lib", hdrs = ["rustdoc.h"], @@ -424,6 +478,16 @@ def rustdoc_test_suite(name): target_under_test = ":lib_with_cc_doc", ) + rustdoc_for_lib_with_features_test( + name = "rustdoc_for_lib_with_features_test", + target_under_test = ":rustdoc_lib_with_features", + ) + + rustdoc_for_lib_without_features_test( + name = "rustdoc_for_lib_without_features_test", + target_under_test = ":rustdoc_lib_without_features", + ) + rustdoc_with_args_test( name = "rustdoc_with_args_test", target_under_test = ":rustdoc_with_args", @@ -455,6 +519,8 @@ def rustdoc_test_suite(name): ":rustdoc_for_lib_with_proc_macro_in_docs_test", ":rustdoc_for_lib_with_proc_macro_test", ":rustdoc_for_lib_with_cc_lib_test", + ":rustdoc_for_lib_with_features_test", + ":rustdoc_for_lib_without_features_test", ":rustdoc_with_args_test", ":rustdoc_with_json_error_format_test", ":rustdoc_zip_output_test",