Skip to content

Commit

Permalink
Pass C++ runtime lib when C++ toolchain declares it
Browse files Browse the repository at this point in the history
Currently `rules_rust` won't link against the C++ standard library in case
C++ toolchain is the `static_link_cpp_runtimes` feature (therefore when
it uses `cc_toolchain.static_runtime_lib` and `cc_toolchain.dynamic_runtime_lib`
attributes to declare which version of C++ static library should be
linked into the final binary).

This PR modifies `get_libs_for_static_executable` to also look into the
C++ toolchain and depend on C++ standard library from there.

Once we implement the support for dynamically linked rust binaries we
will likely have an equivalend `get_libs_for_dynamic_executable`, which
would then look into `cc_toolchain.dynamic_runtime_lib`.

While there, I moved the `get_cc_toolchain` function to the `utils.rs`,
to be consistent with the handling of the Rust toolchain.
  • Loading branch information
hlopko committed Feb 5, 2021
1 parent 3b02397 commit 8ac6e3a
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 37 deletions.
6 changes: 3 additions & 3 deletions cargo/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ load("//rust:rust.bzl", "rust_binary")
load("//rust/private:rust.bzl", "name_to_crate_name")

# buildifier: disable=bzl-visibility
load("//rust/private:rustc.bzl", "BuildInfo", "DepInfo", "get_cc_toolchain", "get_compilation_mode_opts", "get_linker_and_args")
load("//rust/private:rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_linker_and_args")

# buildifier: disable=bzl-visibility
load("//rust/private:utils.bzl", "expand_locations", "find_toolchain")
load("//rust/private:utils.bzl", "expand_locations", "find_cc_toolchain", "find_toolchain")

def get_cc_compile_env(cc_toolchain, feature_configuration):
"""Gather cc environment variables from the given `cc_toolchain`
Expand Down Expand Up @@ -98,7 +98,7 @@ def _build_script_impl(ctx):

# Pull in env vars which may be required for the cc_toolchain to work (e.g. on OSX, the SDK version).
# We hope that the linker env is sufficient for the whole cc_toolchain.
cc_toolchain, feature_configuration = get_cc_toolchain(ctx)
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
_, _, linker_env = get_linker_and_args(ctx, cc_toolchain, feature_configuration, None)
env.update(**linker_env)

Expand Down
7 changes: 3 additions & 4 deletions rust/private/clippy.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ load(
"collect_deps",
"collect_inputs",
"construct_arguments",
"get_cc_toolchain",
)
load("//rust/private:utils.bzl", "determine_output_hash", "find_toolchain")
load("//rust/private:utils.bzl", "determine_output_hash", "find_cc_toolchain", "find_toolchain")

_rust_extensions = [
"rs",
Expand All @@ -48,6 +47,7 @@ def _clippy_aspect_impl(target, ctx):
rust_srcs = _rust_sources(target, ctx.rule)

toolchain = find_toolchain(ctx)
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
crate_info = target[rust_common.crate_info]
crate_type = crate_info.type

Expand All @@ -72,6 +72,7 @@ def _clippy_aspect_impl(target, ctx):
ctx.rule.file,
ctx.rule.files,
toolchain,
cc_toolchain,
crate_info,
dep_info,
build_info,
Expand All @@ -81,8 +82,6 @@ def _clippy_aspect_impl(target, ctx):
# This file is necessary because "ctx.actions.run" mandates an output.
clippy_marker = ctx.actions.declare_file(ctx.label.name + "_clippy.ok")

cc_toolchain, feature_configuration = get_cc_toolchain(ctx)

args, env = construct_arguments(
ctx,
ctx.file,
Expand Down
63 changes: 33 additions & 30 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ load(
"@bazel_tools//tools/build_defs/cc:action_names.bzl",
"CPP_LINK_EXECUTABLE_ACTION_NAME",
)
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
load("//rust/private:common.bzl", "rust_common")
load(
"//rust/private:utils.bzl",
"expand_locations",
"find_cc_toolchain",
"get_lib_name",
"get_libs_for_static_executable",
"relativize",
Expand Down Expand Up @@ -215,25 +215,6 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain):
build_info,
)

def get_cc_toolchain(ctx):
"""Extracts a CcToolchain from the current target's context
Args:
ctx (ctx): The current target's rule context object
Returns:
tuple: A tuple of (CcToolchain, FeatureConfiguration)
"""
cc_toolchain = find_cpp_toolchain(ctx)

feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
return cc_toolchain, feature_configuration

def get_cc_user_link_flags(ctx):
"""Get the current target's linkopt flags
Expand Down Expand Up @@ -319,16 +300,18 @@ def collect_inputs(
file,
files,
toolchain,
cc_toolchain,
crate_info,
dep_info,
build_info):
"""Gather's the inputs and required input information for a rustc action
Args:
ctx (ctx): The rule's context object
ctx (ctx): The rule's context object.
file (struct): A struct containing files defined in label type attributes marked as `allow_single_file`.
files (list): A list of all inputs
toolchain (rust_toolchain): The current `rust_toolchain`
files (list): A list of all inputs.
toolchain (rust_toolchain): The current `rust_toolchain`.
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`.
crate_info (CrateInfo): The Crate information of the crate to process build scripts for.
dep_info (DepInfo): The target Crate's dependency information.
build_info (BuildInfo): The target Crate's build settings.
Expand All @@ -338,7 +321,7 @@ def collect_inputs(
"""
linker_script = getattr(file, "linker_script") if hasattr(file, "linker_script") else None

