Skip to content
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

Fixes for rust_binary that depends on a cc_library that depends on a rust_library #825

Merged
merged 18 commits into from
Jul 20, 2021
Merged
Show file tree
Hide file tree
Changes from 17 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
4 changes: 2 additions & 2 deletions rust/private/rustc.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ load(
"find_cc_toolchain",
"get_lib_name",
"get_preferred_artifact",
"make_static_lib",
"relativize",
)

Expand Down Expand Up @@ -635,8 +636,7 @@ def establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configur
# bazel hard-codes a check for endswith((".a", ".pic.a",
# ".lib")) in create_library_to_link, so we work around that
# by creating a symlink to the .rlib with a .a extension.
dot_a = ctx.actions.declare_file(crate_info.name + ".a", sibling = crate_info.output)
ctx.actions.symlink(output = dot_a, target_file = crate_info.output)
dot_a = make_static_lib(ctx, crate_info.output)
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved

# TODO(hlopko): handle PIC/NOPIC correctly
library_to_link = cc_common.create_library_to_link(
Expand Down
27 changes: 27 additions & 0 deletions rust/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,30 @@ def dedent(doc_string):
# Remove the leading block of spaces from the current line
block = " " * space_count
return "\n".join([line.replace(block, "", 1).rstrip() for line in lines])

def make_static_lib(ctx, rlib_file):
UebelAndre marked this conversation as resolved.
Show resolved Hide resolved
"""Add a .a symlink to an .rlib file, so it can be used as a staticlib.
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved

The name of the symlink is derived from the <name> of the <name>.rlib file as follows:
* `<name>.a`, if <name> starts with `lib`
* `lib<name>.a`, otherwise.

For example, the name of the symlink for
* `libcratea.rlib` is `libcratea.a`
* `crateb.rlib` is `libcrateb.a`.

Args:
ctx (ctx): The rule's context object.
rlib_file (File): The file to symlink, which must end in .rlib.

Returns:
The symlink's File.
"""
if not rlib_file.basename.endswith(".rlib"):
fail("file is not an .rlib: ", rlib_file.basename)
basename = rlib_file.basename[:-5]
if not basename.startswith("lib"):
basename = "lib" + basename
dot_a = ctx.actions.declare_file(basename + ".a", sibling = rlib_file)
ctx.actions.symlink(output = dot_a, target_file = rlib_file)
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved
return dot_a
29 changes: 12 additions & 17 deletions rust/toolchain.bzl
Original file line number Diff line number Diff line change
@@ -1,21 +1,7 @@
"""The rust_toolchain rule definition and implementation."""

load("//rust/private:common.bzl", "rust_common")
load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain")

def _make_dota(ctx, file):
"""Add a symlink for a file that ends in .a, so it can be used as a staticlib.

Args:
ctx (ctx): The rule's context object.
file (File): The file to symlink.

Returns:
The symlink's File.
"""
dot_a = ctx.actions.declare_file(file.basename + ".a", sibling = file)
ctx.actions.symlink(output = dot_a, target_file = file)
return dot_a
load("//rust/private:utils.bzl", "dedent", "find_cc_toolchain", "make_static_lib")

def _rust_stdlib_filegroup_impl(ctx):
rust_lib = ctx.files.srcs
Expand All @@ -35,7 +21,7 @@ def _rust_stdlib_filegroup_impl(ctx):
#
# alloc depends on the allocator_library if it's configured, but we
# do that later.
dot_a_files = [_make_dota(ctx, f) for f in std_rlibs]
dot_a_files = [make_static_lib(ctx, f) for f in std_rlibs]

alloc_files = [f for f in dot_a_files if "alloc" in f.basename and "std" not in f.basename]
between_alloc_and_core_files = [f for f in dot_a_files if "compiler_builtins" in f.basename]
Expand Down Expand Up @@ -140,8 +126,17 @@ def _make_libstd_and_allocator_ccinfo(ctx, rust_lib, allocator_library):
transitive = [between_alloc_and_core_inputs],
order = "topological",
)

