-
Notifications
You must be signed in to change notification settings - Fork 644
Add support for Rust ABI dynamic libraries #4179
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
base: main
Are you sure you want to change the base?
Changes from all commits
dce8357
69c9424
9ea36c6
328b197
20aeb2e
827755c
699208e
e2b071d
df9ca0b
8456bf7
663af41
f53b392
8ffb4ca
8da0e14
66fbcc4
315ada9
e4365f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,8 +159,29 @@ def _rust_static_library_impl(ctx): | |
| """ | ||
| return _rust_library_common(ctx, "staticlib") | ||
|
|
||
| def _rust_shared_library_impl(ctx): | ||
| """The implementation of the `rust_shared_library` rule. | ||
| def _rust_dylib_library_impl(ctx): | ||
| """The implementation of the `rust_dylib_library` rule. | ||
|
|
||
| This rule provides CcInfo, so it can be used everywhere Bazel expects | ||
| rules_cc. | ||
|
|
||
| **Note**: When dynamic libraries are listed as dependencies for other Rust | ||
| binaries they can induce errors from multiply defined symbols, causing | ||
| linker errors in rustc. Some libraries in the dependency graph may need to | ||
| be converted to dynamic libraries, and/or have the standard library | ||
| dynamically linked (`link_std_dylib`) to avoid this. These rules do not | ||
| attempt to resolve these linking issues automatically. | ||
|
|
||
| Args: | ||
| ctx (ctx): The rule's context object | ||
|
|
||
| Returns: | ||
| list: A list of providers. | ||
| """ | ||
| return _rust_library_common(ctx, "dylib") | ||
|
|
||
| def _rust_cdylib_library_impl(ctx): | ||
| """The implementation of the `rust_cdylib_library` rule. | ||
|
|
||
| This rule provides CcInfo, so it can be used everywhere Bazel | ||
| expects rules_cc. | ||
|
|
@@ -987,6 +1008,15 @@ _RUST_TEST_ATTRS = { | |
| "env_inherit": attr.string_list( | ||
| doc = "Specifies additional environment variables to inherit from the external environment when the test is executed by bazel test.", | ||
| ), | ||
| "link_std_dylib": attr.bool( | ||
| mandatory = False, | ||
| default = False, | ||
| doc = dedent("""\ | ||
| Flag to dynamically link the standard library as a Rust dylib .so object when building this test. | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. don't we also need this for rust_binary?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, it's there! |
||
|
|
||
| Default is false. This is often required when testing a target that depends on a Rust ABI dylib. | ||
| """), | ||
| ), | ||
| "use_libtest_harness": attr.bool( | ||
| mandatory = False, | ||
| default = True, | ||
|
|
@@ -1082,6 +1112,53 @@ rust_library = rule( | |
| """), | ||
| ) | ||
|
|
||
| rust_dylib_library = rule( | ||
| implementation = _rust_dylib_library_impl, | ||
| provides = COMMON_PROVIDERS, | ||
| attrs = _COMMON_ATTRS | { | ||
| "disable_pipelining": attr.bool( | ||
| default = False, | ||
| doc = dedent("""\ | ||
| Disables pipelining for this rule if it is globally enabled. | ||
| This will cause this rule to not produce a `.rmeta` file and all the dependent | ||
| crates will instead use the `.rlib` file. | ||
| """), | ||
| ), | ||
| "link_std_dylib": attr.bool( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have use cases at all for
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, that's totally fair. AFAICT, Rust ABI dylibs will just be depended on by Rust targets, which would require |
||
| mandatory = False, | ||
| default = True, | ||
| doc = dedent("""\ | ||
| Flag to dynamically link the standard library as a Rust dylib .so object when building this library. | ||
|
|
||
| Default is true. This is typically required for Rust ABI dylibs so that the stdlib is shared | ||
| with the binary that loads them, avoiding duplicate symbols. | ||
| """), | ||
| ), | ||
| }, | ||
| fragments = ["cpp"], | ||
| toolchains = [ | ||
| str(Label("//rust:toolchain_type")), | ||
| config_common.toolchain_type("@bazel_tools//tools/cpp:toolchain_type", mandatory = False), | ||
| ], | ||
| doc = dedent("""\ | ||
| Builds a shared library using the unstable Rust ABI. | ||
|
|
||
| This library can be depended on by other Rust targets via --extern, | ||
| making it suitable for splitting a Rust project into separately compiled | ||
| dynamic libraries. Note that the Rust ABI is not stable across compiler | ||
| versions. | ||
|
|
||
| This rule provides CcInfo, so it can be used everywhere Bazel expects `rules_cc`. | ||
|
|
||
| **Note**: When dynamic libraries are listed as dependencies for other Rust | ||
| binaries they can induce errors from multiply defined symbols, causing | ||
| linker errors in rustc. Some libraries in the dependency graph may need to | ||
| be converted to dynamic libraries, and/or have the standard library | ||
| dynamically linked (`link_std_dylib`) to avoid this. These rules do not | ||
| attempt to resolve these linking issues automatically. | ||
| """), | ||
| ) | ||
|
|
||
| def _resolve_platform(settings, attr): | ||
| """Resolve the platform label for a transition, adding @ prefix if needed. | ||
|
|
||
|
|
@@ -1158,8 +1235,8 @@ _rust_shared_library_transition = transition( | |
| ], | ||
| ) | ||
|
|
||
| rust_shared_library = rule( | ||
| implementation = _rust_shared_library_impl, | ||
| rust_cdylib_library = rule( | ||
| implementation = _rust_cdylib_library_impl, | ||
| attrs = _COMMON_ATTRS | _PLATFORM_ATTRS | _EXPERIMENTAL_USE_CC_COMMON_LINK_ATTRS, | ||
| fragments = ["cpp"], | ||
| cfg = _rust_shared_library_transition, | ||
|
|
@@ -1172,7 +1249,7 @@ rust_shared_library = rule( | |
| rust_common.test_crate_info, | ||
| ], | ||
| doc = dedent("""\ | ||
| Builds a Rust shared library. | ||
| Builds a C ABI Rust shared library. | ||
|
|
||
| This shared library will contain all transitively reachable crates and native objects. | ||
| It is meant to be used when producing an artifact that is then consumed by some other build system | ||
|
|
@@ -1226,6 +1303,15 @@ _RUST_BINARY_ATTRS = { | |
| more complicated debugger attachment. | ||
| """), | ||
| ), | ||
| "link_std_dylib": attr.bool( | ||
| mandatory = False, | ||
| default = False, | ||
| doc = dedent("""\ | ||
| Flag to dynamically link the standard library as a Rust dylib .so object when building this binary. | ||
|
|
||
| Default is false. This is often required when building a binary that depends on a Rust ABI dylib. | ||
| """), | ||
| ), | ||
| "linker_script": attr.label( | ||
| doc = dedent("""\ | ||
| Link script to forward into linker via rustc options. | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,7 +43,7 @@ def make_libstd_and_allocator_ccinfo( | |
| feature_configuration, | ||
| label, | ||
| actions, | ||
| experimental_link_std_dylib, | ||
| link_std_dylib, | ||
| rust_std, | ||
| allocator_library, | ||
| std = "std"): | ||
|
|
@@ -54,7 +54,7 @@ def make_libstd_and_allocator_ccinfo( | |
| feature_configuration (feature_configuration): feature_configuration to be queried. | ||
| label (Label): The rule's label. | ||
| actions: The rule's ctx.actions object. | ||
| experimental_link_std_dylib (boolean): The value of the standard library's `_experimental_link_std_dylib(ctx)`. | ||
| link_std_dylib (boolean): If the standard library should be included as a dylib. | ||
| rust_std: The Rust standard library. | ||
| allocator_library (struct): The target to use for providing allocator functions. | ||
| This should be a struct with either: | ||
|
|
@@ -82,6 +82,9 @@ def make_libstd_and_allocator_ccinfo( | |
| """).format(label, rust_std)) | ||
| rust_stdlib_info = rust_std[rust_common.stdlib_info] | ||
|
|
||
| if link_std_dylib and (not rust_stdlib_info.std_dylib or not cc_toolchain): | ||
| return None | ||
|
|
||
| if rust_stdlib_info.self_contained_files: | ||
| compilation_outputs = cc_common.create_compilation_outputs( | ||
| objects = depset(rust_stdlib_info.self_contained_files), | ||
|
|
@@ -183,7 +186,7 @@ def make_libstd_and_allocator_ccinfo( | |
| order = "topological", | ||
| ) | ||
|
|
||
| if experimental_link_std_dylib: | ||
| if link_std_dylib: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this flag no longer experimental now?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, less that it's not experimental and more that it's now a computed quantity/property as a function of the toolchain-level I opted to try and rename things so that the |
||
| # std dylib has everything so that we do not need to include all std_files | ||
| std_inputs = depset( | ||
| [cc_common.create_library_to_link( | ||
|
|
@@ -264,20 +267,23 @@ def _rust_allocator_libraries_impl(ctx): | |
|
|
||
| toolchain = find_toolchain(ctx) | ||
|
|
||
| def make_cc_info(info, std): | ||
| def make_cc_info(info, std, link_std_dylib): | ||
| return toolchain.make_libstd_and_allocator_ccinfo( | ||
| ctx.label, | ||
| ctx.actions, | ||
| struct(allocator_libraries_impl_info = info), | ||
| std, | ||
| link_std_dylib, | ||
| ) | ||
|
|
||
| providers = [AllocatorLibrariesInfo( | ||
| allocator_library = allocator_library, | ||
| global_allocator_library = global_allocator_library, | ||
| libstd_and_allocator_ccinfo = make_cc_info(allocator_library, "std"), | ||
| libstd_and_global_allocator_ccinfo = make_cc_info(global_allocator_library, "std"), | ||
| nostd_and_global_allocator_ccinfo = make_cc_info(global_allocator_library, "no_std_with_alloc"), | ||
| libstd_and_allocator_ccinfo = make_cc_info(allocator_library, "std", False), | ||
| libstd_and_global_allocator_ccinfo = make_cc_info(global_allocator_library, "std", False), | ||
| nostd_and_global_allocator_ccinfo = make_cc_info(global_allocator_library, "no_std_with_alloc", False), | ||
| libstd_dylib_and_allocator_ccinfo = make_cc_info(allocator_library, "std", True), | ||
| libstd_dylib_and_global_allocator_ccinfo = make_cc_info(global_allocator_library, "std", True), | ||
| )] | ||
|
|
||
| return providers | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.