Skip to content

Commit 7298c5f

Browse files
committed
Export CcInfo for staticlib & cdylib allowing rust outputs to be used in c++ rules
1 parent 8e7e3ba commit 7298c5f

File tree

7 files changed

+135
-23
lines changed

7 files changed

+135
-23
lines changed

cargo/cargo_build_script.bzl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_linker_and_args")
1+
load("@io_bazel_rules_rust//rust:private/rustc.bzl", "BuildInfo", "DepInfo", "get_compilation_mode_opts", "get_cc_toolchain", "get_linker_and_args")
22
load("@io_bazel_rules_rust//rust:private/utils.bzl", "find_toolchain")
33
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_binary")
44
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
@@ -41,7 +41,8 @@ def _cargo_build_script_run(ctx, script):
4141

4242
# Pull in env vars which may be required for the cc_toolchain to work (e.g. on OSX, the SDK version).
4343
# We hope that the linker env is sufficient for the whole cc_toolchain.
44-
_, _, linker_env = get_linker_and_args(ctx, None)
44+
cc_toolchain, feature_configuration = get_cc_toolchain(ctx)
45+
_, _, linker_env = get_linker_and_args(ctx, cc_toolchain, feature_configuration, None)
4546
env.update(**linker_env)
4647

4748
if cc_toolchain:

examples/ffi/c_calling_rust/BUILD

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
1+
load("@rules_cc//cc:defs.bzl", "cc_test")
22
load("@io_bazel_rules_rust//rust:rust.bzl", "rust_library")
33

