diff --git a/ciimage/Dockerfile b/ciimage/Dockerfile index 25cc6fa3e..326013bc2 100644 --- a/ciimage/Dockerfile +++ b/ciimage/Dockerfile @@ -13,9 +13,13 @@ RUN apt-get -y update && apt-get -y upgrade \ && apt-get -y install python-dev \ && apt-get -y install libomp-dev openssh-client \ && apt-get -y install -y clang libclang-dev llvm-dev flex \ +&& apt-get -y install gdc ldc \ && python3 -m pip install hotdoc codecov \ && dub fetch urld \ -&& dub build urld --compiler=gdc +&& dub build urld --compiler=gdc \ +&& dub fetch dubtestproject \ +&& dub build dubtestproject:test1 --compiler=ldc2 \ +&& dub build dubtestproject:test2 --compiler=ldc2 # OpenSSH client is needed to run openmpi binaries. diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index c81c048df..118a662b7 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -95,6 +95,9 @@ class DCompiler(Compiler): def name_string(self): return ' '.join(self.exelist) + def get_exelist(self): + return self.exelist + def get_linker_exelist(self): return self.exelist[:] @@ -292,6 +295,11 @@ class DCompiler(Compiler): # a linker search path. dcargs.append('-L' + arg) continue + elif arg.startswith('/') or arg.startswith('./'): + # absolute (or relative) paths passed to the linker may be static libraries + # or other objects that we need to link. + dcargs.append('-L' + arg) + continue elif arg.startswith('-mscrtlib='): mscrtlib = arg[10:].lower() @@ -307,6 +315,7 @@ class DCompiler(Compiler): dcargs.append('-L/DEFAULTLIB:legacy_stdio_definitions.lib') dcargs.append(arg) + continue dcargs.append(arg) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index 04c47019e..e375f102a 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -24,6 +24,7 @@ import json import shlex import shutil import textwrap +import platform from enum import Enum from pathlib import PurePath @@ -849,12 +850,13 @@ class DubDependency(ExternalDependency): super().__init__('dub', environment, 'd', kwargs) self.name = name self.compiler = super().get_compiler() + self.module_path = None if 'required' in kwargs: self.required = kwargs.get('required') if DubDependency.class_dubbin is None: - self.dubbin = self.check_dub() + self.dubbin = self._check_dub() DubDependency.class_dubbin = self.dubbin else: self.dubbin = DubDependency.class_dubbin @@ -875,20 +877,33 @@ class DubDependency(ExternalDependency): self.is_found = False return - j = json.loads(res) comp = self.compiler.get_id().replace('llvm', 'ldc').replace('gcc', 'gdc') + packages = [] + j = json.loads(res) for package in j['packages']: + packages.append(package['name']) if package['name'] == name: - if j['compiler'] != comp: - msg = ['Dependency', mlog.bold(name), 'found but it was compiled with'] - msg += [mlog.bold(j['compiler']), 'and we are using', mlog.bold(comp)] - mlog.error(*msg) + self.is_found = True + + not_lib = True + if 'targetType' in package: + if package['targetType'] == 'library': + not_lib = False + + if not_lib: + mlog.error(mlog.bold(name), 'found but it isn\'t a library') + self.is_found = False + return + + self.module_path = self._find_right_lib_path(package['path'], comp, j, True, package['targetFileName']) + + if not os.path.exists(self.module_path): + mlog.error(mlog.bold(name), 'found but it wasn\'t compiled with', mlog.bold(comp)) self.is_found = False return self.version = package['version'] self.pkg = package - break if self.pkg['targetFileName'].endswith('.a'): self.static = True @@ -899,39 +914,93 @@ class DubDependency(ExternalDependency): for path in self.pkg['importPaths']: self.compile_args.append('-I' + os.path.join(self.pkg['path'], path)) - self.link_args = [] + self.link_args = self.raw_link_args = [] for flag in self.pkg['lflags']: self.link_args.append(flag) - search_paths = [] - search_paths.append(os.path.join(self.pkg['path'], self.pkg['targetPath'])) - found, res = self.__search_paths(search_paths, self.pkg['targetFileName']) - for file in res: - self.link_args.append(file) + self.link_args.append(os.path.join(self.module_path, self.pkg['targetFileName'])) - self.is_found = found + # Handle dependencies + libs = [] + + def add_lib_args(field_name, target): + if field_name in target['buildSettings']: + if os.name is 'nt': + for lib in target['buildSettings'][field_name]: + if lib not in target['buildSettings'][field_name]: + libs.append(lib) + # TODO: Use CCompiler.find_library to find the path of the .lib files + else: # posix and everything else + for lib in target['buildSettings'][field_name]: + if lib not in libs: + libs.append(lib) + pkgdep = PkgConfigDependency(lib, environment, {'required': 'true', 'silent': 'true'}) + for arg in pkgdep.get_compile_args(): + self.compile_args.append(arg) + for arg in pkgdep.get_link_args(): + self.link_args.append(arg) + for arg in pkgdep.get_link_args(raw=True): + self.raw_link_args.append(arg) + + for target in j['targets']: + if target['rootPackage'] in packages: + add_lib_args('libs', target) + add_lib_args('libs-{}'.format(platform.machine()), target) + for file in target['buildSettings']['linkerFiles']: + self.link_args.append(self._find_right_lib_path(file, comp, j)) def get_compiler(self): return self.compiler - def __search_paths(self, search_paths, target_file): - found = False - res = [] - if target_file == '': - return True, res - for path in search_paths: - if os.path.isdir(path): - for file in os.listdir(path): - if file == target_file: - res.append(os.path.join(path, file)) - found = True - return found, res + def _find_right_lib_path(self, default_path, comp, j, folder_only=False, file_name=''): + path = '' + + module_build_path = lib_file_name = '' + if folder_only: + module_build_path = default_path + lib_file_name = file_name + else: + module_build_path = os.path.dirname(default_path) + lib_file_name = os.path.basename(default_path) + + # Get D version implemented in the compiler + # gdc doesn't support this + ret, res = self._call_dubbin(['--version']) + + if ret != 0: + mlog.error('Failed to run {!r}', mlog.bold(comp)) + self.is_found = False + return + + d_ver = re.search('v[0-9].[0-9][0-9][0-9].[0-9]', res) # Ex.: v2.081.2 + if d_ver is not None: + d_ver = d_ver.group().rsplit('.', 1)[0].replace('v', '').replace('.', '') # Fix structure. Ex.: 2081 + else: + d_ver = '' # gdc + + # Ex.: library-debug-linux.posix-x86_64-ldc_2081-EF934983A3319F8F8FF2F0E107A363BA + build_name = 'library-{}-{}.{}-{}-{}_{}'.format(j['buildType'], j['platform'][0], j['platform'][1], platform.machine(), comp, d_ver) + for entry in os.listdir(os.path.join(module_build_path, '.dub', 'build')): + if entry.startswith(build_name): + for file in os.listdir(os.path.join(module_build_path, '.dub', 'build', entry)): + if file == lib_file_name: + if folder_only: + path = os.path.join(module_build_path, '.dub', 'build', entry) + else: + path = os.path.join(module_build_path, '.dub', 'build', entry, lib_file_name) + break + + return path def _call_dubbin(self, args, env=None): p, out = Popen_safe(self.dubbin.get_command() + args, env=env)[0:2] return p.returncode, out.strip() - def check_dub(self): + def _call_copmbin(self, args, env=None): + p, out = Popen_safe(self.compiler.get_exelist() + args, env=env)[0:2] + return p.returncode, out.strip() + + def _check_dub(self): dubbin = ExternalProgram('dub', silent=True) if dubbin.found(): try: diff --git a/test cases/failing/85 dub libray/meson.build b/test cases/failing/85 dub libray/meson.build new file mode 100644 index 000000000..792171834 --- /dev/null +++ b/test cases/failing/85 dub libray/meson.build @@ -0,0 +1,3 @@ +project('dub', 'd', meson_version: '0.48.0') + +dependency('dubtestproject', method: 'dub') # Not library (none) diff --git a/test cases/failing/86 dub executable/meson.build b/test cases/failing/86 dub executable/meson.build new file mode 100644 index 000000000..a44f1beb9 --- /dev/null +++ b/test cases/failing/86 dub executable/meson.build @@ -0,0 +1,3 @@ +project('dub', 'd', meson_version: '0.48.0') + +dependency('dubtestproject:test1', method: 'dub') # Not library (executable) diff --git a/test cases/failing/87 dub compiler/meson.build b/test cases/failing/87 dub compiler/meson.build new file mode 100644 index 000000000..f5bc4946f --- /dev/null +++ b/test cases/failing/87 dub compiler/meson.build @@ -0,0 +1,3 @@ +project('dub', 'd', meson_version: '0.48.0') + +dependency('dubtestproject:test2', method: 'dub') # Compiler mismatch