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 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
82 help='path to a file containing the input arguments ' | 82 help='path to a file containing the input arguments ' |
83 'as a JSON object.') | 83 'as a JSON object.') |
84 subp.add_argument('output_path', nargs=1, | 84 subp.add_argument('output_path', nargs=1, |
85 help='path to a file containing the output arguments ' | 85 help='path to a file containing the output arguments ' |
86 'as a JSON object.') | 86 'as a JSON object.') |
87 subp.set_defaults(func=self.CmdAnalyze) | 87 subp.set_defaults(func=self.CmdAnalyze) |
88 | 88 |
89 subp = subps.add_parser('gen', | 89 subp = subps.add_parser('gen', |
90 help='generate a new set of build files') | 90 help='generate a new set of build files') |
91 AddCommonOptions(subp) | 91 AddCommonOptions(subp) |
| 92 subp.add_argument('--swarming-targets-file', |
| 93 help='save runtime dependencies for targets listed ' |
| 94 'in file.') |
92 subp.add_argument('path', nargs=1, | 95 subp.add_argument('path', nargs=1, |
93 help='path to generate build into') | 96 help='path to generate build into') |
94 subp.set_defaults(func=self.CmdGen) | 97 subp.set_defaults(func=self.CmdGen) |
95 | 98 |
96 subp = subps.add_parser('isolate', | 99 subp = subps.add_parser('isolate', |
97 help='build isolates') | 100 help='build isolates') |
98 AddCommonOptions(subp) | 101 AddCommonOptions(subp) |
99 subp.add_argument('path', nargs=1, | 102 subp.add_argument('path', nargs=1, |
100 help='path build was generated into.') | 103 help='path build was generated into.') |
101 subp.add_argument('input_path', nargs=1, | 104 subp.add_argument('input_path', nargs=1, |
(...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 if vals['gyp_defines']: | 332 if vals['gyp_defines']: |
330 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] | 333 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] |
331 else: | 334 else: |
332 vals['gyp_defines'] = mixin_vals['gyp_defines'] | 335 vals['gyp_defines'] = mixin_vals['gyp_defines'] |
333 if 'mixins' in mixin_vals: | 336 if 'mixins' in mixin_vals: |
334 self.FlattenMixins(mixin_vals['mixins'], vals, visited) | 337 self.FlattenMixins(mixin_vals['mixins'], vals, visited) |
335 return vals | 338 return vals |
336 | 339 |
337 def RunGNGen(self, path, vals): | 340 def RunGNGen(self, path, vals): |
338 cmd = self.GNCmd('gen', path, vals['gn_args']) | 341 cmd = self.GNCmd('gen', path, vals['gn_args']) |
| 342 |
| 343 swarming_targets = [] |
| 344 if self.args.swarming_targets_file: |
| 345 # We need GN to generate the list of runtime dependencies for |
| 346 # the compile targets listed (one per line) in the file so |
| 347 # we can run them via swarming. We use ninja_to_gn.pyl to convert |
| 348 # the compile targets to the matching GN labels. |
| 349 contents = self.ReadFile(self.args.swarming_targets_file) |
| 350 swarming_targets = contents.splitlines() |
| 351 ninja_targets_to_labels = ast.literal_eval(self.ReadFile(os.path.join( |
| 352 self.chromium_src_dir, 'testing', 'buildbot', 'ninja_to_gn.pyl'))) |
| 353 gn_labels = [] |
| 354 for target in swarming_targets: |
| 355 if not target in ninja_targets_to_labels: |
| 356 raise MBErr('test target "%s" not found in %s' % |
| 357 (target, '//testing/buildbot/ninja_to_gn.pyl')) |
| 358 gn_labels.append(ninja_targets_to_labels[target]) |
| 359 |
| 360 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') |
| 361 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') |
| 362 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) |
| 363 |
339 ret, _, _ = self.Run(cmd) | 364 ret, _, _ = self.Run(cmd) |
| 365 |
| 366 for target in swarming_targets: |
| 367 deps_path = self.ToAbsPath(path, target + '.runtime_deps') |
| 368 if not self.Exists(deps_path): |
| 369 raise MBErr('did not generate %s' % deps_path) |
| 370 |
340 return ret | 371 return ret |
341 | 372 |
342 def GNCmd(self, subcommand, path, gn_args=''): | 373 def GNCmd(self, subcommand, path, gn_args=''): |
343 if self.platform == 'linux2': | 374 if self.platform == 'linux2': |
344 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'linux64', | 375 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'linux64', |
345 'gn') | 376 'gn') |
346 elif self.platform == 'darwin': | 377 elif self.platform == 'darwin': |
347 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'mac', | 378 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'mac', |
348 'gn') | 379 'gn') |
349 else: | 380 else: |
(...skipping 30 matching lines...) Expand all Loading... |
380 self.Print() | 411 self.Print() |
381 | 412 |
382 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | 413 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) |
383 cmd.extend(['-G', 'config_path=%s' % self.args.input_path[0], | 414 cmd.extend(['-G', 'config_path=%s' % self.args.input_path[0], |
384 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) | 415 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) |
385 ret, _, _ = self.Run(cmd) | 416 ret, _, _ = self.Run(cmd) |
386 if not ret and self.args.verbose: | 417 if not ret and self.args.verbose: |
387 outp = json.loads(self.ReadFile(self.args.output_path[0])) | 418 outp = json.loads(self.ReadFile(self.args.output_path[0])) |
388 self.Print() | 419 self.Print() |
389 self.Print('analyze output:') | 420 self.Print('analyze output:') |
390 self.PrintJSON(inp) | 421 self.PrintJSON(outp) |
391 self.Print() | 422 self.Print() |
392 | 423 |
393 return ret | 424 return ret |
394 | 425 |
395 def RunGNIsolate(self, vals): | 426 def RunGNIsolate(self, vals): |
396 build_path = self.args.path[0] | 427 build_path = self.args.path[0] |
397 inp = self.ReadInputJSON(['targets']) | 428 inp = self.ReadInputJSON(['targets']) |
398 if self.args.verbose: | 429 if self.args.verbose: |
399 self.Print() | 430 self.Print() |
400 self.Print('isolate input:') | 431 self.Print('isolate input:') |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 else: | 528 else: |
498 # TODO(dpranke): Handle script_tests and other types of | 529 # TODO(dpranke): Handle script_tests and other types of |
499 # swarmed tests. | 530 # swarmed tests. |
500 self.WriteFailureAndRaise('unknown test type "%s" for %s' % | 531 self.WriteFailureAndRaise('unknown test type "%s" for %s' % |
501 (test_type, target), | 532 (test_type, target), |
502 output_path) | 533 output_path) |
503 | 534 |
504 | 535 |
505 return cmdline, extra_files | 536 return cmdline, extra_files |
506 | 537 |
507 def ToAbsPath(self, build_path, relpath): | 538 def ToAbsPath(self, build_path, *comps): |
508 return os.path.join(self.chromium_src_dir, | 539 return os.path.join(self.chromium_src_dir, |
509 self.ToSrcRelPath(build_path), | 540 self.ToSrcRelPath(build_path), |
510 relpath) | 541 *comps) |
511 | 542 |
512 def ToSrcRelPath(self, path): | 543 def ToSrcRelPath(self, path): |
513 """Returns a relative path from the top of the repo.""" | 544 """Returns a relative path from the top of the repo.""" |
514 # TODO: Support normal paths in addition to source-absolute paths. | 545 # TODO: Support normal paths in addition to source-absolute paths. |
515 assert(path.startswith('//')) | 546 assert(path.startswith('//')) |
516 return path[2:] | 547 return path[2:] |
517 | 548 |
518 def ParseGYPConfigPath(self, path): | 549 def ParseGYPConfigPath(self, path): |
519 rpath = self.ToSrcRelPath(path) | 550 rpath = self.ToSrcRelPath(path) |
520 output_dir, _, config = rpath.rpartition('/') | 551 output_dir, _, config = rpath.rpartition('/') |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
717 | 748 |
718 if __name__ == '__main__': | 749 if __name__ == '__main__': |
719 try: | 750 try: |
720 sys.exit(main(sys.argv[1:])) | 751 sys.exit(main(sys.argv[1:])) |
721 except MBErr as e: | 752 except MBErr as e: |
722 print(e) | 753 print(e) |
723 sys.exit(1) | 754 sys.exit(1) |
724 except KeyboardInterrupt: | 755 except KeyboardInterrupt: |
725 print("interrupted, exiting", stream=sys.stderr) | 756 print("interrupted, exiting", stream=sys.stderr) |
726 sys.exit(130) | 757 sys.exit(130) |
OLD | NEW |