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