summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpaugier <pierre.augier@univ-grenoble-alpes.fr>2024-08-30 17:29:10 +0200
committerEli Schwartz <eschwartz93@gmail.com>2024-09-24 11:30:21 -0400
commit901f5dfbf8899c80a4880a81cee91796bd697e71 (patch)
tree476311fa9ff84384abd11a571fa9970f409db0e6
parente2ab61627a2989b9c7e4c8062d681a8084bf5280 (diff)
downloadmeson-901f5dfbf8899c80a4880a81cee91796bd697e71.tar.gz
MPI detection: support more implementations (any compilers)
-rw-r--r--mesonbuild/dependencies/configtool.py40
-rw-r--r--mesonbuild/dependencies/mpi.py131
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):