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

Update rust_bindgen_library to only link into the direct consumer #2361

Merged
merged 8 commits into from
Dec 28, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
96 changes: 93 additions & 3 deletions bindgen/private/bindgen.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ load(
)
load("@rules_cc//cc:defs.bzl", "CcInfo")
load("//rust:defs.bzl", "rust_library")
load("//rust:rust_common.bzl", "BuildInfo")

# buildifier: disable=bzl-visibility
load("//rust/private:rustc.bzl", "get_linker_and_args")
Expand Down Expand Up @@ -64,27 +65,94 @@ def rust_bindgen_library(
if "tags" in kwargs:
kwargs.pop("tags")

sub_tags = tags + ([] if "manual" in tags else ["manual"])

deps = kwargs.get("deps") or []
if "deps" in kwargs:
kwargs.pop("deps")

bindgen_kwargs = {}
if "leak_symbols" in kwargs:
bindgen_kwargs.update({"leak_symbols": kwargs.pop("leak_symbols")})

rust_bindgen(
name = name + "__bindgen",
header = header,
cc_lib = cc_lib,
bindgen_flags = bindgen_flags or [],
clang_flags = clang_flags or [],
tags = ["manual"],
tags = sub_tags,
**bindgen_kwargs
)

for custom_tag in ["__bindgen", "no-clippy", "no-rustfmt"]:
tags = tags + ([] if custom_tag in tags else [custom_tag])

rust_library(
name = name,
srcs = [name + "__bindgen.rs"],
tags = tags + ["__bindgen", "noclippy"],
deps = deps + [cc_lib],
deps = deps + [name + "__bindgen"],
tags = tags,
**kwargs
)

def _generate_cc_link_build_info(ctx, cc_lib):
"""Produce the eqivilant cargo_build_script providers for use in linking the library.

Args:
ctx (ctx): The rule's context object
cc_lib (Target): The `rust_bindgen.cc_lib` target.

Returns:
The `BuildInfo` provider.
"""
compile_data = []
linker_flags = []
linker_search_paths = []

for linker_input in cc_lib[CcInfo].linking_context.linker_inputs.to_list():
for lib in linker_input.libraries:
if lib.static_library:
linker_flags.append("-lstatic={}".format(lib.static_library.owner.name))
linker_search_paths.append(lib.static_library.dirname)
compile_data.append(lib.static_library)
elif lib.pic_static_library:
linker_flags.append("-lstatic={}".format(lib.pic_static_library.owner.name))
linker_search_paths.append(lib.pic_static_library.dirname)
compile_data.append(lib.pic_static_library)

linker_flags.extend(linker_input.user_link_flags)

if not compile_data:
fail("No static libraries found in {}".format(
cc_lib.label,
))

link_flags = ctx.actions.declare_file("{}.link_flags".format(ctx.label.name))
ctx.actions.write(
output = link_flags,
content = "\n".join(linker_flags),
)

link_search_paths = ctx.actions.declare_file("{}.link_search_paths".format(ctx.label.name))
ctx.actions.write(
output = link_search_paths,
content = "\n".join([
"-Lnative=${{pwd}}/{}".format(path)
for path in depset(linker_search_paths).to_list()
]),
)

return BuildInfo(
compile_data = depset(compile_data),
dep_env = None,
flags = None,
link_flags = link_flags,
link_search_paths = link_search_paths,
out_dir = None,
rustc_env = None,
)

def _rust_bindgen_impl(ctx):
# nb. We can't grab the cc_library`s direct headers, so a header must be provided.
cc_lib = ctx.attr.cc_lib
Expand Down Expand Up @@ -200,6 +268,21 @@ def _rust_bindgen_impl(ctx):
tools = tools,
)

if ctx.attr.leak_symbols:
# buildifier: disable=print
print("WARN: rust_bindgen.leak_symbols is set to True for {} - please file an issue at https://github.com/bazelbuild/rules_rust/issues explaining why this was necessary, as this support will be removed soon.".format(ctx.label))
providers = [cc_common.merge_cc_infos(
UebelAndre marked this conversation as resolved.
Show resolved Hide resolved
direct_cc_infos = [cc_lib[CcInfo]],
)]
else:
providers = [_generate_cc_link_build_info(ctx, cc_lib)]

return providers + [
OutputGroupInfo(
bindgen_bindings = depset([output]),
),
]