44
rust_library(
@@ -7,16 +7,8 @@ rust_library(
77
crate_type = "staticlib",
88
)
99

10-
# cc_* rules expect cc_* deps, so we need to wrap our rust staticlib.
11-
cc_library(
12-
name = "wrapper",
13-
srcs = [":rusty"],
14-
# We could link dynamically by setting crate_type to cdylib
15-
linkstatic = True,
16-
)
17-
1810
cc_test(
1911
name = "main",
2012
srcs = ["main.c"],
21-
deps = [":wrapper"],
13+
deps = [":rusty"],
2214
)

rust/platform/triple_mappings.bzl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,47 @@ _SYSTEM_TO_DYLIB_EXT = {
6666
"unknown": ".wasm",
6767
}
6868

69+
# See https://github.com/rust-lang/rust/blob/master/src/libstd/build.rs
70+
_SYSTEM_TO_STDLIB_LINKFLAGS = {
71+
# TODO(https://github.com/bazelbuild/rules_cc/issues/75):
72+
#
73+
# Right now bazel cc rules does not specify the exact flag setup needed for calling out system
74+
# libs, that is we dont know given a toolchain if it should be, for example,
75+
# `-lxxx` or `/Lxxx` or `xxx.lib` etc.
76+
#
77+
# We include the flag setup as they are _commonly seen_ on various platforms with a cc_rules
78+
# style override for people doing things like gnu-mingw on windows.
79+
#
80+
# If you are reading this ... sorry! set the env var `BAZEL_RUST_STDLIB_LINKFLAGS` to
81+
# what you need for your specific setup, for example like so
82+
# `BAZEL_RUST_STDLIB_LINKFLAGS="-ladvapi32:-lws2_32:-luserenv"`
83+
84+
"freebsd": ["-lexecinfo", "-lpthread"],
85+
# TODO: This ignores musl. Longer term what does Bazel think about musl?
86+
"linux": ["-ldl", "-lpthread"],
87+
"darwin": ["-lSystem", "-lresolv"],
88+
"uwp": ["ws2_32.lib"],
89+
"windows": ["advapi32.lib", "ws2_32.lib", "userenv.lib"],
90+
"ios": ["-lSystem", "-lobjc", "-framework Security", "-framework Foundation", "-lresolv"],
91+
# NOTE: Rust stdlib `build.rs` treats android as a subset of linux, rust rules treat android
92+
# as its own system.
93+
"android": ["-ldl", "-llog", "-lgcc"],
94+
"emscripten": [],
95+
"nacl": [],
96+
"bitrig": [],
97+
"dragonfly": ["-lpthread"],
98+
"netbsd": ["-lpthread", "-lrt"],
99+
"openbsd": ["-lpthread"],
100+
"solaris": ["-lsocket", "-lposix4", "-lpthread", "-lresolv"],
101+
"illumos": ["-lsocket", "-lposix4", "-lpthread", "-lresolv", "-lnsl", "-lumem"],
102+
"fuchsia": ["-lzircon", "-lfdio"],
103+
# TODO(gregbowyer): If rust stdlib is compiled for cloudabi with the backtrace feature it
104+
# includes `-lunwind` but this might not actually be required.
105+
# I am not sure which is the common configuration or how we encode it as a link flag.
106+
"cloudabi": ["-lunwind", "-lc", "-lcompiler_rt"],
107+
"unknown": [],
108+
}
109+
69110
def cpu_arch_to_constraints(cpu_arch):
70111
plat_suffix = _CPU_ARCH_TO_BUILTIN_PLAT_SUFFIX[cpu_arch]
71112

@@ -110,6 +151,9 @@ def system_to_staticlib_ext(system):
110151
def system_to_binary_ext(system):
111152
return _SYSTEM_TO_BINARY_EXT[system]
112153

154+
def system_to_stdlib_linkflags(system):
155+
return _SYSTEM_TO_STDLIB_LINKFLAGS[system]
156+
113157
def triple_to_constraint_set(triple):
114158
component_parts = triple.split("-")
115159
if len(component_parts) < 3:

rust/private/clippy.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ load(
1818
"collect_deps",
1919
"collect_inputs",
2020
"construct_arguments",
21+
"get_cc_toolchain",
2122
"construct_compile_command",
2223
)
2324
load(
@@ -70,10 +71,14 @@ def _clippy_aspect_impl(target, ctx):
7071
build_info
7172
)
7273

74+
cc_toolchain, feature_configuration = get_cc_toolchain(ctx)
75+
7376
args, env, dynamic_env = construct_arguments(
7477
ctx,
7578
ctx.rule.file,
7679
toolchain,
80+
cc_toolchain,
81+
feature_configuration,
7782
crate_info,
7883
dep_info,
7984
output_hash = repr(hash(root.path)),

rust/private/rustc.bzl

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -198,26 +198,35 @@ def collect_deps(label, deps, proc_macro_deps, aliases, toolchain):
198198
build_info,
199199
)
200200

201-
def get_linker_and_args(ctx, rpaths):
202-
if (len(BAZEL_VERSION) == 0 or
203-
versions.is_at_least("0.18.0", BAZEL_VERSION)):
204-
user_link_flags = ctx.fragments.cpp.linkopts
205-
else:
206-
user_link_flags = depset(ctx.fragments.cpp.linkopts)
207-
201+
def get_cc_toolchain(ctx):
208202
cc_toolchain = find_cpp_toolchain(ctx)
203+
209204
kwargs = {
210205
"ctx": ctx,
211206
} if len(BAZEL_VERSION) == 0 or versions.is_at_least(
212207
"0.25.0",
213208
BAZEL_VERSION,
214209
) else {}
210+
215211
feature_configuration = cc_common.configure_features(
216212
cc_toolchain = cc_toolchain,
217213
requested_features = ctx.features,
218214
unsupported_features = ctx.disabled_features,
219215
**kwargs
220216
)
217+
218+
return cc_toolchain, feature_configuration
219+
220+
def get_cc_user_link_flags(ctx):
221+
if (len(BAZEL_VERSION) == 0 or
222+
versions.is_at_least("0.18.0", BAZEL_VERSION)):
223+
return ctx.fragments.cpp.linkopts
224+
else:
225+
return depset(ctx.fragments.cpp.linkopts)
226+
227+
def get_linker_and_args(ctx, cc_toolchain, feature_configuration, rpaths):
228+
user_link_flags = get_cc_user_link_flags(ctx)
229+
221230
link_variables = cc_common.create_link_variables(
222231
feature_configuration = feature_configuration,
223232
cc_toolchain = cc_toolchain,
@@ -290,6 +299,8 @@ def construct_arguments(
290299
ctx,
291300
file,
292301
toolchain,
302+
cc_toolchain,
303+
feature_configuration,
293304
crate_info,
294305
dep_info,
295306
output_hash,
@@ -340,7 +351,7 @@ def construct_arguments(
340351
# linker since it won't understand.
341352
if toolchain.target_arch != "wasm32":
342353
rpaths = _compute_rpaths(toolchain, output_dir, dep_info)
343-
ld, link_args, link_env = get_linker_and_args(ctx, rpaths)
354+
ld, link_args, link_env = get_linker_and_args(ctx, cc_toolchain, feature_configuration, rpaths)
344355
env.update(link_env)
345356
args.add("--codegen=linker=" + ld)
346357
args.add_joined("--codegen", link_args, join_with = " ", format_joined = "link-args=%s")
@@ -451,10 +462,14 @@ def rustc_compile_action(
451462
build_info,
452463
)
453464

465+
cc_toolchain, feature_configuration = get_cc_toolchain(ctx)
466+
454467
args, env, dynamic_env = construct_arguments(
455468
ctx,
456469
ctx.file,
457470
toolchain,
471+
cc_toolchain,
472+
feature_configuration,
458473
crate_info,
459474
dep_info,
460475
output_hash,
@@ -502,7 +517,7 @@ def rustc_compile_action(
502517
if hasattr(ctx.attr, "out_binary"):
503518
out_binary = getattr(ctx.attr, "out_binary")
504519

505-
return [
520+
return establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configuration) + [
506521
crate_info,
507522
dep_info,
508523
DefaultInfo(
@@ -513,6 +528,43 @@ def rustc_compile_action(
513528
),
514529
]
515530

531+
def establish_cc_info(ctx, crate_info, toolchain, cc_toolchain, feature_configuration):
532+
""" If the produced crate is suitable yield a CcInfo to allow for interop with cc rules """
533+
534+
if crate_info.type not in ("staticlib", "cdylib"):
535+
return []
536+
537+
if crate_info.type == "staticlib":
538+
library_to_link = cc_common.create_library_to_link(
539+
actions = ctx.actions,
540+
feature_configuration = feature_configuration,
541+
cc_toolchain = cc_toolchain,
542+
static_library = crate_info.output,
543+
)
544+
elif crate_info.type == "cdylib":
545+
library_to_link = cc_common.create_library_to_link(
546+
actions = ctx.actions,
547+
feature_configuration = feature_configuration,
548+
cc_toolchain = cc_toolchain,
549+
dynamic_library = crate_info.output,
550+
)
551+
552+
link_input = cc_common.create_linker_input(
553+
owner = ctx.label,
554+
libraries = depset([library_to_link]),
555+
user_link_flags = depset(toolchain.stdlib_linkflags),
556+
)
557+
558+
linking_context = cc_common.create_linking_context(
559+
# TODO - What to do for no_std?
560+
linker_inputs = depset([link_input]),
561+
)
562+
563+
cc_infos = [dep[CcInfo] for dep in ctx.attr.deps]
564+
cc_infos.append(CcInfo(linking_context = linking_context))
565+
566+
return [cc_common.merge_cc_infos(cc_infos = cc_infos)]
567+
516568
def add_edition_flags(args, crate):
517569
if crate.edition != "2015":
518570
args.add("--edition={}".format(crate.edition))

rust/repositories.bzl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
load(":known_shas.bzl", "FILE_KEY_TO_SHA")
2-
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")
2+
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")
33
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
44
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
55

@@ -181,17 +181,21 @@ filegroup(
181181
target_triple = target_triple,
182182
)
183183

184-
def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple, default_edition = "2015"):
184+
def BUILD_for_rust_toolchain(workspace_name, name, exec_triple, target_triple,
185+
stdlib_linkflags=None, default_edition = "2015"):
185186
"""Emits a toolchain declaration to match an existing compiler and stdlib.
186187
187188
Args:
188189
workspace_name: The name of the workspace that this toolchain resides in
189190
name: The name of the toolchain declaration
190191
exec_triple: The rust-style target that this compiler runs on
191192
target_triple: The rust-style target triple of the tool
193+
stdlib_linkflags: Overriden flags needed for linking to rust stdlib, akin to BAZEL_LINKLIBS
192194
"""
193195

194196
system = triple_to_system(target_triple)
197+
if stdlib_linkflags == None:
198+
stdlib_linkflags = ", ".join(['"%s"' % x for x in system_to_stdlib_linkflags(system)])
195199

196200
return """
197201
rust_toolchain(
@@ -204,6 +208,7 @@ rust_toolchain(
204208
rustc_lib = "@{workspace_name}//:rustc_lib",
205209
staticlib_ext = "{staticlib_ext}",
206210
dylib_ext = "{dylib_ext}",
211+
stdlib_linkflags = [{stdlib_linkflags}],
207212
os = "{system}",
208213
default_edition = "{default_edition}",
209214
exec_triple = "{exec_triple}",
@@ -215,6 +220,7 @@ rust_toolchain(
215220
workspace_name = workspace_name,
216221
staticlib_ext = system_to_staticlib_ext(system),
217222
dylib_ext = system_to_dylib_ext(system),
223+
stdlib_linkflags = stdlib_linkflags,
218224
system = system,
219225
default_edition = default_edition,
220226
exec_triple = exec_triple,
@@ -376,13 +382,19 @@ def _load_rust_stdlib(ctx, target_triple):
376382

377383
toolchain_prefix = ctx.attr.toolchain_name_prefix or DEFAULT_TOOLCHAIN_NAME_PREFIX
378384
stdlib_BUILD = BUILD_for_stdlib(target_triple)
385+
386+
stdlib_linkflags = None
387+
if 'BAZEL_RUST_STDLIB_LINKFLAGS' in ctx.os.environ:
388+
stdlib_linkflags = ctx.os.environ['BAZEL_RUST_STDLIB_LINKFLAGS'].split(':')
389+
379390
toolchain_BUILD = BUILD_for_rust_toolchain(
380391
name = "{toolchain_prefix}_{target_triple}".format(
381392
toolchain_prefix = toolchain_prefix,
382393
target_triple = target_triple,
383394
),
384395
exec_triple = ctx.attr.exec_triple,
385396
target_triple = target_triple,
397+
stdlib_linkflags = stdlib_linkflags,
386398
workspace_name = ctx.attr.name,
387399
default_edition = ctx.attr.edition,
388400
)

rust/toolchain.bzl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ def _rust_toolchain_impl(ctx):
2121
rust_lib = ctx.attr.rust_lib,
2222
staticlib_ext = ctx.attr.staticlib_ext,
2323
dylib_ext = ctx.attr.dylib_ext,
24+
stdlib_linkflags = ctx.attr.stdlib_linkflags,
2425
target_triple = ctx.attr.target_triple,
2526
exec_triple = ctx.attr.exec_triple,
2627
os = ctx.attr.os,
@@ -58,6 +59,10 @@ rust_toolchain = rule(
5859
),
5960
"staticlib_ext": attr.string(mandatory = True),
6061
"dylib_ext": attr.string(mandatory = True),
62+
"stdlib_linkflags": attr.string_list(
63+
doc = """Additional linker libs used when std lib is linked,
64+
see https://github.com/rust-lang/rust/blob/master/src/libstd/build.rs""",
65+
mandatory = True),
6166
"os": attr.string(mandatory = True),
6267
"default_edition": attr.string(
6368
doc = "The edition to use for rust_* rules that don't specify an edition.",
@@ -100,6 +105,7 @@ rust_toolchain(
100105
rust_doc = "@rust_cpuX//:rustdoc",
101106
staticlib_ext = ".a",
102107
dylib_ext = ".so",
108+
stdlib_linkflags = ["-lpthread", "-ldl"],
103109
os = "linux",
104110
)
105111

0 commit comments

Comments
 (0)