From a34fb8a1b2a9605ee6c1eaf9ab8486ef96a3d445 Mon Sep 17 00:00:00 2001 From: Andrei Horodniceanu Date: Fri, 16 Aug 2024 21:07:38 +0300 Subject: [PATCH] dependencies/dub: First try to describe local project The current approach of determining dub dependencies is by specifying a name and, optionally, a version. Dub will then be called to generate a json summary of the package and code in meson will parse that and extract relevant information. This can be insufficient because dub packages can provide multiple configurations for multiple use-cases, examples include providing a configuration for an executable and a configuration for a library. As a practical example, the dub package itself provides an application configuration and multiple library configurations, the json description of dub will, by default, be for the application configuration which will make dub as a library unusable in meson. This can be solved without modifying the meson build interface by having dub describe the entire local project and collecting dependencies information from that. This way dub will generate information based on the project's 'dub.json' file, which is free to require dependencies in any way accepted by dub, by specifying configurations, by modifying compilation flags etc. This is all transparent to meson as dub's main purpose is to provide a path to the library file generated by the dependency in addition to other command-line arguments for the compiler. This change will, however, require that projects that want to build with meson also provided a 'dub.json' file in which dependency information is recorded. Failure to do so will not break existing projects that didn't use a 'dub.json', but they will be limited to what the previous implementation offered. Projects that already have a 'dub.json' should be fine, so long as the file is valid and the information in it matches the one in 'meson.build'. For example for a 'dependency()' call in 'meson.build' that dependency must exist in 'dub.json', otherwise the call will now fail when it worked previously. Using a 'dub.json' also has as a consequence that the version of the dependencies that are found are the ones specified in 'dub.selections.json', which can be helpful for projects that already provide a 'dub.json' in addition to 'meson.build' to de-duplicate code. In terms of other code changes: - multiple version requirements for a dub dependency now work, though they can only be used when a 'dub.json' is present in which case the version of dependencies is already pinned by 'dub.selections.json' - the 'd/11 dub' test case has been changed to auto-generate the 'dub.json' config outside of the source directory, as the auto-generated file triggers warning when parsed by dub, which upsets the new code as the warnings interfere with the legitimate output. Signed-off-by: Andrei Horodniceanu --- mesonbuild/dependencies/dub.py | 152 +++++++++++------- test cases/d/11 dub/meson.build | 4 +- .../.gitignore | 1 + .../dub.json | 6 + .../dub.selections.json | 6 + .../meson.build | 25 +++ .../source/app.d | 1 + .../d/18 dub respects project root/.gitignore | 1 + .../d/18 dub respects project root/dub.json | 6 + .../dub.selections.json | 6 + .../18 dub respects project root/meson.build | 16 ++ .../18 dub respects project root/source/app.d | 1 + .../x/y/z/dub.json | 6 + .../x/y/z/dub.selections.json | 6 + .../x/y/z/meson.build | 10 ++ .../d/19 dub configured dependency/.gitignore | 1 + .../d/19 dub configured dependency/dub.json | 25 +++ .../dub.selections.json | 6 + .../19 dub configured dependency/meson.build | 45 ++++++ .../19 dub configured dependency/source/app.d | 1 + .../.gitignore | 1 + .../dub.json | 6 + .../dub.selections.json | 6 + .../meson.build | 20 +++ .../source/app.d | 1 + .../132 dub missing dependency/dub.json | 3 + .../dub.selections.json | 5 + .../132 dub missing dependency/meson.build | 17 ++ .../132 dub missing dependency/source/app.d | 1 + .../132 dub missing dependency/test.json | 8 + 30 files changed, 331 insertions(+), 62 deletions(-) create mode 100644 test cases/d/17 dub respects dub.selections.json/.gitignore create mode 100644 test cases/d/17 dub respects dub.selections.json/dub.json create mode 100644 test cases/d/17 dub respects dub.selections.json/dub.selections.json create mode 100644 test cases/d/17 dub respects dub.selections.json/meson.build create mode 100644 test cases/d/17 dub respects dub.selections.json/source/app.d create mode 100644 test cases/d/18 dub respects project root/.gitignore create mode 100644 test cases/d/18 dub respects project root/dub.json create mode 100644 test cases/d/18 dub respects project root/dub.selections.json create mode 100644 test cases/d/18 dub respects project root/meson.build create mode 100644 test cases/d/18 dub respects project root/source/app.d create mode 100644 test cases/d/18 dub respects project root/x/y/z/dub.json create mode 100644 test cases/d/18 dub respects project root/x/y/z/dub.selections.json create mode 100644 test cases/d/18 dub respects project root/x/y/z/meson.build create mode 100644 test cases/d/19 dub configured dependency/.gitignore create mode 100644 test cases/d/19 dub configured dependency/dub.json create mode 100644 test cases/d/19 dub configured dependency/dub.selections.json create mode 100644 test cases/d/19 dub configured dependency/meson.build create mode 100644 test cases/d/19 dub configured dependency/source/app.d create mode 100644 test cases/d/20 dub dependency multiple version reqs/.gitignore create mode 100644 test cases/d/20 dub dependency multiple version reqs/dub.json create mode 100644 test cases/d/20 dub dependency multiple version reqs/dub.selections.json create mode 100644 test cases/d/20 dub dependency multiple version reqs/meson.build create mode 100644 test cases/d/20 dub dependency multiple version reqs/source/app.d create mode 100644 test cases/failing/132 dub missing dependency/dub.json create mode 100644 test cases/failing/132 dub missing dependency/dub.selections.json create mode 100644 test cases/failing/132 dub missing dependency/meson.build create mode 100644 test cases/failing/132 dub missing dependency/source/app.d create mode 100644 test cases/failing/132 dub missing dependency/test.json diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py index 1c904ab2a5af..82929f45d441 100644 --- a/mesonbuild/dependencies/dub.py +++ b/mesonbuild/dependencies/dub.py @@ -5,10 +5,11 @@ from .base import ExternalDependency, DependencyException, DependencyTypeName from .pkgconfig import PkgConfigDependency -from ..mesonlib import (Popen_safe, join_args, version_compare) +from ..mesonlib import (Popen_safe, join_args, version_compare, version_compare_many) from ..options import OptionKey from ..programs import ExternalProgram from .. import mlog +from enum import Enum import re import os import json @@ -56,6 +57,10 @@ class FindTargetEntry(TypedDict): search: str artifactPath: str +class DubDescriptionSource(Enum): + Local = 'local' + External = 'external' + class DubDependency(ExternalDependency): # dub program and version class_dubbin: T.Optional[T.Tuple[ExternalProgram, str]] = None @@ -87,7 +92,6 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. if DubDependency.class_dubbin is None: if self.required: raise DependencyException('DUB not found.') - self.is_found = False return (self.dubbin, dubver) = DubDependency.class_dubbin # pylint: disable=unpacking-non-sequence @@ -99,6 +103,8 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. self._use_cache_describe = version_compare(dubver, '>=1.35.0') self._dub_has_build_deep = version_compare(dubver, '>=1.35.0') + self.is_found = False + if not self._search_in_cache and not self._use_cache_describe: if self.required: raise DependencyException( @@ -108,20 +114,11 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. mlog.warning(f'DUB dependency {name} not found because Dub {dubver} ' "is not compatible with Meson. (Can't locate artifacts in DUB's cache)." ' Upgrade to Dub >= 1.35') - self.is_found = False return mlog.debug('Determining dependency {!r} with DUB executable ' '{!r}'.format(name, self.dubbin.get_path())) - # if an explicit version spec was stated, use this when querying Dub - main_pack_spec = name - if 'version' in kwargs: - version_spec = kwargs['version'] - if isinstance(version_spec, list): - version_spec = " ".join(version_spec) - main_pack_spec = f'{name}@{version_spec}' - # we need to know the target architecture dub_arch = self.compiler.arch @@ -135,37 +132,11 @@ def __init__(self, name: str, environment: 'Environment', kwargs: T.Dict[str, T. elif dub_buildtype == 'minsize': dub_buildtype = 'release' - # A command that might be useful in case of missing DUB package - def dub_build_deep_command() -> str: - if self._dub_has_build_deep: - cmd = ['dub', 'build', '--deep'] - else: - cmd = ['dub', 'run', '--yes', 'dub-build-deep', '--'] - - return join_args(cmd + [ - main_pack_spec, - '--arch=' + dub_arch, - '--compiler=' + self.compiler.get_exelist()[-1], - '--build=' + dub_buildtype - ]) - - # Ask dub for the package - describe_cmd = [ - 'describe', main_pack_spec, '--arch=' + dub_arch, - '--build=' + dub_buildtype, '--compiler=' + self.compiler.get_exelist()[-1] - ] - ret, res, err = self._call_dubbin(describe_cmd) - - if ret != 0: - mlog.debug('DUB describe failed: ' + err) - if 'locally' in err: - mlog.error(mlog.bold(main_pack_spec), 'is not present locally. You may try the following command:') - mlog.log(mlog.bold(dub_build_deep_command())) - self.is_found = False + result = self._get_dub_description(dub_arch, dub_buildtype) + if result is None: return - + description, build_cmd, description_source = result dub_comp_id = self._ID_MAP[self.compiler.get_id()] - description: DubDescription = json.loads(res) self.compile_args = [] self.link_args = self.raw_link_args = [] @@ -204,7 +175,7 @@ def find_package_target(pkg: DubPackDesc) -> bool: mlog.error(mlog.bold(pack_id), 'not found') mlog.log('You may try the following command to install the necessary DUB libraries:') - mlog.log(mlog.bold(dub_build_deep_command())) + mlog.log(mlog.bold(build_cmd)) return False @@ -223,33 +194,45 @@ def find_package_target(pkg: DubPackDesc) -> bool: # 4. Add other build settings (imports, versions etc.) # 1 - self.is_found = False packages: T.Dict[str, DubPackDesc] = {} + found_it = False for pkg in description['packages']: packages[pkg['name']] = pkg if not pkg['active']: continue - if pkg['targetType'] == 'dynamicLibrary': - mlog.error('DUB dynamic library dependencies are not supported.') - self.is_found = False - return - # check that the main dependency is indeed a library if pkg['name'] == name: - self.is_found = True - if pkg['targetType'] not in ['library', 'sourceLibrary', 'staticLibrary']: - mlog.error(mlog.bold(name), "found but it isn't a library") - self.is_found = False + mlog.error(mlog.bold(name), "found but it isn't a static library, it is:", + pkg['targetType']) return + if self.version_reqs is not None: + ver = pkg['version'] + if not version_compare_many(ver, self.version_reqs)[0]: + mlog.error(mlog.bold(f'{name}@{ver}'), + 'does not satisfy all version requirements of:', + ' '.join(self.version_reqs)) + return + + found_it = True self.version = pkg['version'] self.pkg = pkg + if not found_it: + mlog.error(f'Could not find {name} in DUB description.') + if description_source is DubDescriptionSource.Local: + mlog.log('Make sure that the dependency is registered for your dub project by running:') + mlog.log(mlog.bold(f'dub add {name}')) + elif description_source is DubDescriptionSource.External: + # It shouldn't be possible to get here + mlog.log('Make sure that the dependency is built:') + mlog.log(mlog.bold(build_cmd)) + return + if name not in targets: - self.is_found = False if self.pkg['targetType'] == 'sourceLibrary': # source libraries have no associated targets, # but some build settings like import folders must be found from the package object. @@ -258,10 +241,7 @@ def find_package_target(pkg: DubPackDesc) -> bool: # (See openssl DUB package for example of sourceLibrary) mlog.error('DUB targets of type', mlog.bold('sourceLibrary'), 'are not supported.') else: - mlog.error('Could not find target description for', mlog.bold(main_pack_spec)) - - if not self.is_found: - mlog.error(f'Could not find {name} in DUB description') + mlog.error('Could not find target description for', mlog.bold(self.name)) return # Current impl only supports static libraries @@ -269,19 +249,17 @@ def find_package_target(pkg: DubPackDesc) -> bool: # 2 if not find_package_target(self.pkg): - self.is_found = False return # 3 for link_dep in targets[name]['linkDependencies']: pkg = packages[link_dep] if not find_package_target(pkg): - self.is_found = False return if show_buildtype_warning: mlog.log('If it is not suitable, try the following command and reconfigure Meson with', mlog.bold('--clearcache')) - mlog.log(mlog.bold(dub_build_deep_command())) + mlog.log(mlog.bold(build_cmd)) # 4 bs = targets[name]['buildSettings'] @@ -345,6 +323,60 @@ def find_package_target(pkg: DubPackDesc) -> bool: # fallback self.link_args.append('-l'+lib) + self.is_found = True + + # Get the dub description needed to resolve the dependency and a + # build command that can be used to build the dependency in case it is + # not present. + def _get_dub_description(self, dub_arch: str, dub_buildtype: str) -> T.Optional[T.Tuple[DubDescription, str, DubDescriptionSource]]: + def get_build_command() -> T.List[str]: + if self._dub_has_build_deep: + cmd = ['dub', 'build', '--deep'] + else: + cmd = ['dub', 'run', '--yes', 'dub-build-deep', '--'] + + return cmd + [ + '--arch=' + dub_arch, + '--compiler=' + self.compiler.get_exelist()[-1], + '--build=' + dub_buildtype, + ] + + # Ask dub for the package + describe_cmd = [ + 'describe', '--arch=' + dub_arch, + '--build=' + dub_buildtype, '--compiler=' + self.compiler.get_exelist()[-1] + ] + helper_build = join_args(get_build_command()) + source = DubDescriptionSource.Local + ret, res, err = self._call_dubbin(describe_cmd) + if ret == 0: + return (json.loads(res), helper_build, source) + + pack_spec = self.name + if self.version_reqs is not None: + if len(self.version_reqs) > 1: + mlog.error('Multiple version requirements are not supported for raw dub dependencies.') + mlog.error("Please specify only an exact version like '1.2.3'") + raise DependencyException('Multiple version requirements are not solvable for raw dub depencies') + elif len(self.version_reqs) == 1: + pack_spec += '@' + self.version_reqs[0] + + describe_cmd = [ + 'describe', pack_spec, '--arch=' + dub_arch, + '--build=' + dub_buildtype, '--compiler=' + self.compiler.get_exelist()[-1] + ] + helper_build = join_args(get_build_command() + [pack_spec]) + source = DubDescriptionSource.External + ret, res, err = self._call_dubbin(describe_cmd) + if ret == 0: + return (json.loads(res), helper_build, source) + + mlog.debug('DUB describe failed: ' + err) + if 'locally' in err: + mlog.error(mlog.bold(pack_spec), 'is not present locally. You may try the following command:') + mlog.log(mlog.bold(helper_build)) + return None + # This function finds the target of the provided JSON package, built for the right # compiler, architecture, configuration... # It returns (target|None, {compatibilities}) @@ -469,7 +501,7 @@ def _get_comp_versions_to_find(self, dub_comp_id: str) -> T.List[str]: def _call_dubbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]: assert isinstance(self.dubbin, ExternalProgram) - p, out, err = Popen_safe(self.dubbin.get_command() + args, env=env) + p, out, err = Popen_safe(self.dubbin.get_command() + args, env=env, cwd=self.env.get_source_dir()) return p.returncode, out.strip(), err.strip() def _call_compbin(self, args: T.List[str], env: T.Optional[T.Dict[str, str]] = None) -> T.Tuple[int, str, str]: diff --git a/test cases/d/11 dub/meson.build b/test cases/d/11 dub/meson.build index 91955710e709..d4c6fa440191 100644 --- a/test cases/d/11 dub/meson.build +++ b/test cases/d/11 dub/meson.build @@ -17,7 +17,7 @@ test('test urld', test_exe) # If you want meson to generate/update a dub.json file dlang = import('dlang') -dlang.generate_dub_file(meson.project_name().to_lower(), meson.source_root(), +dlang.generate_dub_file(meson.project_name().to_lower(), meson.build_root(), authors: 'Meson Team', description: 'Test executable', copyright: 'Copyright © 2018, Meson Team', @@ -25,4 +25,4 @@ dlang.generate_dub_file(meson.project_name().to_lower(), meson.source_root(), sourceFiles: 'test.d', targetType: 'executable', dependencies: urld_dep -) \ No newline at end of file +) diff --git a/test cases/d/17 dub respects dub.selections.json/.gitignore b/test cases/d/17 dub respects dub.selections.json/.gitignore new file mode 100644 index 000000000000..3f5829545224 --- /dev/null +++ b/test cases/d/17 dub respects dub.selections.json/.gitignore @@ -0,0 +1 @@ +dub-respects-dub-selections-json* diff --git a/test cases/d/17 dub respects dub.selections.json/dub.json b/test cases/d/17 dub respects dub.selections.json/dub.json new file mode 100644 index 000000000000..7c8e3ec06031 --- /dev/null +++ b/test cases/d/17 dub respects dub.selections.json/dub.json @@ -0,0 +1,6 @@ +{ + "name": "dub-respects-dub-selections-json", + "dependencies": { + "urld": "2.0.2" + } +} diff --git a/test cases/d/17 dub respects dub.selections.json/dub.selections.json b/test cases/d/17 dub respects dub.selections.json/dub.selections.json new file mode 100644 index 000000000000..d5cb275d85ff --- /dev/null +++ b/test cases/d/17 dub respects dub.selections.json/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "urld": "2.0.2" + } +} diff --git a/test cases/d/17 dub respects dub.selections.json/meson.build b/test cases/d/17 dub respects dub.selections.json/meson.build new file mode 100644 index 000000000000..fd50274d3f6d --- /dev/null +++ b/test cases/d/17 dub respects dub.selections.json/meson.build @@ -0,0 +1,25 @@ +project('Dub dependency respects dub.selections.json', 'd') + +dub_exe = find_program('dub', required : false) +if not dub_exe.found() + error('MESON_SKIP_TEST: Dub not found') +endif + +dub_ver = dub_exe.version() +if not dub_ver.version_compare('>=1.35.0') + error('MESON_SKIP_TEST: test requires dub >=1.35.0') +endif + +dc = meson.get_compiler('d').cmd_array()[0] +arch = host_machine.cpu_family() + +root = meson.source_root() +run_command(dub_exe, 'build', '--deep', '--compiler', dc, '--arch', arch, + '--root', root, + check: true) +urld = dependency('urld', method: 'dub') + +version = urld.version() +if version != '2.0.2' + error(f'Expected urld version to be the one selected in dub.selections.json but got @version@') +endif diff --git a/test cases/d/17 dub respects dub.selections.json/source/app.d b/test cases/d/17 dub respects dub.selections.json/source/app.d new file mode 100644 index 000000000000..d66321b3c581 --- /dev/null +++ b/test cases/d/17 dub respects dub.selections.json/source/app.d @@ -0,0 +1 @@ +void main () {} diff --git a/test cases/d/18 dub respects project root/.gitignore b/test cases/d/18 dub respects project root/.gitignore new file mode 100644 index 000000000000..d40ae8d2de4a --- /dev/null +++ b/test cases/d/18 dub respects project root/.gitignore @@ -0,0 +1 @@ +dub-respects-project-root* diff --git a/test cases/d/18 dub respects project root/dub.json b/test cases/d/18 dub respects project root/dub.json new file mode 100644 index 000000000000..b2ee577260bb --- /dev/null +++ b/test cases/d/18 dub respects project root/dub.json @@ -0,0 +1,6 @@ +{ + "name": "dub-respects-project-root", + "dependencies": { + "urld": "2.0.2" + } +} diff --git a/test cases/d/18 dub respects project root/dub.selections.json b/test cases/d/18 dub respects project root/dub.selections.json new file mode 100644 index 000000000000..d5cb275d85ff --- /dev/null +++ b/test cases/d/18 dub respects project root/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "urld": "2.0.2" + } +} diff --git a/test cases/d/18 dub respects project root/meson.build b/test cases/d/18 dub respects project root/meson.build new file mode 100644 index 000000000000..d0d1cdd0a2ce --- /dev/null +++ b/test cases/d/18 dub respects project root/meson.build @@ -0,0 +1,16 @@ +project('Dub describes project root', 'd') + +dub_exe = find_program('dub', required : false) +if not dub_exe.found() + error('MESON_SKIP_TEST: Dub not found') +endif + +dub_ver = dub_exe.version() +if not dub_ver.version_compare('>=1.35.0') + error('MESON_SKIP_TEST: test requires dub >=1.35.0') +endif + +dc = meson.get_compiler('d').cmd_array()[0] +arch = host_machine.cpu_family() + +subdir('x/y/z') diff --git a/test cases/d/18 dub respects project root/source/app.d b/test cases/d/18 dub respects project root/source/app.d new file mode 100644 index 000000000000..d66321b3c581 --- /dev/null +++ b/test cases/d/18 dub respects project root/source/app.d @@ -0,0 +1 @@ +void main () {} diff --git a/test cases/d/18 dub respects project root/x/y/z/dub.json b/test cases/d/18 dub respects project root/x/y/z/dub.json new file mode 100644 index 000000000000..0442acb863e0 --- /dev/null +++ b/test cases/d/18 dub respects project root/x/y/z/dub.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "urld": "~>3.0.1" + }, + "name": "dub-respects-project-root-subdir" +} diff --git a/test cases/d/18 dub respects project root/x/y/z/dub.selections.json b/test cases/d/18 dub respects project root/x/y/z/dub.selections.json new file mode 100644 index 000000000000..a7acd78516f4 --- /dev/null +++ b/test cases/d/18 dub respects project root/x/y/z/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "urld": "3.0.1" + } +} diff --git a/test cases/d/18 dub respects project root/x/y/z/meson.build b/test cases/d/18 dub respects project root/x/y/z/meson.build new file mode 100644 index 000000000000..a4a1420ac441 --- /dev/null +++ b/test cases/d/18 dub respects project root/x/y/z/meson.build @@ -0,0 +1,10 @@ +root = meson.source_root() +run_command(dub_exe, 'build', '--deep', '--compiler', dc, '--arch', arch, + '--root', root, + check: true) +urld = dependency('urld', method: 'dub') + +version = urld.version() +if version != '2.0.2' + error(f'Expected urld version to be the one selected in "@root@/dub.selections.json" but got @version@') +endif diff --git a/test cases/d/19 dub configured dependency/.gitignore b/test cases/d/19 dub configured dependency/.gitignore new file mode 100644 index 000000000000..c61a31998422 --- /dev/null +++ b/test cases/d/19 dub configured dependency/.gitignore @@ -0,0 +1 @@ +lib19-this-package* diff --git a/test cases/d/19 dub configured dependency/dub.json b/test cases/d/19 dub configured dependency/dub.json new file mode 100644 index 000000000000..f4e6db25496e --- /dev/null +++ b/test cases/d/19 dub configured dependency/dub.json @@ -0,0 +1,25 @@ +{ + "name": "19-this-package", + "subPackages": [ + { + "name": "dep", + "configurations": [ + { + "name": "default", + "targetType": "library" + }, + { + "name": "custom", + "targetType": "library" + } + ] + } + ], + "dependencies": { + ":dep": "*" + }, + "subConfigurations": { + "19-this-package:dep": "custom" + }, + "targetType": "library" +} diff --git a/test cases/d/19 dub configured dependency/dub.selections.json b/test cases/d/19 dub configured dependency/dub.selections.json new file mode 100644 index 000000000000..34876737fba0 --- /dev/null +++ b/test cases/d/19 dub configured dependency/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "inifiled": "2.0.0" + } +} diff --git a/test cases/d/19 dub configured dependency/meson.build b/test cases/d/19 dub configured dependency/meson.build new file mode 100644 index 000000000000..89e07aad0025 --- /dev/null +++ b/test cases/d/19 dub configured dependency/meson.build @@ -0,0 +1,45 @@ +project('Dub dependency respects dub.selections.json', 'd') + +dub_exe = find_program('dub', required : false) +if not dub_exe.found() + error('MESON_SKIP_TEST: Dub not found') +endif + +dub_ver = dub_exe.version() +if not dub_ver.version_compare('>=1.35.0') + error('MESON_SKIP_TEST: test requires dub >=1.35.0') +endif + +dc = meson.get_compiler('d').cmd_array()[0] +arch = host_machine.cpu_family() + +# Test that the dependency resolution will only find dub packages as +# described in dub.json. In this case we test that the configurations +# must match. + +# 1. clean all built artifacts for this package + +root = meson.source_root() +run_command(dub_exe, 'clean', '--root', root, + check: true) + +# 2. Compile the dependency with the wrong configuration +# (dub.json expectes '--config custom') +run_command(dub_exe, 'build', '--deep', '--compiler', dc, '--arch', arch, + '--root', root, ':dep', '--config', 'default', + check: true) +bad_configuration = dependency('19-this-package:dep', method: 'dub', required: false) + +if bad_configuration.found() + error('Dependecy should not have been found because it is not built with the proper configuration') +endif + +# 3. Compile the dependency with the right configuration +# For caching reasons, the names provided to `dependency()` must differ. +run_command(dub_exe, 'build', '--deep', '--compiler', dc, '--arch', arch, + '--root', root, + check: true) +good_configuration = dependency('19-this-package', method: 'dub', required: false) +if not good_configuration.found() + error('Did not find dependecy after build with the proper configuration') +endif diff --git a/test cases/d/19 dub configured dependency/source/app.d b/test cases/d/19 dub configured dependency/source/app.d new file mode 100644 index 000000000000..d66321b3c581 --- /dev/null +++ b/test cases/d/19 dub configured dependency/source/app.d @@ -0,0 +1 @@ +void main () {} diff --git a/test cases/d/20 dub dependency multiple version reqs/.gitignore b/test cases/d/20 dub dependency multiple version reqs/.gitignore new file mode 100644 index 000000000000..6b10c73f2fe0 --- /dev/null +++ b/test cases/d/20 dub dependency multiple version reqs/.gitignore @@ -0,0 +1 @@ +20-vers-reqs* diff --git a/test cases/d/20 dub dependency multiple version reqs/dub.json b/test cases/d/20 dub dependency multiple version reqs/dub.json new file mode 100644 index 000000000000..902776681038 --- /dev/null +++ b/test cases/d/20 dub dependency multiple version reqs/dub.json @@ -0,0 +1,6 @@ +{ + "name": "20-vers-reqs", + "dependencies": { + "urld": "==3.0.1" + } +} diff --git a/test cases/d/20 dub dependency multiple version reqs/dub.selections.json b/test cases/d/20 dub dependency multiple version reqs/dub.selections.json new file mode 100644 index 000000000000..a7acd78516f4 --- /dev/null +++ b/test cases/d/20 dub dependency multiple version reqs/dub.selections.json @@ -0,0 +1,6 @@ +{ + "fileVersion": 1, + "versions": { + "urld": "3.0.1" + } +} diff --git a/test cases/d/20 dub dependency multiple version reqs/meson.build b/test cases/d/20 dub dependency multiple version reqs/meson.build new file mode 100644 index 000000000000..7c0497e5e989 --- /dev/null +++ b/test cases/d/20 dub dependency multiple version reqs/meson.build @@ -0,0 +1,20 @@ +project('Dub dependency with multiple version requirements', 'd') + +dub_exe = find_program('dub', required : false) +if not dub_exe.found() + error('MESON_SKIP_TEST: Dub not found') +endif + +dub_ver = dub_exe.version() +if not dub_ver.version_compare('>=1.35.0') + error('MESON_SKIP_TEST: test requires dub >=1.35.0') +endif + +dc = meson.get_compiler('d').cmd_array()[0] +arch = host_machine.cpu_family() + +root = meson.source_root() +run_command(dub_exe, 'build', '--deep', '--compiler', dc, '--arch', arch, + '--root', root, + check: true) +urld = dependency('urld', method: 'dub', version: [ '<3.1.0', '>=3.0.0', '>2.9.9' ]) diff --git a/test cases/d/20 dub dependency multiple version reqs/source/app.d b/test cases/d/20 dub dependency multiple version reqs/source/app.d new file mode 100644 index 000000000000..d66321b3c581 --- /dev/null +++ b/test cases/d/20 dub dependency multiple version reqs/source/app.d @@ -0,0 +1 @@ +void main () {} diff --git a/test cases/failing/132 dub missing dependency/dub.json b/test cases/failing/132 dub missing dependency/dub.json new file mode 100644 index 000000000000..1ad9ddcc1f19 --- /dev/null +++ b/test cases/failing/132 dub missing dependency/dub.json @@ -0,0 +1,3 @@ +{ + "name": "132-missing-dep" +} diff --git a/test cases/failing/132 dub missing dependency/dub.selections.json b/test cases/failing/132 dub missing dependency/dub.selections.json new file mode 100644 index 000000000000..322586b10676 --- /dev/null +++ b/test cases/failing/132 dub missing dependency/dub.selections.json @@ -0,0 +1,5 @@ +{ + "fileVersion": 1, + "versions": { + } +} diff --git a/test cases/failing/132 dub missing dependency/meson.build b/test cases/failing/132 dub missing dependency/meson.build new file mode 100644 index 000000000000..fcccb3b415d4 --- /dev/null +++ b/test cases/failing/132 dub missing dependency/meson.build @@ -0,0 +1,17 @@ +project('Dub dependency not in dub.json') + +if not add_languages('d', required: false) + error('MESON_SKIP_TEST test requires D compiler') +endif + +dub_exe = find_program('dub', required : false) +if not dub_exe.found() + error('MESON_SKIP_TEST: Dub not found') +endif + +dub_ver = dub_exe.version() +if not dub_ver.version_compare('>=1.35.0') + error('MESON_SKIP_TEST: test requires dub >=1.35.0') +endif + +dep = dependency('urld', method: 'dub') # not in dub.json diff --git a/test cases/failing/132 dub missing dependency/source/app.d b/test cases/failing/132 dub missing dependency/source/app.d new file mode 100644 index 000000000000..d66321b3c581 --- /dev/null +++ b/test cases/failing/132 dub missing dependency/source/app.d @@ -0,0 +1 @@ +void main () {} diff --git a/test cases/failing/132 dub missing dependency/test.json b/test cases/failing/132 dub missing dependency/test.json new file mode 100644 index 000000000000..e58dbc7aabee --- /dev/null +++ b/test cases/failing/132 dub missing dependency/test.json @@ -0,0 +1,8 @@ +{ + "stdout": [ + { + "line": "test cases/failing/132 dub missing dependency/meson.build:17:6: ERROR: Dependency \"urld\" not found", + "line": "dub add urld" + } + ] +}