diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index 9ab2066fc27f..da9fc8d445f8 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -305,6 +305,7 @@ or compiler being used: | 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.9.0)* | +| rust_nightly | auto | enabled, disabled, auto | Nightly Rust compiler (enabled=required, disabled=don't use nightly feature, auto=use nightly feature if available) *(Added in 1.10.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/mesonbuild/cargo/interpreter.py b/mesonbuild/cargo/interpreter.py index 241009a087c9..04a0adeed9e9 100644 --- a/mesonbuild/cargo/interpreter.py +++ b/mesonbuild/cargo/interpreter.py @@ -139,6 +139,7 @@ def _create_package(self, pkg: PackageState, build: builder.Builder, subdir: str ] ast += self._create_dependencies(pkg, build) ast += self._create_meson_subdir(build) + ast += self._create_env_args(pkg, build, subdir) if pkg.manifest.lib: crate_type = pkg.manifest.lib.crate_type @@ -596,6 +597,56 @@ def _create_meson_subdir(self, build: builder.Builder) -> T.List[mparser.BaseNod build.block([build.function('subdir', [build.string('meson')])])) ] + def _pkg_common_env(self, pkg: PackageState, subdir: str) -> T.Dict[str, str]: + # Common variables for build.rs and crates + # https://doc.rust-lang.org/cargo/reference/environment-variables.html + # OUT_DIR is the directory where build.rs generate files. In our case, + # it's the directory where meson/meson.build places generated files. + out_dir = os.path.join(self.environment.build_dir, subdir, 'meson') + os.makedirs(out_dir, exist_ok=True) + version_arr = pkg.manifest.package.version.split('.') + version_arr += ['' * (4 - len(version_arr))] + return { + 'OUT_DIR': out_dir, + 'CARGO_MANIFEST_DIR': os.path.join(self.environment.source_dir, subdir), + 'CARGO_MANIFEST_PATH': os.path.join(self.environment.source_dir, subdir, 'Cargo.toml'), + 'CARGO_PKG_VERSION': pkg.manifest.package.version, + 'CARGO_PKG_VERSION_MAJOR': version_arr[0], + 'CARGO_PKG_VERSION_MINOR': version_arr[1], + 'CARGO_PKG_VERSION_PATCH': version_arr[2], + 'CARGO_PKG_VERSION_PRE': version_arr[3], + 'CARGO_PKG_AUTHORS': ','.join(pkg.manifest.package.authors), + 'CARGO_PKG_NAME': pkg.manifest.package.name, + # FIXME: description can contain newlines which breaks ninja. + #'CARGO_PKG_DESCRIPTION': pkg.manifest.package.description or '', + 'CARGO_PKG_HOMEPAGE': pkg.manifest.package.homepage or '', + 'CARGO_PKG_REPOSITORY': pkg.manifest.package.repository or '', + 'CARGO_PKG_LICENSE': pkg.manifest.package.license or '', + 'CARGO_PKG_LICENSE_FILE': pkg.manifest.package.license_file or '', + 'CARGO_PKG_RUST_VERSION': pkg.manifest.package.rust_version or '', + 'CARGO_PKG_README': pkg.manifest.package.readme or '', + } + + def _create_env_args(self, pkg: PackageState, build: builder.Builder, subdir: str) -> T.List[mparser.BaseNode]: + host_rustc = T.cast('RustCompiler', self.environment.coredata.compilers[MachineChoice.HOST]['rust']) + enable_env_set_args = host_rustc.enable_env_set_args() + if enable_env_set_args is None: + return [build.assign(build.array([]), 'env_args')] + # https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates + env_dict = self._pkg_common_env(pkg, subdir) + env_dict.update({ + 'CARGO_CRATE_NAME': fixup_meson_varname(pkg.manifest.package.name), + #FIXME: TODO + #CARGO_BIN_NAME + #CARGO_BIN_EXE_ + #CARGO_PRIMARY_PACKAGE + #CARGO_TARGET_TMPDIR + }) + env_args: T.List[mparser.BaseNode] = [build.string(a) for a in enable_env_set_args] + for k, v in env_dict.items(): + env_args += [build.string('--env-set'), build.string(f'{k}={v}')] + return [build.assign(build.array(env_args), 'env_args')] + def _create_lib(self, pkg: PackageState, build: builder.Builder, lib_type: Literal['rust', 'c', 'proc-macro'], static: bool = False, shared: bool = False) -> T.List[mparser.BaseNode]: @@ -616,6 +667,7 @@ def _create_lib(self, pkg: PackageState, build: builder.Builder, build.identifier('features_args'), build.identifier(_extra_args_varname()), build.identifier('system_deps_args'), + build.identifier('env_args'), ] dependencies.append(build.identifier(_extra_deps_varname())) diff --git a/mesonbuild/compilers/rust.py b/mesonbuild/compilers/rust.py index c0acf92adff5..fadf9772ff8f 100644 --- a/mesonbuild/compilers/rust.py +++ b/mesonbuild/compilers/rust.py @@ -104,6 +104,7 @@ def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoic self.native_static_libs: T.List[str] = [] self.is_beta = '-beta' in full_version self.is_nightly = '-nightly' in full_version + self.allow_nightly = False # Will be set in sanity_check() self.has_check_cfg = version_compare(version, '>=1.80.0') def needs_static_linker(self) -> bool: @@ -144,6 +145,14 @@ def sanity_check(self, work_dir: str, environment: Environment) -> None: raise EnvironmentException(f'Rust compiler {self.name_string()} cannot compile programs.') self._native_static_libs(work_dir, source_name) self.run_sanity_check(environment, [output_name], work_dir) + # Check if we are allowed to use nightly features. + # This is done here because it's the only place we have access to + # environment object, and sanity_check() is called after the compiler + # options have been initialized. + nightly_opt = self.get_compileropt_value('nightly', environment, None) + if nightly_opt == 'enabled' and not self.is_nightly: + raise EnvironmentException(f'Rust compiler {self.name_string()} is not a nightly compiler as required by the "nightly" option.') + self.allow_nightly = nightly_opt != 'disabled' and self.is_nightly def _native_static_libs(self, work_dir: str, source_name: str) -> None: # Get libraries needed to link with a Rust staticlib @@ -288,6 +297,12 @@ def get_options(self) -> MutableKeyedOptionDictType: 'Whether to link Rust build targets to a dynamic libstd', False) + key = self.form_compileropt_key('nightly') + opts[key] = options.UserFeatureOption( + self.make_option_name(key), + "Nightly Rust compiler (enabled=required, disabled=don't use nightly feature, auto=use nightly feature if available)", + 'auto') + return opts def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]: @@ -384,6 +399,15 @@ def get_rustdoc(self, env: 'Environment') -> T.Optional[RustdocTestCompiler]: self.is_cross, self.info, full_version=self.full_version, linker=self.linker, rustc=self) + def enable_env_set_args(self) -> T.Optional[T.List[str]]: + '''Extra arguments to enable --env-set support in rustc. + Returns None if not supported. + ''' + if version_compare(self.version, '>= 1.76') and self.allow_nightly: + return ['-Z', 'unstable-options'] + return None + + class ClippyRustCompiler(RustCompiler): """Clippy is a linter that wraps Rustc.