Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: tools/mb/mb.py

Issue 2160353003: Implement multi-phase build support in MB. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright 2015 The Chromium Authors. All rights reserved. 2 # Copyright 2015 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """MB - the Meta-Build wrapper around GYP and GN 6 """MB - the Meta-Build wrapper around GYP and GN
7 7
8 MB is a wrapper script for GYP and GN that can be used to generate build files 8 MB is a wrapper script for GYP and GN that can be used to generate build files
9 for sets of canned configurations and analyze them. 9 for sets of canned configurations and analyze them.
10 """ 10 """
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 return 1 71 return 1
72 72
73 def ParseArgs(self, argv): 73 def ParseArgs(self, argv):
74 def AddCommonOptions(subp): 74 def AddCommonOptions(subp):
75 subp.add_argument('-b', '--builder', 75 subp.add_argument('-b', '--builder',
76 help='builder name to look up config from') 76 help='builder name to look up config from')
77 subp.add_argument('-m', '--master', 77 subp.add_argument('-m', '--master',
78 help='master name to look up config from') 78 help='master name to look up config from')
79 subp.add_argument('-c', '--config', 79 subp.add_argument('-c', '--config',
80 help='configuration to analyze') 80 help='configuration to analyze')
81 subp.add_argument('--phase', type=int,
82 help=('build phase for a given build '
83 '(int in [1, 2, ...))'))
81 subp.add_argument('-f', '--config-file', metavar='PATH', 84 subp.add_argument('-f', '--config-file', metavar='PATH',
82 default=self.default_config, 85 default=self.default_config,
83 help='path to config file ' 86 help='path to config file '
84 '(default is //tools/mb/mb_config.pyl)') 87 '(default is //tools/mb/mb_config.pyl)')
85 subp.add_argument('-g', '--goma-dir', 88 subp.add_argument('-g', '--goma-dir',
86 help='path to goma directory') 89 help='path to goma directory')
87 subp.add_argument('--gyp-script', metavar='PATH', 90 subp.add_argument('--gyp-script', metavar='PATH',
88 default=self.PathJoin('build', 'gyp_chromium'), 91 default=self.PathJoin('build', 'gyp_chromium'),
89 help='path to gyp script relative to project root ' 92 help='path to gyp script relative to project root '
90 '(default is %(default)s)') 93 '(default is %(default)s)')
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 def CmdValidate(self, print_ok=True): 324 def CmdValidate(self, print_ok=True):
322 errs = [] 325 errs = []
323 326
324 # Read the file to make sure it parses. 327 # Read the file to make sure it parses.
325 self.ReadConfigFile() 328 self.ReadConfigFile()
326 329
327 # Build a list of all of the configs referenced by builders. 330 # Build a list of all of the configs referenced by builders.
328 all_configs = {} 331 all_configs = {}
329 for master in self.masters: 332 for master in self.masters:
330 for config in self.masters[master].values(): 333 for config in self.masters[master].values():
331 all_configs[config] = master 334 if isinstance(config, list):
335 for c in config:
336 all_configs[c] = master
337 else:
338 all_configs[config] = master
332 339
333 # Check that every referenced args file or config actually exists. 340 # Check that every referenced args file or config actually exists.
334 for config, loc in all_configs.items(): 341 for config, loc in all_configs.items():
335 if config.startswith('//'): 342 if config.startswith('//'):
336 if not self.Exists(self.ToAbsPath(config)): 343 if not self.Exists(self.ToAbsPath(config)):
337 errs.append('Unknown args file "%s" referenced from "%s".' % 344 errs.append('Unknown args file "%s" referenced from "%s".' %
338 (config, loc)) 345 (config, loc))
339 elif not config in self.configs: 346 elif not config in self.configs:
340 errs.append('Unknown config "%s" referenced from "%s".' % 347 errs.append('Unknown config "%s" referenced from "%s".' %
341 (config, loc)) 348 (config, loc))
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
468 config_only = config_builders - master_builders 475 config_only = config_builders - master_builders
469 tbd = set() 476 tbd = set()
470 gyp = set() 477 gyp = set()
471 done = set() 478 done = set()
472 notes = {builder: '' for builder in config_builders | master_builders} 479 notes = {builder: '' for builder in config_builders | master_builders}
473 480
474 for builder in both: 481 for builder in both:
475 config = self.masters[master][builder] 482 config = self.masters[master][builder]
476 if config == 'tbd': 483 if config == 'tbd':
477 tbd.add(builder) 484 tbd.add(builder)
485 elif isinstance(config, list):
486 vals = self.FlattenConfig(config[0])
487 if vals['type'] == 'gyp':
488 gyp.add(builder)
489 else:
490 done.add(builder)
478 elif config.startswith('//'): 491 elif config.startswith('//'):
479 done.add(builder) 492 done.add(builder)
480 else: 493 else:
481 # TODO(dpranke): Check if MB is actually running?
482 vals = self.FlattenConfig(config) 494 vals = self.FlattenConfig(config)
483 if vals['type'] == 'gyp': 495 if vals['type'] == 'gyp':
484 gyp.add(builder) 496 gyp.add(builder)
485 else: 497 else:
486 done.add(builder) 498 done.add(builder)
487 499
488 if self.args.check_compile and (tbd or master_only): 500 if self.args.check_compile and (tbd or master_only):
489 either = tbd | master_only 501 either = tbd | master_only
490 for builder in either: 502 for builder in either:
491 notes[builder] = ' (' + self.CheckCompile(master, builder) +')' 503 notes[builder] = ' (' + self.CheckCompile(master, builder) +')'
(...skipping 23 matching lines...) Expand all
515 527
516 vals = {} 528 vals = {}
517 if self.args.builder or self.args.master or self.args.config: 529 if self.args.builder or self.args.master or self.args.config:
518 vals = self.Lookup() 530 vals = self.Lookup()
519 if vals['type'] == 'gn': 531 if vals['type'] == 'gn':
520 # Re-run gn gen in order to ensure the config is consistent with the 532 # Re-run gn gen in order to ensure the config is consistent with the
521 # build dir. 533 # build dir.
522 self.RunGNGen(vals) 534 self.RunGNGen(vals)
523 return vals 535 return vals
524 536
525 # TODO: We can only get the config for GN build dirs, not GYP build dirs.
526 # GN stores the args that were used in args.gn in the build dir,
527 # but GYP doesn't store them anywhere. We should consider modifying
528 # gyp_chromium to record the arguments it runs with in a similar
529 # manner.
530
531 mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type') 537 mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type')
532 if not self.Exists(mb_type_path): 538 if not self.Exists(mb_type_path):
533 toolchain_path = self.PathJoin(self.ToAbsPath(build_dir), 539 toolchain_path = self.PathJoin(self.ToAbsPath(build_dir),
534 'toolchain.ninja') 540 'toolchain.ninja')
535 if not self.Exists(toolchain_path): 541 if not self.Exists(toolchain_path):
536 self.Print('Must either specify a path to an existing GN build dir ' 542 self.Print('Must either specify a path to an existing GN build dir '
537 'or pass in a -m/-b pair or a -c flag to specify the ' 543 'or pass in a -m/-b pair or a -c flag to specify the '
538 'configuration') 544 'configuration')
539 return {} 545 return {}
540 else: 546 else:
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
649 '(-m/--master and -b/--builder)') 655 '(-m/--master and -b/--builder)')
650 656
651 if not self.args.master in self.masters: 657 if not self.args.master in self.masters:
652 raise MBErr('Master name "%s" not found in "%s"' % 658 raise MBErr('Master name "%s" not found in "%s"' %
653 (self.args.master, self.args.config_file)) 659 (self.args.master, self.args.config_file))
654 660
655 if not self.args.builder in self.masters[self.args.master]: 661 if not self.args.builder in self.masters[self.args.master]:
656 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' % 662 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' %
657 (self.args.builder, self.args.master, self.args.config_file)) 663 (self.args.builder, self.args.master, self.args.config_file))
658 664
659 return self.masters[self.args.master][self.args.builder] 665 config = self.masters[self.args.master][self.args.builder]
666 if isinstance(config, list):
667 if self.args.phase is None:
668 raise MBErr('Must specify a build --phase for %s on %s' %
669 (self.args.builder, self.args.master))
670 phase = int(self.args.phase)
671 if phase < 1 or phase > len(config):
672 raise MBErr('Phase %d out of bounds for %s on %s' %
673 (phase, self.args.builder, self.args.master))
674 return config[phase-1]
675
676 if self.args.phase is not None:
677 raise MBErr('Must not specify a build --phase for %s on %s' %
678 (self.args.builder, self.args.master))
679 return config
660 680
661 def FlattenConfig(self, config): 681 def FlattenConfig(self, config):
662 mixins = self.configs[config] 682 mixins = self.configs[config]
663 # TODO(dpranke): We really should provide a constructor for the
664 # default set of values.
665 vals = { 683 vals = {
666 'args_file': '', 684 'args_file': '',
667 'cros_passthrough': False, 685 'cros_passthrough': False,
668 'gn_args': [], 686 'gn_args': [],
669 'gyp_defines': '', 687 'gyp_defines': '',
670 'gyp_crosscompile': False, 688 'gyp_crosscompile': False,
671 'type': None, 689 'type': None,
672 } 690 }
673 691
674 visited = [] 692 visited = []
675 self.FlattenMixins(mixins, vals, visited) 693 self.FlattenMixins(mixins, vals, visited)
676 return vals 694 return vals
677 695
678 def FlattenMixins(self, mixins, vals, visited): 696 def FlattenMixins(self, mixins, vals, visited):
679 for m in mixins: 697 for m in mixins:
680 if m not in self.mixins: 698 if m not in self.mixins:
681 raise MBErr('Unknown mixin "%s"' % m) 699 raise MBErr('Unknown mixin "%s"' % m)
682 700
683 # TODO: check for cycles in mixins.
684
685 visited.append(m) 701 visited.append(m)
686 702
687 mixin_vals = self.mixins[m] 703 mixin_vals = self.mixins[m]
688 704
689 if 'cros_passthrough' in mixin_vals: 705 if 'cros_passthrough' in mixin_vals:
690 vals['cros_passthrough'] = mixin_vals['cros_passthrough'] 706 vals['cros_passthrough'] = mixin_vals['cros_passthrough']
691 if 'gn_args' in mixin_vals: 707 if 'gn_args' in mixin_vals:
692 if vals['gn_args']: 708 if vals['gn_args']:
693 vals['gn_args'] += ' ' + mixin_vals['gn_args'] 709 vals['gn_args'] += ' ' + mixin_vals['gn_args']
694 else: 710 else:
(...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after
969 self.PrintJSON(outp) 985 self.PrintJSON(outp)
970 self.Print() 986 self.Print()
971 987
972 return ret 988 return ret
973 989
974 def GetIsolateCommand(self, target, vals, gn_isolate_map): 990 def GetIsolateCommand(self, target, vals, gn_isolate_map):
975 android = 'target_os="android"' in vals['gn_args'] 991 android = 'target_os="android"' in vals['gn_args']
976 992
977 # This needs to mirror the settings in //build/config/ui.gni: 993 # This needs to mirror the settings in //build/config/ui.gni:
978 # use_x11 = is_linux && !use_ozone. 994 # use_x11 = is_linux && !use_ozone.
979 # TODO(dpranke): Figure out how to keep this in sync better.
980 use_x11 = (self.platform == 'linux2' and 995 use_x11 = (self.platform == 'linux2' and
981 not android and 996 not android and
982 not 'use_ozone=true' in vals['gn_args']) 997 not 'use_ozone=true' in vals['gn_args'])
983 998
984 asan = 'is_asan=true' in vals['gn_args'] 999 asan = 'is_asan=true' in vals['gn_args']
985 msan = 'is_msan=true' in vals['gn_args'] 1000 msan = 'is_msan=true' in vals['gn_args']
986 tsan = 'is_tsan=true' in vals['gn_args'] 1001 tsan = 'is_tsan=true' in vals['gn_args']
987 1002
988 target_name = self.GNTargetName(target) 1003 target_name = self.GNTargetName(target)
989 test_type = gn_isolate_map[target_name]['type'] 1004 test_type = gn_isolate_map[target_name]['type']
(...skipping 496 matching lines...) Expand 10 before | Expand all | Expand 10 after
1486 # Then check to see if the arg contains any metacharacters other than 1501 # Then check to see if the arg contains any metacharacters other than
1487 # double quotes; if it does, quote everything (including the double 1502 # double quotes; if it does, quote everything (including the double
1488 # quotes) for safety. 1503 # quotes) for safety.
1489 if any(a in UNSAFE_FOR_CMD for a in arg): 1504 if any(a in UNSAFE_FOR_CMD for a in arg):
1490 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg) 1505 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg)
1491 return arg 1506 return arg
1492 1507
1493 1508
1494 if __name__ == '__main__': 1509 if __name__ == '__main__':
1495 sys.exit(main(sys.argv[1:])) 1510 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « tools/mb/docs/user_guide.md ('k') | tools/mb/mb_config.pyl » ('j') | tools/mb/mb_unittest.py » ('J')

Powered by Google App Engine
This is Rietveld 408576698