1#!/usr/bin/python 2# 3# Copyright (C) 2013-2020 Free Software Foundation, Inc. 4# 5# This script is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3, or (at your option) 8# any later version. 9 10# This script adjusts the copyright notices at the top of source files 11# so that they have the form: 12# 13# Copyright XXXX-YYYY Free Software Foundation, Inc. 14# 15# It doesn't change code that is known to be maintained elsewhere or 16# that carries a non-FSF copyright. 17# 18# The script also doesn't change testsuite files, except those in 19# libstdc++-v3. This is because libstdc++-v3 has a conformance testsuite, 20# while most tests in other directories are just things that failed at some 21# point in the past. 22# 23# Pass --this-year to the script if you want it to add the current year 24# to all applicable notices. Pass --quilt if you are using quilt and 25# want files to be added to the quilt before being changed. 26# 27# By default the script will update all directories for which the 28# output has been vetted. You can instead pass the names of individual 29# directories, including those that haven't been approved. So: 30# 31# update-copyright.py --this-year 32# 33# is the command that would be used at the beginning of a year to update 34# all copyright notices (and possibly at other times to check whether 35# new files have been added with old years). On the other hand: 36# 37# update-copyright.py --this-year libitm 38# 39# would run the script on just libitm/. 40# 41# Note that things like --version output strings must be updated before 42# this script is run. There's already a separate procedure for that. 43 44import os 45import re 46import sys 47import time 48import subprocess 49 50class Errors: 51 def __init__ (self): 52 self.num_errors = 0 53 54 def report (self, filename, string): 55 if filename: 56 string = filename + ': ' + string 57 sys.stderr.write (string + '\n') 58 self.num_errors += 1 59 60 def ok (self): 61 return self.num_errors == 0 62 63class GenericFilter: 64 def __init__ (self): 65 self.skip_files = set() 66 self.skip_dirs = set() 67 self.skip_extensions = set() 68 self.fossilised_files = set() 69 self.own_files = set() 70 71 self.skip_files |= set ([ 72 # Skip licence files. 73 'COPYING', 74 'COPYING.LIB', 75 'COPYING3', 76 'COPYING3.LIB', 77 'LICENSE', 78 'LICENSE.txt', 79 'fdl.texi', 80 'gpl_v3.texi', 81 'fdl-1.3.xml', 82 'gpl-3.0.xml', 83 84 # Skip auto- and libtool-related files 85 'aclocal.m4', 86 'compile', 87 'config.guess', 88 'config.sub', 89 'depcomp', 90 'install-sh', 91 'libtool.m4', 92 'ltmain.sh', 93 'ltoptions.m4', 94 'ltsugar.m4', 95 'ltversion.m4', 96 'lt~obsolete.m4', 97 'missing', 98 'mkdep', 99 'mkinstalldirs', 100 'move-if-change', 101 'shlibpath.m4', 102 'symlink-tree', 103 'ylwrap', 104 105 # Skip FSF mission statement, etc. 106 'gnu.texi', 107 'funding.texi', 108 'appendix_free.xml', 109 110 # Skip imported texinfo files. 111 'texinfo.tex', 112 ]) 113 114 115 def get_line_filter (self, dir, filename): 116 if filename.startswith ('ChangeLog'): 117 # Ignore references to copyright in changelog entries. 118 return re.compile ('\t') 119 120 return None 121 122 def skip_file (self, dir, filename): 123 if filename in self.skip_files: 124 return True 125 126 (base, extension) = os.path.splitext (os.path.join (dir, filename)) 127 if extension in self.skip_extensions: 128 return True 129 130 if extension == '.in': 131 # Skip .in files produced by automake. 132 if os.path.exists (base + '.am'): 133 return True 134 135 # Skip files produced by autogen 136 if (os.path.exists (base + '.def') 137 and os.path.exists (base + '.tpl')): 138 return True 139 140 # Skip configure files produced by autoconf 141 if filename == 'configure': 142 if os.path.exists (base + '.ac'): 143 return True 144 if os.path.exists (base + '.in'): 145 return True 146 147 return False 148 149 def skip_dir (self, dir, subdir): 150 return subdir in self.skip_dirs 151 152 def is_fossilised_file (self, dir, filename): 153 if filename in self.fossilised_files: 154 return True 155 # Only touch current current ChangeLogs. 156 if filename != 'ChangeLog' and filename.find ('ChangeLog') >= 0: 157 return True 158 return False 159 160 def by_package_author (self, dir, filename): 161 return filename in self.own_files 162 163class Copyright: 164 def __init__ (self, errors): 165 self.errors = errors 166 167 # Characters in a range of years. Include '.' for typos. 168 ranges = '[0-9](?:[-0-9.,\s]|\s+and\s+)*[0-9]' 169 170 # Non-whitespace characters in a copyright holder's name. 171 name = '[\w.,-]' 172 173 # Matches one year. 174 self.year_re = re.compile ('[0-9]+') 175 176 # Matches part of a year or copyright holder. 177 self.continuation_re = re.compile (ranges + '|' + name) 178 179 # Matches a full copyright notice: 180 self.copyright_re = re.compile ( 181 # 1: 'Copyright (C)', etc. 182 '([Cc]opyright' 183 '|[Cc]opyright\s+\([Cc]\)' 184 '|[Cc]opyright\s+%s' 185 '|[Cc]opyright\s+©' 186 '|[Cc]opyright\s+@copyright{}' 187 '|copyright = u\'' 188 '|@set\s+copyright[\w-]+)' 189 190 # 2: the years. Include the whitespace in the year, so that 191 # we can remove any excess. 192 '(\s*(?:' + ranges + ',?' 193 '|@value\{[^{}]*\})\s*)' 194 195 # 3: 'by ', if used 196 '(by\s+)?' 197 198 # 4: the copyright holder. Don't allow multiple consecutive 199 # spaces, so that right-margin gloss doesn't get caught 200 # (e.g. gnat_ugn.texi). 201 '(' + name + '(?:\s?' + name + ')*)?') 202 203 # A regexp for notices that might have slipped by. Just matching 204 # 'copyright' is too noisy, and 'copyright.*[0-9]' falls foul of 205 # HTML header markers, so check for 'copyright' and two digits. 206 self.other_copyright_re = re.compile ('copyright.*[0-9][0-9]', 207 re.IGNORECASE) 208 self.comment_re = re.compile('#+|[*]+|;+|%+|//+|@c |dnl ') 209 self.holders = { '@copying': '@copying' } 210 self.holder_prefixes = set() 211 212 # True to 'quilt add' files before changing them. 213 self.use_quilt = False 214 215 # If set, force all notices to include this year. 216 self.max_year = None 217 218 # Goes after the year(s). Could be ', '. 219 self.separator = ' ' 220 221 def add_package_author (self, holder, canon_form = None): 222 if not canon_form: 223 canon_form = holder 224 self.holders[holder] = canon_form 225 index = holder.find (' ') 226 while index >= 0: 227 self.holder_prefixes.add (holder[:index]) 228 index = holder.find (' ', index + 1) 229 230 def add_external_author (self, holder): 231 self.holders[holder] = None 232 233 class BadYear(): 234 def __init__ (self, year): 235 self.year = year 236 237 def __str__ (self): 238 return 'unrecognised year: ' + self.year 239 240 def parse_year (self, string): 241 year = int (string) 242 if len (string) == 2: 243 if year > 70: 244 return year + 1900 245 elif len (string) == 4: 246 return year 247 raise self.BadYear (string) 248 249 def year_range (self, years): 250 year_list = [self.parse_year (year) 251 for year in self.year_re.findall (years)] 252 assert len (year_list) > 0 253 return (min (year_list), max (year_list)) 254 255 def set_use_quilt (self, use_quilt): 256 self.use_quilt = use_quilt 257 258 def include_year (self, year): 259 assert not self.max_year 260 self.max_year = year 261 262 def canonicalise_years (self, dir, filename, filter, years): 263 # Leave texinfo variables alone. 264 if years.startswith ('@value'): 265 return years 266 267 (min_year, max_year) = self.year_range (years) 268 269 # Update the upper bound, if enabled. 270 if self.max_year and not filter.is_fossilised_file (dir, filename): 271 max_year = max (max_year, self.max_year) 272 273 # Use a range. 274 if min_year == max_year: 275 return '%d' % min_year 276 else: 277 return '%d-%d' % (min_year, max_year) 278 279 def strip_continuation (self, line): 280 line = line.lstrip() 281 match = self.comment_re.match (line) 282 if match: 283 line = line[match.end():].lstrip() 284 return line 285 286 def is_complete (self, match): 287 holder = match.group (4) 288 return (holder 289 and (holder not in self.holder_prefixes 290 or holder in self.holders)) 291 292 def update_copyright (self, dir, filename, filter, file, line, match): 293 orig_line = line 294 next_line = None 295 pathname = os.path.join (dir, filename) 296 297 intro = match.group (1) 298 if intro.startswith ('@set'): 299 # Texinfo year variables should always be on one line 300 after_years = line[match.end (2):].strip() 301 if after_years != '': 302 self.errors.report (pathname, 303 'trailing characters in @set: ' 304 + after_years) 305 return (False, orig_line, next_line) 306 else: 307 # If it looks like the copyright is incomplete, add the next line. 308 while not self.is_complete (match): 309 try: 310 next_line = file.next() 311 except StopIteration: 312 break 313 314 # If the next line doesn't look like a proper continuation, 315 # assume that what we've got is complete. 316 continuation = self.strip_continuation (next_line) 317 if not self.continuation_re.match (continuation): 318 break 319 320 # Merge the lines for matching purposes. 321 orig_line += next_line 322 line = line.rstrip() + ' ' + continuation 323 next_line = None 324 325 # Rematch with the longer line, at the original position. 326 match = self.copyright_re.match (line, match.start()) 327 assert match 328 329 holder = match.group (4) 330 331 # Use the filter to test cases where markup is getting in the way. 332 if filter.by_package_author (dir, filename): 333 assert holder not in self.holders 334 335 elif not holder: 336 self.errors.report (pathname, 'missing copyright holder') 337 return (False, orig_line, next_line) 338 339 elif holder not in self.holders: 340 self.errors.report (pathname, 341 'unrecognised copyright holder: ' + holder) 342 return (False, orig_line, next_line) 343 344 else: 345 # See whether the copyright is associated with the package 346 # author. 347 canon_form = self.holders[holder] 348 if not canon_form: 349 return (False, orig_line, next_line) 350 351 # Make sure the author is given in a consistent way. 352 line = (line[:match.start (4)] 353 + canon_form 354 + line[match.end (4):]) 355 356 # Remove any 'by' 357 line = line[:match.start (3)] + line[match.end (3):] 358 359 # Update the copyright years. 360 years = match.group (2).strip() 361 try: 362 canon_form = self.canonicalise_years (dir, filename, filter, years) 363 except self.BadYear as e: 364 self.errors.report (pathname, str (e)) 365 return (False, orig_line, next_line) 366 367 line = (line[:match.start (2)] 368 + ('' if intro.startswith ('copyright = ') else ' ') 369 + canon_form + self.separator 370 + line[match.end (2):]) 371 372 # Use the standard (C) form. 373 if intro.endswith ('right'): 374 intro += ' (C)' 375 elif intro.endswith ('(c)'): 376 intro = intro[:-3] + '(C)' 377 line = line[:match.start (1)] + intro + line[match.end (1):] 378 379 # Strip trailing whitespace 380 line = line.rstrip() + '\n' 381 382 return (line != orig_line, line, next_line) 383 384 def process_file (self, dir, filename, filter): 385 pathname = os.path.join (dir, filename) 386 if filename.endswith ('.tmp'): 387 # Looks like something we tried to create before. 388 try: 389 os.remove (pathname) 390 except OSError: 391 pass 392 return 393 394 lines = [] 395 changed = False 396 line_filter = filter.get_line_filter (dir, filename) 397 mode = None 398 with open (pathname, 'r') as file: 399 prev = None 400 mode = os.fstat (file.fileno()).st_mode 401 for line in file: 402 while line: 403 next_line = None 404 # Leave filtered-out lines alone. 405 if not (line_filter and line_filter.match (line)): 406 match = self.copyright_re.search (line) 407 if match: 408 res = self.update_copyright (dir, filename, filter, 409 file, line, match) 410 (this_changed, line, next_line) = res 411 changed = changed or this_changed 412 413 # Check for copyright lines that might have slipped by. 414 elif self.other_copyright_re.search (line): 415 self.errors.report (pathname, 416 'unrecognised copyright: %s' 417 % line.strip()) 418 lines.append (line) 419 line = next_line 420 421 # If something changed, write the new file out. 422 if changed and self.errors.ok(): 423 tmp_pathname = pathname + '.tmp' 424 with open (tmp_pathname, 'w') as file: 425 for line in lines: 426 file.write (line) 427 os.fchmod (file.fileno(), mode) 428 if self.use_quilt: 429 subprocess.call (['quilt', 'add', pathname]) 430 os.rename (tmp_pathname, pathname) 431 432 def process_tree (self, tree, filter): 433 for (dir, subdirs, filenames) in os.walk (tree): 434 # Don't recurse through directories that should be skipped. 435 for i in xrange (len (subdirs) - 1, -1, -1): 436 if filter.skip_dir (dir, subdirs[i]): 437 del subdirs[i] 438 439 # Handle the files in this directory. 440 for filename in filenames: 441 if filter.skip_file (dir, filename): 442 sys.stdout.write ('Skipping %s\n' 443 % os.path.join (dir, filename)) 444 else: 445 self.process_file (dir, filename, filter) 446 447class CmdLine: 448 def __init__ (self, copyright = Copyright): 449 self.errors = Errors() 450 self.copyright = copyright (self.errors) 451 self.dirs = [] 452 self.default_dirs = [] 453 self.chosen_dirs = [] 454 self.option_handlers = dict() 455 self.option_help = [] 456 457 self.add_option ('--help', 'Print this help', self.o_help) 458 self.add_option ('--quilt', '"quilt add" files before changing them', 459 self.o_quilt) 460 self.add_option ('--this-year', 'Add the current year to every notice', 461 self.o_this_year) 462 463 def add_option (self, name, help, handler): 464 self.option_help.append ((name, help)) 465 self.option_handlers[name] = handler 466 467 def add_dir (self, dir, filter = GenericFilter()): 468 self.dirs.append ((dir, filter)) 469 470 def o_help (self, option = None): 471 sys.stdout.write ('Usage: %s [options] dir1 dir2...\n\n' 472 'Options:\n' % sys.argv[0]) 473 format = '%-15s %s\n' 474 for (what, help) in self.option_help: 475 sys.stdout.write (format % (what, help)) 476 sys.stdout.write ('\nDirectories:\n') 477 478 format = '%-25s' 479 i = 0 480 for (dir, filter) in self.dirs: 481 i += 1 482 if i % 3 == 0 or i == len (self.dirs): 483 sys.stdout.write (dir + '\n') 484 else: 485 sys.stdout.write (format % dir) 486 sys.exit (0) 487 488 def o_quilt (self, option): 489 self.copyright.set_use_quilt (True) 490 491 def o_this_year (self, option): 492 self.copyright.include_year (time.localtime().tm_year) 493 494 def main (self): 495 for arg in sys.argv[1:]: 496 if arg[:1] != '-': 497 self.chosen_dirs.append (arg) 498 elif arg in self.option_handlers: 499 self.option_handlers[arg] (arg) 500 else: 501 self.errors.report (None, 'unrecognised option: ' + arg) 502 if self.errors.ok(): 503 if len (self.chosen_dirs) == 0: 504 self.chosen_dirs = self.default_dirs 505 if len (self.chosen_dirs) == 0: 506 self.o_help() 507 else: 508 for chosen_dir in self.chosen_dirs: 509 canon_dir = os.path.join (chosen_dir, '') 510 count = 0 511 for (dir, filter) in self.dirs: 512 if (dir + os.sep).startswith (canon_dir): 513 count += 1 514 self.copyright.process_tree (dir, filter) 515 if count == 0: 516 self.errors.report (None, 'unrecognised directory: ' 517 + chosen_dir) 518 sys.exit (0 if self.errors.ok() else 1) 519 520#---------------------------------------------------------------------------- 521 522class TopLevelFilter (GenericFilter): 523 def skip_dir (self, dir, subdir): 524 return True 525 526class ConfigFilter (GenericFilter): 527 def __init__ (self): 528 GenericFilter.__init__ (self) 529 530 def skip_file (self, dir, filename): 531 if filename.endswith ('.m4'): 532 pathname = os.path.join (dir, filename) 533 with open (pathname) as file: 534 # Skip files imported from gettext. 535 if file.readline().find ('gettext-') >= 0: 536 return True 537 return GenericFilter.skip_file (self, dir, filename) 538 539class GCCFilter (GenericFilter): 540 def __init__ (self): 541 GenericFilter.__init__ (self) 542 543 self.skip_files |= set ([ 544 # Not part of GCC 545 'math-68881.h', 546 ]) 547 548 self.skip_dirs |= set ([ 549 # Better not create a merge nightmare for the GNAT folks. 550 'ada', 551 552 # Handled separately. 553 'testsuite', 554 ]) 555 556 self.skip_extensions |= set ([ 557 # Maintained by the translation project. 558 '.po', 559 560 # Automatically-generated. 561 '.pot', 562 ]) 563 564 self.fossilised_files |= set ([ 565 # Old news won't be updated. 566 'ONEWS', 567 ]) 568 569class TestsuiteFilter (GenericFilter): 570 def __init__ (self): 571 GenericFilter.__init__ (self) 572 573 self.skip_extensions |= set ([ 574 # Don't change the tests, which could be woend by anyone. 575 '.c', 576 '.C', 577 '.cc', 578 '.d', 579 '.h', 580 '.hs', 581 '.f', 582 '.f90', 583 '.go', 584 '.inc', 585 '.java', 586 ]) 587 588 def skip_file (self, dir, filename): 589 # g++.niklas/README contains historical copyright information 590 # and isn't updated. 591 if filename == 'README' and os.path.basename (dir) == 'g++.niklas': 592 return True 593 # Similarly params/README. 594 if filename == 'README' and os.path.basename (dir) == 'params': 595 return True 596 if filename == 'pdt_5.f03' and os.path.basename (dir) == 'gfortran.dg': 597 return True 598 return GenericFilter.skip_file (self, dir, filename) 599 600class LibCppFilter (GenericFilter): 601 def __init__ (self): 602 GenericFilter.__init__ (self) 603 604 self.skip_extensions |= set ([ 605 # Maintained by the translation project. 606 '.po', 607 608 # Automatically-generated. 609 '.pot', 610 ]) 611 612class LibGCCFilter (GenericFilter): 613 def __init__ (self): 614 GenericFilter.__init__ (self) 615 616 self.skip_dirs |= set ([ 617 # Imported from GLIBC. 618 'soft-fp', 619 ]) 620 621class LibPhobosFilter (GenericFilter): 622 def __init__ (self): 623 GenericFilter.__init__ (self) 624 625 self.skip_files |= set ([ 626 # Source module imported from upstream. 627 'object.d', 628 ]) 629 630 self.skip_dirs |= set ([ 631 # Contains sources imported from upstream. 632 'core', 633 'etc', 634 'gc', 635 'gcstub', 636 'rt', 637 'std', 638 ]) 639 640class LibStdCxxFilter (GenericFilter): 641 def __init__ (self): 642 GenericFilter.__init__ (self) 643 644 self.skip_files |= set ([ 645 # Contains no copyright of its own, but quotes the GPL. 646 'intro.xml', 647 ]) 648 649 self.skip_dirs |= set ([ 650 # Contains automatically-generated sources. 651 'html', 652 653 # The testsuite data files shouldn't be changed. 654 'data', 655 656 # Contains imported images 657 'images', 658 ]) 659 660 self.own_files |= set ([ 661 # Contains markup around the copyright owner. 662 'spine.xml', 663 ]) 664 665 def get_line_filter (self, dir, filename): 666 if filename == 'boost_concept_check.h': 667 return re.compile ('// \(C\) Copyright Jeremy Siek') 668 return GenericFilter.get_line_filter (self, dir, filename) 669 670class GCCCopyright (Copyright): 671 def __init__ (self, errors): 672 Copyright.__init__ (self, errors) 673 674 canon_fsf = 'Free Software Foundation, Inc.' 675 self.add_package_author ('Free Software Foundation', canon_fsf) 676 self.add_package_author ('Free Software Foundation.', canon_fsf) 677 self.add_package_author ('Free Software Foundation Inc.', canon_fsf) 678 self.add_package_author ('Free Software Foundation, Inc', canon_fsf) 679 self.add_package_author ('Free Software Foundation, Inc.', canon_fsf) 680 self.add_package_author ('The Free Software Foundation', canon_fsf) 681 self.add_package_author ('The Free Software Foundation, Inc.', canon_fsf) 682 self.add_package_author ('Software Foundation, Inc.', canon_fsf) 683 684 self.add_external_author ('ARM') 685 self.add_external_author ('AdaCore') 686 self.add_external_author ('Ami Tavory and Vladimir Dreizin, IBM-HRL.') 687 self.add_external_author ('Cavium Networks.') 688 self.add_external_author ('Faraday Technology Corp.') 689 self.add_external_author ('Florida State University') 690 self.add_external_author ('Gerard Jungman') 691 self.add_external_author ('Greg Colvin and Beman Dawes.') 692 self.add_external_author ('Hewlett-Packard Company') 693 self.add_external_author ('Intel Corporation') 694 self.add_external_author ('Information Technology Industry Council.') 695 self.add_external_author ('James Theiler, Brian Gough') 696 self.add_external_author ('Makoto Matsumoto and Takuji Nishimura,') 697 self.add_external_author ('Mentor Graphics Corporation') 698 self.add_external_author ('National Research Council of Canada.') 699 self.add_external_author ('NVIDIA Corporation') 700 self.add_external_author ('Peter Dimov and Multi Media Ltd.') 701 self.add_external_author ('Peter Dimov') 702 self.add_external_author ('Pipeline Associates, Inc.') 703 self.add_external_author ('Regents of the University of California.') 704 self.add_external_author ('Silicon Graphics Computer Systems, Inc.') 705 self.add_external_author ('Silicon Graphics') 706 self.add_external_author ('Stephen L. Moshier') 707 self.add_external_author ('Sun Microsystems, Inc. All rights reserved.') 708 self.add_external_author ('The D Language Foundation, All Rights Reserved') 709 self.add_external_author ('The Go Authors. All rights reserved.') 710 self.add_external_author ('The Go Authors. All rights reserved.') 711 self.add_external_author ('The Go Authors.') 712 self.add_external_author ('The Regents of the University of California.') 713 self.add_external_author ('Unicode, Inc.') 714 self.add_external_author ('University of Toronto.') 715 self.add_external_author ('Yoshinori Sato') 716 717class GCCCmdLine (CmdLine): 718 def __init__ (self): 719 CmdLine.__init__ (self, GCCCopyright) 720 721 self.add_dir ('.', TopLevelFilter()) 722 # boehm-gc is imported from upstream. 723 self.add_dir ('config', ConfigFilter()) 724 # contrib isn't really part of GCC. 725 self.add_dir ('fixincludes') 726 self.add_dir ('gcc', GCCFilter()) 727 self.add_dir (os.path.join ('gcc', 'testsuite'), TestsuiteFilter()) 728 self.add_dir ('gnattools') 729 self.add_dir ('gotools') 730 self.add_dir ('include') 731 # intl is imported from upstream. 732 self.add_dir ('libada') 733 self.add_dir ('libatomic') 734 self.add_dir ('libbacktrace') 735 self.add_dir ('libcc1') 736 self.add_dir ('libcpp', LibCppFilter()) 737 self.add_dir ('libdecnumber') 738 # libffi is imported from upstream. 739 self.add_dir ('libgcc', LibGCCFilter()) 740 self.add_dir ('libgfortran') 741 # libgo is imported from upstream. 742 self.add_dir ('libgomp') 743 self.add_dir ('libhsail-rt') 744 self.add_dir ('libiberty') 745 self.add_dir ('libitm') 746 self.add_dir ('libobjc') 747 # liboffloadmic is imported from upstream. 748 self.add_dir ('libphobos', LibPhobosFilter()) 749 self.add_dir ('libquadmath') 750 # libsanitizer is imported from upstream. 751 self.add_dir ('libssp') 752 self.add_dir ('libstdc++-v3', LibStdCxxFilter()) 753 self.add_dir ('libvtv') 754 self.add_dir ('lto-plugin') 755 # maintainer-scripts maintainer-scripts 756 # zlib is imported from upstream. 757 758 self.default_dirs = [ 759 'gcc', 760 'include', 761 'libada', 762 'libatomic', 763 'libbacktrace', 764 'libcc1', 765 'libcpp', 766 'libdecnumber', 767 'libgcc', 768 'libgfortran', 769 'libgomp', 770 'libhsail-rt', 771 'libiberty', 772 'libitm', 773 'libobjc', 774 'libphobos', 775 'libssp', 776 'libstdc++-v3', 777 'libvtv', 778 'lto-plugin', 779 ] 780 781GCCCmdLine().main() 782