Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: tools/mb/mb.py

Issue 1880903002: Switch MB to write the GN args to args.gn. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fix_mb_goma
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 """
11 11
12 from __future__ import print_function 12 from __future__ import print_function
13 13
14 import argparse 14 import argparse
15 import ast 15 import ast
16 import errno 16 import errno
17 import json 17 import json
18 import os 18 import os
19 import pipes 19 import pipes
20 import pprint 20 import pprint
21 import re 21 import re
22 import shutil 22 import shutil
23 import sys 23 import sys
24 import subprocess 24 import subprocess
25 import tempfile 25 import tempfile
26 import urllib2 26 import urllib2
27 27
28 from collections import OrderedDict 28 from collections import OrderedDict
29 29
30 CHROMIUM_SRC_DIR = os.path.dirname(os.path.dirname(os.path.dirname(
31 os.path.abspath(__file__))))
32 sys.path = [os.path.join(CHROMIUM_SRC_DIR, 'build')] + sys.path
33
34 import gn_helpers
35
36
30 def main(args): 37 def main(args):
31 mbw = MetaBuildWrapper() 38 mbw = MetaBuildWrapper()
32 return mbw.Main(args) 39 return mbw.Main(args)
33 40
34 41
35 class MetaBuildWrapper(object): 42 class MetaBuildWrapper(object):
36 def __init__(self): 43 def __init__(self):
37 p = os.path 44 self.chromium_src_dir = CHROMIUM_SRC_DIR
38 d = os.path.dirname 45 self.default_config = os.path.join(self.chromium_src_dir, 'tools', 'mb',
39 self.chromium_src_dir = p.normpath(d(d(d(p.abspath(__file__))))) 46 'mb_config.pyl')
40 self.default_config = p.join(self.chromium_src_dir, 'tools', 'mb',
41 'mb_config.pyl')
42 self.executable = sys.executable 47 self.executable = sys.executable
43 self.platform = sys.platform 48 self.platform = sys.platform
44 self.sep = os.sep 49 self.sep = os.sep
45 self.args = argparse.Namespace() 50 self.args = argparse.Namespace()
46 self.configs = {} 51 self.configs = {}
47 self.masters = {} 52 self.masters = {}
48 self.mixins = {} 53 self.mixins = {}
49 54
50 def Main(self, args): 55 def Main(self, args):
51 self.ParseArgs(args) 56 self.ParseArgs(args)
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
248 return 1 253 return 1
249 254
250 if vals['type'] == 'gn': 255 if vals['type'] == 'gn':
251 return self.RunGNIsolate(vals) 256 return self.RunGNIsolate(vals)
252 else: 257 else:
253 return self.Build('%s_run' % self.args.target[0]) 258 return self.Build('%s_run' % self.args.target[0])
254 259
255 def CmdLookup(self): 260 def CmdLookup(self):
256 vals = self.Lookup() 261 vals = self.Lookup()
257 if vals['type'] == 'gn': 262 if vals['type'] == 'gn':
258 cmd = self.GNCmd('gen', '_path_', vals['gn_args']) 263 cmd = self.GNCmd('gen', '_path_')
264 gn_args = self.GNArgs(vals)
265 self.Print('\nWriting """\\\n%s""" to _path_/args.gn.\n' % gn_args)
259 env = None 266 env = None
260 else: 267 else:
261 cmd, env = self.GYPCmd('_path_', vals) 268 cmd, env = self.GYPCmd('_path_', vals)
262 269
263 self.PrintCmd(cmd, env) 270 self.PrintCmd(cmd, env)
264 return 0 271 return 0
265 272
266 def CmdRun(self): 273 def CmdRun(self):
267 vals = self.GetConfig() 274 vals = self.GetConfig()
268 if not vals: 275 if not vals:
(...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 690
684 if needs_clobber: 691 if needs_clobber:
685 self.RemoveDirectory(build_dir) 692 self.RemoveDirectory(build_dir)
686 693
687 self.MaybeMakeDirectory(build_dir) 694 self.MaybeMakeDirectory(build_dir)
688 self.WriteFile(mb_type_path, new_mb_type) 695 self.WriteFile(mb_type_path, new_mb_type)
689 696
690 def RunGNGen(self, vals): 697 def RunGNGen(self, vals):
691 build_dir = self.args.path[0] 698 build_dir = self.args.path[0]
692 699
693 cmd = self.GNCmd('gen', build_dir, vals['gn_args'], extra_args=['--check']) 700 cmd = self.GNCmd('gen', build_dir, '--check')
701 gn_args = self.GNArgs(vals)
702
703 # Since GN hasn't run yet, the build directory may not even exist.
704 self.MaybeMakeDirectory(self.ToAbsPath(build_dir))
705
706 gn_args_path = self.ToAbsPath(build_dir, 'args.gn')
707 self.WriteFile(gn_args_path, gn_args)
694 708
695 swarming_targets = [] 709 swarming_targets = []
696 if getattr(self.args, 'swarming_targets_file', None): 710 if getattr(self.args, 'swarming_targets_file', None):
697 # We need GN to generate the list of runtime dependencies for 711 # We need GN to generate the list of runtime dependencies for
698 # the compile targets listed (one per line) in the file so 712 # the compile targets listed (one per line) in the file so
699 # we can run them via swarming. We use ninja_to_gn.pyl to convert 713 # we can run them via swarming. We use ninja_to_gn.pyl to convert
700 # the compile targets to the matching GN labels. 714 # the compile targets to the matching GN labels.
701 path = self.args.swarming_targets_file 715 path = self.args.swarming_targets_file
702 if not self.Exists(path): 716 if not self.Exists(path):
703 self.WriteFailureAndRaise('"%s" does not exist' % path, 717 self.WriteFailureAndRaise('"%s" does not exist' % path,
(...skipping 11 matching lines...) Expand all
715 elif gn_isolate_map[target_name]['type'] == 'unknown': 729 elif gn_isolate_map[target_name]['type'] == 'unknown':
716 err += ('test target "%s" type is unknown\n' % target_name) 730 err += ('test target "%s" type is unknown\n' % target_name)
717 else: 731 else:
718 gn_labels.append(gn_isolate_map[target_name]['label']) 732 gn_labels.append(gn_isolate_map[target_name]['label'])
719 733
720 if err: 734 if err:
721 raise MBErr('Error: Failed to match swarming targets to %s:\n%s' % 735 raise MBErr('Error: Failed to match swarming targets to %s:\n%s' %
722 ('//testing/buildbot/gn_isolate_map.pyl', err)) 736 ('//testing/buildbot/gn_isolate_map.pyl', err))
723 737
724 gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps') 738 gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps')
725
726 # Since GN hasn't run yet, the build directory may not even exist.
727 self.MaybeMakeDirectory(self.ToAbsPath(build_dir))
728
729 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') 739 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n')
730 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) 740 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path)
731 741
732 ret, _, _ = self.Run(cmd) 742 ret, _, _ = self.Run(cmd)
733 if ret: 743 if ret:
734 # If `gn gen` failed, we should exit early rather than trying to 744 # If `gn gen` failed, we should exit early rather than trying to
735 # generate isolates. Run() will have already logged any error output. 745 # generate isolates. Run() will have already logged any error output.
736 self.Print('GN gen failed: %d' % ret) 746 self.Print('GN gen failed: %d' % ret)
737 return ret 747 return ret
738 748
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 def RunGNIsolate(self, vals): 795 def RunGNIsolate(self, vals):
786 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( 796 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin(
787 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) 797 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl')))
788 798
789 build_dir = self.args.path[0] 799 build_dir = self.args.path[0]
790 target = self.args.target[0] 800 target = self.args.target[0]
791 target_name = self.GNTargetName(target) 801 target_name = self.GNTargetName(target)
792 command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map) 802 command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map)
793 803
794 label = gn_isolate_map[target_name]['label'] 804 label = gn_isolate_map[target_name]['label']
795 cmd = self.GNCmd('desc', build_dir, extra_args=[label, 'runtime_deps']) 805 cmd = self.GNCmd('desc', build_dir, label, 'runtime_deps')
796 ret, out, _ = self.Call(cmd) 806 ret, out, _ = self.Call(cmd)
797 if ret: 807 if ret:
798 if out: 808 if out:
799 self.Print(out) 809 self.Print(out)
800 return ret 810 return ret
801 811
802 runtime_deps = out.splitlines() 812 runtime_deps = out.splitlines()
803 813
804 self.WriteIsolateFiles(build_dir, command, target, runtime_deps, 814 self.WriteIsolateFiles(build_dir, command, target, runtime_deps,
805 extra_files) 815 extra_files)
(...skipping 28 matching lines...) Expand all
834 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)), 844 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)),
835 '--isolate', 845 '--isolate',
836 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)), 846 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)),
837 ], 847 ],
838 'dir': self.chromium_src_dir, 848 'dir': self.chromium_src_dir,
839 'version': 1, 849 'version': 1,
840 }, 850 },
841 isolate_path + 'd.gen.json', 851 isolate_path + 'd.gen.json',
842 ) 852 )
843 853
844 def GNCmd(self, subcommand, path, gn_args='', extra_args=None): 854 def GNCmd(self, subcommand, path, *args):
845 if self.platform == 'linux2': 855 if self.platform == 'linux2':
846 subdir, exe = 'linux64', 'gn' 856 subdir, exe = 'linux64', 'gn'
847 elif self.platform == 'darwin': 857 elif self.platform == 'darwin':
848 subdir, exe = 'mac', 'gn' 858 subdir, exe = 'mac', 'gn'
849 else: 859 else:
850 subdir, exe = 'win', 'gn.exe' 860 subdir, exe = 'win', 'gn.exe'
861
851 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe) 862 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, exe)
852 863
853 cmd = [gn_path, subcommand, path] 864 return [gn_path, subcommand, path] + list(args)
865
866 def GNArgs(self, vals):
867 gn_args = vals['gn_args']
854 if self.args.goma_dir: 868 if self.args.goma_dir:
855 gn_args += ' goma_dir="%s"' % self.args.goma_dir 869 gn_args += ' goma_dir="%s"' % self.args.goma_dir
856 if gn_args: 870
857 cmd.append('--args=%s' % gn_args) 871 # Canonicalize the arg string into a sorted, newline-separated list
858 if extra_args: 872 # of key-value pairs, and de-dup the keys if need be so that only
859 cmd.extend(extra_args) 873 # the last instance of each arg is listed.
860 return cmd 874 gn_args = gn_helpers.ToGNString(gn_helpers.FromGNArgs(gn_args))
875
876 return gn_args
861 877
862 def RunGYPGen(self, vals): 878 def RunGYPGen(self, vals):
863 path = self.args.path[0] 879 path = self.args.path[0]
864 880
865 output_dir = self.ParseGYPConfigPath(path) 881 output_dir = self.ParseGYPConfigPath(path)
866 cmd, env = self.GYPCmd(output_dir, vals) 882 cmd, env = self.GYPCmd(output_dir, vals)
867 ret, _, _ = self.Run(cmd, env=env) 883 ret, _, _ = self.Run(cmd, env=env)
868 return ret 884 return ret
869 885
870 def RunGYPAnalyze(self, vals): 886 def RunGYPAnalyze(self, vals):
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
1079 }, output_path) 1095 }, output_path)
1080 return 0 1096 return 0
1081 1097
1082 ret = 0 1098 ret = 0
1083 response_file = self.TempFile() 1099 response_file = self.TempFile()
1084 response_file.write('\n'.join(inp['files']) + '\n') 1100 response_file.write('\n'.join(inp['files']) + '\n')
1085 response_file.close() 1101 response_file.close()
1086 1102
1087 matching_targets = set() 1103 matching_targets = set()
1088 try: 1104 try:
1089 cmd = self.GNCmd('refs', self.args.path[0]) + [ 1105 cmd = self.GNCmd('refs',
1090 '@%s' % response_file.name, '--all', '--as=output'] 1106 self.args.path[0],
1107 '@%s' % response_file.name,
1108 '--all',
1109 '--as=output')
1091 ret, out, _ = self.Run(cmd, force_verbose=False) 1110 ret, out, _ = self.Run(cmd, force_verbose=False)
1092 if ret and not 'The input matches no targets' in out: 1111 if ret and not 'The input matches no targets' in out:
1093 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), 1112 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
1094 output_path) 1113 output_path)
1095 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep 1114 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep
1096 for output in out.splitlines(): 1115 for output in out.splitlines():
1097 build_output = output.replace(build_dir, '') 1116 build_output = output.replace(build_dir, '')
1098 if build_output in targets: 1117 if build_output in targets:
1099 matching_targets.add(build_output) 1118 matching_targets.add(build_output)
1100 1119
1101 cmd = self.GNCmd('refs', self.args.path[0]) + [ 1120 cmd = self.GNCmd('refs',
1102 '@%s' % response_file.name, '--all'] 1121 self.args.path[0],
1122 '@%s' % response_file.name,
1123 '--all')
1103 ret, out, _ = self.Run(cmd, force_verbose=False) 1124 ret, out, _ = self.Run(cmd, force_verbose=False)
1104 if ret and not 'The input matches no targets' in out: 1125 if ret and not 'The input matches no targets' in out:
1105 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), 1126 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out),
1106 output_path) 1127 output_path)
1107 for label in out.splitlines(): 1128 for label in out.splitlines():
1108 build_target = label[2:] 1129 build_target = label[2:]
1109 # We want to accept 'chrome/android:chrome_public_apk' and 1130 # We want to accept 'chrome/android:chrome_public_apk' and
1110 # just 'chrome_public_apk'. This may result in too many targets 1131 # just 'chrome_public_apk'. This may result in too many targets
1111 # getting built, but we can adjust that later if need be. 1132 # getting built, but we can adjust that later if need be.
1112 for input_target in targets: 1133 for input_target in targets:
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
1354 # Then check to see if the arg contains any metacharacters other than 1375 # Then check to see if the arg contains any metacharacters other than
1355 # double quotes; if it does, quote everything (including the double 1376 # double quotes; if it does, quote everything (including the double
1356 # quotes) for safety. 1377 # quotes) for safety.
1357 if any(a in UNSAFE_FOR_CMD for a in arg): 1378 if any(a in UNSAFE_FOR_CMD for a in arg):
1358 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg) 1379 arg = ''.join('^' + a if a in ALL_META_CHARS else a for a in arg)
1359 return arg 1380 return arg
1360 1381
1361 1382
1362 if __name__ == '__main__': 1383 if __name__ == '__main__':
1363 sys.exit(main(sys.argv[1:])) 1384 sys.exit(main(sys.argv[1:]))
OLDNEW
« build/gn_helpers.py ('K') | « build/gn_helpers.py ('k') | tools/mb/mb_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698