diff options
Diffstat (limited to 'mesonbuild')
-rw-r--r-- | mesonbuild/compilers/fortran.py | 9 | ||||
-rw-r--r-- | mesonbuild/dependencies/__init__.py | 8 | ||||
-rw-r--r-- | mesonbuild/dependencies/base.py | 8 | ||||
-rw-r--r-- | mesonbuild/dependencies/misc.py | 208 |
4 files changed, 229 insertions, 4 deletions
diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index e17cda0..49200bb 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -120,6 +120,9 @@ end program prog def get_include_args(self, path, is_system): return ['-I' + path] + def get_module_incdir_args(self): + return ('-I', ) + def get_module_outdir_args(self, path): return ['-J' + path] @@ -209,6 +212,9 @@ class SunFortranCompiler(FortranCompiler): def get_warn_args(self, level): return [] + def get_module_incdir_args(self): + return ('-M', ) + def get_module_outdir_args(self, path): return ['-moddir=' + path] @@ -251,6 +257,9 @@ class PGIFortranCompiler(FortranCompiler): super().__init__(exelist, version, is_cross, exe_wrapper=None) self.id = 'pgi' + def get_module_incdir_args(self): + return ('-module', ) + def get_module_outdir_args(self, path): return ['-module', path] diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index f153b97..c16b92e 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -15,9 +15,9 @@ from .base import ( # noqa: F401 Dependency, DependencyException, DependencyMethods, ExternalProgram, ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency, - PkgConfigDependency, find_external_dependency, get_dep_identifier, packages) + PkgConfigDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language) from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency -from .misc import BoostDependency, Python3Dependency, ThreadDependency +from .misc import (BoostDependency, MPIDependency, Python3Dependency, ThreadDependency) from .platform import AppleFrameworks from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency @@ -31,6 +31,7 @@ packages.update({ # From misc: 'boost': BoostDependency, + 'mpi': MPIDependency, 'python3': Python3Dependency, 'threads': ThreadDependency, @@ -46,3 +47,6 @@ packages.update({ 'wxwidgets': WxDependency, 'vulkan': VulkanDependency, }) +_packages_accept_language.update({ + 'mpi', +}) diff --git a/mesonbuild/dependencies/base.py b/mesonbuild/dependencies/base.py index f98de44..1f18c52 100644 --- a/mesonbuild/dependencies/base.py +++ b/mesonbuild/dependencies/base.py @@ -26,8 +26,9 @@ from .. import mesonlib from ..mesonlib import MesonException, Popen_safe, flatten, version_compare_many -# This must be defined in this file to avoid cyclical references. +# These must be defined in this file to avoid cyclical references. packages = {} +_packages_accept_language = set() class DependencyException(MesonException): @@ -610,10 +611,15 @@ def find_external_dependency(name, env, kwargs): raise DependencyException('Keyword "method" must be a string.') lname = name.lower() if lname in packages: + if lname not in _packages_accept_language and 'language' in kwargs: + raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) dep = packages[lname](env, kwargs) if required and not dep.found(): raise DependencyException('Dependency "%s" not found' % name) return dep + if 'language' in kwargs: + # Remove check when PkgConfigDependency supports language. + raise DependencyException('%s dependency does not accept "language" keyword argument' % (lname, )) pkg_exc = None pkgdep = None try: diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 99df587..f5cbb96 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -16,6 +16,8 @@ import glob import os +import re +import shlex import stat import sysconfig @@ -24,7 +26,7 @@ from .. import mesonlib from ..environment import detect_cpu_family from .base import DependencyException, DependencyMethods -from .base import ExternalDependency, ExtraFrameworkDependency, PkgConfigDependency +from .base import ExternalDependency, ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency class BoostDependency(ExternalDependency): @@ -277,6 +279,210 @@ class BoostDependency(ExternalDependency): return 'thread' in self.requested_modules +class MPIDependency(ExternalDependency): + def __init__(self, environment, kwargs): + language = kwargs.get('language', 'c') + super().__init__('mpi', environment, language, kwargs) + required = kwargs.pop('required', True) + kwargs['required'] = False + kwargs['silent'] = True + self.is_found = False + + # NOTE: Only OpenMPI supplies a pkg-config file at the moment. + if language == 'c': + env_vars = ['MPICC'] + pkgconfig_files = ['ompi-c'] + default_wrappers = ['mpicc'] + elif language == 'cpp': + env_vars = ['MPICXX'] + pkgconfig_files = ['ompi-cxx'] + default_wrappers = ['mpic++', 'mpicxx', 'mpiCC'] + elif language == 'fortran': + env_vars = ['MPIFC', 'MPIF90', 'MPIF77'] + pkgconfig_files = ['ompi-fort'] + default_wrappers = ['mpifort', 'mpif90', 'mpif77'] + else: + raise DependencyException('Language {} is not supported with MPI.'.format(language)) + + for pkg in pkgconfig_files: + try: + pkgdep = PkgConfigDependency(pkg, environment, kwargs) + if pkgdep.found(): + self.compile_args = pkgdep.get_compile_args() + self.link_args = pkgdep.get_link_args() + self.version = pkgdep.get_version() + self.is_found = True + break + except Exception: + pass + + if not self.is_found: + # Prefer environment. + for var in env_vars: + if var in os.environ: + wrappers = [os.environ[var]] + break + else: + # Or search for default wrappers. + wrappers = default_wrappers + + for prog in wrappers: + result = self._try_openmpi_wrapper(prog) + if result is not None: + self.is_found = True + self.version = result[0] + self.compile_args = self._filter_compile_args(result[1]) + self.link_args = self._filter_link_args(result[2]) + break + result = self._try_other_wrapper(prog) + if result is not None: + self.is_found = True + self.version = result[0] + self.compile_args = self._filter_compile_args(result[1]) + self.link_args = self._filter_link_args(result[2]) + break + + if not self.is_found and mesonlib.is_windows(): + result = self._try_msmpi() + if result is not None: + self.is_found = True + self.version, self.compile_args, self.link_args = result + + if self.is_found: + mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.green('YES'), self.version) + else: + mlog.log('Dependency', mlog.bold(self.name), 'for', self.language, 'found:', mlog.red('NO')) + if required: + raise DependencyException('MPI dependency {!r} not found'.format(self.name)) + + def _filter_compile_args(self, args): + """ + MPI wrappers return a bunch of garbage args. + Drop -O2 and everything that is not needed. + """ + result = [] + multi_args = ('-I', ) + if self.language == 'fortran': + fc = self.env.coredata.compilers['fortran'] + multi_args += fc.get_module_incdir_args() + + include_next = False + for f in args: + if f.startswith(('-D', '-f') + multi_args) or f == '-pthread' \ + or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')): + result.append(f) + if f in multi_args: + # Path is a separate argument. + include_next = True + elif include_next: + include_next = False + result.append(f) + return result + + def _filter_link_args(self, args): + """ + MPI wrappers return a bunch of garbage args. + Drop -O2 and everything that is not needed. + """ + result = [] + include_next = False + for f in args: + if f.startswith(('-L', '-l', '-Xlinker')) or f == '-pthread' \ + or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror')): + result.append(f) + if f in ('-L', '-Xlinker'): + include_next = True + elif include_next: + include_next = False + result.append(f) + return result + + def _try_openmpi_wrapper(self, prog): + prog = ExternalProgram(prog, silent=True) + if prog.found(): + cmd = prog.get_command() + ['--showme:compile'] + p, o, e = mesonlib.Popen_safe(cmd) + p.wait() + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), o) + mlog.debug(mlog.bold('Standard error\n'), e) + return + cargs = shlex.split(o) + + cmd = prog.get_command() + ['--showme:link'] + p, o, e = mesonlib.Popen_safe(cmd) + p.wait() + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), o) + mlog.debug(mlog.bold('Standard error\n'), e) + return + libs = shlex.split(o) + + cmd = prog.get_command() + ['--showme:version'] + p, o, e = mesonlib.Popen_safe(cmd) + p.wait() + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), o) + mlog.debug(mlog.bold('Standard error\n'), e) + return + version = re.search('\d+.\d+.\d+', o) + if version: + version = version.group(0) + else: + version = 'none' + + return version, cargs, libs + + def _try_other_wrapper(self, prog): + prog = ExternalProgram(prog, silent=True) + if prog.found(): + cmd = prog.get_command() + ['-show'] + p, o, e = mesonlib.Popen_safe(cmd) + p.wait() + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), o) + mlog.debug(mlog.bold('Standard error\n'), e) + return + args = shlex.split(o) + + version = 'none' + + return version, args, args + + def _try_msmpi(self): + if self.language == 'cpp': + # MS-MPI does not support the C++ version of MPI, only the standard C API. + return + if 'MSMPI_INC' not in os.environ: + return + incdir = os.environ['MSMPI_INC'] + arch = detect_cpu_family(self.env.coredata.compilers) + if arch == 'x86': + if 'MSMPI_LIB32' not in os.environ: + return + libdir = os.environ['MSMPI_LIB32'] + post = 'x86' + elif arch == 'x86_64': + if 'MSMPI_LIB64' not in os.environ: + return + libdir = os.environ['MSMPI_LIB64'] + post = 'x64' + else: + return + if self.language == 'fortran': + return ('none', + ['-I' + incdir, '-I' + os.path.join(incdir, post)], + [os.path.join(libdir, 'msmpi.lib'), os.path.join(libdir, 'msmpifec.lib')]) + else: + return ('none', + ['-I' + incdir, '-I' + os.path.join(incdir, post)], + [os.path.join(libdir, 'msmpi.lib')]) + + class ThreadDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('threads', environment, None, {}) |