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 abc 16import os 17import typing as T 18 19from . import mesonlib 20from .arglist import CompilerArgs 21from .envconfig import get_env_var 22 23if T.TYPE_CHECKING: 24 from .coredata import OptionDictType 25 from .environment import Environment 26 27 28class StaticLinker: 29 30 def __init__(self, exelist: T.List[str]): 31 self.exelist = exelist 32 33 def compiler_args(self, args: T.Optional[T.Iterable[str]] = None) -> CompilerArgs: 34 return CompilerArgs(self, args) 35 36 def can_linker_accept_rsp(self) -> bool: 37 """ 38 Determines whether the linker can accept arguments using the @rsp syntax. 39 """ 40 return mesonlib.is_windows() 41 42 def get_base_link_args(self, options: 'OptionDictType') -> T.List[str]: 43 """Like compilers.get_base_link_args, but for the static linker.""" 44 return [] 45 46 def get_exelist(self) -> T.List[str]: 47 return self.exelist.copy() 48 49 def get_std_link_args(self) -> T.List[str]: 50 return [] 51 52 def get_buildtype_linker_args(self, buildtype: str) -> T.List[str]: 53 return [] 54 55 def get_output_args(self, target: str) -> T.List[str]: 56 return[] 57 58 def get_coverage_link_args(self) -> T.List[str]: 59 return [] 60 61 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 62 rpath_paths: str, build_rpath: str, 63 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 64 return ([], set()) 65 66 def thread_link_flags(self, env: 'Environment') -> T.List[str]: 67 return [] 68 69 def openmp_flags(self) -> T.List[str]: 70 return [] 71 72 def get_option_link_args(self, options: 'OptionDictType') -> T.List[str]: 73 return [] 74 75 @classmethod 76 def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]: 77 return args[:] 78 79 @classmethod 80 def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]: 81 return args[:] 82 83 def get_link_debugfile_name(self, targetfile: str) -> str: 84 return None 85 86 def get_link_debugfile_args(self, targetfile: str) -> T.List[str]: 87 # Static libraries do not have PDB files 88 return [] 89 90 def get_always_args(self) -> T.List[str]: 91 return [] 92 93 def get_linker_always_args(self) -> T.List[str]: 94 return [] 95 96 97class VisualStudioLikeLinker: 98 always_args = ['/NOLOGO'] 99 100 def __init__(self, machine: str): 101 self.machine = machine 102 103 def get_always_args(self) -> T.List[str]: 104 return self.always_args.copy() 105 106 def get_linker_always_args(self) -> T.List[str]: 107 return self.always_args.copy() 108 109 def get_output_args(self, target: str) -> T.List[str]: 110 args = [] # type: T.List[str] 111 if self.machine: 112 args += ['/MACHINE:' + self.machine] 113 args += ['/OUT:' + target] 114 return args 115 116 @classmethod 117 def unix_args_to_native(cls, args: T.List[str]) -> T.List[str]: 118 from .compilers import VisualStudioCCompiler 119 return VisualStudioCCompiler.unix_args_to_native(args) 120 121 @classmethod 122 def native_args_to_unix(cls, args: T.List[str]) -> T.List[str]: 123 from .compilers import VisualStudioCCompiler 124 return VisualStudioCCompiler.native_args_to_unix(args) 125 126 127class VisualStudioLinker(VisualStudioLikeLinker, StaticLinker): 128 129 """Microsoft's lib static linker.""" 130 131 def __init__(self, exelist: T.List[str], machine: str): 132 StaticLinker.__init__(self, exelist) 133 VisualStudioLikeLinker.__init__(self, machine) 134 135 136class IntelVisualStudioLinker(VisualStudioLikeLinker, StaticLinker): 137 138 """Intel's xilib static linker.""" 139 140 def __init__(self, exelist: T.List[str], machine: str): 141 StaticLinker.__init__(self, exelist) 142 VisualStudioLikeLinker.__init__(self, machine) 143 144 145class ArLinker(StaticLinker): 146 147 def __init__(self, exelist: T.List[str]): 148 super().__init__(exelist) 149 self.id = 'ar' 150 pc, stdo = mesonlib.Popen_safe(self.exelist + ['-h'])[0:2] 151 # Enable deterministic builds if they are available. 152 if '[D]' in stdo: 153 self.std_args = ['csrD'] 154 else: 155 self.std_args = ['csr'] 156 self.can_rsp = '@<' in stdo 157 158 def can_linker_accept_rsp(self) -> bool: 159 return self.can_rsp 160 161 def get_std_link_args(self) -> T.List[str]: 162 return self.std_args 163 164 def get_output_args(self, target: str) -> T.List[str]: 165 return [target] 166 167 168class ArmarLinker(ArLinker): # lgtm [py/missing-call-to-init] 169 170 def __init__(self, exelist: T.List[str]): 171 StaticLinker.__init__(self, exelist) 172 self.id = 'armar' 173 self.std_args = ['-csr'] 174 175 def can_linker_accept_rsp(self) -> bool: 176 # armar can't accept arguments using the @rsp syntax 177 return False 178 179 180class DLinker(StaticLinker): 181 def __init__(self, exelist: T.List[str], arch: str): 182 super().__init__(exelist) 183 self.id = exelist[0] 184 self.arch = arch 185 186 def get_std_link_args(self) -> T.List[str]: 187 return ['-lib'] 188 189 def get_output_args(self, target: str) -> T.List[str]: 190 return ['-of=' + target] 191 192 def get_linker_always_args(self) -> T.List[str]: 193 if mesonlib.is_windows(): 194 if self.arch == 'x86_64': 195 return ['-m64'] 196 elif self.arch == 'x86_mscoff' and self.id == 'dmd': 197 return ['-m32mscoff'] 198 return ['-m32'] 199 return [] 200 201 202class CcrxLinker(StaticLinker): 203 204 def __init__(self, exelist: T.List[str]): 205 super().__init__(exelist) 206 self.id = 'rlink' 207 208 def can_linker_accept_rsp(self) -> bool: 209 return False 210 211 def get_output_args(self, target: str) -> T.List[str]: 212 return ['-output={}'.format(target)] 213 214 def get_linker_always_args(self) -> T.List[str]: 215 return ['-nologo', '-form=library'] 216 217 218class Xc16Linker(StaticLinker): 219 220 def __init__(self, exelist: T.List[str]): 221 super().__init__(exelist) 222 self.id = 'xc16-ar' 223 224 def can_linker_accept_rsp(self) -> bool: 225 return False 226 227 def get_output_args(self, target: str) -> T.List[str]: 228 return ['{}'.format(target)] 229 230 def get_linker_always_args(self) -> T.List[str]: 231 return ['rcs'] 232 233 234class C2000Linker(StaticLinker): 235 236 def __init__(self, exelist: T.List[str]): 237 super().__init__(exelist) 238 self.id = 'ar2000' 239 240 def can_linker_accept_rsp(self) -> bool: 241 return False 242 243 def get_output_args(self, target: str) -> T.List[str]: 244 return ['{}'.format(target)] 245 246 def get_linker_always_args(self) -> T.List[str]: 247 return ['-r'] 248 249 250def prepare_rpaths(raw_rpaths: str, build_dir: str, from_dir: str) -> T.List[str]: 251 # The rpaths we write must be relative if they point to the build dir, 252 # because otherwise they have different length depending on the build 253 # directory. This breaks reproducible builds. 254 internal_format_rpaths = [evaluate_rpath(p, build_dir, from_dir) for p in raw_rpaths] 255 ordered_rpaths = order_rpaths(internal_format_rpaths) 256 return ordered_rpaths 257 258 259def order_rpaths(rpath_list: T.List[str]) -> T.List[str]: 260 # We want rpaths that point inside our build dir to always override 261 # those pointing to other places in the file system. This is so built 262 # binaries prefer our libraries to the ones that may lie somewhere 263 # in the file system, such as /lib/x86_64-linux-gnu. 264 # 265 # The correct thing to do here would be C++'s std::stable_partition. 266 # Python standard library does not have it, so replicate it with 267 # sort, which is guaranteed to be stable. 268 return sorted(rpath_list, key=os.path.isabs) 269 270 271def evaluate_rpath(p: str, build_dir: str, from_dir: str) -> str: 272 if p == from_dir: 273 return '' # relpath errors out in this case 274 elif os.path.isabs(p): 275 return p # These can be outside of build dir. 276 else: 277 return os.path.relpath(os.path.join(build_dir, p), os.path.join(build_dir, from_dir)) 278 279 280class LinkerEnvVarsMixin(metaclass=abc.ABCMeta): 281 282 """Mixin reading LDFLAGS from the environment.""" 283 284 @staticmethod 285 def get_args_from_envvars(for_machine: mesonlib.MachineChoice, 286 is_cross: bool) -> T.List[str]: 287 raw_value = get_env_var(for_machine, is_cross, 'LDFLAGS') 288 if raw_value is not None: 289 return mesonlib.split_args(raw_value) 290 else: 291 return [] 292 293class DynamicLinker(LinkerEnvVarsMixin, metaclass=abc.ABCMeta): 294 295 """Base class for dynamic linkers.""" 296 297 _BUILDTYPE_ARGS = { 298 'plain': [], 299 'debug': [], 300 'debugoptimized': [], 301 'release': [], 302 'minsize': [], 303 'custom': [], 304 } # type: T.Dict[str, T.List[str]] 305 306 def _apply_prefix(self, arg: T.Union[str, T.List[str]]) -> T.List[str]: 307 args = [arg] if isinstance(arg, str) else arg 308 if self.prefix_arg is None: 309 return args 310 elif isinstance(self.prefix_arg, str): 311 return [self.prefix_arg + arg for arg in args] 312 ret = [] 313 for arg in args: 314 ret += self.prefix_arg + [arg] 315 return ret 316 317 def __init__(self, id_: str, exelist: T.List[str], 318 for_machine: mesonlib.MachineChoice, prefix_arg: T.Union[str, T.List[str]], 319 always_args: T.List[str], *, version: str = 'unknown version'): 320 self.exelist = exelist 321 self.for_machine = for_machine 322 self.version = version 323 self.id = id_ 324 self.prefix_arg = prefix_arg 325 self.always_args = always_args 326 327 def __repr__(self) -> str: 328 return '<{}: v{} `{}`>'.format(type(self).__name__, self.version, ' '.join(self.exelist)) 329 330 def get_id(self) -> str: 331 return self.id 332 333 def get_version_string(self) -> str: 334 return '({} {})'.format(self.id, self.version) 335 336 def get_exelist(self) -> T.List[str]: 337 return self.exelist.copy() 338 339 def get_accepts_rsp(self) -> bool: 340 # rsp files are only used when building on Windows because we want to 341 # avoid issues with quoting and max argument length 342 return mesonlib.is_windows() 343 344 def get_always_args(self) -> T.List[str]: 345 return self.always_args.copy() 346 347 def get_lib_prefix(self) -> str: 348 return '' 349 350 # XXX: is use_ldflags a compiler or a linker attribute? 351 352 def get_option_args(self, options: 'OptionDictType') -> T.List[str]: 353 return [] 354 355 def has_multi_arguments(self, args: T.List[str], env: 'Environment') -> T.Tuple[bool, bool]: 356 m = 'Language {} does not support has_multi_link_arguments.' 357 raise mesonlib.EnvironmentException(m.format(self.id)) 358 359 def get_debugfile_name(self, targetfile: str) -> str: 360 '''Name of debug file written out (see below)''' 361 return None 362 363 def get_debugfile_args(self, targetfile: str) -> T.List[str]: 364 """Some compilers (MSVC) write debug into a separate file. 365 366 This method takes the target object path and returns a list of 367 commands to append to the linker invocation to control where that 368 file is written. 369 """ 370 return [] 371 372 def get_std_shared_lib_args(self) -> T.List[str]: 373 return [] 374 375 def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]: 376 return self.get_std_shared_lib_args() 377 378 def get_pie_args(self) -> T.List[str]: 379 # TODO: this really needs to take a boolean and return the args to 380 # disable pie, otherwise it only acts to enable pie if pie *isn't* the 381 # default. 382 m = 'Linker {} does not support position-independent executable' 383 raise mesonlib.EnvironmentException(m.format(self.id)) 384 385 def get_lto_args(self) -> T.List[str]: 386 return [] 387 388 def sanitizer_args(self, value: str) -> T.List[str]: 389 return [] 390 391 def get_buildtype_args(self, buildtype: str) -> T.List[str]: 392 # We can override these in children by just overriding the 393 # _BUILDTYPE_ARGS value. 394 return self._BUILDTYPE_ARGS[buildtype] 395 396 def get_asneeded_args(self) -> T.List[str]: 397 return [] 398 399 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 400 raise mesonlib.EnvironmentException( 401 'Linker {} does not support link_whole'.format(self.id)) 402 403 def get_allow_undefined_args(self) -> T.List[str]: 404 raise mesonlib.EnvironmentException( 405 'Linker {} does not support allow undefined'.format(self.id)) 406 407 @abc.abstractmethod 408 def get_output_args(self, outname: str) -> T.List[str]: 409 pass 410 411 def get_coverage_args(self) -> T.List[str]: 412 m = "Linker {} doesn't implement coverage data generation.".format(self.id) 413 raise mesonlib.EnvironmentException(m) 414 415 @abc.abstractmethod 416 def get_search_args(self, dirname: str) -> T.List[str]: 417 pass 418 419 def export_dynamic_args(self, env: 'Environment') -> T.List[str]: 420 return [] 421 422 def import_library_args(self, implibname: str) -> T.List[str]: 423 """The name of the outputted import library. 424 425 This implementation is used only on Windows by compilers that use GNU ld 426 """ 427 return [] 428 429 def thread_flags(self, env: 'Environment') -> T.List[str]: 430 return [] 431 432 def no_undefined_args(self) -> T.List[str]: 433 """Arguments to error if there are any undefined symbols at link time. 434 435 This is the inverse of get_allow_undefined_args(). 436 437 TODO: A future cleanup might merge this and 438 get_allow_undefined_args() into a single method taking a 439 boolean 440 """ 441 return [] 442 443 def fatal_warnings(self) -> T.List[str]: 444 """Arguments to make all warnings errors.""" 445 return [] 446 447 def headerpad_args(self) -> T.List[str]: 448 # Only used by the Apple linker 449 return [] 450 451 def bitcode_args(self) -> T.List[str]: 452 raise mesonlib.MesonException('This linker does not support bitcode bundles') 453 454 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 455 rpath_paths: str, build_rpath: str, 456 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 457 return ([], set()) 458 459 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 460 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 461 is_shared_module: bool) -> T.List[str]: 462 return [] 463 464 465class PosixDynamicLinkerMixin: 466 467 """Mixin class for POSIX-ish linkers. 468 469 This is obviously a pretty small subset of the linker interface, but 470 enough dynamic linkers that meson supports are POSIX-like but not 471 GNU-like that it makes sense to split this out. 472 """ 473 474 def get_output_args(self, outname: str) -> T.List[str]: 475 return ['-o', outname] 476 477 def get_std_shared_lib_args(self) -> T.List[str]: 478 return ['-shared'] 479 480 def get_search_args(self, dirname: str) -> T.List[str]: 481 return ['-L' + dirname] 482 483 484class GnuLikeDynamicLinkerMixin: 485 486 """Mixin class for dynamic linkers that provides gnu-like interface. 487 488 This acts as a base for the GNU linkers (bfd and gold), LLVM's lld, and 489 other linkers like GNU-ld. 490 """ 491 492 _BUILDTYPE_ARGS = { 493 'plain': [], 494 'debug': [], 495 'debugoptimized': [], 496 'release': ['-O1'], 497 'minsize': [], 498 'custom': [], 499 } # type: T.Dict[str, T.List[str]] 500 501 def get_buildtype_args(self, buildtype: str) -> T.List[str]: 502 # We can override these in children by just overriding the 503 # _BUILDTYPE_ARGS value. 504 return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]]) 505 506 def get_pie_args(self) -> T.List[str]: 507 return ['-pie'] 508 509 def get_asneeded_args(self) -> T.List[str]: 510 return self._apply_prefix('--as-needed') 511 512 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 513 if not args: 514 return args 515 return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive') 516 517 def get_allow_undefined_args(self) -> T.List[str]: 518 return self._apply_prefix('--allow-shlib-undefined') 519 520 def get_lto_args(self) -> T.List[str]: 521 return ['-flto'] 522 523 def sanitizer_args(self, value: str) -> T.List[str]: 524 if value == 'none': 525 return [] 526 return ['-fsanitize=' + value] 527 528 def get_coverage_args(self) -> T.List[str]: 529 return ['--coverage'] 530 531 def export_dynamic_args(self, env: 'Environment') -> T.List[str]: 532 m = env.machines[self.for_machine] 533 if m.is_windows() or m.is_cygwin(): 534 return self._apply_prefix('--export-all-symbols') 535 return self._apply_prefix('-export-dynamic') 536 537 def import_library_args(self, implibname: str) -> T.List[str]: 538 return self._apply_prefix('--out-implib=' + implibname) 539 540 def thread_flags(self, env: 'Environment') -> T.List[str]: 541 if env.machines[self.for_machine].is_haiku(): 542 return [] 543 return ['-pthread'] 544 545 def no_undefined_args(self) -> T.List[str]: 546 return self._apply_prefix('--no-undefined') 547 548 def fatal_warnings(self) -> T.List[str]: 549 return self._apply_prefix('--fatal-warnings') 550 551 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 552 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 553 is_shared_module: bool) -> T.List[str]: 554 m = env.machines[self.for_machine] 555 if m.is_windows() or m.is_cygwin(): 556 # For PE/COFF the soname argument has no effect 557 return [] 558 sostr = '' if soversion is None else '.' + soversion 559 return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)) 560 561 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 562 rpath_paths: str, build_rpath: str, 563 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 564 m = env.machines[self.for_machine] 565 if m.is_windows() or m.is_cygwin(): 566 return ([], set()) 567 if not rpath_paths and not install_rpath and not build_rpath: 568 return ([], set()) 569 args = [] 570 origin_placeholder = '$ORIGIN' 571 processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) 572 # Need to deduplicate rpaths, as macOS's install_name_tool 573 # is *very* allergic to duplicate -delete_rpath arguments 574 # when calling depfixer on installation. 575 all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) 576 rpath_dirs_to_remove = set() 577 for p in all_paths: 578 rpath_dirs_to_remove.add(p.encode('utf8')) 579 # Build_rpath is used as-is (it is usually absolute). 580 if build_rpath != '': 581 all_paths.add(build_rpath) 582 for p in build_rpath.split(':'): 583 rpath_dirs_to_remove.add(p.encode('utf8')) 584 585 # TODO: should this actually be "for (dragonfly|open)bsd"? 586 if mesonlib.is_dragonflybsd() or mesonlib.is_openbsd(): 587 # This argument instructs the compiler to record the value of 588 # ORIGIN in the .dynamic section of the elf. On Linux this is done 589 # by default, but is not on dragonfly/openbsd for some reason. Without this 590 # $ORIGIN in the runtime path will be undefined and any binaries 591 # linked against local libraries will fail to resolve them. 592 args.extend(self._apply_prefix('-z,origin')) 593 594 # In order to avoid relinking for RPATH removal, the binary needs to contain just 595 # enough space in the ELF header to hold the final installation RPATH. 596 paths = ':'.join(all_paths) 597 if len(paths) < len(install_rpath): 598 padding = 'X' * (len(install_rpath) - len(paths)) 599 if not paths: 600 paths = padding 601 else: 602 paths = paths + ':' + padding 603 args.extend(self._apply_prefix('-rpath,' + paths)) 604 605 # TODO: should this actually be "for solaris/sunos"? 606 if mesonlib.is_sunos(): 607 return (args, rpath_dirs_to_remove) 608 609 # Rpaths to use while linking must be absolute. These are not 610 # written to the binary. Needed only with GNU ld: 611 # https://sourceware.org/bugzilla/show_bug.cgi?id=16936 612 # Not needed on Windows or other platforms that don't use RPATH 613 # https://github.com/mesonbuild/meson/issues/1897 614 # 615 # In addition, this linker option tends to be quite long and some 616 # compilers have trouble dealing with it. That's why we will include 617 # one option per folder, like this: 618 # 619 # -Wl,-rpath-link,/path/to/folder1 -Wl,-rpath,/path/to/folder2 ... 620 # 621 # ...instead of just one single looooong option, like this: 622 # 623 # -Wl,-rpath-link,/path/to/folder1:/path/to/folder2:... 624 for p in rpath_paths: 625 args.extend(self._apply_prefix('-rpath-link,' + os.path.join(build_dir, p))) 626 627 return (args, rpath_dirs_to_remove) 628 629 630class AppleDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): 631 632 """Apple's ld implementation.""" 633 634 def __init__(self, *args, **kwargs): 635 super().__init__('ld64', *args, **kwargs) 636 637 def get_asneeded_args(self) -> T.List[str]: 638 return self._apply_prefix('-dead_strip_dylibs') 639 640 def get_allow_undefined_args(self) -> T.List[str]: 641 return self._apply_prefix('-undefined,dynamic_lookup') 642 643 def get_std_shared_module_args(self, options: 'OptionDictType') -> T.List[str]: 644 return ['-bundle'] + self._apply_prefix('-undefined,dynamic_lookup') 645 646 def get_pie_args(self) -> T.List[str]: 647 return ['-pie'] 648 649 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 650 result = [] # type: T.List[str] 651 for a in args: 652 result.extend(self._apply_prefix('-force_load')) 653 result.append(a) 654 return result 655 656 def get_coverage_args(self) -> T.List[str]: 657 return ['--coverage'] 658 659 def sanitizer_args(self, value: str) -> T.List[str]: 660 if value == 'none': 661 return [] 662 return ['-fsanitize=' + value] 663 664 def no_undefined_args(self) -> T.List[str]: 665 return self._apply_prefix('-undefined,error') 666 667 def headerpad_args(self) -> T.List[str]: 668 return self._apply_prefix('-headerpad_max_install_names') 669 670 def bitcode_args(self) -> T.List[str]: 671 return self._apply_prefix('-bitcode_bundle') 672 673 def fatal_warnings(self) -> T.List[str]: 674 return self._apply_prefix('-fatal_warnings') 675 676 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 677 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 678 is_shared_module: bool) -> T.List[str]: 679 if is_shared_module: 680 return [] 681 install_name = ['@rpath/', prefix, shlib_name] 682 if soversion is not None: 683 install_name.append('.' + soversion) 684 install_name.append('.dylib') 685 args = ['-install_name', ''.join(install_name)] 686 if darwin_versions: 687 args.extend(['-compatibility_version', darwin_versions[0], 688 '-current_version', darwin_versions[1]]) 689 return args 690 691 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 692 rpath_paths: str, build_rpath: str, 693 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 694 if not rpath_paths and not install_rpath and not build_rpath: 695 return ([], set()) 696 args = [] 697 # @loader_path is the equivalent of $ORIGIN on macOS 698 # https://stackoverflow.com/q/26280738 699 origin_placeholder = '@loader_path' 700 processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) 701 all_paths = mesonlib.OrderedSet([os.path.join(origin_placeholder, p) for p in processed_rpaths]) 702 if build_rpath != '': 703 all_paths.add(build_rpath) 704 for rp in all_paths: 705 args.extend(self._apply_prefix('-rpath,' + rp)) 706 707 return (args, set()) 708 709 710class GnuDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): 711 712 """Representation of GNU ld.bfd and ld.gold.""" 713 714 def get_accepts_rsp(self) -> bool: 715 return True; 716 717 718class GnuGoldDynamicLinker(GnuDynamicLinker): 719 720 def __init__(self, *args, **kwargs): 721 super().__init__('ld.gold', *args, **kwargs) 722 723 724class GnuBFDDynamicLinker(GnuDynamicLinker): 725 726 def __init__(self, *args, **kwargs): 727 super().__init__('ld.bfd', *args, **kwargs) 728 729 730class LLVMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): 731 732 """Representation of LLVM's ld.lld linker. 733 734 This is only the gnu-like linker, not the apple like or link.exe like 735 linkers. 736 """ 737 738 def __init__(self, *args, **kwargs): 739 super().__init__('ld.lld', *args, **kwargs) 740 741 # Some targets don't seem to support this argument (windows, wasm, ...) 742 _, _, e = mesonlib.Popen_safe(self.exelist + self._apply_prefix('--allow-shlib-undefined')) 743 self.has_allow_shlib_undefined = not ('unknown argument: --allow-shlib-undefined' in e) 744 745 def get_allow_undefined_args(self) -> T.List[str]: 746 if self.has_allow_shlib_undefined: 747 return self._apply_prefix('--allow-shlib-undefined') 748 return [] 749 750 751class WASMDynamicLinker(GnuLikeDynamicLinkerMixin, PosixDynamicLinkerMixin, DynamicLinker): 752 753 """Emscripten's wasm-ld.""" 754 755 def __init__(self, *args, **kwargs): 756 super().__init__('ld.wasm', *args, **kwargs) 757 758 def thread_link_flags(self, env: 'Environment') -> T.List[str]: 759 args = ['-s', 'USE_PTHREADS=1'] 760 count = env.coredata.compiler_options[self.for_machine]['{}_thread_count'.format(self.language)].value # type: int 761 if count: 762 args.extend(['-s', 'PTHREAD_POOL_SIZE={}'.format(count)]) 763 return args 764 765 def get_allow_undefined_args(self) -> T.List[str]: 766 return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=0'] 767 768 def no_undefined_args(self) -> T.List[str]: 769 return ['-s', 'ERROR_ON_UNDEFINED_SYMBOLS=1'] 770 771 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 772 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 773 is_shared_module: bool) -> T.List[str]: 774 raise mesonlib.MesonException('{} does not support shared libraries.'.format(self.id)) 775 776 def get_asneeded_args(self) -> T.List[str]: 777 return [] 778 779 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 780 rpath_paths: str, build_rpath: str, 781 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 782 return ([], set()) 783 784 785class CcrxDynamicLinker(DynamicLinker): 786 787 """Linker for Renesis CCrx compiler.""" 788 789 def __init__(self, for_machine: mesonlib.MachineChoice, 790 *, version: str = 'unknown version'): 791 super().__init__('rlink', ['rlink.exe'], for_machine, '', [], 792 version=version) 793 794 def get_accepts_rsp(self) -> bool: 795 return False 796 797 def get_lib_prefix(self) -> str: 798 return '-lib=' 799 800 def get_std_shared_lib_args(self) -> T.List[str]: 801 return [] 802 803 def get_output_args(self, outputname: str) -> T.List[str]: 804 return ['-output={}'.format(outputname)] 805 806 def get_search_args(self, dirname: str) -> 'T.NoReturn': 807 raise EnvironmentError('rlink.exe does not have a search dir argument') 808 809 def get_allow_undefined_args(self) -> T.List[str]: 810 return [] 811 812 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 813 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 814 is_shared_module: bool) -> T.List[str]: 815 return [] 816 817 818class Xc16DynamicLinker(DynamicLinker): 819 820 """Linker for Microchip XC16 compiler.""" 821 822 def __init__(self, for_machine: mesonlib.MachineChoice, 823 *, version: str = 'unknown version'): 824 super().__init__('xc16-gcc', ['xc16-gcc.exe'], for_machine, '', [], 825 version=version) 826 827 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 828 if not args: 829 return args 830 return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group') 831 832 def get_accepts_rsp(self) -> bool: 833 return False 834 835 def get_lib_prefix(self) -> str: 836 return '' 837 838 def get_std_shared_lib_args(self) -> T.List[str]: 839 return [] 840 841 def get_output_args(self, outputname: str) -> T.List[str]: 842 return ['-o{}'.format(outputname)] 843 844 def get_search_args(self, dirname: str) -> 'T.NoReturn': 845 raise EnvironmentError('xc16-gcc.exe does not have a search dir argument') 846 847 def get_allow_undefined_args(self) -> T.List[str]: 848 return [] 849 850 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 851 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 852 is_shared_module: bool) -> T.List[str]: 853 return [] 854 855 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 856 rpath_paths: str, build_rpath: str, 857 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 858 return ([], set()) 859 860 861class C2000DynamicLinker(DynamicLinker): 862 863 """Linker for Texas Instruments C2000 compiler.""" 864 865 def __init__(self, for_machine: mesonlib.MachineChoice, 866 *, version: str = 'unknown version'): 867 super().__init__('cl2000', ['cl2000.exe'], for_machine, '', [], 868 version=version) 869 870 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 871 if not args: 872 return args 873 return self._apply_prefix('--start-group') + args + self._apply_prefix('--end-group') 874 875 def get_accepts_rsp(self) -> bool: 876 return False 877 878 def get_lib_prefix(self) -> str: 879 return '-l=' 880 881 def get_std_shared_lib_args(self) -> T.List[str]: 882 return [] 883 884 def get_output_args(self, outputname: str) -> T.List[str]: 885 return ['-z', '--output_file={}'.format(outputname)] 886 887 def get_search_args(self, dirname: str) -> 'T.NoReturn': 888 raise EnvironmentError('cl2000.exe does not have a search dir argument') 889 890 def get_allow_undefined_args(self) -> T.List[str]: 891 return [] 892 893 def get_always_args(self) -> T.List[str]: 894 return [] 895 896 897class ArmDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): 898 899 """Linker for the ARM compiler.""" 900 901 def __init__(self, for_machine: mesonlib.MachineChoice, 902 *, version: str = 'unknown version'): 903 super().__init__('armlink', ['armlink'], for_machine, '', [], 904 version=version) 905 906 def get_accepts_rsp(self) -> bool: 907 return False 908 909 def get_std_shared_lib_args(self) -> 'T.NoReturn': 910 raise mesonlib.MesonException('The Arm Linkers do not support shared libraries') 911 912 def get_allow_undefined_args(self) -> T.List[str]: 913 return [] 914 915 916class ArmClangDynamicLinker(ArmDynamicLinker): 917 918 """Linker used with ARM's clang fork. 919 920 The interface is similar enough to the old ARM ld that it inherits and 921 extends a few things as needed. 922 """ 923 924 def export_dynamic_args(self, env: 'Environment') -> T.List[str]: 925 return ['--export_dynamic'] 926 927 def import_library_args(self, implibname: str) -> T.List[str]: 928 return ['--symdefs=' + implibname] 929 930 931class PGIDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): 932 933 """PGI linker.""" 934 935 def __init__(self, *args, **kwargs): 936 super().__init__('pgi', *args, **kwargs) 937 938 def get_allow_undefined_args(self) -> T.List[str]: 939 return [] 940 941 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 942 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 943 is_shared_module: bool) -> T.List[str]: 944 return [] 945 946 def get_std_shared_lib_args(self) -> T.List[str]: 947 # PGI -shared is Linux only. 948 if mesonlib.is_windows(): 949 return ['-Bdynamic', '-Mmakedll'] 950 elif mesonlib.is_linux(): 951 return ['-shared'] 952 return [] 953 954 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 955 rpath_paths: str, build_rpath: str, 956 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 957 if not env.machines[self.for_machine].is_windows(): 958 return (['-R' + os.path.join(build_dir, p) for p in rpath_paths], set()) 959 return ([], set()) 960 961 962class PGIStaticLinker(StaticLinker): 963 def __init__(self, exelist: T.List[str]): 964 super().__init__(exelist) 965 self.id = 'ar' 966 self.std_args = ['-r'] 967 968 def get_std_link_args(self) -> T.List[str]: 969 return self.std_args 970 971 def get_output_args(self, target: str) -> T.List[str]: 972 return [target] 973 974 975class VisualStudioLikeLinkerMixin: 976 977 _BUILDTYPE_ARGS = { 978 'plain': [], 979 'debug': [], 980 'debugoptimized': [], 981 # The otherwise implicit REF and ICF linker optimisations are disabled by 982 # /DEBUG. REF implies ICF. 983 'release': ['/OPT:REF'], 984 'minsize': ['/INCREMENTAL:NO', '/OPT:REF'], 985 'custom': [], 986 } # type: T.Dict[str, T.List[str]] 987 988 def __init__(self, *args, direct: bool = True, machine: str = 'x86', **kwargs): 989 super().__init__(*args, **kwargs) 990 self.machine = machine 991 992 def get_buildtype_args(self, buildtype: str) -> T.List[str]: 993 return mesonlib.listify([self._apply_prefix(a) for a in self._BUILDTYPE_ARGS[buildtype]]) 994 995 def invoked_by_compiler(self) -> bool: 996 return not self.direct 997 998 def get_output_args(self, outputname: str) -> T.List[str]: 999 return self._apply_prefix(['/MACHINE:' + self.machine, '/OUT:' + outputname]) 1000 1001 def get_always_args(self) -> T.List[str]: 1002 return self._apply_prefix('/nologo') + super().get_always_args() 1003 1004 def get_search_args(self, dirname: str) -> T.List[str]: 1005 return self._apply_prefix('/LIBPATH:' + dirname) 1006 1007 def get_std_shared_lib_args(self) -> T.List[str]: 1008 return self._apply_prefix('/DLL') 1009 1010 def get_debugfile_name(self, targetfile: str) -> str: 1011 basename = targetfile.rsplit('.', maxsplit=1)[0] 1012 return basename + '.pdb' 1013 1014 def get_debugfile_args(self, targetfile: str) -> T.List[str]: 1015 return self._apply_prefix(['/DEBUG', '/PDB:' + self.get_debugfile_name(targetfile)]) 1016 1017 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 1018 # Only since VS2015 1019 args = mesonlib.listify(args) 1020 l = [] # T.List[str] 1021 for a in args: 1022 l.extend(self._apply_prefix('/WHOLEARCHIVE:' + a)) 1023 return l 1024 1025 def get_allow_undefined_args(self) -> T.List[str]: 1026 return [] 1027 1028 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 1029 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 1030 is_shared_module: bool) -> T.List[str]: 1031 return [] 1032 1033 def import_library_args(self, implibname: str) -> T.List[str]: 1034 """The command to generate the import library.""" 1035 return self._apply_prefix(['/IMPLIB:' + implibname]) 1036 1037 1038class MSVCDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): 1039 1040 """Microsoft's Link.exe.""" 1041 1042 def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *, 1043 exelist: T.Optional[T.List[str]] = None, 1044 prefix: T.Union[str, T.List[str]] = '', 1045 machine: str = 'x86', version: str = 'unknown version', 1046 direct: bool = True): 1047 super().__init__('link', exelist or ['link.exe'], for_machine, 1048 prefix, always_args, machine=machine, version=version, direct=direct) 1049 1050 def get_always_args(self) -> T.List[str]: 1051 return self._apply_prefix(['/nologo', '/release']) + super().get_always_args() 1052 1053 1054class ClangClDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): 1055 1056 """Clang's lld-link.exe.""" 1057 1058 def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], *, 1059 exelist: T.Optional[T.List[str]] = None, 1060 prefix: T.Union[str, T.List[str]] = '', 1061 machine: str = 'x86', version: str = 'unknown version', 1062 direct: bool = True): 1063 super().__init__('lld-link', exelist or ['lld-link.exe'], for_machine, 1064 prefix, always_args, machine=machine, version=version, direct=direct) 1065 1066 1067class XilinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): 1068 1069 """Intel's Xilink.exe.""" 1070 1071 def __init__(self, for_machine: mesonlib.MachineChoice, always_args: T.List[str], 1072 *, version: str = 'unknown version'): 1073 super().__init__('xilink', ['xilink.exe'], for_machine, '', always_args, version=version) 1074 1075 1076class SolarisDynamicLinker(PosixDynamicLinkerMixin, DynamicLinker): 1077 1078 """Sys-V derived linker used on Solaris and OpenSolaris.""" 1079 1080 def __init__(self, *args, **kwargs): 1081 super().__init__('ld.solaris', *args, **kwargs) 1082 1083 def get_link_whole_for(self, args: T.List[str]) -> T.List[str]: 1084 if not args: 1085 return args 1086 return self._apply_prefix('--whole-archive') + args + self._apply_prefix('--no-whole-archive') 1087 1088 def get_pie_args(self) -> T.List[str]: 1089 # Available in Solaris 11.2 and later 1090 return ['-z', 'type=pie'] 1091 1092 def get_asneeded_args(self) -> T.List[str]: 1093 return self._apply_prefix(['-z', 'ignore']) 1094 1095 def no_undefined_args(self) -> T.List[str]: 1096 return ['-z', 'defs'] 1097 1098 def get_allow_undefined_args(self) -> T.List[str]: 1099 return ['-z', 'nodefs'] 1100 1101 def fatal_warnings(self) -> T.List[str]: 1102 return ['-z', 'fatal-warnings'] 1103 1104 def build_rpath_args(self, env: 'Environment', build_dir: str, from_dir: str, 1105 rpath_paths: str, build_rpath: str, 1106 install_rpath: str) -> T.Tuple[T.List[str], T.Set[bytes]]: 1107 if not rpath_paths and not install_rpath and not build_rpath: 1108 return ([], set()) 1109 processed_rpaths = prepare_rpaths(rpath_paths, build_dir, from_dir) 1110 all_paths = mesonlib.OrderedSet([os.path.join('$ORIGIN', p) for p in processed_rpaths]) 1111 if build_rpath != '': 1112 all_paths.add(build_rpath) 1113 1114 # In order to avoid relinking for RPATH removal, the binary needs to contain just 1115 # enough space in the ELF header to hold the final installation RPATH. 1116 paths = ':'.join(all_paths) 1117 if len(paths) < len(install_rpath): 1118 padding = 'X' * (len(install_rpath) - len(paths)) 1119 if not paths: 1120 paths = padding 1121 else: 1122 paths = paths + ':' + padding 1123 return (self._apply_prefix('-rpath,{}'.format(paths)), set()) 1124 1125 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 1126 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 1127 is_shared_module: bool) -> T.List[str]: 1128 sostr = '' if soversion is None else '.' + soversion 1129 return self._apply_prefix('-soname,{}{}.{}{}'.format(prefix, shlib_name, suffix, sostr)) 1130 1131 1132class OptlinkDynamicLinker(VisualStudioLikeLinkerMixin, DynamicLinker): 1133 1134 """Digital Mars dynamic linker for windows.""" 1135 1136 def __init__(self, exelist: T.List[str], for_machine: mesonlib.MachineChoice, 1137 *, version: str = 'unknown version'): 1138 # Use optlink instead of link so we don't interfer with other link.exe 1139 # implementations. 1140 super().__init__('optlink', exelist, for_machine, '', [], version=version) 1141 1142 def get_allow_undefined_args(self) -> T.List[str]: 1143 return [] 1144 1145 def get_debugfile_args(self, targetfile: str) -> T.List[str]: 1146 # Optlink does not generate pdb files. 1147 return [] 1148 1149 def get_always_args(self) -> T.List[str]: 1150 return [] 1151 1152 1153class CudaLinker(PosixDynamicLinkerMixin, DynamicLinker): 1154 """Cuda linker (nvlink)""" 1155 1156 def __init__(self, *args, **kwargs): 1157 super().__init__('nvlink', *args, **kwargs) 1158 1159 @staticmethod 1160 def parse_version(): 1161 version_cmd = ['nvlink', '--version'] 1162 try: 1163 _, out, _ = mesonlib.Popen_safe(version_cmd) 1164 except OSError: 1165 return 'unknown version' 1166 # Output example: 1167 # nvlink: NVIDIA (R) Cuda linker 1168 # Copyright (c) 2005-2018 NVIDIA Corporation 1169 # Built on Sun_Sep_30_21:09:22_CDT_2018 1170 # Cuda compilation tools, release 10.0, V10.0.166 1171 # we need the most verbose version output. Luckily starting with V 1172 return out.strip().split('V')[-1] 1173 1174 def get_accepts_rsp(self) -> bool: 1175 # nvcc does not support response files 1176 return False 1177 1178 def get_lib_prefix(self) -> str: 1179 if not mesonlib.is_windows(): 1180 return '' 1181 # nvcc doesn't recognize Meson's default .a extension for static libraries on 1182 # Windows and passes it to cl as an object file, resulting in 'warning D9024 : 1183 # unrecognized source file type 'xxx.a', object file assumed'. 1184 # 1185 # nvcc's --library= option doesn't help: it takes the library name without the 1186 # extension and assumes that the extension on Windows is .lib; prefixing the 1187 # library with -Xlinker= seems to work. 1188 from .compilers import CudaCompiler 1189 return CudaCompiler.LINKER_PREFIX 1190 1191 def fatal_warnings(self) -> T.List[str]: 1192 return ['--warning-as-error'] 1193 1194 def get_allow_undefined_args(self) -> T.List[str]: 1195 return [] 1196 1197 def get_soname_args(self, env: 'Environment', prefix: str, shlib_name: str, 1198 suffix: str, soversion: str, darwin_versions: T.Tuple[str, str], 1199 is_shared_module: bool) -> T.List[str]: 1200 return [] 1201