Skip to content

Export CcInfo for staticlib & cdylib allowing rust outputs to be used in c++ rules #361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cargo/cargo_build_script.bzl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_linker_and_args")
load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_cc_toolchain", "get_linker_and_args")
load("@io_bazel_rules_rust//rust:private/utils.bzl", "find_toolchain")
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
Expand Down Expand Up @@ -41,7 +41,8 @@ def _cargo_build_script_run(ctx, script):

# 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.
_, _, linker_env = get_linker_and_args(ctx, None)
cc_toolchain, feature_configuration = get_cc_toolchain(ctx)
_, _, linker_env = get_linker_and_args(ctx, cc_toolchain, feature_configuration, None)
env.update(**linker_env)

if cc_toolchain:
Expand Down
12 changes: 2 additions & 10 deletions examples/ffi/c_calling_rust/BUILD
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
load("@rules_cc//cc:defs.bzl", "cc_test")
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_library")

rust_library(
Expand All @@ -7,16 +7,8 @@ rust_library(
crate_type = "staticlib",
)

# cc_* rules expect cc_* deps, so we need to wrap our rust staticlib.
cc_library(
name = "wrapper",
srcs = [":rusty"],
# We could link dynamically by setting crate_type to cdylib
linkstatic = True,
)

cc_test(
name = "main",
srcs = ["main.c"],
deps = [":wrapper"],
deps = [":rusty"],
)
44 changes: 44 additions & 0 deletions rust/platform/triple_mappings.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,47 @@ _SYSTEM_TO_DYLIB_EXT = {
"unknown": ".wasm",
}

# See https://github.com/rust-lang/rust/blob/master/src/libstd/build.rs
_SYSTEM_TO_STDLIB_LINKFLAGS = {
# TODO(bazelbuild/rules_cc#75):
#
# Right now bazel cc rules does not specify the exact flag setup needed for calling out system
# libs, that is we dont know given a toolchain if it should be, for example,
# `-lxxx` or `/Lxxx` or `xxx.lib` etc.
#
# We include the flag setup as they are _commonly seen_ on various platforms with a cc_rules
# style override for people doing things like gnu-mingw on windows.
#
# If you are reading this ... sorry! set the env var `BAZEL_RUST_STDLIB_LINKFLAGS` to
# what you need for your specific setup, for example like so
# `BAZEL_RUST_STDLIB_LINKFLAGS="-ladvapi32:-lws2_32:-luserenv"`

"freebsd": ["-lexecinfo", "-lpthread"],
# TODO: This ignores musl. Longer term what does Bazel think about musl?
"linux": ["-ldl", "-lpthread"],
"darwin": ["-lSystem", "-lresolv"],
"uwp": ["ws2_32.lib"],
"windows": ["advapi32.lib", "ws2_32.lib", "userenv.lib"],
"ios": ["-lSystem", "-lobjc", "-framework Security", "-framework Foundation", "-lresolv"],
# NOTE: Rust stdlib `build.rs` treats android as a subset of linux, rust rules treat android
# as its own system.
"android": ["-ldl", "-llog", "-lgcc"],
"emscripten": [],
"nacl": [],
"bitrig": [],
"dragonfly": ["-lpthread"],
"netbsd": ["-lpthread", "-lrt"],
"openbsd": ["-lpthread"],
"solaris": ["-lsocket", "-lposix4", "-lpthread", "-lresolv"],
"illumos": ["-lsocket", "-lposix4", "-lpthread", "-lresolv", "-lnsl", "-lumem"],
"fuchsia": ["-lzircon", "-lfdio"],
# TODO(gregbowyer): If rust stdlib is compiled for cloudabi with the backtrace feature it
# includes `-lunwind` but this might not actually be required.
# I am not sure which is the common configuration or how we encode it as a link flag.
"cloudabi": ["-lunwind", "-lc", "-lcompiler_rt"],
"unknown": [],
}

def cpu_arch_to_constraints(cpu_arch):
plat_suffix = _CPU_ARCH_TO_BUILTIN_PLAT_SUFFIX[cpu_arch]

Expand Down Expand Up @@ -113,6 +154,9 @@ def system_to_staticlib_ext(system):
def system_to_binary_ext(system):
return _SYSTEM_TO_BINARY_EXT[system]

def system_to_stdlib_linkflags(system):
return _SYSTEM_TO_STDLIB_LINKFLAGS[system]

def triple_to_constraint_set(triple):
component_parts = triple.split("-")
if len(component_parts) < 3:
Expand Down
5 changes: 5 additions & 0 deletions rust/private/clippy.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ load(
"collect_deps",
"collect_inputs",
"construct_arguments",
"get_cc_toolchain",
)
load(
"@io_bazel_rules_rust//rust:private/rust.bzl",
Expand Down Expand Up @@ -73,11 +74,15 @@ 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,
toolchain,
toolchain.clippy_driver.path,
cc_toolchain,
feature_configuration,
crate_info,
dep_info,
output_hash = repr(hash(root.path)),
Expand Down
66 changes: 57 additions & 9 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -197,14 +197,9 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain):
build_info,
)