rust_bindgen = rule(
doc = "Generates a rust source file from a cc_library and a header.",
implementation = _rust_bindgen_impl,
Expand All @@ -220,6 +303,13 @@ rust_bindgen = rule(
allow_single_file = True,
mandatory = True,
),
"leak_symbols": attr.bool(
doc = (
"If True, `cc_lib` will be exposed and linked into all downstream consumers of the target vs. the " +
"`rust_library` directly consuming it."
),
default = False,
),
"_cc_toolchain": attr.label(
default = Label("@bazel_tools//tools/cpp:current_cc_toolchain"),
),
Expand Down
5 changes: 4 additions & 1 deletion cargo/private/cargo_build_script.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ def _cargo_build_script_impl(ctx):
flags = flags_out,
link_flags = link_flags,
link_search_paths = link_search_paths,
compile_data = depset([]),
),
OutputGroupInfo(
streams = depset([streams.stdout, streams.stderr]),
Expand Down Expand Up @@ -449,6 +450,7 @@ def _cargo_dep_env_implementation(ctx):
link_search_paths = empty_file,
out_dir = out_dir,
rustc_env = empty_file,
compile_data = depset([]),
))
return [
DefaultInfo(files = depset(ctx.files.src)),
Expand All @@ -465,8 +467,9 @@ def _cargo_dep_env_implementation(ctx):
flags = empty_file,
link_flags = empty_file,
link_search_paths = empty_file,
out_dir = empty_dir,
out_dir = None,
rustc_env = empty_file,
compile_data = depset([]),
),
# Information here is used directly by dependencies, and it is an error to have more than
# one dependency which sets this. This is the main way to specify information from build
Expand Down
3 changes: 2 additions & 1 deletion docs/flatten.md
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ is available under the key `dsym_folder` in `OutputGroupInfo`.
## rust_bindgen

<pre>
rust_bindgen(<a href="#rust_bindgen-name">name</a>, <a href="#rust_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_bindgen-cc_lib">cc_lib</a>, <a href="#rust_bindgen-clang_flags">clang_flags</a>, <a href="#rust_bindgen-header">header</a>)
rust_bindgen(<a href="#rust_bindgen-name">name</a>, <a href="#rust_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_bindgen-cc_lib">cc_lib</a>, <a href="#rust_bindgen-clang_flags">clang_flags</a>, <a href="#rust_bindgen-header">header</a>, <a href="#rust_bindgen-leak_symbols">leak_symbols</a>)
</pre>

Generates a rust source file from a cc_library and a header.
Expand All @@ -374,6 +374,7 @@ Generates a rust source file from a cc_library and a header.
| <a id="rust_bindgen-cc_lib"></a>cc_lib | The cc_library that contains the <code>.h</code> file. This is used to find the transitive includes. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="rust_bindgen-clang_flags"></a>clang_flags | Flags to pass directly to the clang executable. | List of strings | optional | <code>[]</code> |
| <a id="rust_bindgen-header"></a>header | The <code>.h</code> file to generate bindings for. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="rust_bindgen-leak_symbols"></a>leak_symbols | If True, <code>cc_lib</code> will be exposed and linked into all downstream consumers of the target vs. the <code>rust_library</code> directly consuming it. | Boolean | optional | <code>False</code> |


