Chromium Code Reviews| 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 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 128 vals = self.GetConfig() | 128 vals = self.GetConfig() |
| 129 if vals['type'] == 'gn': | 129 if vals['type'] == 'gn': |
| 130 return self.RunGNAnalyze(vals) | 130 return self.RunGNAnalyze(vals) |
| 131 elif vals['type'] == 'gyp': | 131 elif vals['type'] == 'gyp': |
| 132 return self.RunGYPAnalyze(vals) | 132 return self.RunGYPAnalyze(vals) |
| 133 else: | 133 else: |
| 134 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 134 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 135 | 135 |
| 136 def CmdGen(self): | 136 def CmdGen(self): |
| 137 vals = self.GetConfig() | 137 vals = self.GetConfig() |
| 138 | |
| 139 self.ClobberIfNeeded(vals) | |
| 140 | |
| 138 if vals['type'] == 'gn': | 141 if vals['type'] == 'gn': |
| 139 return self.RunGNGen(vals) | 142 return self.RunGNGen(vals) |
| 140 if vals['type'] == 'gyp': | 143 if vals['type'] == 'gyp': |
| 141 return self.RunGYPGen(vals) | 144 return self.RunGYPGen(vals) |
| 142 | 145 |
| 143 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 146 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 144 | 147 |
| 145 def CmdLookup(self): | 148 def CmdLookup(self): |
| 146 vals = self.GetConfig() | 149 vals = self.GetConfig() |
| 147 if vals['type'] == 'gn': | 150 if vals['type'] == 'gn': |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 283 (self.args.builder, self.args.master, self.args.config_file)) | 286 (self.args.builder, self.args.master, self.args.config_file)) |
| 284 | 287 |
| 285 return self.masters[self.args.master][self.args.builder] | 288 return self.masters[self.args.master][self.args.builder] |
| 286 | 289 |
| 287 def FlattenConfig(self, config): | 290 def FlattenConfig(self, config): |
| 288 mixins = self.configs[config] | 291 mixins = self.configs[config] |
| 289 vals = { | 292 vals = { |
| 290 'type': None, | 293 'type': None, |
| 291 'gn_args': [], | 294 'gn_args': [], |
| 292 'gyp_config': [], | 295 'gyp_config': [], |
| 293 'gyp_defines': [], | 296 'gyp_defines': '', |
|
Dirk Pranke
2015/09/12 00:49:41
this was a bug caught by the new unit tests.
| |
| 294 'gyp_crosscompile': False, | 297 'gyp_crosscompile': False, |
| 295 } | 298 } |
| 296 | 299 |
| 297 visited = [] | 300 visited = [] |
| 298 self.FlattenMixins(mixins, vals, visited) | 301 self.FlattenMixins(mixins, vals, visited) |
| 299 return vals | 302 return vals |
| 300 | 303 |
| 301 def FlattenMixins(self, mixins, vals, visited): | 304 def FlattenMixins(self, mixins, vals, visited): |
| 302 for m in mixins: | 305 for m in mixins: |
| 303 if m not in self.mixins: | 306 if m not in self.mixins: |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 321 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] | 324 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] |
| 322 if 'gyp_defines' in mixin_vals: | 325 if 'gyp_defines' in mixin_vals: |
| 323 if vals['gyp_defines']: | 326 if vals['gyp_defines']: |
| 324 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] | 327 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] |
| 325 else: | 328 else: |
| 326 vals['gyp_defines'] = mixin_vals['gyp_defines'] | 329 vals['gyp_defines'] = mixin_vals['gyp_defines'] |
| 327 if 'mixins' in mixin_vals: | 330 if 'mixins' in mixin_vals: |
| 328 self.FlattenMixins(mixin_vals['mixins'], vals, visited) | 331 self.FlattenMixins(mixin_vals['mixins'], vals, visited) |
| 329 return vals | 332 return vals |
| 330 | 333 |
| 334 def ClobberIfNeeded(self, vals): | |
| 335 path = self.args.path[0] | |
| 336 build_dir = self.ToAbsPath(path) | |
| 337 mb_type_path = os.path.join(build_dir, 'mb_type') | |
| 338 needs_clobber = False | |
| 339 new_mb_type = vals['type'] | |
| 340 if self.Exists(build_dir): | |
| 341 if self.Exists(mb_type_path): | |
| 342 old_mb_type = self.ReadFile(mb_type_path) | |
| 343 if old_mb_type != new_mb_type: | |
| 344 self.Print("Build type mismatch: was %s, will be %s, clobbering %s" % | |
| 345 (old_mb_type, new_mb_type, path)) | |
| 346 needs_clobber = True | |
| 347 else: | |
| 348 # There is no 'mb_type' file in the build directory, so this probably | |
| 349 # means that the prior build(s) were not done through mb, and we | |
| 350 # have no idea if this was a GYP build or a GN build. Clobber it | |
| 351 # to be safe. | |
| 352 self.Print("%s/mb_type missing, clobbering to be safe" % path) | |
| 353 needs_clobber = True | |
| 354 | |
| 355 if needs_clobber: | |
| 356 self.RemoveDirectory(build_dir) | |
| 357 | |
| 358 self.MaybeMakeDirectory(build_dir) | |
| 359 self.WriteFile(mb_type_path, new_mb_type) | |
| 360 | |
| 331 def RunGNGen(self, vals): | 361 def RunGNGen(self, vals): |
| 332 path = self.args.path[0] | 362 path = self.args.path[0] |
| 333 | 363 |
| 334 cmd = self.GNCmd('gen', path, vals['gn_args']) | 364 cmd = self.GNCmd('gen', path, vals['gn_args']) |
| 335 | 365 |
| 336 swarming_targets = [] | 366 swarming_targets = [] |
| 337 if self.args.swarming_targets_file: | 367 if self.args.swarming_targets_file: |
| 338 # We need GN to generate the list of runtime dependencies for | 368 # We need GN to generate the list of runtime dependencies for |
| 339 # the compile targets listed (one per line) in the file so | 369 # the compile targets listed (one per line) in the file so |
| 340 # we can run them via swarming. We use ninja_to_gn.pyl to convert | 370 # we can run them via swarming. We use ninja_to_gn.pyl to convert |
| (...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 814 | 844 |
| 815 def ReadFile(self, path): | 845 def ReadFile(self, path): |
| 816 # This function largely exists so it can be overriden for testing. | 846 # This function largely exists so it can be overriden for testing. |
| 817 with open(path) as fp: | 847 with open(path) as fp: |
| 818 return fp.read() | 848 return fp.read() |
| 819 | 849 |
| 820 def RemoveFile(self, path): | 850 def RemoveFile(self, path): |
| 821 # This function largely exists so it can be overriden for testing. | 851 # This function largely exists so it can be overriden for testing. |
| 822 os.remove(path) | 852 os.remove(path) |
| 823 | 853 |
| 854 def RemoveDirectory(self, abs_path): | |
| 855 if sys.platform == 'win32': | |
| 856 # In other places in chromium, we often have to retry this command | |
|
brettw
2015/09/12 02:08:25
But doesn't shutil still work? I don't see the nee
| |
| 857 # because we're worried about other processes still holding on to | |
| 858 # file handles, but when MB is invoked, it will be early enough in the | |
| 859 # build that their should be no other processes to interfere. We | |
| 860 # can change this if need be. | |
| 861 self.Run(['cmd.exe', '/c', 'rmdir', '/q', '/s', abs_path]) | |
| 862 else: | |
| 863 shutil.rmtree(abs_path, ignore_errors=True) | |
| 864 | |
| 824 def TempFile(self, mode='w'): | 865 def TempFile(self, mode='w'): |
| 825 # This function largely exists so it can be overriden for testing. | 866 # This function largely exists so it can be overriden for testing. |
| 826 return tempfile.NamedTemporaryFile(mode=mode, delete=False) | 867 return tempfile.NamedTemporaryFile(mode=mode, delete=False) |
| 827 | 868 |
| 828 def WriteFile(self, path, contents): | 869 def WriteFile(self, path, contents): |
| 829 # This function largely exists so it can be overriden for testing. | 870 # This function largely exists so it can be overriden for testing. |
| 830 if self.args.dryrun or self.args.verbose: | 871 if self.args.dryrun or self.args.verbose: |
| 831 self.Print('\nWriting """\\\n%s""" to %s.\n' % (contents, path)) | 872 self.Print('\nWriting """\\\n%s""" to %s.\n' % (contents, path)) |
| 832 with open(path, 'w') as fp: | 873 with open(path, 'w') as fp: |
| 833 return fp.write(contents) | 874 return fp.write(contents) |
| 834 | 875 |
| 835 | 876 |
| 836 class MBErr(Exception): | 877 class MBErr(Exception): |
| 837 pass | 878 pass |
| 838 | 879 |
| 839 | 880 |
| 840 if __name__ == '__main__': | 881 if __name__ == '__main__': |
| 841 try: | 882 try: |
| 842 sys.exit(main(sys.argv[1:])) | 883 sys.exit(main(sys.argv[1:])) |
| 843 except MBErr as e: | 884 except MBErr as e: |
| 844 print(e) | 885 print(e) |
| 845 sys.exit(1) | 886 sys.exit(1) |
| 846 except KeyboardInterrupt: | 887 except KeyboardInterrupt: |
| 847 print("interrupted, exiting", stream=sys.stderr) | 888 print("interrupted, exiting", stream=sys.stderr) |
| 848 sys.exit(130) | 889 sys.exit(130) |
| OLD | NEW |