Merge pull request #6355 from scivision/depmethod

dependencies: refactor {coarray,mpi,hdf5,netcdf} to use dependency(.., methods: ...)
pull/6379/head
Jussi Pakkanen 5 years ago committed by GitHub
commit 7981308e6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 25
      mesonbuild/dependencies/coarrays.py
  2. 29
      mesonbuild/dependencies/hdf5.py
  3. 19
      mesonbuild/dependencies/misc.py
  4. 19
      mesonbuild/dependencies/mpi.py
  5. 8
      mesonbuild/dependencies/scalapack.py
  6. 2
      test cases/fortran/13 coarray/meson.build
  7. 4
      test cases/frameworks/25 hdf5/meson.build
  8. 37
      test cases/frameworks/26 netcdf/meson.build
  9. 3
      test cases/frameworks/30 scalapack/meson.build

@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from .base import CMakeDependency, ExternalDependency, PkgConfigDependency from ..mesonlib import listify
from .base import CMakeDependency, DependencyMethods, ExternalDependency, PkgConfigDependency
class CoarrayDependency(ExternalDependency): class CoarrayDependency(ExternalDependency):
@ -29,11 +30,13 @@ class CoarrayDependency(ExternalDependency):
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
methods = listify(self.methods)
cid = self.get_compiler().get_id() cid = self.get_compiler().get_id()
if cid == 'gcc': if cid == 'gcc':
""" OpenCoarrays is the most commonly used method for Fortran Coarray with GCC """ """ OpenCoarrays is the most commonly used method for Fortran Coarray with GCC """
# first try pkg-config
if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
for pkg in ['caf-openmpi', 'caf']: for pkg in ['caf-openmpi', 'caf']:
pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language) pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
if pkgdep.found(): if pkgdep.found():
@ -43,19 +46,25 @@ class CoarrayDependency(ExternalDependency):
self.is_found = True self.is_found = True
self.pcdep = pkgdep self.pcdep = pkgdep
return return
# second try CMake
if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
if not kwargs.get('modules'):
kwargs['modules'] = 'OpenCoarrays::caf_mpi' kwargs['modules'] = 'OpenCoarrays::caf_mpi'
cmakedep = CMakeDependency('OpenCoarrays', environment, kwargs) cmakedep = CMakeDependency('OpenCoarrays', environment, kwargs, language=self.language)
if cmakedep.found(): if cmakedep.found():
self.compile_args = cmakedep.get_compile_args() self.compile_args = cmakedep.get_compile_args()
self.link_args = cmakedep.get_link_args() self.link_args = cmakedep.get_link_args()
self.version = cmakedep.get_version() self.version = cmakedep.get_version()
self.is_found = True self.is_found = True
return return
# give up, just run as single image fallback
if DependencyMethods.AUTO in methods:
# fallback to single image
self.compile_args = ['-fcoarray=single'] self.compile_args = ['-fcoarray=single']
self.version = 'single image' self.version = 'single image (fallback)'
self.is_found = True self.is_found = True
return
elif cid == 'intel': elif cid == 'intel':
""" Coarrays are built into Intel compilers, no external library needed """ """ Coarrays are built into Intel compilers, no external library needed """
self.is_found = True self.is_found = True
@ -68,3 +77,7 @@ class CoarrayDependency(ExternalDependency):
elif cid == 'nagfor': elif cid == 'nagfor':
""" NAG doesn't require any special arguments for Coarray """ """ NAG doesn't require any special arguments for Coarray """
self.is_found = True self.is_found = True
@staticmethod
def get_methods():
return [DependencyMethods.AUTO, DependencyMethods.CMAKE, DependencyMethods.PKGCONFIG]

