diff options
-rw-r--r-- | .travis.yml | 2 | ||||
-rw-r--r-- | docs/markdown/Contributing.md | 39 | ||||
-rw-r--r-- | mesonbuild/compilers/compilers.py | 19 | ||||
-rw-r--r-- | mesonbuild/compilers/d.py | 85 | ||||
-rw-r--r-- | mesonbuild/compilers/mixins/visualstudio.py | 4 | ||||
-rw-r--r-- | mesonbuild/environment.py | 90 | ||||
-rw-r--r-- | mesonbuild/linkers.py | 15 | ||||
-rwxr-xr-x | run_project_tests.py | 79 | ||||
-rw-r--r-- | test cases/d/1 simple/test.json | 3 | ||||
-rw-r--r-- | test cases/d/2 static library/test.json | 1 | ||||
-rw-r--r-- | test cases/d/3 shared library/lld-test.py | 20 | ||||
-rw-r--r-- | test cases/d/3 shared library/meson.build | 7 | ||||
-rw-r--r-- | test cases/d/3 shared library/sub/libstuff.d | 14 | ||||
-rw-r--r-- | test cases/d/3 shared library/sub/meson.build | 2 | ||||
-rw-r--r-- | test cases/d/3 shared library/test.json | 6 | ||||
-rw-r--r-- | test cases/d/4 library versions/test.json | 38 | ||||
-rw-r--r-- | test cases/d/5 mixed/test.json | 8 | ||||
-rw-r--r-- | test cases/d/6 unittest/test.json | 3 | ||||
-rw-r--r-- | test cases/d/7 multilib/test.json | 23 |
19 files changed, 325 insertions, 133 deletions
diff --git a/.travis.yml b/.travis.yml index ed59a85..34303b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,7 @@ matrix: before_install: - python ./skip_ci.py --base-branch-env=TRAVIS_BRANCH --is-pull-env=TRAVIS_PULL_REQUEST - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt llvm ninja; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt ldc llvm ninja; fi # # Run one macOS build without pkg-config available, and the other (unity=on) with pkg-config - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MESON_ARGS" =~ .*unity=on.* ]]; then brew install pkg-config; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then docker pull jpakkane/mesonci:eoan; fi diff --git a/docs/markdown/Contributing.md b/docs/markdown/Contributing.md index 26f3512..49b485b 100644 --- a/docs/markdown/Contributing.md +++ b/docs/markdown/Contributing.md @@ -190,6 +190,7 @@ Exanple `test.json`: "installed": [ { "type": "exe", "file": "usr/bin/testexe" }, { "type": "pdb", "file": "usr/bin/testexe" }, + { "type": "shared_lib", "file": "usr/lib/z", "version": "1.2.3" }, ], "matrix": { "options": { @@ -226,6 +227,8 @@ to be installed. Each dict contains the following keys: - `file` - `type` - `platform` (optional) +- `version` (optional) +- `language` (optional) The `file` entry contains the relative path (from the install root) to the actually installed file. @@ -233,17 +236,37 @@ actually installed file. The `type` entry specifies how the `file` path should be interpreted based on the current platform. The following values are currently supported: -| `type` | Description | -| :-----------: | -------------------------------------------------------------------------------- | -| `file` | No postprocessing, just use the provided path | -| `exe` | For executables. On Windows the `.exe` suffix is added to the path in `file` | -| `pdb` | For Windows PDB files. PDB entries are ignored on non Windows platforms | -| `implib` | For Windows import libraries. These entries are ignored on non Windows platforms | -| `implibempty` | Like `implib`, but no symbols are exported in the library | -| `expr` | `file` is an expression. This type should be avoided and removed if possible | +| `type` | Description | +| :-----------: | ------------------------------------------------------------------------------------------------------- | +| `file` | No postprocessing, just use the provided path | +| `exe` | For executables. On Windows the `.exe` suffix is added to the path in `file` | +| `shared_lib` | For shared libraries, always written as `name`. The appropriate suffix and prefix are added by platform | +| `pdb` | For Windows PDB files. PDB entries are ignored on non Windows platforms | +| `implib` | For Windows import libraries. These entries are ignored on non Windows platforms | +| `implibempty` | Like `implib`, but no symbols are exported in the library | +| `expr` | `file` is an expression. This type should be avoided and removed if possible | Except for the `file` and `expr` types, all paths should be provided *without* a suffix. +| Argument | Applies to | Description | +| :---------:|----------------------------|-------------------------------------------------------------------------------| +| `version` | `shared_lib`, `pdb` | Sets the version to look for appropriately per-platform | +| `language` | `pdb` | Determines which compiler/linker determines the existence of this file | + +The `shared_lib` and `pdb` types takes an optional additional parameter, `version`, this is us a string in `X.Y.Z` format that will be applied to the library. Each version to be tested must have a single version. The harness will apply this correctly per platform: + +`pdb` takes an optional `language` argument. This determines which compiler/linker should generate the pdb file. Because it's possible to mix compilers that do and don't generate pdb files (dmd's optlink doesn't). Currently this is only needed when mixing D and C code. + +```json +{ + "type": "shared_lib", "file": "usr/lib/lib", + "type": "shared_lib", "file": "usr/lib/lib", "version": "1", + "type": "shared_lib", "file": "usr/lib/lib", "version": "1.2.3.", +} +``` + +This will be applied appropriatly per platform. On windows this expects `lib.dll` and `lib-1.dll`. on MacOS it expects `liblib.dylib` and `liblib.1.dylib`. On other Unices it expects `liblib.so`, `liblib.so.1`, and `liblib.so.1.2.3`. + If the `platform` key is present, the installed file entry is only considered if the platform matches. The following values for `platform` are currently supported: diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 366bb50..e13256e 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -536,6 +536,15 @@ class CompilerArgs(collections.abc.MutableSequence): # both of which are invalid. if arg in cls.dedup2_prefixes: return 0 + if arg.startswith('-L='): + # DMD and LDC proxy all linker arguments using -L=; in conjunction + # with ld64 on macOS this can lead to command line arguments such + # as: `-L=-compatibility_version -L=0 -L=current_version -L=0`. + # These cannot be combined, ld64 insists they must be passed with + # spaces and quoting does not work. if we deduplicate these then + # one of the -L=0 arguments will be removed and the version + # argument will consume the next argument instead. + return 0 if arg in cls.dedup2_args or \ arg.startswith(cls.dedup2_prefixes) or \ arg.endswith(cls.dedup2_suffixes): @@ -571,7 +580,17 @@ class CompilerArgs(collections.abc.MutableSequence): isinstance(self.compiler.linker, (GnuLikeDynamicLinkerMixin, SolarisDynamicLinker))): group_start = -1 group_end = -1 + is_soname = False for i, each in enumerate(new): + if is_soname: + is_soname = False + continue + elif '-soname' in each: + # To proxy these arguments with D you need to split the + # arguments, thus you get `-L=-soname -L=lib.so` we don't + # want to put the lib in a link -roup + is_soname = True + continue if not each.startswith(('-Wl,-l', '-l')) and not each.endswith('.a') and \ not soregex.match(each): continue diff --git a/mesonbuild/compilers/d.py b/mesonbuild/compilers/d.py index b974504..9a46a4e 100644 --- a/mesonbuild/compilers/d.py +++ b/mesonbuild/compilers/d.py @@ -28,7 +28,6 @@ from .compilers import ( CompilerArgs, ) from .mixins.gnu import GnuCompiler -from .mixins.islinker import LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin if T.TYPE_CHECKING: from ..envconfig import MachineInfo @@ -69,7 +68,7 @@ dmd_optimization_args = {'0': [], class DmdLikeCompilerMixin: - LINKER_PREFIX = '-L' + LINKER_PREFIX = '-L=' def get_output_args(self, target): return ['-of=' + target] @@ -214,26 +213,30 @@ class DmdLikeCompilerMixin: return [] def gen_import_library_args(self, implibname): - return ['-Wl,--out-implib=' + implibname] + return self.linker.import_library_args(implibname) def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): if self.info.is_windows(): return [] - # This method is to be used by LDC and DMD. - # GDC can deal with the verbatim flags. - if not rpath_paths and not install_rpath: - return [] - paths = ':'.join([os.path.join(build_dir, p) for p in rpath_paths]) - if build_rpath != '': - paths += ':' + build_rpath - if len(paths) < len(install_rpath): - padding = 'X' * (len(install_rpath) - len(paths)) - if not paths: - paths = padding - else: - paths = paths + ':' + padding - return ['-Wl,-rpath,{}'.format(paths)] + # GNU ld, solaris ld, and lld acting like GNU ld + if self.linker.id.startswith('ld'): + # The way that dmd and ldc pass rpath to gcc is different than we would + # do directly, each argument -rpath and the value to rpath, need to be + # split into two separate arguments both prefaced with the -L=. + args = [] + for r in super().build_rpath_args( + env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): + if ',' in r: + a, b = r.split(',', maxsplit=1) + args.append(a) + args.append(self.LINKER_PREFIX + b) + else: + args.append(r) + return args + + return super().build_rpath_args( + env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) def translate_args_to_nongnu(self, args): dcargs = [] @@ -391,15 +394,33 @@ class DmdLikeCompilerMixin: def get_soname_args(self, *args, **kwargs) -> T.List[str]: # LDC and DMD actually do use a linker, but they proxy all of that with # their own arguments - soargs = [] - for arg in Compiler.get_soname_args(self, *args, **kwargs): - soargs.append('-L=' + arg) - return soargs + if self.linker.id.startswith('ld.'): + soargs = [] + for arg in super().get_soname_args(*args, **kwargs): + a, b = arg.split(',', maxsplit=1) + soargs.append(a) + soargs.append(self.LINKER_PREFIX + b) + return soargs + elif self.linker.id.startswith('ld64'): + soargs = [] + for arg in super().get_soname_args(*args, **kwargs): + if not arg.startswith(self.LINKER_PREFIX): + soargs.append(self.LINKER_PREFIX + arg) + else: + soargs.append(arg) + return soargs + else: + return super().get_soname_args(*args, **kwargs) def get_allow_undefined_link_args(self) -> T.List[str]: - args = [] - for arg in self.linker.get_allow_undefined_args(): - args.append('-L=' + arg) + args = self.linker.get_allow_undefined_args() + if self.info.is_darwin(): + # On macOS we're passing these options to the C compiler, but + # they're linker options and need -Wl, so clang/gcc knows what to + # do with them. I'm assuming, but don't know for certain, that + # ldc/dmd do some kind of mapping internally for arguments they + # understand, but pass arguments they don't understand directly. + args = [a.replace('-L=', '-Xcc=-Wl,') for a in args] return args @@ -600,7 +621,7 @@ class DCompiler(Compiler): return [] def thread_link_flags(self, env): - return ['-pthread'] + return self.linker.thread_flags(env) def name_string(self): return ' '.join(self.exelist) @@ -658,7 +679,7 @@ class GnuDCompiler(DCompiler, GnuCompiler): return self.linker.get_allow_undefined_args() -class LLVMDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler): +class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, **kwargs): @@ -687,9 +708,6 @@ class LLVMDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompi def get_pic_args(self): return ['-relocation-model=pic'] - def get_std_shared_lib_link_args(self): - return ['-shared'] - def get_crt_link_args(self, crt_val, buildtype): return self.get_crt_args(crt_val, buildtype) @@ -699,8 +717,12 @@ class LLVMDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompi def get_optimization_args(self, optimization_level): return ldc_optimization_args[optimization_level] + @classmethod + def use_linker_args(cls, linker: str) -> T.List[str]: + return ['-linker={}'.format(linker)] + -class DmdDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompilerMixin, DCompiler): +class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): def __init__(self, exelist, version, for_machine: MachineChoice, info: 'MachineInfo', arch, **kwargs): @@ -760,3 +782,6 @@ class DmdDCompiler(DmdLikeCompilerMixin, LinkerEnvVarsMixin, BasicLinkerIsCompil def get_optimization_args(self, optimization_level): return dmd_optimization_args[optimization_level] + + def can_linker_accept_rsp(self) -> bool: + return False diff --git a/mesonbuild/compilers/mixins/visualstudio.py b/mesonbuild/compilers/mixins/visualstudio.py index a994379..44aefc8 100644 --- a/mesonbuild/compilers/mixins/visualstudio.py +++ b/mesonbuild/compilers/mixins/visualstudio.py @@ -205,10 +205,6 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): objname = os.path.splitext(pchname)[0] + '.obj' return objname, ['/Yc' + header, '/Fp' + pchname, '/Fo' + objname] - def gen_import_library_args(self, implibname: str) -> T.List[str]: - "The name of the outputted import library" - return ['/IMPLIB:' + implibname] - def openmp_flags(self) -> T.List[str]: return ['/openmp'] diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index b995a59..f25c671 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -752,7 +752,8 @@ class Environment: def _guess_win_linker(self, compiler: T.List[str], comp_class: Compiler, for_machine: MachineChoice, *, - use_linker_prefix: bool = True) -> 'DynamicLinker': + use_linker_prefix: bool = True, invoked_directly: bool = True, + extra_args: T.Optional[T.List[str]] = None) -> 'DynamicLinker': self.coredata.add_lang_args(comp_class.language, comp_class, for_machine, self) # Explicitly pass logo here so that we can get the version of link.exe @@ -771,25 +772,29 @@ class Environment: override = comp_class.use_linker_args(value[0]) check_args += override + if extra_args is not None: + check_args.extend(extra_args) + p, o, _ = Popen_safe(compiler + check_args) if o.startswith('LLD'): if '(compatible with GNU linkers)' in o: return LLVMDynamicLinker( compiler, for_machine, comp_class.LINKER_PREFIX, - override, version=search_version(o)) - - if value is not None: + override, version=search_version(o), direct=invoked_directly) + + if value is not None and invoked_directly: compiler = value + # We've already hanedled the non-direct case above p, o, e = Popen_safe(compiler + check_args) if o.startswith('LLD'): return ClangClDynamicLinker( for_machine, [], prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [], - exelist=compiler, version=search_version(o)) + exelist=compiler, version=search_version(o), direct=invoked_directly) elif 'OPTLINK' in o: # Opltink's stdout *may* beging with a \r character. - return OptlinkDynamicLinker(for_machine, version=search_version(o)) + return OptlinkDynamicLinker(compiler, for_machine, version=search_version(o)) elif o.startswith('Microsoft') or e.startswith('Microsoft'): out = o or e match = re.search(r'.*(X86|X64|ARM|ARM64).*', out) @@ -801,7 +806,7 @@ class Environment: return MSVCDynamicLinker( for_machine, [], machine=target, exelist=compiler, prefix=comp_class.LINKER_PREFIX if use_linker_prefix else [], - version=search_version(out)) + version=search_version(out), direct=invoked_directly) elif 'GNU coreutils' in o: raise EnvironmentException( "Found GNU link.exe instead of MSVC link.exe. This link.exe " @@ -1496,28 +1501,31 @@ class Environment: if 'LLVM D compiler' in out: # LDC seems to require a file - if info.is_windows() or info.is_cygwin(): - # Getting LDC on windows to give useful linker output when - # not doing real work is painfully hard. It ships with a - # version of lld-link, so unless we think the user wants - # link.exe, just assume that we're going to use lld-link - # with it. - linker = self._guess_win_linker( - ['link' if is_msvc else 'lld-link'], - compilers.LLVMDCompiler, for_machine, use_linker_prefix=False) - else: - with tempfile.NamedTemporaryFile(suffix='.d') as f: + # We cannot use NamedTemproraryFile on windows, its documented + # to not work for our uses. So, just use mkstemp and only have + # one path for simplicity. + o, f = tempfile.mkstemp('.d') + os.close(o) + + try: + if info.is_windows() or info.is_cygwin(): + objfile = os.path.basename(f)[:-1] + 'obj' + linker = self._guess_win_linker( + exelist, + compilers.LLVMDCompiler, for_machine, + use_linker_prefix=True, invoked_directly=False, + extra_args=[f]) + else: # LDC writes an object file to the current working directory. # Clean it up. - objectfile = os.path.basename(f.name)[:-1] + 'o' + objfile = os.path.basename(f)[:-1] + 'o' linker = self._guess_nix_linker( exelist, compilers.LLVMDCompiler, for_machine, - extra_args=[f.name]) - try: - os.unlink(objectfile) - except Exception: - # Thank you Windows file system semantics and virus scanners. - pass + extra_args=[f]) + finally: + mesonlib.windows_proof_rm(f) + mesonlib.windows_proof_rm(objfile) + return compilers.LLVMDCompiler( exelist, version, for_machine, info, arch, full_version=full_version, linker=linker) @@ -1528,20 +1536,30 @@ class Environment: full_version=full_version, linker=linker) elif 'The D Language Foundation' in out or 'Digital Mars' in out: # DMD seems to require a file - if info.is_windows() or info.is_cygwin(): - if is_msvc: - linker_cmd = ['link'] - elif arch == 'x86': - linker_cmd = ['optlink'] + # We cannot use NamedTemproraryFile on windows, its documented + # to not work for our uses. So, just use mkstemp and only have + # one path for simplicity. + o, f = tempfile.mkstemp('.d') + os.close(o) + + # DMD as different detection logic for x86 and x86_64 + arch_arg = '-m64' if arch == 'x86_64' else '-m32' + + try: + if info.is_windows() or info.is_cygwin(): + objfile = os.path.basename(f)[:-1] + 'obj' + linker = self._guess_win_linker( + exelist, compilers.DmdDCompiler, for_machine, + invoked_directly=False, extra_args=[f, arch_arg]) else: - linker_cmd = ['lld-link'] - linker = self._guess_win_linker(linker_cmd, compilers.DmdDCompiler, for_machine, - use_linker_prefix=False) - else: - with tempfile.NamedTemporaryFile(suffix='.d') as f: + objfile = os.path.basename(f)[:-1] + 'o' linker = self._guess_nix_linker( exelist, compilers.DmdDCompiler, for_machine, - extra_args=[f.name]) + extra_args=[f, arch_arg]) + finally: + mesonlib.windows_proof_rm(f) + mesonlib.windows_proof_rm(objfile) + return compilers.DmdDCompiler( exelist, version, for_machine, info, arch, full_version=full_version, linker=linker) diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 73cdeef..e4fffe3 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -901,6 +901,10 @@ class VisualStudioLikeLinkerMixin: is_shared_module: bool) -> T.List[str]: return [] + def import_library_args(self, implibname: str) -> T.List[str]: + """The command to generate the import library.""" + return self._apply_prefix(['/IMPLIB:' + implibname]) + class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): @@ -993,15 +997,22 @@ class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): """Digital Mars dynamic linker for windows.""" - def __init__(self, for_machine: mesonlib.MachineChoice, + def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice, *, version: str = 'unknown version'): # Use optlink instead of link so we don't interfer with other link.exe # implementations. - super().__init__('optlink', ['optlink.exe'], for_machine, '', [], version=version) + super().__init__('optlink', exelist, for_machine, '', [], version=version) def get_allow_undefined_args(self) -> T.List[str]: return [] + def get_debugfile_args(self, targetfile: str) -> T.List[str]: + # Optlink does not generate pdb files. + return [] + + def get_always_args(self) -> T.List[str]: + return [] + class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker): """Cuda linker (nvlink)""" diff --git a/run_project_tests.py b/run_project_tests.py index 86db599..3b20025 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -14,19 +14,27 @@ # See the License for the specific language governing permissions and # limitations under the License. -import typing as T +from concurrent.futures import ProcessPoolExecutor, CancelledError +from enum import Enum +from io import StringIO +from pathlib import Path, PurePath +import argparse import functools import itertools +import json +import multiprocessing import os -import subprocess +import re +import shlex import shutil -import sys import signal -import shlex -from io import StringIO -from enum import Enum +import subprocess +import sys import tempfile -from pathlib import Path, PurePath +import time +import typing as T +import xml.etree.ElementTree as ET + from mesonbuild import build from mesonbuild import environment from mesonbuild import compilers @@ -35,13 +43,7 @@ from mesonbuild import mlog from mesonbuild import mtest from mesonbuild.mesonlib import MachineChoice, Popen_safe from mesonbuild.coredata import backendlist -import argparse -import json -import xml.etree.ElementTree as ET -import time -import multiprocessing -from concurrent.futures import ProcessPoolExecutor, CancelledError -import re + from run_tests import get_fake_options, run_configure, get_meson_script from run_tests import get_backend_commands, get_backend_args_for_dir, Backend from run_tests import ensure_backend_detects_changes @@ -94,13 +96,29 @@ class InstalledFile: self.path = raw['file'] self.typ = raw['type'] self.platform = raw.get('platform', None) + self.language = raw.get('language', 'c') # type: str + + version = raw.get('version', '') # type: str + if version: + self.version = version.split('.') # type: T.List[str] + else: + # split on '' will return [''], we want an empty list though + self.version = [] def get_path(self, compiler: str, env: environment.Environment) -> T.Optional[Path]: p = Path(self.path) canonical_compiler = compiler - if (compiler in ['clang-cl', 'intel-cl']) or (env.machines.host.is_windows() and compiler == 'pgi'): + if ((compiler in ['clang-cl', 'intel-cl']) or + (env.machines.host.is_windows() and compiler in {'pgi', 'dmd', 'ldc'})): canonical_compiler = 'msvc' + has_pdb = False + if self.language in {'c', 'cpp'}: + has_pdb = canonical_compiler == 'msvc' + elif self.language == 'd': + # dmd's optlink does not genearte pdb iles + has_pdb = env.coredata.compilers.host['d'].linker.id in {'link', 'lld-link'} + # Abort if the platform does not match matches = { 'msvc': canonical_compiler == 'msvc', @@ -114,11 +132,38 @@ class InstalledFile: # Handle the different types if self.typ == 'file': return p + elif self.typ == 'shared_lib': + if env.machines.host.is_windows() or env.machines.host.is_cygwin(): + # Windows only has foo.dll and foo-X.dll + if len(self.version) > 1: + return None + if self.version: + p = p.with_name('{}-{}'.format(p.name, self.version[0])) + return p.with_suffix('.dll') + + p = p.with_name('lib{}'.format(p.name)) + if env.machines.host.is_darwin(): + # MacOS only has libfoo.dylib and libfoo.X.dylib + if len(self.version) > 1: + return None + + # pathlib.Path.with_suffix replaces, not appends + suffix = '.dylib' + if self.version: + suffix = '.{}{}'.format(self.version[0], suffix) + else: + # pathlib.Path.with_suffix replaces, not appends + suffix = '.so' + if self.version: + suffix = '{}.{}'.format(suffix, '.'.join(self.version)) + return p.with_suffix(suffix) elif self.typ == 'exe': if env.machines.host.is_windows() or env.machines.host.is_cygwin(): return p.with_suffix('.exe') elif self.typ == 'pdb': - return p.with_suffix('.pdb') if canonical_compiler == 'msvc' else None + if self.version: + p = p.with_name('{}-{}'.format(p.name, self.version[0])) + return p.with_suffix('.pdb') if has_pdb else None elif self.typ == 'implib' or self.typ == 'implibempty': if env.machines.host.is_windows() and canonical_compiler == 'msvc': # only MSVC doesn't generate empty implibs @@ -208,7 +253,7 @@ def setup_commands(optbackend): uninstall_commands = get_backend_commands(backend, do_debug) # TODO try to eliminate or at least reduce this function -def platform_fix_name(fname: str, canonical_compiler: str, env: environment.EnvironmentException) -> str: +def platform_fix_name(fname: str, canonical_compiler: str, env: environment.Environment) -> str: if '?lib' in fname: if env.machines.host.is_windows() and canonical_compiler == 'msvc': fname = re.sub(r'lib/\?lib(.*)\.', r'bin/\1.', fname) diff --git a/test cases/d/1 simple/test.json b/test cases/d/1 simple/test.json index 7ec2783..62f907a 100644 --- a/test cases/d/1 simple/test.json +++ b/test cases/d/1 simple/test.json @@ -1,5 +1,6 @@ { "installed": [ - {"type": "exe", "file": "usr/bin/dsimpleapp"} + {"type": "exe", "file": "usr/bin/dsimpleapp"}, + {"type": "pdb", "file": "usr/bin/dsimpleapp", "language": "d"} ] } diff --git a/test cases/d/2 static library/test.json b/test cases/d/2 static library/test.json index 50d5cdf..6abb934 100644 --- a/test cases/d/2 static library/test.json +++ b/test cases/d/2 static library/test.json @@ -1,6 +1,7 @@ { "installed": [ {"type": "exe", "file": "usr/bin/app_s"}, + {"type": "pdb", "file": "usr/bin/app_s", "language": "d"}, {"type": "file", "file": "usr/lib/libstuff.a"} ] } diff --git a/test cases/d/3 shared library/lld-test.py b/test cases/d/3 shared library/lld-test.py new file mode 100644 index 0000000..3f32f59 --- /dev/null +++ b/test cases/d/3 shared library/lld-test.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 + +import argparse +import subprocess + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('ldd') + parser.add_argument('bin') + args = parser.parse_args() + + p, o, _ = subprocess.run([args.ldd, args.bin], stdout=subprocess.PIPE) + assert p == 0 + o = o.decode() + assert 'libstuff.so =>' in o, 'libstuff so not in linker path.' + assert 'libstuff.so => not found' not in o, 'libstuff.so not found correctly' + + +if __name__ == '__main__': + main() diff --git a/test cases/d/3 shared library/meson.build b/test cases/d/3 shared library/meson.build index b37b700..fa41779 100644 --- a/test cases/d/3 shared library/meson.build +++ b/test cases/d/3 shared library/meson.build @@ -7,7 +7,7 @@ if dc.get_id() == 'gcc' endif endif -ldyn = shared_library('stuff', 'libstuff.d', install : true) +subdir('sub') ed = executable('app_d', 'app.d', link_with : ldyn, install : true) test('linktest_dyn', ed) @@ -19,3 +19,8 @@ pkgc.generate(name: 'test', description: 'A test of D attributes to pkgconfig.generate.', d_module_versions: ['Use_Static'] ) + +ldd = find_program('ldd', required : false) +if ldd.found() + test('ldd-test.py', ed) +endif diff --git a/test cases/d/3 shared library/sub/libstuff.d b/test cases/d/3 shared library/sub/libstuff.d new file mode 100644 index 0000000..8205490 --- /dev/null +++ b/test cases/d/3 shared library/sub/libstuff.d @@ -0,0 +1,14 @@ +import std.stdio; +import std.string : format; + +export int printLibraryString (string str) +{ + writeln ("Library says: %s".format (str)); + return 4; +} + +version (Windows) +{ + import core.sys.windows.dll; + mixin SimpleDllMain; +} diff --git a/test cases/d/3 shared library/sub/meson.build b/test cases/d/3 shared library/sub/meson.build new file mode 100644 index 0000000..fb4b996 --- /dev/null +++ b/test cases/d/3 shared library/sub/meson.build @@ -0,0 +1,2 @@ +ldyn = shared_library('stuff', 'libstuff.d', install : true) + diff --git a/test cases/d/3 shared library/test.json b/test cases/d/3 shared library/test.json index 66c546b..50eb9cb 100644 --- a/test cases/d/3 shared library/test.json +++ b/test cases/d/3 shared library/test.json @@ -1,9 +1,11 @@ { "installed": [ {"type": "exe", "file": "usr/bin/app_d"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/stuff.dll"}, + {"type": "pdb", "file": "usr/bin/app_d", "language": "d"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/stuff"}, + {"type": "pdb", "file": "usr/bin/stuff", "language": "d"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/stuff"}, {"type": "file", "platform": "msvc", "file": "usr/lib/stuff.lib"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libstuff.so"}, {"type": "file", "file": "usr/lib/pkgconfig/test.pc"} ] } diff --git a/test cases/d/4 library versions/test.json b/test cases/d/4 library versions/test.json index 2a3433e..23c95dd 100644 --- a/test cases/d/4 library versions/test.json +++ b/test cases/d/4 library versions/test.json @@ -1,21 +1,25 @@ { "installed": [ - {"type": "file", "platform": "gcc", "file": "usr/lib/libsome.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsome.so.0"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsome.so.1.2.3"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libnoversion.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libonlyversion.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libonlyversion.so.1"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libonlyversion.so.1.4.5"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libonlysoversion.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libonlysoversion.so.5"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/noversion.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/onlysoversion-5.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/onlyversion-1.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/some-0.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/noversion.lib"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/onlysoversion.lib"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/onlyversion.lib"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/some.lib"} + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some", "version": "0"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/some", "version": "1.2.3"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/noversion"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion", "version": "1"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlyversion", "version": "1.4.5"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlysoversion"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/onlysoversion", "version": "5"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/noversion"}, + {"type": "pdb", "file": "usr/bin/noversion", "language": "d"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/onlysoversion", "version": "5"}, + {"type": "pdb", "file": "usr/bin/onlysoversion", "version": "5", "language": "d"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/onlyversion", "version": "1"}, + {"type": "pdb", "file": "usr/bin/onlyversion", "version": "1", "language": "d"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/some", "version": "0"}, + {"type": "pdb", "file": "usr/bin/some", "version": "0", "language": "d"}, + {"type": "implib", "file": "usr/lib/noversion"}, + {"type": "implib", "file": "usr/lib/onlysoversion"}, + {"type": "implib", "file": "usr/lib/onlyversion"}, + {"type": "implib", "file": "usr/lib/some"} ] } diff --git a/test cases/d/5 mixed/test.json b/test cases/d/5 mixed/test.json index a63a19b..c95d0ca 100644 --- a/test cases/d/5 mixed/test.json +++ b/test cases/d/5 mixed/test.json @@ -1,11 +1,13 @@ { "installed": [ {"type": "exe", "file": "usr/bin/appdc_d"}, + {"type": "pdb", "file": "usr/bin/appdc_d", "language": "d"}, {"type": "exe", "file": "usr/bin/appdc_s"}, + {"type": "pdb", "file": "usr/bin/appdc_s", "language": "d"}, {"type": "file", "file": "usr/lib/libstuff.a"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libstuff.so"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/stuff.dll"}, - {"type": "pdb", "file": "usr/bin/stuff"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/stuff"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/stuff"}, + {"type": "pdb", "file": "usr/bin/stuff", "language": "c"}, {"type": "file", "platform": "msvc", "file": "usr/lib/stuff.lib"} ] } diff --git a/test cases/d/6 unittest/test.json b/test cases/d/6 unittest/test.json index 433e4b0..adc4d75 100644 --- a/test cases/d/6 unittest/test.json +++ b/test cases/d/6 unittest/test.json @@ -1,5 +1,6 @@ { "installed": [ - {"type": "exe", "file": "usr/bin/dapp"} + {"type": "exe", "file": "usr/bin/dapp"}, + {"type": "pdb", "file": "usr/bin/dapp", "language": "d"} ] } diff --git a/test cases/d/7 multilib/test.json b/test cases/d/7 multilib/test.json index 408c4f2..5944ae0 100644 --- a/test cases/d/7 multilib/test.json +++ b/test cases/d/7 multilib/test.json @@ -1,15 +1,18 @@ { "installed": [ {"type": "exe", "file": "usr/bin/app_d"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay1.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay1.so.0"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay1.so.1.2.3"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay2.so"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay2.so.1"}, - {"type": "file", "platform": "gcc", "file": "usr/lib/libsay2.so.1.2.4"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/say1-0.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/bin/say2-1.dll"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/say1.lib"}, - {"type": "file", "platform": "msvc", "file": "usr/lib/say2.lib"} + {"type": "pdb", "file": "usr/bin/app_d", "language": "d"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1", "version": "0"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say1", "version": "1.2.3"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2", "version": "1"}, + {"type": "shared_lib", "platform": "gcc", "file": "usr/lib/say2", "version": "1.2.4"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/say1", "version": "0"}, + {"type": "pdb", "file": "usr/bin/say1", "version": "0", "language": "d"}, + {"type": "shared_lib", "platform": "msvc", "file": "usr/bin/say2", "version": "1"}, + {"type": "pdb", "file": "usr/bin/say2", "version": "1", "language": "d"}, + {"type": "implib", "file": "usr/lib/say1"}, + {"type": "implib", "file": "usr/lib/say2"} ] } |