Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/markdown/snippets/subp-method.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Set [[dependency]] and [[subproject]] build method

Subprojects can already define a build method in their `.wrap` file. It can
now also be done with [[dependency]]'s `fallback_method` and [[subproject]]'s
`method` keyword arguments. Supported values are `meson`, `cmake` and `cargo`.
It defaults to the `method` field in the wrap file if any, otherwise it defaults
to `meson`.
9 changes: 9 additions & 0 deletions docs/yaml/functions/dependency.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ kwargs:
If the value is an empty array it has the same effect as
`allow_fallback: false`.

fallback_method:
type: str
since: 1.10.0
description: |
Specifies which method should be used to configure the fallback if the
dependency is not found in the system. Supported values are `meson`,
`cmake` and `cargo`. It defaults to the `method` field in the wrap file
if any, otherwise it defaults to `meson`.

language:
type: str
since: 0.42.0
Expand Down
8 changes: 8 additions & 0 deletions docs/yaml/functions/subproject.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,11 @@ kwargs:
default: true
description: |
Works just the same as in [[dependency]].

method:
type: str
since: 1.10.0
description: |
Specifies which method should be used to configure the subproject.
Supported values are `meson`, `cmake` and `cargo`. It defaults to the
`method` field in the wrap file if any, otherwise it defaults to `meson`.
27 changes: 19 additions & 8 deletions mesonbuild/cargo/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def interpret_package(self, manifest: Manifest, build: builder.Builder, subdir:
member = ws.packages_to_member[manifest.package.name]
pkg = ws.packages[member]
else:
pkg, cached = self._fetch_package(manifest.package.name, manifest.package.api)
pkg, cached = self._fetch_package_from_manifest(manifest)
if not cached:
# This is an entry point, always enable the 'default' feature.
# FIXME: We should have a Meson option similar to `cargo build --no-default-features`
Expand Down Expand Up @@ -223,15 +223,15 @@ def _require_workspace_member(self, ws: WorkspaceState, member: str) -> PackageS
ws.required_members.append(member)
return pkg

def _fetch_package(self, package_name: str, api: str) -> T.Tuple[PackageState, bool]:
def _fetch_package(self, package_name: str, api: str) -> PackageState:
key = PackageKey(package_name, api)
pkg = self.packages.get(key)
if pkg:
return pkg, True
return pkg
meson_depname = _dependency_name(package_name, api)
return self._fetch_package_from_subproject(package_name, meson_depname)

def _fetch_package_from_subproject(self, package_name: str, meson_depname: str) -> T.Tuple[PackageState, bool]:
def _fetch_package_from_subproject(self, package_name: str, meson_depname: str) -> PackageState:
subp_name, _ = self.environment.wrap_resolver.find_dep_provider(meson_depname)
if subp_name is None:
# If Cargo.lock has a different version, this could be a resolution
Expand All @@ -251,17 +251,28 @@ def _fetch_package_from_subproject(self, package_name: str, meson_depname: str)
downloaded = \
subp_name in self.environment.wrap_resolver.wraps and \
self.environment.wrap_resolver.wraps[subp_name].type is not None

if isinstance(manifest, Workspace):
ws = self._get_workspace(manifest, subdir)
member = ws.packages_to_member[package_name]
pkg = self._require_workspace_member(ws, member)
return pkg, False
return pkg

key = PackageKey(package_name, version.api(manifest.package.version))
pkg = self.packages.get(key)
if pkg:
return pkg
pkg = PackageState(manifest, downloaded)
self.packages[key] = pkg
self._prepare_package(pkg)
return pkg

def _fetch_package_from_manifest(self, manifest: Manifest) -> T.Tuple[PackageState, bool]:
key = PackageKey(manifest.package.name, version.api(manifest.package.version))
pkg = self.packages.get(key)
if pkg:
return pkg, True
pkg = PackageState(manifest, downloaded)
pkg = PackageState(manifest, downloaded=False)
self.packages[key] = pkg
self._prepare_package(pkg)
return pkg, False
Expand All @@ -287,7 +298,7 @@ def _dep_package(self, pkg: PackageState, dep: Dependency) -> PackageState:
dep_pkg = self._require_workspace_member(ws, dep_member)
elif dep.git:
_, _, directory = _parse_git_url(dep.git, dep.branch)
dep_pkg, _ = self._fetch_package_from_subproject(dep.package, directory)
dep_pkg = self._fetch_package_from_subproject(dep.package, directory)
else:
# From all available versions from Cargo.lock, pick the most recent
# satisfying the constraints
Expand All @@ -302,7 +313,7 @@ def _dep_package(self, pkg: PackageState, dep: Dependency) -> PackageState:
else:
if not dep.meson_version:
raise MesonException(f'Cannot determine version of cargo package {dep.package}')
dep_pkg, _ = self._fetch_package(dep.package, dep.api)
dep_pkg = self._fetch_package(dep.package, dep.api)
return dep_pkg

def _load_manifest(self, subdir: str, workspace: T.Optional[Workspace] = None, member_path: str = '') -> T.Union[Manifest, Workspace]:
Expand Down
13 changes: 7 additions & 6 deletions mesonbuild/dependencies/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,21 @@ def get_dep_identifier(name: str, kwargs: T.Dict[str, T.Any]) -> 'TV_DepID':
nkwargs.update(kwargs)

from ..interpreter import permitted_dependency_kwargs
assert len(permitted_dependency_kwargs) == 19, \
assert len(permitted_dependency_kwargs) == 20, \
'Extra kwargs have been added to dependency(), please review if it makes sense to handle it here'
for key, value in nkwargs.items():
# 'version' is irrelevant for caching; the caller must check version matches
# 'native' is handled above with `for_machine`
# 'required' is irrelevant for caching; the caller handles it separately
# 'fallback' and 'allow_fallback' is not part of the cache because,
# once a dependency has been found through a fallback, it should
# be used for the rest of the Meson run.
# 'fallback', 'allow_fallback' and 'fallback_method' are not part of the
# cache because, once a dependency has been found through a fallback,
# it should be used for the rest of the Meson run.
# 'default_options' is only used in fallback case
# 'not_found_message' has no impact on the dependency lookup
# 'include_type' is handled after the dependency lookup
if key in {'version', 'native', 'required', 'fallback', 'allow_fallback', 'default_options',
'not_found_message', 'include_type'}:
if key in {'version', 'native', 'required', 'fallback', 'allow_fallback',
'fallback_method', 'default_options', 'not_found_message',
'include_type'}:
continue
# All keyword arguments are strings, ints, or lists (or lists of lists)
if isinstance(value, list):
Expand Down
7 changes: 5 additions & 2 deletions mesonbuild/interpreter/dependencyfallbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
from .interpreter import Interpreter
from ..interpreterbase import TYPE_nkwargs, TYPE_nvar
from .interpreterobjects import SubprojectHolder
from ..wrap.wrap import Method


class DependencyFallbacksHolder(MesonInterpreterObject):
def __init__(self,
interpreter: 'Interpreter',
names: T.List[str],
allow_fallback: T.Optional[bool] = None,
default_options: T.Optional[T.Dict[str, str]] = None) -> None:
default_options: T.Optional[T.Dict[str, str]] = None,
fallback_method: Method = 'meson') -> None:
super().__init__(subproject=interpreter.subproject)
self.interpreter = interpreter
self.subproject = interpreter.subproject
Expand All @@ -42,6 +44,7 @@ def __init__(self,
self.names: T.List[str] = []
self.forcefallback: bool = False
self.nofallback: bool = False
self.fallback_method = fallback_method
for name in names:
if not name:
raise InterpreterException('dependency_fallbacks empty name \'\' is not allowed')
Expand Down Expand Up @@ -132,7 +135,7 @@ def _do_subproject(self, kwargs: TYPE_nkwargs, func_args: TYPE_nvar, func_kwargs
subp_name = self.subproject_name
varname = self.subproject_varname
func_kwargs.setdefault('version', [])
self.interpreter.do_subproject(subp_name, func_kwargs, forced_options=forced_options)
self.interpreter.do_subproject(subp_name, func_kwargs, forced_options=forced_options, force_method=self.fallback_method)
return self._get_subproject_dep(subp_name, varname, kwargs)

def _get_subproject(self, subp_name: str) -> T.Optional[SubprojectHolder]:
Expand Down
8 changes: 6 additions & 2 deletions mesonbuild/interpreter/interpreter.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
STATIC_LIB_KWS,
VARIABLES_KW,
TEST_KWS,
FALLBACK_METHOD_KW,
NoneType,
in_set_validator,
env_convertor_with_method
Expand Down Expand Up @@ -245,6 +246,7 @@ class InterpreterRuleRelaxation(Enum):
'components',
'default_options',
'fallback',
'fallback_method',
'include_type',
'language',
'main',
Expand Down Expand Up @@ -867,6 +869,7 @@ def func_option(self, nodes, args, kwargs):
REQUIRED_KW,
DEFAULT_OPTIONS.evolve(since='0.38.0'),
KwargInfo('version', ContainerTypeInfo(list, str), default=[], listify=True),
FALLBACK_METHOD_KW.evolve(name='method'),
)
def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: kwtypes.Subproject) -> SubprojectHolder:
kw: kwtypes.DoSubproject = {
Expand All @@ -876,7 +879,7 @@ def func_subproject(self, nodes: mparser.BaseNode, args: T.Tuple[str], kwargs: k
'options': None,
'cmake_options': [],
}
return self.do_subproject(args[0], kw)
return self.do_subproject(args[0], kw, force_method=kwargs['method'])

def disabled_subproject(self, subp_name: str, disabled_feature: T.Optional[str] = None,
exception: T.Optional[Exception] = None) -> SubprojectHolder:
Expand Down Expand Up @@ -1809,7 +1812,8 @@ def func_dependency(self, node: mparser.BaseNode, args: T.Tuple[T.List[str]], kw
raise InvalidArguments('"allow_fallback" argument must be boolean')
fallback = kwargs.get('fallback')
default_options = kwargs.get('default_options')
df = DependencyFallbacksHolder(self, names, allow_fallback, default_options)
fallback_method = kwargs.get('fallback_method')
df = DependencyFallbacksHolder(self, names, allow_fallback, default_options, fallback_method)
df.set_fallback(fallback)
not_found_message = kwargs.get('not_found_message', '')
if not isinstance(not_found_message, str):
Expand Down
3 changes: 3 additions & 0 deletions mesonbuild/interpreter/kwargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..options import OptionKey
from ..modules.cmake import CMakeSubprojectOptions
from ..programs import ExternalProgram
from ..wrap.wrap import Method as WrapMethod
from .type_checking import PkgConfigDefineType, SourcesVarargsType

TestArgs = T.Union[str, File, build.Target, ExternalProgram]
Expand Down Expand Up @@ -315,6 +316,7 @@ class Subproject(ExtractRequired):

default_options: T.Dict[OptionKey, options.ElementaryOptionValues]
version: T.List[str]
method: T.Optional[WrapMethod]


class DoSubproject(ExtractRequired):
Expand Down Expand Up @@ -491,3 +493,4 @@ class FuncDeclareDependency(TypedDict):
class FuncDependency(TypedDict):

default_options: T.Dict[OptionKey, options.ElementaryOptionValues]
fallback_method: T.Optional[WrapMethod]
9 changes: 9 additions & 0 deletions mesonbuild/interpreter/type_checking.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from ..mesonlib import (File, FileMode, MachineChoice, has_path_sep, listify, stringlistify,
EnvironmentVariables)
from ..programs import ExternalProgram
from ..wrap.wrap import METHODS

# Helper definition for type checks that are `Optional[T]`
NoneType: T.Type[None] = type(None)
Expand Down Expand Up @@ -892,7 +893,15 @@ def _pkgconfig_define_convertor(x: T.List[str]) -> PkgConfigDefineType:
convertor=_pkgconfig_define_convertor,
)

FALLBACK_METHOD_KW: KwargInfo = KwargInfo(
'fallback_method',
(str, NoneType),
default=None,
validator=in_set_validator(METHODS),
since='1.10.0')


DEPENDENCY_KWS: T.List[KwargInfo] = [
DEFAULT_OPTIONS.evolve(since='0.38.0'),
FALLBACK_METHOD_KW,
]
1 change: 1 addition & 0 deletions mesonbuild/wrap/wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
WHITELIST_SUBDOMAIN = 'wrapdb.mesonbuild.com'

ALL_TYPES = ['file', 'git', 'hg', 'svn', 'redirect']
METHODS = {'meson', 'cmake', 'cargo'}

if mesonlib.is_windows():
from ..programs import ExternalProgram
Expand Down
4 changes: 4 additions & 0 deletions test cases/rust/31 cargo fallback method/meson.build
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
project('cargo fallback method')

subproject('rust', method : 'cargo')
dependency('foo-0-rs', fallback_method : 'cargo')
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[package]
name = "empty"
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[wrap-file]

[provide]
dependency_names = foo-0-rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "foo"

[lib]
path = "lib.rs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn foo() -> i32 {
0
}
Loading