| OLD | NEW |
| 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 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 | 139 |
| 140 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 140 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 141 | 141 |
| 142 def CmdLookup(self): | 142 def CmdLookup(self): |
| 143 vals = self.GetConfig() | 143 vals = self.GetConfig() |
| 144 if vals['type'] == 'gn': | 144 if vals['type'] == 'gn': |
| 145 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) | 145 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) |
| 146 elif vals['type'] == 'gyp': | 146 elif vals['type'] == 'gyp': |
| 147 if vals['gyp_crosscompile']: | 147 if vals['gyp_crosscompile']: |
| 148 self.Print('GYP_CROSSCOMPILE=1') | 148 self.Print('GYP_CROSSCOMPILE=1') |
| 149 cmd = self.GYPCmd('<path>', vals['gyp_defines'], vals['gyp_config']) | 149 cmd = self.GYPCmd('<path>', vals['gyp_defines']) |
| 150 else: | 150 else: |
| 151 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 151 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 152 | 152 |
| 153 self.PrintCmd(cmd) | 153 self.PrintCmd(cmd) |
| 154 return 0 | 154 return 0 |
| 155 | 155 |
| 156 def CmdHelp(self): | 156 def CmdHelp(self): |
| 157 if self.args.subcommand: | 157 if self.args.subcommand: |
| 158 self.ParseArgs([self.args.subcommand, '--help']) | 158 self.ParseArgs([self.args.subcommand, '--help']) |
| 159 else: | 159 else: |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' % | 278 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' % |
| 279 (self.args.builder, self.args.master, self.args.config_file)) | 279 (self.args.builder, self.args.master, self.args.config_file)) |
| 280 | 280 |
| 281 return self.masters[self.args.master][self.args.builder] | 281 return self.masters[self.args.master][self.args.builder] |
| 282 | 282 |
| 283 def FlattenConfig(self, config): | 283 def FlattenConfig(self, config): |
| 284 mixins = self.configs[config] | 284 mixins = self.configs[config] |
| 285 vals = { | 285 vals = { |
| 286 'type': None, | 286 'type': None, |
| 287 'gn_args': [], | 287 'gn_args': [], |
| 288 'gyp_config': [], | |
| 289 'gyp_defines': '', | 288 'gyp_defines': '', |
| 290 'gyp_crosscompile': False, | 289 'gyp_crosscompile': False, |
| 291 } | 290 } |
| 292 | 291 |
| 293 visited = [] | 292 visited = [] |
| 294 self.FlattenMixins(mixins, vals, visited) | 293 self.FlattenMixins(mixins, vals, visited) |
| 295 return vals | 294 return vals |
| 296 | 295 |
| 297 def FlattenMixins(self, mixins, vals, visited): | 296 def FlattenMixins(self, mixins, vals, visited): |
| 298 for m in mixins: | 297 for m in mixins: |
| 299 if m not in self.mixins: | 298 if m not in self.mixins: |
| 300 raise MBErr('Unknown mixin "%s"' % m) | 299 raise MBErr('Unknown mixin "%s"' % m) |
| 301 | 300 |
| 302 # TODO: check for cycles in mixins. | 301 # TODO: check for cycles in mixins. |
| 303 | 302 |
| 304 visited.append(m) | 303 visited.append(m) |
| 305 | 304 |
| 306 mixin_vals = self.mixins[m] | 305 mixin_vals = self.mixins[m] |
| 307 if 'type' in mixin_vals: | 306 if 'type' in mixin_vals: |
| 308 vals['type'] = mixin_vals['type'] | 307 vals['type'] = mixin_vals['type'] |
| 309 if 'gn_args' in mixin_vals: | 308 if 'gn_args' in mixin_vals: |
| 310 if vals['gn_args']: | 309 if vals['gn_args']: |
| 311 vals['gn_args'] += ' ' + mixin_vals['gn_args'] | 310 vals['gn_args'] += ' ' + mixin_vals['gn_args'] |
| 312 else: | 311 else: |
| 313 vals['gn_args'] = mixin_vals['gn_args'] | 312 vals['gn_args'] = mixin_vals['gn_args'] |
| 314 if 'gyp_config' in mixin_vals: | |
| 315 vals['gyp_config'] = mixin_vals['gyp_config'] | |
| 316 if 'gyp_crosscompile' in mixin_vals: | 313 if 'gyp_crosscompile' in mixin_vals: |
| 317 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] | 314 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] |
| 318 if 'gyp_defines' in mixin_vals: | 315 if 'gyp_defines' in mixin_vals: |
| 319 if vals['gyp_defines']: | 316 if vals['gyp_defines']: |
| 320 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] | 317 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] |
| 321 else: | 318 else: |
| 322 vals['gyp_defines'] = mixin_vals['gyp_defines'] | 319 vals['gyp_defines'] = mixin_vals['gyp_defines'] |
| 323 if 'mixins' in mixin_vals: | 320 if 'mixins' in mixin_vals: |
| 324 self.FlattenMixins(mixin_vals['mixins'], vals, visited) | 321 self.FlattenMixins(mixin_vals['mixins'], vals, visited) |
| 325 return vals | 322 return vals |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 451 | 448 |
| 452 cmd = [gn_path, subcommand, path] | 449 cmd = [gn_path, subcommand, path] |
| 453 gn_args = gn_args.replace("$(goma_dir)", self.args.goma_dir) | 450 gn_args = gn_args.replace("$(goma_dir)", self.args.goma_dir) |
| 454 if gn_args: | 451 if gn_args: |
| 455 cmd.append('--args=%s' % gn_args) | 452 cmd.append('--args=%s' % gn_args) |
| 456 return cmd | 453 return cmd |
| 457 | 454 |
| 458 def RunGYPGen(self, vals): | 455 def RunGYPGen(self, vals): |
| 459 path = self.args.path[0] | 456 path = self.args.path[0] |
| 460 | 457 |
| 461 output_dir, gyp_config = self.ParseGYPConfigPath(path) | 458 output_dir = self.ParseGYPConfigPath(path) |
| 462 if gyp_config != vals['gyp_config']: | 459 cmd = self.GYPCmd(output_dir, vals['gyp_defines']) |
| 463 raise MBErr('The last component of the path (%s) must match the ' | |
| 464 'GYP configuration specified in the config (%s), and ' | |
| 465 'it does not.' % (gyp_config, vals['gyp_config'])) | |
| 466 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | |
| 467 env = None | 460 env = None |
| 468 if vals['gyp_crosscompile']: | 461 if vals['gyp_crosscompile']: |
| 469 if self.args.verbose: | 462 if self.args.verbose: |
| 470 self.Print('Setting GYP_CROSSCOMPILE=1 in the environment') | 463 self.Print('Setting GYP_CROSSCOMPILE=1 in the environment') |
| 471 env = os.environ.copy() | 464 env = os.environ.copy() |
| 472 env['GYP_CROSSCOMPILE'] = '1' | 465 env['GYP_CROSSCOMPILE'] = '1' |
| 473 ret, _, _ = self.Run(cmd, env=env) | 466 ret, _, _ = self.Run(cmd, env=env) |
| 474 return ret | 467 return ret |
| 475 | 468 |
| 476 def RunGYPAnalyze(self, vals): | 469 def RunGYPAnalyze(self, vals): |
| 477 output_dir, gyp_config = self.ParseGYPConfigPath(self.args.path[0]) | 470 output_dir = self.ParseGYPConfigPath(self.args.path[0]) |
| 478 if gyp_config != vals['gyp_config']: | |
| 479 raise MBErr('The last component of the path (%s) must match the ' | |
| 480 'GYP configuration specified in the config (%s), and ' | |
| 481 'it does not.' % (gyp_config, vals['gyp_config'])) | |
| 482 if self.args.verbose: | 471 if self.args.verbose: |
| 483 inp = self.ReadInputJSON(['files', 'targets']) | 472 inp = self.ReadInputJSON(['files', 'targets']) |
| 484 self.Print() | 473 self.Print() |
| 485 self.Print('analyze input:') | 474 self.Print('analyze input:') |
| 486 self.PrintJSON(inp) | 475 self.PrintJSON(inp) |
| 487 self.Print() | 476 self.Print() |
| 488 | 477 |
| 489 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | 478 cmd = self.GYPCmd(output_dir, vals['gyp_defines']) |
| 490 cmd.extend(['-f', 'analyzer', | 479 cmd.extend(['-f', 'analyzer', |
| 491 '-G', 'config_path=%s' % self.args.input_path[0], | 480 '-G', 'config_path=%s' % self.args.input_path[0], |
| 492 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) | 481 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) |
| 493 ret, _, _ = self.Run(cmd) | 482 ret, _, _ = self.Run(cmd) |
| 494 if not ret and self.args.verbose: | 483 if not ret and self.args.verbose: |
| 495 outp = json.loads(self.ReadFile(self.args.output_path[0])) | 484 outp = json.loads(self.ReadFile(self.args.output_path[0])) |
| 496 self.Print() | 485 self.Print() |
| 497 self.Print('analyze output:') | 486 self.Print('analyze output:') |
| 498 self.PrintJSON(outp) | 487 self.PrintJSON(outp) |
| 499 self.Print() | 488 self.Print() |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 585 *comps) | 574 *comps) |
| 586 | 575 |
| 587 def ToSrcRelPath(self, path): | 576 def ToSrcRelPath(self, path): |
| 588 """Returns a relative path from the top of the repo.""" | 577 """Returns a relative path from the top of the repo.""" |
| 589 # TODO: Support normal paths in addition to source-absolute paths. | 578 # TODO: Support normal paths in addition to source-absolute paths. |
| 590 assert(path.startswith('//')) | 579 assert(path.startswith('//')) |
| 591 return path[2:].replace('/', os.sep) | 580 return path[2:].replace('/', os.sep) |
| 592 | 581 |
| 593 def ParseGYPConfigPath(self, path): | 582 def ParseGYPConfigPath(self, path): |
| 594 rpath = self.ToSrcRelPath(path) | 583 rpath = self.ToSrcRelPath(path) |
| 595 output_dir, _, config = rpath.rpartition('/') | 584 output_dir, _, _ = rpath.rpartition('/') |
| 596 self.CheckGYPConfigIsSupported(config, path) | 585 return output_dir |
| 597 return output_dir, config | |
| 598 | 586 |
| 599 def CheckGYPConfigIsSupported(self, config, path): | 587 def GYPCmd(self, output_dir, gyp_defines): |
| 600 if config not in ('Debug', 'Release'): | |
| 601 if (sys.platform in ('win32', 'cygwin') and | |
| 602 config not in ('Debug_x64', 'Release_x64')): | |
| 603 raise MBErr('Unknown or unsupported config type "%s" in "%s"' % | |
| 604 config, path) | |
| 605 | |
| 606 def GYPCmd(self, output_dir, gyp_defines, config): | |
| 607 gyp_defines = gyp_defines.replace("$(goma_dir)", self.args.goma_dir) | 588 gyp_defines = gyp_defines.replace("$(goma_dir)", self.args.goma_dir) |
| 608 cmd = [ | 589 cmd = [ |
| 609 sys.executable, | 590 sys.executable, |
| 610 os.path.join('build', 'gyp_chromium'), | 591 os.path.join('build', 'gyp_chromium'), |
| 611 '-G', | 592 '-G', |
| 612 'output_dir=' + output_dir, | 593 'output_dir=' + output_dir, |
| 613 '-G', | |
| 614 'config=' + config, | |
| 615 ] | 594 ] |
| 616 for d in shlex.split(gyp_defines): | 595 for d in shlex.split(gyp_defines): |
| 617 cmd += ['-D', d] | 596 cmd += ['-D', d] |
| 618 return cmd | 597 return cmd |
| 619 | 598 |
| 620 def RunGNAnalyze(self, vals): | 599 def RunGNAnalyze(self, vals): |
| 621 # analyze runs before 'gn gen' now, so we need to run gn gen | 600 # analyze runs before 'gn gen' now, so we need to run gn gen |
| 622 # in order to ensure that we have a build directory. | 601 # in order to ensure that we have a build directory. |
| 623 ret = self.RunGNGen(vals) | 602 ret = self.RunGNGen(vals) |
| 624 if ret: | 603 if ret: |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 832 | 811 |
| 833 if __name__ == '__main__': | 812 if __name__ == '__main__': |
| 834 try: | 813 try: |
| 835 sys.exit(main(sys.argv[1:])) | 814 sys.exit(main(sys.argv[1:])) |
| 836 except MBErr as e: | 815 except MBErr as e: |
| 837 print(e) | 816 print(e) |
| 838 sys.exit(1) | 817 sys.exit(1) |
| 839 except KeyboardInterrupt: | 818 except KeyboardInterrupt: |
| 840 print("interrupted, exiting", stream=sys.stderr) | 819 print("interrupted, exiting", stream=sys.stderr) |
| 841 sys.exit(130) | 820 sys.exit(130) |
| OLD | NEW |