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 |