diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 0f0bea98da..f101e21b94 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -15,9 +15,12 @@ platforms: - "..." - "@examples//..." macos: - build_targets: - - "..." - - "@examples//..." - test_targets: + targets: &targets + - "--" # Hack for https://github.com/bazelbuild/continuous-integration/pull/245 - "..." + # Skip tests for dylib support on osx, since we don't support it yet. - "@examples//..." + - "-@examples//ffi/rust_calling_c:matrix_dylib_test" + - "-@examples//ffi/rust_calling_c:matrix_dynamically_linked" + build_targets: *targets + test_targets: *targets \ No newline at end of file diff --git a/examples/ffi/rust_calling_c/BUILD b/examples/ffi/rust_calling_c/BUILD new file mode 100644 index 0000000000..394cd7a7ad --- /dev/null +++ b/examples/ffi/rust_calling_c/BUILD @@ -0,0 +1,41 @@ +package(default_visibility = ["//ffi/rust_calling_c:__subpackages__"]) + +load("@//rust:rust.bzl", "rust_library", "rust_test", "rust_binary") + +rust_library( + name = "matrix", + srcs = [ + "src/ffi.rs", + "src/lib.rs", + "src/matrix.rs", + ], + deps = [ + "//ffi/rust_calling_c/c:native_matrix", + "@libc//:libc", + ], +) + +rust_test( + name = "matrix_test", + deps = [":matrix"], +) + +## Do the same as above, but with a dynamic c library. + +rust_library( + name = "matrix_dynamically_linked", + srcs = [ + "src/ffi.rs", + "src/lib.rs", + "src/matrix.rs", + ], + deps = [ + "//ffi/rust_calling_c/c:native_matrix_so", + "@libc//:libc", + ], +) + +rust_test( + name = "matrix_dylib_test", + deps = [":matrix_dynamically_linked"], +) diff --git a/examples/ffi/rust_calling_c/c/BUILD b/examples/ffi/rust_calling_c/c/BUILD new file mode 100644 index 0000000000..71fd21047e --- /dev/null +++ b/examples/ffi/rust_calling_c/c/BUILD @@ -0,0 +1,35 @@ +package(default_visibility = ["//ffi/rust_calling_c:__subpackages__"]) + +cc_library( + name = "native_matrix", + srcs = ["matrix.c"], + hdrs = ["matrix.h"], + copts = ["-std=c99"], +) + +cc_test( + name = "native_matrix_test", + srcs = ["matrix_test.c"], + copts = ["-std=c99"], + deps = [ + ":native_matrix", + ], +) + +## Do the same as above, but with a dynamic c library. + +cc_library( + name = "native_matrix_so", + srcs = [":libnative_matrix_so.so"], + hdrs = ["matrix.h"], +) + +cc_binary( + name = "libnative_matrix_so.so", + srcs = [ + "matrix.c", + "matrix.h", + ], + copts = ["-std=c99"], + linkshared = True, +) diff --git a/examples/matrix/src/matrix.c b/examples/ffi/rust_calling_c/c/matrix.c similarity index 98% rename from examples/matrix/src/matrix.c rename to examples/ffi/rust_calling_c/c/matrix.c index 637fd7078b..343be4ffff 100644 --- a/examples/matrix/src/matrix.c +++ b/examples/ffi/rust_calling_c/c/matrix.c @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "matrix/src/matrix.h" +#include "ffi/rust_calling_c/c/matrix.h" #include #include diff --git a/examples/matrix/src/matrix.h b/examples/ffi/rust_calling_c/c/matrix.h similarity index 100% rename from examples/matrix/src/matrix.h rename to examples/ffi/rust_calling_c/c/matrix.h diff --git a/examples/matrix/src/matrix_test.c b/examples/ffi/rust_calling_c/c/matrix_test.c similarity index 98% rename from examples/matrix/src/matrix_test.c rename to examples/ffi/rust_calling_c/c/matrix_test.c index f1752e9ceb..adeade4b4e 100644 --- a/examples/matrix/src/matrix_test.c +++ b/examples/ffi/rust_calling_c/c/matrix_test.c @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "matrix/src/matrix.h" +#include "ffi/rust_calling_c/c/matrix.h" #include #include diff --git a/examples/matrix/src/ffi.rs b/examples/ffi/rust_calling_c/src/ffi.rs similarity index 93% rename from examples/matrix/src/ffi.rs rename to examples/ffi/rust_calling_c/src/ffi.rs index a990c8e84d..02a7b4c8de 100644 --- a/examples/matrix/src/ffi.rs +++ b/examples/ffi/rust_calling_c/src/ffi.rs @@ -24,7 +24,7 @@ pub struct Matrix { pub data: *mut uint64_t, } -#[link(name = "native_matrix")] +// #[link(name = "native_matrix")] // Don't need this, BUILD file manages linking already. extern { pub fn matrix_new(rows: size_t, cols: size_t, data: *const uint64_t) -> *mut Matrix; pub fn matrix_at(matrix: *const Matrix, row: size_t, col: size_t, n: *mut uint64_t) -> c_int; diff --git a/examples/matrix/src/lib.rs b/examples/ffi/rust_calling_c/src/lib.rs similarity index 97% rename from examples/matrix/src/lib.rs rename to examples/ffi/rust_calling_c/src/lib.rs index ca92797c4f..87923ea86f 100644 --- a/examples/matrix/src/lib.rs +++ b/examples/ffi/rust_calling_c/src/lib.rs @@ -16,4 +16,4 @@ extern crate libc; mod ffi; -pub mod matrix; +pub mod matrix; \ No newline at end of file diff --git a/examples/matrix/src/matrix.rs b/examples/ffi/rust_calling_c/src/matrix.rs similarity index 97% rename from examples/matrix/src/matrix.rs rename to examples/ffi/rust_calling_c/src/matrix.rs index 77a76a2bce..02e815aded 100644 --- a/examples/matrix/src/matrix.rs +++ b/examples/ffi/rust_calling_c/src/matrix.rs @@ -18,7 +18,7 @@ use std::ptr; /// Wrapper around pointer to FFI Matrix struct. pub struct Matrix { - pub matrix: *mut ffi::Matrix, + matrix: *mut ffi::Matrix, } /// Wrapper around low-level FFI Matrix API. @@ -38,7 +38,7 @@ impl Matrix { let mut data_copy: Vec = vec![0; data.len()]; data_copy.clone_from_slice(data); unsafe { - let mut matrix: *mut ffi::Matrix = ffi::matrix_new(rows, cols, data_copy.as_ptr()); + let matrix: *mut ffi::Matrix = ffi::matrix_new(rows, cols, data_copy.as_ptr()); if matrix.is_null() { panic!("Failed to allocate Matrix."); } diff --git a/examples/matrix/BUILD b/examples/matrix/BUILD deleted file mode 100644 index 17de43e955..0000000000 --- a/examples/matrix/BUILD +++ /dev/null @@ -1,37 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -load("@//rust:rust.bzl", "rust_library", "rust_test") - -cc_library( - name = "native_matrix", - srcs = ["src/matrix.c"], - hdrs = ["src/matrix.h"], - copts = ["-std=c99"], -) - -cc_test( - name = "native_matrix_test", - srcs = ["src/matrix_test.c"], - copts = ["-std=c99"], - deps = [ - ":native_matrix", - ], -) - -rust_library( - name = "matrix", - srcs = [ - "src/ffi.rs", - "src/lib.rs", - "src/matrix.rs", - ], - deps = [ - ":native_matrix", - "@libc//:libc", - ], -) - -rust_test( - name = "matrix_test", - deps = [":matrix"], -) diff --git a/rust/repositories.bzl b/rust/repositories.bzl index 5e39308a19..ccb71f7d7f 100644 --- a/rust/repositories.bzl +++ b/rust/repositories.bzl @@ -124,6 +124,7 @@ rust_toolchain( rustc_lib = ["@rust_linux_x86_64//:rustc_lib"], staticlib_ext = ".a", dylib_ext = ".so", + os = "linux", visibility = ["//visibility:public"], ) @@ -149,6 +150,7 @@ rust_toolchain( rustc_lib = ["@rust_darwin_x86_64//:rustc_lib"], staticlib_ext = ".a", dylib_ext = ".dylib", + os = "mac os x", visibility = ["//visibility:public"], ) @@ -174,6 +176,7 @@ rust_toolchain( rustc_lib = ["@rust_freebsd_x86_64//:rustc_lib"], staticlib_ext = ".a", dylib_ext = ".so", + os = "freebsd", visibility = ["//visibility:public"], ) """ diff --git a/rust/rust.bzl b/rust/rust.bzl index cf79786253..d6bee8896a 100644 --- a/rust/rust.bzl +++ b/rust/rust.bzl @@ -49,12 +49,12 @@ rust_repositories() [Cargo](https://crates.io/). """ -load(":toolchain.bzl", "build_rustc_command", "build_rustdoc_command", "build_rustdoc_test_command") +load(":toolchain.bzl", "build_rustc_command", "build_rustdoc_command", + "build_rustdoc_test_command") +load(":utils.bzl", "relative_path") RUST_FILETYPE = FileType([".rs"]) -A_FILETYPE = FileType([".a"]) - # Used by rust_doc HTML_MD_FILETYPE = FileType([ ".html", @@ -63,38 +63,12 @@ HTML_MD_FILETYPE = FileType([ CSS_FILETYPE = FileType([".css"]) -def _path_parts(path): - """Takes a path and returns a list of its parts with all "." elements removed. - - The main use case of this function is if one of the inputs to _relative() - is a relative path, such as "./foo". - - Args: - path_parts: A list containing parts of a path. - - Returns: - Returns a list containing the path parts with all "." elements removed. - """ - path_parts = path.split("/") - return [part for part in path_parts if part != "."] - -def _relative(src_path, dest_path): - """Returns the relative path from src_path to dest_path.""" - src_parts = _path_parts(src_path) - dest_parts = _path_parts(dest_path) - n = 0 - done = False - for src_part, dest_part in zip(src_parts, dest_parts): - if src_part != dest_part: - break - n += 1 - - relative_path = "" - for i in range(n, len(src_parts)): - relative_path += "../" - relative_path += "/".join(dest_parts[n:]) - - return relative_path +def _get_lib_name(lib): + """Returns the name of a library artifact, eg. libabc.a -> abc""" + libname, ext = lib.basename.split(".", 2) + if not libname.startswith("lib"): + fail("Expected {} to start with 'lib' prefix.".format(lib)) + return libname[3:] def _create_setup_cmd(lib, deps_dir, in_runfiles): """ @@ -103,7 +77,7 @@ def _create_setup_cmd(lib, deps_dir, in_runfiles): """ lib_path = lib.short_path if in_runfiles else lib.path return ( - "ln -sf " + _relative(deps_dir, lib_path) + " " + + "ln -sf " + relative_path(deps_dir, lib_path) + " " + deps_dir + "/" + lib.basename + "\n" ) @@ -116,7 +90,8 @@ def _out_dir_setup_cmd(out_dir_tar): else: return [] -def _setup_deps(deps, name, working_dir, allow_cc_deps=False, +def _setup_deps(deps, name, working_dir, toolchain, + allow_cc_deps=False, in_runfiles=False): """ Walks through dependencies and constructs the necessary commands for linking @@ -134,8 +109,10 @@ def _setup_deps(deps, name, working_dir, allow_cc_deps=False, Returns: Returns a struct containing the following fields: - libs: - transitive_libs: + transitive_rlibs: + transitive_dylibs: + transitive_staticlibs: + transitive_libs: All transitive dependencies, not filtered by type. setup_cmd: search_flags: link_flags: @@ -143,59 +120,60 @@ def _setup_deps(deps, name, working_dir, allow_cc_deps=False, deps_dir = working_dir + "/" + name + ".deps" setup_cmd = ["rm -rf " + deps_dir + "; mkdir " + deps_dir + "\n"] - has_rlib = False - has_native = False + staticlib_filetype = FileType([toolchain.staticlib_ext]) + dylib_filetype = FileType([toolchain.dylib_ext]) - libs = depset() - transitive_libs = depset() - symlinked_libs = depset() link_flags = [] + transitive_rlibs = depset() + transitive_dylibs = depset(order="topological") # dylib link flag ordering matters. + transitive_staticlibs = depset() for dep in deps: if hasattr(dep, "rust_lib"): # This dependency is a rust_library - libs += [dep.rust_lib] - transitive_libs += [dep.rust_lib] + dep.transitive_libs - symlinked_libs += [dep.rust_lib] + dep.transitive_libs - link_flags += [( - "--extern " + dep.label.name + "=" + - deps_dir + "/" + dep.rust_lib.basename - )] - has_rlib = True + transitive_rlibs += [dep.rust_lib] + transitive_rlibs += dep.transitive_rlibs + transitive_dylibs += dep.transitive_dylibs + transitive_staticlibs += dep.transitive_staticlibs + link_flags += ["--extern " + dep.label.name + "=" + deps_dir + "/" + dep.rust_lib.basename] elif hasattr(dep, "cc"): + # This dependency is a cc_library if not allow_cc_deps: fail("Only rust_library, rust_binary, and rust_test targets can " + "depend on cc_library") - # This dependency is a cc_library - native_libs = A_FILETYPE.filter(dep.cc.libs) - libs += native_libs - transitive_libs += native_libs - symlinked_libs += native_libs - link_flags += ["-l static=" + dep.label.name] - has_native = True + transitive_dylibs += dylib_filetype.filter(dep.cc.libs) + transitive_staticlibs += staticlib_filetype.filter(dep.cc.libs) else: fail("rust_library, rust_binary and rust_test targets can only depend " + "on rust_library or cc_library targets.") - for symlinked_lib in symlinked_libs: - setup_cmd += [_create_setup_cmd(symlinked_lib, deps_dir, in_runfiles)] + link_flags += ["-l static=" + _get_lib_name(lib) for lib in transitive_staticlibs.to_list()] + link_flags += ["-l dylib=" + _get_lib_name(lib) for lib in transitive_dylibs.to_list()] search_flags = [] - if has_rlib: + if transitive_rlibs: search_flags += ["-L dependency=%s" % deps_dir] - if has_native: + if transitive_dylibs or transitive_staticlibs: search_flags += ["-L native=%s" % deps_dir] + # Create symlinks pointing to each transitive lib in deps_dir. + transitive_libs = transitive_rlibs + transitive_staticlibs + transitive_dylibs + for transitive_lib in transitive_libs: + setup_cmd += [_create_setup_cmd(transitive_lib, deps_dir, in_runfiles)] + return struct( - libs = list(libs), transitive_libs = list(transitive_libs), + transitive_rlibs = transitive_rlibs, + transitive_dylibs = transitive_dylibs, + transitive_staticlibs = transitive_staticlibs, setup_cmd = setup_cmd, search_flags = search_flags, link_flags = link_flags) def _find_toolchain(ctx): + """Finds the first rust toolchain that is configured.""" return ctx.toolchains["@io_bazel_rules_rust//rust:toolchain"] def _find_crate_root_src(srcs, file_names=["lib.rs"]): @@ -264,6 +242,7 @@ def _rust_library_impl(ctx): depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, output_dir, + toolchain, allow_cc_deps=True) # Build rustc command @@ -281,7 +260,6 @@ def _rust_library_impl(ctx): compile_inputs = ( ctx.files.srcs + ctx.files.data + - depinfo.libs + depinfo.transitive_libs + [toolchain.rustc] + toolchain.rustc_lib + @@ -306,7 +284,9 @@ def _rust_library_impl(ctx): crate_root = lib_rs, rust_srcs = ctx.files.srcs, rust_deps = ctx.attr.deps, - transitive_libs = depinfo.transitive_libs, + transitive_rlibs = depinfo.transitive_rlibs, + transitive_dylibs = depinfo.transitive_dylibs, + transitive_staticlibs = depinfo.transitive_staticlibs, rust_lib = rust_lib) def _rust_binary_impl(ctx): @@ -319,14 +299,15 @@ def _rust_binary_impl(ctx): rust_binary = ctx.outputs.executable output_dir = rust_binary.dirname + toolchain = _find_toolchain(ctx) # Dependencies depinfo = _setup_deps(ctx.attr.deps, ctx.label.name, output_dir, + toolchain, allow_cc_deps=True) # Build rustc command. - toolchain = _find_toolchain(ctx) cmd = build_rustc_command(ctx = ctx, toolchain = toolchain, crate_name = ctx.label.name, @@ -339,7 +320,6 @@ def _rust_binary_impl(ctx): compile_inputs = ( ctx.files.srcs + ctx.files.data + - depinfo.libs + depinfo.transitive_libs + [toolchain.rustc] + toolchain.rustc_lib + @@ -358,7 +338,9 @@ def _rust_binary_impl(ctx): progress_message = ("Compiling Rust binary %s (%d files)" % (ctx.label.name, len(ctx.files.srcs)))) - runfiles = ctx.runfiles(files = ctx.files.data, collect_data = True) + runfiles = ctx.runfiles( + files = depinfo.transitive_dylibs.to_list() + ctx.files.data, + collect_data = True) return struct(rust_srcs = ctx.files.srcs, crate_root = main_rs, @@ -392,13 +374,15 @@ def _rust_test_common(ctx, test_binary): crate_root = _crate_root_src(ctx), crate_type = "lib") + toolchain = _find_toolchain(ctx) + # Get information about dependencies depinfo = _setup_deps(target.deps, target.name, output_dir, + toolchain, allow_cc_deps=True) - toolchain = _find_toolchain(ctx) cmd = build_rustc_command(ctx = ctx, toolchain = toolchain, crate_name = test_binary.basename, @@ -410,7 +394,6 @@ def _rust_test_common(ctx, test_binary): compile_inputs = (target.srcs + ctx.files.data + - depinfo.libs + depinfo.transitive_libs + [toolchain.rustc] + toolchain.rustc_lib + @@ -428,14 +411,18 @@ def _rust_test_common(ctx, test_binary): use_default_shell_env = True, progress_message = ("Compiling Rust test %s (%d files)" % (ctx.label.name, len(target.srcs)))) + return depinfo def _rust_test_impl(ctx): """ Implementation for rust_test Skylark rule. """ - _rust_test_common(ctx, ctx.outputs.executable) + depinfo = _rust_test_common(ctx, ctx.outputs.executable) + + runfiles = ctx.runfiles( + files = depinfo.transitive_dylibs.to_list() + ctx.files.data, + collect_data = True) - runfiles = ctx.runfiles(files = ctx.files.data, collect_data = True) return struct(runfiles = runfiles) def _rust_bench_test_impl(ctx): @@ -443,7 +430,7 @@ def _rust_bench_test_impl(ctx): rust_bench_test = ctx.outputs.executable test_binary = ctx.new_file(ctx.configuration.bin_dir, "%s_bin" % rust_bench_test.basename) - _rust_test_common(ctx, test_binary) + depinfo = _rust_test_common(ctx, test_binary) ctx.file_action( output = rust_bench_test, @@ -453,7 +440,10 @@ def _rust_bench_test_impl(ctx): "%s --bench\n" % test_binary.short_path]), executable = True) - runfiles = ctx.runfiles(files = [test_binary], collect_data = True) + runfiles = ctx.runfiles( + files = depinfo.transitive_dylibs.to_list() + [test_binary], + collect_data = True) + return struct(runfiles = runfiles) def _build_rustdoc_flags(ctx): @@ -484,23 +474,25 @@ def _rust_doc_impl(ctx): lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"]) if target.crate_root == None else target.crate_root) + toolchain = _find_toolchain(ctx) + # Get information about dependencies output_dir = rust_doc_zip.dirname depinfo = _setup_deps(target.deps, target.name, output_dir, + toolchain, allow_cc_deps=False) # Rustdoc flags. doc_flags = _build_rustdoc_flags(ctx) # Build rustdoc command. - toolchain = _find_toolchain(ctx) doc_cmd = build_rustdoc_command(ctx, toolchain, rust_doc_zip, depinfo, lib_rs, target, doc_flags) # Rustdoc action rustdoc_inputs = (target.srcs + - depinfo.libs + + depinfo.transitive_libs + [toolchain.rust_doc] + toolchain.rustc_lib + toolchain.rust_lib) @@ -528,18 +520,21 @@ def _rust_doc_test_impl(ctx): lib_rs = (_find_crate_root_src(target.srcs, ["lib.rs", "main.rs"]) if target.crate_root == None else target.crate_root) + toolchain = _find_toolchain(ctx) + # Get information about dependencies output_dir = rust_doc_test.dirname + working_dir="." depinfo = _setup_deps(target.deps, target.name, - working_dir=".", + working_dir, + toolchain, allow_cc_deps=False, in_runfiles=True) # Construct rustdoc test command, which will be written to a shell script # to be executed to run the test. - toolchain = _find_toolchain(ctx) doc_test_cmd = build_rustdoc_test_command(ctx, toolchain, depinfo, lib_rs) ctx.file_action(output = rust_doc_test, @@ -547,7 +542,6 @@ def _rust_doc_test_impl(ctx): executable = True) doc_test_inputs = (target.srcs + - depinfo.libs + depinfo.transitive_libs + [toolchain.rust_doc] + toolchain.rustc_lib + diff --git a/rust/toolchain.bzl b/rust/toolchain.bzl index bc11b3c57c..e7ca0f5a44 100644 --- a/rust/toolchain.bzl +++ b/rust/toolchain.bzl @@ -2,6 +2,8 @@ Toolchain rules used by Rust. """ +load(":utils.bzl", "relative_path") + ZIP_PATH = "/usr/bin/zip" # Utility methods that use the toolchain provider. @@ -23,6 +25,8 @@ def build_rustc_command(ctx, toolchain, crate_name, crate_type, src, output_dir, if ar_str.find("libtool", 0) != -1: ar = "/usr/bin/ar" + rpaths = _compute_rpaths(toolchain, ctx.bin_dir, output_dir, depinfo) + # Construct features flags features_flags = _get_features_flags(ctx.attr.crate_features) @@ -32,6 +36,8 @@ def build_rustc_command(ctx, toolchain, crate_name, crate_type, src, output_dir, return " ".join( ["set -e;"] + + # If TMPDIR is set but not created, rustc will die. + ['if [ ! -z "${TMPDIR+x}" ]; then mkdir -p $TMPDIR; fi;'] + depinfo.setup_cmd + _out_dir_setup_cmd(ctx.file.out_dir_tar) + [ @@ -42,26 +48,27 @@ def build_rustc_command(ctx, toolchain, crate_name, crate_type, src, output_dir, src.path, "--crate-name %s" % crate_name, "--crate-type %s" % crate_type, - "-C opt-level=3", + "--codegen opt-level=3", # @TODO Might not want to do -o3 on tests # Disambiguate this crate from similarly named ones - "-C metadata=%s" % extra_filename, - "-C extra-filename='%s'" % extra_filename, + "--codegen metadata=%s" % extra_filename, + "--codegen extra-filename='%s'" % extra_filename, "--codegen ar=%s" % ar, "--codegen linker=%s" % cc, "--codegen link-args='%s'" % ' '.join(cpp_fragment.link_options), - ] + ["-L all=%s" % dir for dir in _get_dir_names(toolchain.rust_lib)] + [ "--out-dir %s" % output_dir, "--emit=dep-info,link", ] + + ["--codegen link-arg='-Wl,-rpath={}'".format(rpath) for rpath in rpaths] + features_flags + rust_flags + + ["-L all=%s" % dir for dir in _get_dir_names(toolchain.rust_lib)] + depinfo.search_flags + depinfo.link_flags + ctx.attr.rustc_flags) def build_rustdoc_command(ctx, toolchain, rust_doc_zip, depinfo, lib_rs, target, doc_flags): """ - Constructs the rustdocc command used to build the current target. + Constructs the rustdoc command used to build the current target. """ docs_dir = rust_doc_zip.dirname + "/_rust_docs" @@ -110,6 +117,21 @@ def build_rustdoc_test_command(ctx, toolchain, depinfo, lib_rs): depinfo.search_flags + depinfo.link_flags) +def _compute_rpaths(toolchain, bin_dir, output_dir, depinfo): + """ + Determine the artifact's rpaths relative to the bazel root + for runtime linking of shared libraries. + """ + if not depinfo.transitive_dylibs: + return [] + if toolchain.os != 'linux': + fail("Runtime linking is not supported on {}, but found {}".format( + toolchain.os, depinfo.transitive_dylibs)) + + # Multiple dylibs can be present in the same directory, so deduplicate them. + return depset(["$ORIGIN/" + relative_path(output_dir, dylib.dirname) + for dylib in depinfo.transitive_dylibs]) + def _get_features_flags(features): """ Constructs a string containing the feature flags from the features specified @@ -161,6 +183,7 @@ def _rust_toolchain_impl(ctx): rust_lib = _get_files(ctx.attr.rust_lib), staticlib_ext = ctx.attr.staticlib_ext, dylib_ext = ctx.attr.dylib_ext, + os = ctx.attr.os, crosstool_files = ctx.files._crosstool) return [toolchain] @@ -173,6 +196,7 @@ rust_toolchain = rule( "rust_lib": attr.label_list(allow_files = True), "staticlib_ext": attr.string(mandatory = True), "dylib_ext": attr.string(mandatory = True), + "os": attr.string(mandatory = True), "_crosstool": attr.label( default = Label("//tools/defaults:crosstool"), ), diff --git a/rust/utils.bzl b/rust/utils.bzl new file mode 100644 index 0000000000..a6190c438d --- /dev/null +++ b/rust/utils.bzl @@ -0,0 +1,50 @@ +# Copyright 2015 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. + +""" +Utility functions not specific to the rust toolchain. +""" + +def relative_path(src_path, dest_path): + """Returns the relative path from src_path to dest_path.""" + src_parts = _path_parts(src_path) + dest_parts = _path_parts(dest_path) + n = 0 + done = False + for src_part, dest_part in zip(src_parts, dest_parts): + if src_part != dest_part: + break + n += 1 + + relative_path = "" + for i in range(n, len(src_parts)): + relative_path += "../" + relative_path += "/".join(dest_parts[n:]) + + return relative_path + +def _path_parts(path): + """Takes a path and returns a list of its parts with all "." elements removed. + + The main use case of this function is if one of the inputs to _relative() + is a relative path, such as "./foo". + + Args: + path_parts: A list containing parts of a path. + + Returns: + Returns a list containing the path parts with all "." elements removed. + """ + path_parts = path.split("/") + return [part for part in path_parts if part != "."] diff --git a/test/BUILD b/test/BUILD index ce3c0c0532..fe4406ac87 100644 --- a/test/BUILD +++ b/test/BUILD @@ -16,7 +16,9 @@ rule_test( generates = ["libhello_lib--1343350674.rlib"], provides = { "rust_lib": "/libhello_lib--1343350674.rlib>\\?$", - "transitive_libs": "^\\[\\]$", + "transitive_rlibs": "^depset(\[\])$", + "transitive_dylibs": "^depset(\[\], order = \"topological\")$", + "transitive_staticlibs": "^depset(\[\])$", }, rule = "@examples//hello_lib:hello_lib", )