"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/node-gyp/gyp/pylib/gyp/generator/cmake.py" (7 Feb 2017, 44604 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file.

    1 # Copyright (c) 2013 Google Inc. 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 """cmake output module
    6 
    7 This module is under development and should be considered experimental.
    8 
    9 This module produces cmake (2.8.8+) input as its output. One CMakeLists.txt is
   10 created for each configuration.
   11 
   12 This module's original purpose was to support editing in IDEs like KDevelop
   13 which use CMake for project management. It is also possible to use CMake to
   14 generate projects for other IDEs such as eclipse cdt and code::blocks. QtCreator
   15 will convert the CMakeLists.txt to a code::blocks cbp for the editor to read,
   16 but build using CMake. As a result QtCreator editor is unaware of compiler
   17 defines. The generated CMakeLists.txt can also be used to build on Linux. There
   18 is currently no support for building on platforms other than Linux.
   19 
   20 The generated CMakeLists.txt should properly compile all projects. However,
   21 there is a mismatch between gyp and cmake with regard to linking. All attempts
   22 are made to work around this, but CMake sometimes sees -Wl,--start-group as a
   23 library and incorrectly repeats it. As a result the output of this generator
   24 should not be relied on for building.
   25 
   26 When using with kdevelop, use version 4.4+. Previous versions of kdevelop will
   27 not be able to find the header file directories described in the generated
   28 CMakeLists.txt file.
   29 """
   30 
   31 import multiprocessing
   32 import os
   33 import signal
   34 import string
   35 import subprocess
   36 import gyp.common
   37 
   38 generator_default_variables = {
   39   'EXECUTABLE_PREFIX': '',
   40   'EXECUTABLE_SUFFIX': '',
   41   'STATIC_LIB_PREFIX': 'lib',
   42   'STATIC_LIB_SUFFIX': '.a',
   43   'SHARED_LIB_PREFIX': 'lib',
   44   'SHARED_LIB_SUFFIX': '.so',
   45   'SHARED_LIB_DIR': '${builddir}/lib.${TOOLSET}',
   46   'LIB_DIR': '${obj}.${TOOLSET}',
   47   'INTERMEDIATE_DIR': '${obj}.${TOOLSET}/${TARGET}/geni',
   48   'SHARED_INTERMEDIATE_DIR': '${obj}/gen',
   49   'PRODUCT_DIR': '${builddir}',
   50   'RULE_INPUT_PATH': '${RULE_INPUT_PATH}',
   51   'RULE_INPUT_DIRNAME': '${RULE_INPUT_DIRNAME}',
   52   'RULE_INPUT_NAME': '${RULE_INPUT_NAME}',
   53   'RULE_INPUT_ROOT': '${RULE_INPUT_ROOT}',
   54   'RULE_INPUT_EXT': '${RULE_INPUT_EXT}',
   55   'CONFIGURATION_NAME': '${configuration}',
   56 }
   57 
   58 FULL_PATH_VARS = ('${CMAKE_CURRENT_LIST_DIR}', '${builddir}', '${obj}')
   59 
   60 generator_supports_multiple_toolsets = True
   61 generator_wants_static_library_dependencies_adjusted = True
   62 
   63 COMPILABLE_EXTENSIONS = {
   64   '.c': 'cc',
   65   '.cc': 'cxx',
   66   '.cpp': 'cxx',
   67   '.cxx': 'cxx',
   68   '.s': 's', # cc
   69   '.S': 's', # cc
   70 }
   71 
   72 
   73 def RemovePrefix(a, prefix):
   74   """Returns 'a' without 'prefix' if it starts with 'prefix'."""
   75   return a[len(prefix):] if a.startswith(prefix) else a
   76 
   77 
   78 def CalculateVariables(default_variables, params):
   79   """Calculate additional variables for use in the build (called by gyp)."""
   80   default_variables.setdefault('OS', gyp.common.GetFlavor(params))
   81 
   82 
   83 def Compilable(filename):
   84   """Return true if the file is compilable (should be in OBJS)."""
   85   return any(filename.endswith(e) for e in COMPILABLE_EXTENSIONS)
   86 
   87 
   88 def Linkable(filename):
   89   """Return true if the file is linkable (should be on the link line)."""
   90   return filename.endswith('.o')
   91 
   92 
   93 def NormjoinPathForceCMakeSource(base_path, rel_path):
   94   """Resolves rel_path against base_path and returns the result.
   95 
   96   If rel_path is an absolute path it is returned unchanged.
   97   Otherwise it is resolved against base_path and normalized.
   98   If the result is a relative path, it is forced to be relative to the
   99   CMakeLists.txt.
  100   """
  101   if os.path.isabs(rel_path):
  102     return rel_path
  103   if any([rel_path.startswith(var) for var in FULL_PATH_VARS]):
  104     return rel_path
  105   # TODO: do we need to check base_path for absolute variables as well?
  106   return os.path.join('${CMAKE_CURRENT_LIST_DIR}',
  107                       os.path.normpath(os.path.join(base_path, rel_path)))
  108 
  109 
  110 def NormjoinPath(base_path, rel_path):
  111   """Resolves rel_path against base_path and returns the result.
  112   TODO: what is this really used for?
  113   If rel_path begins with '$' it is returned unchanged.
  114   Otherwise it is resolved against base_path if relative, then normalized.
  115   """
  116   if rel_path.startswith('$') and not rel_path.startswith('${configuration}'):
  117     return rel_path
  118   return os.path.normpath(os.path.join(base_path, rel_path))
  119 
  120 
  121 def CMakeStringEscape(a):
  122   """Escapes the string 'a' for use inside a CMake string.
  123 
  124   This means escaping
  125   '\' otherwise it may be seen as modifying the next character
  126   '"' otherwise it will end the string
  127   ';' otherwise the string becomes a list
  128 
  129   The following do not need to be escaped
  130   '#' when the lexer is in string state, this does not start a comment
  131 
  132   The following are yet unknown
  133   '$' generator variables (like ${obj}) must not be escaped,
  134       but text $ should be escaped
  135       what is wanted is to know which $ come from generator variables
  136   """
  137   return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"')
  138 
  139 
  140 def SetFileProperty(output, source_name, property_name, values, sep):
  141   """Given a set of source file, sets the given property on them."""
  142   output.write('set_source_files_properties(')
  143   output.write(source_name)
  144   output.write(' PROPERTIES ')
  145   output.write(property_name)
  146   output.write(' "')
  147   for value in values:
  148     output.write(CMakeStringEscape(value))
  149     output.write(sep)
  150   output.write('")\n')
  151 
  152 
  153 def SetFilesProperty(output, variable, property_name, values, sep):
  154   """Given a set of source files, sets the given property on them."""
  155   output.write('set_source_files_properties(')
  156   WriteVariable(output, variable)
  157   output.write(' PROPERTIES ')
  158   output.write(property_name)
  159   output.write(' "')
  160   for value in values:
  161     output.write(CMakeStringEscape(value))
  162     output.write(sep)
  163   output.write('")\n')
  164 
  165 
  166 def SetTargetProperty(output, target_name, property_name, values, sep=''):
  167   """Given a target, sets the given property."""
  168   output.write('set_target_properties(')
  169   output.write(target_name)
  170   output.write(' PROPERTIES ')
  171   output.write(property_name)
  172   output.write(' "')
  173   for value in values:
  174     output.write(CMakeStringEscape(value))
  175     output.write(sep)
  176   output.write('")\n')
  177 
  178 
  179 def SetVariable(output, variable_name, value):
  180   """Sets a CMake variable."""
  181   output.write('set(')
  182   output.write(variable_name)
  183   output.write(' "')
  184   output.write(CMakeStringEscape(value))
  185   output.write('")\n')
  186 
  187 
  188 def SetVariableList(output, variable_name, values):
  189   """Sets a CMake variable to a list."""
  190   if not values:
  191     return SetVariable(output, variable_name, "")
  192   if len(values) == 1:
  193     return SetVariable(output, variable_name, values[0])
  194   output.write('list(APPEND ')
  195   output.write(variable_name)
  196   output.write('\n  "')
  197   output.write('"\n  "'.join([CMakeStringEscape(value) for value in values]))
  198   output.write('")\n')
  199 
  200 
  201 def UnsetVariable(output, variable_name):
  202   """Unsets a CMake variable."""
  203   output.write('unset(')
  204   output.write(variable_name)
  205   output.write(')\n')
  206 
  207 
  208 def WriteVariable(output, variable_name, prepend=None):
  209   if prepend:
  210     output.write(prepend)
  211   output.write('${')
  212   output.write(variable_name)
  213   output.write('}')
  214 
  215 
  216 class CMakeTargetType(object):
  217   def __init__(self, command, modifier, property_modifier):
  218     self.command = command
  219     self.modifier = modifier
  220     self.property_modifier = property_modifier
  221 
  222 
  223 cmake_target_type_from_gyp_target_type = {
  224   'executable': CMakeTargetType('add_executable', None, 'RUNTIME'),
  225   'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE'),
  226   'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY'),
  227   'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY'),
  228   'none': CMakeTargetType('add_custom_target', 'SOURCES', None),
  229 }
  230 
  231 
  232 def StringToCMakeTargetName(a):
  233   """Converts the given string 'a' to a valid CMake target name.
  234 
  235   All invalid characters are replaced by '_'.
  236   Invalid for cmake: ' ', '/', '(', ')', '"'
  237   Invalid for make: ':'
  238   Invalid for unknown reasons but cause failures: '.'
  239   """
  240   return a.translate(string.maketrans(' /():."', '_______'))
  241 
  242 
  243 def WriteActions(target_name, actions, extra_sources, extra_deps,
  244                  path_to_gyp, output):
  245   """Write CMake for the 'actions' in the target.
  246 
  247   Args:
  248     target_name: the name of the CMake target being generated.
  249     actions: the Gyp 'actions' dict for this target.
  250     extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
  251     extra_deps: [<cmake_taget>] to append with generated targets.
  252     path_to_gyp: relative path from CMakeLists.txt being generated to
  253         the Gyp file in which the target being generated is defined.
  254   """
  255   for action in actions:
  256     action_name = StringToCMakeTargetName(action['action_name'])
  257     action_target_name = '%s__%s' % (target_name, action_name)
  258 
  259     inputs = action['inputs']
  260     inputs_name = action_target_name + '__input'
  261     SetVariableList(output, inputs_name,
  262         [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
  263 
  264     outputs = action['outputs']
  265     cmake_outputs = [NormjoinPathForceCMakeSource(path_to_gyp, out)
  266                      for out in outputs]
  267     outputs_name = action_target_name + '__output'
  268     SetVariableList(output, outputs_name, cmake_outputs)
  269 
  270     # Build up a list of outputs.
  271     # Collect the output dirs we'll need.
  272     dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
  273 
  274     if int(action.get('process_outputs_as_sources', False)):
  275       extra_sources.extend(zip(cmake_outputs, outputs))
  276 
  277     # add_custom_command
  278     output.write('add_custom_command(OUTPUT ')
  279     WriteVariable(output, outputs_name)
  280     output.write('\n')
  281 
  282     if len(dirs) > 0:
  283       for directory in dirs:
  284         output.write('  COMMAND ${CMAKE_COMMAND} -E make_directory ')
  285         output.write(directory)
  286         output.write('\n')
  287 
  288     output.write('  COMMAND ')
  289     output.write(gyp.common.EncodePOSIXShellList(action['action']))
  290     output.write('\n')
  291 
  292     output.write('  DEPENDS ')
  293     WriteVariable(output, inputs_name)
  294     output.write('\n')
  295 
  296     output.write('  WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
  297     output.write(path_to_gyp)
  298     output.write('\n')
  299 
  300     output.write('  COMMENT ')
  301     if 'message' in action:
  302       output.write(action['message'])
  303     else:
  304       output.write(action_target_name)
  305     output.write('\n')
  306 
  307     output.write('  VERBATIM\n')
  308     output.write(')\n')
  309 
  310     # add_custom_target
  311     output.write('add_custom_target(')
  312     output.write(action_target_name)
  313     output.write('\n  DEPENDS ')
  314     WriteVariable(output, outputs_name)
  315     output.write('\n  SOURCES ')
  316     WriteVariable(output, inputs_name)
  317     output.write('\n)\n')
  318 
  319     extra_deps.append(action_target_name)
  320 
  321 
  322 def NormjoinRulePathForceCMakeSource(base_path, rel_path, rule_source):
  323   if rel_path.startswith(("${RULE_INPUT_PATH}","${RULE_INPUT_DIRNAME}")):
  324     if any([rule_source.startswith(var) for var in FULL_PATH_VARS]):
  325       return rel_path
  326   return NormjoinPathForceCMakeSource(base_path, rel_path)
  327 
  328 
  329 def WriteRules(target_name, rules, extra_sources, extra_deps,
  330                path_to_gyp, output):
  331   """Write CMake for the 'rules' in the target.
  332 
  333   Args:
  334     target_name: the name of the CMake target being generated.
  335     actions: the Gyp 'actions' dict for this target.
  336     extra_sources: [(<cmake_src>, <src>)] to append with generated source files.
  337     extra_deps: [<cmake_taget>] to append with generated targets.
  338     path_to_gyp: relative path from CMakeLists.txt being generated to
  339         the Gyp file in which the target being generated is defined.
  340   """
  341   for rule in rules:
  342     rule_name = StringToCMakeTargetName(target_name + '__' + rule['rule_name'])
  343 
  344     inputs = rule.get('inputs', [])
  345     inputs_name = rule_name + '__input'
  346     SetVariableList(output, inputs_name,
  347         [NormjoinPathForceCMakeSource(path_to_gyp, dep) for dep in inputs])
  348     outputs = rule['outputs']
  349     var_outputs = []
  350 
  351     for count, rule_source in enumerate(rule.get('rule_sources', [])):
  352       action_name = rule_name + '_' + str(count)
  353 
  354       rule_source_dirname, rule_source_basename = os.path.split(rule_source)
  355       rule_source_root, rule_source_ext = os.path.splitext(rule_source_basename)
  356 
  357       SetVariable(output, 'RULE_INPUT_PATH', rule_source)
  358       SetVariable(output, 'RULE_INPUT_DIRNAME', rule_source_dirname)
  359       SetVariable(output, 'RULE_INPUT_NAME', rule_source_basename)
  360       SetVariable(output, 'RULE_INPUT_ROOT', rule_source_root)
  361       SetVariable(output, 'RULE_INPUT_EXT', rule_source_ext)
  362 
  363       # Build up a list of outputs.
  364       # Collect the output dirs we'll need.
  365       dirs = set(dir for dir in (os.path.dirname(o) for o in outputs) if dir)
  366 
  367       # Create variables for the output, as 'local' variable will be unset.
  368       these_outputs = []
  369       for output_index, out in enumerate(outputs):
  370         output_name = action_name + '_' + str(output_index)
  371         SetVariable(output, output_name,
  372                      NormjoinRulePathForceCMakeSource(path_to_gyp, out,
  373                                                       rule_source))
  374         if int(rule.get('process_outputs_as_sources', False)):
  375           extra_sources.append(('${' + output_name + '}', out))
  376         these_outputs.append('${' + output_name + '}')
  377         var_outputs.append('${' + output_name + '}')
  378 
  379       # add_custom_command
  380       output.write('add_custom_command(OUTPUT\n')
  381       for out in these_outputs:
  382         output.write('  ')
  383         output.write(out)
  384         output.write('\n')
  385 
  386       for directory in dirs:
  387         output.write('  COMMAND ${CMAKE_COMMAND} -E make_directory ')
  388         output.write(directory)
  389         output.write('\n')
  390 
  391       output.write('  COMMAND ')
  392       output.write(gyp.common.EncodePOSIXShellList(rule['action']))
  393       output.write('\n')
  394 
  395       output.write('  DEPENDS ')
  396       WriteVariable(output, inputs_name)
  397       output.write(' ')
  398       output.write(NormjoinPath(path_to_gyp, rule_source))
  399       output.write('\n')
  400 
  401       # CMAKE_CURRENT_LIST_DIR is where the CMakeLists.txt lives.
  402       # The cwd is the current build directory.
  403       output.write('  WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
  404       output.write(path_to_gyp)
  405       output.write('\n')
  406 
  407       output.write('  COMMENT ')
  408       if 'message' in rule:
  409         output.write(rule['message'])
  410       else:
  411         output.write(action_name)
  412       output.write('\n')
  413 
  414       output.write('  VERBATIM\n')
  415       output.write(')\n')
  416 
  417       UnsetVariable(output, 'RULE_INPUT_PATH')
  418       UnsetVariable(output, 'RULE_INPUT_DIRNAME')
  419       UnsetVariable(output, 'RULE_INPUT_NAME')
  420       UnsetVariable(output, 'RULE_INPUT_ROOT')
  421       UnsetVariable(output, 'RULE_INPUT_EXT')
  422 
  423     # add_custom_target
  424     output.write('add_custom_target(')
  425     output.write(rule_name)
  426     output.write(' DEPENDS\n')
  427     for out in var_outputs:
  428       output.write('  ')
  429       output.write(out)
  430       output.write('\n')
  431     output.write('SOURCES ')
  432     WriteVariable(output, inputs_name)
  433     output.write('\n')
  434     for rule_source in rule.get('rule_sources', []):
  435       output.write('  ')
  436       output.write(NormjoinPath(path_to_gyp, rule_source))
  437       output.write('\n')
  438     output.write(')\n')
  439 
  440     extra_deps.append(rule_name)
  441 
  442 
  443 def WriteCopies(target_name, copies, extra_deps, path_to_gyp, output):
  444   """Write CMake for the 'copies' in the target.
  445 
  446   Args:
  447     target_name: the name of the CMake target being generated.
  448     actions: the Gyp 'actions' dict for this target.
  449     extra_deps: [<cmake_taget>] to append with generated targets.
  450     path_to_gyp: relative path from CMakeLists.txt being generated to
  451         the Gyp file in which the target being generated is defined.
  452   """
  453   copy_name = target_name + '__copies'
  454 
  455   # CMake gets upset with custom targets with OUTPUT which specify no output.
  456   have_copies = any(copy['files'] for copy in copies)
  457   if not have_copies:
  458     output.write('add_custom_target(')
  459     output.write(copy_name)
  460     output.write(')\n')
  461     extra_deps.append(copy_name)
  462     return
  463 
  464   class Copy(object):
  465     def __init__(self, ext, command):
  466       self.cmake_inputs = []
  467       self.cmake_outputs = []
  468       self.gyp_inputs = []
  469       self.gyp_outputs = []
  470       self.ext = ext
  471       self.inputs_name = None
  472       self.outputs_name = None
  473       self.command = command
  474 
  475   file_copy = Copy('', 'copy')
  476   dir_copy = Copy('_dirs', 'copy_directory')
  477 
  478   for copy in copies:
  479     files = copy['files']
  480     destination = copy['destination']
  481     for src in files:
  482       path = os.path.normpath(src)
  483       basename = os.path.split(path)[1]
  484       dst = os.path.join(destination, basename)
  485 
  486       copy = file_copy if os.path.basename(src) else dir_copy
  487 
  488       copy.cmake_inputs.append(NormjoinPathForceCMakeSource(path_to_gyp, src))
  489       copy.cmake_outputs.append(NormjoinPathForceCMakeSource(path_to_gyp, dst))
  490       copy.gyp_inputs.append(src)
  491       copy.gyp_outputs.append(dst)
  492 
  493   for copy in (file_copy, dir_copy):
  494     if copy.cmake_inputs:
  495       copy.inputs_name = copy_name + '__input' + copy.ext
  496       SetVariableList(output, copy.inputs_name, copy.cmake_inputs)
  497 
  498       copy.outputs_name = copy_name + '__output' + copy.ext
  499       SetVariableList(output, copy.outputs_name, copy.cmake_outputs)
  500 
  501   # add_custom_command
  502   output.write('add_custom_command(\n')
  503 
  504   output.write('OUTPUT')
  505   for copy in (file_copy, dir_copy):
  506     if copy.outputs_name:
  507       WriteVariable(output, copy.outputs_name, ' ')
  508   output.write('\n')
  509 
  510   for copy in (file_copy, dir_copy):
  511     for src, dst in zip(copy.gyp_inputs, copy.gyp_outputs):
  512       # 'cmake -E copy src dst' will create the 'dst' directory if needed.
  513       output.write('COMMAND ${CMAKE_COMMAND} -E %s ' % copy.command)
  514       output.write(src)
  515       output.write(' ')
  516       output.write(dst)
  517       output.write("\n")
  518 
  519   output.write('DEPENDS')
  520   for copy in (file_copy, dir_copy):
  521     if copy.inputs_name:
  522       WriteVariable(output, copy.inputs_name, ' ')
  523   output.write('\n')
  524 
  525   output.write('WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/')
  526   output.write(path_to_gyp)
  527   output.write('\n')
  528 
  529   output.write('COMMENT Copying for ')
  530   output.write(target_name)
  531   output.write('\n')
  532 
  533   output.write('VERBATIM\n')
  534   output.write(')\n')
  535 
  536   # add_custom_target
  537   output.write('add_custom_target(')
  538   output.write(copy_name)
  539   output.write('\n  DEPENDS')
  540   for copy in (file_copy, dir_copy):
  541     if copy.outputs_name:
  542       WriteVariable(output, copy.outputs_name, ' ')
  543   output.write('\n  SOURCES')
  544   if file_copy.inputs_name:
  545     WriteVariable(output, file_copy.inputs_name, ' ')
  546   output.write('\n)\n')
  547 
  548   extra_deps.append(copy_name)
  549 
  550 
  551 def CreateCMakeTargetBaseName(qualified_target):
  552   """This is the name we would like the target to have."""
  553   _, gyp_target_name, gyp_target_toolset = (
  554       gyp.common.ParseQualifiedTarget(qualified_target))
  555   cmake_target_base_name = gyp_target_name
  556   if gyp_target_toolset and gyp_target_toolset != 'target':
  557     cmake_target_base_name += '_' + gyp_target_toolset
  558   return StringToCMakeTargetName(cmake_target_base_name)
  559 
  560 
  561 def CreateCMakeTargetFullName(qualified_target):
  562   """An unambiguous name for the target."""
  563   gyp_file, gyp_target_name, gyp_target_toolset = (
  564       gyp.common.ParseQualifiedTarget(qualified_target))
  565   cmake_target_full_name = gyp_file + ':' + gyp_target_name
  566   if gyp_target_toolset and gyp_target_toolset != 'target':
  567     cmake_target_full_name += '_' + gyp_target_toolset
  568   return StringToCMakeTargetName(cmake_target_full_name)
  569 
  570 
  571 class CMakeNamer(object):
  572   """Converts Gyp target names into CMake target names.
  573 
  574   CMake requires that target names be globally unique. One way to ensure
  575   this is to fully qualify the names of the targets. Unfortunatly, this
  576   ends up with all targets looking like "chrome_chrome_gyp_chrome" instead
  577   of just "chrome". If this generator were only interested in building, it
  578   would be possible to fully qualify all target names, then create
  579   unqualified target names which depend on all qualified targets which
  580   should have had that name. This is more or less what the 'make' generator
  581   does with aliases. However, one goal of this generator is to create CMake
  582   files for use with IDEs, and fully qualified names are not as user
  583   friendly.
  584 
  585   Since target name collision is rare, we do the above only when required.
  586 
  587   Toolset variants are always qualified from the base, as this is required for
  588   building. However, it also makes sense for an IDE, as it is possible for
  589   defines to be different.
  590   """
  591   def __init__(self, target_list):
  592     self.cmake_target_base_names_conficting = set()
  593 
  594     cmake_target_base_names_seen = set()
  595     for qualified_target in target_list:
  596       cmake_target_base_name = CreateCMakeTargetBaseName(qualified_target)
  597 
  598       if cmake_target_base_name not in cmake_target_base_names_seen:
  599         cmake_target_base_names_seen.add(cmake_target_base_name)
  600       else:
  601         self.cmake_target_base_names_conficting.add(cmake_target_base_name)
  602 
  603   def CreateCMakeTargetName(self, qualified_target):
  604     base_name = CreateCMakeTargetBaseName(qualified_target)
  605     if base_name in self.cmake_target_base_names_conficting:
  606       return CreateCMakeTargetFullName(qualified_target)
  607     return base_name
  608 
  609 
  610 def WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
  611                 options, generator_flags, all_qualified_targets, output):
  612 
  613   # The make generator does this always.
  614   # TODO: It would be nice to be able to tell CMake all dependencies.
  615   circular_libs = generator_flags.get('circular', True)
  616 
  617   if not generator_flags.get('standalone', False):
  618     output.write('\n#')
  619     output.write(qualified_target)
  620     output.write('\n')
  621 
  622   gyp_file, _, _ = gyp.common.ParseQualifiedTarget(qualified_target)
  623   rel_gyp_file = gyp.common.RelativePath(gyp_file, options.toplevel_dir)
  624   rel_gyp_dir = os.path.dirname(rel_gyp_file)
  625 
  626   # Relative path from build dir to top dir.
  627   build_to_top = gyp.common.InvertRelativePath(build_dir, options.toplevel_dir)
  628   # Relative path from build dir to gyp dir.
  629   build_to_gyp = os.path.join(build_to_top, rel_gyp_dir)
  630 
  631   path_from_cmakelists_to_gyp = build_to_gyp
  632 
  633   spec = target_dicts.get(qualified_target, {})
  634   config = spec.get('configurations', {}).get(config_to_use, {})
  635 
  636   target_name = spec.get('target_name', '<missing target name>')
  637   target_type = spec.get('type', '<missing target type>')
  638   target_toolset = spec.get('toolset')
  639 
  640   cmake_target_type = cmake_target_type_from_gyp_target_type.get(target_type)
  641   if cmake_target_type is None:
  642     print ('Target %s has unknown target type %s, skipping.' %
  643           (        target_name,               target_type  ) )
  644     return
  645 
  646   SetVariable(output, 'TARGET', target_name)
  647   SetVariable(output, 'TOOLSET', target_toolset)
  648 
  649   cmake_target_name = namer.CreateCMakeTargetName(qualified_target)
  650 
  651   extra_sources = []
  652   extra_deps = []
  653 
  654   # Actions must come first, since they can generate more OBJs for use below.
  655   if 'actions' in spec:
  656     WriteActions(cmake_target_name, spec['actions'], extra_sources, extra_deps,
  657                  path_from_cmakelists_to_gyp, output)
  658 
  659   # Rules must be early like actions.
  660   if 'rules' in spec:
  661     WriteRules(cmake_target_name, spec['rules'], extra_sources, extra_deps,
  662                path_from_cmakelists_to_gyp, output)
  663 
  664   # Copies
  665   if 'copies' in spec:
  666     WriteCopies(cmake_target_name, spec['copies'], extra_deps,
  667                 path_from_cmakelists_to_gyp, output)
  668 
  669   # Target and sources
  670   srcs = spec.get('sources', [])
  671 
  672   # Gyp separates the sheep from the goats based on file extensions.
  673   # A full separation is done here because of flag handing (see below).
  674   s_sources = []
  675   c_sources = []
  676   cxx_sources = []
  677   linkable_sources = []
  678   other_sources = []
  679   for src in srcs:
  680     _, ext = os.path.splitext(src)
  681     src_type = COMPILABLE_EXTENSIONS.get(ext, None)
  682     src_norm_path = NormjoinPath(path_from_cmakelists_to_gyp, src);
  683 
  684     if src_type == 's':
  685       s_sources.append(src_norm_path)
  686     elif src_type == 'cc':
  687       c_sources.append(src_norm_path)
  688     elif src_type == 'cxx':
  689       cxx_sources.append(src_norm_path)
  690     elif Linkable(ext):
  691       linkable_sources.append(src_norm_path)
  692     else:
  693       other_sources.append(src_norm_path)
  694 
  695   for extra_source in extra_sources:
  696     src, real_source = extra_source
  697     _, ext = os.path.splitext(real_source)
  698     src_type = COMPILABLE_EXTENSIONS.get(ext, None)
  699 
  700     if src_type == 's':
  701       s_sources.append(src)
  702     elif src_type == 'cc':
  703       c_sources.append(src)
  704     elif src_type == 'cxx':
  705       cxx_sources.append(src)
  706     elif Linkable(ext):
  707       linkable_sources.append(src)
  708     else:
  709       other_sources.append(src)
  710 
  711   s_sources_name = None
  712   if s_sources:
  713     s_sources_name = cmake_target_name + '__asm_srcs'
  714     SetVariableList(output, s_sources_name, s_sources)
  715 
  716   c_sources_name = None
  717   if c_sources:
  718     c_sources_name = cmake_target_name + '__c_srcs'
  719     SetVariableList(output, c_sources_name, c_sources)
  720 
  721   cxx_sources_name = None
  722   if cxx_sources:
  723     cxx_sources_name = cmake_target_name + '__cxx_srcs'
  724     SetVariableList(output, cxx_sources_name, cxx_sources)
  725 
  726   linkable_sources_name = None
  727   if linkable_sources:
  728     linkable_sources_name = cmake_target_name + '__linkable_srcs'
  729     SetVariableList(output, linkable_sources_name, linkable_sources)
  730 
  731   other_sources_name = None
  732   if other_sources:
  733     other_sources_name = cmake_target_name + '__other_srcs'
  734     SetVariableList(output, other_sources_name, other_sources)
  735 
  736   # CMake gets upset when executable targets provide no sources.
  737   # http://www.cmake.org/pipermail/cmake/2010-July/038461.html
  738   dummy_sources_name = None
  739   has_sources = (s_sources_name or
  740                  c_sources_name or
  741                  cxx_sources_name or
  742                  linkable_sources_name or
  743                  other_sources_name)
  744   if target_type == 'executable' and not has_sources:
  745     dummy_sources_name = cmake_target_name + '__dummy_srcs'
  746     SetVariable(output, dummy_sources_name,
  747                 "${obj}.${TOOLSET}/${TARGET}/genc/dummy.c")
  748     output.write('if(NOT EXISTS "')
  749     WriteVariable(output, dummy_sources_name)
  750     output.write('")\n')
  751     output.write('  file(WRITE "')
  752     WriteVariable(output, dummy_sources_name)
  753     output.write('" "")\n')
  754     output.write("endif()\n")
  755 
  756 
  757   # CMake is opposed to setting linker directories and considers the practice
  758   # of setting linker directories dangerous. Instead, it favors the use of
  759   # find_library and passing absolute paths to target_link_libraries.
  760   # However, CMake does provide the command link_directories, which adds
  761   # link directories to targets defined after it is called.
  762   # As a result, link_directories must come before the target definition.
  763   # CMake unfortunately has no means of removing entries from LINK_DIRECTORIES.
  764   library_dirs = config.get('library_dirs')
  765   if library_dirs is not None:
  766     output.write('link_directories(')
  767     for library_dir in library_dirs:
  768       output.write(' ')
  769       output.write(NormjoinPath(path_from_cmakelists_to_gyp, library_dir))
  770       output.write('\n')
  771     output.write(')\n')
  772 
  773   output.write(cmake_target_type.command)
  774   output.write('(')
  775   output.write(cmake_target_name)
  776 
  777   if cmake_target_type.modifier is not None:
  778     output.write(' ')
  779     output.write(cmake_target_type.modifier)
  780 
  781   if s_sources_name:
  782     WriteVariable(output, s_sources_name, ' ')
  783   if c_sources_name:
  784     WriteVariable(output, c_sources_name, ' ')
  785   if cxx_sources_name:
  786     WriteVariable(output, cxx_sources_name, ' ')
  787   if linkable_sources_name:
  788     WriteVariable(output, linkable_sources_name, ' ')
  789   if other_sources_name:
  790     WriteVariable(output, other_sources_name, ' ')
  791   if dummy_sources_name:
  792     WriteVariable(output, dummy_sources_name, ' ')
  793 
  794   output.write(')\n')
  795 
  796   # Let CMake know if the 'all' target should depend on this target.
  797   exclude_from_all = ('TRUE' if qualified_target not in all_qualified_targets
  798                              else 'FALSE')
  799   SetTargetProperty(output, cmake_target_name,
  800                       'EXCLUDE_FROM_ALL', exclude_from_all)
  801   for extra_target_name in extra_deps:
  802     SetTargetProperty(output, extra_target_name,
  803                         'EXCLUDE_FROM_ALL', exclude_from_all)
  804 
  805   # Output name and location.
  806   if target_type != 'none':
  807     # Link as 'C' if there are no other files
  808     if not c_sources and not cxx_sources:
  809       SetTargetProperty(output, cmake_target_name, 'LINKER_LANGUAGE', ['C'])
  810 
  811     # Mark uncompiled sources as uncompiled.
  812     if other_sources_name:
  813       output.write('set_source_files_properties(')
  814       WriteVariable(output, other_sources_name, '')
  815       output.write(' PROPERTIES HEADER_FILE_ONLY "TRUE")\n')
  816 
  817     # Mark object sources as linkable.
  818     if linkable_sources_name:
  819       output.write('set_source_files_properties(')
  820       WriteVariable(output, other_sources_name, '')
  821       output.write(' PROPERTIES EXTERNAL_OBJECT "TRUE")\n')
  822 
  823     # Output directory
  824     target_output_directory = spec.get('product_dir')
  825     if target_output_directory is None:
  826       if target_type in ('executable', 'loadable_module'):
  827         target_output_directory = generator_default_variables['PRODUCT_DIR']
  828       elif target_type == 'shared_library':
  829         target_output_directory = '${builddir}/lib.${TOOLSET}'
  830       elif spec.get('standalone_static_library', False):
  831         target_output_directory = generator_default_variables['PRODUCT_DIR']
  832       else:
  833         base_path = gyp.common.RelativePath(os.path.dirname(gyp_file),
  834                                             options.toplevel_dir)
  835         target_output_directory = '${obj}.${TOOLSET}'
  836         target_output_directory = (
  837             os.path.join(target_output_directory, base_path))
  838 
  839     cmake_target_output_directory = NormjoinPathForceCMakeSource(
  840                                         path_from_cmakelists_to_gyp,
  841                                         target_output_directory)
  842     SetTargetProperty(output,
  843         cmake_target_name,
  844         cmake_target_type.property_modifier + '_OUTPUT_DIRECTORY',
  845         cmake_target_output_directory)
  846 
  847     # Output name
  848     default_product_prefix = ''
  849     default_product_name = target_name
  850     default_product_ext = ''
  851     if target_type == 'static_library':
  852       static_library_prefix = generator_default_variables['STATIC_LIB_PREFIX']
  853       default_product_name = RemovePrefix(default_product_name,
  854                                           static_library_prefix)
  855       default_product_prefix = static_library_prefix
  856       default_product_ext = generator_default_variables['STATIC_LIB_SUFFIX']
  857 
  858     elif target_type in ('loadable_module', 'shared_library'):
  859       shared_library_prefix = generator_default_variables['SHARED_LIB_PREFIX']
  860       default_product_name = RemovePrefix(default_product_name,
  861                                           shared_library_prefix)
  862       default_product_prefix = shared_library_prefix
  863       default_product_ext = generator_default_variables['SHARED_LIB_SUFFIX']
  864 
  865     elif target_type != 'executable':
  866       print ('ERROR: What output file should be generated?',
  867               'type', target_type, 'target', target_name)
  868 
  869     product_prefix = spec.get('product_prefix', default_product_prefix)
  870     product_name = spec.get('product_name', default_product_name)
  871     product_ext = spec.get('product_extension')
  872     if product_ext:
  873       product_ext = '.' + product_ext
  874     else:
  875       product_ext = default_product_ext
  876 
  877     SetTargetProperty(output, cmake_target_name, 'PREFIX', product_prefix)
  878     SetTargetProperty(output, cmake_target_name,
  879                         cmake_target_type.property_modifier + '_OUTPUT_NAME',
  880                         product_name)
  881     SetTargetProperty(output, cmake_target_name, 'SUFFIX', product_ext)
  882 
  883     # Make the output of this target referenceable as a source.
  884     cmake_target_output_basename = product_prefix + product_name + product_ext
  885     cmake_target_output = os.path.join(cmake_target_output_directory,
  886                                        cmake_target_output_basename)
  887     SetFileProperty(output, cmake_target_output, 'GENERATED', ['TRUE'], '')
  888 
  889     # Includes
  890     includes = config.get('include_dirs')
  891     if includes:
  892       # This (target include directories) is what requires CMake 2.8.8
  893       includes_name = cmake_target_name + '__include_dirs'
  894       SetVariableList(output, includes_name,
  895           [NormjoinPathForceCMakeSource(path_from_cmakelists_to_gyp, include)
  896            for include in includes])
  897       output.write('set_property(TARGET ')
  898       output.write(cmake_target_name)
  899       output.write(' APPEND PROPERTY INCLUDE_DIRECTORIES ')
  900       WriteVariable(output, includes_name, '')
  901       output.write(')\n')
  902 
  903     # Defines
  904     defines = config.get('defines')
  905     if defines is not None:
  906       SetTargetProperty(output,
  907                           cmake_target_name,
  908                           'COMPILE_DEFINITIONS',
  909                           defines,
  910                           ';')
  911 
  912     # Compile Flags - http://www.cmake.org/Bug/view.php?id=6493
  913     # CMake currently does not have target C and CXX flags.
  914     # So, instead of doing...
  915 
  916     # cflags_c = config.get('cflags_c')
  917     # if cflags_c is not None:
  918     #   SetTargetProperty(output, cmake_target_name,
  919     #                       'C_COMPILE_FLAGS', cflags_c, ' ')
  920 
  921     # cflags_cc = config.get('cflags_cc')
  922     # if cflags_cc is not None:
  923     #   SetTargetProperty(output, cmake_target_name,
  924     #                       'CXX_COMPILE_FLAGS', cflags_cc, ' ')
  925 
  926     # Instead we must...
  927     cflags = config.get('cflags', [])
  928     cflags_c = config.get('cflags_c', [])
  929     cflags_cxx = config.get('cflags_cc', [])
  930     if (not cflags_c or not c_sources) and (not cflags_cxx or not cxx_sources):
  931       SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', cflags, ' ')
  932 
  933     elif c_sources and not (s_sources or cxx_sources):
  934       flags = []
  935       flags.extend(cflags)
  936       flags.extend(cflags_c)
  937       SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
  938 
  939     elif cxx_sources and not (s_sources or c_sources):
  940       flags = []
  941       flags.extend(cflags)
  942       flags.extend(cflags_cxx)
  943       SetTargetProperty(output, cmake_target_name, 'COMPILE_FLAGS', flags, ' ')
  944 
  945     else:
  946       # TODO: This is broken, one cannot generally set properties on files,
  947       # as other targets may require different properties on the same files.
  948       if s_sources and cflags:
  949         SetFilesProperty(output, s_sources_name, 'COMPILE_FLAGS', cflags, ' ')
  950 
  951       if c_sources and (cflags or cflags_c):
  952         flags = []
  953         flags.extend(cflags)
  954         flags.extend(cflags_c)
  955         SetFilesProperty(output, c_sources_name, 'COMPILE_FLAGS', flags, ' ')
  956 
  957       if cxx_sources and (cflags or cflags_cxx):
  958         flags = []
  959         flags.extend(cflags)
  960         flags.extend(cflags_cxx)
  961         SetFilesProperty(output, cxx_sources_name, 'COMPILE_FLAGS', flags, ' ')
  962 
  963     # Linker flags
  964     ldflags = config.get('ldflags')
  965     if ldflags is not None:
  966       SetTargetProperty(output, cmake_target_name, 'LINK_FLAGS', ldflags, ' ')
  967 
  968   # Note on Dependencies and Libraries:
  969   # CMake wants to handle link order, resolving the link line up front.
  970   # Gyp does not retain or enforce specifying enough information to do so.
  971   # So do as other gyp generators and use --start-group and --end-group.
  972   # Give CMake as little information as possible so that it doesn't mess it up.
  973 
  974   # Dependencies
  975   rawDeps = spec.get('dependencies', [])
  976 
  977   static_deps = []
  978   shared_deps = []
  979   other_deps = []
  980   for rawDep in rawDeps:
  981     dep_cmake_name = namer.CreateCMakeTargetName(rawDep)
  982     dep_spec = target_dicts.get(rawDep, {})
  983     dep_target_type = dep_spec.get('type', None)
  984 
  985     if dep_target_type == 'static_library':
  986       static_deps.append(dep_cmake_name)
  987     elif dep_target_type ==  'shared_library':
  988       shared_deps.append(dep_cmake_name)
  989     else:
  990       other_deps.append(dep_cmake_name)
  991 
  992   # ensure all external dependencies are complete before internal dependencies
  993   # extra_deps currently only depend on their own deps, so otherwise run early
  994   if static_deps or shared_deps or other_deps:
  995     for extra_dep in extra_deps:
  996       output.write('add_dependencies(')
  997       output.write(extra_dep)
  998       output.write('\n')
  999       for deps in (static_deps, shared_deps, other_deps):
 1000         for dep in gyp.common.uniquer(deps):
 1001           output.write('  ')
 1002           output.write(dep)
 1003           output.write('\n')
 1004       output.write(')\n')
 1005 
 1006   linkable = target_type in ('executable', 'loadable_module', 'shared_library')
 1007   other_deps.extend(extra_deps)
 1008   if other_deps or (not linkable and (static_deps or shared_deps)):
 1009     output.write('add_dependencies(')
 1010     output.write(cmake_target_name)
 1011     output.write('\n')
 1012     for dep in gyp.common.uniquer(other_deps):
 1013       output.write('  ')
 1014       output.write(dep)
 1015       output.write('\n')
 1016     if not linkable:
 1017       for deps in (static_deps, shared_deps):
 1018         for lib_dep in gyp.common.uniquer(deps):
 1019           output.write('  ')
 1020           output.write(lib_dep)
 1021           output.write('\n')
 1022     output.write(')\n')
 1023 
 1024   # Libraries
 1025   if linkable:
 1026     external_libs = [lib for lib in spec.get('libraries', []) if len(lib) > 0]
 1027     if external_libs or static_deps or shared_deps:
 1028       output.write('target_link_libraries(')
 1029       output.write(cmake_target_name)
 1030       output.write('\n')
 1031       if static_deps:
 1032         write_group = circular_libs and len(static_deps) > 1
 1033         if write_group:
 1034           output.write('-Wl,--start-group\n')
 1035         for dep in gyp.common.uniquer(static_deps):
 1036           output.write('  ')
 1037           output.write(dep)
 1038           output.write('\n')
 1039         if write_group:
 1040           output.write('-Wl,--end-group\n')
 1041       if shared_deps:
 1042         for dep in gyp.common.uniquer(shared_deps):
 1043           output.write('  ')
 1044           output.write(dep)
 1045           output.write('\n')
 1046       if external_libs:
 1047         for lib in gyp.common.uniquer(external_libs):
 1048           output.write('  ')
 1049           output.write(lib)
 1050           output.write('\n')
 1051 
 1052       output.write(')\n')
 1053 
 1054   UnsetVariable(output, 'TOOLSET')
 1055   UnsetVariable(output, 'TARGET')
 1056 
 1057 
 1058 def GenerateOutputForConfig(target_list, target_dicts, data,
 1059                             params, config_to_use):
 1060   options = params['options']
 1061   generator_flags = params['generator_flags']
 1062 
 1063   # generator_dir: relative path from pwd to where make puts build files.
 1064   # Makes migrating from make to cmake easier, cmake doesn't put anything here.
 1065   # Each Gyp configuration creates a different CMakeLists.txt file
 1066   # to avoid incompatibilities between Gyp and CMake configurations.
 1067   generator_dir = os.path.relpath(options.generator_output or '.')
 1068 
 1069   # output_dir: relative path from generator_dir to the build directory.
 1070   output_dir = generator_flags.get('output_dir', 'out')
 1071 
 1072   # build_dir: relative path from source root to our output files.
 1073   # e.g. "out/Debug"
 1074   build_dir = os.path.normpath(os.path.join(generator_dir,
 1075                                             output_dir,
 1076                                             config_to_use))
 1077 
 1078   toplevel_build = os.path.join(options.toplevel_dir, build_dir)
 1079 
 1080   output_file = os.path.join(toplevel_build, 'CMakeLists.txt')
 1081   gyp.common.EnsureDirExists(output_file)
 1082 
 1083   output = open(output_file, 'w')
 1084   output.write('cmake_minimum_required(VERSION 2.8.8 FATAL_ERROR)\n')
 1085   output.write('cmake_policy(VERSION 2.8.8)\n')
 1086 
 1087   gyp_file, project_target, _ = gyp.common.ParseQualifiedTarget(target_list[-1])
 1088   output.write('project(')
 1089   output.write(project_target)
 1090   output.write(')\n')
 1091 
 1092   SetVariable(output, 'configuration', config_to_use)
 1093 
 1094   ar = None
 1095   cc = None
 1096   cxx = None
 1097 
 1098   make_global_settings = data[gyp_file].get('make_global_settings', [])
 1099   build_to_top = gyp.common.InvertRelativePath(build_dir,
 1100                                                options.toplevel_dir)
 1101   for key, value in make_global_settings:
 1102     if key == 'AR':
 1103       ar = os.path.join(build_to_top, value)
 1104     if key == 'CC':
 1105       cc = os.path.join(build_to_top, value)
 1106     if key == 'CXX':
 1107       cxx = os.path.join(build_to_top, value)
 1108 
 1109   ar = gyp.common.GetEnvironFallback(['AR_target', 'AR'], ar)
 1110   cc = gyp.common.GetEnvironFallback(['CC_target', 'CC'], cc)
 1111   cxx = gyp.common.GetEnvironFallback(['CXX_target', 'CXX'], cxx)
 1112 
 1113   if ar:
 1114     SetVariable(output, 'CMAKE_AR', ar)
 1115   if cc:
 1116     SetVariable(output, 'CMAKE_C_COMPILER', cc)
 1117   if cxx:
 1118     SetVariable(output, 'CMAKE_CXX_COMPILER', cxx)
 1119 
 1120   # The following appears to be as-yet undocumented.
 1121   # http://public.kitware.com/Bug/view.php?id=8392
 1122   output.write('enable_language(ASM)\n')
 1123   # ASM-ATT does not support .S files.
 1124   # output.write('enable_language(ASM-ATT)\n')
 1125 
 1126   if cc:
 1127     SetVariable(output, 'CMAKE_ASM_COMPILER', cc)
 1128 
 1129   SetVariable(output, 'builddir', '${CMAKE_CURRENT_BINARY_DIR}')
 1130   SetVariable(output, 'obj', '${builddir}/obj')
 1131   output.write('\n')
 1132 
 1133   # TODO: Undocumented/unsupported (the CMake Java generator depends on it).
 1134   # CMake by default names the object resulting from foo.c to be foo.c.o.
 1135   # Gyp traditionally names the object resulting from foo.c foo.o.
 1136   # This should be irrelevant, but some targets extract .o files from .a
 1137   # and depend on the name of the extracted .o files.
 1138   output.write('set(CMAKE_C_OUTPUT_EXTENSION_REPLACE 1)\n')
 1139   output.write('set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)\n')
 1140   output.write('\n')
 1141 
 1142   # Force ninja to use rsp files. Otherwise link and ar lines can get too long,
 1143   # resulting in 'Argument list too long' errors.
 1144   output.write('set(CMAKE_NINJA_FORCE_RESPONSE_FILE 1)\n')
 1145   output.write('\n')
 1146 
 1147   namer = CMakeNamer(target_list)
 1148 
 1149   # The list of targets upon which the 'all' target should depend.
 1150   # CMake has it's own implicit 'all' target, one is not created explicitly.
 1151   all_qualified_targets = set()
 1152   for build_file in params['build_files']:
 1153     for qualified_target in gyp.common.AllTargets(target_list,
 1154                                                   target_dicts,
 1155                                                   os.path.normpath(build_file)):
 1156       all_qualified_targets.add(qualified_target)
 1157 
 1158   for qualified_target in target_list:
 1159     WriteTarget(namer, qualified_target, target_dicts, build_dir, config_to_use,
 1160                 options, generator_flags, all_qualified_targets, output)
 1161 
 1162   output.close()
 1163 
 1164 
 1165 def PerformBuild(data, configurations, params):
 1166   options = params['options']
 1167   generator_flags = params['generator_flags']
 1168 
 1169   # generator_dir: relative path from pwd to where make puts build files.
 1170   # Makes migrating from make to cmake easier, cmake doesn't put anything here.
 1171   generator_dir = os.path.relpath(options.generator_output or '.')
 1172 
 1173   # output_dir: relative path from generator_dir to the build directory.
 1174   output_dir = generator_flags.get('output_dir', 'out')
 1175 
 1176   for config_name in configurations:
 1177     # build_dir: relative path from source root to our output files.
 1178     # e.g. "out/Debug"
 1179     build_dir = os.path.normpath(os.path.join(generator_dir,
 1180                                               output_dir,
 1181                                               config_name))
 1182     arguments = ['cmake', '-G', 'Ninja']
 1183     print 'Generating [%s]: %s' % (config_name, arguments)
 1184     subprocess.check_call(arguments, cwd=build_dir)
 1185 
 1186     arguments = ['ninja', '-C', build_dir]
 1187     print 'Building [%s]: %s' % (config_name, arguments)
 1188     subprocess.check_call(arguments)
 1189 
 1190 
 1191 def CallGenerateOutputForConfig(arglist):
 1192   # Ignore the interrupt signal so that the parent process catches it and
 1193   # kills all multiprocessing children.
 1194   signal.signal(signal.SIGINT, signal.SIG_IGN)
 1195 
 1196   target_list, target_dicts, data, params, config_name = arglist
 1197   GenerateOutputForConfig(target_list, target_dicts, data, params, config_name)
 1198 
 1199 
 1200 def GenerateOutput(target_list, target_dicts, data, params):
 1201   user_config = params.get('generator_flags', {}).get('config', None)
 1202   if user_config:
 1203     GenerateOutputForConfig(target_list, target_dicts, data,
 1204                             params, user_config)
 1205   else:
 1206     config_names = target_dicts[target_list[0]]['configurations'].keys()
 1207     if params['parallel']:
 1208       try:
 1209         pool = multiprocessing.Pool(len(config_names))
 1210         arglists = []
 1211         for config_name in config_names:
 1212           arglists.append((target_list, target_dicts, data,
 1213                            params, config_name))
 1214           pool.map(CallGenerateOutputForConfig, arglists)
 1215       except KeyboardInterrupt, e:
 1216         pool.terminate()
 1217         raise e
 1218     else:
 1219       for config_name in config_names:
 1220         GenerateOutputForConfig(target_list, target_dicts, data,
 1221                                 params, config_name)