Skip to content

Commit a0807a3

Browse files
committed
cargo: implement machine-specific dependency tracking
Change the dependency resolution code to take a MachineChoice as an argument. Create build- and/or host-side configurations through the machines_from() method in Manifest.
1 parent 03bc899 commit a0807a3

File tree

3 files changed

+82
-42
lines changed

3 files changed

+82
-42
lines changed

docs/markdown/Wrap-dependency-system-manual.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,10 @@ Some naming conventions need to be respected:
364364
This is typically used as `extra_deps += dependency('foo')`.
365365
- Since *1.10.0* the `features` variable is an array of enabled features for the subproject.
366366

367+
Note that currently `meson/meson.build` is only evaluated once even if a given
368+
dependency is needed for both the build and host machine. This should rarely be
369+
a problem, but it should be kept in mind to avoid problems when cross compiling.
370+
367371
Since *1.5.0* Cargo wraps can also be provided with `Cargo.lock` file at the root
368372
of (sub)project source tree. Meson will automatically load that file and convert
369373
it into a series of wraps definitions.

mesonbuild/cargo/interpreter.py

Lines changed: 57 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,11 @@ def interpret_package(self, manifest: Manifest, build: builder.Builder, subdir:
138138
else:
139139
pkg, cached = self._fetch_package(manifest.package.name, manifest.package.api)
140140
if not cached:
141-
self._prepare_package(pkg)
142-
# This is an entry point, always enable the 'default' feature.
143-
# FIXME: We should have a Meson option similar to `cargo build --no-default-features`
144-
self._enable_feature(pkg, 'default')
141+
for machine in pkg.manifest.machines_from(MachineChoice.HOST):
142+
self._prepare_package(pkg, machine)
143+
# This is an entry point, always enable the 'default' feature.
144+
# FIXME: We should have a Meson option similar to `cargo build --no-default-features`
145+
self._enable_feature(pkg, 'default', machine)
145146
ast += self._create_project(pkg.manifest.package.name, pkg, build)
146147
ast.append(build.assign(build.function('import', [build.string('rust')]), 'rust'))
147148
ast += self._create_package(pkg, build, subdir)
@@ -186,6 +187,8 @@ def _create_package(self, pkg: PackageState, build: builder.Builder, subdir: str
186187

187188
if pkg.manifest.lib:
188189
for crate_type in pkg.manifest.lib.crate_type:
190+
if crate_type == 'proc-macro' and machine == MachineChoice.HOST:
191+
continue
189192
ast.extend(self._create_lib(pkg, build, crate_type, machine))
190193

191194
return ast
@@ -199,7 +202,8 @@ def interpret_workspace(self, workspace: Workspace, build: builder.Builder, subd
199202
if not ws.required_members:
200203
for member in ws.workspace.default_members:
201204
pkg = self._require_workspace_member(ws, member)
202-
self._prepare_package(pkg)
205+
for machine in pkg.manifest.machines_from(MachineChoice.HOST):
206+
self._prepare_package(pkg, machine)
203207

204208
# Call subdir() for each required member of the workspace. The order is
205209
# important, if a member depends on another member, that member must be
@@ -210,12 +214,16 @@ def _process_member(member: str) -> None:
210214
if member in processed_members:
211215
return
212216
pkg = ws.packages[member]
213-
cfg = pkg.cfg[MachineChoice.HOST]
214-
for depname in cfg.required_deps:
215-
dep = pkg.manifest.dependencies[depname]
216-
if dep.path:
217-
dep_member = os.path.normpath(os.path.join(pkg.ws_member, dep.path))
218-
_process_member(dep_member)
217+
# Process dependencies for all configured machines
218+
for machine in MachineChoice:
219+
cfg = pkg.cfg[machine]
220+
if cfg is None:
221+
continue
222+
for depname in cfg.required_deps:
223+
dep = pkg.manifest.dependencies[depname]
224+
if dep.path:
225+
dep_member = os.path.normpath(os.path.join(pkg.ws_member, dep.path))
226+
_process_member(dep_member)
219227
if member == '.':
220228
ast.extend(self._create_package(pkg, build, subdir))
221229
else:
@@ -295,20 +303,21 @@ def _fetch_package_from_subproject(self, package_name: str, meson_depname: str)
295303
self.packages[key] = pkg
296304
return pkg, False
297305

298-
def _prepare_package(self, pkg: PackageState) -> None:
299-
if pkg.cfg[MachineChoice.HOST]:
300-
return
306+
def _prepare_package(self, pkg: PackageState, machine: MachineChoice) -> None:
307+
"""Prepare package configuration for specific machine."""
308+
if pkg.cfg[machine] is not None:
309+
return # Already prepared for this machine
301310

302-
pkg.cfg[MachineChoice.HOST] = PackageConfiguration()
303-
# Merge target specific dependencies that are enabled
304-
cfgs = self._get_cfgs(MachineChoice.HOST)
311+
pkg.cfg[machine] = PackageConfiguration()
312+
# Merge target-specific dependencies that are enabled for this machine
313+
target_cfgs = self._get_cfgs(machine)
305314
for condition, dependencies in pkg.manifest.target.items():
306-
if eval_cfg(condition, cfgs):
315+
if eval_cfg(condition, target_cfgs):
307316
pkg.manifest.dependencies.update(dependencies)
308-
# Fetch required dependencies recursively.
317+
# Fetch required dependencies recursively for this machine
309318
for depname, dep in pkg.manifest.dependencies.items():
310319
if not dep.optional:
311-
self._add_dependency(pkg, depname)
320+
self._add_dependency(pkg, depname, machine)
312321

313322
def _dep_package(self, pkg: PackageState, dep: Dependency) -> PackageState:
314323
if dep.path:
@@ -363,8 +372,8 @@ def _load_manifest(self, subdir: str, workspace: T.Optional[Workspace] = None, m
363372
self.manifests[subdir] = manifest_
364373
return manifest_
365374

366-
def _add_dependency(self, pkg: PackageState, depname: str) -> None:
367-
cfg = pkg.cfg[MachineChoice.HOST]
375+
def _add_dependency(self, pkg: PackageState, depname: str, machine: MachineChoice) -> None:
376+
cfg = pkg.cfg[machine]
368377
if depname in cfg.required_deps:
369378
return
370379
dep = pkg.manifest.dependencies.get(depname)
@@ -373,22 +382,24 @@ def _add_dependency(self, pkg: PackageState, depname: str) -> None:
373382
return
374383
cfg.required_deps.add(depname)
375384
dep_pkg = self._dep_package(pkg, dep)
376-
self._prepare_package(dep_pkg)
377-
if dep.default_features:
378-
self._enable_feature(dep_pkg, 'default')
379-
for f in dep.features:
380-
self._enable_feature(dep_pkg, f)
381-
for f in cfg.optional_deps_features[depname]:
382-
self._enable_feature(dep_pkg, f)
383-
384-
def _enable_feature(self, pkg: PackageState, feature: str) -> None:
385-
cfg = pkg.cfg[MachineChoice.HOST]
385+
# Use machines_from() to determine which machines the dependency needs
386+
for dep_machine in dep_pkg.manifest.machines_from(machine):
387+
self._prepare_package(dep_pkg, dep_machine)
388+
if dep.default_features:
389+
self._enable_feature(dep_pkg, 'default', dep_machine)
390+
for f in dep.features:
391+
self._enable_feature(dep_pkg, f, dep_machine)
392+
for f in cfg.optional_deps_features[depname]:
393+
self._enable_feature(dep_pkg, f, dep_machine)
394+
395+
def _enable_feature(self, pkg: PackageState, feature: str, machine: MachineChoice) -> None:
396+
cfg = pkg.cfg[machine]
386397
if feature in cfg.features:
387398
return
388399
cfg.features.add(feature)
389400
# A feature can also be a dependency.
390401
if feature in pkg.manifest.dependencies:
391-
self._add_dependency(pkg, feature)
402+
self._add_dependency(pkg, feature, machine)
392403
# Recurse on extra features and dependencies this feature pulls.
393404
# https://doc.rust-lang.org/cargo/reference/features.html#the-features-section
394405
for f in pkg.manifest.features.get(feature, []):
@@ -397,19 +408,21 @@ def _enable_feature(self, pkg: PackageState, feature: str) -> None:
397408
if depname[-1] == '?':
398409
depname = depname[:-1]
399410
else:
400-
self._add_dependency(pkg, depname)
411+
self._add_dependency(pkg, depname, machine)
401412
if depname in cfg.required_deps:
402413
dep = pkg.manifest.dependencies[depname]
403414
dep_pkg = self._dep_package(pkg, dep)
404-
self._enable_feature(dep_pkg, dep_f)
415+
# Use machines_from() to determine which machines the dependency needs
416+
for dep_machine in dep_pkg.manifest.machines_from(machine):
417+
self._enable_feature(dep_pkg, dep_f, dep_machine)
405418
else:
406419
# This feature will be enabled only if that dependency
407420
# is later added.
408421
cfg.optional_deps_features[depname].add(dep_f)
409422
elif f.startswith('dep:'):
410-
self._add_dependency(pkg, f[4:])
423+
self._add_dependency(pkg, f[4:], machine)
411424
else:
412-
self._enable_feature(pkg, f)
425+
self._enable_feature(pkg, f, machine)
413426

414427
def has_check_cfg(self, machine: MachineChoice) -> bool:
415428
if not self.environment.is_cross_build():
@@ -501,8 +514,10 @@ def _create_dependencies(self, pkg: PackageState, build: builder.Builder, machin
501514
for depname in cfg.required_deps:
502515
dep = pkg.manifest.dependencies[depname]
503516
dep_pkg = self._dep_package(pkg, dep)
504-
if dep_pkg.manifest.lib:
505-
ast += self._create_dependency(dep_pkg, dep, build, machine)
517+
if not dep_pkg.manifest.lib:
518+
continue
519+
for dep_machine in dep_pkg.manifest.machines_from(machine):
520+
ast += self._create_dependency(dep_pkg, dep, build, dep_machine)
506521
ast.append(build.assign(build.array([]), 'system_deps_args'))
507522
for name, sys_dep in pkg.manifest.system_dependencies.items():
508523
if sys_dep.enabled(cfg.features):
@@ -626,10 +641,11 @@ def _create_lib(self, pkg: PackageState, build: builder.Builder, crate_type: raw
626641
for name in cfg.required_deps:
627642
dep = pkg.manifest.dependencies[name]
628643
dep_pkg = self._dep_package(pkg, dep)
629-
dependencies.append(build.identifier(_dependency_varname(dep.package, machine)))
644+
for dep_machine in dep_pkg.manifest.machines_from(machine):
645+
dependencies.append(build.identifier(_dependency_varname(dep.package, dep_machine)))
630646
dep_lib_name = dep_pkg.manifest.lib.name
631647
dep_crate_name = name if name != dep.package else dep_lib_name
632-
dependency_map[build.string(_fixup_meson_target_name(dep_lib_name, machine))] = build.string(dep_crate_name)
648+
dependency_map[build.string(_fixup_meson_target_name(dep_lib_name, dep_machine))] = build.string(dep_crate_name)
633649
for name, sys_dep in pkg.manifest.system_dependencies.items():
634650
if sys_dep.enabled(cfg.features):
635651
dependencies.append(build.identifier(f'{fixup_meson_varname(name)}_system_dep'))

mesonbuild/cargo/manifest.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import typing as T
1212

1313
from . import version
14-
from ..mesonlib import MesonException, lazy_property, Version
14+
from ..mesonlib import MesonException, lazy_property, Version, MachineChoice
1515
from .. import mlog
1616

1717
if T.TYPE_CHECKING:
@@ -513,6 +513,26 @@ class Manifest:
513513
def __post_init__(self) -> None:
514514
self.features.setdefault('default', [])
515515

516+
def machines_from(self, parent_machine: MachineChoice) -> T.Iterable[MachineChoice]:
517+
"""Return the machines this manifest should be built for based on the machine
518+
for the package that depended on this one."""
519+
if self.lib is None:
520+
# No support for bin, test, etc.
521+
return
522+
523+
need_build = False
524+
need_host = False
525+
for crate_type in self.lib.crate_type:
526+
if crate_type == 'proc-macro' or parent_machine == MachineChoice.BUILD:
527+
need_build = True
528+
else:
529+
need_host = True
530+
531+
if need_build:
532+
yield MachineChoice.BUILD
533+
if need_host:
534+
yield MachineChoice.HOST
535+
516536
@lazy_property
517537
def system_dependencies(self) -> T.Dict[str, SystemDependency]:
518538
return {k: SystemDependency.from_raw(k, v) for k, v in self.package.metadata.get('system-deps', {}).items()}

0 commit comments

Comments
 (0)