mirror of
https://github.com/mesonbuild/meson.git
synced 2026-11-06 05:16:42 +00:00
This replaces all of the Apache blurbs at the start of each file with an `# SPDX-License-Identifier: Apache-2.0` string. It also fixes existing uses to be consistent in capitalization, and to be placed above any copyright notices. This removes nearly 3000 lines of boilerplate from the project (only python files), which no developer cares to look at. SPDX is in common use, particularly in the Linux kernel, and is the recommended format for Meson's own `project(license: )` field
232 lines
8.3 KiB
Python
232 lines
8.3 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# Copyright 2013-2019 The Meson development team
|
|
|
|
from __future__ import annotations
|
|
|
|
import functools
|
|
import typing as T
|
|
import os
|
|
import re
|
|
|
|
from ..environment import detect_cpu_family
|
|
from .base import DependencyMethods, detect_compiler, SystemDependency
|
|
from .configtool import ConfigToolDependency
|
|
from .detect import packages
|
|
from .factory import factory_methods
|
|
from .pkgconfig import PkgConfigDependency
|
|
|
|
if T.TYPE_CHECKING:
|
|
from .factory import DependencyGenerator
|
|
from ..environment import Environment
|
|
from ..mesonlib import MachineChoice
|
|
|
|
|
|
@factory_methods({DependencyMethods.PKGCONFIG, DependencyMethods.CONFIG_TOOL, DependencyMethods.SYSTEM})
|
|
def mpi_factory(env: 'Environment',
|
|
for_machine: 'MachineChoice',
|
|
kwargs: T.Dict[str, T.Any],
|
|
methods: T.List[DependencyMethods]) -> T.List['DependencyGenerator']:
|
|
language = kwargs.get('language', 'c')
|
|
if language not in {'c', 'cpp', 'fortran'}:
|
|
# OpenMPI doesn't work without any other languages
|
|
return []
|
|
|
|
candidates: T.List['DependencyGenerator'] = []
|
|
compiler = detect_compiler('mpi', env, for_machine, language)
|
|
if not compiler:
|
|
return []
|
|
compiler_is_intel = compiler.get_id() in {'intel', 'intel-cl'}
|
|
|
|
# Only OpenMPI has pkg-config, and it doesn't work with the intel compilers
|
|
if DependencyMethods.PKGCONFIG in methods and not compiler_is_intel:
|
|
pkg_name = None
|
|
if language == 'c':
|
|
pkg_name = 'ompi-c'
|
|
elif language == 'cpp':
|
|
pkg_name = 'ompi-cxx'
|
|
elif language == 'fortran':
|
|
pkg_name = 'ompi-fort'
|
|
candidates.append(functools.partial(
|
|
PkgConfigDependency, pkg_name, env, kwargs, language=language))
|
|
|
|
if DependencyMethods.CONFIG_TOOL in methods:
|
|
nwargs = kwargs.copy()
|
|
|
|
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']
|
|
elif language == 'cpp':
|
|
tool_names = [os.environ.get('I_MPI_CXX'), 'mpiicpc']
|
|
elif language == 'fortran':
|
|
tool_names = [os.environ.get('I_MPI_F90'), '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
|
|
|
|
nwargs['tools'] = tool_names
|
|
candidates.append(functools.partial(
|
|
cls, tool_names[0], env, nwargs, language=language))
|
|
|
|
if DependencyMethods.SYSTEM in methods:
|
|
candidates.append(functools.partial(
|
|
MSMPIDependency, 'msmpi', env, kwargs, language=language))
|
|
|
|
return candidates
|
|
|
|
packages['mpi'] = mpi_factory
|
|
|
|
|
|
class _MPIConfigToolDependency(ConfigToolDependency):
|
|
|
|
def _filter_compile_args(self, args: T.List[str]) -> T.List[str]:
|
|
"""
|
|
MPI wrappers return a bunch of garbage args.
|
|
Drop -O2 and everything that is not needed.
|
|
"""
|
|
result = []
|
|
multi_args: T.Tuple[str, ...] = ('-I', )
|
|
if self.language == 'fortran':
|
|
fc = self.env.coredata.compilers[self.for_machine]['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: T.List[str]) -> T.List[str]:
|
|
"""
|
|
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 self._is_link_arg(f):
|
|
result.append(f)
|
|
if f in {'-L', '-Xlinker'}:
|
|
include_next = True
|
|
elif include_next:
|
|
include_next = False
|
|
result.append(f)
|
|
return result
|
|
|
|
def _is_link_arg(self, f: str) -> bool:
|
|
if self.clib_compiler.id == 'intel-cl':
|
|
return f == '/link' or f.startswith('/LIBPATH') or f.endswith('.lib') # always .lib whether static or dynamic
|
|
else:
|
|
return (f.startswith(('-L', '-l', '-Xlinker')) or
|
|
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)
|
|
if v:
|
|
return '{}.{}'.format(v.group(1), v.group(2))
|
|
return out
|
|
|
|
|
|
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)
|
|
if v:
|
|
return v.group(0)
|
|
return out
|
|
|
|
|
|
class MSMPIDependency(SystemDependency):
|
|
|
|
"""The Microsoft MPI."""
|
|
|
|
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)
|
|
# MSMPI only supports the C API
|
|
if language not in {'c', 'fortran', None}:
|
|
self.is_found = False
|
|
return
|
|
# MSMPI is only for windows, obviously
|
|
if not self.env.machines[self.for_machine].is_windows():
|
|
return
|
|
|
|
incdir = os.environ.get('MSMPI_INC')
|
|
arch = detect_cpu_family(self.env.coredata.compilers.host)
|
|
libdir = None
|
|
if arch == 'x86':
|
|
libdir = os.environ.get('MSMPI_LIB32')
|
|
post = 'x86'
|
|
elif arch == 'x86_64':
|
|
libdir = os.environ.get('MSMPI_LIB64')
|
|
post = 'x64'
|
|
|
|
if libdir is None or incdir is None:
|
|
self.is_found = False
|
|
return
|
|
|
|
self.is_found = True
|
|
self.link_args = ['-l' + os.path.join(libdir, 'msmpi')]
|
|
self.compile_args = ['-I' + incdir, '-I' + os.path.join(incdir, post)]
|
|
if self.language == 'fortran':
|
|
self.link_args.append('-l' + os.path.join(libdir, 'msmpifec'))
|