From 5a7e06a64f90f24b7cf642b43a81faf300bfc2fe Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 3 Jun 2017 23:38:52 -0400 Subject: [PATCH 1/7] Add MPI dependency. We prefer pkg-config files, though only OpenMPI supplies them. Otherwise, check environment variables and search for wrappers and ask them for what to do. --- mesonbuild/dependencies/__init__.py | 3 +- mesonbuild/dependencies/misc.py | 131 +++++++++++++++++++++++++- test cases/common/157 mpi/main.c | 27 ++++++ test cases/common/157 mpi/main.cpp | 11 +++ test cases/common/157 mpi/main.f90 | 21 +++++ test cases/common/157 mpi/meson.build | 24 +++++ 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 test cases/common/157 mpi/main.c create mode 100644 test cases/common/157 mpi/main.cpp create mode 100644 test cases/common/157 mpi/main.f90 create mode 100644 test cases/common/157 mpi/meson.build diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index f153b976b..fb57e3d95 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -17,7 +17,7 @@ from .base import ( # noqa: F401 ExternalDependency, ExternalLibrary, ExtraFrameworkDependency, InternalDependency, PkgConfigDependency, find_external_dependency, get_dep_identifier, packages) 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, diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 99df587ed..71f736901 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,133 @@ 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 = result[1] + self.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 = result[1] + self.link_args = result[2] + break + + 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 _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 + + class ThreadDependency(ExternalDependency): def __init__(self, environment, kwargs): super().__init__('threads', environment, None, {}) diff --git a/test cases/common/157 mpi/main.c b/test cases/common/157 mpi/main.c new file mode 100644 index 000000000..e44357a97 --- /dev/null +++ b/test cases/common/157 mpi/main.c @@ -0,0 +1,27 @@ +#include +#include + +int main(int argc, char **argv) +{ + int ier, flag; + ier = MPI_Init(&argc, &argv); + if (ier) { + printf("Unable to initialize MPI: %d\n", ier); + return 1; + } + ier = MPI_Initialized(&flag); + if (ier) { + printf("Unable to check MPI initialization state: %d\n", ier); + return 1; + } + if (!flag) { + printf("MPI did not initialize!\n"); + return 1; + } + ier = MPI_Finalize(); + if (ier) { + printf("Unable to finalize MPI: %d\n", ier); + return 1; + } + return 0; +} diff --git a/test cases/common/157 mpi/main.cpp b/test cases/common/157 mpi/main.cpp new file mode 100644 index 000000000..0e0b62173 --- /dev/null +++ b/test cases/common/157 mpi/main.cpp @@ -0,0 +1,11 @@ +#include + +int main(int argc, char **argv) +{ + MPI::Init(argc, argv); + if (!MPI::Is_initialized()) { + printf("MPI did not initialize!\n"); + return 1; + } + MPI::Finalize(); +} diff --git a/test cases/common/157 mpi/main.f90 b/test cases/common/157 mpi/main.f90 new file mode 100644 index 000000000..d379e96f8 --- /dev/null +++ b/test cases/common/157 mpi/main.f90 @@ -0,0 +1,21 @@ +program mpitest + implicit none + include 'mpif.h' + logical :: flag + integer :: ier + call MPI_Init(ier) + if (ier /= 0) then + print *, 'Unable to initialize MPI: ', ier + stop 1 + endif + call MPI_Initialized(flag, ier) + if (ier /= 0) then + print *, 'Unable to check MPI initialization state: ', ier + stop 1 + endif + call MPI_Finalize(ier) + if (ier /= 0) then + print *, 'Unable to finalize MPI: ', ier + stop 1 + endif +end program mpitest diff --git a/test cases/common/157 mpi/meson.build b/test cases/common/157 mpi/meson.build new file mode 100644 index 000000000..f36b03980 --- /dev/null +++ b/test cases/common/157 mpi/meson.build @@ -0,0 +1,24 @@ +project('mpi', 'c', 'cpp') + +mpic = dependency('mpi', language : 'c') +exec = executable('exec', + 'main.c', + dependencies : [mpic]) + +test('MPI C', exec) + +mpicpp = dependency('mpi', language : 'cpp') +execpp = executable('execpp', + 'main.cpp', + dependencies : [mpicpp]) + +test('MPI C++', execpp) + +if add_languages('fortran', required : false) + mpifort = dependency('mpi', language : 'fortran') + exef = executable('exef', + 'main.f90', + dependencies : [mpifort]) + + test('MPI Fortran', exef) +endif From 4c9611c2d6ebdcc782c2a7ccd5315dee603b02d4 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 3 Jun 2017 23:43:11 -0400 Subject: [PATCH 2/7] Add documentation for new MPI dependency. --- docs/markdown/Dependencies.md | 15 +++++++++++++++ docs/markdown/Release-notes-for-0.42.0.md | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/docs/markdown/Dependencies.md b/docs/markdown/Dependencies.md index 18512336c..401e019a3 100644 --- a/docs/markdown/Dependencies.md +++ b/docs/markdown/Dependencies.md @@ -51,6 +51,21 @@ If your boost headers or libraries are in non-standard locations you can set the GTest and GMock come as sources that must be compiled as part of your project. With Meson you don't have to care about the details, just pass `gtest` or `gmock` to `dependency` and it will do everything for you. If you want to use GMock, it is recommended to use GTest as well, as getting it to work standalone is tricky. +## MPI ## + +MPI is supported for C, C++ and Fortran. Because dependencies are +language-specific, you must specify the requested language using the +`language` keyword argument, i.e., + * `dependency('mpi', language='c')` for the C MPI headers and libraries + * `dependency('mpi', language='cpp')` for the C++ MPI headers and libraries + * `dependency('mpi', language='fortran')` for the Fortran MPI headers and libraries + +Meson prefers pkg-config for MPI, but if your MPI implementation does not +provide them, it will search for the standard wrapper executables, `mpic`, +`mpicxx`, `mpic++`, `mpifort`, `mpif90`, `mpif77`. If these are not in your +path, they can be specified by setting the standard environment variables +`MPICC`, `MPICXX`, `MPIFC`, `MPIF90`, or `MPIF77`, during configuration. + ## Qt5 ## Meson has native Qt5 support. Its usage is best demonstrated with an example. diff --git a/docs/markdown/Release-notes-for-0.42.0.md b/docs/markdown/Release-notes-for-0.42.0.md index 0fa27c3d8..f3127de7f 100644 --- a/docs/markdown/Release-notes-for-0.42.0.md +++ b/docs/markdown/Release-notes-for-0.42.0.md @@ -104,3 +104,11 @@ By default Meson adds the current source and build directories to the header search path. On some rare occasions this is not desired. Setting the `implicit_include_directories` keyword argument to `false` these directories are not used. + +## Support for MPI dependency + +MPI is now supported as a dependency. Because dependencies are +language-specific, you must specify the requested language with the `language` +keyword, i.e., `dependency('mpi', language='c')` will request the C MPI headers +and libraries. See [the MPI dependency](Dependencies.md#mpi) for more +information. From 17b051c8b1939177c1e3f81bae58c7ce40cdbce3 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 19 Jul 2017 04:34:08 -0400 Subject: [PATCH 3/7] Add info on module include flag for Fortran compilers. --- mesonbuild/compilers/fortran.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index e17cda0c5..49200bb70 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] From 271601124e22695bfa0b0791543473b7164948b1 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 19 Jul 2017 04:49:32 -0400 Subject: [PATCH 4/7] Filter out extra args from MPI wrappers. --- mesonbuild/dependencies/misc.py | 50 ++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 71f736901..4773f2fcf 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -331,15 +331,15 @@ class MPIDependency(ExternalDependency): if result is not None: self.is_found = True self.version = result[0] - self.compile_args = result[1] - self.link_args = result[2] + 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 = result[1] - self.link_args = result[2] + self.compile_args = self._filter_compile_args(result[1]) + self.link_args = self._filter_link_args(result[2]) break if self.is_found: @@ -349,6 +349,48 @@ class MPIDependency(ExternalDependency): 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(): From 4cbfb9a08dd8b89aaec7fffd4efbe3a542a67a3d Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Wed, 26 Jul 2017 02:38:23 -0400 Subject: [PATCH 5/7] Add support for MS-MPI. --- .appveyor.yml | 11 +++++++++ mesonbuild/dependencies/misc.py | 35 +++++++++++++++++++++++++++ test cases/common/157 mpi/meson.build | 19 +++++++++++---- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 655144599..77d00af8d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -76,6 +76,17 @@ install: - ps: If($Env:compiler -eq 'msys2-mingw') {(new-object Net.WebClient).DownloadFile('https://bootstrap.pypa.io/get-pip.py', 'C:\projects\meson\get-pip.py')} - cmd: if %compiler%==msys2-mingw ( %PYTHON% "C:\projects\meson\get-pip.py" ) - cmd: if %compiler%==cygwin ( call ci\appveyor-install.bat ) + - ps: | + If($Env:compiler -like 'msvc*') { + (new-object net.webclient).DownloadFile( + "https://download.microsoft.com/download/D/B/B/DBB64BA1-7B51-43DB-8BF1-D1FB45EACF7A/msmpisdk.msi", + "C:\projects\msmpisdk.msi") + c:\windows\system32\msiexec.exe /i C:\projects\msmpisdk.msi /quiet + (new-object net.webclient).DownloadFile( + "https://download.microsoft.com/download/D/B/B/DBB64BA1-7B51-43DB-8BF1-D1FB45EACF7A/MSMpiSetup.exe", + "C:\projects\MSMpiSetup.exe") + c:\projects\MSMpiSetup.exe -unattend -full + } # Install additional packages needed for all builds. - cmd: "%WRAPPER% %PYTHON% -m pip install codecov" diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 4773f2fcf..f5cbb96bf 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -342,6 +342,12 @@ class MPIDependency(ExternalDependency): 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: @@ -447,6 +453,35 @@ class MPIDependency(ExternalDependency): 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): diff --git a/test cases/common/157 mpi/meson.build b/test cases/common/157 mpi/meson.build index f36b03980..5e9bc563d 100644 --- a/test cases/common/157 mpi/meson.build +++ b/test cases/common/157 mpi/meson.build @@ -1,5 +1,11 @@ project('mpi', 'c', 'cpp') +cc = meson.get_compiler('c') + +if build_machine.system() == 'windows' and cc.get_id() != 'msvc' + error('MESON_SKIP_TEST: MPI not available on Windows without MSVC.') +endif + mpic = dependency('mpi', language : 'c') exec = executable('exec', 'main.c', @@ -7,12 +13,15 @@ exec = executable('exec', test('MPI C', exec) -mpicpp = dependency('mpi', language : 'cpp') -execpp = executable('execpp', - 'main.cpp', - dependencies : [mpicpp]) +if build_machine.system() != 'windows' + # C++ MPI not supported by MS-MPI used on AppVeyor. + mpicpp = dependency('mpi', language : 'cpp') + execpp = executable('execpp', + 'main.cpp', + dependencies : [mpicpp]) -test('MPI C++', execpp) + test('MPI C++', execpp) +endif if add_languages('fortran', required : false) mpifort = dependency('mpi', language : 'fortran') From edb260b4f4e79433f38bdda11bc84fa5ee56b080 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Mon, 31 Jul 2017 15:38:26 -0400 Subject: [PATCH 6/7] Move MPI tests into frameworks. This prevents them being cross-compiled (which wouldn't work without MPI cross-compilers) and disables Windows builds (will need to be fixed later.) --- test cases/{common/157 mpi => frameworks/17 mpi}/main.c | 0 test cases/{common/157 mpi => frameworks/17 mpi}/main.cpp | 0 test cases/{common/157 mpi => frameworks/17 mpi}/main.f90 | 0 test cases/{common/157 mpi => frameworks/17 mpi}/meson.build | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename test cases/{common/157 mpi => frameworks/17 mpi}/main.c (100%) rename test cases/{common/157 mpi => frameworks/17 mpi}/main.cpp (100%) rename test cases/{common/157 mpi => frameworks/17 mpi}/main.f90 (100%) rename test cases/{common/157 mpi => frameworks/17 mpi}/meson.build (100%) diff --git a/test cases/common/157 mpi/main.c b/test cases/frameworks/17 mpi/main.c similarity index 100% rename from test cases/common/157 mpi/main.c rename to test cases/frameworks/17 mpi/main.c diff --git a/test cases/common/157 mpi/main.cpp b/test cases/frameworks/17 mpi/main.cpp similarity index 100% rename from test cases/common/157 mpi/main.cpp rename to test cases/frameworks/17 mpi/main.cpp diff --git a/test cases/common/157 mpi/main.f90 b/test cases/frameworks/17 mpi/main.f90 similarity index 100% rename from test cases/common/157 mpi/main.f90 rename to test cases/frameworks/17 mpi/main.f90 diff --git a/test cases/common/157 mpi/meson.build b/test cases/frameworks/17 mpi/meson.build similarity index 100% rename from test cases/common/157 mpi/meson.build rename to test cases/frameworks/17 mpi/meson.build From d9f01ffcea142cdd9bf2bbf1f9213e40efc189b5 Mon Sep 17 00:00:00 2001 From: Elliott Sales de Andrade Date: Sat, 5 Aug 2017 16:44:39 -0400 Subject: [PATCH 7/7] Disallow language keyword for unsupported deps. Also, document it in the manual. --- docs/markdown/Reference-manual.md | 1 + mesonbuild/dependencies/__init__.py | 5 ++++- mesonbuild/dependencies/base.py | 8 +++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/markdown/Reference-manual.md b/docs/markdown/Reference-manual.md index ebd7b394e..265f76d6a 100644 --- a/docs/markdown/Reference-manual.md +++ b/docs/markdown/Reference-manual.md @@ -193,6 +193,7 @@ Finds an external dependency with the given name with `pkg-config` if possible a - `fallback` specifies a subproject fallback to use in case the dependency is not found in the system. The value is an array `['subproj_name', 'subproj_dep']` where the first value is the name of the subproject and the second is the variable name in that subproject that contains the value of [`declare_dependency`](#declare_dependency). - `default_options` *(added 0.37.0)* an array of option values that override those set in the project's `default_options` invocation (like `default_options` in [`project()`](#project), they only have effect when Meson is run for the first time, and command line arguments override any default options in build files) - `method` defines the way the dependency is detected, the default is `auto` but can be overridden to be e.g. `qmake` for Qt development, and different dependencies support different values for this (though `auto` will work on all of them) +- `language` *(added 0.42.0)* defines what language-specific dependency to find if it's available for multiple languages. The returned object also has methods that are documented in the [object methods section](#dependency-object) below. diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index fb57e3d95..c16b92e19 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -15,7 +15,7 @@ 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, MPIDependency, Python3Dependency, ThreadDependency) from .platform import AppleFrameworks @@ -47,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 f98de4423..1f18c5284 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: