mirror of
https://github.com/mesonbuild/meson.git
synced 2026-11-06 05:16:42 +00:00
cargo: apply profile to targets, via override_options
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
1 parent
b4b39dee4a
commit
c6cbfbbf68
6 files changed
+113
-5
No files matched your search
@@ -19,3 +19,6 @@ settings found in a Cargo `[profile]` section can be expressed natively:
|
||||
The remaining Cargo profile keys map onto existing built-in options:
|
||||
`opt-level` to `optimization`, `debug` to `debug`, `debug-assertions`
|
||||
to `b_ndebug` and `lto` to `b_lto`.
|
||||
|
||||
The Cargo workspace object will also add these automatically based on
|
||||
the value of another new option, `rust_cargo_profile`.
|
||||
@@ -40,9 +40,10 @@ if T.TYPE_CHECKING:
|
||||
from .. import mparser
|
||||
from typing_extensions import Literal
|
||||
|
||||
from .manifest import Dependency
|
||||
from .manifest import Dependency, Profile
|
||||
from ..environment import Environment
|
||||
from ..compilers.rust import RustCompiler
|
||||
from ..options import ElementaryOptionValues
|
||||
|
||||
RUST_ABI = Literal['rust', 'c', 'proc-macro']
|
||||
|
||||
@@ -282,6 +283,8 @@ class Interpreter:
|
||||
self.packages: T.Dict[PackageKey, PackageState] = {}
|
||||
# Map subdir to workspace
|
||||
self.workspaces: T.Dict[str, WorkspaceState] = {}
|
||||
# [profile] tables from the top-level Cargo.toml
|
||||
self.profiles: T.Dict[str, Profile] = {}
|
||||
# Files that should trigger a reconfigure if modified
|
||||
self.build_def_files: T.List[str] = []
|
||||
# Cargo packages
|
||||
@@ -321,9 +324,8 @@ class Interpreter:
|
||||
# [patch] only takes effect in the top-level Cargo.toml
|
||||
for warning in validate_patch(ws.workspace.patch, ws.packages_to_member):
|
||||
mlog.warning(warning)
|
||||
if ws.workspace.profile:
|
||||
mlog.warning('[profile] entries are not implemented yet')
|
||||
|
||||
self.profiles = ws.workspace.profile
|
||||
self._prepare_entry_point(ws)
|
||||
return ws
|
||||
|
||||
@@ -350,6 +352,45 @@ class Interpreter:
|
||||
raise MesonException('argument to package() cannot be a subproject')
|
||||
return ws.packages[path]
|
||||
|
||||
def _selected_profile(self, override: T.Optional[ElementaryOptionValues] = None) -> T.Optional[str]:
|
||||
"""Resolve the rust_cargo_profile selection to a Cargo profile name.
|
||||
override takes precedence over the rust_cargo_profile option, and
|
||||
comes from a target's own override_options."""
|
||||
optstore = self.environment.coredata.optstore
|
||||
if override is not None:
|
||||
selection = override
|
||||
else:
|
||||
try:
|
||||
selection = optstore.get_value_for('rust_cargo_profile')
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
assert isinstance(selection, str)
|
||||
if selection == 'none':
|
||||
return None
|
||||
if selection != 'from_buildtype':
|
||||
return selection
|
||||
|
||||
buildtype = optstore.get_value_for('buildtype')
|
||||
if buildtype in {'plain', 'custom'}:
|
||||
return None
|
||||
return 'dev' if buildtype == 'debug' else 'release'
|
||||
|
||||
def get_override_options(self, pkg: PackageState, for_machine: MachineChoice,
|
||||
profile: str | None = None) -> T.Dict[str, ElementaryOptionValues]:
|
||||
"""Return override_options implied by the Cargo manifest: the package
|
||||
edition (rust_std) and the options implied by a [profile], using
|
||||
``profile`` if not None or otherwise rust_cargo_profile selects."""
|
||||
opts: T.Dict[str, ElementaryOptionValues] = {
|
||||
'rust_std': pkg.manifest.package.edition,
|
||||
}
|
||||
profile_name = self._selected_profile(profile)
|
||||
if profile_name is not None and self.profiles is not None:
|
||||
if (profile_obj := self.profiles.get(profile_name)) is not None:
|
||||
opts.update(profile_obj.to_meson_options(for_machine))
|
||||
|
||||
return opts
|
||||
|
||||
def interpret(self, subdir: str, project_root: T.Optional[str] = None) -> mparser.CodeBlockNode:
|
||||
filename = os.path.join(self.environment.source_dir, subdir, 'Cargo.toml')
|
||||
build = builder.Builder(filename)
|
||||
|
||||
@@ -23,6 +23,7 @@ if T.TYPE_CHECKING:
|
||||
|
||||
from . import raw
|
||||
from .raw import EDITION, CRATE_TYPE, LINT_LEVEL
|
||||
from ..options import ElementaryOptionValues
|
||||
from ..wrap.wrap import PackageDefinition
|
||||
|
||||
# Copied from typeshed. Blarg that they don't expose this
|
||||
@@ -550,6 +551,36 @@ class Profile:
|
||||
profile.lto_mode = 'thin' if raw_profile.get('lto') == 'thin' else 'default'
|
||||
return profile
|
||||
|
||||
def to_meson_options(self, for_machine: MachineChoice) -> T.Dict[str, ElementaryOptionValues]:
|
||||
"""Map the profile onto Meson option values, only for keys that are set.
|
||||
For the build machine, the [build-override] settings are layered on top
|
||||
(Cargo applies those to build scripts, proc macros and their deps)."""
|
||||
opts: T.Dict[str, ElementaryOptionValues] = {}
|
||||
if self.opt_level is not None:
|
||||
# Meson's 'optimization' has no 'z'; fall back to 's'.
|
||||
opts['optimization'] = 's' if self.opt_level == 'z' else self.opt_level
|
||||
if self.debug is not None:
|
||||
opts['debug'] = self.debug
|
||||
# Meson only handles strip at install time
|
||||
if self.debug_assertions is not None:
|
||||
# note inverted polarity
|
||||
opts['b_ndebug'] = 'false' if self.debug_assertions else 'true'
|
||||
if self.overflow_checks is not None:
|
||||
opts['rust_overflow_checks'] = self.overflow_checks
|
||||
if self.lto is not None:
|
||||
opts['b_lto'] = self.lto
|
||||
if self.lto_mode is not None:
|
||||
opts['b_lto_mode'] = self.lto_mode
|
||||
if self.panic is not None:
|
||||
opts['rust_panic'] = self.panic
|
||||
if self.incremental is not None:
|
||||
opts['rust_incremental'] = self.incremental
|
||||
if self.codegen_units is not None:
|
||||
opts['rust_codegen_units'] = self.codegen_units
|
||||
if for_machine is MachineChoice.BUILD and self.build_override is not None:
|
||||
opts.update(self.build_override.to_meson_options(for_machine))
|
||||
return opts
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Manifest:
|
||||
|
||||
@@ -404,6 +404,13 @@ class RustCompiler(Compiler):
|
||||
'Directory used to store incremental compilation data (empty=pick a default under the build directory)',
|
||||
'')
|
||||
|
||||
key = self.form_compileropt_key('cargo_profile')
|
||||
opts[key] = options.UserComboOption(
|
||||
self.make_option_name(key),
|
||||
'Cargo [profile] to apply when building Cargo subprojects',
|
||||
'from_buildtype',
|
||||
choices=['none', 'dev', 'release', 'from_buildtype'])
|
||||
|
||||
return opts
|
||||
|
||||
def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
|
||||
|
||||
@@ -391,7 +391,11 @@ class RustPackage(RustCrate):
|
||||
self.package.get_rustc_args(state.environment, state.subdir, kwargs['native'])
|
||||
kwargs['rust_args'].extend(rust_args)
|
||||
|
||||
kwargs['override_options'].setdefault('rust_std', self.package.manifest.package.edition)
|
||||
profile = kwargs['override_options'].get('rust_cargo_profile')
|
||||
assert profile is None or isinstance(profile, str), 'for mypy'
|
||||
overrides = self.rust_ws.interpreter.cargo.get_override_options(self.package, kwargs['native'], profile)
|
||||
for key, value in overrides.items():
|
||||
kwargs['override_options'].setdefault(key, value)
|
||||
|
||||
def _library_method(self, state: ModuleState, args: T.Tuple[
|
||||
T.Optional[T.Union[str, StructuredSources]],
|
||||
|
||||
+23
-1
@@ -14,7 +14,7 @@ from mesonbuild.cargo.interpreter import load_cargo_lock
|
||||
from mesonbuild.cargo.manifest import Dependency, Lint, Manifest, Package, Workspace, validate_patch
|
||||
from mesonbuild.cargo.toml import load_toml
|
||||
from mesonbuild.cargo.version import api, cargo_parse, SemVer
|
||||
from mesonbuild.mesonlib import MesonException
|
||||
from mesonbuild.mesonlib import MachineChoice, MesonException
|
||||
|
||||
|
||||
class CargoVersionTest(unittest.TestCase):
|
||||
@@ -746,6 +746,28 @@ class CargoTomlTest(unittest.TestCase):
|
||||
|
||||
self.assertEqual(manifest.profile['dev'].opt_level, 's')
|
||||
|
||||
def test_cargo_toml_profile_to_meson_options(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
fname = os.path.join(tmpdir, 'Cargo.toml')
|
||||
with open(fname, 'w', encoding='utf-8') as f:
|
||||
f.write(self.CARGO_TOML_PROFILE)
|
||||
manifest = Manifest.from_raw(load_toml(fname), 'Cargo.toml')
|
||||
|
||||
release = manifest.profile['release']
|
||||
host = release.to_meson_options(MachineChoice.HOST)
|
||||
self.assertEqual(host['optimization'], '3')
|
||||
self.assertEqual(host['rust_codegen_units'], 16)
|
||||
self.assertEqual(host['b_lto_mode'], 'thin')
|
||||
self.assertEqual(host['rust_panic'], 'abort')
|
||||
|
||||
build = release.to_meson_options(MachineChoice.BUILD)
|
||||
# On the build machine the [build-override] keys are layered on top.
|
||||
self.assertEqual(build['optimization'], '0')
|
||||
self.assertEqual(build['rust_codegen_units'], 256)
|
||||
# keys not set by build-override stay from the base profile
|
||||
self.assertEqual(build['b_lto_mode'], 'thin')
|
||||
self.assertEqual(build['rust_panic'], 'abort')
|
||||
|
||||
def test_validate_patch(self) -> None:
|
||||
# packages_to_member values are normalized with os.path.normpath (see
|
||||
# _load_workspace_member), so do the same here
|
||||
|
||||
Reference in new issue
Block a user