diff options
author | Jussi Pakkanen <jpakkane@gmail.com> | 2019-05-14 00:24:48 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-05-14 00:24:48 +0300 |
commit | 7b8ef78bc0002d0327626c6218b793f87c2a5eb8 (patch) | |
tree | 44ffa3b3c11e8e154615d65e79f9c79f5334648d | |
parent | b849f6f935787055834ed3745faf7203c22c982b (diff) | |
parent | 523c7beefc170395fd3f49cf4609aadb8e986ad1 (diff) | |
download | meson-7b8ef78bc0002d0327626c6218b793f87c2a5eb8.zip meson-7b8ef78bc0002d0327626c6218b793f87c2a5eb8.tar.gz meson-7b8ef78bc0002d0327626c6218b793f87c2a5eb8.tar.bz2 |
Merge pull request #5331 from dcbaker/icl
ICL (Intel for Windows) support
28 files changed, 343 insertions, 119 deletions
diff --git a/docs/markdown/Reference-tables.md b/docs/markdown/Reference-tables.md index d3a6815..682e508 100644 --- a/docs/markdown/Reference-tables.md +++ b/docs/markdown/Reference-tables.md @@ -5,29 +5,30 @@ These are return values of the `get_id` (Compiler family) and `get_argument_syntax` (Argument syntax) method in a compiler object. -| Value | Compiler family | Argument syntax | -| ----- | --------------- | --------------- | -| arm | ARM compiler | | -| armclang | ARMCLANG compiler | | -| ccrx | Renesas RX Family C/C++ compiler | | -| clang | The Clang compiler | gcc | -| clang-cl | The Clang compiler (MSVC compatible driver) | msvc | -| dmd | D lang reference compiler | | -| flang | Flang Fortran compiler | | -| g95 | The G95 Fortran compiler | | -| gcc | The GNU Compiler Collection | gcc | -| intel | Intel compiler | msvc on windows, otherwise gcc | -| lcc | Elbrus C/C++/Fortran Compiler | | -| llvm | LLVM-based compiler (Swift, D) | | -| mono | Xamarin C# compiler | | -| msvc | Microsoft Visual Studio | msvc | -| nagfor | The NAG Fortran compiler | | -| open64 | The Open64 Fortran Compiler | | -| pathscale | The Pathscale Fortran compiler | | -| pgi | Portland PGI C/C++/Fortran compilers | | -| rustc | Rust compiler | | -| sun | Sun Fortran compiler | | -| valac | Vala compiler | | +| Value | Compiler family | Argument syntax | +| ----- | --------------- | --------------- | +| arm | ARM compiler | | +| armclang | ARMCLANG compiler | | +| ccrx | Renesas RX Family C/C++ compiler | | +| clang | The Clang compiler | gcc | +| clang-cl | The Clang compiler (MSVC compatible driver) | msvc | +| dmd | D lang reference compiler | | +| flang | Flang Fortran compiler | | +| g95 | The G95 Fortran compiler | | +| gcc | The GNU Compiler Collection | gcc | +| intel | Intel compiler (Linux and Mac) | gcc | +| intel-cl | Intel compiler (Windows) | msvc | +| lcc | Elbrus C/C++/Fortran Compiler | | +| llvm | LLVM-based compiler (Swift, D) | | +| mono | Xamarin C# compiler | | +| msvc | Microsoft Visual Studio | msvc | +| nagfor | The NAG Fortran compiler | | +| open64 | The Open64 Fortran Compiler | | +| pathscale | The Pathscale Fortran compiler | | +| pgi | Portland PGI C/C++/Fortran compilers | | +| rustc | Rust compiler | | +| sun | Sun Fortran compiler | | +| valac | Vala compiler | | ## Script environment variables diff --git a/docs/markdown/snippets/intel-cl.md b/docs/markdown/snippets/intel-cl.md new file mode 100644 index 0000000..d866e70 --- /dev/null +++ b/docs/markdown/snippets/intel-cl.md @@ -0,0 +1,13 @@ +## Support for the Intel Compiler on Windows (ICL) + +Support has been added for ICL.EXE and ifort on windows. The support should be +on part with ICC support on Linux/MacOS. The ICL C/C++ compiler behaves like +Microsoft's CL.EXE rather than GCC/Clang like ICC does, and has a different id, +`intel-cl` to differentiate it. + +```meson +cc = meson.get_compiler('c') +if cc.get_id == 'intel-cl' + add_project_argument('/Qfoobar:yes', language : 'c') +endif +``` diff --git a/mesonbuild/backend/ninjabackend.py b/mesonbuild/backend/ninjabackend.py index e0a6440..69682d4 100644 --- a/mesonbuild/backend/ninjabackend.py +++ b/mesonbuild/backend/ninjabackend.py @@ -221,6 +221,10 @@ class NinjaBackend(backends.Backend): Detect the search prefix to use.''' for compiler in self.build.compilers.values(): # Have to detect the dependency format + + # IFort on windows is MSVC like, but doesn't have /showincludes + if isinstance(compiler, FortranCompiler): + continue if isinstance(compiler, VisualStudioLikeCompiler): break else: diff --git a/mesonbuild/build.py b/mesonbuild/build.py index 603e0d0..bc17445 100644 --- a/mesonbuild/build.py +++ b/mesonbuild/build.py @@ -1249,7 +1249,7 @@ You probably should put it in link_with instead.''') ''' linker, _ = self.get_clink_dynamic_linker_and_stdlibs() # Mixing many languages with MSVC is not supported yet so ignore stdlibs. - if linker and linker.get_id() in ['msvc', 'clang-cl', 'llvm', 'dmd']: + if linker and linker.get_id() in {'msvc', 'clang-cl', 'intel-cl', 'llvm', 'dmd'}: return True return False diff --git a/mesonbuild/compilers/__init__.py b/mesonbuild/compilers/__init__.py index 3c06f38..ea65c21 100644 --- a/mesonbuild/compilers/__init__.py +++ b/mesonbuild/compilers/__init__.py @@ -65,10 +65,14 @@ __all__ = [ 'FlangFortranCompiler', 'GnuObjCCompiler', 'GnuObjCPPCompiler', - 'IntelCompiler', + 'IntelGnuLikeCompiler', + 'IntelVisualStudioLikeCompiler', 'IntelCCompiler', 'IntelCPPCompiler', + 'IntelClCCompiler', + 'IntelClCPPCompiler', 'IntelFortranCompiler', + 'IntelClFortranCompiler', 'JavaCompiler', 'LLVMDCompiler', 'MonoCompiler', @@ -119,9 +123,10 @@ from .compilers import ( ClangCompiler, CompilerArgs, GnuCompiler, - IntelCompiler, + IntelGnuLikeCompiler, CcrxCompiler, VisualStudioLikeCompiler, + IntelVisualStudioLikeCompiler, ) from .c import ( CCompiler, @@ -132,6 +137,7 @@ from .c import ( GnuCCompiler, ElbrusCCompiler, IntelCCompiler, + IntelClCCompiler, PGICCompiler, CcrxCCompiler, VisualStudioCCompiler, @@ -145,6 +151,7 @@ from .cpp import ( GnuCPPCompiler, ElbrusCPPCompiler, IntelCPPCompiler, + IntelClCPPCompiler, PGICPPCompiler, CcrxCPPCompiler, VisualStudioCPPCompiler, @@ -164,6 +171,7 @@ from .fortran import ( ElbrusFortranCompiler, FlangFortranCompiler, IntelFortranCompiler, + IntelClFortranCompiler, NAGFortranCompiler, Open64FortranCompiler, PathScaleFortranCompiler, diff --git a/mesonbuild/compilers/c.py b/mesonbuild/compilers/c.py index 73a4083..0cfcbc3 100644 --- a/mesonbuild/compilers/c.py +++ b/mesonbuild/compilers/c.py @@ -16,7 +16,7 @@ import os.path import typing from .. import coredata -from ..mesonlib import MesonException, version_compare +from ..mesonlib import MesonException, version_compare, mlog from .c_function_attributes import C_FUNC_ATTRIBUTES from .clike import CLikeCompiler @@ -30,7 +30,8 @@ from .compilers import ( CompilerType, GnuCompiler, ElbrusCompiler, - IntelCompiler, + IntelGnuLikeCompiler, + IntelVisualStudioLikeCompiler, PGICompiler, CcrxCompiler, VisualStudioLikeCompiler, @@ -221,10 +222,10 @@ class ElbrusCCompiler(GnuCCompiler, ElbrusCompiler): dependencies=dependencies) -class IntelCCompiler(IntelCompiler, CCompiler): +class IntelCCompiler(IntelGnuLikeCompiler, CCompiler): def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) - IntelCompiler.__init__(self, compiler_type) + IntelGnuLikeCompiler.__init__(self, compiler_type) self.lang_header = 'c-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark'] self.warn_args = {'0': [], @@ -279,6 +280,36 @@ class ClangClCCompiler(VisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, self.id = 'clang-cl' +class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler): + + """Intel "ICL" compiler abstraction.""" + + __have_warned = False + + def __init__(self, exelist, version, is_cross, exe_wrap, target): + CCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + IntelVisualStudioLikeCompiler.__init__(self, target) + + def get_options(self): + opts = super().get_options() + c_stds = ['none', 'c89', 'c99', 'c11'] + opts.update({'c_std': coredata.UserComboOption('c_std', 'C language standard to use', + c_stds, + 'none')}) + return opts + + def get_option_compile_args(self, options): + args = [] + std = options['c_std'] + if std.value == 'c89': + if not self.__have_warned: + self.__have_warned = True + mlog.warning("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.") + elif std.value != 'none': + args.append('/Qstd:' + std.value) + return args + + class ArmCCompiler(ArmCompiler, CCompiler): def __init__(self, exelist, version, compiler_type, is_cross, exe_wrapper=None, **kwargs): CCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwargs) diff --git a/mesonbuild/compilers/clike.py b/mesonbuild/compilers/clike.py index e9d5d1d..3d29b75 100644 --- a/mesonbuild/compilers/clike.py +++ b/mesonbuild/compilers/clike.py @@ -776,7 +776,7 @@ class CLikeCompiler: return True, cached # MSVC does not have compiler __builtin_-s. - if self.get_id() == 'msvc': + if self.get_id() in {'msvc', 'intel-cl'}: return False, False # Detect function as a built-in @@ -849,7 +849,7 @@ class CLikeCompiler: ''' args = self.get_compiler_check_args() n = 'symbols_have_underscore_prefix' - with self.compile(code, args, 'compile', want_output=True) as p: + with self.compile(code, extra_args=args, mode='compile', want_output=True) as p: if p.returncode != 0: m = 'BUG: Unable to compile {!r} check: {}' raise RuntimeError(m.format(n, p.stdo)) diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py index bafb023..dacf75d 100644 --- a/mesonbuild/compilers/compilers.py +++ b/mesonbuild/compilers/compilers.py @@ -1146,7 +1146,7 @@ class Compiler: return os.path.join(dirname, 'output.' + suffix) @contextlib.contextmanager - def compile(self, code, extra_args=None, mode='link', want_output=False): + def compile(self, code, extra_args=None, *, mode='link', want_output=False): if extra_args is None: extra_args = [] try: @@ -1199,7 +1199,7 @@ class Compiler: pass @contextlib.contextmanager - def cached_compile(self, code, cdata: coredata.CoreData, extra_args=None, mode: str = 'link'): + def cached_compile(self, code, cdata: coredata.CoreData, *, extra_args=None, mode: str = 'link'): assert(isinstance(cdata, coredata.CoreData)) # Calculate the key @@ -1465,14 +1465,14 @@ def get_compiler_uses_gnuld(c): # FIXME: Perhaps we should detect the linker in the environment? # FIXME: Assumes that *BSD use GNU ld, but they might start using lld soon compiler_type = getattr(c, 'compiler_type', None) - return compiler_type in ( + return compiler_type in { CompilerType.GCC_STANDARD, CompilerType.GCC_MINGW, CompilerType.GCC_CYGWIN, CompilerType.CLANG_STANDARD, CompilerType.CLANG_MINGW, CompilerType.ICC_STANDARD, - CompilerType.ICC_WIN) + } def get_largefile_args(compiler): ''' @@ -1791,16 +1791,7 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): return None return vs32_instruction_set_args.get(instruction_set, None) - def get_toolset_version(self): - if self.id == 'clang-cl': - # I have no idea - return '14.1' - - # See boost/config/compiler/visualc.cpp for up to date mapping - try: - version = int(''.join(self.version.split('.')[0:2])) - except ValueError: - return None + def _calculate_toolset_version(self, version: int) -> Optional[str]: if version < 1310: return '7.0' elif version < 1400: @@ -1824,6 +1815,18 @@ class VisualStudioLikeCompiler(metaclass=abc.ABCMeta): mlog.warning('Could not find toolset for version {!r}'.format(self.version)) return None + def get_toolset_version(self): + if self.id == 'clang-cl': + # I have no idea + return '14.1' + + # See boost/config/compiler/visualc.cpp for up to date mapping + try: + version = int(''.join(self.version.split('.')[0:2])) + except ValueError: + return None + return self._calculate_toolset_version(version) + def get_default_include_dirs(self): if 'INCLUDE' not in os.environ: return [] @@ -2288,7 +2291,7 @@ class ArmclangCompiler: # Tested on linux for ICC 14.0.3, 15.0.6, 16.0.4, 17.0.1, 19.0.0 -class IntelCompiler(GnuLikeCompiler): +class IntelGnuLikeCompiler(GnuLikeCompiler): def __init__(self, compiler_type): super().__init__(compiler_type) @@ -2344,6 +2347,48 @@ class IntelCompiler(GnuLikeCompiler): return ['-prof-use'] +class IntelVisualStudioLikeCompiler(VisualStudioLikeCompiler): + + """Abstractions for ICL, the Intel compiler on Windows.""" + + def __init__(self, target: str): + super().__init__(target) + self.compiler_type = CompilerType.ICC_WIN + self.id = 'intel-cl' + + def compile(self, code, *, extra_args=None, **kwargs): + # This covers a case that .get('foo', []) doesn't, that extra_args is + if kwargs.get('mode', 'compile') != 'link': + extra_args = extra_args.copy() if extra_args is not None else [] + extra_args.extend([ + '/Qdiag-error:10006', # ignoring unknown option + '/Qdiag-error:10148', # Option not supported + '/Qdiag-error:10155', # ignoring argument required + '/Qdiag-error:10156', # ignoring not argument allowed + '/Qdiag-error:10157', # Ignoring argument of the wrong type + '/Qdiag-error:10158', # Argument must be separate. Can be hit by trying an option like -foo-bar=foo when -foo=bar is a valid option but -foo-bar isn't + ]) + return super().compile(code, extra_args, **kwargs) + + def get_toolset_version(self) -> Optional[str]: + # Avoid circular dependencies.... + from ..environment import search_version + + # ICL provides a cl.exe that returns the version of MSVC it tries to + # emulate, so we'll get the version from that and pass it to the same + # function the real MSVC uses to calculate the toolset version. + _, _, err = Popen_safe(['cl.exe']) + v1, v2, *_ = search_version(err).split('.') + version = int(v1 + v2) + return self._calculate_toolset_version(version) + + def get_linker_exelist(self): + return ['xilink'] + + def openmp_flags(self): + return ['/Qopenmp'] + + class ArmCompiler: # Functionality that is common to all ARM family compilers. def __init__(self, compiler_type): diff --git a/mesonbuild/compilers/cpp.py b/mesonbuild/compilers/cpp.py index 988eac6..9fae22c 100644 --- a/mesonbuild/compilers/cpp.py +++ b/mesonbuild/compilers/cpp.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import copy import functools import os.path import typing @@ -26,7 +27,8 @@ from .compilers import ( ClangCompiler, GnuCompiler, ElbrusCompiler, - IntelCompiler, + IntelGnuLikeCompiler, + IntelVisualStudioLikeCompiler, PGICompiler, ArmCompiler, ArmclangCompiler, @@ -104,7 +106,7 @@ class CPPCompiler(CLikeCompiler, Compiler): # 2. even if it did have an env object, that might contain another more # recent -std= argument, which might lead to a cascaded failure. CPP_TEST = 'int i = static_cast<int>(0);' - with self.compile(code=CPP_TEST, extra_args=[cpp_std_value], mode='compile') as p: + with self.compile(CPP_TEST, extra_args=[cpp_std_value], mode='compile') as p: if p.returncode == 0: mlog.debug('Compiler accepts {}:'.format(cpp_std_value), 'YES') return True @@ -310,10 +312,10 @@ class ElbrusCPPCompiler(GnuCPPCompiler, ElbrusCompiler): dependencies=dependencies) -class IntelCPPCompiler(IntelCompiler, CPPCompiler): +class IntelCPPCompiler(IntelGnuLikeCompiler, CPPCompiler): def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap, **kwargs): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) - IntelCompiler.__init__(self, compiler_type) + IntelGnuLikeCompiler.__init__(self, compiler_type) self.lang_header = 'c++-header' default_warn_args = ['-Wall', '-w3', '-diag-disable:remark', '-Wpch-messages', '-Wnon-virtual-dtor'] @@ -371,6 +373,16 @@ class VisualStudioLikeCPPCompilerMixin: """Mixin for C++ specific method overrides in MSVC-like compilers.""" + VC_VERSION_MAP = { + 'none': (True, None), + 'vc++11': (True, 11), + 'vc++14': (True, 14), + 'vc++17': (True, 17), + 'c++11': (False, 11), + 'c++14': (False, 14), + 'c++17': (False, 17), + } + def get_option_link_args(self, options): return options['cpp_winlibs'].value[:] @@ -397,34 +409,12 @@ class VisualStudioLikeCPPCompilerMixin: elif eh.value != 'none': args.append('/EH' + eh.value) - vc_version_map = { - 'none': (True, None), - 'vc++11': (True, 11), - 'vc++14': (True, 14), - 'vc++17': (True, 17), - 'c++11': (False, 11), - 'c++14': (False, 14), - 'c++17': (False, 17)} - - permissive, ver = vc_version_map[options['cpp_std'].value] - - if ver is None: - pass - elif ver == 11: - # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can - # which means setting the C++ standard version to C++14, in compilers that support it - # (i.e., after VS2015U3) - # if one is using anything before that point, one cannot set the standard. - if self.id == 'clang-cl' or version_compare(self.version, '>=19.00.24210'): - mlog.warning('MSVC does not support C++11; ' - 'attempting best effort; setting the standard to C++14') - args.append('/std:c++14') - else: - mlog.warning('This version of MSVC does not support cpp_std arguments') - else: + permissive, ver = self.VC_VERSION_MAP[options['cpp_std'].value] + + if ver is not None: args.append('/std:c++{}'.format(ver)) - if not permissive and version_compare(self.version, '>=19.11'): + if not permissive: args.append('/permissive-') return args @@ -434,7 +424,33 @@ class VisualStudioLikeCPPCompilerMixin: return CLikeCompiler.get_compiler_check_args(self) -class VisualStudioCPPCompiler(VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): +class CPP11AsCPP14Mixin: + + """Mixin class for VisualStudio and ClangCl to replace C++11 std with C++14. + + This is a limitation of Clang and MSVC that ICL doesn't share. + """ + + def get_option_compile_args(self, options): + # Note: there is no explicit flag for supporting C++11; we attempt to do the best we can + # which means setting the C++ standard version to C++14, in compilers that support it + # (i.e., after VS2015U3) + # if one is using anything before that point, one cannot set the standard. + if options['cpp_std'].value in {'vc++11', 'c++11'}: + mlog.warning(self.id, 'does not support C++11;', + 'attempting best effort; setting the standard to C++14') + # Don't mutate anything we're going to change, we need to use + # deepcopy since we're messing with members, and we can't simply + # copy the members because the option proxy doesn't support it. + options = copy.deepcopy(options) + if options['cpp_std'].value == 'vc++11': + options['cpp_std'].value = 'vc++14' + else: + options['cpp_std'].value = 'c++14' + return super().get_option_compile_args(options) + + +class VisualStudioCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap, target): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) @@ -445,14 +461,29 @@ class VisualStudioCPPCompiler(VisualStudioLikeCPPCompilerMixin, VisualStudioLike cpp_stds = ['none', 'c++11', 'vc++11'] # Visual Studio 2015 and later if version_compare(self.version, '>=19'): - cpp_stds.extend(['c++14', 'vc++14', 'c++latest', 'vc++latest']) + cpp_stds.extend(['c++14', 'c++latest', 'vc++latest']) # Visual Studio 2017 and later if version_compare(self.version, '>=19.11'): - cpp_stds.extend(['c++17', 'vc++17']) + cpp_stds.extend(['vc++14', 'c++17', 'vc++17']) return self._get_options_impl(super().get_options(), cpp_stds) + def get_option_compile_args(self, options): + if options['cpp_std'].value != 'none' and version_compare(self.version, '<19.00.24210'): + mlog.warning('This version of MSVC does not support cpp_std arguments') + options = copy.copy(options) + options['cpp_std'].value = 'none' + + args = super().get_option_compile_args(options) + + if version_compare(self.version, '<19.11'): + try: + i = args.index('/permissive-') + except ValueError: + return args + del args[i] + return args -class ClangClCPPCompiler(VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): +class ClangClCPPCompiler(CPP11AsCPP14Mixin, VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompiler, CPPCompiler): def __init__(self, exelist, version, is_cross, exe_wrap, target): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) VisualStudioLikeCompiler.__init__(self, target) @@ -463,6 +494,18 @@ class ClangClCPPCompiler(VisualStudioLikeCPPCompilerMixin, VisualStudioLikeCompi return self._get_options_impl(super().get_options(), cpp_stds) +class IntelClCPPCompiler(VisualStudioLikeCPPCompilerMixin, IntelVisualStudioLikeCompiler, CPPCompiler): + + def __init__(self, exelist, version, is_cross, exe_wrap, target): + CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap) + IntelVisualStudioLikeCompiler.__init__(self, target) + + def get_options(self): + # This has only been tested with verison 19.0, + cpp_stds = ['none', 'c++11', 'vc++11', 'c++14', 'vc++14', 'c++17', 'vc++17', 'c++latest'] + return self._get_options_impl(super().get_options(), cpp_stds) + + class ArmCPPCompiler(ArmCompiler, CPPCompiler): def __init__(self, exelist, version, compiler_type, is_cross, exe_wrap=None, **kwargs): CPPCompiler.__init__(self, exelist, version, is_cross, exe_wrap, **kwargs) diff --git a/mesonbuild/compilers/fortran.py b/mesonbuild/compilers/fortran.py index 3fee43b..06e01d0 100644 --- a/mesonbuild/compilers/fortran.py +++ b/mesonbuild/compilers/fortran.py @@ -26,8 +26,9 @@ from .compilers import ( GnuCompiler, ClangCompiler, ElbrusCompiler, - IntelCompiler, + IntelGnuLikeCompiler, PGICompiler, + IntelVisualStudioLikeCompiler, ) from .clike import CLikeCompiler @@ -66,6 +67,7 @@ class FortranCompiler(CLikeCompiler, Compiler): for_machine = MachineChoice.HOST extra_flags = environment.coredata.get_external_args(for_machine, self.language) extra_flags += environment.coredata.get_external_link_args(for_machine, self.language) + extra_flags += self.get_always_args() # %% build the test executable pc = subprocess.Popen(self.exelist + extra_flags + [str(source_name), '-o', str(binary_name)]) pc.wait() @@ -213,13 +215,13 @@ class SunFortranCompiler(FortranCompiler): return ['-xopenmp'] -class IntelFortranCompiler(IntelCompiler, FortranCompiler): +class IntelFortranCompiler(IntelGnuLikeCompiler, FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): self.file_suffixes = ('f90', 'f', 'for', 'ftn', 'fpp') FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper, **kwags) # FIXME: Add support for OS X and Windows in detect_fortran_compiler so # we are sent the type of compiler - IntelCompiler.__init__(self, CompilerType.ICC_STANDARD) + IntelGnuLikeCompiler.__init__(self, CompilerType.ICC_STANDARD) self.id = 'intel' default_warn_args = ['-warn', 'general', '-warn', 'truncated_source'] self.warn_args = {'0': [], @@ -239,6 +241,36 @@ class IntelFortranCompiler(IntelCompiler, FortranCompiler): def language_stdlib_only_link_flags(self): return ['-lifcore', '-limf'] +class IntelClFortranCompiler(IntelVisualStudioLikeCompiler, FortranCompiler): + + file_suffixes = ['f90', 'f', 'for', 'ftn', 'fpp'] + always_args = ['/nologo'] + + BUILD_ARGS = { + 'plain': [], + 'debug': ["/Zi", "/Od"], + 'debugoptimized': ["/Zi", "/O1"], + 'release': ["/O2"], + 'minsize': ["/Os"], + 'custom': [], + } + + def __init__(self, exelist, version, is_cross, target: str, exe_wrapper=None): + FortranCompiler.__init__(self, exelist, version, is_cross, exe_wrapper) + IntelVisualStudioLikeCompiler.__init__(self, target) + + default_warn_args = ['/warn:general', '/warn:truncated_source'] + self.warn_args = {'0': [], + '1': default_warn_args, + '2': default_warn_args + ['/warn:unused'], + '3': ['/warn:all']} + + def get_module_outdir_args(self, path) -> List[str]: + return ['/module:' + path] + + def get_buildtype_args(self, buildtype: str) -> List[str]: + return self.BUILD_ARGS[buildtype] + class PathScaleFortranCompiler(FortranCompiler): def __init__(self, exelist, version, is_cross, exe_wrapper=None, **kwags): diff --git a/mesonbuild/environment.py b/mesonbuild/environment.py index dd1d4cf..9620639 100644 --- a/mesonbuild/environment.py +++ b/mesonbuild/environment.py @@ -15,7 +15,7 @@ import os, platform, re, sys, shlex, shutil, subprocess, typing from . import coredata -from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker +from .linkers import ArLinker, ArmarLinker, VisualStudioLinker, DLinker, CcrxLinker, IntelVisualStudioLinker from . import mesonlib from .mesonlib import ( MesonException, EnvironmentException, MachineChoice, Popen_safe, @@ -60,7 +60,10 @@ from .compilers import ( ElbrusFortranCompiler, IntelCCompiler, IntelCPPCompiler, + IntelClCCompiler, + IntelClCPPCompiler, IntelFortranCompiler, + IntelClFortranCompiler, JavaCompiler, MonoCompiler, CudaCompiler, @@ -457,12 +460,18 @@ class Environment: # List of potential compilers. if mesonlib.is_windows(): # Intel C and C++ compiler is icl on Windows, but icc and icpc elsewhere. - self.default_c = ['cl', 'cc', 'gcc', 'clang', 'clang-cl', 'pgcc', 'icl'] + # Search for icl before cl, since Intel "helpfully" provides a + # cl.exe that returns *exactly the same thing* that microsofts + # cl.exe does, and if icl is present, it's almost certainly what + # you want. + self.default_c = ['icl', 'cl', 'cc', 'gcc', 'clang', 'clang-cl', 'pgcc'] # There is currently no pgc++ for Windows, only for Mac and Linux. - self.default_cpp = ['cl', 'c++', 'g++', 'clang++', 'clang-cl', 'icl'] + self.default_cpp = ['icl', 'cl', 'c++', 'g++', 'clang++', 'clang-cl'] + self.default_fortran = ['ifort', 'gfortran', 'flang', 'pgfortran', 'g95'] else: self.default_c = ['cc', 'gcc', 'clang', 'pgcc', 'icc'] self.default_cpp = ['c++', 'g++', 'clang++', 'pgc++', 'icpc'] + self.default_fortran = ['gfortran', 'flang', 'pgfortran', 'ifort', 'g95'] if mesonlib.is_windows(): self.default_cs = ['csc', 'mcs'] else: @@ -470,7 +479,6 @@ class Environment: self.default_objc = ['cc'] self.default_objcpp = ['c++'] self.default_d = ['ldc2', 'ldc', 'gdc', 'dmd'] - self.default_fortran = ['gfortran', 'flang', 'pgfortran', 'ifort', 'g95'] self.default_java = ['javac'] self.default_cuda = ['nvcc'] self.default_rust = ['rustc'] @@ -677,8 +685,12 @@ class Environment: arg = '--vsn' elif 'ccrx' in compiler[0]: arg = '-v' + elif 'icl' in compiler[0]: + # if you pass anything to icl you get stuck in a pager + arg = '' else: arg = '--version' + try: p, out, err = Popen_safe(compiler + [arg]) except OSError as e: @@ -753,6 +765,11 @@ class Environment: compiler_type = CompilerType.CLANG_STANDARD cls = ClangCCompiler if lang == 'c' else ClangCPPCompiler return cls(ccache + compiler, version, compiler_type, is_cross, exe_wrap, full_version=full_version) + if 'Intel(R) C++ Intel(R)' in err: + version = search_version(err) + target = 'x86' if 'IA-32' in err else 'x86_64' + cls = IntelClCCompiler if lang == 'c' else IntelClCPPCompiler + return cls(compiler, version, is_cross, exe_wrap, target) if 'Microsoft' in out or 'Microsoft' in err: # Latest versions of Visual Studio print version # number to stderr but earlier ones print version @@ -886,6 +903,11 @@ class Environment: version = search_version(err) return SunFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) + if 'Intel(R) Visual Fortran' in err: + version = search_version(err) + target = 'x86' if 'IA-32' in err else 'x86_64' + return IntelClFortranCompiler(compiler, version, is_cross, target, exe_wrap) + if 'ifort (IFORT)' in out: return IntelFortranCompiler(compiler, version, is_cross, exe_wrap, full_version=full_version) @@ -1172,11 +1194,14 @@ class Environment: linkers = [self.vs_static_linker, self.clang_cl_static_linker, compiler.get_linker_exelist()] else: linkers = [self.default_static_linker, compiler.get_linker_exelist()] + elif isinstance(compiler, IntelClCCompiler): + # Intel has it's own linker that acts like microsoft's lib + linkers = ['xilib'] else: linkers = [self.default_static_linker] popen_exceptions = {} for linker in linkers: - if not set(['lib', 'lib.exe', 'llvm-lib', 'llvm-lib.exe']).isdisjoint(linker): + if not {'lib', 'lib.exe', 'llvm-lib', 'llvm-lib.exe', 'xilib', 'xilib.exe'}.isdisjoint(linker): arg = '/?' else: arg = '--version' @@ -1185,6 +1210,8 @@ class Environment: except OSError as e: popen_exceptions[' '.join(linker + [arg])] = e continue + if "xilib: executing 'lib'" in err: + return IntelVisualStudioLinker(linker, getattr(compiler, 'machine', None)) if '/OUT:' in out.upper() or '/OUT:' in err.upper(): return VisualStudioLinker(linker, getattr(compiler, 'machine', None)) if p.returncode == 0 and ('armar' in linker or 'armar.exe' in linker): diff --git a/mesonbuild/linkers.py b/mesonbuild/linkers.py index c6302bf..648d1ef 100644 --- a/mesonbuild/linkers.py +++ b/mesonbuild/linkers.py @@ -23,7 +23,7 @@ class StaticLinker: return mesonlib.is_windows() -class VisualStudioLinker(StaticLinker): +class VisualStudioLikeLinker: always_args = ['/NOLOGO'] def __init__(self, exelist, machine): @@ -31,7 +31,7 @@ class VisualStudioLinker(StaticLinker): self.machine = machine def get_exelist(self): - return self.exelist[:] + return self.exelist.copy() def get_std_link_args(self): return [] @@ -50,10 +50,10 @@ class VisualStudioLinker(StaticLinker): return [] def get_always_args(self): - return VisualStudioLinker.always_args[:] + return self.always_args.copy() def get_linker_always_args(self): - return VisualStudioLinker.always_args[:] + return self.always_args.copy() def build_rpath_args(self, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): return [] @@ -77,6 +77,16 @@ class VisualStudioLinker(StaticLinker): return [] +class VisualStudioLinker(VisualStudioLikeLinker, StaticLinker): + + """Microsoft's lib static linker.""" + + +class IntelVisualStudioLinker(VisualStudioLikeLinker, StaticLinker): + + """Intel's xilib static linker.""" + + class ArLinker(StaticLinker): def __init__(self, exelist): diff --git a/mesonbuild/modules/windows.py b/mesonbuild/modules/windows.py index 87a83fe..e2fd9a8 100644 --- a/mesonbuild/modules/windows.py +++ b/mesonbuild/modules/windows.py @@ -51,7 +51,7 @@ class WindowsModule(ExtensionModule): if not rescomp or not rescomp.found(): comp = self.detect_compiler(state.compilers) - if comp.id == 'msvc' or comp.id == 'clang-cl': + if comp.id in {'msvc', 'clang-cl', 'intel-cl'}: rescomp = ExternalProgram('rc', silent=True) else: rescomp = ExternalProgram('windres', silent=True) diff --git a/run_project_tests.py b/run_project_tests.py index b9077c9..02ceb04 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -120,7 +120,7 @@ def get_relative_files_list_from_dir(fromdir): def platform_fix_name(fname, compiler, env): # canonicalize compiler - if compiler == 'clang-cl': + if compiler in {'clang-cl', 'intel-cl'}: canonical_compiler = 'msvc' else: canonical_compiler = compiler diff --git a/run_unittests.py b/run_unittests.py index dd19fa0..f4d969c 100755 --- a/run_unittests.py +++ b/run_unittests.py @@ -981,7 +981,8 @@ class InternalTests(unittest.TestCase): toolset_ver = cc.get_toolset_version() self.assertIsNotNone(toolset_ver) # Visual Studio 2015 and older versions do not define VCToolsVersion - if int(''.join(cc.version.split('.')[0:2])) < 1910: + # TODO: ICL doesn't set this in the VSC2015 profile either + if cc.id == 'msvc' and int(''.join(cc.version.split('.')[0:2])) < 1910: return self.assertIn('VCToolsVersion', os.environ) vctools_ver = os.environ['VCToolsVersion'] @@ -1938,7 +1939,7 @@ class AllPlatformTests(BasePlatformTests): ''' gnu = mesonbuild.compilers.GnuCompiler clang = mesonbuild.compilers.ClangCompiler - intel = mesonbuild.compilers.IntelCompiler + intel = mesonbuild.compilers.IntelGnuLikeCompiler msvc = (mesonbuild.compilers.VisualStudioCCompiler, mesonbuild.compilers.VisualStudioCPPCompiler) clangcl = (mesonbuild.compilers.ClangClCCompiler, mesonbuild.compilers.ClangClCPPCompiler) ar = mesonbuild.linkers.ArLinker @@ -2821,7 +2822,7 @@ recommended as it is not supported on some platforms''') testdirlib = os.path.join(testdirbase, 'lib') extra_args = None env = get_fake_env(testdirlib, self.builddir, self.prefix) - if env.detect_c_compiler(False).get_id() not in ['msvc', 'clang-cl']: + if env.detect_c_compiler(False).get_id() not in {'msvc', 'clang-cl', 'intel-cl'}: # static libraries are not linkable with -l with msvc because meson installs them # as .a files which unix_args_to_native will not know as it expects libraries to use # .lib as extension. For a DLL the import library is installed as .lib. Thus for msvc @@ -3994,7 +3995,7 @@ class WindowsTests(BasePlatformTests): # resource compiler depfile generation is not yet implemented for msvc env = get_fake_env(testdir, self.builddir, self.prefix) - depfile_works = env.detect_c_compiler(False).get_id() not in ['msvc', 'clang-cl'] + depfile_works = env.detect_c_compiler(False).get_id() not in {'msvc', 'clang-cl', 'intel-cl'} self.init(testdir) self.build() @@ -5872,6 +5873,10 @@ class NativeFileTests(BasePlatformTests): raise unittest.SkipTest('No alternate Fortran implementation.') elif comp.id == 'gcc': if shutil.which('ifort'): + # There is an ICC for windows (windows build, linux host), + # but we don't support that ATM so lets not worry about it. + if is_windows(): + return 'ifort', 'intel-cl' return 'ifort', 'intel' elif shutil.which('flang'): return 'flang', 'flang' diff --git a/test cases/common/1 trivial/meson.build b/test cases/common/1 trivial/meson.build index 67d6ed6..c71d9b0 100644 --- a/test cases/common/1 trivial/meson.build +++ b/test cases/common/1 trivial/meson.build @@ -6,9 +6,12 @@ project('trivial test', #this is a comment sources = 'trivial.c' -if meson.get_compiler('c').get_id() == 'intel' +cc = meson.get_compiler('c') +if cc.get_id() == 'intel' # Error out if the -std=xxx option is incorrect add_project_arguments('-diag-error', '10159', language : 'c') +elif cc.get_id() == 'intel-cl' + add_project_arguments('/Qdiag-error:10159', language : 'c') endif if meson.is_cross_build() diff --git a/test cases/common/123 llvm ir and assembly/meson.build b/test cases/common/123 llvm ir and assembly/meson.build index a67c6c6..3cc7d5e 100644 --- a/test cases/common/123 llvm ir and assembly/meson.build +++ b/test cases/common/123 llvm ir and assembly/meson.build @@ -41,16 +41,17 @@ foreach lang : ['c', 'cpp'] error('MESON_SKIP_TEST: ML (masm) not found') endif # Preprocess file (ml doesn't support pre-processing) + # Force the intput to be C (/Tc) because ICL otherwise assumes it's an object (.obj) file preproc_name = lang + square_base + '.i' square_preproc = custom_target(lang + square_impl + 'preproc', input : square_impl, output : preproc_name, - command : [cl, '/EP', '/P', '/Fi' + preproc_name, '@INPUT@'] + uscore_args) + command : [cl, '/nologo', '/EP', '/P', '/Fi' + preproc_name, '/Tc', '@INPUT@'] + uscore_args) # Use assembled object file instead of the original .S assembly source square_impl = custom_target(lang + square_impl, input : square_preproc, output : lang + square_base + '.obj', - command : [ml, '/safeseh', '/Fo', '@OUTPUT@', '/c', '@INPUT@']) + command : [ml, '/nologo', '/safeseh', '/Fo', '@OUTPUT@', '/c', '@INPUT@']) endif if supported_cpus.contains(cpu) e = executable('square_asm_' + lang, square_impl, 'main.' + lang, diff --git a/test cases/common/124 cpp and asm/meson.build b/test cases/common/124 cpp and asm/meson.build index f097084..cf064d0 100644 --- a/test cases/common/124 cpp and asm/meson.build +++ b/test cases/common/124 cpp and asm/meson.build @@ -15,7 +15,7 @@ endif sources = ['trivial.cc'] # If the compiler cannot compile assembly, don't use it -if not ['msvc', 'clang-cl'].contains(meson.get_compiler('cpp').get_id()) +if not ['msvc', 'clang-cl', 'intel-cl'].contains(meson.get_compiler('cpp').get_id()) sources += ['retval-' + cpu + '.S'] cpp_args = ['-DUSE_ASM'] message('Using ASM') diff --git a/test cases/common/132 generated assembly/meson.build b/test cases/common/132 generated assembly/meson.build index 5fb7429..2837747 100644 --- a/test cases/common/132 generated assembly/meson.build +++ b/test cases/common/132 generated assembly/meson.build @@ -2,7 +2,7 @@ project('generated assembly', 'c') cc = meson.get_compiler('c') -if ['msvc', 'clang-cl'].contains(cc.get_id()) +if ['msvc', 'clang-cl', 'intel-cl'].contains(cc.get_id()) error('MESON_SKIP_TEST: assembly files cannot be compiled directly by the compiler') endif diff --git a/test cases/common/143 C and CPP link/meson.build b/test cases/common/143 C and CPP link/meson.build index 75281de..a93a981 100644 --- a/test cases/common/143 C and CPP link/meson.build +++ b/test cases/common/143 C and CPP link/meson.build @@ -30,6 +30,8 @@ if cxx.get_argument_syntax() == 'msvc' static_linker = find_program('lib') elif cxx.get_id() == 'clang-cl' static_linker = find_program('llvm-lib') + elif cxx.get_id() == 'intel-cl' + static_linker = find_program('xilib') else error('unable to determine static linker to use with this compiler') endif diff --git a/test cases/common/2 cpp/meson.build b/test cases/common/2 cpp/meson.build index 6398382..27c4321 100644 --- a/test cases/common/2 cpp/meson.build +++ b/test cases/common/2 cpp/meson.build @@ -1,8 +1,11 @@ project('c++ test', 'cpp') -if meson.get_compiler('cpp').get_id() == 'intel' +cpp = meson.get_compiler('cpp') +if cpp.get_id() == 'intel' # Error out if the -std=xxx option is incorrect add_project_arguments('-diag-error', '10159', language : 'cpp') +elif cpp.get_id() == 'intel-cl' + add_project_arguments('/Qdiag-error:10159', language : 'cpp') endif exe = executable('trivialprog', 'trivial.cc', extra_files : 'something.txt') diff --git a/test cases/common/204 function attributes/meson.build b/test cases/common/204 function attributes/meson.build index 1e93803..58ac7c8 100644 --- a/test cases/common/204 function attributes/meson.build +++ b/test cases/common/204 function attributes/meson.build @@ -19,7 +19,7 @@ project('gcc func attributes', ['c', 'cpp']) c = meson.get_compiler('c') cpp = meson.get_compiler('cpp') -expected_result = not ['msvc', 'clang-cl'].contains(c.get_id()) +expected_result = not ['msvc', 'clang-cl', 'intel-cl'].contains(c.get_id()) # Q: Why is ifunc not in this list or any of the below lists? # A: It's too damn hard to figure out if you actually support it, since it @@ -95,7 +95,7 @@ foreach a : ['dllexport', 'dllimport'] endforeach message('checking get_supported_function_attributes') -if not ['msvc', 'clang-cl'].contains(c.get_id()) +if not ['msvc', 'clang-cl', 'intel-cl'].contains(c.get_id()) multi_expected = attributes else multi_expected = [] diff --git a/test cases/common/206 argument syntax/meson.build b/test cases/common/206 argument syntax/meson.build index 216da45..b97ca74 100644 --- a/test cases/common/206 argument syntax/meson.build +++ b/test cases/common/206 argument syntax/meson.build @@ -5,16 +5,10 @@ project( cc = meson.get_compiler('c') -if ['gcc', 'lcc', 'clang'].contains(cc.get_id()) +if ['gcc', 'lcc', 'clang', 'intel'].contains(cc.get_id()) expected = 'gcc' -elif ['msvc', 'clang-cl'].contains(cc.get_id()) +elif ['msvc', 'clang-cl', 'intel-cl'].contains(cc.get_id()) expected = 'msvc' -elif cc.get_id() == 'intel' - if host_machine.system() == 'windows' - expected = 'msvc' - else - expected = 'gcc' - endif else # It's possible that other compilers end up here that shouldn't expected = 'other' diff --git a/test cases/common/40 has function/meson.build b/test cases/common/40 has function/meson.build index eb30acd..539f313 100644 --- a/test cases/common/40 has function/meson.build +++ b/test cases/common/40 has function/meson.build @@ -21,7 +21,7 @@ foreach cc : compilers # not taken from a cache (ie. the check above) # On MSVC fprintf is defined as an inline function in the header, so it cannot # be found without the include. - if cc.get_id() != 'msvc' + if not ['msvc', 'intel-cl'].contains(cc.get_id()) assert(cc.has_function('fprintf', args : unit_test_args), '"fprintf" function not found without include (on !msvc).') else diff --git a/test cases/fortran/1 basic/meson.build b/test cases/fortran/1 basic/meson.build index 042902f..959ad35 100644 --- a/test cases/fortran/1 basic/meson.build +++ b/test cases/fortran/1 basic/meson.build @@ -1,7 +1,7 @@ project('simple fortran', 'fortran') fc = meson.get_compiler('fortran') -if fc == 'gcc' +if fc.get_id() == 'gcc' add_global_arguments('-fbounds-check', language : 'fortran') endif diff --git a/test cases/fortran/14 fortran links c/clib.def b/test cases/fortran/14 fortran links c/clib.def new file mode 100644 index 0000000..4caeb24 --- /dev/null +++ b/test cases/fortran/14 fortran links c/clib.def @@ -0,0 +1,2 @@ +EXPORTS + hello diff --git a/test cases/fortran/14 fortran links c/meson.build b/test cases/fortran/14 fortran links c/meson.build index 163aec6..cd1369d 100644 --- a/test cases/fortran/14 fortran links c/meson.build +++ b/test cases/fortran/14 fortran links c/meson.build @@ -5,7 +5,7 @@ if ccid == 'msvc' or ccid == 'clang-cl' error('MESON_SKIP_TEST: MSVC and GCC do not interoperate like this.') endif -c_lib = library('clib', 'clib.c') +c_lib = library('clib', 'clib.c', vs_module_defs : 'clib.def') f_call_c = executable('f_call_c', 'f_call_c.f90', link_with: c_lib, diff --git a/test cases/fortran/9 cpp/meson.build b/test cases/fortran/9 cpp/meson.build index ad7d4b2..7f73985 100644 --- a/test cases/fortran/9 cpp/meson.build +++ b/test cases/fortran/9 cpp/meson.build @@ -7,7 +7,7 @@ if cpp.get_id() == 'clang' error('MESON_SKIP_TEST Clang C++ does not find -lgfortran for some reason.') endif -if build_machine.system() == 'windows' and cpp.get_id() != 'gnu' +if build_machine.system() == 'windows' and cpp.get_id() != fc.get_id() error('MESON_SKIP_TEST mixing gfortran with non-GNU C++ does not work.') endif |