summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xci/ciimage/opensuse/install.sh11
-rwxr-xr-xci/ciimage/ubuntu-rolling/install.sh11
-rw-r--r--mesonbuild/dependencies/dub.py151
-rw-r--r--test cases/d/11 dub/meson.build4
-rw-r--r--test cases/d/17 dub and meson project/.gitignore2
-rw-r--r--test cases/d/17 dub and meson project/dub.json11
-rw-r--r--test cases/d/17 dub and meson project/dub.selections.json7
-rw-r--r--test cases/d/17 dub and meson project/meson.build32
-rw-r--r--test cases/d/17 dub and meson project/multi-configuration/.gitignore2
-rw-r--r--test cases/d/17 dub and meson project/multi-configuration/dub.json14
-rw-r--r--test cases/d/17 dub and meson project/multi-configuration/dub.selections.json5
-rw-r--r--test cases/d/17 dub and meson project/multi-configuration/source/app.d1
-rw-r--r--test cases/d/17 dub and meson project/multi-configuration/source/foo.d0
-rw-r--r--test cases/d/17 dub and meson project/source/app.d1
-rw-r--r--test cases/d/17 dub and meson project/x/y/z/dub.json6
-rw-r--r--test cases/d/17 dub and meson project/x/y/z/dub.selections.json6
-rw-r--r--test cases/d/17 dub and meson project/x/y/z/meson.build6
-rw-r--r--test cases/failing/133 dub missing dependency/dub.json3
-rw-r--r--test cases/failing/133 dub missing dependency/dub.selections.json5
-rw-r--r--test cases/failing/133 dub missing dependency/meson.build17
-rw-r--r--test cases/failing/133 dub missing dependency/source/app.d1
-rw-r--r--test cases/failing/133 dub missing dependency/test.json8
22 files changed, 231 insertions, 73 deletions
diff --git a/ci/ciimage/opensuse/install.sh b/ci/ciimage/opensuse/install.sh
index 5ee1f6435..43b0f7c9b 100755
--- a/ci/ciimage/opensuse/install.sh
+++ b/ci/ciimage/opensuse/install.sh
@@ -42,11 +42,12 @@ echo 'ulimit -n -S 10000' >> /ci/env_vars.sh
source /ci/env_vars.sh
-dub_fetch urld
-dub build --deep urld --arch=x86_64 --compiler=dmd --build=debug
-dub_fetch dubtestproject
-dub build dubtestproject:test1 --compiler=dmd
-dub build dubtestproject:test2 --compiler=dmd
+dub_fetch dubtestproject@1.2.0
+dub build dubtestproject:test1 --compiler=dmd --arch=x86_64
+dub build dubtestproject:test2 --compiler=dmd --arch=x86_64
+dub build dubtestproject:test3 --compiler=dmd --arch=x86_64
+dub_fetch urld@3.0.0
+dub build urld --compiler=dmd --arch=x86_64
# Cleanup
zypper --non-interactive clean --all
diff --git a/ci/ciimage/ubuntu-rolling/install.sh b/ci/ciimage/ubuntu-rolling/install.sh
index 212ed020a..1c0891c23 100755
--- a/ci/ciimage/ubuntu-rolling/install.sh
+++ b/ci/ciimage/ubuntu-rolling/install.sh
@@ -50,11 +50,12 @@ install_python_packages hotdoc
echo 'ulimit -n -S 10000' >> /ci/env_vars.sh
ulimit -n -S 10000
# dub stuff
-dub_fetch urld
-dub build --deep urld --arch=x86_64 --compiler=gdc --build=debug
-dub_fetch dubtestproject
-dub build dubtestproject:test1 --compiler=ldc2
-dub build dubtestproject:test2 --compiler=ldc2
+dub_fetch dubtestproject@1.2.0
+dub build dubtestproject:test1 --compiler=ldc2 --arch=x86_64
+dub build dubtestproject:test2 --compiler=ldc2 --arch=x86_64
+dub build dubtestproject:test3 --compiler=gdc --arch=x86_64
+dub_fetch urld@3.0.0
+dub build urld --compiler=gdc --arch=x86_64
# Remove debian version of Rust and install latest with rustup.
# This is needed to get the cross toolchain as well.
diff --git a/mesonbuild/dependencies/dub.py b/mesonbuild/dependencies/dub.py
index 009e4f46f..6b6d28306 100644
--- a/mesonbuild/dependencies/dub.py
+++ b/mesonbuild/dependencies/dub.py
@@ -5,10 +5,11 @@ from __future__ import annotations
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 @@ if T.TYPE_CHECKING:
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,14 +92,13 @@ class DubDependency(ExternalDependency):
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
assert isinstance(self.dubbin, ExternalProgram)
- # Check if Dub's compatibility with Meson
+ # Check Dub's compatibility with Meson
self._search_in_cache = version_compare(dubver, '<=1.31.1')
self._use_cache_describe = version_compare(dubver, '>=1.35.0')
self._dub_has_build_deep = version_compare(dubver, '>=1.35.0')
@@ -108,20 +112,11 @@ class DubDependency(ExternalDependency):
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 +130,11 @@ class DubDependency(ExternalDependency):
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 +173,7 @@ class DubDependency(ExternalDependency):
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 +192,44 @@ class DubDependency(ExternalDependency):
# 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:
+ # `dub describe pkg` did not contain the pkg
+ raise RuntimeError(f'`dub describe` succeeded but it does not contains {name}')
+ 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 +238,7 @@ class DubDependency(ExternalDependency):
# (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 +246,17 @@ class DubDependency(ExternalDependency):
# 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 +320,60 @@ class DubDependency(ExternalDependency):
# 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 +498,7 @@ class DubDependency(ExternalDependency):
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 cfdb7fa59..fe79e046e 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 and meson project/.gitignore b/test cases/d/17 dub and meson project/.gitignore
new file mode 100644
index 000000000..0036ff394
--- /dev/null
+++ b/test cases/d/17 dub and meson project/.gitignore
@@ -0,0 +1,2 @@
+17-dub-meson-project*
+lib17-dub-meson-project*
diff --git a/test cases/d/17 dub and meson project/dub.json b/test cases/d/17 dub and meson project/dub.json
new file mode 100644
index 000000000..f04e51b55
--- /dev/null
+++ b/test cases/d/17 dub and meson project/dub.json
@@ -0,0 +1,11 @@
+{
+ "name": "17-dub-meson-project",
+ "dependencies": {
+ "urld": ">=3.0.0 <3.0.1",
+ "dubtestproject:test3": "1.2.0",
+ ":multi-configuration": "*"
+ },
+ "subPackages": [
+ "multi-configuration"
+ ]
+}
diff --git a/test cases/d/17 dub and meson project/dub.selections.json b/test cases/d/17 dub and meson project/dub.selections.json
new file mode 100644
index 000000000..ad72f3168
--- /dev/null
+++ b/test cases/d/17 dub and meson project/dub.selections.json
@@ -0,0 +1,7 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ "dubtestproject": "1.2.0",
+ "urld": "3.0.0"
+ }
+}
diff --git a/test cases/d/17 dub and meson project/meson.build b/test cases/d/17 dub and meson project/meson.build
new file mode 100644
index 000000000..9070e6c72
--- /dev/null
+++ b/test cases/d/17 dub and meson project/meson.build
@@ -0,0 +1,32 @@
+project('Meson integration with dub.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
+
+# Multiple versions supported
+urld = dependency('urld', method: 'dub', version: [ '>=3.0.0', '<3.0.1' ])
+
+# The version we got is the one in dub.selections.json
+version = urld.version()
+if version != '3.0.0'
+ error(f'Expected urld version to be the one selected in dub.selections.json but got @version@')
+endif
+
+# dependency calls from subdirectories respect meson.project_source_root()/dub.selections.json
+subdir('x/y/z')
+
+# dependencies respect their configuration selected in dub.json
+run_command(dub_exe, 'build', '--deep', ':multi-configuration',
+ '--compiler', meson.get_compiler('d').cmd_array()[0],
+ '--arch', host_machine.cpu_family(),
+ '--root', meson.project_source_root(),
+ '--config', 'lib',
+ check: true)
+found = dependency('17-dub-meson-project:multi-configuration', method: 'dub')
diff --git a/test cases/d/17 dub and meson project/multi-configuration/.gitignore b/test cases/d/17 dub and meson project/multi-configuration/.gitignore
new file mode 100644
index 000000000..61763ee20
--- /dev/null
+++ b/test cases/d/17 dub and meson project/multi-configuration/.gitignore
@@ -0,0 +1,2 @@
+libmulti-configuration*
+multi-configuration*
diff --git a/test cases/d/17 dub and meson project/multi-configuration/dub.json b/test cases/d/17 dub and meson project/multi-configuration/dub.json
new file mode 100644
index 000000000..373176d9e
--- /dev/null
+++ b/test cases/d/17 dub and meson project/multi-configuration/dub.json
@@ -0,0 +1,14 @@
+{
+ "name": "multi-configuration",
+ "configurations": {
+ "app": {
+ "targetType": "executable"
+ },
+ "lib": {
+ "targetType": "library",
+ "excludedSourceFiles": [
+ "source/app.d"
+ ]
+ }
+ }
+}
diff --git a/test cases/d/17 dub and meson project/multi-configuration/dub.selections.json b/test cases/d/17 dub and meson project/multi-configuration/dub.selections.json
new file mode 100644
index 000000000..322586b10
--- /dev/null
+++ b/test cases/d/17 dub and meson project/multi-configuration/dub.selections.json
@@ -0,0 +1,5 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ }
+}
diff --git a/test cases/d/17 dub and meson project/multi-configuration/source/app.d b/test cases/d/17 dub and meson project/multi-configuration/source/app.d
new file mode 100644
index 000000000..d66321b3c
--- /dev/null
+++ b/test cases/d/17 dub and meson project/multi-configuration/source/app.d
@@ -0,0 +1 @@
+void main () {}
diff --git a/test cases/d/17 dub and meson project/multi-configuration/source/foo.d b/test cases/d/17 dub and meson project/multi-configuration/source/foo.d
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/test cases/d/17 dub and meson project/multi-configuration/source/foo.d
diff --git a/test cases/d/17 dub and meson project/source/app.d b/test cases/d/17 dub and meson project/source/app.d
new file mode 100644
index 000000000..d66321b3c
--- /dev/null
+++ b/test cases/d/17 dub and meson project/source/app.d
@@ -0,0 +1 @@
+void main () {}
diff --git a/test cases/d/17 dub and meson project/x/y/z/dub.json b/test cases/d/17 dub and meson project/x/y/z/dub.json
new file mode 100644
index 000000000..dc0ef5159
--- /dev/null
+++ b/test cases/d/17 dub and meson project/x/y/z/dub.json
@@ -0,0 +1,6 @@
+{
+ "dependencies": {
+ "dubtestproject:test3": "*"
+ },
+ "name": "dub-respects-project-root-subdir"
+}
diff --git a/test cases/d/17 dub and meson project/x/y/z/dub.selections.json b/test cases/d/17 dub and meson project/x/y/z/dub.selections.json
new file mode 100644
index 000000000..daf7a2de9
--- /dev/null
+++ b/test cases/d/17 dub and meson project/x/y/z/dub.selections.json
@@ -0,0 +1,6 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ "dubtestproject": "1.3.0"
+ }
+}
diff --git a/test cases/d/17 dub and meson project/x/y/z/meson.build b/test cases/d/17 dub and meson project/x/y/z/meson.build
new file mode 100644
index 000000000..99943b8a7
--- /dev/null
+++ b/test cases/d/17 dub and meson project/x/y/z/meson.build
@@ -0,0 +1,6 @@
+root = meson.project_source_root()
+dep = dependency('dubtestproject:test3', method: 'dub')
+version = dep.version()
+if version != '1.2.0'
+ error(f'Expected urld version to be the one selected in "@root@/dub.selections.json" but got @version@')
+endif
diff --git a/test cases/failing/133 dub missing dependency/dub.json b/test cases/failing/133 dub missing dependency/dub.json
new file mode 100644
index 000000000..1ad9ddcc1
--- /dev/null
+++ b/test cases/failing/133 dub missing dependency/dub.json
@@ -0,0 +1,3 @@
+{
+ "name": "132-missing-dep"
+}
diff --git a/test cases/failing/133 dub missing dependency/dub.selections.json b/test cases/failing/133 dub missing dependency/dub.selections.json
new file mode 100644
index 000000000..322586b10
--- /dev/null
+++ b/test cases/failing/133 dub missing dependency/dub.selections.json
@@ -0,0 +1,5 @@
+{
+ "fileVersion": 1,
+ "versions": {
+ }
+}
diff --git a/test cases/failing/133 dub missing dependency/meson.build b/test cases/failing/133 dub missing dependency/meson.build
new file mode 100644
index 000000000..fcccb3b41
--- /dev/null
+++ b/test cases/failing/133 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/133 dub missing dependency/source/app.d b/test cases/failing/133 dub missing dependency/source/app.d
new file mode 100644
index 000000000..d66321b3c
--- /dev/null
+++ b/test cases/failing/133 dub missing dependency/source/app.d
@@ -0,0 +1 @@
+void main () {}
diff --git a/test cases/failing/133 dub missing dependency/test.json b/test cases/failing/133 dub missing dependency/test.json
new file mode 100644
index 000000000..e58dbc7aa
--- /dev/null
+++ b/test cases/failing/133 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"
+ }
+ ]
+}