# The libraries panic_abort and panic_unwind are alternatives.
# The std by default requires panic_unwind.
# Exclude panic_abort if panic_unwind is present.
# TODO: Provide a setting to choose between panic_abort and panic_unwind.
filtered_between_core_and_std_files = rust_stdlib_info.between_core_and_std_files
has_panic_unwind = [f for f in filtered_between_core_and_std_files if "panic_unwind" in f.basename]
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved
if has_panic_unwind:
filtered_between_core_and_std_files = [f for f in filtered_between_core_and_std_files if "panic_abort" not in f.basename]
between_core_and_std_inputs = depset(
[_ltl(f, ctx, cc_toolchain, feature_configuration) for f in rust_stdlib_info.between_core_and_std_files],
[_ltl(f, ctx, cc_toolchain, feature_configuration) for f in filtered_between_core_and_std_files],
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved
transitive = [core_inputs],
order = "topological",
)
Expand Down
2 changes: 2 additions & 0 deletions test/unit/cc_info/cc_info_test.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ def _assert_cc_info_has_library_to_link(env, tut, type, ccinfo_count):
asserts.equals(env, None, library_to_link.resolved_symlink_dynamic_library)
asserts.equals(env, None, library_to_link.resolved_symlink_interface_library)
asserts.true(env, library_to_link.static_library != None)
if type in ("rlib", "lib"):
asserts.true(env, library_to_link.static_library.basename.startswith("lib" + tut.label.name))
asserts.true(env, library_to_link.pic_static_library != None)
asserts.equals(env, library_to_link.static_library, library_to_link.pic_static_library)

Expand Down
4 changes: 4 additions & 0 deletions test/unit/stdlib/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
load(":stdlib.bzl", "stdlib_suite")

############################ UNIT TESTS #############################
stdlib_suite(name = "stdlib_suite")
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""Unittest to verify ordering of rust stdlib in rust_library() CcInfo"""
"""Unittest to verify contents and ordering of rust stdlib in rust_library() CcInfo"""

load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts")
load("//rust:defs.bzl", "rust_library")
Expand Down Expand Up @@ -26,17 +26,37 @@ def _dedup_preserving_order(list):
r.append(e)
return r

def _stdlibs(tut):
"""Given a target, return the list of its standard rust libraries."""
libs = [lib.static_library for li in tut[CcInfo].linking_context.linker_inputs.to_list() for lib in li.libraries]
krasimirgg marked this conversation as resolved.
Show resolved Hide resolved
stdlibs = [lib for lib in libs if (tut.label.name not in lib.basename)]
return stdlibs

def _libstd_ordering_test_impl(ctx):
env = analysistest.begin(ctx)
tut = analysistest.target_under_test(env)
libs = [lib.static_library for li in tut[CcInfo].linking_context.linker_inputs.to_list() for lib in li.libraries]
rlibs = [_categorize_library(lib.basename) for lib in libs if ".rlib" in lib.basename]
set_to_check = _dedup_preserving_order([lib for lib in rlibs if lib != "other"])
stdlib_categories = [_categorize_library(lib.basename) for lib in _stdlibs(tut)]
set_to_check = _dedup_preserving_order([lib for lib in stdlib_categories if lib != "other"])
asserts.equals(env, ["std", "core", "compiler_builtins", "alloc"], set_to_check)
return analysistest.end(env)

libstd_ordering_test = analysistest.make(_libstd_ordering_test_impl)

def _libstd_panic_test_impl(ctx):
# The libraries panic_unwind and panic_abort are alternatives.
# Check that they don't occur together.
env = analysistest.begin(ctx)
tut = analysistest.target_under_test(env)
stdlibs = _stdlibs(tut)
has_panic_unwind = [lib for lib in stdlibs if "panic_unwind" in lib.basename]
if has_panic_unwind:
has_panic_abort = [lib for lib in stdlibs if "panic_abort" in lib.basename]
asserts.false(env, has_panic_abort)

return analysistest.end(env)

libstd_panic_test = analysistest.make(_libstd_panic_test_impl)

def _native_dep_test():
rust_library(
name = "some_rlib",
Expand All @@ -48,7 +68,12 @@ def _native_dep_test():
target_under_test = ":some_rlib",
)

def stdlib_ordering_suite(name):
libstd_panic_test(
name = "libstd_panic_test",
target_under_test = ":some_rlib",
)

def stdlib_suite(name):
"""Entry-point macro called from the BUILD file.

Args:
Expand Down
4 changes: 0 additions & 4 deletions test/unit/stdlib_ordering/BUILD.bazel

This file was deleted.