1# Copyright 2012-2019 The Meson development team
2
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6
7#     http://www.apache.org/licenses/LICENSE-2.0
8
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import abc
16import contextlib, os.path, re
17import enum
18import itertools
19import typing as T
20from functools import lru_cache
21
22from .. import coredata
23from .. import mlog
24from .. import mesonlib
25from ..mesonlib import (
26    HoldableObject,
27    EnvironmentException, MachineChoice, MesonException,
28    Popen_safe, LibType, TemporaryDirectoryWinProof, OptionKey,
29)
30
31from ..arglist import CompilerArgs
32
33if T.TYPE_CHECKING:
34    from ..build import BuildTarget
35    from ..coredata import KeyedOptionDictType
36    from ..envconfig import MachineInfo
37    from ..environment import Environment
38    from ..linkers import DynamicLinker, RSPFileSyntax
39    from ..dependencies import Dependency
40
41    CompilerType = T.TypeVar('CompilerType', bound='Compiler')
42    _T = T.TypeVar('_T')
43
44"""This file contains the data files of all compilers Meson knows
45about. To support a new compiler, add its information below.
46Also add corresponding autodetection code in environment.py."""
47
48header_suffixes = ('h', 'hh', 'hpp', 'hxx', 'H', 'ipp', 'moc', 'vapi', 'di')  # type: T.Tuple[str, ...]
49obj_suffixes = ('o', 'obj', 'res')  # type: T.Tuple[str, ...]
50# To the emscripten compiler, .js files are libraries
51lib_suffixes = ('a', 'lib', 'dll', 'dll.a', 'dylib', 'so', 'js')  # type: T.Tuple[str, ...]
52# Mapping of language to suffixes of files that should always be in that language
53# This means we can't include .h headers here since they could be C, C++, ObjC, etc.
54lang_suffixes = {
55    'c': ('c',),
56    'cpp': ('cpp', 'cc', 'cxx', 'c++', 'hh', 'hpp', 'ipp', 'hxx', 'ino', 'ixx', 'C'),
57    'cuda': ('cu',),
58    # f90, f95, f03, f08 are for free-form fortran ('f90' recommended)
59    # f, for, ftn, fpp are for fixed-form fortran ('f' or 'for' recommended)
60    'fortran': ('f90', 'f95', 'f03', 'f08', 'f', 'for', 'ftn', 'fpp'),
61    'd': ('d', 'di'),
62    'objc': ('m',),
63    'objcpp': ('mm',),
64    'rust': ('rs',),
65    'vala': ('vala', 'vapi', 'gs'),
66    'cs': ('cs',),
67    'swift': ('swift',),
68    'java': ('java',),
69    'cython': ('pyx', ),
70}  # type: T.Dict[str, T.Tuple[str, ...]]
71all_languages = lang_suffixes.keys()
72cpp_suffixes = lang_suffixes['cpp'] + ('h',)  # type: T.Tuple[str, ...]
73c_suffixes = lang_suffixes['c'] + ('h',)  # type: T.Tuple[str, ...]
74# List of languages that by default consume and output libraries following the
75# C ABI; these can generally be used interchangeably
76clib_langs = ('objcpp', 'cpp', 'objc', 'c', 'fortran',)  # type: T.Tuple[str, ...]
77# List of assembler suffixes that can be linked with C code directly by the linker
78assembler_suffixes: T.Tuple[str, ...] = ('s', 'S')
79# List of languages that can be linked with C code directly by the linker
80# used in build.py:process_compilers() and build.py:get_dynamic_linker()
81clink_langs = ('d', 'cuda') + clib_langs  # type: T.Tuple[str, ...]
82clink_suffixes = tuple()  # type: T.Tuple[str, ...]
83for _l in clink_langs + ('vala',):
84    clink_suffixes += lang_suffixes[_l]
85clink_suffixes += ('h', 'll', 's')
86all_suffixes = set(itertools.chain(*lang_suffixes.values(), clink_suffixes))  # type: T.Set[str]
87SUFFIX_TO_LANG = dict(itertools.chain(*(
88    [(suffix, lang) for suffix in v] for lang, v in lang_suffixes.items()))) # type: T.Dict[str, str]
89
90# Languages that should use LDFLAGS arguments when linking.
91LANGUAGES_USING_LDFLAGS = {'objcpp', 'cpp', 'objc', 'c', 'fortran', 'd', 'cuda'}  # type: T.Set[str]
92# Languages that should use CPPFLAGS arguments when linking.
93LANGUAGES_USING_CPPFLAGS = {'c', 'cpp', 'objc', 'objcpp'}  # type: T.Set[str]
94soregex = re.compile(r'.*\.so(\.[0-9]+)?(\.[0-9]+)?(\.[0-9]+)?$')
95
96# Environment variables that each lang uses.
97CFLAGS_MAPPING: T.Mapping[str, str] = {
98    'c': 'CFLAGS',
99    'cpp': 'CXXFLAGS',
100    'cuda': 'CUFLAGS',
101    'objc': 'OBJCFLAGS',
102    'objcpp': 'OBJCXXFLAGS',
103    'fortran': 'FFLAGS',
104    'd': 'DFLAGS',
105    'vala': 'VALAFLAGS',
106    'rust': 'RUSTFLAGS',
107    'cython': 'CYTHONFLAGS',
108}
109
110CEXE_MAPPING: T.Mapping = {
111    'c': 'CC',
112    'cpp': 'CXX',
113}
114
115# All these are only for C-linkable languages; see `clink_langs` above.
116
117def sort_clink(lang: str) -> int:
118    '''
119    Sorting function to sort the list of languages according to
120    reversed(compilers.clink_langs) and append the unknown langs in the end.
121    The purpose is to prefer C over C++ for files that can be compiled by
122    both such as assembly, C, etc. Also applies to ObjC, ObjC++, etc.
123    '''
124    if lang not in clink_langs:
125        return 1
126    return -clink_langs.index(lang)
127
128def is_header(fname: 'mesonlib.FileOrString') -> bool:
129    if isinstance(fname, mesonlib.File):
130        fname = fname.fname
131    suffix = fname.split('.')[-1]
132    return suffix in header_suffixes
133
134def is_source(fname: 'mesonlib.FileOrString') -> bool:
135    if isinstance(fname, mesonlib.File):
136        fname = fname.fname
137    suffix = fname.split('.')[-1].lower()
138    return suffix in clink_suffixes
139
140def is_assembly(fname: 'mesonlib.FileOrString') -> bool:
141    if isinstance(fname, mesonlib.File):
142        fname = fname.fname
143    return fname.split('.')[-1].lower() == 's'
144
145def is_llvm_ir(fname: 'mesonlib.FileOrString') -> bool:
146    if isinstance(fname, mesonlib.File):
147        fname = fname.fname
148    return fname.split('.')[-1] == 'll'
149
150@lru_cache(maxsize=None)
151def cached_by_name(fname: 'mesonlib.FileOrString') -> bool:
152    suffix = fname.split('.')[-1]
153    return suffix in obj_suffixes
154
155def is_object(fname: 'mesonlib.FileOrString') -> bool:
156    if isinstance(fname, mesonlib.File):
157        fname = fname.fname
158    return cached_by_name(fname)
159
160def is_library(fname: 'mesonlib.FileOrString') -> bool:
161    if isinstance(fname, mesonlib.File):
162        fname = fname.fname
163
164    if soregex.match(fname):
165        return True
166
167    suffix = fname.split('.')[-1]
168    return suffix in lib_suffixes
169
170def is_known_suffix(fname: 'mesonlib.FileOrString') -> bool:
171    if isinstance(fname, mesonlib.File):
172        fname = fname.fname
173    suffix = fname.split('.')[-1]
174
175    return suffix in all_suffixes
176
177
178class CompileCheckMode(enum.Enum):
179
180    PREPROCESS = 'preprocess'
181    COMPILE = 'compile'
182    LINK = 'link'
183
184
185cuda_buildtype_args = {'plain': [],
186                       'debug': ['-g', '-G'],
187                       'debugoptimized': ['-g', '-lineinfo'],
188                       'release': [],
189                       'minsize': [],
190                       'custom': [],
191                       }  # type: T.Dict[str, T.List[str]]
192java_buildtype_args = {'plain': [],
193                       'debug': ['-g'],
194                       'debugoptimized': ['-g'],
195                       'release': [],
196                       'minsize': [],
197                       'custom': [],
198                       }  # type: T.Dict[str, T.List[str]]
199
200rust_buildtype_args = {'plain': [],
201                       'debug': [],
202                       'debugoptimized': [],
203                       'release': [],
204                       'minsize': [],
205                       'custom': [],
206                       }  # type: T.Dict[str, T.List[str]]
207
208d_gdc_buildtype_args = {'plain': [],
209                        'debug': [],
210                        'debugoptimized': ['-finline-functions'],
211                        'release': ['-finline-functions'],
212                        'minsize': [],
213                        'custom': [],
214                        }  # type: T.Dict[str, T.List[str]]
215
216d_ldc_buildtype_args = {'plain': [],
217                        'debug': [],
218                        'debugoptimized': ['-enable-inlining', '-Hkeep-all-bodies'],
219                        'release': ['-enable-inlining', '-Hkeep-all-bodies'],
220                        'minsize': [],
221                        'custom': [],
222                        }  # type: T.Dict[str, T.List[str]]
223
224d_dmd_buildtype_args = {'plain': [],
225                        'debug': [],
226                        'debugoptimized': ['-inline'],
227                        'release': ['-inline'],
228                        'minsize': [],
229                        'custom': [],
230                        }  # type: T.Dict[str, T.List[str]]
231
232mono_buildtype_args = {'plain': [],
233                       'debug': [],
234                       'debugoptimized': ['-optimize+'],
235                       'release': ['-optimize+'],
236                       'minsize': [],
237                       'custom': [],
238                       }  # type: T.Dict[str, T.List[str]]
239
240swift_buildtype_args = {'plain': [],
241                        'debug': [],
242                        'debugoptimized': [],
243                        'release': [],
244                        'minsize': [],
245                        'custom': [],
246                        }  # type: T.Dict[str, T.List[str]]
247
248gnu_winlibs = ['-lkernel32', '-luser32', '-lgdi32', '-lwinspool', '-lshell32',
249               '-lole32', '-loleaut32', '-luuid', '-lcomdlg32', '-ladvapi32']  # type: T.List[str]
250
251msvc_winlibs = ['kernel32.lib', 'user32.lib', 'gdi32.lib',
252                'winspool.lib', 'shell32.lib', 'ole32.lib', 'oleaut32.lib',
253                'uuid.lib', 'comdlg32.lib', 'advapi32.lib']  # type: T.List[str]
254
255clike_optimization_args = {'0': [],
256                           'g': [],
257                           '1': ['-O1'],
258                           '2': ['-O2'],
259                           '3': ['-O3'],
260                           's': ['-Os'],
261                           }  # type: T.Dict[str, T.List[str]]
262
263cuda_optimization_args = {'0': [],
264                          'g': ['-O0'],
265                          '1': ['-O1'],
266                          '2': ['-O2'],
267                          '3': ['-O3'],
268                          's': ['-O3']
269                          }  # type: T.Dict[str, T.List[str]]
270
271cuda_debug_args = {False: [],
272                   True: ['-g']}  # type: T.Dict[bool, T.List[str]]
273
274clike_debug_args = {False: [],
275                    True: ['-g']}  # type: T.Dict[bool, T.List[str]]
276
277base_options: 'KeyedOptionDictType' = {
278    OptionKey('b_pch'): coredata.UserBooleanOption('Use precompiled headers', True),
279    OptionKey('b_lto'): coredata.UserBooleanOption('Use link time optimization', False),
280    OptionKey('b_lto'): coredata.UserBooleanOption('Use link time optimization', False),
281    OptionKey('b_lto_threads'): coredata.UserIntegerOption('Use multiple threads for Link Time Optimization', (None, None, 0)),
282    OptionKey('b_lto_mode'): coredata.UserComboOption('Select between different LTO modes.',
283                                                      ['default', 'thin'],
284                                                      'default'),
285    OptionKey('b_sanitize'): coredata.UserComboOption('Code sanitizer to use',
286                                                      ['none', 'address', 'thread', 'undefined', 'memory', 'address,undefined'],
287                                                      'none'),
288    OptionKey('b_lundef'): coredata.UserBooleanOption('Use -Wl,--no-undefined when linking', True),
289    OptionKey('b_asneeded'): coredata.UserBooleanOption('Use -Wl,--as-needed when linking', True),
290    OptionKey('b_pgo'): coredata.UserComboOption('Use profile guided optimization',
291                                                 ['off', 'generate', 'use'],
292                                                 'off'),
293    OptionKey('b_coverage'): coredata.UserBooleanOption('Enable coverage tracking.', False),
294    OptionKey('b_colorout'): coredata.UserComboOption('Use colored output',
295                                                      ['auto', 'always', 'never'],
296                                                      'always'),
297    OptionKey('b_ndebug'): coredata.UserComboOption('Disable asserts', ['true', 'false', 'if-release'], 'false'),
298    OptionKey('b_staticpic'): coredata.UserBooleanOption('Build static libraries as position independent', True),
299    OptionKey('b_pie'): coredata.UserBooleanOption('Build executables as position independent', False),
300    OptionKey('b_bitcode'): coredata.UserBooleanOption('Generate and embed bitcode (only macOS/iOS/tvOS)', False),
301    OptionKey('b_vscrt'): coredata.UserComboOption('VS run-time library type to use.',
302                                                   ['none', 'md', 'mdd', 'mt', 'mtd', 'from_buildtype', 'static_from_buildtype'],
303                                                   'from_buildtype'),
304}
305
306def option_enabled(boptions: T.Set[OptionKey], options: 'KeyedOptionDictType',
307                   option: OptionKey) -> bool:
308    try:
309        if option not in boptions:
310            return False
311        ret = options[option].value
312        assert isinstance(ret, bool), 'must return bool'  # could also be str
313        return ret
314    except KeyError:
315        return False
316
317
318def get_option_value(options: 'KeyedOptionDictType', opt: OptionKey, fallback: '_T') -> '_T':
319    """Get the value of an option, or the fallback value."""
320    try:
321        v: '_T' = options[opt].value
322    except KeyError:
323        return fallback
324
325    assert isinstance(v, type(fallback)), f'Should have {type(fallback)!r} but was {type(v)!r}'
326    # Mypy doesn't understand that the above assert ensures that v is type _T
327    return v
328
329
330def get_base_compile_args(options: 'KeyedOptionDictType', compiler: 'Compiler') -> T.List[str]:
331    args = []  # type T.List[str]
332    try:
333        if options[OptionKey('b_lto')].value:
334            args.extend(compiler.get_lto_compile_args(
335                threads=get_option_value(options, OptionKey('b_lto_threads'), 0),
336                mode=get_option_value(options, OptionKey('b_lto_mode'), 'default')))
337    except KeyError:
338        pass
339    try:
340        args += compiler.get_colorout_args(options[OptionKey('b_colorout')].value)
341    except KeyError:
342        pass
343    try:
344        args += compiler.sanitizer_compile_args(options[OptionKey('b_sanitize')].value)
345    except KeyError:
346        pass
347    try:
348        pgo_val = options[OptionKey('b_pgo')].value
349        if pgo_val == 'generate':
350            args.extend(compiler.get_profile_generate_args())
351        elif pgo_val == 'use':
352            args.extend(compiler.get_profile_use_args())
353    except KeyError:
354        pass
355    try:
356        if options[OptionKey('b_coverage')].value:
357            args += compiler.get_coverage_args()
358    except KeyError:
359        pass
360    try:
361        if (options[OptionKey('b_ndebug')].value == 'true' or
362                (options[OptionKey('b_ndebug')].value == 'if-release' and
363                 options[OptionKey('buildtype')].value in {'release', 'plain'})):
364            args += compiler.get_disable_assert_args()
365    except KeyError:
366        pass
367    # This does not need a try...except
368    if option_enabled(compiler.base_options, options, OptionKey('b_bitcode')):
369        args.append('-fembed-bitcode')
370    try:
371        crt_val = options[OptionKey('b_vscrt')].value
372        buildtype = options[OptionKey('buildtype')].value
373        try:
374            args += compiler.get_crt_compile_args(crt_val, buildtype)
375        except AttributeError:
376            pass
377    except KeyError:
378        pass
379    return args
380
381def get_base_link_args(options: 'KeyedOptionDictType', linker: 'Compiler',
382                       is_shared_module: bool) -> T.List[str]:
383    args = []  # type: T.List[str]
384    try:
385        if options[OptionKey('b_lto')].value:
386            args.extend(linker.get_lto_link_args(
387                threads=get_option_value(options, OptionKey('b_lto_threads'), 0),
388                mode=get_option_value(options, OptionKey('b_lto_mode'), 'default')))
389    except KeyError:
390        pass
391    try:
392        args += linker.sanitizer_link_args(options[OptionKey('b_sanitize')].value)
393    except KeyError:
394        pass
395    try:
396        pgo_val = options[OptionKey('b_pgo')].value
397        if pgo_val == 'generate':
398            args.extend(linker.get_profile_generate_args())
399        elif pgo_val == 'use':
400            args.extend(linker.get_profile_use_args())
401    except KeyError:
402        pass
403    try:
404        if options[OptionKey('b_coverage')].value:
405            args += linker.get_coverage_link_args()
406    except KeyError:
407        pass
408
409    as_needed = option_enabled(linker.base_options, options, OptionKey('b_asneeded'))
410    bitcode = option_enabled(linker.base_options, options, OptionKey('b_bitcode'))
411    # Shared modules cannot be built with bitcode_bundle because
412    # -bitcode_bundle is incompatible with -undefined and -bundle
413    if bitcode and not is_shared_module:
414        args.extend(linker.bitcode_args())
415    elif as_needed:
416        # -Wl,-dead_strip_dylibs is incompatible with bitcode
417        args.extend(linker.get_asneeded_args())
418
419    # Apple's ld (the only one that supports bitcode) does not like -undefined
420    # arguments or -headerpad_max_install_names when bitcode is enabled
421    if not bitcode:
422        args.extend(linker.headerpad_args())
423        if (not is_shared_module and
424                option_enabled(linker.base_options, options, OptionKey('b_lundef'))):
425            args.extend(linker.no_undefined_link_args())
426        else:
427            args.extend(linker.get_allow_undefined_link_args())
428
429    try:
430        crt_val = options[OptionKey('b_vscrt')].value
431        buildtype = options[OptionKey('buildtype')].value
432        try:
433            args += linker.get_crt_link_args(crt_val, buildtype)
434        except AttributeError:
435            pass
436    except KeyError:
437        pass
438    return args
439
440
441class CrossNoRunException(MesonException):
442    pass
443
444class RunResult(HoldableObject):
445    def __init__(self, compiled: bool, returncode: int = 999,
446                 stdout: str = 'UNDEFINED', stderr: str = 'UNDEFINED'):
447        self.compiled = compiled
448        self.returncode = returncode
449        self.stdout = stdout
450        self.stderr = stderr
451
452
453class CompileResult(HoldableObject):
454
455    """The result of Compiler.compiles (and friends)."""
456
457    def __init__(self, stdo: T.Optional[str] = None, stde: T.Optional[str] = None,
458                 args: T.Optional[T.List[str]] = None,
459                 returncode: int = 999, pid: int = -1,
460                 text_mode: bool = True,
461                 input_name: T.Optional[str] = None,
462                 output_name: T.Optional[str] = None,
463                 command: T.Optional[T.List[str]] = None, cached: bool = False):
464        self.stdout = stdo
465        self.stderr = stde
466        self.input_name = input_name
467        self.output_name = output_name
468        self.command = command or []
469        self.args = args or []
470        self.cached = cached
471        self.returncode = returncode
472        self.pid = pid
473        self.text_mode = text_mode
474
475
476class Compiler(HoldableObject, metaclass=abc.ABCMeta):
477    # Libraries to ignore in find_library() since they are provided by the
478    # compiler or the C library. Currently only used for MSVC.
479    ignore_libs = []  # type: T.List[str]
480    # Libraries that are internal compiler implementations, and must not be
481    # manually searched.
482    internal_libs = []  # type: T.List[str]
483
484    LINKER_PREFIX = None  # type: T.Union[None, str, T.List[str]]
485    INVOKES_LINKER = True
486
487    # TODO: these could be forward declarations once we drop 3.5 support
488    if T.TYPE_CHECKING:
489        language = 'unset'
490        id = ''
491        warn_args = {}  # type: T.Dict[str, T.List[str]]
492
493    def __init__(self, exelist: T.List[str], version: str,
494                 for_machine: MachineChoice, info: 'MachineInfo',
495                 linker: T.Optional['DynamicLinker'] = None,
496                 full_version: T.Optional[str] = None, is_cross: bool = False):
497        self.exelist = exelist
498        # In case it's been overridden by a child class already
499        if not hasattr(self, 'file_suffixes'):
500            self.file_suffixes = lang_suffixes[self.language]
501        if not hasattr(self, 'can_compile_suffixes'):
502            self.can_compile_suffixes = set(self.file_suffixes)
503        self.default_suffix = self.file_suffixes[0]
504        self.version = version
505        self.full_version = full_version
506        self.for_machine = for_machine
507        self.base_options: T.Set[OptionKey] = set()
508        self.linker = linker
509        self.info = info
510        self.is_cross = is_cross
511
512    def __repr__(self) -> str:
513        repr_str = "<{0}: v{1} `{2}`>"
514        return repr_str.format(self.__class__.__name__, self.version,
515                               ' '.join(self.exelist))
516
517    @lru_cache(maxsize=None)
518    def can_compile(self, src: 'mesonlib.FileOrString') -> bool:
519        if isinstance(src, mesonlib.File):
520            src = src.fname
521        suffix = os.path.splitext(src)[1]
522        if suffix != '.C':
523            suffix = suffix.lower()
524        return bool(suffix) and suffix[1:] in self.can_compile_suffixes
525
526    def get_id(self) -> str:
527        return self.id
528
529    def get_linker_id(self) -> str:
530        # There is not guarantee that we have a dynamic linker instance, as
531        # some languages don't have separate linkers and compilers. In those
532        # cases return the compiler id
533        try:
534            return self.linker.id
535        except AttributeError:
536            return self.id
537
538    def get_version_string(self) -> str:
539        details = [self.id, self.version]
540        if self.full_version:
541            details += ['"%s"' % (self.full_version)]
542        return '(%s)' % (' '.join(details))
543
544    def get_language(self) -> str:
545        return self.language
546
547    @classmethod
548    def get_display_language(cls) -> str:
549        return cls.language.capitalize()
550
551    def get_default_suffix(self) -> str:
552        return self.default_suffix
553
554    def get_define(self, dname: str, prefix: str, env: 'Environment',
555                   extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]],
556                   dependencies: T.List['Dependency'],
557                   disable_cache: bool = False) -> T.Tuple[str, bool]:
558        raise EnvironmentException('%s does not support get_define ' % self.get_id())
559
560    def compute_int(self, expression: str, low: T.Optional[int], high: T.Optional[int],
561                    guess: T.Optional[int], prefix: str, env: 'Environment', *,
562                    extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]],
563                    dependencies: T.Optional[T.List['Dependency']]) -> int:
564        raise EnvironmentException('%s does not support compute_int ' % self.get_id())
565
566    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str],
567                                               build_dir: str) -> T.List[str]:
568        raise EnvironmentException('%s does not support compute_parameters_with_absolute_paths ' % self.get_id())
569
570    def has_members(self, typename: str, membernames: T.List[str],
571                    prefix: str, env: 'Environment', *,
572                    extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
573                    dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
574        raise EnvironmentException('%s does not support has_member(s) ' % self.get_id())
575
576    def has_type(self, typename: str, prefix: str, env: 'Environment',
577                 extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]]], *,
578                 dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
579        raise EnvironmentException('%s does not support has_type ' % self.get_id())
580
581    def symbols_have_underscore_prefix(self, env: 'Environment') -> bool:
582        raise EnvironmentException('%s does not support symbols_have_underscore_prefix ' % self.get_id())
583
584    def get_exelist(self) -> T.List[str]:
585        return self.exelist.copy()
586
587    def get_linker_exelist(self) -> T.List[str]:
588        return self.linker.get_exelist()
589
590    @abc.abstractmethod
591    def get_output_args(self, outputname: str) -> T.List[str]:
592        pass
593
594    def get_linker_output_args(self, outputname: str) -> T.List[str]:
595        return self.linker.get_output_args(outputname)
596
597    def get_linker_search_args(self, dirname: str) -> T.List[str]:
598        return self.linker.get_search_args(dirname)
599
600    def get_builtin_define(self, define: str) -> T.Optional[str]:
601        raise EnvironmentException('%s does not support get_builtin_define.' % self.id)
602
603    def has_builtin_define(self, define: str) -> bool:
604        raise EnvironmentException('%s does not support has_builtin_define.' % self.id)
605
606    def get_always_args(self) -> T.List[str]:
607        return []
608
609    def can_linker_accept_rsp(self) -> bool:
610        """
611        Determines whether the linker can accept arguments using the @rsp syntax.
612        """
613        return self.linker.get_accepts_rsp()
614
615    def get_linker_always_args(self) -> T.List[str]:
616        return self.linker.get_always_args()
617
618    def get_linker_lib_prefix(self) -> str:
619        return self.linker.get_lib_prefix()
620
621    def gen_import_library_args(self, implibname: str) -> T.List[str]:
622        """
623        Used only on Windows for libraries that need an import library.
624        This currently means C, C++, Fortran.
625        """
626        return []
627
628    def get_options(self) -> 'KeyedOptionDictType':
629        return {}
630
631    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
632        return []
633
634    def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
635        return self.linker.get_option_args(options)
636
637    def check_header(self, hname: str, prefix: str, env: 'Environment', *,
638                     extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
639                     dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
640        """Check that header is usable.
641
642        Returns a two item tuple of bools. The first bool is whether the
643        check succeeded, the second is whether the result was cached (True)
644        or run fresh (False).
645        """
646        raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language())
647
648    def has_header(self, hname: str, prefix: str, env: 'Environment', *,
649                   extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
650                   dependencies: T.Optional[T.List['Dependency']] = None,
651                   disable_cache: bool = False) -> T.Tuple[bool, bool]:
652        """Check that header is exists.
653
654        This check will return true if the file exists, even if it contains:
655
656        ```c
657        # error "You thought you could use this, LOLZ!"
658        ```
659
660        Use check_header if your header only works in some cases.
661
662        Returns a two item tuple of bools. The first bool is whether the
663        check succeeded, the second is whether the result was cached (True)
664        or run fresh (False).
665        """
666        raise EnvironmentException('Language %s does not support header checks.' % self.get_display_language())
667
668    def has_header_symbol(self, hname: str, symbol: str, prefix: str,
669                          env: 'Environment', *,
670                          extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
671                          dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
672        raise EnvironmentException('Language %s does not support header symbol checks.' % self.get_display_language())
673
674    def run(self, code: 'mesonlib.FileOrString', env: 'Environment', *,
675            extra_args: T.Union[T.List[str], T.Callable[[CompileCheckMode], T.List[str]], None] = None,
676            dependencies: T.Optional[T.List['Dependency']] = None) -> RunResult:
677        raise EnvironmentException('Language %s does not support run checks.' % self.get_display_language())
678
679    def sizeof(self, typename: str, prefix: str, env: 'Environment', *,
680               extra_args: T.Union[None, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
681               dependencies: T.Optional[T.List['Dependency']] = None) -> int:
682        raise EnvironmentException('Language %s does not support sizeof checks.' % self.get_display_language())
683
684    def alignment(self, typename: str, prefix: str, env: 'Environment', *,
685                  extra_args: T.Optional[T.List[str]] = None,
686                  dependencies: T.Optional[T.List['Dependency']] = None) -> int:
687        raise EnvironmentException('Language %s does not support alignment checks.' % self.get_display_language())
688
689    def has_function(self, funcname: str, prefix: str, env: 'Environment', *,
690                     extra_args: T.Optional[T.List[str]] = None,
691                     dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
692        """See if a function exists.
693
694        Returns a two item tuple of bools. The first bool is whether the
695        check succeeded, the second is whether the result was cached (True)
696        or run fresh (False).
697        """
698        raise EnvironmentException('Language %s does not support function checks.' % self.get_display_language())
699
700    def unix_args_to_native(self, args: T.List[str]) -> T.List[str]:
701        "Always returns a copy that can be independently mutated"
702        return args.copy()
703
704    @classmethod
705    def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]:
706        "Always returns a copy that can be independently mutated"
707        return args.copy()
708
709    def find_library(self, libname: str, env: 'Environment', extra_dirs: T.List[str],
710                     libtype: LibType = LibType.PREFER_SHARED) -> T.Optional[T.List[str]]:
711        raise EnvironmentException(f'Language {self.get_display_language()} does not support library finding.')
712
713    def get_library_naming(self, env: 'Environment', libtype: LibType,
714                           strict: bool = False) -> T.Optional[T.Tuple[str, ...]]:
715        raise EnvironmentException(
716            'Language {} does not support get_library_naming.'.format(
717                self.get_display_language()))
718
719    def get_program_dirs(self, env: 'Environment') -> T.List[str]:
720        return []
721
722    def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
723        raise EnvironmentException(
724            'Language {} does not support has_multi_arguments.'.format(
725                self.get_display_language()))
726
727    def has_multi_link_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]:
728        return self.linker.has_multi_arguments(args, env)
729
730    def _get_compile_output(self, dirname: str, mode: str) -> str:
731        # TODO: mode should really be an enum
732        # In pre-processor mode, the output is sent to stdout and discarded
733        if mode == 'preprocess':
734            return None
735        # Extension only matters if running results; '.exe' is
736        # guaranteed to be executable on every platform.
737        if mode == 'link':
738            suffix = 'exe'
739        else:
740            suffix = 'obj'
741        return os.path.join(dirname, 'output.' + suffix)
742
743    def get_compiler_args_for_mode(self, mode: CompileCheckMode) -> T.List[str]:
744        # TODO: mode should really be an enum
745        args = []  # type: T.List[str]
746        args += self.get_always_args()
747        if mode is CompileCheckMode.COMPILE:
748            args += self.get_compile_only_args()
749        elif mode is CompileCheckMode.PREPROCESS:
750            args += self.get_preprocess_only_args()
751        else:
752            assert mode is CompileCheckMode.LINK
753        return args
754
755    def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs:
756        """Return an appropriate CompilerArgs instance for this class."""
757        return CompilerArgs(self, args)
758
759    @contextlib.contextmanager
760    def compile(self, code: 'mesonlib.FileOrString',
761                extra_args: T.Union[None, CompilerArgs, T.List[str]] = None,
762                *, mode: str = 'link', want_output: bool = False,
763                temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[CompileResult]]:
764        # TODO: there isn't really any reason for this to be a contextmanager
765        if extra_args is None:
766            extra_args = []
767
768        with TemporaryDirectoryWinProof(dir=temp_dir) as tmpdirname:
769            no_ccache = False
770            if isinstance(code, str):
771                srcname = os.path.join(tmpdirname,
772                                       'testfile.' + self.default_suffix)
773                with open(srcname, 'w', encoding='utf-8') as ofile:
774                    ofile.write(code)
775                # ccache would result in a cache miss
776                no_ccache = True
777                contents = code
778            else:
779                srcname = code.fname
780                if not is_object(code.fname):
781                    with open(code.fname, encoding='utf-8') as f:
782                        contents = f.read()
783                else:
784                    contents = '<binary>'
785
786            # Construct the compiler command-line
787            commands = self.compiler_args()
788            commands.append(srcname)
789
790            # Preprocess mode outputs to stdout, so no output args
791            output = self._get_compile_output(tmpdirname, mode)
792            if mode != 'preprocess':
793                commands += self.get_output_args(output)
794            commands.extend(self.get_compiler_args_for_mode(CompileCheckMode(mode)))
795
796            # extra_args must be last because it could contain '/link' to
797            # pass args to VisualStudio's linker. In that case everything
798            # in the command line after '/link' is given to the linker.
799            if extra_args:
800                commands += extra_args
801            # Generate full command-line with the exelist
802            command_list = self.get_exelist() + commands.to_native()
803            mlog.debug('Running compile:')
804            mlog.debug('Working directory: ', tmpdirname)
805            mlog.debug('Command line: ', ' '.join(command_list), '\n')
806            mlog.debug('Code:\n', contents)
807            os_env = os.environ.copy()
808            os_env['LC_ALL'] = 'C'
809            if no_ccache:
810                os_env['CCACHE_DISABLE'] = '1'
811            p, stdo, stde = Popen_safe(command_list, cwd=tmpdirname, env=os_env)
812            mlog.debug('Compiler stdout:\n', stdo)
813            mlog.debug('Compiler stderr:\n', stde)
814
815            result = CompileResult(stdo, stde, list(commands), p.returncode, p.pid, input_name=srcname)
816            if want_output:
817                result.output_name = output
818            yield result
819
820    @contextlib.contextmanager
821    def cached_compile(self, code: 'mesonlib.FileOrString', cdata: coredata.CoreData, *,
822                       extra_args: T.Union[None, T.List[str], CompilerArgs] = None,
823                       mode: str = 'link',
824                       temp_dir: T.Optional[str] = None) -> T.Iterator[T.Optional[CompileResult]]:
825        # TODO: There's isn't really any reason for this to be a context manager
826
827        # Calculate the key
828        textra_args = tuple(extra_args) if extra_args is not None else tuple()  # type: T.Tuple[str, ...]
829        key = (tuple(self.exelist), self.version, code, textra_args, mode)  # type: coredata.CompilerCheckCacheKey
830
831        # Check if not cached, and generate, otherwise get from the cache
832        if key in cdata.compiler_check_cache:
833            p = cdata.compiler_check_cache[key]  # type: CompileResult
834            p.cached = True
835            mlog.debug('Using cached compile:')
836            mlog.debug('Cached command line: ', ' '.join(p.command), '\n')
837            mlog.debug('Code:\n', code)
838            mlog.debug('Cached compiler stdout:\n', p.stdout)
839            mlog.debug('Cached compiler stderr:\n', p.stderr)
840            yield p
841        else:
842            with self.compile(code, extra_args=extra_args, mode=mode, want_output=False, temp_dir=temp_dir) as p:
843                cdata.compiler_check_cache[key] = p
844                yield p
845
846    def get_colorout_args(self, colortype: str) -> T.List[str]:
847        # TODO: colortype can probably be an emum
848        return []
849
850    # Some compilers (msvc) write debug info to a separate file.
851    # These args specify where it should be written.
852    def get_compile_debugfile_args(self, rel_obj: str, pch: bool = False) -> T.List[str]:
853        return []
854
855    def get_link_debugfile_name(self, targetfile: str) -> str:
856        return self.linker.get_debugfile_name(targetfile)
857
858    def get_link_debugfile_args(self, targetfile: str) -> T.List[str]:
859        return self.linker.get_debugfile_args(targetfile)
860
861    def get_std_shared_lib_link_args(self) -> T.List[str]:
862        return self.linker.get_std_shared_lib_args()
863
864    def get_std_shared_module_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
865        return self.linker.get_std_shared_module_args(options)
866
867    def get_link_whole_for(self, args: T.List[str]) -> T.List[str]:
868        return self.linker.get_link_whole_for(args)
869
870    def get_allow_undefined_link_args(self) -> T.List[str]:
871        return self.linker.get_allow_undefined_args()
872
873    def no_undefined_link_args(self) -> T.List[str]:
874        return self.linker.no_undefined_args()
875
876    def get_instruction_set_args(self, instruction_set: str) -> T.Optional[T.List[str]]:
877        """Compiler arguments needed to enable the given instruction set.
878
879        Return type ay be an empty list meaning nothing needed or None
880        meaning the given set is not supported.
881        """
882        return None
883
884    def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str,
885                         rpath_paths: str, build_rpath: str,
886                         install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]:
887        return self.linker.build_rpath_args(
888            env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath)
889
890    def thread_flags(self, env: 'Environment') -> T.List[str]:
891        return []
892
893    def thread_link_flags(self, env: 'Environment') -> T.List[str]:
894        return self.linker.thread_flags(env)
895
896    def openmp_flags(self) -> T.List[str]:
897        raise EnvironmentException('Language %s does not support OpenMP flags.' % self.get_display_language())
898
899    def openmp_link_flags(self) -> T.List[str]:
900        return self.openmp_flags()
901
902    def language_stdlib_only_link_flags(self, env: 'Environment') -> T.List[str]:
903        return []
904
905    def gnu_symbol_visibility_args(self, vistype: str) -> T.List[str]:
906        return []
907
908    def get_gui_app_args(self, value: bool) -> T.List[str]:
909        # Only used on Windows
910        return self.linker.get_gui_app_args(value)
911
912    def get_win_subsystem_args(self, value: str) -> T.List[str]:
913        # By default the dynamic linker is going to return an empty
914        # array in case it either doesn't support Windows subsystems
915        # or does not target Windows
916        return self.linker.get_win_subsystem_args(value)
917
918    def has_func_attribute(self, name: str, env: 'Environment') -> T.Tuple[bool, bool]:
919        raise EnvironmentException(
920            f'Language {self.get_display_language()} does not support function attributes.')
921
922    def get_pic_args(self) -> T.List[str]:
923        m = 'Language {} does not support position-independent code'
924        raise EnvironmentException(m.format(self.get_display_language()))
925
926    def get_pie_args(self) -> T.List[str]:
927        m = 'Language {} does not support position-independent executable'
928        raise EnvironmentException(m.format(self.get_display_language()))
929
930    def get_pie_link_args(self) -> T.List[str]:
931        return self.linker.get_pie_args()
932
933    def get_argument_syntax(self) -> str:
934        """Returns the argument family type.
935
936        Compilers fall into families if they try to emulate the command line
937        interface of another compiler. For example, clang is in the GCC family
938        since it accepts most of the same arguments as GCC. ICL (ICC on
939        windows) is in the MSVC family since it accepts most of the same
940        arguments as MSVC.
941        """
942        return 'other'
943
944    def get_profile_generate_args(self) -> T.List[str]:
945        raise EnvironmentException(
946            '%s does not support get_profile_generate_args ' % self.get_id())
947
948    def get_profile_use_args(self) -> T.List[str]:
949        raise EnvironmentException(
950            '%s does not support get_profile_use_args ' % self.get_id())
951
952    def remove_linkerlike_args(self, args: T.List[str]) -> T.List[str]:
953        rm_exact = ('-headerpad_max_install_names',)
954        rm_prefixes = ('-Wl,', '-L',)
955        rm_next = ('-L', '-framework',)
956        ret = []  # T.List[str]
957        iargs = iter(args)
958        for arg in iargs:
959            # Remove this argument
960            if arg in rm_exact:
961                continue
962            # If the argument starts with this, but is not *exactly* this
963            # f.ex., '-L' should match ['-Lfoo'] but not ['-L', 'foo']
964            if arg.startswith(rm_prefixes) and arg not in rm_prefixes:
965                continue
966            # Ignore this argument and the one after it
967            if arg in rm_next:
968                next(iargs)
969                continue
970            ret.append(arg)
971        return ret
972
973    def get_lto_compile_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
974        return []
975
976    def get_lto_link_args(self, *, threads: int = 0, mode: str = 'default') -> T.List[str]:
977        return self.linker.get_lto_args()
978
979    def sanitizer_compile_args(self, value: str) -> T.List[str]:
980        return []
981
982    def sanitizer_link_args(self, value: str) -> T.List[str]:
983        return self.linker.sanitizer_args(value)
984
985    def get_asneeded_args(self) -> T.List[str]:
986        return self.linker.get_asneeded_args()
987
988    def headerpad_args(self) -> T.List[str]:
989        return self.linker.headerpad_args()
990
991    def bitcode_args(self) -> T.List[str]:
992        return self.linker.bitcode_args()
993
994    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
995        raise EnvironmentException(f'{self.id} does not implement get_buildtype_args')
996
997    def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]:
998        return self.linker.get_buildtype_args(buildtype)
999
1000    def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str,
1001                        suffix: str, soversion: str,
1002                        darwin_versions: T.Tuple[str, str]) -> T.List[str]:
1003        return self.linker.get_soname_args(
1004            env, prefix, shlib_name, suffix, soversion,
1005            darwin_versions)
1006
1007    def get_target_link_args(self, target: 'BuildTarget') -> T.List[str]:
1008        return target.link_args
1009
1010    def get_dependency_compile_args(self, dep: 'Dependency') -> T.List[str]:
1011        return dep.get_compile_args()
1012
1013    def get_dependency_link_args(self, dep: 'Dependency') -> T.List[str]:
1014        return dep.get_link_args()
1015
1016    @classmethod
1017    def use_linker_args(cls, linker: str) -> T.List[str]:
1018        """Get a list of arguments to pass to the compiler to set the linker.
1019        """
1020        return []
1021
1022    def get_coverage_args(self) -> T.List[str]:
1023        return []
1024
1025    def get_coverage_link_args(self) -> T.List[str]:
1026        return self.linker.get_coverage_args()
1027
1028    def get_disable_assert_args(self) -> T.List[str]:
1029        return []
1030
1031    def get_crt_compile_args(self, crt_val: str, buildtype: str) -> T.List[str]:
1032        raise EnvironmentException('This compiler does not support Windows CRT selection')
1033
1034    def get_crt_link_args(self, crt_val: str, buildtype: str) -> T.List[str]:
1035        raise EnvironmentException('This compiler does not support Windows CRT selection')
1036
1037    def get_compile_only_args(self) -> T.List[str]:
1038        return []
1039
1040    def get_preprocess_only_args(self) -> T.List[str]:
1041        raise EnvironmentException('This compiler does not have a preprocessor')
1042
1043    def get_default_include_dirs(self) -> T.List[str]:
1044        # TODO: This is a candidate for returning an immutable list
1045        return []
1046
1047    def get_largefile_args(self) -> T.List[str]:
1048        '''Enable transparent large-file-support for 32-bit UNIX systems'''
1049        if not (self.get_argument_syntax() == 'msvc' or self.info.is_darwin()):
1050            # Enable large-file support unconditionally on all platforms other
1051            # than macOS and MSVC. macOS is now 64-bit-only so it doesn't
1052            # need anything special, and MSVC doesn't have automatic LFS.
1053            # You must use the 64-bit counterparts explicitly.
1054            # glibc, musl, and uclibc, and all BSD libcs support this. On Android,
1055            # support for transparent LFS is available depending on the version of
1056            # Bionic: https://github.com/android/platform_bionic#32-bit-abi-bugs
1057            # https://code.google.com/p/android/issues/detail?id=64613
1058            #
1059            # If this breaks your code, fix it! It's been 20+ years!
1060            return ['-D_FILE_OFFSET_BITS=64']
1061            # We don't enable -D_LARGEFILE64_SOURCE since that enables
1062            # transitionary features and must be enabled by programs that use
1063            # those features explicitly.
1064        return []
1065
1066    def get_library_dirs(self, env: 'Environment',
1067                         elf_class: T.Optional[int] = None) -> T.List[str]:
1068        return []
1069
1070    def get_return_value(self,
1071                         fname: str,
1072                         rtype: str,
1073                         prefix: str,
1074                         env: 'Environment',
1075                         extra_args: T.Optional[T.List[str]],
1076                         dependencies: T.Optional[T.List['Dependency']]) -> T.Union[str, int]:
1077        raise EnvironmentException(f'{self.id} does not support get_return_value')
1078
1079    def find_framework(self,
1080                       name: str,
1081                       env: 'Environment',
1082                       extra_dirs: T.List[str],
1083                       allow_system: bool = True) -> T.Optional[T.List[str]]:
1084        raise EnvironmentException(f'{self.id} does not support find_framework')
1085
1086    def find_framework_paths(self, env: 'Environment') -> T.List[str]:
1087        raise EnvironmentException(f'{self.id} does not support find_framework_paths')
1088
1089    def attribute_check_func(self, name: str) -> str:
1090        raise EnvironmentException(f'{self.id} does not support attribute checks')
1091
1092    def get_pch_suffix(self) -> str:
1093        raise EnvironmentException(f'{self.id} does not support pre compiled headers')
1094
1095    def get_pch_name(self, name: str) -> str:
1096        raise EnvironmentException(f'{self.id} does not support pre compiled headers')
1097
1098    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
1099        raise EnvironmentException(f'{self.id} does not support pre compiled headers')
1100
1101    def get_has_func_attribute_extra_args(self, name: str) -> T.List[str]:
1102        raise EnvironmentException(f'{self.id} does not support function attributes')
1103
1104    def name_string(self) -> str:
1105        return ' '.join(self.exelist)
1106
1107    @abc.abstractmethod
1108    def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
1109        """Check that this compiler actually works.
1110
1111        This should provide a simple compile/link test. Something as simple as:
1112        ```python
1113        main(): return 0
1114        ```
1115        is good enough here.
1116        """
1117
1118    def split_shlib_to_parts(self, fname: str) -> T.Tuple[T.Optional[str], str]:
1119        return None, fname
1120
1121    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
1122        return []
1123
1124    def get_std_exe_link_args(self) -> T.List[str]:
1125        # TODO: is this a linker property?
1126        return []
1127
1128    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
1129        return []
1130
1131    def depfile_for_object(self, objfile: str) -> str:
1132        return objfile + '.' + self.get_depfile_suffix()
1133
1134    def get_depfile_suffix(self) -> str:
1135        raise EnvironmentException(f'{self.id} does not implement get_depfile_suffix')
1136
1137    def get_no_stdinc_args(self) -> T.List[str]:
1138        """Arguments to turn off default inclusion of standard libraries."""
1139        return []
1140
1141    def get_warn_args(self, level: str) -> T.List[str]:
1142        return []
1143
1144    def get_werror_args(self) -> T.List[str]:
1145        return []
1146
1147    @abc.abstractmethod
1148    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
1149        pass
1150
1151    def get_module_incdir_args(self) -> T.Tuple[str, ...]:
1152        raise EnvironmentException(f'{self.id} does not implement get_module_incdir_args')
1153
1154    def get_module_outdir_args(self, path: str) -> T.List[str]:
1155        raise EnvironmentException(f'{self.id} does not implement get_module_outdir_args')
1156
1157    def module_name_to_filename(self, module_name: str) -> str:
1158        raise EnvironmentException(f'{self.id} does not implement module_name_to_filename')
1159
1160    def get_compiler_check_args(self, mode: CompileCheckMode) -> T.List[str]:
1161        """Arguments to pass the compiler and/or linker for checks.
1162
1163        The default implementation turns off optimizations.
1164
1165        Examples of things that go here:
1166          - extra arguments for error checking
1167          - Arguments required to make the compiler exit with a non-zero status
1168            when something is wrong.
1169        """
1170        return self.get_no_optimization_args()
1171
1172    def get_no_optimization_args(self) -> T.List[str]:
1173        """Arguments to the compiler to turn off all optimizations."""
1174        return []
1175
1176    def build_wrapper_args(self, env: 'Environment',
1177                           extra_args: T.Union[None, CompilerArgs, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]],
1178                           dependencies: T.Optional[T.List['Dependency']],
1179                           mode: CompileCheckMode = CompileCheckMode.COMPILE) -> CompilerArgs:
1180        """Arguments to pass the build_wrapper helper.
1181
1182        This generally needs to be set on a per-language baises. It provides
1183        a hook for languages to handle dependencies and extra args. The base
1184        implementation handles the most common cases, namely adding the
1185        check_arguments, unwrapping dependencies, and appending extra args.
1186        """
1187        if callable(extra_args):
1188            extra_args = extra_args(mode)
1189        if extra_args is None:
1190            extra_args = []
1191        if dependencies is None:
1192            dependencies = []
1193
1194        # Collect compiler arguments
1195        args = self.compiler_args(self.get_compiler_check_args(mode))
1196        for d in dependencies:
1197            # Add compile flags needed by dependencies
1198            args += d.get_compile_args()
1199            if mode is CompileCheckMode.LINK:
1200                # Add link flags needed to find dependencies
1201                args += d.get_link_args()
1202
1203        if mode is CompileCheckMode.COMPILE:
1204            # Add DFLAGS from the env
1205            args += env.coredata.get_external_args(self.for_machine, self.language)
1206        elif mode is CompileCheckMode.LINK:
1207            # Add LDFLAGS from the env
1208            args += env.coredata.get_external_link_args(self.for_machine, self.language)
1209        # extra_args must override all other arguments, so we add them last
1210        args += extra_args
1211        return args
1212
1213    @contextlib.contextmanager
1214    def _build_wrapper(self, code: 'mesonlib.FileOrString', env: 'Environment',
1215                       extra_args: T.Union[None, CompilerArgs, T.List[str], T.Callable[[CompileCheckMode], T.List[str]]] = None,
1216                       dependencies: T.Optional[T.List['Dependency']] = None,
1217                       mode: str = 'compile', want_output: bool = False,
1218                       disable_cache: bool = False,
1219                       temp_dir: str = None) -> T.Iterator[T.Optional[CompileResult]]:
1220        """Helper for getting a cacched value when possible.
1221
1222        This method isn't meant to be called externally, it's mean to be
1223        wrapped by other methods like compiles() and links().
1224        """
1225        args = self.build_wrapper_args(env, extra_args, dependencies, CompileCheckMode(mode))
1226        if disable_cache or want_output:
1227            with self.compile(code, extra_args=args, mode=mode, want_output=want_output, temp_dir=env.scratch_dir) as r:
1228                yield r
1229        else:
1230            with self.cached_compile(code, env.coredata, extra_args=args, mode=mode, temp_dir=env.scratch_dir) as r:
1231                yield r
1232
1233    def compiles(self, code: 'mesonlib.FileOrString', env: 'Environment', *,
1234                extra_args: T.Union[None, T.List[str], CompilerArgs, T.Callable[[CompileCheckMode], T.List[str]]] = None,
1235                 dependencies: T.Optional[T.List['Dependency']] = None,
1236                 mode: str = 'compile',
1237                 disable_cache: bool = False) -> T.Tuple[bool, bool]:
1238        with self._build_wrapper(code, env, extra_args, dependencies, mode, disable_cache=disable_cache) as p:
1239            return p.returncode == 0, p.cached
1240
1241    def links(self, code: 'mesonlib.FileOrString', env: 'Environment', *,
1242              compiler: T.Optional['Compiler'] = None,
1243              extra_args: T.Union[None, T.List[str], CompilerArgs, T.Callable[[CompileCheckMode], T.List[str]]] = None,
1244              dependencies: T.Optional[T.List['Dependency']] = None,
1245              mode: str = 'compile',
1246              disable_cache: bool = False) -> T.Tuple[bool, bool]:
1247        if compiler:
1248            with compiler._build_wrapper(code, env, dependencies=dependencies, want_output=True) as r:
1249                objfile = mesonlib.File.from_absolute_file(r.output_name)
1250                return self.compiles(objfile, env, extra_args=extra_args,
1251                                     dependencies=dependencies, mode='link', disable_cache=True)
1252
1253        return self.compiles(code, env, extra_args=extra_args,
1254                             dependencies=dependencies, mode='link', disable_cache=disable_cache)
1255
1256    def get_feature_args(self, kwargs: T.Dict[str, T.Any], build_to_src: str) -> T.List[str]:
1257        """Used by D for extra language features."""
1258        # TODO: using a TypeDict here would improve this
1259        raise EnvironmentException(f'{self.id} does not implement get_feature_args')
1260
1261    def get_prelink_args(self, prelink_name: str, obj_list: T.List[str]) -> T.List[str]:
1262        raise EnvironmentException(f'{self.id} does not know how to do prelinking.')
1263
1264    def rsp_file_syntax(self) -> 'RSPFileSyntax':
1265        """The format of the RSP file that this compiler supports.
1266
1267        If `self.can_linker_accept_rsp()` returns True, then this needs to
1268        be implemented
1269        """
1270        return self.linker.rsp_file_syntax()
1271
1272    def get_debug_args(self, is_debug: bool) -> T.List[str]:
1273        """Arguments required for a debug build."""
1274        return []
1275
1276    def get_no_warn_args(self) -> T.List[str]:
1277        """Arguments to completely disable warnings."""
1278        return []
1279
1280
1281def get_global_options(lang: str,
1282                       comp: T.Type[Compiler],
1283                       for_machine: MachineChoice,
1284                       env: 'Environment') -> 'KeyedOptionDictType':
1285    """Retrieve options that apply to all compilers for a given language."""
1286    description = f'Extra arguments passed to the {lang}'
1287    argkey = OptionKey('args', lang=lang, machine=for_machine)
1288    largkey = argkey.evolve('link_args')
1289    envkey = argkey.evolve('env_args')
1290
1291    comp_key = argkey if argkey in env.options else envkey
1292
1293    comp_options = env.options.get(comp_key, [])
1294    link_options = env.options.get(largkey, [])
1295
1296    cargs = coredata.UserArrayOption(
1297        description + ' compiler',
1298        comp_options, split_args=True, user_input=True, allow_dups=True)
1299
1300    largs = coredata.UserArrayOption(
1301        description + ' linker',
1302        link_options, split_args=True, user_input=True, allow_dups=True)
1303
1304    if comp.INVOKES_LINKER and comp_key == envkey:
1305        # If the compiler acts as a linker driver, and we're using the
1306        # environment variable flags for both the compiler and linker
1307        # arguments, then put the compiler flags in the linker flags as well.
1308        # This is how autotools works, and the env vars freature is for
1309        # autotools compatibility.
1310        largs.extend_value(comp_options)
1311
1312    opts: 'KeyedOptionDictType' = {argkey: cargs, largkey: largs}
1313
1314    return opts
1315