1# Copyright 2012-2020 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 os.path
16import typing as T
17
18from .. import coredata
19from .. import mlog
20from ..mesonlib import MachineChoice, MesonException, version_compare, OptionKey
21from .c_function_attributes import C_FUNC_ATTRIBUTES
22from .mixins.clike import CLikeCompiler
23from .mixins.ccrx import CcrxCompiler
24from .mixins.xc16 import Xc16Compiler
25from .mixins.compcert import CompCertCompiler
26from .mixins.c2000 import C2000Compiler
27from .mixins.arm import ArmCompiler, ArmclangCompiler
28from .mixins.visualstudio import MSVCCompiler, ClangClCompiler
29from .mixins.gnu import GnuCompiler
30from .mixins.intel import IntelGnuLikeCompiler, IntelVisualStudioLikeCompiler
31from .mixins.clang import ClangCompiler
32from .mixins.elbrus import ElbrusCompiler
33from .mixins.pgi import PGICompiler
34from .mixins.emscripten import EmscriptenMixin
35from .compilers import (
36    gnu_winlibs,
37    msvc_winlibs,
38    Compiler,
39)
40
41if T.TYPE_CHECKING:
42    from ..coredata import KeyedOptionDictType
43    from ..dependencies import Dependency
44    from ..envconfig import MachineInfo
45    from ..environment import Environment
46    from ..linkers import DynamicLinker
47    from ..programs import ExternalProgram
48    from .compilers import CompileCheckMode
49
50    CompilerMixinBase = Compiler
51else:
52    CompilerMixinBase = object
53
54
55class CCompiler(CLikeCompiler, Compiler):
56
57    @staticmethod
58    def attribute_check_func(name: str) -> str:
59        try:
60            return C_FUNC_ATTRIBUTES[name]
61        except KeyError:
62            raise MesonException(f'Unknown function attribute "{name}"')
63
64    language = 'c'
65
66    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
67                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
68                 linker: T.Optional['DynamicLinker'] = None,
69                 full_version: T.Optional[str] = None):
70        # If a child ObjC or CPP class has already set it, don't set it ourselves
71        Compiler.__init__(self, exelist, version, for_machine, info,
72                          is_cross=is_cross, full_version=full_version, linker=linker)
73        CLikeCompiler.__init__(self, exe_wrapper)
74
75    def get_no_stdinc_args(self) -> T.List[str]:
76        return ['-nostdinc']
77
78    def sanity_check(self, work_dir: str, environment: 'Environment') -> None:
79        code = 'int main(void) { int class=0; return class; }\n'
80        return self._sanity_check_impl(work_dir, environment, 'sanitycheckc.c', code)
81
82    def has_header_symbol(self, hname: str, symbol: str, prefix: str,
83                          env: 'Environment', *,
84                          extra_args: T.Union[None, T.List[str], T.Callable[['CompileCheckMode'], T.List[str]]] = None,
85                          dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
86        fargs = {'prefix': prefix, 'header': hname, 'symbol': symbol}
87        t = '''{prefix}
88        #include <{header}>
89        int main(void) {{
90            /* If it's not defined as a macro, try to use as a symbol */
91            #ifndef {symbol}
92                {symbol};
93            #endif
94            return 0;
95        }}'''
96        return self.compiles(t.format(**fargs), env, extra_args=extra_args,
97                             dependencies=dependencies)
98
99    def get_options(self) -> 'KeyedOptionDictType':
100        opts = super().get_options()
101        opts.update({
102            OptionKey('std', machine=self.for_machine, lang=self.language): coredata.UserComboOption(
103                'C language standard to use',
104                ['none'],
105                'none',
106            )
107        })
108        return opts
109
110
111class _ClangCStds(CompilerMixinBase):
112
113    """Mixin class for clang based compilers for setting C standards.
114
115    This is used by both ClangCCompiler and ClangClCompiler, as they share
116    the same versions
117    """
118
119    _C17_VERSION = '>=6.0.0'
120    _C18_VERSION = '>=8.0.0'
121    _C2X_VERSION = '>=9.0.0'
122
123    def get_options(self) -> 'KeyedOptionDictType':
124        opts = super().get_options()
125        c_stds = ['c89', 'c99', 'c11']
126        g_stds = ['gnu89', 'gnu99', 'gnu11']
127        # https://releases.llvm.org/6.0.0/tools/clang/docs/ReleaseNotes.html
128        # https://en.wikipedia.org/wiki/Xcode#Latest_versions
129        if version_compare(self.version, self._C17_VERSION):
130            c_stds += ['c17']
131            g_stds += ['gnu17']
132        if version_compare(self.version, self._C18_VERSION):
133            c_stds += ['c18']
134            g_stds += ['gnu18']
135        if version_compare(self.version, self._C2X_VERSION):
136            c_stds += ['c2x']
137            g_stds += ['gnu2x']
138        opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds + g_stds
139        return opts
140
141
142class ClangCCompiler(_ClangCStds, ClangCompiler, CCompiler):
143
144    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
145                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
146                 linker: T.Optional['DynamicLinker'] = None,
147                 defines: T.Optional[T.Dict[str, str]] = None,
148                 full_version: T.Optional[str] = None):
149        CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version)
150        ClangCompiler.__init__(self, defines)
151        default_warn_args = ['-Wall', '-Winvalid-pch']
152        self.warn_args = {'0': [],
153                          '1': default_warn_args,
154                          '2': default_warn_args + ['-Wextra'],
155                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}
156
157    def get_options(self) -> 'KeyedOptionDictType':
158        opts = super().get_options()
159        if self.info.is_windows() or self.info.is_cygwin():
160            opts.update({
161                OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption(
162                    'Standard Win libraries to link against',
163                    gnu_winlibs,
164                ),
165            })
166        return opts
167
168    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
169        args = []
170        std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
171        if std.value != 'none':
172            args.append('-std=' + std.value)
173        return args
174
175    def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
176        if self.info.is_windows() or self.info.is_cygwin():
177            # without a typedict mypy can't understand this.
178            libs = options[OptionKey('winlibs', machine=self.for_machine, lang=self.language)].value.copy()
179            assert isinstance(libs, list)
180            for l in libs:
181                assert isinstance(l, str)
182            return libs
183        return []
184
185
186class AppleClangCCompiler(ClangCCompiler):
187
188    """Handle the differences between Apple Clang and Vanilla Clang.
189
190    Right now this just handles the differences between the versions that new
191    C standards were added.
192    """
193
194    _C17_VERSION = '>=10.0.0'
195    _C18_VERSION = '>=11.0.0'
196    _C2X_VERSION = '>=11.0.0'
197
198
199class EmscriptenCCompiler(EmscriptenMixin, ClangCCompiler):
200    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
201                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
202                 linker: T.Optional['DynamicLinker'] = None,
203                 defines: T.Optional[T.Dict[str, str]] = None,
204                 full_version: T.Optional[str] = None):
205        if not is_cross:
206            raise MesonException('Emscripten compiler can only be used for cross compilation.')
207        ClangCCompiler.__init__(self, exelist, version, for_machine, is_cross,
208                                info, exe_wrapper=exe_wrapper, linker=linker,
209                                defines=defines, full_version=full_version)
210        self.id = 'emscripten'
211
212
213class ArmclangCCompiler(ArmclangCompiler, CCompiler):
214    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
215                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
216                 linker: T.Optional['DynamicLinker'] = None,
217                 full_version: T.Optional[str] = None):
218        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
219                           info, exe_wrapper, linker=linker, full_version=full_version)
220        ArmclangCompiler.__init__(self)
221        default_warn_args = ['-Wall', '-Winvalid-pch']
222        self.warn_args = {'0': [],
223                          '1': default_warn_args,
224                          '2': default_warn_args + ['-Wextra'],
225                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}
226
227    def get_options(self) -> 'KeyedOptionDictType':
228        opts = CCompiler.get_options(self)
229        key = OptionKey('std', machine=self.for_machine, lang=self.language)
230        opts[key].choices = ['none', 'c90', 'c99', 'c11', 'gnu90', 'gnu99', 'gnu11']
231        return opts
232
233    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
234        args = []
235        std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
236        if std.value != 'none':
237            args.append('-std=' + std.value)
238        return args
239
240    def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
241        return []
242
243
244class GnuCCompiler(GnuCompiler, CCompiler):
245
246    _C18_VERSION = '>=8.0.0'
247    _C2X_VERSION = '>=9.0.0'
248    _INVALID_PCH_VERSION = ">=3.4.0"
249
250    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
251                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
252                 linker: T.Optional['DynamicLinker'] = None,
253                 defines: T.Optional[T.Dict[str, str]] = None,
254                 full_version: T.Optional[str] = None):
255        CCompiler.__init__(self, exelist, version, for_machine, is_cross, info, exe_wrapper, linker=linker, full_version=full_version)
256        GnuCompiler.__init__(self, defines)
257        default_warn_args = ['-Wall']
258        if version_compare(self.version, self._INVALID_PCH_VERSION):
259            default_warn_args += ['-Winvalid-pch']
260        self.warn_args = {'0': [],
261                          '1': default_warn_args,
262                          '2': default_warn_args + ['-Wextra'],
263                          '3': default_warn_args + ['-Wextra', '-Wpedantic']}
264
265    def get_options(self) -> 'KeyedOptionDictType':
266        opts = CCompiler.get_options(self)
267        c_stds = ['c89', 'c99', 'c11']
268        g_stds = ['gnu89', 'gnu99', 'gnu11']
269        if version_compare(self.version, self._C18_VERSION):
270            c_stds += ['c17', 'c18']
271            g_stds += ['gnu17', 'gnu18']
272        if version_compare(self.version, self._C2X_VERSION):
273            c_stds += ['c2x']
274            g_stds += ['gnu2x']
275        key = OptionKey('std', machine=self.for_machine, lang=self.language)
276        opts[key].choices = ['none'] + c_stds + g_stds
277        if self.info.is_windows() or self.info.is_cygwin():
278            opts.update({
279                key.evolve('winlibs'): coredata.UserArrayOption(
280                    'Standard Win libraries to link against',
281                    gnu_winlibs,
282                ),
283            })
284        return opts
285
286    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
287        args = []
288        std = options[OptionKey('std', lang=self.language, machine=self.for_machine)]
289        if std.value != 'none':
290            args.append('-std=' + std.value)
291        return args
292
293    def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
294        if self.info.is_windows() or self.info.is_cygwin():
295            # without a typeddict mypy can't figure this out
296            libs: T.List[str] = options[OptionKey('winlibs', lang=self.language, machine=self.for_machine)].value.copy()
297            assert isinstance(libs, list)
298            for l in libs:
299                assert isinstance(l, str)
300            return libs
301        return []
302
303    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
304        return ['-fpch-preprocess', '-include', os.path.basename(header)]
305
306
307class PGICCompiler(PGICompiler, CCompiler):
308    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
309                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
310                 linker: T.Optional['DynamicLinker'] = None,
311                 full_version: T.Optional[str] = None):
312        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
313                           info, exe_wrapper, linker=linker, full_version=full_version)
314        PGICompiler.__init__(self)
315
316
317class NvidiaHPC_CCompiler(PGICompiler, CCompiler):
318    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
319                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
320                 linker: T.Optional['DynamicLinker'] = None,
321                 full_version: T.Optional[str] = None):
322        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
323                           info, exe_wrapper, linker=linker, full_version=full_version)
324        PGICompiler.__init__(self)
325        self.id = 'nvidia_hpc'
326
327
328class ElbrusCCompiler(ElbrusCompiler, CCompiler):
329    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
330                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
331                 linker: T.Optional['DynamicLinker'] = None,
332                 defines: T.Optional[T.Dict[str, str]] = None,
333                 full_version: T.Optional[str] = None):
334        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
335                           info, exe_wrapper, linker=linker, full_version=full_version)
336        ElbrusCompiler.__init__(self)
337
338    def get_options(self) -> 'KeyedOptionDictType':
339        opts = CCompiler.get_options(self)
340        stds = ['c89', 'c9x', 'c99', 'gnu89', 'gnu9x', 'gnu99']
341        stds += ['iso9899:1990', 'iso9899:199409', 'iso9899:1999']
342        if version_compare(self.version, '>=1.20.00'):
343            stds += ['c11', 'gnu11']
344        if version_compare(self.version, '>=1.21.00') and version_compare(self.version, '<1.22.00'):
345            stds += ['c90', 'c1x', 'gnu90', 'gnu1x', 'iso9899:2011']
346        if version_compare(self.version, '>=1.23.00'):
347            stds += ['c90', 'c1x', 'gnu90', 'gnu1x', 'iso9899:2011']
348        if version_compare(self.version, '>=1.26.00'):
349            stds += ['c17', 'c18', 'iso9899:2017', 'iso9899:2018', 'gnu17', 'gnu18']
350        opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + stds
351        return opts
352
353    # Elbrus C compiler does not have lchmod, but there is only linker warning, not compiler error.
354    # So we should explicitly fail at this case.
355    def has_function(self, funcname: str, prefix: str, env: 'Environment', *,
356                     extra_args: T.Optional[T.List[str]] = None,
357                     dependencies: T.Optional[T.List['Dependency']] = None) -> T.Tuple[bool, bool]:
358        if funcname == 'lchmod':
359            return False, False
360        else:
361            return super().has_function(funcname, prefix, env,
362                                        extra_args=extra_args,
363                                        dependencies=dependencies)
364
365
366class IntelCCompiler(IntelGnuLikeCompiler, CCompiler):
367    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice, is_cross: bool,
368                 info: 'MachineInfo', exe_wrapper: T.Optional['ExternalProgram'] = None,
369                 linker: T.Optional['DynamicLinker'] = None,
370                 full_version: T.Optional[str] = None):
371        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
372                           info, exe_wrapper, linker=linker, full_version=full_version)
373        IntelGnuLikeCompiler.__init__(self)
374        self.lang_header = 'c-header'
375        default_warn_args = ['-Wall', '-w3', '-diag-disable:remark']
376        self.warn_args = {'0': [],
377                          '1': default_warn_args,
378                          '2': default_warn_args + ['-Wextra'],
379                          '3': default_warn_args + ['-Wextra']}
380
381    def get_options(self) -> 'KeyedOptionDictType':
382        opts = CCompiler.get_options(self)
383        c_stds = ['c89', 'c99']
384        g_stds = ['gnu89', 'gnu99']
385        if version_compare(self.version, '>=16.0.0'):
386            c_stds += ['c11']
387        opts[OptionKey('std', machine=self.for_machine, lang=self.language)].choices = ['none'] + c_stds + g_stds
388        return opts
389
390    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
391        args = []
392        std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
393        if std.value != 'none':
394            args.append('-std=' + std.value)
395        return args
396
397
398class VisualStudioLikeCCompilerMixin(CompilerMixinBase):
399
400    """Shared methods that apply to MSVC-like C compilers."""
401
402    def get_options(self) -> 'KeyedOptionDictType':
403        opts = super().get_options()
404        opts.update({
405            OptionKey('winlibs', machine=self.for_machine, lang=self.language): coredata.UserArrayOption(
406                'Windows libs to link against.',
407                msvc_winlibs,
408            ),
409        })
410        return opts
411
412    def get_option_link_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
413        # need a TypeDict to make this work
414        key = OptionKey('winlibs', machine=self.for_machine, lang=self.language)
415        libs = options[key].value.copy()
416        assert isinstance(libs, list)
417        for l in libs:
418            assert isinstance(l, str)
419        return libs
420
421
422class VisualStudioCCompiler(MSVCCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
423
424    _C11_VERSION = '>=19.28'
425    _C17_VERSION = '>=19.28'
426
427    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
428                 is_cross: bool, info: 'MachineInfo', target: str,
429                 exe_wrapper: T.Optional['ExternalProgram'] = None,
430                 linker: T.Optional['DynamicLinker'] = None,
431                 full_version: T.Optional[str] = None):
432        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
433                           info, exe_wrapper, linker=linker,
434                           full_version=full_version)
435        MSVCCompiler.__init__(self, target)
436
437    def get_options(self) -> 'KeyedOptionDictType':
438        opts = super().get_options()
439        c_stds = ['c89', 'c99']
440        # Need to have these to be compatible with projects
441        # that set c_std to e.g. gnu99.
442        # https://github.com/mesonbuild/meson/issues/7611
443        g_stds = ['gnu89', 'gnu90', 'gnu9x', 'gnu99']
444        if version_compare(self.version, self._C11_VERSION):
445            c_stds += ['c11']
446            g_stds += ['gnu1x', 'gnu11']
447        if version_compare(self.version, self._C17_VERSION):
448            c_stds += ['c17', 'c18']
449            g_stds += ['gnu17', 'gnu18']
450        key = OptionKey('std', machine=self.for_machine, lang=self.language)
451        opts[key].choices = ['none'] + c_stds + g_stds
452        return opts
453
454    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
455        args = []
456        std = options[OptionKey('std', machine=self.for_machine, lang=self.language)]
457        if std.value.startswith('gnu'):
458            mlog.log_once(
459                'cl.exe does not actually support gnu standards, and meson '
460                'will instead demote to the nearest ISO C standard. This '
461                'may cause compilation to fail.')
462        # As of MVSC 16.8, /std:c11 and /std:c17 are the only valid C standard options.
463        if std.value in {'c11', 'gnu1x', 'gnu11'}:
464            args.append('/std:c11')
465        elif std.value in {'c17', 'c18', 'gnu17', 'gnu18'}:
466            args.append('/std:c17')
467        return args
468
469
470class ClangClCCompiler(_ClangCStds, ClangClCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
471    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
472                 is_cross: bool, info: 'MachineInfo', target: str,
473                 exe_wrapper: T.Optional['ExternalProgram'] = None,
474                 linker: T.Optional['DynamicLinker'] = None,
475                 full_version: T.Optional[str] = None):
476        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
477                           info, exe_wrapper, linker=linker,
478                           full_version=full_version)
479        ClangClCompiler.__init__(self, target)
480
481    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
482        key = OptionKey('std', machine=self.for_machine, lang=self.language)
483        std = options[key].value
484        if std != "none":
485            return [f'/clang:-std={std}']
486        return []
487
488
489class IntelClCCompiler(IntelVisualStudioLikeCompiler, VisualStudioLikeCCompilerMixin, CCompiler):
490
491    """Intel "ICL" compiler abstraction."""
492
493    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
494                 is_cross: bool, info: 'MachineInfo', target: str,
495                 exe_wrapper: T.Optional['ExternalProgram'] = None,
496                 linker: T.Optional['DynamicLinker'] = None,
497                 full_version: T.Optional[str] = None):
498        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
499                           info, exe_wrapper, linker=linker,
500                           full_version=full_version)
501        IntelVisualStudioLikeCompiler.__init__(self, target)
502
503    def get_options(self) -> 'KeyedOptionDictType':
504        opts = super().get_options()
505        key = OptionKey('std', machine=self.for_machine, lang=self.language)
506        opts[key].choices = ['none', 'c89', 'c99', 'c11']
507        return opts
508
509    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
510        args = []
511        key = OptionKey('std', machine=self.for_machine, lang=self.language)
512        std = options[key]
513        if std.value == 'c89':
514            mlog.log_once("ICL doesn't explicitly implement c89, setting the standard to 'none', which is close.")
515        elif std.value != 'none':
516            args.append('/Qstd:' + std.value)
517        return args
518
519
520class ArmCCompiler(ArmCompiler, CCompiler):
521    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
522                 is_cross: bool, info: 'MachineInfo',
523                 exe_wrapper: T.Optional['ExternalProgram'] = None,
524                 linker: T.Optional['DynamicLinker'] = None,
525                 full_version: T.Optional[str] = None):
526        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
527                           info, exe_wrapper, linker=linker,
528                           full_version=full_version)
529        ArmCompiler.__init__(self)
530
531    def get_options(self) -> 'KeyedOptionDictType':
532        opts = CCompiler.get_options(self)
533        key = OptionKey('std', machine=self.for_machine, lang=self.language)
534        opts[key].choices = ['none', 'c89', 'c99', 'c11']
535        return opts
536
537    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
538        args = []
539        key = OptionKey('std', machine=self.for_machine, lang=self.language)
540        std = options[key]
541        if std.value != 'none':
542            args.append('--' + std.value)
543        return args
544
545
546class CcrxCCompiler(CcrxCompiler, CCompiler):
547    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
548                 is_cross: bool, info: 'MachineInfo',
549                 exe_wrapper: T.Optional['ExternalProgram'] = None,
550                 linker: T.Optional['DynamicLinker'] = None,
551                 full_version: T.Optional[str] = None):
552        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
553                           info, exe_wrapper, linker=linker, full_version=full_version)
554        CcrxCompiler.__init__(self)
555
556    # Override CCompiler.get_always_args
557    def get_always_args(self) -> T.List[str]:
558        return ['-nologo']
559
560    def get_options(self) -> 'KeyedOptionDictType':
561        opts = CCompiler.get_options(self)
562        key = OptionKey('std', machine=self.for_machine, lang=self.language)
563        opts[key].choices = ['none', 'c89', 'c99']
564        return opts
565
566    def get_no_stdinc_args(self) -> T.List[str]:
567        return []
568
569    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
570        args = []
571        key = OptionKey('std', machine=self.for_machine, lang=self.language)
572        std = options[key]
573        if std.value == 'c89':
574            args.append('-lang=c')
575        elif std.value == 'c99':
576            args.append('-lang=c99')
577        return args
578
579    def get_compile_only_args(self) -> T.List[str]:
580        return []
581
582    def get_no_optimization_args(self) -> T.List[str]:
583        return ['-optimize=0']
584
585    def get_output_args(self, target: str) -> T.List[str]:
586        return [f'-output=obj={target}']
587
588    def get_werror_args(self) -> T.List[str]:
589        return ['-change_message=error']
590
591    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
592        if path == '':
593            path = '.'
594        return ['-include=' + path]
595
596
597class Xc16CCompiler(Xc16Compiler, CCompiler):
598    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
599                 is_cross: bool, info: 'MachineInfo',
600                 exe_wrapper: T.Optional['ExternalProgram'] = None,
601                 linker: T.Optional['DynamicLinker'] = None,
602                 full_version: T.Optional[str] = None):
603        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
604                           info, exe_wrapper, linker=linker, full_version=full_version)
605        Xc16Compiler.__init__(self)
606
607    def get_options(self) -> 'KeyedOptionDictType':
608        opts = CCompiler.get_options(self)
609        key = OptionKey('std', machine=self.for_machine, lang=self.language)
610        opts[key].choices = ['none', 'c89', 'c99', 'gnu89', 'gnu99']
611        return opts
612
613    def get_no_stdinc_args(self) -> T.List[str]:
614        return []
615
616    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
617        args = []
618        key = OptionKey('std', machine=self.for_machine, lang=self.language)
619        std = options[key]
620        if std.value != 'none':
621            args.append('-ansi')
622            args.append('-std=' + std.value)
623        return args
624
625    def get_compile_only_args(self) -> T.List[str]:
626        return []
627
628    def get_no_optimization_args(self) -> T.List[str]:
629        return ['-O0']
630
631    def get_output_args(self, target: str) -> T.List[str]:
632        return [f'-o{target}']
633
634    def get_werror_args(self) -> T.List[str]:
635        return ['-change_message=error']
636
637    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
638        if path == '':
639            path = '.'
640        return ['-I' + path]
641
642class CompCertCCompiler(CompCertCompiler, CCompiler):
643    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
644                 is_cross: bool, info: 'MachineInfo',
645                 exe_wrapper: T.Optional['ExternalProgram'] = None,
646                 linker: T.Optional['DynamicLinker'] = None,
647                 full_version: T.Optional[str] = None):
648        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
649                           info, exe_wrapper, linker=linker, full_version=full_version)
650        CompCertCompiler.__init__(self)
651
652    def get_options(self) -> 'KeyedOptionDictType':
653        opts = CCompiler.get_options(self)
654        key = OptionKey('std', machine=self.for_machine, lang=self.language)
655        opts[key].choices = ['none', 'c89', 'c99']
656        return opts
657
658    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
659        return []
660
661    def get_no_optimization_args(self) -> T.List[str]:
662        return ['-O0']
663
664    def get_output_args(self, target: str) -> T.List[str]:
665        return [f'-o{target}']
666
667    def get_werror_args(self) -> T.List[str]:
668        return ['-Werror']
669
670    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
671        if path == '':
672            path = '.'
673        return ['-I' + path]
674
675class C2000CCompiler(C2000Compiler, CCompiler):
676    def __init__(self, exelist: T.List[str], version: str, for_machine: MachineChoice,
677                 is_cross: bool, info: 'MachineInfo',
678                 exe_wrapper: T.Optional['ExternalProgram'] = None,
679                 linker: T.Optional['DynamicLinker'] = None,
680                 full_version: T.Optional[str] = None):
681        CCompiler.__init__(self, exelist, version, for_machine, is_cross,
682                           info, exe_wrapper, linker=linker, full_version=full_version)
683        C2000Compiler.__init__(self)
684
685    # Override CCompiler.get_always_args
686    def get_always_args(self) -> T.List[str]:
687        return []
688
689    def get_options(self) -> 'KeyedOptionDictType':
690        opts = CCompiler.get_options(self)
691        key = OptionKey('std', machine=self.for_machine, lang=self.language)
692        opts[key].choices = ['none', 'c89', 'c99', 'c11']
693        return opts
694
695    def get_no_stdinc_args(self) -> T.List[str]:
696        return []
697
698    def get_option_compile_args(self, options: 'KeyedOptionDictType') -> T.List[str]:
699        args = []
700        key = OptionKey('std', machine=self.for_machine, lang=self.language)
701        std = options[key]
702        if std.value != 'none':
703            args.append('--' + std.value)
704        return args
705
706    def get_compile_only_args(self) -> T.List[str]:
707        return []
708
709    def get_no_optimization_args(self) -> T.List[str]:
710        return ['-Ooff']
711
712    def get_output_args(self, target: str) -> T.List[str]:
713        return [f'--output_file={target}']
714
715    def get_werror_args(self) -> T.List[str]:
716        return ['-change_message=error']
717
718    def get_include_args(self, path: str, is_system: bool) -> T.List[str]:
719        if path == '':
720            path = '.'
721        return ['--include_path=' + path]
722