diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index c879e5d75c..ba6cef7ac5 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -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") @@ -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: diff --git a/examples/ffi/c_calling_rust/BUILD b/examples/ffi/c_calling_rust/BUILD index e0c644ae9e..b8a6f879ff 100644 --- a/examples/ffi/c_calling_rust/BUILD +++ b/examples/ffi/c_calling_rust/BUILD @@ -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( @@ -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"], ) diff --git a/rust/platform/triple_mappings.bzl b/rust/platform/triple_mappings.bzl index d6f7b3d753..07e91fae60 100644 --- a/rust/platform/triple_mappings.bzl +++ b/rust/platform/triple_mappings.bzl @@ -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] @@ -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: diff --git a/rust/private/clippy.bzl b/rust/private/clippy.bzl index b5162d6dd0..f8a11ddf93 100644 --- a/rust/private/clippy.bzl +++ b/rust/private/clippy.bzl @@ -18,6 +18,7 @@ load( "collect_deps", "collect_inputs", "construct_arguments", + "get_cc_toolchain", ) load( "@io_bazel_rules_rust//rust:private/rust.bzl", @@ -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)), diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 9595a1537d..f41e63e2c2 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -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( @@ -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, @@ -290,6 +296,8 @@ def construct_arguments( file, toolchain, tool_path, + cc_toolchain, + feature_configuration, crate_info, dep_info, output_hash, @@ -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") @@ -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, @@ -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( @@ -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)) diff --git a/rust/repositories.bzl b/rust/repositories.bzl index 1860a4880b..5b7e729119 100644 --- a/rust/repositories.bzl +++ b/rust/repositories.bzl @@ -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") @@ -181,7 +181,8 @@ 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: @@ -189,9 +190,12 @@ def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple, d 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( @@ -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}", @@ -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, @@ -378,6 +384,11 @@ 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, @@ -385,6 +396,7 @@ def _load_rust_stdlib(ctx, 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, ) diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index cb9738b77c..0192733d50 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -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, @@ -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.", @@ -103,6 +108,7 @@ rust_toolchain( binary_ext = "", staticlib_ext = ".a", dylib_ext = ".so", + stdlib_linkflags = ["-lpthread", "-ldl"], os = "linux", )