diff options
22 files changed, 509 insertions, 213 deletions
diff --git a/.github/workflows/lint_mypy.yml b/.github/workflows/lint_mypy.yml index 235c9cb..3ce1859 100644 --- a/.github/workflows/lint_mypy.yml +++ b/.github/workflows/lint_mypy.yml @@ -30,4 +30,4 @@ jobs: with: python-version: '3.x' - run: python -m pip install mypy - - run: mypy --follow-imports=skip mesonbuild/mtest.py mesonbuild/minit.py mesonbuild/msetup.py mesonbuild/wrap tools/ mesonbuild/modules/fs.py + - run: mypy --follow-imports=skip mesonbuild/mtest.py mesonbuild/minit.py mesonbuild/msetup.py mesonbuild/wrap tools/ mesonbuild/modules/fs.py mesonbuild/dependencies/mpi.py diff --git a/docs/markdown/Builtin-options.md b/docs/markdown/Builtin-options.md index f406067..9eac371 100644 --- a/docs/markdown/Builtin-options.md +++ b/docs/markdown/Builtin-options.md @@ -146,6 +146,7 @@ compiler being used: | cpp_eh | default | none, default, a, s, sc | C++ exception handling type | | cpp_rtti | true | true, false | Whether to enable RTTI (runtime type identification) | | cpp_winlibs | see below | free-form comma-separated list | Standard Windows libs to link against | +| fortran_std | none | [none, legacy, f95, f2003, f2008, f2018] | Fortran language standard to use | The default values of `c_winlibs` and `cpp_winlibs` are in compiler-specific argument forms, but the libraries are: kernel32, user32, gdi32, winspool, diff --git a/docs/markdown/Configuring-a-build-directory.md b/docs/markdown/Configuring-a-build-directory.md index b0fb574..1387a46 100644 --- a/docs/markdown/Configuring-a-build-directory.md +++ b/docs/markdown/Configuring-a-build-directory.md @@ -65,6 +65,7 @@ sample output for a simple project. cpp_debugstl false [true, false] STL debug mode cpp_link_args [] Extra arguments passed to the C++ linker cpp_std c++11 [none, c++98, c++03, c++11, c++14, c++17, c++1z, c++2a, gnu++03, gnu++11, gnu++14, gnu++17, gnu++1z, gnu++2a] C++ language standard to use + fortran_std [] [none, legacy, f95, f2003, f2008, f2018] language standard to use Directories: Option Current Value Description diff --git a/docs/markdown/IDE-integration.md b/docs/markdown/IDE-integration.md index 8e634aa..88043d3 100644 --- a/docs/markdown/IDE-integration.md +++ b/docs/markdown/IDE-integration.md @@ -261,3 +261,4 @@ This API can also work without a build directory for the `--projectinfo` command - [KDevelop](https://www.kdevelop.org) - [Eclipse CDT](https://www.eclipse.org/cdt/) (experimental) - [Meson Cmake Wrapper](https://github.com/prozum/meson-cmake-wrapper) (for cmake IDEs) +- [Meson Syntax Highlighter](https://plugins.jetbrains.com/plugin/13269-meson-syntax-highlighter) plugin for JetBrains IDEs. diff --git a/docs/markdown/snippets/fortran_std.md b/docs/markdown/snippets/fortran_std.md new file mode 100644 index 0000000..2170a5e --- /dev/null +++ b/docs/markdown/snippets/fortran_std.md @@ -0,0 +1,14 @@ +## `fortran_std` option + +**new in 0.53.0** +Akin to the `c_std` and `cpp_std` options, the `fortran_std` option sets Fortran compilers to warn or error on non-Fortran standard code. +Only the Gfortran and Intel Fortran compilers have support for this option. +Other Fortran compilers ignore the `fortran_std` option. + +Supported values for `fortran_std` include: + +* `legacy` for non-conforming code--this is especially important for Gfortran, which by default errors on old non-compliant Fortran code +* `f95` for Fortran 95 compliant code. +* `f2003` for Fortran 2003 compliant code. +* `f2008` for Fortran 2008 compliant code. +* `f2018` for Fortran 2018 compliant code.
\ No newline at end of file diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index 4623497..52a2788 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -88,8 +88,10 @@ cflags_mapping = {'c': 'CFLAGS', 'vala': 'VALAFLAGS', 'rust': 'RUSTFLAGS'} -# execinfo is a compiler lib on BSD -unixy_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt', 'execinfo') +unixy_compiler_internal_libs = ('m', 'c', 'pthread', 'dl', 'rt') +# execinfo is a compiler lib on FreeBSD and NetBSD +if mesonlib.is_freebsd() or mesonlib.is_netbsd(): + unixy_compiler_internal_libs += ('execinfo',) # All these are only for C-linkable languages; see `clink_langs` above. diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 5a2766e..3003fcd 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -17,6 +17,7 @@ from typing import List import subprocess, os import typing +from .. import coredata from .compilers import ( clike_debug_args, Compiler, @@ -32,7 +33,7 @@ from .mixins.pgi import PGICompiler from .. import mlog from mesonbuild.mesonlib import ( - EnvironmentException, MesonException, MachineChoice, LibType + version_compare, EnvironmentException, MesonException, MachineChoice, LibType ) if typing.TYPE_CHECKING: @@ -179,6 +180,25 @@ class GnuFortranCompiler(GnuCompiler, FortranCompiler): '2': default_warn_args + ['-Wextra'], '3': default_warn_args + ['-Wextra', '-Wpedantic', '-fimplicit-none']} + def get_options(self): + opts = FortranCompiler.get_options(self) + fortran_stds = ['legacy', 'f95', 'f2003'] + if version_compare(self.version, '>=4.4.0'): + fortran_stds += ['f2008'] + if version_compare(self.version, '>=8.0.0'): + fortran_stds += ['f2018'] + opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', + ['none'] + fortran_stds, + 'none')}) + return opts + + def get_option_compile_args(self, options) -> typing.List[str]: + args = [] + std = options['fortran_std'] + if std.value != 'none': + args.append('-std=' + std.value) + return args + def get_dependency_gen_args(self, outtarget, outfile): # Disabled until this is fixed: # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62162 @@ -269,6 +289,22 @@ class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): '2': default_warn_args + ['-warn', 'unused'], '3': ['-warn', 'all']} + def get_options(self): + opts = FortranCompiler.get_options(self) + fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] + opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', + ['none'] + fortran_stds, + 'none')}) + return opts + + def get_option_compile_args(self, options) -> typing.List[str]: + args = [] + std = options['fortran_std'] + stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} + if std.value != 'none': + args.append('-stand=' + stds[std.value]) + return args + def get_preprocess_only_args(self): return ['-cpp', '-EP'] @@ -312,6 +348,22 @@ class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): '2': default_warn_args + ['/warn:unused'], '3': ['/warn:all']} + def get_options(self): + opts = FortranCompiler.get_options(self) + fortran_stds = ['legacy', 'f95', 'f2003', 'f2008', 'f2018'] + opts.update({'fortran_std': coredata.UserComboOption('Fortran language standard to use', + ['none'] + fortran_stds, + 'none')}) + return opts + + def get_option_compile_args(self, options) -> typing.List[str]: + args = [] + std = options['fortran_std'] + stds = {'legacy': 'none', 'f95': 'f95', 'f2003': 'f03', 'f2008': 'f08', 'f2018': 'f18'} + if std.value != 'none': + args.append('/stand:' + stds[std.value]) + return args + def get_module_outdir_args(self, path) -> List[str]: return ['/module:' + path] diff --git a/mesonbuild/compilers/mixins/clike.py b/mesonbuild/compilers/mixins/clike.py index ce3d9d7..b5992ef 100644 --- a/mesonbuild/compilers/mixins/clike.py +++ b/mesonbuild/compilers/mixins/clike.py @@ -423,7 +423,7 @@ class CLikeCompiler: cur = maxint high = cur else: - low = cur = -1 + high = cur = -1 while self._compile_int('%s < %d' % (expression, cur), prefix, env, extra_args, dependencies): high = cur - 1 if high < minint: diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 095ec1d..c2c5e6d 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -20,7 +20,8 @@ from .base import ( # noqa: F401 PkgConfigDependency, CMakeDependency, find_external_dependency, get_dep_identifier, packages, _packages_accept_language) from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency from .coarrays import CoarrayDependency -from .misc import (BlocksDependency, HDF5Dependency, MPIDependency, NetCDFDependency, OpenMPDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency, LibGCryptDependency, GpgmeDependency, ShadercDependency) +from .mpi import MPIDependency +from .misc import (BlocksDependency, HDF5Dependency, NetCDFDependency, OpenMPDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency, LibGCryptDependency, GpgmeDependency, ShadercDependency) from .platform import AppleFrameworks from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency diff --git a/mesonbuild/dependencies/misc.py b/mesonbuild/dependencies/misc.py index 56a852e..789015a 100644 --- a/mesonbuild/dependencies/misc.py +++ b/mesonbuild/dependencies/misc.py @@ -16,18 +16,16 @@ from pathlib import Path import functools -import os import re import sysconfig from .. import mlog from .. import mesonlib -from ..mesonlib import split_args from ..environment import detect_cpu_family from .base import ( DependencyException, DependencyMethods, ExternalDependency, - ExternalProgram, ExtraFrameworkDependency, PkgConfigDependency, + ExtraFrameworkDependency, PkgConfigDependency, CMakeDependency, ConfigToolDependency, ) @@ -108,206 +106,6 @@ class NetCDFDependency(ExternalDependency): self.is_found = True self.pcdep.append(pkgdep) -class MPIDependency(ExternalDependency): - - def __init__(self, environment, kwargs): - language = kwargs.get('language', 'c') - super().__init__('mpi', environment, language, kwargs) - 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, language=self.language) - 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 - self.pcdep = pkgdep - 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 = 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 = self._filter_compile_args(result[1]) - self.link_args = self._filter_link_args(result[2]) - break - - if not self.is_found and mesonlib.is_windows(): - # only Intel Fortran compiler is compatible with Microsoft MPI at this time. - if language == 'fortran' and environment.detect_fortran_compiler(self.for_machine).name_string() != 'intel-cl': - return - result = self._try_msmpi() - if result is not None: - self.is_found = True - self.version, self.compile_args, self.link_args = result - - 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[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): - """ - 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(): - 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 = split_args(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 = split_args(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(r'\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 = split_args(o) - - version = None - - 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.host) - 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 OpenMPDependency(ExternalDependency): # Map date of specification release (which is the macro value) to a version. diff --git a/mesonbuild/dependencies/mpi.py b/mesonbuild/dependencies/mpi.py new file mode 100644 index 0000000..63460e5 --- /dev/null +++ b/mesonbuild/dependencies/mpi.py @@ -0,0 +1,274 @@ +# Copyright 2013-2019 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import typing +import os +import re +import subprocess + +from .. import mlog +from .. import mesonlib +from ..mesonlib import split_args +from ..environment import detect_cpu_family +from .base import DependencyException, ExternalDependency, ExternalProgram, PkgConfigDependency + + +class MPIDependency(ExternalDependency): + + def __init__(self, environment, kwargs: dict): + language = kwargs.get('language', 'c') + super().__init__('mpi', environment, language, kwargs) + kwargs['required'] = False + kwargs['silent'] = True + self.is_found = False + env_vars = [] + default_wrappers = [] + pkgconfig_files = [] + if language == 'c': + cid = environment.detect_c_compiler(self.for_machine).get_id() + if cid in ('intel', 'intel-cl'): + env_vars.append('I_MPI_CC') + # IntelMPI doesn't have .pc files + default_wrappers.append('mpiicc') + else: + env_vars.append('MPICC') + pkgconfig_files.append('ompi-c') + default_wrappers.append('mpicc') + elif language == 'cpp': + cid = environment.detect_cpp_compiler(self.for_machine).get_id() + if cid in ('intel', 'intel-cl'): + env_vars.append('I_MPI_CXX') + # IntelMPI doesn't have .pc files + default_wrappers.append('mpiicpc') + else: + env_vars.append('MPICXX') + pkgconfig_files.append('ompi-cxx') + default_wrappers += ['mpic++', 'mpicxx', 'mpiCC'] # these are not for intelmpi + elif language == 'fortran': + cid = environment.detect_fortran_compiler(self.for_machine).get_id() + if cid in ('intel', 'intel-cl'): + env_vars.append('I_MPI_F90') + # IntelMPI doesn't have .pc files + default_wrappers.append('mpiifort') + else: + env_vars += ['MPIFC', 'MPIF90', 'MPIF77'] + pkgconfig_files.append('ompi-fort') + default_wrappers += ['mpifort', 'mpif90', 'mpif77'] + else: + raise DependencyException('Language {} is not supported with MPI.'.format(language)) + + # 1. try pkg-config + for pkg in pkgconfig_files: + try: + pkgdep = PkgConfigDependency(pkg, environment, kwargs, language=self.language) + 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 + self.pcdep = pkgdep + return + except Exception: + pass + + # 2. Try environment variables + 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: + # Note: Some use OpenMPI with Intel compilers on Linux + result = self._try_openmpi_wrapper(prog, cid) + if result is not None: + self.is_found = True + self.version = result[0] + self.compile_args = self._filter_compile_args(result[1]) + self.link_args = self._filter_link_args(result[2], cid) + break + result = self._try_other_wrapper(prog, cid) + if result is not None: + self.is_found = True + self.version = result[0] + self.compile_args = self._filter_compile_args(result[1]) + self.link_args = self._filter_link_args(result[2], cid) + break + + if not self.is_found and mesonlib.is_windows(): + # only Intel Fortran compiler is compatible with Microsoft MPI at this time. + if language == 'fortran' and cid != 'intel-cl': + return + result = self._try_msmpi() + if result is not None: + self.is_found = True + self.version, self.compile_args, self.link_args = result + + def _filter_compile_args(self, args: typing.Sequence[str]) -> typing.List[str]: + """ + 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[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: typing.Sequence[str], cid: str) -> typing.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, cid): + result.append(f) + if f in ('-L', '-Xlinker'): + include_next = True + elif include_next: + include_next = False + result.append(f) + return result + + @staticmethod + def _is_link_arg(f: str, cid: str) -> bool: + if cid == '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'))) + + def _try_openmpi_wrapper(self, prog, cid: str): + # https://www.open-mpi.org/doc/v4.0/man1/mpifort.1.php + if cid == 'intel-cl': # IntelCl doesn't support OpenMPI + return None + prog = ExternalProgram(prog, silent=True) + if not prog.found(): + return None + + # compiler args + cmd = prog.get_command() + ['--showme:compile'] + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15) + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), p.stdout) + mlog.debug(mlog.bold('Standard error\n'), p.stderr) + return None + cargs = split_args(p.stdout) + # link args + cmd = prog.get_command() + ['--showme:link'] + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15) + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), p.stdout) + mlog.debug(mlog.bold('Standard error\n'), p.stderr) + return None + libs = split_args(p.stdout) + # version + cmd = prog.get_command() + ['--showme:version'] + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15) + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), p.stdout) + mlog.debug(mlog.bold('Standard error\n'), p.stderr) + return None + v = re.search(r'\d+.\d+.\d+', p.stdout) + if v: + version = v.group(0) + else: + version = None + + return version, cargs, libs + + def _try_other_wrapper(self, prog, cid: str) -> typing.Tuple[str, typing.List[str], typing.List[str]]: + prog = ExternalProgram(prog, silent=True) + if not prog.found(): + return None + + cmd = prog.get_command() + if cid == 'intel-cl': + cmd.append('/show') + else: + cmd.append('-show') + p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15) + if p.returncode != 0: + mlog.debug('Command', mlog.bold(cmd), 'failed to run:') + mlog.debug(mlog.bold('Standard output\n'), p.stdout) + mlog.debug(mlog.bold('Standard error\n'), p.stderr) + return None + + version = None + stdout = p.stdout + if 'Intel(R) MPI Library' in p.stdout: # intel-cl: remove messy compiler logo + out = stdout.split('\n', 2) + version = out[0] + stdout = out[2] + + if version is None: + p = subprocess.run(cmd + ['-v'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True, timeout=15) + if p.returncode == 0: + version = p.stdout.split('\n', 1)[0] + + args = split_args(stdout) + + return version, args, args + + def _try_msmpi(self) -> typing.Tuple[str, typing.List[str], typing.List[str]]: + if self.language == 'cpp': + # MS-MPI does not support the C++ version of MPI, only the standard C API. + return None + if 'MSMPI_INC' not in os.environ: + return None + + incdir = os.environ['MSMPI_INC'] + arch = detect_cpu_family(self.env.coredata.compilers.host) + if arch == 'x86': + if 'MSMPI_LIB32' not in os.environ: + return None + libdir = os.environ['MSMPI_LIB32'] + post = 'x86' + elif arch == 'x86_64': + if 'MSMPI_LIB64' not in os.environ: + return None + libdir = os.environ['MSMPI_LIB64'] + post = 'x64' + else: + return None + + 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')]) diff --git a/mesonbuild/dependencies/ui.py b/mesonbuild/dependencies/ui.py index 6d784e6..638bc68 100644 --- a/mesonbuild/dependencies/ui.py +++ b/mesonbuild/dependencies/ui.py @@ -25,7 +25,7 @@ from .. import mesonlib from ..mesonlib import ( MesonException, Popen_safe, extract_as_list, version_compare_many ) -from ..environment import detect_cpu +from ..environment import detect_cpu_family from .base import DependencyException, DependencyMethods from .base import ExternalDependency, ExternalProgram, NonExistingExternalProgram @@ -609,7 +609,7 @@ class VulkanDependency(ExternalDependency): lib_name = 'vulkan-1' lib_dir = 'Lib32' inc_dir = 'Include' - if detect_cpu({}) == 'x86_64': + if detect_cpu_family(self.env.coredata.compilers.host) == 'x86_64': lib_dir = 'Lib' else: lib_name = 'vulkan' diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index 6c27d6e..371220b 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -636,7 +636,6 @@ class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): return args - class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): """Representation of GNU ld.bfd and ld.gold.""" diff --git a/mesonbuild/mesonlib.py b/mesonbuild/mesonlib.py index 52d12bf..361bc2d 100644 --- a/mesonbuild/mesonlib.py +++ b/mesonbuild/mesonlib.py @@ -770,7 +770,7 @@ if is_windows(): result += (num_backslashes * 2) * '\\' + '"' return result - def split_args(cmd): + def split_args(cmd: typing.Sequence[str]) -> typing.List[str]: result = [] arg = '' num_backslashes = 0 diff --git a/mesonbuild/modules/unstable_cuda.py b/mesonbuild/modules/unstable_cuda.py index cd116cc..0d693c3 100644 --- a/mesonbuild/modules/unstable_cuda.py +++ b/mesonbuild/modules/unstable_cuda.py @@ -44,6 +44,7 @@ class CudaModule(ExtensionModule): raise argerror driver_version_table = [ + {'cuda_version': '>=10.2.89', 'windows': '441.22', 'linux': '440.33'}, {'cuda_version': '>=10.1.105', 'windows': '418.96', 'linux': '418.39'}, {'cuda_version': '>=10.0.130', 'windows': '411.31', 'linux': '410.48'}, {'cuda_version': '>=9.2.148', 'windows': '398.26', 'linux': '396.37'}, diff --git a/test cases/common/138 compute int/meson.build b/test cases/common/138 compute int/meson.build index 22bd266..89f4746 100644 --- a/test cases/common/138 compute int/meson.build +++ b/test cases/common/138 compute int/meson.build @@ -10,6 +10,9 @@ foobar = cc.compute_int('FOOBAR_IN_FOOBAR_H', prefix : '#include "foobar.h"', in maxint = cc.compute_int('INT_MAX', prefix: '#include <limits.h>') minint = cc.compute_int('INT_MIN', prefix: '#include <limits.h>') +# Regression test for the special case -1 that used to fail when cross compiling +assert(cc.compute_int('-1') == -1, 'compute_int(-1) failed') + cd = configuration_data() cd.set('INTSIZE', intsize) cd.set('FOOBAR', foobar) diff --git a/test cases/fortran/19 fortran_std/legacy.f b/test cases/fortran/19 fortran_std/legacy.f new file mode 100644 index 0000000..339064d --- /dev/null +++ b/test cases/fortran/19 fortran_std/legacy.f @@ -0,0 +1,7 @@ + ! non-integer loop indices are deleted in Fortran 95 standard + real a + + do 10 a=0,0.5,0.1 +10 continue + + end program
\ No newline at end of file diff --git a/test cases/fortran/19 fortran_std/meson.build b/test cases/fortran/19 fortran_std/meson.build new file mode 100644 index 0000000..f46f8ff --- /dev/null +++ b/test cases/fortran/19 fortran_std/meson.build @@ -0,0 +1,27 @@ +project('FortranStd', 'fortran', + default_options: ['warning_level=0']) +# As with C and C++, each Fortran compiler + version has a subset of supported Fortran standards +# Additionally, a necessary option for non-standard Fortran projects is the "legacy" +# option, which allows non-standard syntax and behavior quirks. +# Thus "legacy" is a necessity for some old but important Fortran projects. +# By default, popular Fortran compilers disallow these quirks without "legacy" option. + +fc = meson.get_compiler('fortran') + +executable('stdnone', 'std95.f90') + +executable('std_legacy', 'legacy.f', override_options : ['fortran_std=legacy']) + +executable('std_95', 'std95.f90', override_options : ['fortran_std=f95']) + +executable('std_f2003', 'std2003.f90', override_options : ['fortran_std=f2003']) + +executable('std_f2008', 'std2008.f90', override_options : ['fortran_std=f2008']) + +if fc.get_id() == 'gcc' + if fc.version().version_compare('>=8.0') + executable('std_f2018', 'std2018.f90', override_options : ['fortran_std=f2018']) + endif +else + executable('std_f2018', 'std2018.f90', override_options : ['fortran_std=f2018']) +endif
\ No newline at end of file diff --git a/test cases/fortran/19 fortran_std/std2003.f90 b/test cases/fortran/19 fortran_std/std2003.f90 new file mode 100644 index 0000000..08d2f50 --- /dev/null +++ b/test cases/fortran/19 fortran_std/std2003.f90 @@ -0,0 +1,36 @@ +use, intrinsic :: iso_fortran_env, only : error_unit +implicit none + +! http://fortranwiki.org/fortran/show/Real+precision +integer, parameter :: sp = selected_real_kind(6, 37) +integer, parameter :: dp = selected_real_kind(15, 307) + +real(sp) :: a32 +real(dp) :: a64 + +real(sp), parameter :: pi32 = 4*atan(1._sp) +real(dp), parameter :: pi64 = 4*atan(1._dp) + +if (pi32 == pi64) stop 1 + +call timestwo(a32) +call timestwo(a64) + +contains + +elemental subroutine timestwo(a) + +class(*), intent(inout) :: a + +select type (a) + type is (real(sp)) + a = 2*a + type is (real(dp)) + a = 2*a + type is (integer) + a = 2*a +end select + +end subroutine timestwo + +end program
\ No newline at end of file diff --git a/test cases/fortran/19 fortran_std/std2008.f90 b/test cases/fortran/19 fortran_std/std2008.f90 new file mode 100644 index 0000000..e7887ae --- /dev/null +++ b/test cases/fortran/19 fortran_std/std2008.f90 @@ -0,0 +1,32 @@ +use, intrinsic :: iso_fortran_env, only : error_unit, sp=>real32, dp=>real64 +implicit none + +real(sp) :: a32 +real(dp) :: a64 + +real(sp), parameter :: pi32 = 4*atan(1._sp) +real(dp), parameter :: pi64 = 4*atan(1._dp) + +if (pi32 == pi64) error stop 'real32 values generally do not exactly equal real64 values' + +call timestwo(a32) +call timestwo(a64) + +contains + +elemental subroutine timestwo(a) + +class(*), intent(inout) :: a + +select type (a) + type is (real(sp)) + a = 2*a + type is (real(dp)) + a = 2*a + type is (integer) + a = 2*a +end select + +end subroutine timestwo + +end program
\ No newline at end of file diff --git a/test cases/fortran/19 fortran_std/std2018.f90 b/test cases/fortran/19 fortran_std/std2018.f90 new file mode 100644 index 0000000..9a326b1 --- /dev/null +++ b/test cases/fortran/19 fortran_std/std2018.f90 @@ -0,0 +1,34 @@ +use, intrinsic :: iso_fortran_env, only : error_unit, sp=>real32, dp=>real64 +implicit none + +real(sp) :: a32 +real(dp) :: a64 + +real(sp), parameter :: pi32 = 4*atan(1._sp) +real(dp), parameter :: pi64 = 4*atan(1._dp) + +if (pi32 == pi64) error stop 'real32 values generally do not exactly equal real64 values' + +call timestwo(a32) +call timestwo(a64) + +contains + +elemental subroutine timestwo(a) + +class(*), intent(inout) :: a + +select type (a) + type is (real(sp)) + a = 2*a + type is (real(dp)) + a = 2*a + type is (integer) + a = 2*a + class default + error stop 'requires real32, real64 or integer' +end select + +end subroutine timestwo + +end program
\ No newline at end of file diff --git a/test cases/fortran/19 fortran_std/std95.f90 b/test cases/fortran/19 fortran_std/std95.f90 new file mode 100644 index 0000000..8518df1 --- /dev/null +++ b/test cases/fortran/19 fortran_std/std95.f90 @@ -0,0 +1,13 @@ +implicit none + +integer :: i, j +integer, parameter :: N=3 +real :: A(N,N) + +A = 0 + +forall (i=1:N, j=1:N) + A(i,j) = 1 +end forall + +end program
\ No newline at end of file |