@ -15,11 +15,13 @@
# This file contains the detection logic for miscellaneous external dependencies. # This file contains the detection logic for miscellaneous external dependencies.
import subprocess import subprocess
import shutil
from pathlib import Path from pathlib import Path
from .. import mlog from .. import mlog
from ..mesonlib import split_args from ..mesonlib import split_args, listify
from .base import DependencyException, ExternalDependency, ExternalProgram, PkgConfigDependency from .base import (DependencyException, DependencyMethods, ExternalDependency, ExternalProgram,
PkgConfigDependency)
class HDF5Dependency(ExternalDependency): class HDF5Dependency(ExternalDependency):
@ -29,23 +31,23 @@ class HDF5Dependency(ExternalDependency):
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
methods = listify(self.methods)
# 1. pkg-config if language not in ('c', 'cpp', 'fortran'):
raise DependencyException('Language {} is not supported with HDF5.'.format(language))
if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
PCEXE = shutil.which('pkg-config')
if PCEXE:
pkgconfig_files = ['hdf5', 'hdf5-serial'] pkgconfig_files = ['hdf5', 'hdf5-serial']
# some distros put hdf5-1.2.3.pc with version number in .pc filename. # some distros put hdf5-1.2.3.pc with version number in .pc filename.
try: ret = subprocess.run([PCEXE, '--list-all'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
ret = subprocess.run(['pkg-config', '--list-all'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL,
universal_newlines=True) universal_newlines=True)
if ret.returncode == 0: if ret.returncode == 0:
for pkg in ret.stdout.split('\n'): for pkg in ret.stdout.split('\n'):
if pkg.startswith(('hdf5')): if pkg.startswith(('hdf5')):
pkgconfig_files.append(pkg.split(' ', 1)[0]) pkgconfig_files.append(pkg.split(' ', 1)[0])
pkgconfig_files = list(set(pkgconfig_files)) # dedupe pkgconfig_files = list(set(pkgconfig_files)) # dedupe
except FileNotFoundError:
# pkg-config was not available
pass
if language not in ('c', 'cpp', 'fortran'):
raise DependencyException('Language {} is not supported with HDF5.'.format(language))
for pkg in pkgconfig_files: for pkg in pkgconfig_files:
pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language) pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
@ -94,7 +96,7 @@ class HDF5Dependency(ExternalDependency):
self.pcdep = pkgdep self.pcdep = pkgdep
return return
# 2. compiler wrapper fallback if DependencyMethods.AUTO in methods:
wrappers = {'c': 'h5cc', 'cpp': 'h5c++', 'fortran': 'h5fc'} wrappers = {'c': 'h5cc', 'cpp': 'h5c++', 'fortran': 'h5fc'}
comp_args = [] comp_args = []
link_args = [] link_args = []
@ -121,3 +123,8 @@ class HDF5Dependency(ExternalDependency):
self.compile_args = comp_args self.compile_args = comp_args
self.link_args = link_args self.link_args = link_args
self.is_found = True self.is_found = True
return
@staticmethod
def get_methods():
return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]

@ -39,12 +39,14 @@ class NetCDFDependency(ExternalDependency):
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
methods = listify(self.methods)
pkgconfig_files = ['netcdf']
if language not in ('c', 'cpp', 'fortran'): if language not in ('c', 'cpp', 'fortran'):
raise DependencyException('Language {} is not supported with NetCDF.'.format(language)) raise DependencyException('Language {} is not supported with NetCDF.'.format(language))
if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
pkgconfig_files = ['netcdf']
if language == 'fortran': if language == 'fortran':
pkgconfig_files.append('netcdf-fortran') pkgconfig_files.append('netcdf-fortran')
@ -60,6 +62,19 @@ class NetCDFDependency(ExternalDependency):
self.is_found = True self.is_found = True
self.pcdep.append(pkgdep) self.pcdep.append(pkgdep)
if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
cmakedep = CMakeDependency('NetCDF', environment, kwargs, language=self.language)
if cmakedep.found():
self.compile_args = cmakedep.get_compile_args()
self.link_args = cmakedep.get_link_args()
self.version = cmakedep.get_version()
self.is_found = True
return
@staticmethod
def get_methods():
return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG, DependencyMethods.CMAKE]
class OpenMPDependency(ExternalDependency): class OpenMPDependency(ExternalDependency):
# Map date of specification release (which is the macro value) to a version. # Map date of specification release (which is the macro value) to a version.

