diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index ffbab47d879d..6c4cd189e7bc 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -290,6 +290,7 @@ or compiler being used: | cpp_thread_count | 4 | integer value ≥ 0 | Number of threads to use with emcc when using threads | | cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against | | fortran_std | none | [none, legacy, f95, f2003, f2008, f2018] | Fortran language standard to use | +| rust_dynamic_std | false | true, false | Whether to link dynamically to the Rust standard library *(Added in 1.8.0)* | | cuda_ccbindir | | filesystem path | CUDA non-default toolchain directory to use (-ccbin) *(Added in 0.57.1)* | The default values of `c_winlibs` and `cpp_winlibs` are in 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/compilers/rust.py b/mesonbuild/compilers/rust.py index 2d018400f228..016ebabaac55 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -238,7 +238,11 @@ def get_options(self) -> MutableKeyedOptionDictType: self.form_compileropt_key('std'), 'Rust edition to use', ['none', '2015', '2018', '2021', '2024'], - 'none'),)) + 'none'), + self.create_option(options.UserBooleanOption, + self.form_compileropt_key('dynamic_std'), + 'Whether to link Rust programs to a dynamic libstd', + False))) def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: # Rust doesn't have dependency compile arguments so simply return 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"} ] }