<a id="rust_bindgen_toolchain"></a>
Expand Down
3 changes: 2 additions & 1 deletion docs/rust_bindgen.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ toolchains following the instructions for [rust_bindgen_toolchain](#rust_bindgen
## rust_bindgen

<pre>
rust_bindgen(<a href="#rust_bindgen-name">name</a>, <a href="#rust_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_bindgen-cc_lib">cc_lib</a>, <a href="#rust_bindgen-clang_flags">clang_flags</a>, <a href="#rust_bindgen-header">header</a>)
rust_bindgen(<a href="#rust_bindgen-name">name</a>, <a href="#rust_bindgen-bindgen_flags">bindgen_flags</a>, <a href="#rust_bindgen-cc_lib">cc_lib</a>, <a href="#rust_bindgen-clang_flags">clang_flags</a>, <a href="#rust_bindgen-header">header</a>, <a href="#rust_bindgen-leak_symbols">leak_symbols</a>)
</pre>

Generates a rust source file from a cc_library and a header.
Expand All @@ -68,6 +68,7 @@ Generates a rust source file from a cc_library and a header.
| <a id="rust_bindgen-cc_lib"></a>cc_lib | The cc_library that contains the <code>.h</code> file. This is used to find the transitive includes. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="rust_bindgen-clang_flags"></a>clang_flags | Flags to pass directly to the clang executable. | List of strings | optional | <code>[]</code> |
| <a id="rust_bindgen-header"></a>header | The <code>.h</code> file to generate bindings for. | <a href="https://bazel.build/concepts/labels">Label</a> | required | |
| <a id="rust_bindgen-leak_symbols"></a>leak_symbols | If True, <code>cc_lib</code> will be exposed and linked into all downstream consumers of the target vs. the <code>rust_library</code> directly consuming it. | Boolean | optional | <code>False</code> |


<a id="rust_bindgen_toolchain"></a>
Expand Down
34 changes: 26 additions & 8 deletions examples/bindgen/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
load("@rules_cc//cc:defs.bzl", "cc_library")
load("@rules_rust//bindgen:defs.bzl", "rust_bindgen_library")
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test")

cc_library(
name = "simple",
srcs = ["simple.h"],
)

rust_bindgen_library(
name = "simple_bindgen",
bindgen_flags = [
"--allowlist-function=simple_.*",
"--allowlist-var=SIMPLE_.*",
],
cc_lib = ":simple",
header = "simple.h",
cc_lib = "//bindgen/simple",
header = "//bindgen/simple:simple.h",
leak_symbols = False,
)

rust_binary(
Expand All @@ -26,3 +22,25 @@ rust_test(
name = "simple_test",
crate = ":simple_example",
)

rust_bindgen_library(
name = "simple_leaked_bindgen",
bindgen_flags = [
"--allowlist-function=simple_.*",
"--allowlist-var=SIMPLE_.*",
],
cc_lib = "//bindgen/simple",
header = "//bindgen/simple:simple.h",
leak_symbols = True,
)

rust_binary(
name = "simple_leaked_example",
srcs = ["main_leaked.rs"],
deps = [":simple_leaked_bindgen"],
)

rust_test(
name = "simple_leaked_test",
crate = ":simple_leaked_example",
)
13 changes: 12 additions & 1 deletion examples/bindgen/main.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
//! rust_bindgen_library example consumer

fn simple_function() -> i64 {
unsafe { simple_bindgen::simple_function() }
}

fn main() {
println!("The value is {}!", simple_bindgen::SIMPLE_VALUE);
println!(
"The values are {} and {}!",
simple_bindgen::SIMPLE_VALUE,
simple_function()
);
}

#[cfg(test)]
mod test {
#[test]
fn do_the_test() {
assert_eq!(42, simple_bindgen::SIMPLE_VALUE);
assert_eq!(1337, super::simple_function());
}
}
22 changes: 22 additions & 0 deletions examples/bindgen/main_leaked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//! rust_bindgen_library example consumer

fn simple_function() -> i64 {
unsafe { simple_leaked_bindgen::simple_function() }
}

fn main() {
println!(
"The values are {} and {}!",
simple_leaked_bindgen::SIMPLE_VALUE,
simple_function()
);
}

#[cfg(test)]
mod test {
#[test]
fn do_the_test() {
assert_eq!(42, simple_leaked_bindgen::SIMPLE_VALUE);
assert_eq!(1337, super::simple_function());
}
}
5 changes: 0 additions & 5 deletions examples/bindgen/simple.h

This file was deleted.

15 changes: 15 additions & 0 deletions examples/bindgen/simple/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
load("@rules_cc//cc:defs.bzl", "cc_library")

exports_files(
[
"simple.h",
],
visibility = ["//bindgen:__pkg__"],
)

cc_library(
name = "simple",
srcs = ["simple.cc"],
hdrs = ["simple.h"],
visibility = ["//bindgen:__pkg__"],
)
3 changes: 3 additions & 0 deletions examples/bindgen/simple/simple.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "simple.h"

EXTERN_C const int64_t simple_function() { return 1337; }
16 changes: 16 additions & 0 deletions examples/bindgen/simple/simple.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef __SIMPLE_H_INCLUDE__
#define __SIMPLE_H_INCLUDE__

#ifdef __cplusplus
#define EXTERN_C extern "C"
#else
#define EXTERN_C
#endif

#include <stdint.h>

EXTERN_C const int64_t SIMPLE_VALUE = 42;

EXTERN_C const int64_t simple_function();

#endif
13 changes: 7 additions & 6 deletions rust/private/providers.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,13 @@ CrateGroupInfo = provider(
BuildInfo = provider(
doc = "A provider containing `rustc` build settings for a given Crate.",
fields = {
"dep_env": "File: extra build script environment varibles to be set to direct dependencies.",
"flags": "File: file containing additional flags to pass to rustc",
"link_flags": "File: file containing flags to pass to the linker",
"link_search_paths": "File: file containing search paths to pass to the linker",
"out_dir": "File: directory containing the result of a build script",
"rustc_env": "File: file containing additional environment variables to set for rustc.",
"compile_data": "Depset[File]: Compile data provided by the build script that was not copied into `out_dir`.",
"dep_env": "Optinal[File]: extra build script environment varibles to be set to direct dependencies.",
"flags": "Optional[File]: file containing additional flags to pass to rustc",
"link_flags": "Optional[File]: file containing flags to pass to the linker",
"link_search_paths": "Optional[File]: file containing search paths to pass to the linker",
"out_dir": "Optional[File]: directory containing the result of a build script",
"rustc_env": "Optional[File]: file containing additional environment variables to set for rustc.",
},
)

Expand Down
Loading
Loading