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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 subp.add_argument('-v', '--verbose', action='store_true', | 68 subp.add_argument('-v', '--verbose', action='store_true', |
69 help='verbose logging') | 69 help='verbose logging') |
70 | 70 |
71 parser = argparse.ArgumentParser(prog='mb') | 71 parser = argparse.ArgumentParser(prog='mb') |
72 subps = parser.add_subparsers() | 72 subps = parser.add_subparsers() |
73 | 73 |
74 subp = subps.add_parser('analyze', | 74 subp = subps.add_parser('analyze', |
75 help='analyze whether changes to a set of files ' | 75 help='analyze whether changes to a set of files ' |
76 'will cause a set of binaries to be rebuilt.') | 76 'will cause a set of binaries to be rebuilt.') |
77 AddCommonOptions(subp) | 77 AddCommonOptions(subp) |
78 subp.add_argument('--swarming-targets-file', | |
79 help='save runtime dependencies for targets listed ' | |
80 'in file.') | |
81 subp.add_argument('path', nargs=1, | 78 subp.add_argument('path', nargs=1, |
82 help='path build was generated into.') | 79 help='path build was generated into.') |
83 subp.add_argument('input_path', nargs=1, | 80 subp.add_argument('input_path', nargs=1, |
84 help='path to a file containing the input arguments ' | 81 help='path to a file containing the input arguments ' |
85 'as a JSON object.') | 82 'as a JSON object.') |
86 subp.add_argument('output_path', nargs=1, | 83 subp.add_argument('output_path', nargs=1, |
87 help='path to a file containing the output arguments ' | 84 help='path to a file containing the output arguments ' |
88 'as a JSON object.') | 85 'as a JSON object.') |
89 subp.set_defaults(func=self.CmdAnalyze) | 86 subp.set_defaults(func=self.CmdAnalyze) |
90 | 87 |
91 subp = subps.add_parser('gen', | 88 subp = subps.add_parser('gen', |
92 help='generate a new set of build files') | 89 help='generate a new set of build files') |
93 AddCommonOptions(subp) | 90 AddCommonOptions(subp) |
94 subp.add_argument('--swarming-targets-file', | 91 subp.add_argument('--swarming-targets-file', |
95 help='save runtime dependencies for targets listed ' | 92 help='save runtime dependencies for targets listed ' |
96 'in file.') | 93 'in file.') |
97 subp.add_argument('path', nargs=1, | 94 subp.add_argument('path', nargs=1, |
98 help='path to generate build into') | 95 help='path to generate build into') |
99 subp.set_defaults(func=self.CmdGen) | 96 subp.set_defaults(func=self.CmdGen) |
100 | 97 |
| 98 subp = subps.add_parser('isolate', |
| 99 help='generate the .isolate files for a given' |
| 100 'binary') |
| 101 AddCommonOptions(subp) |
| 102 subp.add_argument('path', nargs=1, |
| 103 help='path build was generated into') |
| 104 subp.add_argument('target', nargs=1, |
| 105 help='ninja target to generate the isolate for') |
| 106 subp.set_defaults(func=self.CmdIsolate) |
| 107 |
101 subp = subps.add_parser('lookup', | 108 subp = subps.add_parser('lookup', |
102 help='look up the command for a given config or ' | 109 help='look up the command for a given config or ' |
103 'builder') | 110 'builder') |
104 AddCommonOptions(subp) | 111 AddCommonOptions(subp) |
105 subp.set_defaults(func=self.CmdLookup) | 112 subp.set_defaults(func=self.CmdLookup) |
106 | 113 |
| 114 subp = subps.add_parser('run', |
| 115 help='build and run the isolated version of a ' |
| 116 'binary') |
| 117 AddCommonOptions(subp) |
| 118 subp.add_argument('-j', '--jobs', dest='jobs', type=int, |
| 119 help='Number of jobs to pass to ninja') |
| 120 subp.add_argument('--no-build', dest='build', default=True, |
| 121 action='store_false', |
| 122 help='Do not build, just isolate and run') |
| 123 subp.add_argument('path', nargs=1, |
| 124 help='path to generate build into') |
| 125 subp.add_argument('target', nargs=1, |
| 126 help='ninja target to build and run') |
| 127 subp.set_defaults(func=self.CmdRun) |
| 128 |
107 subp = subps.add_parser('validate', | 129 subp = subps.add_parser('validate', |
108 help='validate the config file') | 130 help='validate the config file') |
109 subp.add_argument('-f', '--config-file', metavar='PATH', | 131 subp.add_argument('-f', '--config-file', metavar='PATH', |
110 default=self.default_config, | 132 default=self.default_config, |
111 help='path to config file ' | 133 help='path to config file ' |
112 '(default is //tools/mb/mb_config.pyl)') | 134 '(default is //tools/mb/mb_config.pyl)') |
113 subp.set_defaults(func=self.CmdValidate) | 135 subp.set_defaults(func=self.CmdValidate) |
114 | 136 |
115 subp = subps.add_parser('help', | 137 subp = subps.add_parser('help', |
116 help='Get help on a subcommand.') | 138 help='Get help on a subcommand.') |
117 subp.add_argument(nargs='?', action='store', dest='subcommand', | 139 subp.add_argument(nargs='?', action='store', dest='subcommand', |
118 help='The command to get help for.') | 140 help='The command to get help for.') |
119 subp.set_defaults(func=self.CmdHelp) | 141 subp.set_defaults(func=self.CmdHelp) |
120 | 142 |
121 self.args = parser.parse_args(argv) | 143 self.args = parser.parse_args(argv) |
122 | 144 |
123 def CmdAnalyze(self): | 145 def CmdAnalyze(self): |
124 vals = self.GetConfig() | 146 vals = self.Lookup() |
125 if vals['type'] == 'gn': | 147 if vals['type'] == 'gn': |
126 return self.RunGNAnalyze(vals) | 148 return self.RunGNAnalyze(vals) |
127 elif vals['type'] == 'gyp': | 149 else: |
128 return self.RunGYPAnalyze(vals) | 150 return self.RunGYPAnalyze(vals) |
129 else: | |
130 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | |
131 | 151 |
132 def CmdGen(self): | 152 def CmdGen(self): |
133 vals = self.GetConfig() | 153 vals = self.Lookup() |
134 | |
135 self.ClobberIfNeeded(vals) | 154 self.ClobberIfNeeded(vals) |
136 | 155 |
137 if vals['type'] == 'gn': | 156 if vals['type'] == 'gn': |
138 return self.RunGNGen(vals) | 157 return self.RunGNGen(vals) |
139 if vals['type'] == 'gyp': | 158 else: |
140 return self.RunGYPGen(vals) | 159 return self.RunGYPGen(vals) |
141 | 160 |
142 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | |
143 | |
144 def CmdLookup(self): | |
145 vals = self.GetConfig() | |
146 if vals['type'] == 'gn': | |
147 cmd = self.GNCmd('gen', '_path_', vals['gn_args']) | |
148 env = None | |
149 elif vals['type'] == 'gyp': | |
150 cmd, env = self.GYPCmd('_path_', vals) | |
151 else: | |
152 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | |
153 | |
154 self.PrintCmd(cmd, env) | |
155 return 0 | |
156 | |
157 def CmdHelp(self): | 161 def CmdHelp(self): |
158 if self.args.subcommand: | 162 if self.args.subcommand: |
159 self.ParseArgs([self.args.subcommand, '--help']) | 163 self.ParseArgs([self.args.subcommand, '--help']) |
160 else: | 164 else: |
161 self.ParseArgs(['--help']) | 165 self.ParseArgs(['--help']) |
162 | 166 |
| 167 def CmdIsolate(self): |
| 168 vals = self.GetConfig() |
| 169 if not vals: |
| 170 return 1 |
| 171 |
| 172 if vals['type'] == 'gn': |
| 173 return self.RunGNIsolate(vals) |
| 174 else: |
| 175 return self.Build('%s_run' % self.args.target[0]) |
| 176 |
| 177 def CmdLookup(self): |
| 178 vals = self.Lookup() |
| 179 if vals['type'] == 'gn': |
| 180 cmd = self.GNCmd('gen', '_path_', vals['gn_args']) |
| 181 env = None |
| 182 else: |
| 183 cmd, env = self.GYPCmd('_path_', vals) |
| 184 |
| 185 self.PrintCmd(cmd, env) |
| 186 return 0 |
| 187 |
| 188 def CmdRun(self): |
| 189 vals = self.GetConfig() |
| 190 if not vals: |
| 191 return 1 |
| 192 |
| 193 build_dir = self.args.path[0] |
| 194 target = self.args.target[0] |
| 195 |
| 196 if vals['type'] == 'gn': |
| 197 if self.args.build: |
| 198 ret = self.Build(target) |
| 199 if ret: |
| 200 return ret |
| 201 ret = self.RunGNIsolate(vals) |
| 202 if ret: |
| 203 return ret |
| 204 else: |
| 205 ret = self.Build('%s_run' % target) |
| 206 if ret: |
| 207 return ret |
| 208 |
| 209 ret, _, _ = self.Run([ |
| 210 self.executable, |
| 211 self.PathJoin('tools', 'swarming_client', 'isolate.py'), |
| 212 'run', |
| 213 '-s', |
| 214 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target))], |
| 215 force_verbose=False, buffer_output=False) |
| 216 |
| 217 return ret |
| 218 |
163 def CmdValidate(self): | 219 def CmdValidate(self): |
164 errs = [] | 220 errs = [] |
165 | 221 |
166 # Read the file to make sure it parses. | 222 # Read the file to make sure it parses. |
167 self.ReadConfigFile() | 223 self.ReadConfigFile() |
168 | 224 |
169 # Figure out the whole list of configs and ensure that no config is | 225 # Figure out the whole list of configs and ensure that no config is |
170 # listed in more than one category. | 226 # listed in more than one category. |
171 all_configs = {} | 227 all_configs = {} |
172 for config in self.common_dev_configs: | 228 for config in self.common_dev_configs: |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 errs.append('Unreferenced mixin "%s".' % mixin) | 283 errs.append('Unreferenced mixin "%s".' % mixin) |
228 | 284 |
229 if errs: | 285 if errs: |
230 raise MBErr(('mb config file %s has problems:' % self.args.config_file) + | 286 raise MBErr(('mb config file %s has problems:' % self.args.config_file) + |
231 '\n ' + '\n '.join(errs)) | 287 '\n ' + '\n '.join(errs)) |
232 | 288 |
233 self.Print('mb config file %s looks ok.' % self.args.config_file) | 289 self.Print('mb config file %s looks ok.' % self.args.config_file) |
234 return 0 | 290 return 0 |
235 | 291 |
236 def GetConfig(self): | 292 def GetConfig(self): |
| 293 build_dir = self.args.path[0] |
| 294 |
| 295 vals = {} |
| 296 if self.args.builder or self.args.master or self.args.config: |
| 297 vals = self.Lookup() |
| 298 if vals['type'] == 'gn': |
| 299 # Re-run gn gen in order to ensure the config is consistent with the |
| 300 # build dir. |
| 301 self.RunGNGen(vals) |
| 302 return vals |
| 303 |
| 304 # TODO: We can only get the config for GN build dirs, not GYP build dirs. |
| 305 # GN stores the args that were used in args.gn in the build dir, |
| 306 # but GYP doesn't store them anywhere. We should consider modifying |
| 307 # gyp_chromium to record the arguments it runs with in a similar |
| 308 # manner. |
| 309 |
| 310 mb_type_path = self.PathJoin(self.ToAbsPath(build_dir), 'mb_type') |
| 311 if not self.Exists(mb_type_path): |
| 312 gn_args_path = self.PathJoin(self.ToAbsPath(build_dir), 'args.gn') |
| 313 if not self.Exists(gn_args_path): |
| 314 self.Print('Must either specify a path to an existing GN build dir ' |
| 315 'or pass in a -m/-b pair or a -c flag to specify the ' |
| 316 'configuration') |
| 317 return {} |
| 318 else: |
| 319 mb_type = 'gn' |
| 320 else: |
| 321 mb_type = self.ReadFile(mb_type_path).strip() |
| 322 |
| 323 if mb_type == 'gn': |
| 324 vals = self.GNValsFromDir(build_dir) |
| 325 else: |
| 326 vals = {} |
| 327 vals['type'] = mb_type |
| 328 |
| 329 return vals |
| 330 |
| 331 def GNValsFromDir(self, build_dir): |
| 332 args_contents = self.ReadFile( |
| 333 self.PathJoin(self.ToAbsPath(build_dir), 'args.gn')) |
| 334 gn_args = [] |
| 335 for l in args_contents.splitlines(): |
| 336 fields = l.split(' ') |
| 337 name = fields[0] |
| 338 val = ' '.join(fields[2:]) |
| 339 gn_args.append('%s=%s' % (name, val)) |
| 340 |
| 341 return { |
| 342 'gn_args': ' '.join(gn_args), |
| 343 'type': 'gn', |
| 344 } |
| 345 |
| 346 def Lookup(self): |
237 self.ReadConfigFile() | 347 self.ReadConfigFile() |
238 config = self.ConfigFromArgs() | 348 config = self.ConfigFromArgs() |
239 if not config in self.configs: | 349 if not config in self.configs: |
240 raise MBErr('Config "%s" not found in %s' % | 350 raise MBErr('Config "%s" not found in %s' % |
241 (config, self.args.config_file)) | 351 (config, self.args.config_file)) |
242 | 352 |
243 return self.FlattenConfig(config) | 353 vals = self.FlattenConfig(config) |
| 354 |
| 355 # Do some basic sanity checking on the config so that we |
| 356 # don't have to do this in every caller. |
| 357 assert 'type' in vals, 'No meta-build type specified in the config' |
| 358 assert vals['type'] in ('gn', 'gyp'), ( |
| 359 'Unknown meta-build type "%s"' % vals['gn_args']) |
| 360 |
| 361 return vals |
244 | 362 |
245 def ReadConfigFile(self): | 363 def ReadConfigFile(self): |
246 if not self.Exists(self.args.config_file): | 364 if not self.Exists(self.args.config_file): |
247 raise MBErr('config file not found at %s' % self.args.config_file) | 365 raise MBErr('config file not found at %s' % self.args.config_file) |
248 | 366 |
249 try: | 367 try: |
250 contents = ast.literal_eval(self.ReadFile(self.args.config_file)) | 368 contents = ast.literal_eval(self.ReadFile(self.args.config_file)) |
251 except SyntaxError as e: | 369 except SyntaxError as e: |
252 raise MBErr('Failed to parse config file "%s": %s' % | 370 raise MBErr('Failed to parse config file "%s": %s' % |
253 (self.args.config_file, e)) | 371 (self.args.config_file, e)) |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
346 if self.args.dryrun: | 464 if self.args.dryrun: |
347 return | 465 return |
348 | 466 |
349 if needs_clobber: | 467 if needs_clobber: |
350 self.RemoveDirectory(build_dir) | 468 self.RemoveDirectory(build_dir) |
351 | 469 |
352 self.MaybeMakeDirectory(build_dir) | 470 self.MaybeMakeDirectory(build_dir) |
353 self.WriteFile(mb_type_path, new_mb_type) | 471 self.WriteFile(mb_type_path, new_mb_type) |
354 | 472 |
355 def RunGNGen(self, vals): | 473 def RunGNGen(self, vals): |
356 path = self.args.path[0] | 474 build_dir = self.args.path[0] |
357 | 475 |
358 cmd = self.GNCmd('gen', path, vals['gn_args'], extra_args=['--check']) | 476 cmd = self.GNCmd('gen', build_dir, vals['gn_args'], extra_args=['--check']) |
359 | 477 |
360 swarming_targets = [] | 478 swarming_targets = [] |
361 if self.args.swarming_targets_file: | 479 if getattr(self.args, 'swarming_targets_file', None): |
362 # We need GN to generate the list of runtime dependencies for | 480 # We need GN to generate the list of runtime dependencies for |
363 # the compile targets listed (one per line) in the file so | 481 # the compile targets listed (one per line) in the file so |
364 # we can run them via swarming. We use ninja_to_gn.pyl to convert | 482 # we can run them via swarming. We use ninja_to_gn.pyl to convert |
365 # the compile targets to the matching GN labels. | 483 # the compile targets to the matching GN labels. |
366 contents = self.ReadFile(self.args.swarming_targets_file) | 484 contents = self.ReadFile(self.args.swarming_targets_file) |
367 swarming_targets = contents.splitlines() | 485 swarming_targets = contents.splitlines() |
368 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( | 486 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( |
369 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) | 487 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) |
370 gn_labels = [] | 488 gn_labels = [] |
371 for target in swarming_targets: | 489 for target in swarming_targets: |
372 if not target in gn_isolate_map: | 490 if not target in gn_isolate_map: |
373 raise MBErr('test target "%s" not found in %s' % | 491 raise MBErr('test target "%s" not found in %s' % |
374 (target, '//testing/buildbot/gn_isolate_map.pyl')) | 492 (target, '//testing/buildbot/gn_isolate_map.pyl')) |
375 gn_labels.append(gn_isolate_map[target]['label']) | 493 gn_labels.append(gn_isolate_map[target]['label']) |
376 | 494 |
377 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') | 495 gn_runtime_deps_path = self.ToAbsPath(build_dir, 'runtime_deps') |
378 | 496 |
379 # Since GN hasn't run yet, the build directory may not even exist. | 497 # Since GN hasn't run yet, the build directory may not even exist. |
380 self.MaybeMakeDirectory(self.ToAbsPath(path)) | 498 self.MaybeMakeDirectory(self.ToAbsPath(build_dir)) |
381 | 499 |
382 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') | 500 self.WriteFile(gn_runtime_deps_path, '\n'.join(gn_labels) + '\n') |
383 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) | 501 cmd.append('--runtime-deps-list-file=%s' % gn_runtime_deps_path) |
384 | 502 |
385 ret, _, _ = self.Run(cmd) | 503 ret, _, _ = self.Run(cmd) |
386 if ret: | 504 if ret: |
387 # If `gn gen` failed, we should exit early rather than trying to | 505 # If `gn gen` failed, we should exit early rather than trying to |
388 # generate isolates. Run() will have already logged any error output. | 506 # generate isolates. Run() will have already logged any error output. |
389 self.Print('GN gen failed: %d' % ret) | 507 self.Print('GN gen failed: %d' % ret) |
390 return ret | 508 return ret |
391 | 509 |
392 for target in swarming_targets: | 510 for target in swarming_targets: |
393 if gn_isolate_map[target]['type'] == 'gpu_browser_test': | 511 if gn_isolate_map[target]['type'] == 'gpu_browser_test': |
394 runtime_deps_target = 'browser_tests' | 512 runtime_deps_target = 'browser_tests' |
395 elif gn_isolate_map[target]['type'] == 'script': | 513 elif gn_isolate_map[target]['type'] == 'script': |
396 # For script targets, the build target is usually a group, | 514 # For script targets, the build target is usually a group, |
397 # for which gn generates the runtime_deps next to the stamp file | 515 # for which gn generates the runtime_deps next to the stamp file |
398 # for the label, which lives under the obj/ directory. | 516 # for the label, which lives under the obj/ directory. |
399 label = gn_isolate_map[target]['label'] | 517 label = gn_isolate_map[target]['label'] |
400 runtime_deps_target = 'obj/%s.stamp' % label.replace(':', '/') | 518 runtime_deps_target = 'obj/%s.stamp' % label.replace(':', '/') |
401 else: | 519 else: |
402 runtime_deps_target = target | 520 runtime_deps_target = target |
403 if self.platform == 'win32': | 521 if self.platform == 'win32': |
404 deps_path = self.ToAbsPath(path, | 522 deps_path = self.ToAbsPath(build_dir, |
405 runtime_deps_target + '.exe.runtime_deps') | 523 runtime_deps_target + '.exe.runtime_deps') |
406 else: | 524 else: |
407 deps_path = self.ToAbsPath(path, | 525 deps_path = self.ToAbsPath(build_dir, |
408 runtime_deps_target + '.runtime_deps') | 526 runtime_deps_target + '.runtime_deps') |
409 if not self.Exists(deps_path): | 527 if not self.Exists(deps_path): |
410 raise MBErr('did not generate %s' % deps_path) | 528 raise MBErr('did not generate %s' % deps_path) |
411 | 529 |
412 command, extra_files = self.GetIsolateCommand(target, vals, | 530 command, extra_files = self.GetIsolateCommand(target, vals, |
413 gn_isolate_map) | 531 gn_isolate_map) |
414 | 532 |
415 runtime_deps = self.ReadFile(deps_path).splitlines() | 533 runtime_deps = self.ReadFile(deps_path).splitlines() |
416 | 534 |
417 isolate_path = self.ToAbsPath(path, target + '.isolate') | 535 self.WriteIsolateFiles(build_dir, command, target, runtime_deps, |
418 self.WriteFile(isolate_path, | 536 extra_files) |
419 pprint.pformat({ | |
420 'variables': { | |
421 'command': command, | |
422 'files': sorted(runtime_deps + extra_files), | |
423 } | |
424 }) + '\n') | |
425 | 537 |
426 self.WriteJSON( | 538 return 0 |
427 { | 539 |
428 'args': [ | 540 def RunGNIsolate(self, vals): |
429 '--isolated', | 541 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( |
430 self.ToSrcRelPath('%s%s%s.isolated' % (path, self.sep, target)), | 542 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) |
431 '--isolate', | 543 |
432 self.ToSrcRelPath('%s%s%s.isolate' % (path, self.sep, target)), | 544 build_dir = self.args.path[0] |
433 ], | 545 target = self.args.target[0] |
434 'dir': self.chromium_src_dir, | 546 command, extra_files = self.GetIsolateCommand(target, vals, gn_isolate_map) |
435 'version': 1, | 547 |
436 }, | 548 label = gn_isolate_map[target]['label'] |
437 isolate_path + 'd.gen.json', | 549 ret, out, _ = self.Call(['gn', 'desc', build_dir, label, 'runtime_deps']) |
438 ) | 550 if ret: |
| 551 return ret |
| 552 |
| 553 runtime_deps = out.splitlines() |
| 554 |
| 555 self.WriteIsolateFiles(build_dir, command, target, runtime_deps, |
| 556 extra_files) |
| 557 |
| 558 ret, _, _ = self.Run([ |
| 559 self.executable, |
| 560 self.PathJoin('tools', 'swarming_client', 'isolate.py'), |
| 561 'check', |
| 562 '-i', |
| 563 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)), |
| 564 '-s', |
| 565 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target))], |
| 566 buffer_output=False) |
439 | 567 |
440 return ret | 568 return ret |
441 | 569 |
| 570 def WriteIsolateFiles(self, build_dir, command, target, runtime_deps, |
| 571 extra_files): |
| 572 isolate_path = self.ToAbsPath(build_dir, target + '.isolate') |
| 573 self.WriteFile(isolate_path, |
| 574 pprint.pformat({ |
| 575 'variables': { |
| 576 'command': command, |
| 577 'files': sorted(runtime_deps + extra_files), |
| 578 } |
| 579 }) + '\n') |
| 580 |
| 581 self.WriteJSON( |
| 582 { |
| 583 'args': [ |
| 584 '--isolated', |
| 585 self.ToSrcRelPath('%s/%s.isolated' % (build_dir, target)), |
| 586 '--isolate', |
| 587 self.ToSrcRelPath('%s/%s.isolate' % (build_dir, target)), |
| 588 ], |
| 589 'dir': self.chromium_src_dir, |
| 590 'version': 1, |
| 591 }, |
| 592 isolate_path + 'd.gen.json', |
| 593 ) |
| 594 |
442 def GNCmd(self, subcommand, path, gn_args='', extra_args=None): | 595 def GNCmd(self, subcommand, path, gn_args='', extra_args=None): |
443 if self.platform == 'linux2': | 596 if self.platform == 'linux2': |
444 subdir = 'linux64' | 597 subdir = 'linux64' |
445 elif self.platform == 'darwin': | 598 elif self.platform == 'darwin': |
446 subdir = 'mac' | 599 subdir = 'mac' |
447 else: | 600 else: |
448 subdir = 'win' | 601 subdir = 'win' |
449 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, 'gn') | 602 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, 'gn') |
450 | 603 |
451 cmd = [gn_path, subcommand, path] | 604 cmd = [gn_path, subcommand, path] |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
762 cmd = ['python'] + cmd[1:] | 915 cmd = ['python'] + cmd[1:] |
763 self.Print(*[shell_quoter(arg) for arg in cmd]) | 916 self.Print(*[shell_quoter(arg) for arg in cmd]) |
764 | 917 |
765 def PrintJSON(self, obj): | 918 def PrintJSON(self, obj): |
766 self.Print(json.dumps(obj, indent=2, sort_keys=True)) | 919 self.Print(json.dumps(obj, indent=2, sort_keys=True)) |
767 | 920 |
768 def Print(self, *args, **kwargs): | 921 def Print(self, *args, **kwargs): |
769 # This function largely exists so it can be overridden for testing. | 922 # This function largely exists so it can be overridden for testing. |
770 print(*args, **kwargs) | 923 print(*args, **kwargs) |
771 | 924 |
772 def Run(self, cmd, env=None, force_verbose=True): | 925 def Build(self, target): |
| 926 build_dir = self.ToSrcRelPath(self.args.path[0]) |
| 927 ninja_cmd = ['ninja', '-C', build_dir] |
| 928 if self.args.jobs: |
| 929 ninja_cmd.extend(['-j', '%d' % self.args.jobs]) |
| 930 ninja_cmd.append(target) |
| 931 ret, _, _ = self.Run(ninja_cmd, force_verbose=False, buffer_output=False) |
| 932 return ret |
| 933 |
| 934 def Run(self, cmd, env=None, force_verbose=True, buffer_output=True): |
773 # This function largely exists so it can be overridden for testing. | 935 # This function largely exists so it can be overridden for testing. |
774 if self.args.dryrun or self.args.verbose or force_verbose: | 936 if self.args.dryrun or self.args.verbose or force_verbose: |
775 self.PrintCmd(cmd, env) | 937 self.PrintCmd(cmd, env) |
776 if self.args.dryrun: | 938 if self.args.dryrun: |
777 return 0, '', '' | 939 return 0, '', '' |
778 | 940 |
779 ret, out, err = self.Call(cmd, env=env) | 941 ret, out, err = self.Call(cmd, env=env, buffer_output=buffer_output) |
780 if self.args.verbose or force_verbose: | 942 if self.args.verbose or force_verbose: |
| 943 if ret: |
| 944 self.Print(' -> returned %d' % ret) |
781 if out: | 945 if out: |
782 self.Print(out, end='') | 946 self.Print(out, end='') |
783 if err: | 947 if err: |
784 self.Print(err, end='', file=sys.stderr) | 948 self.Print(err, end='', file=sys.stderr) |
785 return ret, out, err | 949 return ret, out, err |
786 | 950 |
787 def Call(self, cmd, env=None): | 951 def Call(self, cmd, env=None, buffer_output=True): |
788 p = subprocess.Popen(cmd, shell=False, cwd=self.chromium_src_dir, | 952 if buffer_output: |
789 stdout=subprocess.PIPE, stderr=subprocess.PIPE, | 953 p = subprocess.Popen(cmd, shell=False, cwd=self.chromium_src_dir, |
790 env=env) | 954 stdout=subprocess.PIPE, stderr=subprocess.PIPE, |
791 out, err = p.communicate() | 955 env=env) |
| 956 out, err = p.communicate() |
| 957 else: |
| 958 p = subprocess.Popen(cmd, shell=False, cwd=self.chromium_src_dir, |
| 959 env=env) |
| 960 p.wait() |
| 961 out = err = '' |
792 return p.returncode, out, err | 962 return p.returncode, out, err |
793 | 963 |
794 def ExpandUser(self, path): | 964 def ExpandUser(self, path): |
795 # This function largely exists so it can be overridden for testing. | 965 # This function largely exists so it can be overridden for testing. |
796 return os.path.expanduser(path) | 966 return os.path.expanduser(path) |
797 | 967 |
798 def Exists(self, path): | 968 def Exists(self, path): |
799 # This function largely exists so it can be overridden for testing. | 969 # This function largely exists so it can be overridden for testing. |
800 return os.path.exists(path) | 970 return os.path.exists(path) |
801 | 971 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 | 1047 |
878 if __name__ == '__main__': | 1048 if __name__ == '__main__': |
879 try: | 1049 try: |
880 sys.exit(main(sys.argv[1:])) | 1050 sys.exit(main(sys.argv[1:])) |
881 except MBErr as e: | 1051 except MBErr as e: |
882 print(e) | 1052 print(e) |
883 sys.exit(1) | 1053 sys.exit(1) |
884 except KeyboardInterrupt: | 1054 except KeyboardInterrupt: |
885 print("interrupted, exiting", stream=sys.stderr) | 1055 print("interrupted, exiting", stream=sys.stderr) |
886 sys.exit(130) | 1056 sys.exit(130) |
OLD | NEW |