1# Copyright 2012-2020 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
15"""Representations specific to the arm family of compilers."""
16
17import os
18import typing as T
19
20from ... import mesonlib
21from ...linkers import ArmClangDynamicLinker
22from ...mesonlib import OptionKey
23from ..compilers import clike_debug_args
24from .clang import clang_color_args
25
26if T.TYPE_CHECKING:
27    from ...environment import Environment
28    from ...compilers.compilers import Compiler
29else:
30    # This is a bit clever, for mypy we pretend that these mixins descend from
31    # Compiler, so we get all of the methods and attributes defined for us, but
32    # for runtime we make them descend from object (which all classes normally
33    # do). This gives up DRYer type checking, with no runtime impact
34    Compiler = object
35
36arm_buildtype_args = {
37    'plain': [],
38    'debug': [],
39    'debugoptimized': [],
40    'release': [],
41    'minsize': [],
42    'custom': [],
43}  # type: T.Dict[str, T.List[str]]
44
45arm_optimization_args = {
46    '0': ['-O0'],
47    'g': ['-g'],
48    '1': ['-O1'],
49    '2': [], # Compiler defaults to -O2
50    '3': ['-O3', '-Otime'],
51    's': ['-O3'], # Compiler defaults to -Ospace
52}  # type: T.Dict[str, T.List[str]]
53
54armclang_buildtype_args = {
55    'plain': [],
56    'debug': [],
57    'debugoptimized': [],
58    'release': [],
59    'minsize': [],
60    'custom': [],
61}  # type: T.Dict[str, T.List[str]]
62
63armclang_optimization_args = {
64    '0': [], # Compiler defaults to -O0
65    'g': ['-g'],
66    '1': ['-O1'],
67    '2': ['-O2'],
68    '3': ['-O3'],
69    's': ['-Oz']
70}  # type: T.Dict[str, T.List[str]]
71
72
73class ArmCompiler(Compiler):
74
75    """Functionality that is common to all ARM family compilers."""
76
77    def __init__(self) -> None:
78        if not self.is_cross:
79            raise mesonlib.EnvironmentException('armcc supports only cross-compilation.')
80        self.id = 'arm'
81        default_warn_args = []  # type: T.List[str]
82        self.warn_args = {'0': [],
83                          '1': default_warn_args,
84                          '2': default_warn_args + [],
85                          '3': default_warn_args + []}  # type: T.Dict[str, T.List[str]]
86        # Assembly
87        self.can_compile_suffixes.add('s')
88
89    def get_pic_args(self) -> T.List[str]:
90        # FIXME: Add /ropi, /rwpi, /fpic etc. qualifiers to --apcs
91        return []
92
93    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
94        return arm_buildtype_args[buildtype]
95
96    # Override CCompiler.get_always_args
97    def get_always_args(self) -> T.List[str]:
98        return []
99
100    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
101        return ['--depend_target', outtarget, '--depend', outfile, '--depend_single_line']
102
103    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
104        # FIXME: Add required arguments
105        # NOTE from armcc user guide:
106        # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
107        # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
108        # PCH files."
109        return []
110
111    def get_pch_suffix(self) -> str:
112        # NOTE from armcc user guide:
113        # "Support for Precompiled Header (PCH) files is deprecated from ARM Compiler 5.05
114        # onwards on all platforms. Note that ARM Compiler on Windows 8 never supported
115        # PCH files."
116        return 'pch'
117
118    def thread_flags(self, env: 'Environment') -> T.List[str]:
119        return []
120
121    def get_coverage_args(self) -> T.List[str]:
122        return []
123
124    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
125        return arm_optimization_args[optimization_level]
126
127    def get_debug_args(self, is_debug: bool) -> T.List[str]:
128        return clike_debug_args[is_debug]
129
130    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]:
131        for idx, i in enumerate(parameter_list):
132            if i[:2] == '-I' or i[:2] == '-L':
133                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
134
135        return parameter_list
136
137
138class ArmclangCompiler(Compiler):
139
140    def __init__(self) -> None:
141        if not self.is_cross:
142            raise mesonlib.EnvironmentException('armclang supports only cross-compilation.')
143        # Check whether 'armlink' is available in path
144        if not isinstance(self.linker, ArmClangDynamicLinker):
145            raise mesonlib.EnvironmentException(f'Unsupported Linker {self.linker.exelist}, must be armlink')
146        if not mesonlib.version_compare(self.version, '==' + self.linker.version):
147            raise mesonlib.EnvironmentException('armlink version does not match with compiler version')
148        self.id = 'armclang'
149        self.base_options = {
150            OptionKey(o) for o in
151            ['b_pch', 'b_lto', 'b_pgo', 'b_sanitize', 'b_coverage',
152             'b_ndebug', 'b_staticpic', 'b_colorout']}
153        # Assembly
154        self.can_compile_suffixes.add('s')
155
156    def get_pic_args(self) -> T.List[str]:
157        # PIC support is not enabled by default for ARM,
158        # if users want to use it, they need to add the required arguments explicitly
159        return []
160
161    def get_colorout_args(self, colortype: str) -> T.List[str]:
162        return clang_color_args[colortype][:]
163
164    def get_buildtype_args(self, buildtype: str) -> T.List[str]:
165        return armclang_buildtype_args[buildtype]
166
167    def get_pch_suffix(self) -> str:
168        return 'gch'
169
170    def get_pch_use_args(self, pch_dir: str, header: str) -> T.List[str]:
171        # Workaround for Clang bug http://llvm.org/bugs/show_bug.cgi?id=15136
172        # This flag is internal to Clang (or at least not documented on the man page)
173        # so it might change semantics at any time.
174        return ['-include-pch', os.path.join(pch_dir, self.get_pch_name(header))]
175
176    def get_dependency_gen_args(self, outtarget: str, outfile: str) -> T.List[str]:
177        return ['-MD', '-MT', outtarget, '-MF', outfile]
178
179    def get_optimization_args(self, optimization_level: str) -> T.List[str]:
180        return armclang_optimization_args[optimization_level]
181
182    def get_debug_args(self, is_debug: bool) -> T.List[str]:
183        return clike_debug_args[is_debug]
184
185    def compute_parameters_with_absolute_paths(self, parameter_list: T.List[str], build_dir: str) -> T.List[str]:
186        for idx, i in enumerate(parameter_list):
187            if i[:2] == '-I' or i[:2] == '-L':
188                parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:]))
189
190        return parameter_list
191