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