chromium/tools/cr/cr/actions/gn.py

# Copyright 2015 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

"""A module to add gn support to cr."""

from __future__ import print_function

import cr
import os
import re

GN_ARG_PREFIX = 'GN_ARG_'


class GnPrepareOut(cr.PrepareOut):
  """A prepare action that runs gn whenever you select an output directory."""

  @property
  def priority(self):
    return -1

  def UpdateContext(self):
    # Collapse GN_ARGS from all GN_ARG prefixes.
    gn_args = cr.context.Find('GN_ARGS') or ''
    for key, value in cr.context.exported.items():
      if key.startswith(GN_ARG_PREFIX):
        gn_args += ' %s=%s' % (key[len(GN_ARG_PREFIX):], value)

    gn_args += (' is_debug=%s' %
        ('true' if cr.context['CR_BUILDTYPE'] == 'Debug' else 'false'))

    arch = cr.context.Find('CR_ENVSETUP_ARCH') or ''
    if arch:
      gn_args += ' target_cpu="%s"' % ('x86' if arch == 'ia32' else arch)

    cr.context['GN_ARGS'] = gn_args.strip()
    if cr.context.verbose >= 1:
      print(cr.context.Substitute('GN_ARGS = {GN_ARGS}'))

  def Prepare(self):
    if cr.context.verbose >= 1:
      print(cr.context.Substitute('Invoking gn with {GN_ARGS}'))

    out_path = os.path.join(cr.context['CR_SRC'], cr.context['CR_OUT_FULL'])
    args_file = os.path.join(out_path, 'args.gn')
    args = {}
    # Split the argument list while preserving quotes,
    # e.g., a="b c" becomes ('a', '"b c"').
    split_re = r'(?:[^\s,"]|"(?:\\.|[^"])*")+'
    for arg in re.findall(split_re, cr.context['GN_ARGS']):
      key, value = arg.split('=', 1)
      args[key] = value

    # Override any existing settings.
    arg_lines = []
    if os.path.exists(args_file):
      with open(args_file) as f:
        for line in f:
          key = line.split('=', 1)[0].strip()
          if key not in args:
            arg_lines.append(line.strip())

    # Append new settings.
    for key, value in args.items():
      arg_lines.append('%s = %s' % (key, value))

    try:
      os.makedirs(out_path)
    except OSError:
      if not os.path.isdir(out_path):
        raise
    with open(args_file, 'w') as f:
      f.write('\n'.join(arg_lines) + '\n')

    cr.Host.Execute('gn', 'gen', out_path)