Skip to content

Support linking Rust into C++ as rlibs #14215

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

Open
lf- opened this issue Feb 1, 2025 · 4 comments
Open

Support linking Rust into C++ as rlibs #14215

lf- opened this issue Feb 1, 2025 · 4 comments

Comments

@lf-
Copy link
Contributor

lf- commented Feb 1, 2025

Yes, this is unsupported, but it is effectively critical for usable linking to Rust targets in C++ static libs without substantial pain since without the ability to link rlibs, you cannot combine C++ targets arbitrarily anymore if there is any rust in-tree. One of the unintended consequences of #11722 is that it prevents linking rlibs into C++ targets.

Specifically, you cannot combine two static_library C++ targets together if they depend on rust staticlib crates due to duplicate copies of libstd or other crates. The linking of libstd and other stuff from the sysroot must be deferred to the end at the time of linking the executable.

There's a few documented hacks at rust-lang/rust#73632 and bazel/buck2 rules_rust implement rust linking of staticlibs via these methods.

The following is possible but it still needs to correctly generate the link args to link to libstd and the sysroot as a whole, which is not yet a thing.

diff --git a/mesonbuild/build.py b/mesonbuild/build.py
index 460ed549b..8d6a7e6cb 100644
--- a/mesonbuild/build.py
+++ b/mesonbuild/build.py
@@ -1490,8 +1490,6 @@ class BuildTarget(Target):
 
     def check_can_link_together(self, t: BuildTargetTypes) -> None:
         links_with_rust_abi = isinstance(t, BuildTarget) and t.uses_rust_abi()
-        if not self.uses_rust() and links_with_rust_abi:
-            raise InvalidArguments(f'Try to link Rust ABI library {t.name!r} with a non-Rust target {self.name!r}')
         if self.for_machine is not t.for_machine and (not links_with_rust_abi or t.rust_crate_type != 'proc-macro'):
             msg = f'Tried to tied to mix a {t.for_machine} library ("{t.name}") with a {self.for_machine} target "{self.name}"'
             if self.environment.is_cross_build():
@lf-
Copy link
Contributor Author

lf- commented Feb 1, 2025

See also: rust-lang/rust#111594 (comment)

@lf-
Copy link
Contributor Author

lf- commented Feb 1, 2025

This would be a solution to #8828, but it's also desirable and kind of necessary to be able to link dylibs to c++, not just cdylibs.

@bonzini
Copy link
Collaborator

bonzini commented Feb 4, 2025

One possibility could be to add a dependency('rust-std') which is nothing but an empty staticlib, and then require it whenever an rlib is included in the linker command line (and the language is not rust).

Separate from this is the question of how to do -C prefer-dynamic, which most distros would like to use when building packages. I think this should be a Meson built-in option:

  • if set to false, nothing happens.
  • if set to true, rustc linking command lines gain -C prefer-dynamic.

Furthermore, staticlibs and dependency('rust-std') are affected when the option is set to true:

  • both require rustc nightly
  • -Z staticlib-allow-rdylib-deps -Z staticlib-prefer-dynamic are passed when building staticlibs
  • dependency('rust-std') includes linker flags corresponding to the output of rustc --print native-static-libs /dev/null --crate-type staticlib -Z staticlib-prefer-dynamic

--emit obj would be usable as well, but the only way to find the path to libstd on non-nightly is to parse --print link-args by hand. :/

More information:

@lf-
Copy link
Contributor Author

lf- commented Feb 4, 2025

Strongly agreed. I think you're absolutely correct on this; the staticlib targets are primarily busted for having libstd in them. Though another thing that's desirable is being able to link rust dylibs directly into c++ without an intermediary cdylib crate, since the rust symbols are expected to be used by other crates so they need to be in a rust abi target (so if you're following the "rules" you need 1 dylib, 1 cdylib, 1 c++ shared_library), but the crate also needs to export symbols to c++.

The most ideal thing for my use case is actually if we could produce c++ targets which are rust dylib targets from the perspective of rustc: they can export both c++ and rust symbols to downstream dylib/rlib crates and c++ libs and can link internally between their c++ and rust code. Then if you build them in static mode, they can export rust symbols as if as an rlib as well, ideally. This may be overly optimistic and maybe I will get my unicorn instead; perhaps what I would have to do for that is turn the c++ target into a staticlib shoved into a rust abi target that's either dynamic or static depending on overall build mode, but we still would need the ability for meson to link rust abi targets directly into c++.

There may need to be some adjustment of how the libstd itself is distributed so it is not part of the main rustc package outputs: rust-lang/rust#136373

bonzini added a commit to bonzini/meson that referenced this issue Feb 4, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 5, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 5, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 5, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 5, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 5, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 13, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Feb 23, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
bonzini added a commit to bonzini/meson that referenced this issue Mar 7, 2025
As an initial implementation, simply adding "-C prefer-dynamic" works
for binary crates (as well as dylib and proc-macro that already used it).
In the future this could be extended to other crate types.  For more
information see the comment in the changed file, as well as
mesonbuild#8828 and
mesonbuild#14215.

Signed-off-by: Paolo Bonzini <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants