| 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 19 matching lines...) Expand all Loading... |
| 30 return mbw.args.func() | 30 return mbw.args.func() |
| 31 | 31 |
| 32 | 32 |
| 33 class MetaBuildWrapper(object): | 33 class MetaBuildWrapper(object): |
| 34 def __init__(self): | 34 def __init__(self): |
| 35 p = os.path | 35 p = os.path |
| 36 d = os.path.dirname | 36 d = os.path.dirname |
| 37 self.chromium_src_dir = p.normpath(d(d(d(p.abspath(__file__))))) | 37 self.chromium_src_dir = p.normpath(d(d(d(p.abspath(__file__))))) |
| 38 self.default_config = p.join(self.chromium_src_dir, 'tools', 'mb', | 38 self.default_config = p.join(self.chromium_src_dir, 'tools', 'mb', |
| 39 'mb_config.pyl') | 39 'mb_config.pyl') |
| 40 self.executable = sys.executable |
| 40 self.platform = sys.platform | 41 self.platform = sys.platform |
| 42 self.sep = os.sep |
| 41 self.args = argparse.Namespace() | 43 self.args = argparse.Namespace() |
| 42 self.configs = {} | 44 self.configs = {} |
| 43 self.masters = {} | 45 self.masters = {} |
| 44 self.mixins = {} | 46 self.mixins = {} |
| 45 self.private_configs = [] | 47 self.private_configs = [] |
| 46 self.common_dev_configs = [] | 48 self.common_dev_configs = [] |
| 47 self.unsupported_configs = [] | 49 self.unsupported_configs = [] |
| 48 | 50 |
| 49 def ParseArgs(self, argv): | 51 def ParseArgs(self, argv): |
| 50 def AddCommonOptions(subp): | 52 def AddCommonOptions(subp): |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 139 | 141 |
| 140 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 142 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 141 | 143 |
| 142 def CmdLookup(self): | 144 def CmdLookup(self): |
| 143 vals = self.GetConfig() | 145 vals = self.GetConfig() |
| 144 if vals['type'] == 'gn': | 146 if vals['type'] == 'gn': |
| 145 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) | 147 cmd = self.GNCmd('gen', '<path>', vals['gn_args']) |
| 146 elif vals['type'] == 'gyp': | 148 elif vals['type'] == 'gyp': |
| 147 if vals['gyp_crosscompile']: | 149 if vals['gyp_crosscompile']: |
| 148 self.Print('GYP_CROSSCOMPILE=1') | 150 self.Print('GYP_CROSSCOMPILE=1') |
| 149 cmd = self.GYPCmd('<path>', vals['gyp_defines'], vals['gyp_config']) | 151 cmd = self.GYPCmd('<path>', vals['gyp_defines']) |
| 150 else: | 152 else: |
| 151 raise MBErr('Unknown meta-build type "%s"' % vals['type']) | 153 raise MBErr('Unknown meta-build type "%s"' % vals['type']) |
| 152 | 154 |
| 153 self.PrintCmd(cmd) | 155 self.PrintCmd(cmd) |
| 154 return 0 | 156 return 0 |
| 155 | 157 |
| 156 def CmdHelp(self): | 158 def CmdHelp(self): |
| 157 if self.args.subcommand: | 159 if self.args.subcommand: |
| 158 self.ParseArgs([self.args.subcommand, '--help']) | 160 self.ParseArgs([self.args.subcommand, '--help']) |
| 159 else: | 161 else: |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' % | 280 raise MBErr('Builder name "%s" not found under masters[%s] in "%s"' % |
| 279 (self.args.builder, self.args.master, self.args.config_file)) | 281 (self.args.builder, self.args.master, self.args.config_file)) |
| 280 | 282 |
| 281 return self.masters[self.args.master][self.args.builder] | 283 return self.masters[self.args.master][self.args.builder] |
| 282 | 284 |
| 283 def FlattenConfig(self, config): | 285 def FlattenConfig(self, config): |
| 284 mixins = self.configs[config] | 286 mixins = self.configs[config] |
| 285 vals = { | 287 vals = { |
| 286 'type': None, | 288 'type': None, |
| 287 'gn_args': [], | 289 'gn_args': [], |
| 288 'gyp_config': [], | |
| 289 'gyp_defines': '', | 290 'gyp_defines': '', |
| 290 'gyp_crosscompile': False, | 291 'gyp_crosscompile': False, |
| 291 } | 292 } |
| 292 | 293 |
| 293 visited = [] | 294 visited = [] |
| 294 self.FlattenMixins(mixins, vals, visited) | 295 self.FlattenMixins(mixins, vals, visited) |
| 295 return vals | 296 return vals |
| 296 | 297 |
| 297 def FlattenMixins(self, mixins, vals, visited): | 298 def FlattenMixins(self, mixins, vals, visited): |
| 298 for m in mixins: | 299 for m in mixins: |
| 299 if m not in self.mixins: | 300 if m not in self.mixins: |
| 300 raise MBErr('Unknown mixin "%s"' % m) | 301 raise MBErr('Unknown mixin "%s"' % m) |
| 301 | 302 |
| 302 # TODO: check for cycles in mixins. | 303 # TODO: check for cycles in mixins. |
| 303 | 304 |
| 304 visited.append(m) | 305 visited.append(m) |
| 305 | 306 |
| 306 mixin_vals = self.mixins[m] | 307 mixin_vals = self.mixins[m] |
| 307 if 'type' in mixin_vals: | 308 if 'type' in mixin_vals: |
| 308 vals['type'] = mixin_vals['type'] | 309 vals['type'] = mixin_vals['type'] |
| 309 if 'gn_args' in mixin_vals: | 310 if 'gn_args' in mixin_vals: |
| 310 if vals['gn_args']: | 311 if vals['gn_args']: |
| 311 vals['gn_args'] += ' ' + mixin_vals['gn_args'] | 312 vals['gn_args'] += ' ' + mixin_vals['gn_args'] |
| 312 else: | 313 else: |
| 313 vals['gn_args'] = mixin_vals['gn_args'] | 314 vals['gn_args'] = mixin_vals['gn_args'] |
| 314 if 'gyp_config' in mixin_vals: | |
| 315 vals['gyp_config'] = mixin_vals['gyp_config'] | |
| 316 if 'gyp_crosscompile' in mixin_vals: | 315 if 'gyp_crosscompile' in mixin_vals: |
| 317 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] | 316 vals['gyp_crosscompile'] = mixin_vals['gyp_crosscompile'] |
| 318 if 'gyp_defines' in mixin_vals: | 317 if 'gyp_defines' in mixin_vals: |
| 319 if vals['gyp_defines']: | 318 if vals['gyp_defines']: |
| 320 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] | 319 vals['gyp_defines'] += ' ' + mixin_vals['gyp_defines'] |
| 321 else: | 320 else: |
| 322 vals['gyp_defines'] = mixin_vals['gyp_defines'] | 321 vals['gyp_defines'] = mixin_vals['gyp_defines'] |
| 323 if 'mixins' in mixin_vals: | 322 if 'mixins' in mixin_vals: |
| 324 self.FlattenMixins(mixin_vals['mixins'], vals, visited) | 323 self.FlattenMixins(mixin_vals['mixins'], vals, visited) |
| 325 return vals | 324 return vals |
| 326 | 325 |
| 327 def ClobberIfNeeded(self, vals): | 326 def ClobberIfNeeded(self, vals): |
| 328 path = self.args.path[0] | 327 path = self.args.path[0] |
| 329 build_dir = self.ToAbsPath(path) | 328 build_dir = self.ToAbsPath(path) |
| 330 mb_type_path = os.path.join(build_dir, 'mb_type') | 329 mb_type_path = self.PathJoin(build_dir, 'mb_type') |
| 331 needs_clobber = False | 330 needs_clobber = False |
| 332 new_mb_type = vals['type'] | 331 new_mb_type = vals['type'] |
| 333 if self.Exists(build_dir): | 332 if self.Exists(build_dir): |
| 334 if self.Exists(mb_type_path): | 333 if self.Exists(mb_type_path): |
| 335 old_mb_type = self.ReadFile(mb_type_path) | 334 old_mb_type = self.ReadFile(mb_type_path) |
| 336 if old_mb_type != new_mb_type: | 335 if old_mb_type != new_mb_type: |
| 337 self.Print("Build type mismatch: was %s, will be %s, clobbering %s" % | 336 self.Print("Build type mismatch: was %s, will be %s, clobbering %s" % |
| 338 (old_mb_type, new_mb_type, path)) | 337 (old_mb_type, new_mb_type, path)) |
| 339 needs_clobber = True | 338 needs_clobber = True |
| 340 else: | 339 else: |
| (...skipping 16 matching lines...) Expand all Loading... |
| 357 cmd = self.GNCmd('gen', path, vals['gn_args']) | 356 cmd = self.GNCmd('gen', path, vals['gn_args']) |
| 358 | 357 |
| 359 swarming_targets = [] | 358 swarming_targets = [] |
| 360 if self.args.swarming_targets_file: | 359 if self.args.swarming_targets_file: |
| 361 # We need GN to generate the list of runtime dependencies for | 360 # We need GN to generate the list of runtime dependencies for |
| 362 # the compile targets listed (one per line) in the file so | 361 # the compile targets listed (one per line) in the file so |
| 363 # we can run them via swarming. We use ninja_to_gn.pyl to convert | 362 # we can run them via swarming. We use ninja_to_gn.pyl to convert |
| 364 # the compile targets to the matching GN labels. | 363 # the compile targets to the matching GN labels. |
| 365 contents = self.ReadFile(self.args.swarming_targets_file) | 364 contents = self.ReadFile(self.args.swarming_targets_file) |
| 366 swarming_targets = contents.splitlines() | 365 swarming_targets = contents.splitlines() |
| 367 gn_isolate_map = ast.literal_eval(self.ReadFile(os.path.join( | 366 gn_isolate_map = ast.literal_eval(self.ReadFile(self.PathJoin( |
| 368 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) | 367 self.chromium_src_dir, 'testing', 'buildbot', 'gn_isolate_map.pyl'))) |
| 369 gn_labels = [] | 368 gn_labels = [] |
| 370 for target in swarming_targets: | 369 for target in swarming_targets: |
| 371 if not target in gn_isolate_map: | 370 if not target in gn_isolate_map: |
| 372 raise MBErr('test target "%s" not found in %s' % | 371 raise MBErr('test target "%s" not found in %s' % |
| 373 (target, '//testing/buildbot/gn_isolate_map.pyl')) | 372 (target, '//testing/buildbot/gn_isolate_map.pyl')) |
| 374 gn_labels.append(gn_isolate_map[target]['label']) | 373 gn_labels.append(gn_isolate_map[target]['label']) |
| 375 | 374 |
| 376 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') | 375 gn_runtime_deps_path = self.ToAbsPath(path, 'runtime_deps') |
| 377 | 376 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 392 if gn_isolate_map[target]['type'] == 'gpu_browser_test': | 391 if gn_isolate_map[target]['type'] == 'gpu_browser_test': |
| 393 runtime_deps_target = 'browser_tests' | 392 runtime_deps_target = 'browser_tests' |
| 394 elif gn_isolate_map[target]['type'] == 'script': | 393 elif gn_isolate_map[target]['type'] == 'script': |
| 395 # For script targets, the build target is usually a group, | 394 # For script targets, the build target is usually a group, |
| 396 # for which gn generates the runtime_deps next to the stamp file | 395 # for which gn generates the runtime_deps next to the stamp file |
| 397 # for the label, which lives under the obj/ directory. | 396 # for the label, which lives under the obj/ directory. |
| 398 label = gn_isolate_map[target]['label'] | 397 label = gn_isolate_map[target]['label'] |
| 399 runtime_deps_target = 'obj/%s.stamp' % label.replace(':', '/') | 398 runtime_deps_target = 'obj/%s.stamp' % label.replace(':', '/') |
| 400 else: | 399 else: |
| 401 runtime_deps_target = target | 400 runtime_deps_target = target |
| 402 if sys.platform == 'win32': | 401 if self.platform == 'win32': |
| 403 deps_path = self.ToAbsPath(path, | 402 deps_path = self.ToAbsPath(path, |
| 404 runtime_deps_target + '.exe.runtime_deps') | 403 runtime_deps_target + '.exe.runtime_deps') |
| 405 else: | 404 else: |
| 406 deps_path = self.ToAbsPath(path, | 405 deps_path = self.ToAbsPath(path, |
| 407 runtime_deps_target + '.runtime_deps') | 406 runtime_deps_target + '.runtime_deps') |
| 408 if not self.Exists(deps_path): | 407 if not self.Exists(deps_path): |
| 409 raise MBErr('did not generate %s' % deps_path) | 408 raise MBErr('did not generate %s' % deps_path) |
| 410 | 409 |
| 411 command, extra_files = self.GetIsolateCommand(target, vals, | 410 command, extra_files = self.GetIsolateCommand(target, vals, |
| 412 gn_isolate_map) | 411 gn_isolate_map) |
| 413 | 412 |
| 414 runtime_deps = self.ReadFile(deps_path).splitlines() | 413 runtime_deps = self.ReadFile(deps_path).splitlines() |
| 415 | 414 |
| 416 isolate_path = self.ToAbsPath(path, target + '.isolate') | 415 isolate_path = self.ToAbsPath(path, target + '.isolate') |
| 417 self.WriteFile(isolate_path, | 416 self.WriteFile(isolate_path, |
| 418 pprint.pformat({ | 417 pprint.pformat({ |
| 419 'variables': { | 418 'variables': { |
| 420 'command': command, | 419 'command': command, |
| 421 'files': sorted(runtime_deps + extra_files), | 420 'files': sorted(runtime_deps + extra_files), |
| 422 } | 421 } |
| 423 }) + '\n') | 422 }) + '\n') |
| 424 | 423 |
| 425 self.WriteJSON( | 424 self.WriteJSON( |
| 426 { | 425 { |
| 427 'args': [ | 426 'args': [ |
| 428 '--isolated', | 427 '--isolated', |
| 429 self.ToSrcRelPath('%s%s%s.isolated' % (path, os.sep, target)), | 428 self.ToSrcRelPath('%s%s%s.isolated' % (path, self.sep, target)), |
| 430 '--isolate', | 429 '--isolate', |
| 431 self.ToSrcRelPath('%s%s%s.isolate' % (path, os.sep, target)), | 430 self.ToSrcRelPath('%s%s%s.isolate' % (path, self.sep, target)), |
| 432 ], | 431 ], |
| 433 'dir': self.chromium_src_dir, | 432 'dir': self.chromium_src_dir, |
| 434 'version': 1, | 433 'version': 1, |
| 435 }, | 434 }, |
| 436 isolate_path + 'd.gen.json', | 435 isolate_path + 'd.gen.json', |
| 437 ) | 436 ) |
| 438 | 437 |
| 439 return ret | 438 return ret |
| 440 | 439 |
| 441 def GNCmd(self, subcommand, path, gn_args=''): | 440 def GNCmd(self, subcommand, path, gn_args=''): |
| 442 if self.platform == 'linux2': | 441 if self.platform == 'linux2': |
| 443 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'linux64', | 442 subdir = 'linux64' |
| 444 'gn') | |
| 445 elif self.platform == 'darwin': | 443 elif self.platform == 'darwin': |
| 446 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'mac', | 444 subdir = 'mac' |
| 447 'gn') | |
| 448 else: | 445 else: |
| 449 gn_path = os.path.join(self.chromium_src_dir, 'buildtools', 'win', | 446 subdir = 'win' |
| 450 'gn.exe') | 447 gn_path = self.PathJoin(self.chromium_src_dir, 'buildtools', subdir, 'gn') |
| 451 | 448 |
| 452 cmd = [gn_path, subcommand, path] | 449 cmd = [gn_path, subcommand, path] |
| 453 gn_args = gn_args.replace("$(goma_dir)", self.args.goma_dir) | 450 gn_args = gn_args.replace("$(goma_dir)", self.args.goma_dir) |
| 454 if gn_args: | 451 if gn_args: |
| 455 cmd.append('--args=%s' % gn_args) | 452 cmd.append('--args=%s' % gn_args) |
| 456 return cmd | 453 return cmd |
| 457 | 454 |
| 458 def RunGYPGen(self, vals): | 455 def RunGYPGen(self, vals): |
| 459 path = self.args.path[0] | 456 path = self.args.path[0] |
| 460 | 457 |
| 461 output_dir, gyp_config = self.ParseGYPConfigPath(path) | 458 output_dir = self.ParseGYPConfigPath(path) |
| 462 if gyp_config != vals['gyp_config']: | 459 cmd = self.GYPCmd(output_dir, vals['gyp_defines']) |
| 463 raise MBErr('The last component of the path (%s) must match the ' | |
| 464 'GYP configuration specified in the config (%s), and ' | |
| 465 'it does not.' % (gyp_config, vals['gyp_config'])) | |
| 466 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | |
| 467 env = None | 460 env = None |
| 468 if vals['gyp_crosscompile']: | 461 if vals['gyp_crosscompile']: |
| 469 if self.args.verbose: | 462 if self.args.verbose: |
| 470 self.Print('Setting GYP_CROSSCOMPILE=1 in the environment') | 463 self.Print('Setting GYP_CROSSCOMPILE=1 in the environment') |
| 471 env = os.environ.copy() | 464 env = os.environ.copy() |
| 472 env['GYP_CROSSCOMPILE'] = '1' | 465 env['GYP_CROSSCOMPILE'] = '1' |
| 473 ret, _, _ = self.Run(cmd, env=env) | 466 ret, _, _ = self.Run(cmd, env=env) |
| 474 return ret | 467 return ret |
| 475 | 468 |
| 476 def RunGYPAnalyze(self, vals): | 469 def RunGYPAnalyze(self, vals): |
| 477 output_dir, gyp_config = self.ParseGYPConfigPath(self.args.path[0]) | 470 output_dir = self.ParseGYPConfigPath(self.args.path[0]) |
| 478 if gyp_config != vals['gyp_config']: | |
| 479 raise MBErr('The last component of the path (%s) must match the ' | |
| 480 'GYP configuration specified in the config (%s), and ' | |
| 481 'it does not.' % (gyp_config, vals['gyp_config'])) | |
| 482 if self.args.verbose: | 471 if self.args.verbose: |
| 483 inp = self.ReadInputJSON(['files', 'targets']) | 472 inp = self.ReadInputJSON(['files', 'targets']) |
| 484 self.Print() | 473 self.Print() |
| 485 self.Print('analyze input:') | 474 self.Print('analyze input:') |
| 486 self.PrintJSON(inp) | 475 self.PrintJSON(inp) |
| 487 self.Print() | 476 self.Print() |
| 488 | 477 |
| 489 cmd = self.GYPCmd(output_dir, vals['gyp_defines'], config=gyp_config) | 478 cmd = self.GYPCmd(output_dir, vals['gyp_defines']) |
| 490 cmd.extend(['-f', 'analyzer', | 479 cmd.extend(['-f', 'analyzer', |
| 491 '-G', 'config_path=%s' % self.args.input_path[0], | 480 '-G', 'config_path=%s' % self.args.input_path[0], |
| 492 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) | 481 '-G', 'analyzer_output_path=%s' % self.args.output_path[0]]) |
| 493 ret, _, _ = self.Run(cmd) | 482 ret, _, _ = self.Run(cmd) |
| 494 if not ret and self.args.verbose: | 483 if not ret and self.args.verbose: |
| 495 outp = json.loads(self.ReadFile(self.args.output_path[0])) | 484 outp = json.loads(self.ReadFile(self.args.output_path[0])) |
| 496 self.Print() | 485 self.Print() |
| 497 self.Print('analyze output:') | 486 self.Print('analyze output:') |
| 498 self.PrintJSON(outp) | 487 self.PrintJSON(outp) |
| 499 self.Print() | 488 self.Print() |
| 500 | 489 |
| 501 return ret | 490 return ret |
| 502 | 491 |
| 503 def GetIsolateCommand(self, target, vals, gn_isolate_map): | 492 def GetIsolateCommand(self, target, vals, gn_isolate_map): |
| 504 # This needs to mirror the settings in //build/config/ui.gni: | 493 # This needs to mirror the settings in //build/config/ui.gni: |
| 505 # use_x11 = is_linux && !use_ozone. | 494 # use_x11 = is_linux && !use_ozone. |
| 506 # TODO(dpranke): Figure out how to keep this in sync better. | 495 # TODO(dpranke): Figure out how to keep this in sync better. |
| 507 use_x11 = (sys.platform == 'linux2' and | 496 use_x11 = (self.platform == 'linux2' and |
| 508 not 'target_os="android"' in vals['gn_args'] and | 497 not 'target_os="android"' in vals['gn_args'] and |
| 509 not 'use_ozone=true' in vals['gn_args']) | 498 not 'use_ozone=true' in vals['gn_args']) |
| 510 | 499 |
| 511 asan = 'is_asan=true' in vals['gn_args'] | 500 asan = 'is_asan=true' in vals['gn_args'] |
| 512 msan = 'is_msan=true' in vals['gn_args'] | 501 msan = 'is_msan=true' in vals['gn_args'] |
| 513 tsan = 'is_tsan=true' in vals['gn_args'] | 502 tsan = 'is_tsan=true' in vals['gn_args'] |
| 514 | 503 |
| 515 executable_suffix = '.exe' if sys.platform == 'win32' else '' | 504 executable_suffix = '.exe' if self.platform == 'win32' else '' |
| 516 | 505 |
| 517 test_type = gn_isolate_map[target]['type'] | 506 test_type = gn_isolate_map[target]['type'] |
| 518 cmdline = [] | 507 cmdline = [] |
| 519 extra_files = [] | 508 extra_files = [] |
| 520 | 509 |
| 521 if use_x11 and test_type == 'windowed_test_launcher': | 510 if use_x11 and test_type == 'windowed_test_launcher': |
| 522 extra_files = [ | 511 extra_files = [ |
| 523 'xdisplaycheck', | 512 'xdisplaycheck', |
| 524 '../../testing/test_env.py', | 513 '../../testing/test_env.py', |
| 525 '../../testing/xvfb.py', | 514 '../../testing/xvfb.py', |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 './' + str(target) + executable_suffix, | 562 './' + str(target) + executable_suffix, |
| 574 ] + gn_isolate_map[target].get('args') | 563 ] + gn_isolate_map[target].get('args') |
| 575 | 564 |
| 576 else: | 565 else: |
| 577 self.WriteFailureAndRaise('No command line for %s found (test type %s).' | 566 self.WriteFailureAndRaise('No command line for %s found (test type %s).' |
| 578 % (target, test_type), output_path=None) | 567 % (target, test_type), output_path=None) |
| 579 | 568 |
| 580 return cmdline, extra_files | 569 return cmdline, extra_files |
| 581 | 570 |
| 582 def ToAbsPath(self, build_path, *comps): | 571 def ToAbsPath(self, build_path, *comps): |
| 583 return os.path.join(self.chromium_src_dir, | 572 return self.PathJoin(self.chromium_src_dir, |
| 584 self.ToSrcRelPath(build_path), | 573 self.ToSrcRelPath(build_path), |
| 585 *comps) | 574 *comps) |
| 586 | 575 |
| 587 def ToSrcRelPath(self, path): | 576 def ToSrcRelPath(self, path): |
| 588 """Returns a relative path from the top of the repo.""" | 577 """Returns a relative path from the top of the repo.""" |
| 589 # TODO: Support normal paths in addition to source-absolute paths. | 578 # TODO: Support normal paths in addition to source-absolute paths. |
| 590 assert(path.startswith('//')) | 579 assert(path.startswith('//')) |
| 591 return path[2:].replace('/', os.sep) | 580 return path[2:].replace('/', self.sep) |
| 592 | 581 |
| 593 def ParseGYPConfigPath(self, path): | 582 def ParseGYPConfigPath(self, path): |
| 594 rpath = self.ToSrcRelPath(path) | 583 rpath = self.ToSrcRelPath(path) |
| 595 output_dir, _, config = rpath.rpartition('/') | 584 output_dir, _, _ = rpath.rpartition(self.sep) |
| 596 self.CheckGYPConfigIsSupported(config, path) | 585 return output_dir |
| 597 return output_dir, config | |
| 598 | 586 |
| 599 def CheckGYPConfigIsSupported(self, config, path): | 587 def GYPCmd(self, output_dir, gyp_defines): |
| 600 if config not in ('Debug', 'Release'): | |
| 601 if (sys.platform in ('win32', 'cygwin') and | |
| 602 config not in ('Debug_x64', 'Release_x64')): | |
| 603 raise MBErr('Unknown or unsupported config type "%s" in "%s"' % | |
| 604 config, path) | |
| 605 | |
| 606 def GYPCmd(self, output_dir, gyp_defines, config): | |
| 607 gyp_defines = gyp_defines.replace("$(goma_dir)", self.args.goma_dir) | 588 gyp_defines = gyp_defines.replace("$(goma_dir)", self.args.goma_dir) |
| 608 cmd = [ | 589 cmd = [ |
| 609 sys.executable, | 590 self.executable, |
| 610 os.path.join('build', 'gyp_chromium'), | 591 self.PathJoin('build', 'gyp_chromium'), |
| 611 '-G', | 592 '-G', |
| 612 'output_dir=' + output_dir, | 593 'output_dir=' + output_dir, |
| 613 '-G', | |
| 614 'config=' + config, | |
| 615 ] | 594 ] |
| 616 for d in shlex.split(gyp_defines): | 595 for d in shlex.split(gyp_defines): |
| 617 cmd += ['-D', d] | 596 cmd += ['-D', d] |
| 618 return cmd | 597 return cmd |
| 619 | 598 |
| 620 def RunGNAnalyze(self, vals): | 599 def RunGNAnalyze(self, vals): |
| 621 # analyze runs before 'gn gen' now, so we need to run gn gen | 600 # analyze runs before 'gn gen' now, so we need to run gn gen |
| 622 # in order to ensure that we have a build directory. | 601 # in order to ensure that we have a build directory. |
| 623 ret = self.RunGNGen(vals) | 602 ret = self.RunGNGen(vals) |
| 624 if ret: | 603 if ret: |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 660 response_file.close() | 639 response_file.close() |
| 661 | 640 |
| 662 matching_targets = [] | 641 matching_targets = [] |
| 663 try: | 642 try: |
| 664 cmd = self.GNCmd('refs', self.args.path[0]) + [ | 643 cmd = self.GNCmd('refs', self.args.path[0]) + [ |
| 665 '@%s' % response_file.name, '--all', '--as=output'] | 644 '@%s' % response_file.name, '--all', '--as=output'] |
| 666 ret, out, _ = self.Run(cmd, force_verbose=False) | 645 ret, out, _ = self.Run(cmd, force_verbose=False) |
| 667 if ret and not 'The input matches no targets' in out: | 646 if ret and not 'The input matches no targets' in out: |
| 668 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), | 647 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), |
| 669 output_path) | 648 output_path) |
| 670 build_dir = self.ToSrcRelPath(self.args.path[0]) + os.sep | 649 build_dir = self.ToSrcRelPath(self.args.path[0]) + self.sep |
| 671 for output in out.splitlines(): | 650 for output in out.splitlines(): |
| 672 build_output = output.replace(build_dir, '') | 651 build_output = output.replace(build_dir, '') |
| 673 if build_output in inp['targets']: | 652 if build_output in inp['targets']: |
| 674 matching_targets.append(build_output) | 653 matching_targets.append(build_output) |
| 675 | 654 |
| 676 cmd = self.GNCmd('refs', self.args.path[0]) + [ | 655 cmd = self.GNCmd('refs', self.args.path[0]) + [ |
| 677 '@%s' % response_file.name, '--all'] | 656 '@%s' % response_file.name, '--all'] |
| 678 ret, out, _ = self.Run(cmd, force_verbose=False) | 657 ret, out, _ = self.Run(cmd, force_verbose=False) |
| 679 if ret and not 'The input matches no targets' in out: | 658 if ret and not 'The input matches no targets' in out: |
| 680 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), | 659 self.WriteFailureAndRaise('gn refs returned %d: %s' % (ret, out), |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 | 718 |
| 740 def WriteJSON(self, obj, path, force_verbose=False): | 719 def WriteJSON(self, obj, path, force_verbose=False): |
| 741 try: | 720 try: |
| 742 self.WriteFile(path, json.dumps(obj, indent=2, sort_keys=True) + '\n', | 721 self.WriteFile(path, json.dumps(obj, indent=2, sort_keys=True) + '\n', |
| 743 force_verbose=force_verbose) | 722 force_verbose=force_verbose) |
| 744 except Exception as e: | 723 except Exception as e: |
| 745 raise MBErr('Error %s writing to the output path "%s"' % | 724 raise MBErr('Error %s writing to the output path "%s"' % |
| 746 (e, path)) | 725 (e, path)) |
| 747 | 726 |
| 748 def PrintCmd(self, cmd): | 727 def PrintCmd(self, cmd): |
| 749 if cmd[0] == sys.executable: | 728 if cmd[0] == self.executable: |
| 750 cmd = ['python'] + cmd[1:] | 729 cmd = ['python'] + cmd[1:] |
| 751 self.Print(*[pipes.quote(c) for c in cmd]) | 730 self.Print(*[pipes.quote(c) for c in cmd]) |
| 752 | 731 |
| 753 def PrintJSON(self, obj): | 732 def PrintJSON(self, obj): |
| 754 self.Print(json.dumps(obj, indent=2, sort_keys=True)) | 733 self.Print(json.dumps(obj, indent=2, sort_keys=True)) |
| 755 | 734 |
| 756 def Print(self, *args, **kwargs): | 735 def Print(self, *args, **kwargs): |
| 757 # This function largely exists so it can be overridden for testing. | 736 # This function largely exists so it can be overridden for testing. |
| 758 print(*args, **kwargs) | 737 print(*args, **kwargs) |
| 759 | 738 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 787 # This function largely exists so it can be overridden for testing. | 766 # This function largely exists so it can be overridden for testing. |
| 788 return os.path.exists(path) | 767 return os.path.exists(path) |
| 789 | 768 |
| 790 def MaybeMakeDirectory(self, path): | 769 def MaybeMakeDirectory(self, path): |
| 791 try: | 770 try: |
| 792 os.makedirs(path) | 771 os.makedirs(path) |
| 793 except OSError, e: | 772 except OSError, e: |
| 794 if e.errno != errno.EEXIST: | 773 if e.errno != errno.EEXIST: |
| 795 raise | 774 raise |
| 796 | 775 |
| 776 def PathJoin(self, *comps): |
| 777 # This function largely exists so it can be overriden for testing. |
| 778 return os.path.join(*comps) |
| 779 |
| 797 def ReadFile(self, path): | 780 def ReadFile(self, path): |
| 798 # This function largely exists so it can be overriden for testing. | 781 # This function largely exists so it can be overriden for testing. |
| 799 with open(path) as fp: | 782 with open(path) as fp: |
| 800 return fp.read() | 783 return fp.read() |
| 801 | 784 |
| 802 def RemoveFile(self, path): | 785 def RemoveFile(self, path): |
| 803 # This function largely exists so it can be overriden for testing. | 786 # This function largely exists so it can be overriden for testing. |
| 804 os.remove(path) | 787 os.remove(path) |
| 805 | 788 |
| 806 def RemoveDirectory(self, abs_path): | 789 def RemoveDirectory(self, abs_path): |
| 807 if sys.platform == 'win32': | 790 if self.platform == 'win32': |
| 808 # In other places in chromium, we often have to retry this command | 791 # In other places in chromium, we often have to retry this command |
| 809 # because we're worried about other processes still holding on to | 792 # because we're worried about other processes still holding on to |
| 810 # file handles, but when MB is invoked, it will be early enough in the | 793 # file handles, but when MB is invoked, it will be early enough in the |
| 811 # build that their should be no other processes to interfere. We | 794 # build that their should be no other processes to interfere. We |
| 812 # can change this if need be. | 795 # can change this if need be. |
| 813 self.Run(['cmd.exe', '/c', 'rmdir', '/q', '/s', abs_path]) | 796 self.Run(['cmd.exe', '/c', 'rmdir', '/q', '/s', abs_path]) |
| 814 else: | 797 else: |
| 815 shutil.rmtree(abs_path, ignore_errors=True) | 798 shutil.rmtree(abs_path, ignore_errors=True) |
| 816 | 799 |
| 817 def TempFile(self, mode='w'): | 800 def TempFile(self, mode='w'): |
| (...skipping 14 matching lines...) Expand all Loading... |
| 832 | 815 |
| 833 if __name__ == '__main__': | 816 if __name__ == '__main__': |
| 834 try: | 817 try: |
| 835 sys.exit(main(sys.argv[1:])) | 818 sys.exit(main(sys.argv[1:])) |
| 836 except MBErr as e: | 819 except MBErr as e: |
| 837 print(e) | 820 print(e) |
| 838 sys.exit(1) | 821 sys.exit(1) |
| 839 except KeyboardInterrupt: | 822 except KeyboardInterrupt: |
| 840 print("interrupted, exiting", stream=sys.stderr) | 823 print("interrupted, exiting", stream=sys.stderr) |
| 841 sys.exit(130) | 824 sys.exit(130) |
| OLD | NEW |