Skip to content

Commit

Permalink
Introduce feature rules_rust_link_cc. (#2723)
Browse files Browse the repository at this point in the history
This feature is similar to `rules_rust_unsupported_feature`. The
difference is that, `rules_rust_unsupported_feature` gets disabled if
*any* rust is involved, while this feature gets disabled if *only* rust
is involved.

My use case for this feature is to static link to c++ / objc stdlibs.
They are needed only when any C object is being linked, and will produce
invalid rust_proc_macro if linked blindly.

This implementation uses the fact that `DepInfo.transitive_noncrates`
would be empty unless there is a `cc_library` or `cc_import` in the
(transitive) deps. As a side effect, `collect_deps()` can no longer use
the output of `_are_linkstamps_supported()` so it now always returns a
populated linkstamp depset, to be discarded later if linkstamps are not
supported.

---------

Co-authored-by: scentini <[email protected]>
  • Loading branch information
yuzhy8701 and scentini authored Aug 6, 2024
1 parent 70e8729 commit 0e1297d
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 23 deletions.
7 changes: 3 additions & 4 deletions rust/private/clippy.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -99,19 +99,18 @@ def _clippy_aspect_impl(target, ctx):
toolchain = find_toolchain(ctx)
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)

dep_info, build_info, linkstamps = collect_deps(
dep_info, build_info, _ = collect_deps(
deps = crate_info.deps,
proc_macro_deps = crate_info.proc_macro_deps,
aliases = crate_info.aliases,
# Clippy doesn't need to invoke transitive linking, therefore doesn't need linkstamps.
are_linkstamps_supported = False,
)

compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs, ambiguous_libs = collect_inputs(
ctx,
ctx.rule.file,
ctx.rule.files,
linkstamps,
# Clippy doesn't need to invoke transitive linking, therefore doesn't need linkstamps.
depset([]),
toolchain,
cc_toolchain,
feature_configuration,
Expand Down
30 changes: 19 additions & 11 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ load(
)
load(":utils.bzl", "is_std_dylib")

# This feature is disabled unless one of the dependencies is a cc_library.
# Authors of C++ toolchains can place linker flags that should only be applied
# when linking with C objects in a feature with this name, or require this
# feature from other features which needs to be disabled together.
RUST_LINK_CC_FEATURE = "rules_rust_link_cc"

BuildInfo = _BuildInfo

AliasableDepInfo = provider(
Expand Down Expand Up @@ -195,21 +201,19 @@ def _is_proc_macro(crate_info):
def collect_deps(
deps,
proc_macro_deps,
aliases,
are_linkstamps_supported = False):
aliases):
"""Walks through dependencies and collects the transitive dependencies.
Args:
deps (list): The deps from ctx.attr.deps.
proc_macro_deps (list): The proc_macro deps from ctx.attr.proc_macro_deps.
aliases (dict): A dict mapping aliased targets to their actual Crate information.
are_linkstamps_supported (bool): Whether the current rule and the toolchain support building linkstamps..
Returns:
tuple: Returns a tuple of:
DepInfo,
BuildInfo,
linkstamps (depset[CcLinkstamp]): A depset of CcLinkstamps that need to be compiled and linked into all linked binaries.
linkstamps (depset[CcLinkstamp]): A depset of CcLinkstamps that need to be compiled and linked into all linked binaries when applicable.
"""
direct_crates = []
Expand Down Expand Up @@ -249,7 +253,7 @@ def collect_deps(
cc_info = _get_cc_info(dep)
dep_build_info = _get_build_info(dep)

if cc_info and are_linkstamps_supported:
if cc_info:
linkstamps.append(cc_info.linking_context.linkstamps())

if crate_info:
Expand Down Expand Up @@ -1150,8 +1154,6 @@ def rustc_compile_action(
rustc_output = crate_info_dict.get("rustc_output", None)
rustc_rmeta_output = crate_info_dict.get("rustc_rmeta_output", None)

cc_toolchain, feature_configuration = find_cc_toolchain(ctx)

# Determine whether to use cc_common.link:
# * either if experimental_use_cc_common_link is 1,
# * or if experimental_use_cc_common_link is -1 and
Expand All @@ -1169,11 +1171,17 @@ def rustc_compile_action(
deps = crate_info_dict["deps"],
proc_macro_deps = crate_info_dict["proc_macro_deps"],
aliases = crate_info_dict["aliases"],
are_linkstamps_supported = _are_linkstamps_supported(
feature_configuration = feature_configuration,
has_grep_includes = hasattr(ctx.attr, "_use_grep_includes"),
),
)
extra_disabled_features = [RUST_LINK_CC_FEATURE]
if crate_info.type in ["bin", "cdylib"] and dep_info.transitive_noncrates.to_list():
# One or more of the transitive deps is a cc_library / cc_import
extra_disabled_features = []
cc_toolchain, feature_configuration = find_cc_toolchain(ctx, extra_disabled_features)
if not _are_linkstamps_supported(
feature_configuration = feature_configuration,
has_grep_includes = hasattr(ctx.attr, "_use_grep_includes"),
):
linkstamps = depset([])

# Determine if the build is currently running with --stamp
stamp = is_stamping_enabled(attr)
Expand Down
4 changes: 2 additions & 2 deletions rust/private/rustdoc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def rustdoc_compile_action(

cc_toolchain, feature_configuration = find_cc_toolchain(ctx)

dep_info, build_info, linkstamps = collect_deps(
dep_info, build_info, _ = collect_deps(
deps = crate_info.deps,
proc_macro_deps = crate_info.proc_macro_deps,
aliases = crate_info.aliases,
Expand All @@ -87,7 +87,7 @@ def rustdoc_compile_action(
ctx = ctx,
file = ctx.file,
files = ctx.files,
linkstamps = linkstamps,
linkstamps = depset([]),
toolchain = toolchain,
cc_toolchain = cc_toolchain,
feature_configuration = feature_configuration,
Expand Down
7 changes: 3 additions & 4 deletions rust/private/unpretty.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -132,19 +132,18 @@ def _rust_unpretty_aspect_impl(target, ctx):
toolchain = find_toolchain(ctx)
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)

dep_info, build_info, linkstamps = collect_deps(
dep_info, build_info, _ = collect_deps(
deps = crate_info.deps,
proc_macro_deps = crate_info.proc_macro_deps,
aliases = crate_info.aliases,
# Rust expand doesn't need to invoke transitive linking, therefore doesn't need linkstamps.
are_linkstamps_supported = False,
)

compile_inputs, out_dir, build_env_files, build_flags_files, linkstamp_outs, ambiguous_libs = collect_inputs(
ctx,
ctx.rule.file,
ctx.rule.files,
linkstamps,
# Rust expand doesn't need to invoke transitive linking, therefore doesn't need linkstamps.
depset([]),
toolchain,
cc_toolchain,
feature_configuration,
Expand Down
6 changes: 4 additions & 2 deletions rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,12 @@ def find_toolchain(ctx):
"""
return ctx.toolchains[Label("//rust:toolchain_type")]

def find_cc_toolchain(ctx):
def find_cc_toolchain(ctx, extra_unsupported_features = tuple()):
"""Extracts a CcToolchain from the current target's context
Args:
ctx (ctx): The current target's rule context object
extra_unsupported_features (sequence of str): Extra featrures to disable
Returns:
tuple: A tuple of (CcToolchain, FeatureConfiguration)
Expand All @@ -56,7 +57,8 @@ def find_cc_toolchain(ctx):
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = UNSUPPORTED_FEATURES + ctx.disabled_features,
unsupported_features = UNSUPPORTED_FEATURES + ctx.disabled_features +
list(extra_unsupported_features),
)
return cc_toolchain, feature_configuration

Expand Down

0 comments on commit 0e1297d

Please sign in to comment.