ninja.py revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1# Copyright 2013 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""A module to add ninja support to cr.""" 6 7import os 8 9import cr 10 11_PHONY_SUFFIX = ': phony' 12_LINK_SUFFIX = ': link' 13 14 15class NinjaBuilder(cr.Builder): 16 """An implementation of Builder that uses ninja to do the actual build.""" 17 18 # Some basic configuration installed if we are enabled. 19 ENABLED = cr.Config.From( 20 NINJA_BINARY=os.path.join('{DEPOT_TOOLS}', 'ninja'), 21 NINJA_JOBS=200, 22 NINJA_PROCESSORS=12, 23 NINJA_BUILD_FILE=os.path.join('{CR_BUILD_DIR}', 'build.ninja'), 24 GOMA_DIR=os.path.join('{GOOGLE_CODE}', 'goma'), 25 # Don't rename to GOMA_* or Goma will complain: "unkown GOMA_ parameter". 26 NINJA_GOMA_CTL=os.path.join('{GOMA_DIR}', 'goma_ctl.py'), 27 NINJA_GOMA_CC=os.path.join('{GOMA_DIR}', 'gomacc'), 28 NINJA_GOMA_LINE='cc = {NINJA_GOMA_CC} $', 29 ) 30 # A placeholder for the system detected configuration 31 DETECTED = cr.Config('DETECTED') 32 33 def __init__(self): 34 super(NinjaBuilder, self).__init__() 35 self._targets = [] 36 37 def Build(self, context, targets, arguments): 38 # Make sure Goma is started if Ninja is set to use it. 39 # This may be redundant, but it currently improves reliability. 40 try: 41 with open(context.Get('NINJA_BUILD_FILE'), 'r') as f: 42 if f.readline().rstrip('\n') == context.Get('NINJA_GOMA_LINE'): 43 # Goma is active, so make sure it's started. 44 cr.Host.ExecuteSilently( 45 context, 46 '{NINJA_GOMA_CTL}', 47 'ensure_start' 48 ) 49 except IOError: 50 pass 51 52 build_arguments = [target.build_target for target in targets] 53 build_arguments.extend(arguments) 54 cr.Host.Execute( 55 context, 56 '{NINJA_BINARY}', 57 '-C{CR_BUILD_DIR}', 58 '-j{NINJA_JOBS}', 59 '-l{NINJA_PROCESSORS}', 60 *build_arguments 61 ) 62 63 def Clean(self, context, targets, arguments): 64 build_arguments = [target.build_target for target in targets] 65 build_arguments.extend(arguments) 66 cr.Host.Execute( 67 context, 68 '{NINJA_BINARY}', 69 '-C{CR_BUILD_DIR}', 70 '-tclean', 71 *build_arguments 72 ) 73 74 def GetTargets(self, context): 75 """Overridden from Builder.GetTargets.""" 76 if not self._targets: 77 try: 78 context.Get('CR_BUILD_DIR', raise_errors=True) 79 except KeyError: 80 return self._targets 81 output = cr.Host.Capture( 82 context, 83 '{NINJA_BINARY}', 84 '-C{CR_BUILD_DIR}', 85 '-ttargets', 86 'all' 87 ) 88 for line in output.split('\n'): 89 line = line.strip() 90 if line.endswith(_PHONY_SUFFIX): 91 target = line[:-len(_PHONY_SUFFIX)].strip() 92 self._targets.append(target) 93 elif line.endswith(_LINK_SUFFIX): 94 target = line[:-len(_LINK_SUFFIX)].strip() 95 self._targets.append(target) 96 return self._targets 97 98 @classmethod 99 def ClassInit(cls): 100 # TODO(iancottrell): If we can't detect ninja, we should be disabled. 101 ninja_binaries = cr.Host.SearchPath('ninja') 102 if ninja_binaries: 103 cls.DETECTED.Set(NINJA_BINARY=ninja_binaries[0]) 104