| 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 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 140 if vals['type'] == 'gyp': | 140 if vals['type'] == 'gyp': |
| 141 return self.RunGYPGen(vals) | 141 return self.RunGYPGen(vals) |
| 142 | 142 |
| 143 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 143 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 144 | 144 |
| 145 def CmdLookup(self): | 145 def CmdLookup(self): |
| 146 vals = self.GetConfig() | 146 vals = self.GetConfig() |
| 147 if vals['type'] == 'gn': | 147 if vals['type'] == 'gn': |
| 148 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) | 148 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) |
| 149 elif vals['type'] == 'gyp': | 149 elif vals['type'] == 'gyp': |
| 150 if vals['gyp_crosscompile']: |
| 151 self.Print('GYP_CROSSCOMPILE=1') |
| 150 cmd = self.GYPCmd('<path>', vals['gyp_defines'], vals['gyp_config']) | 152 cmd = self.GYPCmd('<path>', vals['gyp_defines'], vals['gyp_config']) |
| 151 else: | 153 else: |
| 152 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 154 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 153 | 155 |
| 154 self.PrintCmd(cmd) | 156 self.PrintCmd(cmd) |
| 155 return 0 | 157 return 0 |
| 156 | 158 |
| 157 def CmdHelp(self): | 159 def CmdHelp(self): |
| 158 if self.args.subcommand: | 160 if self.args.subcommand: |
| 159 self.ParseArgs([self.args.subcommand, '--help']) | 161 self.ParseArgs([self.args.subcommand, '--help']) |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 282 | 284 |
| 283 return self.masters[self.args.master][self.args.builder] | 285 return self.masters[self.args.master][self.args.builder] |
| 284 | 286 |
| 285 def FlattenConfig(self, config): | 287 def FlattenConfig(self, config): |
| 286 mixins = self.configs[config] | 288 mixins = self.configs[config] |
| 287 vals = { | 289 vals = { |
| 288 'type': None, | 290 'type': None, |
| 289 'gn_args': [], | 291 'gn_args': [], |
| 290 'gyp_config': [], | 292 'gyp_config': [], |
| 291 'gyp_defines': [], | 293 'gyp_defines': [], |
| 294 'gyp_crosscompile': False, |
| 292 } | 295 } |
| 293 | 296 |
| 294 visited = [] | 297 visited = [] |
| 295 self.FlattenMixins(mixins, vals, visited) | 298 self.FlattenMixins(mixins, vals, visited) |
| 296 return vals | 299 return vals |
| 297 | 300 |
| 298 def FlattenMixins(self, mixins, vals, visited): | 301 def FlattenMixins(self, mixins, vals, visited): |
| 299 for m in mixins: | 302 for m in mixins: |
| 300 if m not in self.mixins: | 303 if m not in self.mixins: |
| 301 raise MBErr('Unknown mixin "%s"' % m) | 304 raise MBErr('Unknown mixin "%s"' % m) |
| 302 | 305 |
| 303 # TODO: check for cycles in mixins. | 306 # TODO: check for cycles in mixins. |
| 304 | 307 |
| 305 visited.append(m) | 308 visited.append(m) |
| 306 | 309 |
| 307 mixin_vals = self.mixins[m] | 310 mixin_vals = self.mixins[m] |
| 308 if 'type' in mixin_vals: | 311 if 'type' in mixin_vals: |
| 309 vals['type'] = mixin_vals['type'] | 312 vals['type'] = mixin_vals['type'] |
| 310 if 'gn_args' in mixin_vals: | 313 if 'gn_args' in mixin_vals: |
| 311 if vals['gn_args']: | 314 if vals['gn_args']: |
| 312 vals['gn_args'] += ' ' + mixin_vals['gn_args'] | 315 vals['gn_args'] += ' ' + mixin_vals['gn_args'] |
| 313 else: | 316 else: |
| 314 vals['gn_args'] = mixin_vals['gn_args'] | 317 vals['gn_args'] = mixin_vals['gn_args'] |
| 315 if 'gyp_config' in mixin_vals: | 318 if 'gyp_config' in mixin_vals: |
| 316 vals['gyp_config'] = mixin_vals['gyp_config'] | 319 vals['gyp_config'] = mixin_vals['gyp_config'] |
| 320 if 'gyp_crosscompile' in mixin_vals: |
| 321 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] |
| 317 if 'gyp_defines' in mixin_vals: | 322 if 'gyp_defines' in mixin_vals: |
| 318 if vals['gyp_defines']: | 323 if vals['gyp_defines']: |
| 319 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] | 324 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] |
| 320 else: | 325 else: |
| 321 vals['gyp_defines'] = mixin_vals['gyp_defines'] | 326 vals['gyp_defines'] = mixin_vals['gyp_defines'] |
| 322 if 'mixins' in mixin_vals: | 327 if 'mixins' in mixin_vals: |
| 323 self.FlattenMixins(mixin_vals['mixins'], vals, visited) | 328 self.FlattenMixins(mixin_vals['mixins'], vals, visited) |
| 324 return vals | 329 return vals |
| 325 | 330 |
| 326 def RunGNGen(self, vals): | 331 def RunGNGen(self, vals): |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 419 | 424 |
| 420 def RunGYPGen(self, vals): | 425 def RunGYPGen(self, vals): |
| 421 path = self.args.path[0] | 426 path = self.args.path[0] |
| 422 | 427 |
| 423 output_dir, gyp_config = self.ParseGYPConfigPath(path) | 428 output_dir, gyp_config = self.ParseGYPConfigPath(path) |
| 424 if gyp_config != vals['gyp_config']: | 429 if gyp_config != vals['gyp_config']: |
| 425 raise MBErr('The last component of the path (%s) must match the ' | 430 raise MBErr('The last component of the path (%s) must match the ' |
| 426 'GYP configuration specified in the config (%s), and ' | 431 'GYP configuration specified in the config (%s), and ' |
| 427 'it does not.' % (gyp_config, vals['gyp_config'])) | 432 'it does not.' % (gyp_config, vals['gyp_config'])) |
| 428 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | 433 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) |
| 429 ret, _, _ = self.Run(cmd) | 434 env = None |
| 435 if vals['gyp_crosscompile']: |
| 436 if self.args.verbose: |
| 437 self.Print('Setting GYP_CROSSCOMPILE=1 in the environment') |
| 438 env = os.environ.copy() |
| 439 env['GYP_CROSSCOMPILE'] = '1' |
| 440 ret, _, _ = self.Run(cmd, env=env) |
| 430 return ret | 441 return ret |
| 431 | 442 |
| 432 def RunGYPAnalyze(self, vals): | 443 def RunGYPAnalyze(self, vals): |
| 433 output_dir, gyp_config = self.ParseGYPConfigPath(self.args.path[0]) | 444 output_dir, gyp_config = self.ParseGYPConfigPath(self.args.path[0]) |
| 434 if gyp_config != vals['gyp_config']: | 445 if gyp_config != vals['gyp_config']: |
| 435 raise MBErr('The last component of the path (%s) must match the ' | 446 raise MBErr('The last component of the path (%s) must match the ' |
| 436 'GYP configuration specified in the config (%s), and ' | 447 'GYP configuration specified in the config (%s), and ' |
| 437 'it does not.' % (gyp_config, vals['gyp_config'])) | 448 'it does not.' % (gyp_config, vals['gyp_config'])) |
| 438 if self.args.verbose: | 449 if self.args.verbose: |
| 439 inp = self.ReadInputJSON(['files', 'targets']) | 450 inp = self.ReadInputJSON(['files', 'targets']) |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 745 cmd = ['python'] + cmd[1:] | 756 cmd = ['python'] + cmd[1:] |
| 746 self.Print(*[pipes.quote(c) for c in cmd]) | 757 self.Print(*[pipes.quote(c) for c in cmd]) |
| 747 | 758 |
| 748 def PrintJSON(self, obj): | 759 def PrintJSON(self, obj): |
| 749 self.Print(json.dumps(obj, indent=2, sort_keys=True)) | 760 self.Print(json.dumps(obj, indent=2, sort_keys=True)) |
| 750 | 761 |
| 751 def Print(self, *args, **kwargs): | 762 def Print(self, *args, **kwargs): |
| 752 # This function largely exists so it can be overridden for testing. | 763 # This function largely exists so it can be overridden for testing. |
| 753 print(*args, **kwargs) | 764 print(*args, **kwargs) |
| 754 | 765 |
| 755 def Run(self, cmd): | 766 def Run(self, cmd, env=None): |
| 756 # This function largely exists so it can be overridden for testing. | 767 # This function largely exists so it can be overridden for testing. |
| 757 if self.args.dryrun or self.args.verbose: | 768 if self.args.dryrun or self.args.verbose: |
| 758 self.PrintCmd(cmd) | 769 self.PrintCmd(cmd) |
| 759 if self.args.dryrun: | 770 if self.args.dryrun: |
| 760 return 0, '', '' | 771 return 0, '', '' |
| 761 ret, out, err = self.Call(cmd) | 772 ret, out, err = self.Call(cmd, env=env) |
| 762 if self.args.verbose: | 773 if self.args.verbose: |
| 763 if out: | 774 if out: |
| 764 self.Print(out, end='') | 775 self.Print(out, end='') |
| 765 if err: | 776 if err: |
| 766 self.Print(err, end='', file=sys.stderr) | 777 self.Print(err, end='', file=sys.stderr) |
| 767 return ret, out, err | 778 return ret, out, err |
| 768 | 779 |
| 769 def Call(self, cmd): | 780 def Call(self, cmd, env=None): |
| 770 p = subprocess.Popen(cmd, shell=False, cwd=self.chromium_src_dir, | 781 p = subprocess.Popen(cmd, shell=False, cwd=self.chromium_src_dir, |
| 771 stdout=subprocess.PIPE, stderr=subprocess.PIPE) | 782 stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
| 783 env=env) |
| 772 out, err = p.communicate() | 784 out, err = p.communicate() |
| 773 return p.returncode, out, err | 785 return p.returncode, out, err |
| 774 | 786 |
| 775 def ExpandUser(self, path): | 787 def ExpandUser(self, path): |
| 776 # This function largely exists so it can be overridden for testing. | 788 # This function largely exists so it can be overridden for testing. |
| 777 return os.path.expanduser(path) | 789 return os.path.expanduser(path) |
| 778 | 790 |
| 779 def Exists(self, path): | 791 def Exists(self, path): |
| 780 # This function largely exists so it can be overridden for testing. | 792 # This function largely exists so it can be overridden for testing. |
| 781 return os.path.exists(path) | 793 return os.path.exists(path) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 814 | 826 |
| 815 if __name__ == '__main__': | 827 if __name__ == '__main__': |
| 816 try: | 828 try: |
| 817 sys.exit(main(sys.argv[1:])) | 829 sys.exit(main(sys.argv[1:])) |
| 818 except MBErr as e: | 830 except MBErr as e: |
| 819 print(e) | 831 print(e) |
| 820 sys.exit(1) | 832 sys.exit(1) |
| 821 except KeyboardInterrupt: | 833 except KeyboardInterrupt: |
| 822 print("interrupted, exiting", stream=sys.stderr) | 834 print("interrupted, exiting", stream=sys.stderr) |
| 823 sys.exit(130) | 835 sys.exit(130) |
| OLD | NEW |