linker_depset = find_cpp_toolchain(ctx).all_files
linker_depset = cc_toolchain.all_files

compile_inputs = depset(
crate_info.srcs +
Expand Down Expand Up @@ -510,7 +493,7 @@ def construct_arguments(
args.add("--codegen=linker=" + ld)
args.add_joined("--codegen", link_args, join_with = " ", format_joined = "link-args=%s")

add_native_link_flags(args, dep_info, crate_type)
_add_native_link_flags(args, dep_info, crate_type, cc_toolchain, feature_configuration)

# These always need to be added, even if not linking this crate.
add_crate_link_flags(args, dep_info)
Expand Down Expand Up @@ -565,6 +548,8 @@ def rustc_compile_action(
- (DepInfo): The transitive dependencies of this crate.
- (DefaultInfo): The output file for this crate, and its runfiles.
"""
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)

dep_info, build_info = collect_deps(
ctx.label,
crate_info.deps,
Expand All @@ -578,13 +563,12 @@ def rustc_compile_action(
ctx.file,
ctx.files,
toolchain,
cc_toolchain,
crate_info,
dep_info,
build_info,
)

cc_toolchain, feature_configuration = get_cc_toolchain(ctx)

args, env = construct_arguments(
ctx,
ctx.file,
Expand Down Expand Up @@ -656,7 +640,7 @@ def establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configur
ctx (ctx): The rule's context object
crate_info (CrateInfo): The CrateInfo provider of the target crate
toolchain (rust_toolchain): The current `rust_toolchain`
cc_toolchain (CcToolchainInfo): The current CcToolchainInfo
cc_toolchain (CcToolchainInfo): The current `CcToolchainInfo`
feature_configuration (FeatureConfiguration): Feature configuration to be queried.
Returns:
Expand Down Expand Up @@ -821,13 +805,15 @@ def _get_crate_dirname(crate):
"""
return crate.output.dirname

def add_native_link_flags(args, dep_info, crate_type):
def _add_native_link_flags(args, dep_info, crate_type, cc_toolchain, feature_configuration):
"""Adds linker flags for all dependencies of the current target.
Args:
args (Args): The Args struct for a ctx.action
dep_info (DepInfo): Dependency Info provider
crate_type: Crate type of the current target
cc_toolchain (CcToolchainInfo): The current `cc_toolchain`
feature_configuration (FeatureConfiguration): feature configuration to use with cc_toolchain
"""
if crate_type in ["lib", "rlib"]:
Expand All @@ -838,8 +824,25 @@ def add_native_link_flags(args, dep_info, crate_type):
args.add_all(dep_info.transitive_dylibs, map_each = get_lib_name, format_each = "-ldylib=%s")
args.add_all(dep_info.transitive_staticlibs, map_each = get_lib_name, format_each = "-lstatic=%s")

if crate_type in ["dylib", "cdylib"]:
# For shared libraries we want to link C++ runtime library dynamically
# (for example libstdc++.so or libc++.so).
args.add_all(
cc_toolchain.dynamic_runtime_lib(feature_configuration = feature_configuration),
map_each = get_lib_name,
format_each = "-ldylib=%s",
)
else:
# For all other crate types we want to link C++ runtime library statically
# (for example libstdc++.a or libc++.a).
args.add_all(
cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration),
map_each = get_lib_name,
format_each = "-lstatic=%s",
)

def _get_dirname(file):
"""A helper function for `add_native_link_flags`.
"""A helper function for `_add_native_link_flags`.
Args:
file (File): The target file
Expand Down
21 changes: 21 additions & 0 deletions rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

"""Utility functions not specific to the rust toolchain."""

load("@bazel_tools//tools/cpp:toolchain_utils.bzl", find_rules_cc_toolchain = "find_cpp_toolchain")

def find_toolchain(ctx):
"""Finds the first rust toolchain that is configured.
Expand All @@ -25,6 +27,25 @@ def find_toolchain(ctx):
"""
return ctx.toolchains[Label("//rust:toolchain")]

def find_cc_toolchain(ctx):
"""Extracts a CcToolchain from the current target's context
Args:
ctx (ctx): The current target's rule context object
Returns:
tuple: A tuple of (CcToolchain, FeatureConfiguration)
"""
cc_toolchain = find_rules_cc_toolchain(ctx)

feature_configuration = cc_common.configure_features(
ctx = ctx,
cc_toolchain = cc_toolchain,
requested_features = ctx.features,
unsupported_features = ctx.disabled_features,
)
return cc_toolchain, feature_configuration

# TODO: Replace with bazel-skylib's `path.dirname`. This requires addressing some
# dependency issues or generating docs will break.
def relativize(path, start):
Expand Down

0 comments on commit 8ac6e3a

Please sign in to comment.