Skip to content

Commit 43f5664

Browse files
committed
ccinfo: when providing ccinfo, optionally include libstd and alloc
The new attribute on RustToolchain is the label of a target that provides __rust_realloc et al, which allows ld(1) to use the .rlib files directly without needing to involve rustc in the linking step. This means Rust and C++ can be mixed in a cc_binary freely without needing any staticlib-type crates, which avoids problems if you have a cc_binary -> rust_library -> cc_library -> rust_library situation.
1 parent 9eb5eeb commit 43f5664

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

rust/private/rustc.bzl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -693,6 +693,9 @@ def establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configur
693693
if CcInfo in dep:
694694
cc_infos.append(dep[CcInfo])
695695

696+
if crate_info.type in ("rlib", "lib") and toolchain.extra_libstd_and_allocator_ccinfo:
697+
cc_infos.append(toolchain.extra_libstd_and_allocator_ccinfo)
698+
696699
return [cc_common.merge_cc_infos(cc_infos = cc_infos)]
697700

698701
def add_edition_flags(args, crate):

rust/toolchain.bzl

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
"""The rust_toolchain rule definition and implementation."""
22

3+
load(
4+
"//rust/private:utils.bzl",
5+
"find_cc_toolchain",
6+
)
7+
8+
def _make_dota(ctx, f):
9+
dot_a = ctx.actions.declare_file(f.basename + ".a", sibling = f)
10+
ctx.actions.symlink(output = dot_a, target_file = f)
11+
return dot_a
12+
313
def _rust_toolchain_impl(ctx):
414
"""The rust_toolchain implementation
515
@@ -17,6 +27,42 @@ def _rust_toolchain_impl(ctx):
1727
for k, v in ctx.attr.debug_info.items():
1828
if not k in ctx.attr.opt_level:
1929
fail("Compilation mode {} is not defined in opt_level but is defined debug_info".format(k))
30+
link_inputs = []
31+
std_rlibs = [f for f in ctx.attr.rust_lib.files.to_list() if f.basename.endswith(".rlib")]
32+
cc_toolchain, feature_configuration = find_cc_toolchain(ctx)
33+
if std_rlibs:
34+
link_inputs.append(cc_common.create_linker_input(
35+
owner = ctx.attr.rust_lib.label,
36+
libraries = depset(
37+
[
38+
cc_common.create_library_to_link(
39+
# TODO(augie): wat? this needs no actions
40+
actions = ctx.actions,
41+
feature_configuration = feature_configuration,
42+
cc_toolchain = cc_toolchain,
43+
static_library = _make_dota(ctx, f),
44+
)
45+
for f in std_rlibs
46+
],
47+
),
48+
))
49+
if ctx.attr.allocator_library:
50+
link_inputs.append(cc_common.create_linker_input(
51+
owner = ctx.attr.allocator_library.allocator_library.label,
52+
libraries = depset([
53+
cc_common.create_library_to_link(
54+
# TODO(augie): wat? this needs no actions
55+
actions = ctx.actions,
56+
feature_configuration = feature_configuration,
57+
cc_toolchain = cc_toolchain,
58+
static_library = f,
59+
)
60+
for f in ctx.attr.allocator_library.files.to_list()
61+
]),
62+
))
63+
extra_libstd_and_allocator_ccinfo = None
64+
if link_inputs:
65+
extra_libstd_and_allocator_ccinfo = CcInfo(linking_context = cc_common.create_linking_context(linker_inputs = depset(link_inputs)))
2066

2167
toolchain = platform_common.ToolchainInfo(
2268
rustc = ctx.file.rustc,
@@ -38,11 +84,13 @@ def _rust_toolchain_impl(ctx):
3884
default_edition = ctx.attr.default_edition,
3985
compilation_mode_opts = compilation_mode_opts,
4086
crosstool_files = ctx.files._crosstool,
87+
extra_libstd_and_allocator_ccinfo = extra_libstd_and_allocator_ccinfo,
4188
)
4289
return [toolchain]
4390

4491
rust_toolchain = rule(
4592
implementation = _rust_toolchain_impl,
93+
fragments = ["cpp"],
4694
attrs = {
4795
"binary_ext": attr.string(
4896
doc = "The extension for binaries created from rustc.",
@@ -131,6 +179,12 @@ rust_toolchain = rule(
131179
"_crosstool": attr.label(
132180
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
133181
),
182+
"_cc_toolchain": attr.label(
183+
default = "@bazel_tools//tools/cpp:current_cc_toolchain",
184+
),
185+
"allocator_library": attr.label(
186+
doc = "Target that provides allocator functions when rust_library targets are embedded in a cc_binary.",
187+
),
134188
},
135189
doc = """Declares a Rust toolchain for use.
136190

test/unit/cc_info/cc_info_test.bzl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ load("//rust:defs.bzl", "rust_binary", "rust_library", "rust_proc_macro", "rust_
66
def _is_dylib_on_windows(ctx):
77
return ctx.target_platform_has_constraint(ctx.attr._windows[platform_common.ConstraintValueInfo])
88

9-
def _assert_cc_info_has_library_to_link(env, tut, type):
9+
def _assert_cc_info_has_library_to_link(env, tut, type, ccinfo_count):
1010
asserts.true(env, CcInfo in tut, "rust_library should provide CcInfo")
1111
cc_info = tut[CcInfo]
1212
linker_inputs = cc_info.linking_context.linker_inputs.to_list()
13-
asserts.equals(env, len(linker_inputs), 1)
13+
asserts.equals(env, len(linker_inputs), ccinfo_count)
1414
library_to_link = linker_inputs[0].libraries[0]
1515
asserts.equals(env, False, library_to_link.alwayslink)
1616

@@ -42,7 +42,7 @@ def _assert_cc_info_has_library_to_link(env, tut, type):
4242
def _rlib_provides_cc_info_test_impl(ctx):
4343
env = analysistest.begin(ctx)
4444
tut = analysistest.target_under_test(env)
45-
_assert_cc_info_has_library_to_link(env, tut, "rlib")
45+
_assert_cc_info_has_library_to_link(env, tut, "rlib", 2)
4646
return analysistest.end(env)
4747

4848
def _bin_does_not_provide_cc_info_test_impl(ctx):
@@ -60,13 +60,13 @@ def _proc_macro_does_not_provide_cc_info_test_impl(ctx):
6060
def _cdylib_provides_cc_info_test_impl(ctx):
6161
env = analysistest.begin(ctx)
6262
tut = analysistest.target_under_test(env)
63-
_assert_cc_info_has_library_to_link(env, tut, "cdylib")
63+
_assert_cc_info_has_library_to_link(env, tut, "cdylib", 1)
6464
return analysistest.end(env)
6565

6666
def _staticlib_provides_cc_info_test_impl(ctx):
6767
env = analysistest.begin(ctx)
6868
tut = analysistest.target_under_test(env)
69-
_assert_cc_info_has_library_to_link(env, tut, "staticlib")
69+
_assert_cc_info_has_library_to_link(env, tut, "staticlib", 1)
7070
return analysistest.end(env)
7171

7272
rlib_provides_cc_info_test = analysistest.make(_rlib_provides_cc_info_test_impl)

0 commit comments

Comments
 (0)