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