Merge pull request #6902 from xclaesse/auto-fallback

Implicit dependency fallback when a subproject wrap or dir exists
pull/7405/head
Jussi Pakkanen 4 years ago committed by GitHub
commit 026e386ec2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      docs/markdown/Reference-manual.md
  2. 59
      docs/markdown/Wrap-dependency-system-manual.md
  3. 21
      docs/markdown/snippets/implicit_fallback.md
  4. 114
      mesonbuild/interpreter.py
  5. 2
      mesonbuild/mdist.py
  6. 135
      mesonbuild/wrap/wrap.py
  7. 5
      run_unittests.py
  8. 29
      test cases/common/102 subproject subdir/meson.build
  9. 6
      test cases/common/102 subproject subdir/subprojects/sub_implicit.wrap
  10. 11
      test cases/common/102 subproject subdir/subprojects/sub_implicit/meson.build
  11. 3
      test cases/common/187 find override/meson.build
  12. 5
      test cases/common/187 find override/subprojects/sub.wrap
  13. 4
      test cases/common/187 find override/subprojects/sub/meson.build
  14. 3
      test cases/failing/106 fallback consistency/meson.build
  15. 6
      test cases/failing/106 fallback consistency/subprojects/foo.wrap
  16. 6
      test cases/failing/106 fallback consistency/subprojects/foo/meson.build
  17. 7
      test cases/failing/106 fallback consistency/test.json
  18. 4
      test cases/linuxlike/5 dependency versions/meson.build
  19. 3
      test cases/unit/12 promote/subprojects/s2/subprojects/athing.wrap

@ -456,7 +456,11 @@ arguments:
*(since 0.54.0)* `'subproj_dep'` argument can be omitted in the case the
subproject used `meson.override_dependency('dependency_name', subproj_dep)`.
In that case, the `fallback` keyword argument can be a single string instead
of a list of 2 strings.
of a list of 2 strings. *Since 0.55.0* the `fallback` keyword argument can be
omitted when there is a wrap file or a directory with the same `dependency_name`,
and subproject registered the dependency using
`meson.override_dependency('dependency_name', subproj_dep)`, or when the wrap
file has `dependency_name` in its `[provide]` section.
- `language` *(since 0.42.0)*: defines what language-specific
dependency to find if it's available for multiple languages.
- `method`: defines the way the dependency is detected, the default is

@ -71,6 +71,7 @@ revision = head
- `directory` - name of the subproject root directory, defaults to the name of the wrap.
Since *0.55.0* those can be used in all wrap types, they were previously reserved to `wrap-file`:
- `patch_url` - download url to retrieve an optional overlay archive
- `patch_fallback_url` - fallback URL to be used when download from `patch_url` fails *Since: 0.55.0*
- `patch_filename` - filename of the downloaded overlay archive
@ -105,7 +106,7 @@ of downloading the file, even if `--wrap-mode` option is set to
valid value (such as a git tag) for the VCS's `checkout` command, or
(for git) `head` to track upstream's default branch. Required.
## Specific to wrap-git
### Specific to wrap-git
- `depth` - shallowly clone the repository to X number of commits. Note
that git always allow shallowly cloning branches, but in order to
clone commit ids shallowly, the server must support
@ -138,6 +139,62 @@ put them somewhere where you can download them.
Meson build patches are only supported for wrap-file mode. When using
wrap-git, the repository must contain all Meson build definitions.
## `provide` section
*Since *0.55.0*
Wrap files can define the dependencies it provides in the `[provide]` section.
When a wrap file provides the dependency `foo` any call do `dependency('foo')`
will automatically fallback to that subproject even if no `fallback` keyword
argument is given. It is recommended for subprojects to call
`meson.override_dependency('foo', foo_dep)`, dependency name can then be added into
the special `dependency_names` entry which takes comma separated list of dependency
names. For backward compatibility with subprojects that does not call
`meson.override_dependency()`, the variable name can be provided in the wrap file
with entries in the format `dependency_name = variable_name`,
where `dependency_name` usually match the corresponding pkg-config name and
`variable_name` is the name of a variable defined in the subproject that should
be returned for that dependency.
For example when using a recent enough version of glib that uses
`meson.override_dependency()` to override `glib-2.0`, `gobject-2.0` and `gio-2.0`,
a wrap file would look like:
```ini
[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
[provide]
dependency_names = glib-2.0, gobject-2.0, gio-2.0
```
With older version of glib dependency variable names need to be specified:
```ini
[wrap-git]
url=https://gitlab.gnome.org/GNOME/glib.git
revision=glib-2-62
[provide]
glib-2.0=glib_dep
gobject-2.0=gobject_dep
gio-2.0=gio_dep
```
With such wrap file, `dependency('glib-2.0')` will automatically fallback to use
`glib.wrap` and return `glib_dep` variable from the subproject.
Programs can also be provided by wrap files, with the `program_names` key:
```ini
[wrap-git]
...
[provide]
program_names = myprog, otherprog
```
With such wrap file, `find_program('myprog')` will automatically fallback to use
the subproject, assuming it uses `meson.override_find_program('myprog')`.
## Using wrapped projects
Wraps provide a convenient way of obtaining a project into your subproject directory.

