1# Copyright 2012-2017 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, subprocess 16import typing as T 17 18from ..mesonlib import ( 19 EnvironmentException, MachineChoice, version_compare, 20) 21 22from ..arglist import CompilerArgs 23from .compilers import ( 24 d_dmd_buildtype_args, 25 d_gdc_buildtype_args, 26 d_ldc_buildtype_args, 27 clike_debug_args, 28 Compiler, 29) 30from .mixins.gnu import GnuCompiler 31 32if T.TYPE_CHECKING: 33 from ..envconfig import MachineInfo 34 35d_feature_args = {'gcc': {'unittest': '-funittest', 36 'debug': '-fdebug', 37 'version': '-fversion', 38 'import_dir': '-J' 39 }, 40 'llvm': {'unittest': '-unittest', 41 'debug': '-d-debug', 42 'version': '-d-version', 43 'import_dir': '-J' 44 }, 45 'dmd': {'unittest': '-unittest', 46 'debug': '-debug', 47 'version': '-version', 48 'import_dir': '-J' 49 } 50 } 51 52ldc_optimization_args = {'0': [], 53 'g': [], 54 '1': ['-O1'], 55 '2': ['-O2'], 56 '3': ['-O3'], 57 's': ['-Os'], 58 } 59 60dmd_optimization_args = {'0': [], 61 'g': [], 62 '1': ['-O'], 63 '2': ['-O'], 64 '3': ['-O'], 65 's': ['-O'], 66 } 67 68 69class DmdLikeCompilerMixin: 70 71 LINKER_PREFIX = '-L=' 72 73 def get_output_args(self, target): 74 return ['-of=' + target] 75 76 def get_linker_output_args(self, target): 77 return ['-of=' + target] 78 79 def get_include_args(self, path, is_system): 80 return ['-I=' + path] 81 82 def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): 83 for idx, i in enumerate(parameter_list): 84 if i[:3] == '-I=': 85 parameter_list[idx] = i[:3] + os.path.normpath(os.path.join(build_dir, i[3:])) 86 if i[:4] == '-L-L': 87 parameter_list[idx] = i[:4] + os.path.normpath(os.path.join(build_dir, i[4:])) 88 if i[:5] == '-L=-L': 89 parameter_list[idx] = i[:5] + os.path.normpath(os.path.join(build_dir, i[5:])) 90 if i[:6] == '-Wl,-L': 91 parameter_list[idx] = i[:6] + os.path.normpath(os.path.join(build_dir, i[6:])) 92 93 return parameter_list 94 95 def get_warn_args(self, level): 96 return ['-wi'] 97 98 def get_werror_args(self): 99 return ['-w'] 100 101 def get_dependency_gen_args(self, outtarget, outfile): 102 # DMD and LDC does not currently return Makefile-compatible dependency info. 103 return [] 104 105 def get_coverage_args(self): 106 return ['-cov'] 107 108 def get_coverage_link_args(self): 109 return [] 110 111 def get_preprocess_only_args(self): 112 return ['-E'] 113 114 def get_compile_only_args(self): 115 return ['-c'] 116 117 def depfile_for_object(self, objfile): 118 return objfile + '.' + self.get_depfile_suffix() 119 120 def get_depfile_suffix(self): 121 return 'deps' 122 123 def get_pic_args(self): 124 if self.info.is_windows(): 125 return [] 126 return ['-fPIC'] 127 128 def get_feature_args(self, kwargs, build_to_src): 129 res = [] 130 if 'unittest' in kwargs: 131 unittest = kwargs.pop('unittest') 132 unittest_arg = d_feature_args[self.id]['unittest'] 133 if not unittest_arg: 134 raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string()) 135 if unittest: 136 res.append(unittest_arg) 137 138 if 'debug' in kwargs: 139 debug_level = -1 140 debugs = kwargs.pop('debug') 141 if not isinstance(debugs, list): 142 debugs = [debugs] 143 144 debug_arg = d_feature_args[self.id]['debug'] 145 if not debug_arg: 146 raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string()) 147 148 # Parse all debug identifiers and the largest debug level identifier 149 for d in debugs: 150 if isinstance(d, int): 151 if d > debug_level: 152 debug_level = d 153 elif isinstance(d, str) and d.isdigit(): 154 if int(d) > debug_level: 155 debug_level = int(d) 156 else: 157 res.append('{0}={1}'.format(debug_arg, d)) 158 159 if debug_level >= 0: 160 res.append('{0}={1}'.format(debug_arg, debug_level)) 161 162 if 'versions' in kwargs: 163 version_level = -1 164 versions = kwargs.pop('versions') 165 if not isinstance(versions, list): 166 versions = [versions] 167 168 version_arg = d_feature_args[self.id]['version'] 169 if not version_arg: 170 raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string()) 171 172 # Parse all version identifiers and the largest version level identifier 173 for v in versions: 174 if isinstance(v, int): 175 if v > version_level: 176 version_level = v 177 elif isinstance(v, str) and v.isdigit(): 178 if int(v) > version_level: 179 version_level = int(v) 180 else: 181 res.append('{0}={1}'.format(version_arg, v)) 182 183 if version_level >= 0: 184 res.append('{0}={1}'.format(version_arg, version_level)) 185 186 if 'import_dirs' in kwargs: 187 import_dirs = kwargs.pop('import_dirs') 188 if not isinstance(import_dirs, list): 189 import_dirs = [import_dirs] 190 191 import_dir_arg = d_feature_args[self.id]['import_dir'] 192 if not import_dir_arg: 193 raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) 194 for idir_obj in import_dirs: 195 basedir = idir_obj.get_curdir() 196 for idir in idir_obj.get_incdirs(): 197 # Avoid superfluous '/.' at the end of paths when d is '.' 198 if idir not in ('', '.'): 199 expdir = os.path.join(basedir, idir) 200 else: 201 expdir = basedir 202 srctreedir = os.path.join(build_to_src, expdir) 203 res.append('{0}{1}'.format(import_dir_arg, srctreedir)) 204 205 if kwargs: 206 raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) 207 208 return res 209 210 def get_buildtype_linker_args(self, buildtype): 211 if buildtype != 'plain': 212 return self.get_target_arch_args() 213 return [] 214 215 def get_std_exe_link_args(self): 216 return [] 217 218 def gen_import_library_args(self, implibname): 219 return self.linker.import_library_args(implibname) 220 221 def build_rpath_args(self, env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath): 222 if self.info.is_windows(): 223 return ([], set()) 224 225 # GNU ld, solaris ld, and lld acting like GNU ld 226 if self.linker.id.startswith('ld'): 227 # The way that dmd and ldc pass rpath to gcc is different than we would 228 # do directly, each argument -rpath and the value to rpath, need to be 229 # split into two separate arguments both prefaced with the -L=. 230 args = [] 231 (rpath_args, rpath_dirs_to_remove) = super().build_rpath_args( 232 env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) 233 for r in rpath_args: 234 if ',' in r: 235 a, b = r.split(',', maxsplit=1) 236 args.append(a) 237 args.append(self.LINKER_PREFIX + b) 238 else: 239 args.append(r) 240 return (args, rpath_dirs_to_remove) 241 242 return super().build_rpath_args( 243 env, build_dir, from_dir, rpath_paths, build_rpath, install_rpath) 244 245 def translate_args_to_nongnu(self, args): 246 dcargs = [] 247 # Translate common arguments to flags the LDC/DMD compilers 248 # can understand. 249 # The flags might have been added by pkg-config files, 250 # and are therefore out of the user's control. 251 for arg in args: 252 # Translate OS specific arguments first. 253 osargs = [] 254 if self.info.is_windows(): 255 osargs = self.translate_arg_to_windows(arg) 256 elif self.info.is_darwin(): 257 osargs = self.translate_arg_to_osx(arg) 258 if osargs: 259 dcargs.extend(osargs) 260 continue 261 262 # Translate common D arguments here. 263 if arg == '-pthread': 264 continue 265 if arg.startswith('-fstack-protector'): 266 continue 267 if arg.startswith('-D'): 268 continue 269 if arg.startswith('-Wl,'): 270 # Translate linker arguments here. 271 linkargs = arg[arg.index(',') + 1:].split(',') 272 for la in linkargs: 273 dcargs.append('-L=' + la.strip()) 274 continue 275 elif arg.startswith(('-link-defaultlib', '-linker', '-link-internally', '-linkonce-templates', '-lib')): 276 # these are special arguments to the LDC linker call, 277 # arguments like "-link-defaultlib-shared" do *not* 278 # denote a library to be linked, but change the default 279 # Phobos/DRuntime linking behavior, while "-linker" sets the 280 # default linker. 281 dcargs.append(arg) 282 continue 283 elif arg.startswith('-l'): 284 # translate library link flag 285 dcargs.append('-L=' + arg) 286 continue 287 elif arg.startswith('-isystem'): 288 # translate -isystem system include path 289 # this flag might sometimes be added by C library Cflags via 290 # pkg-config. 291 # NOTE: -isystem and -I are not 100% equivalent, so this is just 292 # a workaround for the most common cases. 293 if arg.startswith('-isystem='): 294 dcargs.append('-I=' + arg[9:]) 295 else: 296 dcargs.append('-I' + arg[8:]) 297 continue 298 elif arg.startswith('-idirafter'): 299 # same as -isystem, but appends the path instead 300 if arg.startswith('-idirafter='): 301 dcargs.append('-I=' + arg[11:]) 302 else: 303 dcargs.append('-I' + arg[10:]) 304 continue 305 elif arg.startswith('-L/') or arg.startswith('-L./'): 306 # we need to handle cases where -L is set by e.g. a pkg-config 307 # setting to select a linker search path. We can however not 308 # unconditionally prefix '-L' with '-L' because the user might 309 # have set this flag too to do what it is intended to for this 310 # compiler (pass flag through to the linker) 311 # Hence, we guess here whether the flag was intended to pass 312 # a linker search path. 313 314 # Make sure static library files are passed properly to the linker. 315 if arg.endswith('.a') or arg.endswith('.lib'): 316 if arg.startswith('-L='): 317 farg = arg[3:] 318 else: 319 farg = arg[2:] 320 if len(farg) > 0 and not farg.startswith('-'): 321 dcargs.append('-L=' + farg) 322 continue 323 324 dcargs.append('-L=' + arg) 325 continue 326 elif not arg.startswith('-') and arg.endswith(('.a', '.lib')): 327 # ensure static libraries are passed through to the linker 328 dcargs.append('-L=' + arg) 329 continue 330 else: 331 dcargs.append(arg) 332 333 return dcargs 334 335 @classmethod 336 def translate_arg_to_windows(cls, arg): 337 args = [] 338 if arg.startswith('-Wl,'): 339 # Translate linker arguments here. 340 linkargs = arg[arg.index(',') + 1:].split(',') 341 for la in linkargs: 342 if la.startswith('--out-implib='): 343 # Import library name 344 args.append('-L=/IMPLIB:' + la[13:].strip()) 345 elif arg.startswith('-mscrtlib='): 346 args.append(arg) 347 mscrtlib = arg[10:].lower() 348 if cls is LLVMDCompiler: 349 # Default crt libraries for LDC2 must be excluded for other 350 # selected crt options. 351 if mscrtlib != 'libcmt': 352 args.append('-L=/NODEFAULTLIB:libcmt') 353 args.append('-L=/NODEFAULTLIB:libvcruntime') 354 355 # Fixes missing definitions for printf-functions in VS2017 356 if mscrtlib.startswith('msvcrt'): 357 args.append('-L=/DEFAULTLIB:legacy_stdio_definitions.lib') 358 359 return args 360 361 @classmethod 362 def translate_arg_to_osx(cls, arg): 363 args = [] 364 if arg.startswith('-install_name'): 365 args.append('-L=' + arg) 366 return args 367 368 def get_debug_args(self, is_debug): 369 ddebug_args = [] 370 if is_debug: 371 ddebug_args = [d_feature_args[self.id]['debug']] 372 373 return clike_debug_args[is_debug] + ddebug_args 374 375 def get_crt_args(self, crt_val, buildtype): 376 if not self.info.is_windows(): 377 return [] 378 379 if crt_val in self.mscrt_args: 380 return self.mscrt_args[crt_val] 381 assert(crt_val == 'from_buildtype') 382 383 # Match what build type flags used to do. 384 if buildtype == 'plain': 385 return [] 386 elif buildtype == 'debug': 387 return self.mscrt_args['mdd'] 388 elif buildtype == 'debugoptimized': 389 return self.mscrt_args['md'] 390 elif buildtype == 'release': 391 return self.mscrt_args['md'] 392 elif buildtype == 'minsize': 393 return self.mscrt_args['md'] 394 else: 395 assert(buildtype == 'custom') 396 raise EnvironmentException('Requested C runtime based on buildtype, but buildtype is "custom".') 397 398 def get_soname_args(self, *args, **kwargs) -> T.List[str]: 399 # LDC and DMD actually do use a linker, but they proxy all of that with 400 # their own arguments 401 if self.linker.id.startswith('ld.'): 402 soargs = [] 403 for arg in super().get_soname_args(*args, **kwargs): 404 a, b = arg.split(',', maxsplit=1) 405 soargs.append(a) 406 soargs.append(self.LINKER_PREFIX + b) 407 return soargs 408 elif self.linker.id.startswith('ld64'): 409 soargs = [] 410 for arg in super().get_soname_args(*args, **kwargs): 411 if not arg.startswith(self.LINKER_PREFIX): 412 soargs.append(self.LINKER_PREFIX + arg) 413 else: 414 soargs.append(arg) 415 return soargs 416 else: 417 return super().get_soname_args(*args, **kwargs) 418 419 def get_allow_undefined_link_args(self) -> T.List[str]: 420 args = self.linker.get_allow_undefined_args() 421 if self.info.is_darwin(): 422 # On macOS we're passing these options to the C compiler, but 423 # they're linker options and need -Wl, so clang/gcc knows what to 424 # do with them. I'm assuming, but don't know for certain, that 425 # ldc/dmd do some kind of mapping internally for arguments they 426 # understand, but pass arguments they don't understand directly. 427 args = [a.replace('-L=', '-Xcc=-Wl,') for a in args] 428 return args 429 430class DCompilerArgs(CompilerArgs): 431 prepend_prefixes = ('-I', '-L') 432 dedup2_prefixes = ('-I') 433 434class DCompiler(Compiler): 435 mscrt_args = { 436 'none': ['-mscrtlib='], 437 'md': ['-mscrtlib=msvcrt'], 438 'mdd': ['-mscrtlib=msvcrtd'], 439 'mt': ['-mscrtlib=libcmt'], 440 'mtd': ['-mscrtlib=libcmtd'], 441 } 442 443 language = 'd' 444 445 def __init__(self, exelist, version, for_machine: MachineChoice, 446 info: 'MachineInfo', arch, is_cross, exe_wrapper, **kwargs): 447 super().__init__(exelist, version, for_machine, info, **kwargs) 448 self.id = 'unknown' 449 self.arch = arch 450 self.exe_wrapper = exe_wrapper 451 self.is_cross = is_cross 452 453 def sanity_check(self, work_dir, environment): 454 source_name = os.path.join(work_dir, 'sanity.d') 455 output_name = os.path.join(work_dir, 'dtest') 456 with open(source_name, 'w') as ofile: 457 ofile.write('''void main() { }''') 458 pc = subprocess.Popen(self.exelist + self.get_output_args(output_name) + self.get_target_arch_args() + [source_name], cwd=work_dir) 459 pc.wait() 460 if pc.returncode != 0: 461 raise EnvironmentException('D compiler %s can not compile programs.' % self.name_string()) 462 if self.is_cross: 463 if self.exe_wrapper is None: 464 # Can't check if the binaries run so we have to assume they do 465 return 466 cmdlist = self.exe_wrapper.get_command() + [output_name] 467 else: 468 cmdlist = [output_name] 469 if subprocess.call(cmdlist) != 0: 470 raise EnvironmentException('Executables created by D compiler %s are not runnable.' % self.name_string()) 471 472 def needs_static_linker(self): 473 return True 474 475 def depfile_for_object(self, objfile): 476 return objfile + '.' + self.get_depfile_suffix() 477 478 def get_depfile_suffix(self): 479 return 'deps' 480 481 def get_pic_args(self): 482 if self.info.is_windows(): 483 return [] 484 return ['-fPIC'] 485 486 def get_feature_args(self, kwargs, build_to_src): 487 res = [] 488 if 'unittest' in kwargs: 489 unittest = kwargs.pop('unittest') 490 unittest_arg = d_feature_args[self.id]['unittest'] 491 if not unittest_arg: 492 raise EnvironmentException('D compiler %s does not support the "unittest" feature.' % self.name_string()) 493 if unittest: 494 res.append(unittest_arg) 495 496 if 'debug' in kwargs: 497 debug_level = -1 498 debugs = kwargs.pop('debug') 499 if not isinstance(debugs, list): 500 debugs = [debugs] 501 502 debug_arg = d_feature_args[self.id]['debug'] 503 if not debug_arg: 504 raise EnvironmentException('D compiler %s does not support conditional debug identifiers.' % self.name_string()) 505 506 # Parse all debug identifiers and the largest debug level identifier 507 for d in debugs: 508 if isinstance(d, int): 509 if d > debug_level: 510 debug_level = d 511 elif isinstance(d, str) and d.isdigit(): 512 if int(d) > debug_level: 513 debug_level = int(d) 514 else: 515 res.append('{0}={1}'.format(debug_arg, d)) 516 517 if debug_level >= 0: 518 res.append('{0}={1}'.format(debug_arg, debug_level)) 519 520 if 'versions' in kwargs: 521 version_level = -1 522 versions = kwargs.pop('versions') 523 if not isinstance(versions, list): 524 versions = [versions] 525 526 version_arg = d_feature_args[self.id]['version'] 527 if not version_arg: 528 raise EnvironmentException('D compiler %s does not support conditional version identifiers.' % self.name_string()) 529 530 # Parse all version identifiers and the largest version level identifier 531 for v in versions: 532 if isinstance(v, int): 533 if v > version_level: 534 version_level = v 535 elif isinstance(v, str) and v.isdigit(): 536 if int(v) > version_level: 537 version_level = int(v) 538 else: 539 res.append('{0}={1}'.format(version_arg, v)) 540 541 if version_level >= 0: 542 res.append('{0}={1}'.format(version_arg, version_level)) 543 544 if 'import_dirs' in kwargs: 545 import_dirs = kwargs.pop('import_dirs') 546 if not isinstance(import_dirs, list): 547 import_dirs = [import_dirs] 548 549 import_dir_arg = d_feature_args[self.id]['import_dir'] 550 if not import_dir_arg: 551 raise EnvironmentException('D compiler %s does not support the "string import directories" feature.' % self.name_string()) 552 for idir_obj in import_dirs: 553 basedir = idir_obj.get_curdir() 554 for idir in idir_obj.get_incdirs(): 555 # Avoid superfluous '/.' at the end of paths when d is '.' 556 if idir not in ('', '.'): 557 expdir = os.path.join(basedir, idir) 558 else: 559 expdir = basedir 560 srctreedir = os.path.join(build_to_src, expdir) 561 res.append('{0}{1}'.format(import_dir_arg, srctreedir)) 562 563 if kwargs: 564 raise EnvironmentException('Unknown D compiler feature(s) selected: %s' % ', '.join(kwargs.keys())) 565 566 return res 567 568 def get_buildtype_linker_args(self, buildtype): 569 if buildtype != 'plain': 570 return self.get_target_arch_args() 571 return [] 572 573 def get_std_exe_link_args(self): 574 return [] 575 576 def _get_compiler_check_args(self, env, extra_args, dependencies, mode='compile'): 577 if callable(extra_args): 578 extra_args = extra_args(mode) 579 if extra_args is None: 580 extra_args = [] 581 elif isinstance(extra_args, str): 582 extra_args = [extra_args] 583 if dependencies is None: 584 dependencies = [] 585 elif not isinstance(dependencies, list): 586 dependencies = [dependencies] 587 # Collect compiler arguments 588 args = self.compiler_args() 589 for d in dependencies: 590 # Add compile flags needed by dependencies 591 args += d.get_compile_args() 592 if mode == 'link': 593 # Add link flags needed to find dependencies 594 args += d.get_link_args() 595 596 if mode == 'compile': 597 # Add DFLAGS from the env 598 args += env.coredata.get_external_args(self.for_machine, self.language) 599 elif mode == 'link': 600 # Add LDFLAGS from the env 601 args += env.coredata.get_external_link_args(self.for_machine, self.language) 602 # extra_args must override all other arguments, so we add them last 603 args += extra_args 604 return args 605 606 def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> DCompilerArgs: 607 return DCompilerArgs(self, args) 608 609 def compiles(self, code, env, *, extra_args=None, dependencies=None, mode='compile'): 610 args = self._get_compiler_check_args(env, extra_args, dependencies, mode) 611 612 with self.cached_compile(code, env.coredata, extra_args=args, mode=mode) as p: 613 return p.returncode == 0, p.cached 614 615 def has_multi_arguments(self, args, env): 616 return self.compiles('int i;\n', env, extra_args=args) 617 618 def get_target_arch_args(self): 619 # LDC2 on Windows targets to current OS architecture, but 620 # it should follow the target specified by the MSVC toolchain. 621 if self.info.is_windows(): 622 if self.arch == 'x86_64': 623 return ['-m64'] 624 return ['-m32'] 625 return [] 626 627 def get_crt_compile_args(self, crt_val, buildtype): 628 return [] 629 630 def get_crt_link_args(self, crt_val, buildtype): 631 return [] 632 633 def thread_link_flags(self, env): 634 return self.linker.thread_flags(env) 635 636 def name_string(self): 637 return ' '.join(self.exelist) 638 639 640class GnuDCompiler(GnuCompiler, DCompiler): 641 642 # we mostly want DCompiler, but that gives us the Compiler.LINKER_PREFIX instead 643 LINKER_PREFIX = GnuCompiler.LINKER_PREFIX 644 645 def __init__(self, exelist, version, for_machine: MachineChoice, 646 info: 'MachineInfo', is_cross, exe_wrapper, arch, **kwargs): 647 DCompiler.__init__(self, exelist, version, for_machine, info, is_cross, exe_wrapper, arch, **kwargs) 648 GnuCompiler.__init__(self, {}) 649 self.id = 'gcc' 650 default_warn_args = ['-Wall', '-Wdeprecated'] 651 self.warn_args = {'0': [], 652 '1': default_warn_args, 653 '2': default_warn_args + ['-Wextra'], 654 '3': default_warn_args + ['-Wextra', '-Wpedantic']} 655 self.base_options = ['b_colorout', 'b_sanitize', 'b_staticpic', 656 'b_vscrt', 'b_coverage', 'b_pgo', 'b_ndebug'] 657 658 self._has_color_support = version_compare(self.version, '>=4.9') 659 # dependencies were implemented before, but broken - support was fixed in GCC 7.1+ 660 # (and some backported versions) 661 self._has_deps_support = version_compare(self.version, '>=7.1') 662 663 def get_colorout_args(self, colortype): 664 if self._has_color_support: 665 super().get_colorout_args(colortype) 666 return [] 667 668 def get_dependency_gen_args(self, outtarget, outfile): 669 if self._has_deps_support: 670 return super().get_dependency_gen_args(outtarget, outfile) 671 return [] 672 673 def get_warn_args(self, level): 674 return self.warn_args[level] 675 676 def get_buildtype_args(self, buildtype): 677 return d_gdc_buildtype_args[buildtype] 678 679 def compute_parameters_with_absolute_paths(self, parameter_list, build_dir): 680 for idx, i in enumerate(parameter_list): 681 if i[:2] == '-I' or i[:2] == '-L': 682 parameter_list[idx] = i[:2] + os.path.normpath(os.path.join(build_dir, i[2:])) 683 684 return parameter_list 685 686 def get_allow_undefined_link_args(self) -> T.List[str]: 687 return self.linker.get_allow_undefined_args() 688 689 def get_linker_always_args(self) -> T.List[str]: 690 args = super().get_linker_always_args() 691 if self.info.is_windows(): 692 return args 693 return args + ['-shared-libphobos'] 694 695 def get_disable_assert_args(self): 696 return ['-frelease'] 697 698 699class LLVMDCompiler(DmdLikeCompilerMixin, DCompiler): 700 701 def __init__(self, exelist, version, for_machine: MachineChoice, 702 info: 'MachineInfo', arch, **kwargs): 703 DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs) 704 self.id = 'llvm' 705 self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] 706 707 def get_colorout_args(self, colortype): 708 if colortype == 'always': 709 return ['-enable-color'] 710 return [] 711 712 def get_warn_args(self, level): 713 if level == '2' or level == '3': 714 return ['-wi', '-dw'] 715 elif level == '1': 716 return ['-wi'] 717 else: 718 return [] 719 720 def get_buildtype_args(self, buildtype): 721 if buildtype != 'plain': 722 return self.get_target_arch_args() + d_ldc_buildtype_args[buildtype] 723 return d_ldc_buildtype_args[buildtype] 724 725 def get_pic_args(self): 726 return ['-relocation-model=pic'] 727 728 def get_crt_link_args(self, crt_val, buildtype): 729 return self.get_crt_args(crt_val, buildtype) 730 731 def unix_args_to_native(self, args): 732 return self.translate_args_to_nongnu(args) 733 734 def get_optimization_args(self, optimization_level): 735 return ldc_optimization_args[optimization_level] 736 737 @classmethod 738 def use_linker_args(cls, linker: str) -> T.List[str]: 739 return ['-linker={}'.format(linker)] 740 741 def get_linker_always_args(self) -> T.List[str]: 742 args = super().get_linker_always_args() 743 if self.info.is_windows(): 744 return args 745 return args + ['-link-defaultlib-shared'] 746 747 def get_disable_assert_args(self) -> T.List[str]: 748 return ['--release'] 749 750 751class DmdDCompiler(DmdLikeCompilerMixin, DCompiler): 752 753 def __init__(self, exelist, version, for_machine: MachineChoice, 754 info: 'MachineInfo', arch, **kwargs): 755 DCompiler.__init__(self, exelist, version, for_machine, info, arch, False, None, **kwargs) 756 self.id = 'dmd' 757 self.base_options = ['b_coverage', 'b_colorout', 'b_vscrt', 'b_ndebug'] 758 759 def get_colorout_args(self, colortype): 760 if colortype == 'always': 761 return ['-color=on'] 762 return [] 763 764 def get_buildtype_args(self, buildtype): 765 if buildtype != 'plain': 766 return self.get_target_arch_args() + d_dmd_buildtype_args[buildtype] 767 return d_dmd_buildtype_args[buildtype] 768 769 def get_std_exe_link_args(self): 770 if self.info.is_windows(): 771 # DMD links against D runtime only when main symbol is found, 772 # so these needs to be inserted when linking static D libraries. 773 if self.arch == 'x86_64': 774 return ['phobos64.lib'] 775 elif self.arch == 'x86_mscoff': 776 return ['phobos32mscoff.lib'] 777 return ['phobos.lib'] 778 return [] 779 780 def get_std_shared_lib_link_args(self): 781 libname = 'libphobos2.so' 782 if self.info.is_windows(): 783 if self.arch == 'x86_64': 784 libname = 'phobos64.lib' 785 elif self.arch == 'x86_mscoff': 786 libname = 'phobos32mscoff.lib' 787 else: 788 libname = 'phobos.lib' 789 return ['-shared', '-defaultlib=' + libname] 790 791 def get_target_arch_args(self): 792 # DMD32 and DMD64 on 64-bit Windows defaults to 32-bit (OMF). 793 # Force the target to 64-bit in order to stay consistent 794 # across the different platforms. 795 if self.info.is_windows(): 796 if self.arch == 'x86_64': 797 return ['-m64'] 798 elif self.arch == 'x86_mscoff': 799 return ['-m32mscoff'] 800 return ['-m32'] 801 return [] 802 803 def get_crt_compile_args(self, crt_val, buildtype): 804 return self.get_crt_args(crt_val, buildtype) 805 806 def unix_args_to_native(self, args): 807 return self.translate_args_to_nongnu(args) 808 809 def get_optimization_args(self, optimization_level): 810 return dmd_optimization_args[optimization_level] 811 812 def can_linker_accept_rsp(self) -> bool: 813 return False 814 815 def get_linker_always_args(self) -> T.List[str]: 816 args = super().get_linker_always_args() 817 if self.info.is_windows(): 818 return args 819 return args + ['-defaultlib=phobos2', '-debuglib=phobos2'] 820 821 def get_disable_assert_args(self) -> T.List[str]: 822 return ['-release'] 823