diff options
| author | paugier <pierre.augier@univ-grenoble-alpes.fr> | 2024-08-30 17:29:10 +0200 |
|---|---|---|
| committer | Eli Schwartz <eschwartz93@gmail.com> | 2024-09-24 11:30:21 -0400 |
| commit | 901f5dfbf8899c80a4880a81cee91796bd697e71 (patch) | |
| tree | 476311fa9ff84384abd11a571fa9970f409db0e6 | |
| parent | e2ab61627a2989b9c7e4c8062d681a8084bf5280 (diff) | |
| download | meson-901f5dfbf8899c80a4880a81cee91796bd697e71.tar.gz | |
MPI detection: support more implementations (any compilers)
| -rw-r--r-- | mesonbuild/dependencies/configtool.py | 40 | ||||
| -rw-r--r-- | mesonbuild/dependencies/mpi.py | 131 |
2 files changed, 87 insertions, 84 deletions
diff --git a/mesonbuild/dependencies/configtool.py b/mesonbuild/dependencies/configtool.py index f9ec5217a..ef106a8b0 100644 --- a/mesonbuild/dependencies/configtool.py +++ b/mesonbuild/dependencies/configtool.py @@ -69,6 +69,21 @@ class ConfigToolDependency(ExternalDependency): return m.group(0).rstrip('.') return version + def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[bool, T.Union[str, None]]: + """Check whether a command is valid and get its version""" + p, out = Popen_safe(tool + [self.version_arg])[:2] + valid = True + if p.returncode != returncode: + if self.skip_version: + # maybe the executable is valid even if it doesn't support --version + p = Popen_safe(tool + [self.skip_version])[0] + if p.returncode != returncode: + valid = False + else: + valid = False + version = self._sanitize_version(out.strip()) + return valid, version + def find_config(self, versions: T.List[str], returncode: int = 0) \ -> T.Tuple[T.Optional[T.List[str]], T.Optional[str]]: """Helper method that searches for config tool binaries in PATH and @@ -82,36 +97,29 @@ class ConfigToolDependency(ExternalDependency): continue tool = potential_bin.get_command() try: - p, out = Popen_safe(tool + [self.version_arg])[:2] + valid, version = self._check_and_get_version(tool, returncode) except (FileNotFoundError, PermissionError): continue - if p.returncode != returncode: - if self.skip_version: - # maybe the executable is valid even if it doesn't support --version - p = Popen_safe(tool + [self.skip_version])[0] - if p.returncode != returncode: - continue - else: - continue - - out = self._sanitize_version(out.strip()) + if not valid: + continue + # Some tools, like pcap-config don't supply a version, but also # don't fail with --version, in that case just assume that there is # only one version and return it. - if not out: + if not version: return (tool, None) if versions: - is_found = version_compare_many(out, versions)[0] + is_found = version_compare_many(version, versions)[0] # This allows returning a found version without a config tool, # which is useful to inform the user that you found version x, # but y was required. if not is_found: tool = None if best_match[1]: - if version_compare(out, '> {}'.format(best_match[1])): - best_match = (tool, out) + if version_compare(version, '> {}'.format(best_match[1])): + best_match = (tool, version) else: - best_match = (tool, out) + best_match = (tool, version) return best_match diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py index f97bb3311..14c2560cc 100644 --- a/mesonbuild/dependencies/mpi.py +++ b/mesonbuild/dependencies/mpi.py @@ -9,6 +9,7 @@ import os import re from ..environment import detect_cpu_family +from ..mesonlib import Popen_safe from .base import DependencyMethods, detect_compiler, SystemDependency from .configtool import ConfigToolDependency from .detect import packages @@ -40,41 +41,43 @@ def mpi_factory(env: 'Environment', if DependencyMethods.CONFIG_TOOL in methods: nwargs = kwargs.copy() + # We try the environment variables for the tools first, but then + # fall back to the hardcoded names + + if language == 'c': + env_vars = ['MPICC'] + elif language == 'cpp': + env_vars = ['MPICXX'] + elif language == 'fortran': + env_vars = ['MPIFC', 'MPIF90', 'MPIF77'] + + tool_names = [os.environ.get(env_name) for env_name in env_vars] + tool_names = [t for t in tool_names if t] # remove empty environment variables + if compiler_is_intel: if env.machines[for_machine].is_windows(): - nwargs['version_arg'] = '-v' nwargs['returncode_value'] = 3 if language == 'c': - tool_names = [os.environ.get('I_MPI_CC'), 'mpiicc'] + tool_names.append('mpiicc') elif language == 'cpp': - tool_names = [os.environ.get('I_MPI_CXX'), 'mpiicpc'] + tool_names.append('mpiicpc') elif language == 'fortran': - tool_names = [os.environ.get('I_MPI_F90'), 'mpiifort'] + tool_names.append('mpiifort') - cls: T.Type[ConfigToolDependency] = IntelMPIConfigToolDependency - else: # OpenMPI, which doesn't work with intel - # - # We try the environment variables for the tools first, but then - # fall back to the hardcoded names - if language == 'c': - tool_names = [os.environ.get('MPICC'), 'mpicc'] - elif language == 'cpp': - tool_names = [os.environ.get('MPICXX'), 'mpic++', 'mpicxx', 'mpiCC'] - elif language == 'fortran': - tool_names = [os.environ.get(e) for e in ['MPIFC', 'MPIF90', 'MPIF77']] - tool_names.extend(['mpifort', 'mpif90', 'mpif77']) - - cls = OpenMPIConfigToolDependency - - tool_names = [t for t in tool_names if t] # remove empty environment variables - assert tool_names + # even with intel compilers, mpicc has to be considered + if language == 'c': + tool_names.append('mpicc') + elif language == 'cpp': + tool_names.extend(['mpic++', 'mpicxx', 'mpiCC']) + elif language == 'fortran': + tool_names.extend(['mpifort', 'mpif90', 'mpif77']) nwargs['tools'] = tool_names candidates.append(functools.partial( - cls, tool_names[0], env, nwargs, language=language)) + MPIConfigToolDependency, tool_names[0], env, nwargs, language=language)) - if DependencyMethods.SYSTEM in methods: + if DependencyMethods.SYSTEM in methods and env.machines[for_machine].is_windows(): candidates.append(functools.partial( MSMPIDependency, 'msmpi', env, kwargs, language=language)) @@ -96,7 +99,18 @@ def mpi_factory(env: 'Environment', packages['mpi'] = mpi_factory -class _MPIConfigToolDependency(ConfigToolDependency): +class MPIConfigToolDependency(ConfigToolDependency): + """Wrapper around mpicc, Intel's mpiicc and friends.""" + + def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], + language: T.Optional[str] = None): + super().__init__(name, env, kwargs, language=language) + if not self.is_found: + return + + args = self.get_config_value(['-show'], 'link and compile args') + self.compile_args = self._filter_compile_args(args) + self.link_args = self._filter_link_args(args) def _filter_compile_args(self, args: T.List[str]) -> T.List[str]: """ @@ -147,53 +161,34 @@ class _MPIConfigToolDependency(ConfigToolDependency): f == '-pthread' or (f.startswith('-W') and f != '-Wall' and not f.startswith('-Werror'))) - -class IntelMPIConfigToolDependency(_MPIConfigToolDependency): - - """Wrapper around Intel's mpiicc and friends.""" - - version_arg = '-v' # --version is not the same as -v - - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) - if not self.is_found: - return - - args = self.get_config_value(['-show'], 'link and compile args') - self.compile_args = self._filter_compile_args(args) - self.link_args = self._filter_link_args(args) - - def _sanitize_version(self, out: str) -> str: - v = re.search(r'(\d{4}) Update (\d)', out) + def _check_and_get_version(self, tool: T.List[str], returncode: int) -> T.Tuple[bool, T.Union[str, None]]: + p, out = Popen_safe(tool + ['--showme:version'])[:2] + valid = p.returncode == returncode + if valid: + # OpenMPI + v = re.search(r'\d+.\d+.\d+', out) + if v: + version = v.group(0) + else: + version = None + return valid, version + + # --version is not the same as -v + p, out = Popen_safe(tool + ['-v'])[:2] + valid = p.returncode == returncode + out = out.split("\n", maxsplit=1)[0] + + # cases like "mpicc for MPICH version 4.2.2" + v = re.search(r'\d+.\d+.\d+', out) if v: - return '{}.{}'.format(v.group(1), v.group(2)) - return out - + return valid, v.group(0) -class OpenMPIConfigToolDependency(_MPIConfigToolDependency): - - """Wrapper around OpenMPI mpicc and friends.""" - - version_arg = '--showme:version' - - def __init__(self, name: str, env: 'Environment', kwargs: T.Dict[str, T.Any], - language: T.Optional[str] = None): - super().__init__(name, env, kwargs, language=language) - if not self.is_found: - return - - c_args = self.get_config_value(['--showme:compile'], 'compile_args') - self.compile_args = self._filter_compile_args(c_args) - - l_args = self.get_config_value(['--showme:link'], 'link_args') - self.link_args = self._filter_link_args(l_args) - - def _sanitize_version(self, out: str) -> str: - v = re.search(r'\d+.\d+.\d+', out) + # cases like "mpigcc for Intel(R) MPI library 2021.13" + v = re.search(r'\d+.\d+', out) if v: - return v.group(0) - return out + return valid, v.group(0) + + return valid, None class MSMPIDependency(SystemDependency): |