@ -0,0 +1,21 @@
## Implicit dependency fallback
`dependency('foo')` now automatically fallback if the dependency is not found on
the system but a subproject wrap file or directory exists with the same name.
That means that simply adding `subprojects/foo.wrap` is enough to add fallback
to any `dependency('foo')` call. It is however requires that the subproject call
`meson.override_dependency('foo', foo_dep)` to specify which dependency object
should be used for `foo`.
## Wrap file `provide` section
Wrap files can define the dependencies it provides in the `[provide]` section.
When a wrap file provides the dependency `foo` any call do `dependency('foo')`
will automatically fallback to that subproject even if no `fallback` keyword
argument is given. See [Wrap documentation](Wrap-dependency-system-manual.md#provide_section).
## `find_program()` fallback
When a program cannot be found on the system but a wrap file has its name in the
`[provide]` section, that subproject will be used as fallback.

@ -2779,10 +2779,9 @@ external dependencies (including libraries) must go to "dependencies".''')
self.subproject_dir, dirname))
return subproject
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
r = wrap.Resolver(subproject_dir_abs, self.coredata.get_builtin_option('wrap_mode'), current_subproject=self.subproject)
r = self.environment.wrap_resolver
try:
resolved = r.resolve(dirname, method)
resolved = r.resolve(dirname, method, self.subproject)
except wrap.WrapException as e:
subprojdir = os.path.join(self.subproject_dir, r.directory)
if isinstance(e, wrap.WrapNotFoundException):
@ -2798,7 +2797,7 @@ external dependencies (including libraries) must go to "dependencies".''')
raise e
subdir = os.path.join(self.subproject_dir, resolved)
subdir_abs = os.path.join(subproject_dir_abs, resolved)
subdir_abs = os.path.join(self.environment.get_source_dir(), subdir)
os.makedirs(os.path.join(self.build.environment.get_build_dir(), subdir), exist_ok=True)
self.global_args_frozen = True
@ -3062,6 +3061,10 @@ external dependencies (including libraries) must go to "dependencies".''')
self.subproject_dir = spdirname
self.build.subproject_dir = self.subproject_dir
if not self.is_subproject():
wrap_mode = self.coredata.get_builtin_option('wrap_mode')
subproject_dir_abs = os.path.join(self.environment.get_source_dir(), self.subproject_dir)
self.environment.wrap_resolver = wrap.Resolver(subproject_dir_abs, wrap_mode)
self.build.projects[self.subproject] = proj_name
mlog.log('Project name:', mlog.bold(proj_name))
@ -3248,7 +3251,7 @@ external dependencies (including libraries) must go to "dependencies".''')
return success
def program_from_file_for(self, for_machine, prognames, silent):
def program_from_file_for(self, for_machine, prognames):
for p in unholder(prognames):
if isinstance(p, mesonlib.File):
continue # Always points to a local (i.e. self generated) file.
@ -3287,15 +3290,13 @@ external dependencies (including libraries) must go to "dependencies".''')
if progobj.found():
return progobj
def program_from_overrides(self, command_names, silent=False):
def program_from_overrides(self, command_names, extra_info):
for name in command_names:
if not isinstance(name, str):
continue
if name in self.build.find_overrides:
exe = self.build.find_overrides[name]
if not silent:
mlog.log('Program', mlog.bold(name), 'found:', mlog.green('YES'),
'(overridden: %s)' % exe.description())
extra_info.append(mlog.blue('(overriden)'))
return ExternalProgramHolder(exe, self.subproject, self.backend)
return None
@ -3313,40 +3314,75 @@ external dependencies (including libraries) must go to "dependencies".''')
% name)
self.build.find_overrides[name] = exe
def notfound_program(self, args):
return ExternalProgramHolder(dependencies.NonExistingExternalProgram(' '.join(args)), self.subproject)
# TODO update modules to always pass `for_machine`. It is bad-form to assume
# the host machine.
def find_program_impl(self, args, for_machine: MachineChoice = MachineChoice.HOST,
required=True, silent=True, wanted='', search_dirs=None):
if not isinstance(args, list):
args = [args]
args = mesonlib.listify(args)
progobj = self.program_from_overrides(args, silent=silent)
extra_info = []
progobj = self.program_lookup(args, for_machine, required, search_dirs, extra_info)
if progobj is None:
progobj = self.program_from_file_for(for_machine, args, silent=silent)
if progobj is None:
progobj = self.program_from_system(args, search_dirs, silent=silent)
if progobj is None and args[0].endswith('python3'):
prog = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
progobj = ExternalProgramHolder(prog, self.subproject)
if required and (progobj is None or not progobj.found()):
raise InvalidArguments('Program(s) {!r} not found or not executable'.format(args))
if progobj is None:
return ExternalProgramHolder(dependencies.NonExistingExternalProgram(' '.join(args)), self.subproject)
# Only store successful lookups
self.store_name_lookups(args)
progobj = self.notfound_program(args)
if not progobj.found():
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'))
if required:
m = 'Program {!r} not found'
raise InterpreterException(m.format(progobj.get_name()))
return progobj
if wanted:
version = progobj.get_version(self)
is_found, not_found, found = mesonlib.version_compare_many(version, wanted)
if not is_found:
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.red('NO'),
'found {!r} but need:'.format(version),
', '.join(["'{}'".format(e) for e in not_found]))
'found', mlog.normal_cyan(version), 'but need:',
mlog.bold(', '.join(["'{}'".format(e) for e in not_found])))
if required:
m = 'Invalid version of program, need {!r} {!r} found {!r}.'
raise InvalidArguments(m.format(progobj.get_name(), not_found, version))
return ExternalProgramHolder(dependencies.NonExistingExternalProgram(' '.join(args)), self.subproject)
raise InterpreterException(m.format(progobj.get_name(), not_found, version))
return self.notfound_program(args)
extra_info.insert(0, mlog.normal_cyan(version))
# Only store successful lookups
self.store_name_lookups(args)
mlog.log('Program', mlog.bold(progobj.get_name()), 'found:', mlog.green('YES'), *extra_info)
return progobj
def program_lookup(self, args, for_machine, required, search_dirs, extra_info):
progobj = self.program_from_overrides(args, extra_info)
if progobj:
return progobj
fallback = None
wrap_mode = self.coredata.get_builtin_option('wrap_mode')
if wrap_mode != WrapMode.nofallback:
fallback = self.environment.wrap_resolver.find_program_provider(args)
if fallback and wrap_mode == WrapMode.forcefallback:
return self.find_program_fallback(fallback, args, required, extra_info)
progobj = self.program_from_file_for(for_machine, args)
if progobj is None:
progobj = self.program_from_system(args, search_dirs, silent=True)
if progobj is None and args[0].endswith('python3'):
prog = dependencies.ExternalProgram('python3', mesonlib.python_command, silent=True)
progobj = ExternalProgramHolder(prog, self.subproject) if prog.found() else None
if progobj is None and fallback and required:
progobj = self.find_program_fallback(fallback, args, required, extra_info)
return progobj
def find_program_fallback(self, fallback, args, required, extra_info):
mlog.log('Fallback to subproject', mlog.bold(fallback), 'which provides program',
mlog.bold(' '.join(args)))
sp_kwargs = { 'required': required }
self.do_subproject(fallback, 'meson', sp_kwargs)
return self.program_from_overrides(args, extra_info)
@FeatureNewKwargs('find_program', '0.53.0', ['dirs'])
@FeatureNewKwargs('find_program', '0.52.0', ['version'])
@FeatureNewKwargs('find_program', '0.49.0', ['disabler'])
@ -3359,7 +3395,7 @@ external dependencies (including libraries) must go to "dependencies".''')
disabled, required, feature = extract_required_kwarg(kwargs, self.subproject)
if disabled:
mlog.log('Program', mlog.bold(' '.join(args)), 'skipped: feature', mlog.bold(feature), 'disabled')
return ExternalProgramHolder(dependencies.NonExistingExternalProgram(' '.join(args)), self.subproject)
return self.notfound_program(args)
search_dirs = extract_search_dirs(kwargs)
wanted = mesonlib.stringlistify(kwargs.get('version', []))
@ -3453,8 +3489,12 @@ external dependencies (including libraries) must go to "dependencies".''')
raise DependencyException(m.format(display_name))
return DependencyHolder(cached_dep, self.subproject)
else:
m = 'Subproject {} did not override dependency {}'
raise DependencyException(m.format(subproj_path, display_name))
if required:
m = 'Subproject {} did not override dependency {}'
raise DependencyException(m.format(subproj_path, display_name))
mlog.log('Dependency', mlog.bold(display_name), 'from subproject',
mlog.bold(subproj_path), 'found:', mlog.red('NO'))
return self.notfound_dependency()
if subproject.found():
self.verify_fallback_consistency(dirname, varname, cached_dep)
dep = self.subprojects[dirname].get_variable_method([varname], {})
@ -3549,6 +3589,18 @@ external dependencies (including libraries) must go to "dependencies".''')
return self.notfound_dependency()
has_fallback = 'fallback' in kwargs
if not has_fallback and name:
# Add an implicit fallback if we have a wrap file or a directory with the same name,
# but only if this dependency is required. It is common to first check for a pkg-config,
# then fallback to use find_library() and only afterward check again the dependency
# with a fallback. If the fallback has already been configured then we have to use it
# even if the dependency is not required.
provider = self.environment.wrap_resolver.find_dep_provider(name)
dirname = mesonlib.listify(provider)[0]
if provider and (required or dirname in self.subprojects):
kwargs['fallback'] = provider
has_fallback = True
if 'default_options' in kwargs and not has_fallback:
mlog.warning('The "default_options" keyworg argument does nothing without a "fallback" keyword argument.',
location=self.current_node)

@ -259,7 +259,7 @@ def run(options):
if options.include_subprojects:
subproject_dir = os.path.join(src_root, b.subproject_dir)
for sub in b.subprojects:
_, directory = wrap.get_directory(subproject_dir, sub)
directory = wrap.get_directory(subproject_dir, sub)
subprojects.append(os.path.join(b.subproject_dir, directory))
extra_meson_args.append('-Dwrap_mode=nodownload')

@ -103,14 +103,31 @@ class WrapNotFoundException(WrapException):
class PackageDefinition:
def __init__(self, fname: str):
self.filename = fname
self.type = None
self.values = {} # type: T.Dict[str, str]
self.provided_deps = {} # type: T.Dict[str, T.Optional[str]]
self.provided_programs = [] # type: T.List[str]
self.basename = os.path.basename(fname)
self.name = self.basename[:-5]
self.name = self.basename
if self.name.endswith('.wrap'):
self.name = self.name[:-5]
self.provided_deps[self.name] = None
if fname.endswith('.wrap'):
self.parse_wrap(fname)
self.directory = self.values.get('directory', self.name)
if os.path.dirname(self.directory):
raise WrapException('Directory key must be a name and not a path')
def parse_wrap(self, fname: str):
try:
self.config = configparser.ConfigParser(interpolation=None)
self.config.read(fname)
except configparser.Error:
raise WrapException('Failed to parse {}'.format(self.basename))
self.parse_wrap_section()
self.parse_provide_section()
def parse_wrap_section(self):
if len(self.config.sections()) < 1:
raise WrapException('Missing sections in {}'.format(self.basename))
self.wrap_section = self.config.sections()[0]
@ -120,6 +137,27 @@ class PackageDefinition:
self.type = self.wrap_section[5:]
self.values = dict(self.config[self.wrap_section])
def parse_provide_section(self):
if self.config.has_section('provide'):
for k, v in self.config['provide'].items():
if k == 'dependency_names':
# A comma separated list of dependency names that does not
# need a variable name
names = {n.strip(): None for n in v.split(',')}
self.provided_deps.update(names)
continue
if k == 'program_names':
# A comma separated list of program names
names = [n.strip() for n in v.split(',')]
self.provided_programs += names
continue
if not v:
m = ('Empty dependency variable name for {!r} in {}. '
'If the subproject uses meson.override_dependency() '
'it can be added in the "dependency_names" special key.')
raise WrapException(m.format(k, self.basename))
self.provided_deps[k] = v
def get(self, key: str) -> str:
try:
return self.values[key]
@ -127,35 +165,87 @@ class PackageDefinition:
m = 'Missing key {!r} in {}'
raise WrapException(m.format(key, self.basename))
def load_wrap(subdir_root: str, packagename: str) -> PackageDefinition:
def get_directory(subdir_root: str, packagename: str) -> str:
fname = os.path.join(subdir_root, packagename + '.wrap')
if os.path.isfile(fname):
return PackageDefinition(fname)
return None
def get_directory(subdir_root: str, packagename: str):
directory = packagename
# We always have to load the wrap file, if it exists, because it could
# override the default directory name.
wrap = load_wrap(subdir_root, packagename)
if wrap and 'directory' in wrap.values:
directory = wrap.get('directory')
if os.path.dirname(directory):
raise WrapException('Directory key must be a name and not a path')
return wrap, directory
wrap = PackageDefinition(fname)
return wrap.directory
return packagename
class Resolver:
def __init__(self, subdir_root: str, wrap_mode=WrapMode.default, current_subproject: str = ''):
def __init__(self, subdir_root: str, wrap_mode=WrapMode.default):
self.wrap_mode = wrap_mode
self.subdir_root = subdir_root
self.current_subproject = current_subproject
self.cachedir = os.path.join(self.subdir_root, 'packagecache')
self.filesdir = os.path.join(self.subdir_root, 'packagefiles')
self.wraps = {} # type: T.Dict[str, PackageDefinition]
self.provided_deps = {} # type: T.Dict[str, PackageDefinition]
self.provided_programs = {} # type: T.Dict[str, PackageDefinition]
self.load_wraps()
def resolve(self, packagename: str, method: str) -> str:
def load_wraps(self):
if not os.path.isdir(self.subdir_root):
return
root, dirs, files = next(os.walk(self.subdir_root))
for i in files:
if not i.endswith('.wrap'):
continue
fname = os.path.join(self.subdir_root, i)
wrap = PackageDefinition(fname)
self.wraps[wrap.name] = wrap
if wrap.directory in dirs:
dirs.remove(wrap.directory)
# Add dummy package definition for directories not associated with a wrap file.
for i in dirs:
if i in ['packagecache', 'packagefiles']:
continue
fname = os.path.join(self.subdir_root, i)
wrap = PackageDefinition(fname)
self.wraps[wrap.name] = wrap
for wrap in self.wraps.values():
for k in wrap.provided_deps.keys():
if k in self.provided_deps:
prev_wrap = self.provided_deps[k]
m = 'Multiple wrap files provide {!r} dependency: {} and {}'
raise WrapException(m.format(k, wrap.basename, prev_wrap.basename))
self.provided_deps[k] = wrap
for k in wrap.provided_programs:
if k in self.provided_programs:
prev_wrap = self.provided_programs[k]
m = 'Multiple wrap files provide {!r} program: {} and {}'
raise WrapException(m.format(k, wrap.basename, prev_wrap.basename))
self.provided_programs[k] = wrap
def find_dep_provider(self, packagename: str):
# Return value is in the same format as fallback kwarg:
# ['subproject_name', 'variable_name'], or 'subproject_name'.
wrap = self.provided_deps.get(packagename)
if wrap:
dep_var = wrap.provided_deps.get(packagename)
if dep_var:
return [wrap.name, dep_var]
return wrap.name
return None
def find_program_provider(self, names: T.List[str]):
for name in names:
wrap = self.provided_programs.get(name)
if wrap:
return wrap.name
return None
def resolve(self, packagename: str, method: str, current_subproject: str = '') -> str:
self.current_subproject = current_subproject
self.packagename = packagename
self.wrap, self.directory = get_directory(self.subdir_root, self.packagename)
self.directory = packagename
self.wrap = self.wraps.get(packagename)
if not self.wrap:
m = 'Subproject directory not found and {}.wrap file not found'
raise WrapNotFoundException(m.format(self.packagename))
self.directory = self.wrap.directory
self.dirname = os.path.join(self.subdir_root, self.directory)
meson_file = os.path.join(self.dirname, 'meson.build')
cmake_file = os.path.join(self.dirname, 'CMakeLists.txt')
@ -175,11 +265,6 @@ class Resolver:
if not os.path.isdir(self.dirname):
raise WrapException('Path already exists but is not a directory')
else:
# A wrap file is required to download
if not self.wrap:
m = 'Subproject directory not found and {}.wrap file not found'
raise WrapNotFoundException(m.format(self.packagename))
if self.wrap.type == 'file':
self.get_file()
else:

@ -4080,6 +4080,11 @@ recommended as it is not supported on some platforms''')
'name': 'sub',
'version': '1.0'
},
{
'descriptive_name': 'sub_implicit',
'name': 'sub_implicit',
'version': '1.0',
},
{
'descriptive_name': 'sub-novar',
'name': 'sub_novar',

@ -25,3 +25,32 @@ dependency('sub-novar', fallback : 'sub_novar')
# Verify a subproject can force a dependency to be not-found
d = dependency('sub-notfound', fallback : 'sub_novar', required : false)
assert(not d.found(), 'Dependency should be not-found')
# Verify that implicit fallback works because subprojects/sub_implicit directory exists
d = dependency('sub_implicit')
assert(d.found(), 'Should implicitly fallback')
# Verify that implicit fallback works because sub_implicit.wrap has
# `dependency_names=sub_implicit_provide1` and the subproject overrides sub_implicit_provide1.
d = dependency('sub_implicit_provide1')
assert(d.found(), 'Should implicitly fallback')
# Verify that implicit fallback works because sub_implicit.wrap has
# `sub_implicit_provide2=sub_implicit_provide2_dep` and does not override
# sub_implicit_provide2.
d = dependency('sub_implicit_provide2')
assert(d.found(), 'Should implicitly fallback')
# sub_implicit.wrap provides glib-2.0 and we already configured that subproject,
# so we must not return the system dependency here. Using glib-2.0 here because
# some CI runners have it installed.
d = dependency('glib-2.0', required : false)
assert(d.found())
assert(d.type_name() == 'internal')
# sub_implicit.wrap provides gobject-2.0 and we already configured that subproject,
# so we must not return the system dependency here. But since the subproject did
# not override that dependency and its not required, not-found should be returned.
# Using gobject-2.0 here because some CI runners have it installed.
d = dependency('gobject-2.0', required : false)
assert(not d.found())

@ -0,0 +1,6 @@
[wrap-file]
[provide]
glib-2.0 = glib_dep
dependency_names = sub_implicit_provide1, gobject-2.0
sub_implicit_provide2 = sub_implicit_provide2_dep

@ -0,0 +1,11 @@
project('sub_implicit', 'c', version : '1.0')
dep = declare_dependency()
meson.override_dependency('sub_implicit', dep)
meson.override_dependency('sub_implicit_provide1', dep)
# This one is not overriden but the wrap file tells the variable name to use.
sub_implicit_provide2_dep = dep
# This one is not overriden but the wrap file tells the variable name to use.
glib_dep = dep

@ -10,3 +10,6 @@ if not gencodegen.found()
endif
subdir('otherdir')
tool = find_program('sometool')
assert(tool.found())

@ -0,0 +1,5 @@
[wrap-file]
directory = sub
[provide]
program_names = sometool

@ -0,0 +1,4 @@
project('tools')
exe = find_program('gencodegen')
meson.override_find_program('sometool', exe)

@ -0,0 +1,3 @@
project('fallback consistency')
dependency('foo')

@ -0,0 +1,6 @@
[wrap-file]
source_url = http://host.invalid/foo.tar.gz
source_filename = foo.tar.gz
[provide]
foo = bar_dep

@ -0,0 +1,6 @@
project('sub')
foo_dep = declare_dependency()
meson.override_dependency('foo', foo_dep)
bar_dep = declare_dependency()

@ -0,0 +1,7 @@
{
"stdout": [
{
"line": "test cases/failing/106 fallback consistency/meson.build:3:0: ERROR: Inconsistency: Subproject has overridden the dependency with another variable than 'bar_dep'"
}
]
}

@ -31,10 +31,10 @@ dependency('somebrokenlib', version : '>=1.0', required : false)
# Search for an external dependency that won't be found, but must later be
# found via fallbacks
somelibnotfound = dependency('somelib', required : false)
somelibnotfound = dependency('somelib1', required : false)
assert(somelibnotfound.found() == false, 'somelibnotfound was found?')
# Find internal dependency without version
somelibver = dependency('somelib',
somelibver = dependency('somelib1',
fallback : ['somelibnover', 'some_dep'])
assert(somelibver.type_name() == 'internal', 'somelibver should be of type "internal", not ' + somelibver.type_name())
# Find an internal dependency again with the same name and a specific version

@ -1,2 +1 @@
The contents of this wrap file are never evaluated so they
can be anything.
[wrap-file]

Loading…
Cancel
Save