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