@ -19,9 +19,10 @@ import subprocess
from .. import mlog from .. import mlog
from .. import mesonlib from .. import mesonlib
from ..mesonlib import split_args from ..mesonlib import split_args, listify
from ..environment import detect_cpu_family from ..environment import detect_cpu_family
from .base import DependencyException, ExternalDependency, ExternalProgram, PkgConfigDependency from .base import (DependencyException, DependencyMethods, ExternalDependency, ExternalProgram,
PkgConfigDependency)
class MPIDependency(ExternalDependency): class MPIDependency(ExternalDependency):
@ -32,6 +33,8 @@ class MPIDependency(ExternalDependency):
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
methods = listify(self.methods)
env_vars = [] env_vars = []
default_wrappers = [] default_wrappers = []
pkgconfig_files = [] pkgconfig_files = []
@ -68,9 +71,8 @@ class MPIDependency(ExternalDependency):
else: else:
raise DependencyException('Language {} is not supported with MPI.'.format(language)) raise DependencyException('Language {} is not supported with MPI.'.format(language))
# 1. try pkg-config if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
for pkg in pkgconfig_files: for pkg in pkgconfig_files:
try:
pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language) pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language)
if pkgdep.found(): if pkgdep.found():
self.compile_args = pkgdep.get_compile_args() self.compile_args = pkgdep.get_compile_args()
@ -79,10 +81,8 @@ class MPIDependency(ExternalDependency):
self.is_found = True self.is_found = True
self.pcdep = pkgdep self.pcdep = pkgdep
return return
except Exception:
pass
# 2. Try environment variables if DependencyMethods.AUTO in methods:
for var in env_vars: for var in env_vars:
if var in os.environ: if var in os.environ:
wrappers = [os.environ[var]] wrappers = [os.environ[var]]
@ -116,6 +116,7 @@ class MPIDependency(ExternalDependency):
if result is not None: if result is not None:
self.is_found = True self.is_found = True
self.version, self.compile_args, self.link_args = result self.version, self.compile_args, self.link_args = result
return
def _filter_compile_args(self, args: typing.Sequence[str]) -> typing.List[str]: def _filter_compile_args(self, args: typing.Sequence[str]) -> typing.List[str]:
""" """
@ -272,3 +273,7 @@ class MPIDependency(ExternalDependency):
return (None, return (None,
['-I' + incdir, '-I' + os.path.join(incdir, post)], ['-I' + incdir, '-I' + os.path.join(incdir, post)],
[os.path.join(libdir, 'msmpi.lib')]) [os.path.join(libdir, 'msmpi.lib')])
@staticmethod
def get_methods():
return [DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]

@ -21,14 +21,14 @@ from .base import CMakeDependency, DependencyMethods, ExternalDependency, PkgCon
class ScalapackDependency(ExternalDependency): class ScalapackDependency(ExternalDependency):
def __init__(self, environment, kwargs: dict): def __init__(self, environment, kwargs: dict):
methods = mesonlib.listify(kwargs.get('method', 'auto'))
super().__init__('scalapack', environment, None, kwargs) super().__init__('scalapack', environment, None, kwargs)
kwargs['required'] = False kwargs['required'] = False
kwargs['silent'] = True kwargs['silent'] = True
self.is_found = False self.is_found = False
self.static = kwargs.get('static', False) self.static = kwargs.get('static', False)
methods = mesonlib.listify(self.methods)
if set(methods).intersection(['auto', 'pkg-config']): if set([DependencyMethods.AUTO, DependencyMethods.PKGCONFIG]).intersection(methods):
pkgconfig_files = [] pkgconfig_files = []
mklroot = None mklroot = None
is_gcc = self.clib_compiler.get_id() == 'gcc' is_gcc = self.clib_compiler.get_id() == 'gcc'
@ -106,8 +106,8 @@ class ScalapackDependency(ExternalDependency):
self.pcdep = pkgdep self.pcdep = pkgdep
return return
if set(methods).intersection(['auto', 'cmake']): if set([DependencyMethods.AUTO, DependencyMethods.CMAKE]).intersection(methods):
cmakedep = CMakeDependency('Scalapack', environment, kwargs) cmakedep = CMakeDependency('Scalapack', environment, kwargs, language=self.language)
if cmakedep.found(): if cmakedep.found():
self.compile_args = cmakedep.get_compile_args() self.compile_args = cmakedep.get_compile_args()
self.link_args = cmakedep.get_link_args() self.link_args = cmakedep.get_link_args()