def get_linker_and_args(ctx, rpaths):
if (len(BAZEL_VERSION) == 0 or
versions.is_at_least("0.18.0", BAZEL_VERSION)):
user_link_flags = ctx.fragments.cpp.linkopts
else:
user_link_flags = depset(ctx.fragments.cpp.linkopts)

def get_cc_toolchain(ctx):
cc_toolchain = find_cpp_toolchain(ctx)

kwargs = {
"ctx": ctx,
} if len(BAZEL_VERSION) == 0 or versions.is_at_least(
Expand All @@ -217,6 +212,17 @@ def get_linker_and_args(ctx, rpaths):
unsupported_features = ctx.disabled_features,
**kwargs
)
return cc_toolchain, feature_configuration

def get_cc_user_link_flags(ctx):
if (len(BAZEL_VERSION) == 0 or
versions.is_at_least("0.18.0", BAZEL_VERSION)):
return ctx.fragments.cpp.linkopts
else:
return depset(ctx.fragments.cpp.linkopts)

def get_linker_and_args(ctx, cc_toolchain, feature_configuration, rpaths):
user_link_flags = get_cc_user_link_flags(ctx)
link_variables = cc_common.create_link_variables(
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
Expand Down Expand Up @@ -290,6 +296,8 @@ def construct_arguments(
file,
toolchain,
tool_path,
cc_toolchain,
feature_configuration,
crate_info,
dep_info,
output_hash,
Expand Down Expand Up @@ -392,7 +400,7 @@ def construct_arguments(
# linker since it won't understand.
if toolchain.target_arch != "wasm32":
rpaths = _compute_rpaths(toolchain, output_dir, dep_info)
ld, link_args, link_env = get_linker_and_args(ctx, rpaths)
ld, link_args, link_env = get_linker_and_args(ctx, cc_toolchain, feature_configuration, rpaths)
env.update(link_env)
args.add("--codegen=linker=" + ld)
args.add_joined("--codegen", link_args, join_with = " ", format_joined = "link-args=%s")
Expand Down Expand Up @@ -449,11 +457,15 @@ def rustc_compile_action(
build_info,
)

cc_toolchain, feature_configuration = get_cc_toolchain(ctx)

args, env = construct_arguments(
ctx,
ctx.file,
toolchain,
toolchain.rustc.path,
cc_toolchain,
feature_configuration,
crate_info,
dep_info,
output_hash,
Expand Down Expand Up @@ -493,7 +505,7 @@ def rustc_compile_action(
if hasattr(ctx.attr, "out_binary"):
out_binary = getattr(ctx.attr, "out_binary")

return [
return establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configuration) + [
crate_info,
dep_info,
DefaultInfo(
Expand All @@ -504,6 +516,42 @@ def rustc_compile_action(
),
]

def establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configuration):
""" If the produced crate is suitable yield a CcInfo to allow for interop with cc rules """

if crate_info.type not in ("staticlib", "cdylib"):
return []

if crate_info.type == "staticlib":
library_to_link = cc_common.create_library_to_link(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
static_library = crate_info.output,
)
elif crate_info.type == "cdylib":
library_to_link = cc_common.create_library_to_link(
actions = ctx.actions,
feature_configuration = feature_configuration,
cc_toolchain = cc_toolchain,
dynamic_library = crate_info.output,
)

link_input = cc_common.create_linker_input(
owner = ctx.label,
libraries = depset([library_to_link]),
user_link_flags = depset(toolchain.stdlib_linkflags),
)

linking_context = cc_common.create_linking_context(
# TODO - What to do for no_std?
linker_inputs = depset([link_input]),
)

cc_infos = [dep[CcInfo] for dep in ctx.attr.deps]
cc_infos.append(CcInfo(linking_context = linking_context))

return [cc_common.merge_cc_infos(cc_infos = cc_infos)]
def add_edition_flags(args, crate):
if crate.edition != "2015":
args.add("--edition={}".format(crate.edition))
Expand Down
16 changes: 14 additions & 2 deletions rust/repositories.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
load(":known_shas.bzl", "FILE_KEY_TO_SHA")
load("//rust/platform:triple_mappings.bzl", "system_to_binary_ext", "system_to_dylib_ext", "system_to_staticlib_ext", "triple_to_constraint_set", "triple_to_system")
load("//rust/platform:triple_mappings.bzl", "system_to_binary_ext", "system_to_dylib_ext", "system_to_staticlib_ext", "system_to_stdlib_linkflags", "triple_to_constraint_set", "triple_to_system")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

Expand Down Expand Up @@ -181,17 +181,21 @@ filegroup(
target_triple = target_triple,
)

def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple, default_edition = "2015"):
def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple,
stdlib_linkflags=None, default_edition = "2015"):
"""Emits a toolchain declaration to match an existing compiler and stdlib.

Args:
workspace_name: The name of the workspace that this toolchain resides in
name: The name of the toolchain declaration
exec_triple: The rust-style target that this compiler runs on
target_triple: The rust-style target triple of the tool
stdlib_linkflags: Overriden flags needed for linking to rust stdlib, akin to BAZEL_LINKLIBS
"""

system = triple_to_system(target_triple)
if stdlib_linkflags == None:
stdlib_linkflags = ", ".join(['"%s"' % x for x in system_to_stdlib_linkflags(system)])

return """
rust_toolchain(
Expand All @@ -205,6 +209,7 @@ rust_toolchain(
binary_ext = "{binary_ext}",
staticlib_ext = "{staticlib_ext}",
dylib_ext = "{dylib_ext}",
stdlib_linkflags = [{stdlib_linkflags}],
os = "{system}",
default_edition = "{default_edition}",
exec_triple = "{exec_triple}",
Expand All @@ -217,6 +222,7 @@ rust_toolchain(
binary_ext = system_to_binary_ext(system),
staticlib_ext = system_to_staticlib_ext(system),
dylib_ext = system_to_dylib_ext(system),
stdlib_linkflags = stdlib_linkflags,
system = system,
default_edition = default_edition,
exec_triple = exec_triple,
Expand Down Expand Up @@ -378,13 +384,19 @@ def _load_rust_stdlib(ctx, target_triple):

toolchain_prefix = ctx.attr.toolchain_name_prefix or DEFAULT_TOOLCHAIN_NAME_PREFIX
stdlib_BUILD = BUILD_for_stdlib(target_triple)

stdlib_linkflags = None
if 'BAZEL_RUST_STDLIB_LINKFLAGS' in ctx.os.environ:
stdlib_linkflags = ctx.os.environ['BAZEL_RUST_STDLIB_LINKFLAGS'].split(':')

toolchain_BUILD = BUILD_for_rust_toolchain(
name = "{toolchain_prefix}_{target_triple}".format(
toolchain_prefix = toolchain_prefix,
target_triple = target_triple,
),
exec_triple = ctx.attr.exec_triple,
target_triple = target_triple,
stdlib_linkflags = stdlib_linkflags,
workspace_name = ctx.attr.name,
default_edition = ctx.attr.edition,
)
Expand Down
6 changes: 6 additions & 0 deletions rust/toolchain.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def _rust_toolchain_impl(ctx):
binary_ext = ctx.attr.binary_ext,
staticlib_ext = ctx.attr.staticlib_ext,
dylib_ext = ctx.attr.dylib_ext,
stdlib_linkflags = ctx.attr.stdlib_linkflags,
target_triple = ctx.attr.target_triple,
exec_triple = ctx.attr.exec_triple,
os = ctx.attr.os,
Expand Down Expand Up @@ -60,6 +61,10 @@ rust_toolchain = rule(
"binary_ext": attr.string(mandatory = True),
"staticlib_ext": attr.string(mandatory = True),
"dylib_ext": attr.string(mandatory = True),
"stdlib_linkflags": attr.string_list(
doc = """Additional linker libs used when std lib is linked,
see https://github.com/rust-lang/rust/blob/master/src/libstd/build.rs""",
mandatory = True),
"os": attr.string(mandatory = True),
"default_edition": attr.string(
doc = "The edition to use for rust_* rules that don't specify an edition.",
Expand Down Expand Up @@ -103,6 +108,7 @@ rust_toolchain(
binary_ext = "",
staticlib_ext = ".a",
dylib_ext = ".so",
stdlib_linkflags = ["-lpthread", "-ldl"],
os = "linux",
)

Expand Down