1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)# found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)"""A module to add ninja support to cr."""
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuimport multiprocessing
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import os
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)import cr
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_PHONY_SUFFIX = ': phony'
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)_LINK_SUFFIX = ': link'
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
16effb81e5f8246d0db0270817048dc992db66e9fbBen MurdochDEFAULT = cr.Config.From(
17effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    GOMA_DIR=os.path.expanduser('~/goma'),
18effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch)
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class NinjaBuilder(cr.Builder):
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  """An implementation of Builder that uses ninja to do the actual build."""
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  # Some basic configuration installed if we are enabled.
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXTRA_FOR_IO_BOUND_JOBS = 2
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ENABLED = cr.Config.From(
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NINJA_BINARY=os.path.join('{DEPOT_TOOLS}', 'ninja'),
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NINJA_JOBS=multiprocessing.cpu_count() + EXTRA_FOR_IO_BOUND_JOBS,
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NINJA_PROCESSORS=multiprocessing.cpu_count(),
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NINJA_BUILD_FILE=os.path.join('{CR_BUILD_DIR}', 'build.ninja'),
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # Don't rename to GOMA_* or Goma will complain: "unkown GOMA_ parameter".
31effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      NINJA_GOMA_LINE='cc = {CR_GOMA_CC} $',
32effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  )
33effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  # A config block only included if goma is detected.
34effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  GOMA = cr.Config.From(
35effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      CR_GOMA_CC=os.path.join('{GOMA_DIR}', 'gomacc'),
36effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      CR_GOMA_CTL=os.path.join('{GOMA_DIR}', 'goma_ctl.py'),
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GOMA_DIR='{CR_GOMA_DIR}',
38effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GYP_DEF_gomadir='{CR_GOMA_DIR}',
39effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      GYP_DEF_use_goma=1,
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      NINJA_JOBS=multiprocessing.cpu_count() * 10,
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  )
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  # A placeholder for the system detected configuration
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DETECTED = cr.Config('DETECTED')
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  def __init__(self):
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    super(NinjaBuilder, self).__init__()
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    self._targets = []
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
49effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def Build(self, targets, arguments):
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Make sure Goma is started if Ninja is set to use it.
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # This may be redundant, but it currently improves reliability.
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    try:
53effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      with open(cr.context.Get('NINJA_BUILD_FILE'), 'r') as f:
54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        if f.readline().rstrip('\n') == cr.context.Get('NINJA_GOMA_LINE'):
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          # Goma is active, so make sure it's started.
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          cr.Host.ExecuteSilently(
57effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch              '{CR_GOMA_CTL}',
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              'ensure_start'
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          )
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    except IOError:
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      pass
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    build_arguments = [target.build_target for target in targets]
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    build_arguments.extend(arguments)
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    cr.Host.Execute(
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '{NINJA_BINARY}',
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '-C{CR_BUILD_DIR}',
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '-j{NINJA_JOBS}',
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '-l{NINJA_PROCESSORS}',
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        *build_arguments
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    )
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
73effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def Clean(self, targets, arguments):
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    build_arguments = [target.build_target for target in targets]
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    build_arguments.extend(arguments)
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    cr.Host.Execute(
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '{NINJA_BINARY}',
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '-C{CR_BUILD_DIR}',
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        '-tclean',
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        *build_arguments
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    )
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  def GetTargets(self):
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    """Overridden from Builder.GetTargets."""
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if not self._targets:
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      try:
87effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch        cr.context.Get('CR_BUILD_DIR', raise_errors=True)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      except KeyError:
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        return self._targets
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      output = cr.Host.Capture(
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          '{NINJA_BINARY}',
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          '-C{CR_BUILD_DIR}',
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          '-ttargets',
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          'all'
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      )
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      for line in output.split('\n'):
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        line = line.strip()
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if line.endswith(_PHONY_SUFFIX):
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          target = line[:-len(_PHONY_SUFFIX)].strip()
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          self._targets.append(target)
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        elif line.endswith(_LINK_SUFFIX):
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          target = line[:-len(_LINK_SUFFIX)].strip()
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          self._targets.append(target)
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return self._targets
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  @classmethod
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def ClassInit(cls):
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    # TODO(iancottrell): If we can't detect ninja, we should be disabled.
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ninja_binaries = cr.Host.SearchPath('ninja')
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if ninja_binaries:
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      cls.DETECTED.Set(NINJA_BINARY=ninja_binaries[0])
112effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
113effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    goma_binaries = cr.Host.SearchPath('gomacc', [
114effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      '{GOMA_DIR}',
115effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      '/usr/local/google/code/goma',
116effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      os.path.expanduser('~/goma')
117effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    ])
118effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    if goma_binaries:
119effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      cls.DETECTED.Set(CR_GOMA_DIR=os.path.dirname(goma_binaries[0]))
120effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      cls.DETECTED.AddChildren(cls.GOMA)
121