@ -15,7 +15,7 @@ coarray = dependency('coarray')
# this has to invoke a run of "sync all" to verify the MPI stack is functioning, # this has to invoke a run of "sync all" to verify the MPI stack is functioning,
# particularly for dynamic linking # particularly for dynamic linking
if fc.run('sync all; end', dependencies: coarray, name: 'Coarray link & run').returncode() != 0 if fc.run('sync all; end', dependencies: coarray, name: 'Coarray link & run').returncode() != 0
error('The coarray stack (including MPI) did not link correctly so that a simple test could run.') error('MESON_SKIP_TEST: coarray stack (including MPI) did not link correctly so that a simple test could run.')
endif endif
exe = executable('hello', 'main.f90', exe = executable('hello', 'main.f90',

@ -11,14 +11,14 @@ exec = executable('exec', 'main.c', dependencies : h5c)
test('HDF5 C', exec, timeout: 30) test('HDF5 C', exec, timeout: 30)
# --- C++ tests # --- C++ tests
if add_languages('cpp') if add_languages('cpp', required: false)
h5cpp = dependency('hdf5', language : 'cpp', required : false, disabler: true) h5cpp = dependency('hdf5', language : 'cpp', required : false, disabler: true)
execpp = executable('execpp', 'main.cpp', dependencies : h5cpp) execpp = executable('execpp', 'main.cpp', dependencies : h5cpp)
test('HDF5 C++', execpp, timeout: 30) test('HDF5 C++', execpp, timeout: 30)
endif endif
# --- Fortran tests # --- Fortran tests
if add_languages('fortran') if add_languages('fortran', required: false)
h5f = dependency('hdf5', language : 'fortran', required : false, disabler: true) h5f = dependency('hdf5', language : 'fortran', required : false, disabler: true)
exef = executable('exef', 'main.f90', dependencies : h5f) exef = executable('exef', 'main.f90', dependencies : h5f)
test('HDF5 Fortran', exef, timeout: 30) test('HDF5 Fortran', exef, timeout: 30)

@ -1,31 +1,32 @@
project('netcdf_test', 'c', 'cpp') project('netcdf_test', 'c')
cc = meson.get_compiler('c')
# --- C tests c_code = '''#include <netcdf.h>
nc_c = dependency('netcdf', language : 'c', required : false) int main(void) { return 0; }'''
# --- C
nc_c = dependency('netcdf', language : 'c', required : false, disabler: true)
if not cc.links(c_code, dependencies: nc_c, name: 'NetCDF C')
nc_c = disabler()
endif
if not nc_c.found() if not nc_c.found()
error('MESON_SKIP_TEST: NetCDF C library not found, skipping NetCDF framework tests.') error('MESON_SKIP_TEST: NetCDF C library not found, skipping NetCDF framework tests.')
endif endif
exec = executable('exec', 'main.c', dependencies : nc_c) exec = executable('exec', 'main.c', dependencies : nc_c)
test('NetCDF C', exec, timeout: 15)
test('NetCDF C', exec) # --- C++
if add_languages('cpp', required: false)
# --- C++ tests nc_cpp = dependency('netcdf', language : 'cpp', required : false, disabler: true)
nc_cpp = dependency('netcdf', language : 'cpp', required : false)
if nc_cpp.found()
execpp = executable('execpp', 'main.cpp', dependencies : nc_cpp) execpp = executable('execpp', 'main.cpp', dependencies : nc_cpp)
test('NetCDF C++', execpp) test('NetCDF C++', execpp, timeout: 15)
endif endif
# --- Fortran tests # --- Fortran
if build_machine.system() != 'windows' and build_machine.system() != 'darwin' if build_machine.system() != 'windows' and build_machine.system() != 'darwin'
add_languages('fortran') if add_languages('fortran', required: false)
nc_f = dependency('netcdf', language : 'fortran', required : false, disabler: true)
nc_f = dependency('netcdf', language : 'fortran', required : false)
if nc_f.found()
exef = executable('exef', 'main.f90', dependencies : nc_f) exef = executable('exef', 'main.f90', dependencies : nc_f)
test('NetCDF Fortran', exef, timeout: 15)
test('NetCDF Fortran', exef)
endif endif
endif endif

@ -5,7 +5,6 @@ if not mpi_c.found()
error('MESON_SKIP_TEST: MPI library not available') error('MESON_SKIP_TEST: MPI library not available')
endif endif
scalapack = dependency('scalapack', required: false) scalapack = dependency('scalapack', required: false)
if not scalapack.found() if not scalapack.found()
error('MESON_SKIP_TEST: scalapack library not available') error('MESON_SKIP_TEST: scalapack library not available')
@ -15,7 +14,7 @@ c_exe = executable('scalapack_c', 'main.c',
dependencies: [scalapack, mpi_c]) dependencies: [scalapack, mpi_c])
test('scalapack_c', c_exe, timeout: 30) test('scalapack_c', c_exe, timeout: 30)
if add_languages('fortran') if add_languages('fortran', required: false)
mpi_f = dependency('mpi', language: 'fortran', required: false) mpi_f = dependency('mpi', language: 'fortran', required: false)
if not mpi_f.found() if not mpi_f.found()
error('MESON_SKIP_TEST: MPI Fortran library not available') error('MESON_SKIP_TEST: MPI Fortran library not available')

Loading…
Cancel
Save