diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index d47ba576fa..cee2916959 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -31,6 +31,7 @@ tasks: # Skip tests for dylib support on osx, since we don't support it yet. - "-@examples//ffi/rust_calling_c:matrix_dylib_test" - "-@examples//ffi/rust_calling_c:matrix_dynamically_linked" + - "-@examples//ffi/rust_calling_cc:matrix_dynamically_linked" - "-@examples//ffi/rust_calling_c/simple/..." build_targets: *osx_targets test_targets: *osx_targets @@ -56,6 +57,7 @@ tasks: - "@examples//..." - "-@examples//ffi/rust_calling_c:matrix_dylib_test" - "-@examples//ffi/rust_calling_c:matrix_dynamically_linked" + - "-@examples//ffi/rust_calling_cc:matrix_dynamically_linked" - "-@examples//ffi/rust_calling_c/simple/..." - "-@examples//hello_sys/..." - "-@examples//complex_sys/..." diff --git a/bindgen/bindgen.bzl b/bindgen/bindgen.bzl index afcf8d5757..e1c29115be 100644 --- a/bindgen/bindgen.bzl +++ b/bindgen/bindgen.bzl @@ -13,7 +13,7 @@ # limitations under the License. # buildifier: disable=module-docstring -load("//rust:private/utils.bzl", "find_toolchain", "get_libs_for_static_executable") +load("//rust:private/utils.bzl", "find_cc_toolchain", "find_toolchain", "get_libs_for_static_executable") load("//rust:rust.bzl", "rust_library") def rust_bindgen_library( @@ -53,6 +53,7 @@ def rust_bindgen_library( def _rust_bindgen_impl(ctx): rust_toolchain = find_toolchain(ctx) + cc_toolchain, feature_configuration = find_cc_toolchain(ctx) # nb. We can't grab the cc_library`s direct headers, so a header must be provided. cc_lib = ctx.attr.cc_lib @@ -82,7 +83,7 @@ def _rust_bindgen_impl(ctx): output = ctx.outputs.out # libclang should only have 1 output file - libclang_dir = get_libs_for_static_executable(libclang).to_list()[0].dirname + libclang_dir = get_libs_for_static_executable(libclang, cc_toolchain, feature_configuration).to_list()[0].dirname include_directories = cc_lib[CcInfo].compilation_context.includes.to_list() quote_include_directories = cc_lib[CcInfo].compilation_context.quote_includes.to_list() system_include_directories = cc_lib[CcInfo].compilation_context.system_includes.to_list() @@ -110,7 +111,7 @@ def _rust_bindgen_impl(ctx): } if libstdcxx: - env["LD_LIBRARY_PATH"] = ":".join([f.dirname for f in get_libs_for_static_executable(libstdcxx).to_list()]) + env["LD_LIBRARY_PATH"] = ":".join([f.dirname for f in get_libs_for_static_executable(libstdcxx, cc_toolchain, feature_configuration).to_list()]) ctx.actions.run( executable = bindgen_bin, @@ -118,9 +119,9 @@ def _rust_bindgen_impl(ctx): [header], transitive = [ cc_lib[CcInfo].compilation_context.headers, - get_libs_for_static_executable(libclang), + get_libs_for_static_executable(libclang, cc_toolchain, feature_configuration), ] + [ - get_libs_for_static_executable(libstdcxx), + get_libs_for_static_executable(libstdcxx, cc_toolchain, feature_configuration), ] if libstdcxx else [], ), outputs = [unformatted_output], @@ -173,11 +174,16 @@ rust_bindgen = rule( allow_single_file = True, cfg = "exec", ), + "_cc_toolchain": attr.label( + default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"), + ), }, outputs = {"out": "%{name}.rs"}, + fragments = ["cpp"], toolchains = [ str(Label("//bindgen:bindgen_toolchain")), str(Label("//rust:toolchain")), + "@bazel_tools//tools/cpp:toolchain_type", ], ) diff --git a/cargo/cargo_build_script.bzl b/cargo/cargo_build_script.bzl index efde91e28d..9b880c5bdf 100644 --- a/cargo/cargo_build_script.bzl +++ b/cargo/cargo_build_script.bzl @@ -1,9 +1,8 @@ # buildifier: disable=module-docstring load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "C_COMPILE_ACTION_NAME") -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain") load("//rust:private/rust.bzl", "name_to_crate_name") -load("//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_cc_toolchain", "get_compilation_mode_opts", "get_linker_and_args") -load("//rust:private/utils.bzl", "expand_locations", "find_toolchain") +load("//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_linker_and_args") +load("//rust:private/utils.bzl", "expand_locations", "find_toolchain", "find_cc_toolchain") load("//rust:rust.bzl", "rust_binary") def get_cc_compile_env(cc_toolchain, feature_configuration): @@ -65,7 +64,7 @@ def _build_script_impl(ctx): toolchain.rust_lib.files, ] - cc_toolchain = find_cpp_toolchain(ctx) + cc_toolchain, feature_configuration = find_cc_toolchain(ctx) # Start with the default shell env, which contains any --action_env # settings passed in on the command line. @@ -92,7 +91,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) diff --git a/examples/ffi/rust_calling_cc/BUILD b/examples/ffi/rust_calling_cc/BUILD new file mode 100644 index 0000000000..ac8265301c --- /dev/null +++ b/examples/ffi/rust_calling_cc/BUILD @@ -0,0 +1,26 @@ +load("@rules_rust//rust:rust.bzl", "rust_binary") + +package(default_visibility = ["//ffi/rust_calling_cc:__subpackages__"]) + +rust_binary( + name = "matrix", + srcs = [ + "src/ffi.rs", + "src/matrix.rs", + ], + deps = [ + "//ffi/rust_calling_cc/cc:native_matrix", + ], +) + +rust_binary( + name = "matrix_dynamically_linked", + srcs = [ + "src/ffi.rs", + "src/matrix.rs", + ], + crate_root = "src/matrix.rs", + deps = [ + "//ffi/rust_calling_cc/cc:native_matrix_so", + ], +) diff --git a/examples/ffi/rust_calling_cc/cc/BUILD b/examples/ffi/rust_calling_cc/cc/BUILD new file mode 100644 index 0000000000..0e4c1011d7 --- /dev/null +++ b/examples/ffi/rust_calling_cc/cc/BUILD @@ -0,0 +1,31 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_import", "cc_library", "cc_test") + +package(default_visibility = ["//ffi/rust_calling_cc:__subpackages__"]) + +cc_library( + name = "native_matrix", + srcs = ["matrix.cc"], + hdrs = ["matrix.h"], +) + +cc_test( + name = "native_matrix_test", + srcs = ["matrix_test.cc"], + deps = [ + ":native_matrix", + ], +) + +## Do the same as above, but with a dynamic c library. + +cc_import( + name = "native_matrix_so", + hdrs = ["matrix.h"], + shared_library = ":libnative_matrix_so.so", +) + +cc_binary( + name = "libnative_matrix_so.so", + srcs = ["matrix.cc", "matrix.h"], + linkshared = True, +) diff --git a/examples/ffi/rust_calling_cc/cc/matrix.cc b/examples/ffi/rust_calling_cc/cc/matrix.cc new file mode 100644 index 0000000000..b00b4ef59f --- /dev/null +++ b/examples/ffi/rust_calling_cc/cc/matrix.cc @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +#include "ffi/rust_calling_cc/cc/matrix.h" + +#include + +extern "C" void print_matrix() { + std::cout << "1 2 3" << std::endl; + std::cout << "4 5 6" << std::endl; + std::cout << "7 8 9" << std::endl; +} \ No newline at end of file diff --git a/examples/ffi/rust_calling_cc/cc/matrix.h b/examples/ffi/rust_calling_cc/cc/matrix.h new file mode 100644 index 0000000000..4ba01f036e --- /dev/null +++ b/examples/ffi/rust_calling_cc/cc/matrix.h @@ -0,0 +1,20 @@ +// Copyright 2017 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. + +#ifndef MATRIX_SRC_MATRIX_H_ +#define MATRIX_SRC_MATRIX_H_ + +extern "C" void print_matrix(); + +#endif // MATRIX_SRC_MATRIX_H_ \ No newline at end of file diff --git a/examples/ffi/rust_calling_cc/cc/matrix_test.cc b/examples/ffi/rust_calling_cc/cc/matrix_test.cc new file mode 100644 index 0000000000..346094e07a --- /dev/null +++ b/examples/ffi/rust_calling_cc/cc/matrix_test.cc @@ -0,0 +1,23 @@ +// Copyright 2017 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. + +#include "ffi/rust_calling_cc/cc/matrix.h" + +#include + + +int main(int argc, char** argv) { + print_matrix(); + return EXIT_SUCCESS; +} diff --git a/examples/ffi/rust_calling_cc/src/ffi.rs b/examples/ffi/rust_calling_cc/src/ffi.rs new file mode 100644 index 0000000000..158ab9a7b0 --- /dev/null +++ b/examples/ffi/rust_calling_cc/src/ffi.rs @@ -0,0 +1,17 @@ +// Copyright 2017 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. + +extern "C" { + pub fn print_matrix(); +} diff --git a/examples/ffi/rust_calling_cc/src/matrix.rs b/examples/ffi/rust_calling_cc/src/matrix.rs new file mode 100644 index 0000000000..3eeccce836 --- /dev/null +++ b/examples/ffi/rust_calling_cc/src/matrix.rs @@ -0,0 +1,18 @@ +// Copyright 2017 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. + +mod ffi; +fn main() { + unsafe { ffi::print_matrix(); } +} \ No newline at end of file diff --git a/rust/private/clippy.bzl b/rust/private/clippy.bzl index 9b661cf235..5fdb5c7495 100644 --- a/rust/private/clippy.bzl +++ b/rust/private/clippy.bzl @@ -19,13 +19,12 @@ load( "collect_deps", "collect_inputs", "construct_arguments", - "get_cc_toolchain", ) load( "//rust:private/rust.bzl", "crate_root_src", ) -load("//rust:private/utils.bzl", "determine_output_hash", "find_toolchain") +load("//rust:private/utils.bzl", "determine_output_hash", "find_toolchain", "find_cc_toolchain") _rust_extensions = [ "rs", @@ -48,6 +47,8 @@ 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[CrateInfo] if crate_info.is_test: @@ -64,6 +65,8 @@ def _clippy_aspect_impl(target, ctx): crate_info.proc_macro_deps, crate_info.aliases, toolchain, + cc_toolchain, + feature_configuration, ) compile_inputs, out_dir, build_env_file, build_flags_files = collect_inputs( @@ -71,6 +74,7 @@ def _clippy_aspect_impl(target, ctx): ctx.rule.file, ctx.rule.files, toolchain, + cc_toolchain, crate_info, dep_info, build_info, @@ -80,8 +84,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, diff --git a/rust/private/rustc.bzl b/rust/private/rustc.bzl index 8d62225c9c..d38811f005 100644 --- a/rust/private/rustc.bzl +++ b/rust/private/rustc.bzl @@ -17,10 +17,10 @@ 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/utils.bzl", "expand_locations", + "find_cc_toolchain", "get_lib_name", "get_libs_for_static_executable", "relativize", @@ -129,7 +129,7 @@ def get_compilation_mode_opts(ctx, toolchain): return toolchain.compilation_mode_opts[comp_mode] -def collect_deps(label, deps, proc_macro_deps, aliases, toolchain): +def collect_deps(label, deps, proc_macro_deps, aliases, toolchain, cc_toolchain, feature_configuration): """Walks through dependencies and collects the transitive dependencies. Args: @@ -138,6 +138,8 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain): 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. toolchain (rust_toolchain): The current `rust_toolchain`. + cc_toolchain (CcToolchainInfo): The current `cc_toolchain`. + feature_configuration (FeatureConfiguration): The current `feature_configuration` to use with `cc_toolchain`. Returns: tuple: Returns a tuple (DepInfo, BuildInfo) of providers. @@ -188,7 +190,7 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain): # This dependency is a cc_library # TODO: We could let the user choose how to link, instead of always preferring to link static libraries. - libs = get_libs_for_static_executable(dep) + libs = get_libs_for_static_executable(dep, cc_toolchain, feature_configuration) transitive_dylibs.append(depset([ lib @@ -231,25 +233,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 @@ -335,16 +318,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. @@ -354,7 +339,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 + @@ -572,12 +557,16 @@ 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, crate_info.proc_macro_deps, crate_info.aliases, toolchain, + cc_toolchain, + feature_configuration, ) compile_inputs, out_dir, build_env_file, build_flags_files = collect_inputs( @@ -585,13 +574,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, diff --git a/rust/private/utils.bzl b/rust/private/utils.bzl index 28c1a30510..451efa3fb7 100644 --- a/rust/private/utils.bzl +++ b/rust/private/utils.bzl @@ -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. @@ -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): @@ -97,17 +118,22 @@ def determine_output_hash(crate_root): """ return repr(hash(crate_root.path)) -def get_libs_for_static_executable(dep): +def get_libs_for_static_executable(dep, cc_toolchain, feature_configuration): """find the libraries used for linking a static executable. Args: dep (Target): A cc_library target. + cc_toolchain (CcToolchainInfo): The current `cc_toolchain`. + feature_configuration (FeatureConfiguration): The current `feature_configuration` to use with `cc_toolchain`. Returns: depset: A depset[File] """ linker_inputs = dep[CcInfo].linking_context.linker_inputs.to_list() - return depset([_get_preferred_artifact(lib) for li in linker_inputs for lib in li.libraries]) + return depset( + [_get_preferred_artifact(lib) for li in linker_inputs for lib in li.libraries], + transitive = [cc_toolchain.static_runtime_lib(feature_configuration = feature_configuration)], + ) def _get_preferred_artifact(library_to_link): """Get the first available library to link from a LibraryToLink object.