diff --git a/docs/markdown/snippets/rust-dynamic-std.md b/docs/markdown/snippets/rust-dynamic-std.md new file mode 100644 index 000000000000..63d4cfccd655 --- /dev/null +++ b/docs/markdown/snippets/rust-dynamic-std.md @@ -0,0 +1,8 @@ +## New experimental option `rust_dynamic_std` + +A new option `rust_dynamic_std` can be used to link Rust programs so +that they use a dynamic library for the Rust `libstd`. + +Right now, C ABI crates (corresponding to Rust crate types `cdylib` and +`staticlib`) cannot be produced if `rust_dynamic_std` is true, but this +may change in the future. diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index 24758866c6b5..7f68b0c549c5 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -2115,13 +2115,26 @@ def _link_library(libname: str, static: bool, bundle: bool = False): and dep.rust_crate_type == 'dylib' for dep in target_deps) - if target.rust_crate_type in {'dylib', 'proc-macro'} or has_rust_shared_deps: + if target.rust_crate_type in {'cdylib', 'staticlib'} \ + and target.get_option(OptionKey('rust_dynamic_std')): + # cdylib and staticlib crates always include a copy of the Rust + # libstd, therefore it is not possible to also link it dynamically. + # The options to avoid this (-Z staticlib-allow-rdylib-deps and + # -Z staticlib-prefer-dynamic) are not yet stable; alternatively, + # one could use "--emit obj" (implemented in the pull request at + # https://github.com/mesonbuild/meson/pull/11213) or "--emit rlib" + # (officially not recommended for linking with C programs). + raise MesonException('rust_dynamic_std does not support cdylib and staticlib crates yet') + + if target.rust_crate_type in {'dylib', 'proc-macro'} or has_rust_shared_deps \ + or target.get_option(OptionKey('rust_dynamic_std')): # add prefer-dynamic if any of the Rust libraries we link # against are dynamic or this is a dynamic library itself, # otherwise we'll end up with multiple implementations of libstd. args += ['-C', 'prefer-dynamic'] - if isinstance(target, build.SharedLibrary) or has_shared_deps: + if isinstance(target, build.SharedLibrary) or has_shared_deps \ + or target.get_option(OptionKey('rust_dynamic_std')): args += self.get_build_rpath_args(target, rustc) proc_macro_dylib_path = None diff --git a/mesonbuild/options.py b/mesonbuild/options.py index 1566f940c98c..aba40760e5a9 100644 --- a/mesonbuild/options.py +++ b/mesonbuild/options.py @@ -638,6 +638,7 @@ def add_to_argparse(self, name: str, parser: argparse.ArgumentParser, help_suffi (OptionKey('layout'), BuiltinOption(UserComboOption, 'Build directory layout', 'mirror', choices=['mirror', 'flat'])), (OptionKey('optimization'), BuiltinOption(UserComboOption, 'Optimization level', '0', choices=['plain', '0', 'g', '1', '2', '3', 's'])), (OptionKey('prefer_static'), BuiltinOption(UserBooleanOption, 'Whether to try static linking before shared linking', False)), + (OptionKey('rust_dynamic_std'), BuiltinOption(UserBooleanOption, 'Whether to link Rust programs to a dynamic libstd', False)), (OptionKey('stdsplit'), BuiltinOption(UserBooleanOption, 'Split stdout and stderr in test logs', True)), (OptionKey('strip'), BuiltinOption(UserBooleanOption, 'Strip targets on install', False)), (OptionKey('unity'), BuiltinOption(UserComboOption, 'Unity build', 'off', choices=['on', 'off', 'subprojects'])), diff --git a/test cases/rust/1 basic/meson.build b/test cases/rust/1 basic/meson.build index f422beb74857..00bd2124843d 100644 --- a/test cases/rust/1 basic/meson.build +++ b/test cases/rust/1 basic/meson.build @@ -6,6 +6,12 @@ e = executable('rust-program', 'prog.rs', ) test('rusttest', e) +e = executable('rust-dynamic', 'prog.rs', + override_options: {'rust_dynamic_std': true}, + install : true +) +test('rusttest-dynamic', e) + subdir('subdir') # this should fail due to debug_assert diff --git a/test cases/rust/1 basic/test.json b/test cases/rust/1 basic/test.json index 95e6ced7e4ba..3cbdefa78af8 100644 --- a/test cases/rust/1 basic/test.json +++ b/test cases/rust/1 basic/test.json @@ -3,6 +3,8 @@ {"type": "exe", "file": "usr/bin/rust-program"}, {"type": "pdb", "file": "usr/bin/rust-program"}, {"type": "exe", "file": "usr/bin/rust-program2"}, - {"type": "pdb", "file": "usr/bin/rust-program2"} + {"type": "pdb", "file": "usr/bin/rust-program2"}, + {"type": "exe", "file": "usr/bin/rust-dynamic"}, + {"type": "pdb", "file": "usr/bin/rust-dynamic"} ] }