1cb93a386Sopenharmony_ci#!/usr/bin/env python
2cb93a386Sopenharmony_ci#
3cb93a386Sopenharmony_ci# Copyright 2016 Google Inc.
4cb93a386Sopenharmony_ci#
5cb93a386Sopenharmony_ci# Use of this source code is governed by a BSD-style license that can be
6cb93a386Sopenharmony_ci# found in the LICENSE file.
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci
9cb93a386Sopenharmony_ci"""
10cb93a386Sopenharmony_ciUsage: gn_to_cmake.py <json_file_name>
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_cign gen out/config --ide=json --json-ide-script=../../gn/gn_to_cmake.py
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_cior
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_cign gen out/config --ide=json
17cb93a386Sopenharmony_cipython gn/gn_to_cmake.py out/config/project.json
18cb93a386Sopenharmony_ci
19cb93a386Sopenharmony_ciThe first is recommended, as it will auto-update.
20cb93a386Sopenharmony_ci"""
21cb93a386Sopenharmony_ci
22cb93a386Sopenharmony_ci
23cb93a386Sopenharmony_ciimport itertools
24cb93a386Sopenharmony_ciimport functools
25cb93a386Sopenharmony_ciimport json
26cb93a386Sopenharmony_ciimport posixpath
27cb93a386Sopenharmony_ciimport os
28cb93a386Sopenharmony_ciimport string
29cb93a386Sopenharmony_ciimport sys
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci
32cb93a386Sopenharmony_cidef CMakeStringEscape(a):
33cb93a386Sopenharmony_ci  """Escapes the string 'a' for use inside a CMake string.
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci  This means escaping
36cb93a386Sopenharmony_ci  '\' otherwise it may be seen as modifying the next character
37cb93a386Sopenharmony_ci  '"' otherwise it will end the string
38cb93a386Sopenharmony_ci  ';' otherwise the string becomes a list
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_ci  The following do not need to be escaped
41cb93a386Sopenharmony_ci  '#' when the lexer is in string state, this does not start a comment
42cb93a386Sopenharmony_ci  """
43cb93a386Sopenharmony_ci  return a.replace('\\', '\\\\').replace(';', '\\;').replace('"', '\\"')
44cb93a386Sopenharmony_ci
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_cidef CMakeTargetEscape(a):
47cb93a386Sopenharmony_ci  """Escapes the string 'a' for use as a CMake target name.
48cb93a386Sopenharmony_ci
49cb93a386Sopenharmony_ci  CMP0037 in CMake 3.0 restricts target names to "^[A-Za-z0-9_.:+-]+$"
50cb93a386Sopenharmony_ci  The ':' is only allowed for imported targets.
51cb93a386Sopenharmony_ci  """
52cb93a386Sopenharmony_ci  def Escape(c):
53cb93a386Sopenharmony_ci    if c in string.ascii_letters or c in string.digits or c in '_.+-':
54cb93a386Sopenharmony_ci      return c
55cb93a386Sopenharmony_ci    else:
56cb93a386Sopenharmony_ci      return '__'
57cb93a386Sopenharmony_ci  return ''.join(map(Escape, a))
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_cidef SetVariable(out, variable_name, value):
61cb93a386Sopenharmony_ci  """Sets a CMake variable."""
62cb93a386Sopenharmony_ci  out.write('set("')
63cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(variable_name))
64cb93a386Sopenharmony_ci  out.write('" "')
65cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(value))
66cb93a386Sopenharmony_ci  out.write('")\n')
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_cidef SetVariableList(out, variable_name, values):
70cb93a386Sopenharmony_ci  """Sets a CMake variable to a list."""
71cb93a386Sopenharmony_ci  if not values:
72cb93a386Sopenharmony_ci    return SetVariable(out, variable_name, "")
73cb93a386Sopenharmony_ci  if len(values) == 1:
74cb93a386Sopenharmony_ci    return SetVariable(out, variable_name, values[0])
75cb93a386Sopenharmony_ci  out.write('list(APPEND "')
76cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(variable_name))
77cb93a386Sopenharmony_ci  out.write('"\n  "')
78cb93a386Sopenharmony_ci  out.write('"\n  "'.join([CMakeStringEscape(value) for value in values]))
79cb93a386Sopenharmony_ci  out.write('")\n')
80cb93a386Sopenharmony_ci
81cb93a386Sopenharmony_ci
82cb93a386Sopenharmony_cidef SetFilesProperty(output, variable, property_name, values, sep):
83cb93a386Sopenharmony_ci  """Given a set of source files, sets the given property on them."""
84cb93a386Sopenharmony_ci  output.write('set_source_files_properties(')
85cb93a386Sopenharmony_ci  WriteVariable(output, variable)
86cb93a386Sopenharmony_ci  output.write(' PROPERTIES ')
87cb93a386Sopenharmony_ci  output.write(property_name)
88cb93a386Sopenharmony_ci  output.write(' "')
89cb93a386Sopenharmony_ci  for value in values:
90cb93a386Sopenharmony_ci    output.write(CMakeStringEscape(value))
91cb93a386Sopenharmony_ci    output.write(sep)
92cb93a386Sopenharmony_ci  output.write('")\n')
93cb93a386Sopenharmony_ci
94cb93a386Sopenharmony_ci
95cb93a386Sopenharmony_cidef SetCurrentTargetProperty(out, property_name, values, sep=''):
96cb93a386Sopenharmony_ci  """Given a target, sets the given property."""
97cb93a386Sopenharmony_ci  out.write('set_target_properties("${target}" PROPERTIES ')
98cb93a386Sopenharmony_ci  out.write(property_name)
99cb93a386Sopenharmony_ci  out.write(' "')
100cb93a386Sopenharmony_ci  for value in values:
101cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(value))
102cb93a386Sopenharmony_ci    out.write(sep)
103cb93a386Sopenharmony_ci  out.write('")\n')
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_cidef WriteVariable(output, variable_name, prepend=None):
107cb93a386Sopenharmony_ci  if prepend:
108cb93a386Sopenharmony_ci    output.write(prepend)
109cb93a386Sopenharmony_ci  output.write('${')
110cb93a386Sopenharmony_ci  output.write(variable_name)
111cb93a386Sopenharmony_ci  output.write('}')
112cb93a386Sopenharmony_ci
113cb93a386Sopenharmony_ci
114cb93a386Sopenharmony_ci# See GetSourceFileType in gn
115cb93a386Sopenharmony_cisource_file_types = {
116cb93a386Sopenharmony_ci  '.cc': 'cxx',
117cb93a386Sopenharmony_ci  '.cpp': 'cxx',
118cb93a386Sopenharmony_ci  '.cxx': 'cxx',
119cb93a386Sopenharmony_ci  '.m': 'objc',
120cb93a386Sopenharmony_ci  '.mm': 'objcc',
121cb93a386Sopenharmony_ci  '.c': 'c',
122cb93a386Sopenharmony_ci  '.s': 'asm',
123cb93a386Sopenharmony_ci  '.S': 'asm',
124cb93a386Sopenharmony_ci  '.asm': 'asm',
125cb93a386Sopenharmony_ci  '.o': 'obj',
126cb93a386Sopenharmony_ci  '.obj': 'obj',
127cb93a386Sopenharmony_ci}
128cb93a386Sopenharmony_ci
129cb93a386Sopenharmony_ci
130cb93a386Sopenharmony_ciclass CMakeTargetType(object):
131cb93a386Sopenharmony_ci  def __init__(self, command, modifier, property_modifier, is_linkable):
132cb93a386Sopenharmony_ci    self.command = command
133cb93a386Sopenharmony_ci    self.modifier = modifier
134cb93a386Sopenharmony_ci    self.property_modifier = property_modifier
135cb93a386Sopenharmony_ci    self.is_linkable = is_linkable
136cb93a386Sopenharmony_ciCMakeTargetType.custom = CMakeTargetType('add_custom_target', 'SOURCES',
137cb93a386Sopenharmony_ci                                         None, False)
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ci# See GetStringForOutputType in gn
140cb93a386Sopenharmony_cicmake_target_types = {
141cb93a386Sopenharmony_ci  'unknown': CMakeTargetType.custom,
142cb93a386Sopenharmony_ci  'group': CMakeTargetType.custom,
143cb93a386Sopenharmony_ci  'executable': CMakeTargetType('add_executable', None, 'RUNTIME', True),
144cb93a386Sopenharmony_ci  'loadable_module': CMakeTargetType('add_library', 'MODULE', 'LIBRARY', True),
145cb93a386Sopenharmony_ci  'shared_library': CMakeTargetType('add_library', 'SHARED', 'LIBRARY', True),
146cb93a386Sopenharmony_ci  'static_library': CMakeTargetType('add_library', 'STATIC', 'ARCHIVE', True),
147cb93a386Sopenharmony_ci  'source_set': CMakeTargetType('add_library', 'OBJECT', None, False),
148cb93a386Sopenharmony_ci  'copy': CMakeTargetType.custom,
149cb93a386Sopenharmony_ci  'action': CMakeTargetType.custom,
150cb93a386Sopenharmony_ci  'action_foreach': CMakeTargetType.custom,
151cb93a386Sopenharmony_ci  'bundle_data': CMakeTargetType.custom,
152cb93a386Sopenharmony_ci  'create_bundle': CMakeTargetType.custom,
153cb93a386Sopenharmony_ci}
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ci
156cb93a386Sopenharmony_cidef FindFirstOf(s, a):
157cb93a386Sopenharmony_ci  return min(s.find(i) for i in a if i in s)
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci
160cb93a386Sopenharmony_ciclass Project(object):
161cb93a386Sopenharmony_ci  def __init__(self, project_json):
162cb93a386Sopenharmony_ci    self.targets = project_json['targets']
163cb93a386Sopenharmony_ci    build_settings = project_json['build_settings']
164cb93a386Sopenharmony_ci    self.root_path = build_settings['root_path']
165cb93a386Sopenharmony_ci    self.build_path = self.GetAbsolutePath(build_settings['build_dir'])
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_ci  def GetAbsolutePath(self, path):
168cb93a386Sopenharmony_ci    if path.startswith('//'):
169cb93a386Sopenharmony_ci      return posixpath.join(self.root_path, path[2:])
170cb93a386Sopenharmony_ci    else:
171cb93a386Sopenharmony_ci      return path
172cb93a386Sopenharmony_ci
173cb93a386Sopenharmony_ci  def GetObjectSourceDependencies(self, gn_target_name, object_dependencies):
174cb93a386Sopenharmony_ci    """All OBJECT libraries whose sources have not been absorbed."""
175cb93a386Sopenharmony_ci    dependencies = self.targets[gn_target_name].get('deps', [])
176cb93a386Sopenharmony_ci    for dependency in dependencies:
177cb93a386Sopenharmony_ci      dependency_type = self.targets[dependency].get('type', None)
178cb93a386Sopenharmony_ci      if dependency_type == 'source_set':
179cb93a386Sopenharmony_ci        object_dependencies.add(dependency)
180cb93a386Sopenharmony_ci      if dependency_type not in gn_target_types_that_absorb_objects:
181cb93a386Sopenharmony_ci        self.GetObjectSourceDependencies(dependency, object_dependencies)
182cb93a386Sopenharmony_ci
183cb93a386Sopenharmony_ci  def GetObjectLibraryDependencies(self, gn_target_name, object_dependencies):
184cb93a386Sopenharmony_ci    """All OBJECT libraries whose libraries have not been absorbed."""
185cb93a386Sopenharmony_ci    dependencies = self.targets[gn_target_name].get('deps', [])
186cb93a386Sopenharmony_ci    for dependency in dependencies:
187cb93a386Sopenharmony_ci      dependency_type = self.targets[dependency].get('type', None)
188cb93a386Sopenharmony_ci      if dependency_type == 'source_set':
189cb93a386Sopenharmony_ci        object_dependencies.add(dependency)
190cb93a386Sopenharmony_ci        self.GetObjectLibraryDependencies(dependency, object_dependencies)
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci  def GetCMakeTargetName(self, gn_target_name):
193cb93a386Sopenharmony_ci    # See <chromium>/src/tools/gn/label.cc#Resolve
194cb93a386Sopenharmony_ci    # //base/test:test_support(//build/toolchain/win:msvc)
195cb93a386Sopenharmony_ci    path_separator = FindFirstOf(gn_target_name, (':', '('))
196cb93a386Sopenharmony_ci    location = None
197cb93a386Sopenharmony_ci    name = None
198cb93a386Sopenharmony_ci    toolchain = None
199cb93a386Sopenharmony_ci    if not path_separator:
200cb93a386Sopenharmony_ci      location = gn_target_name[2:]
201cb93a386Sopenharmony_ci    else:
202cb93a386Sopenharmony_ci      location = gn_target_name[2:path_separator]
203cb93a386Sopenharmony_ci      toolchain_separator = gn_target_name.find('(', path_separator)
204cb93a386Sopenharmony_ci      if toolchain_separator == -1:
205cb93a386Sopenharmony_ci        name = gn_target_name[path_separator + 1:]
206cb93a386Sopenharmony_ci      else:
207cb93a386Sopenharmony_ci        if toolchain_separator > path_separator:
208cb93a386Sopenharmony_ci          name = gn_target_name[path_separator + 1:toolchain_separator]
209cb93a386Sopenharmony_ci        assert gn_target_name.endswith(')')
210cb93a386Sopenharmony_ci        toolchain = gn_target_name[toolchain_separator + 1:-1]
211cb93a386Sopenharmony_ci    assert location or name
212cb93a386Sopenharmony_ci
213cb93a386Sopenharmony_ci    cmake_target_name = None
214cb93a386Sopenharmony_ci    if location.endswith('/' + name):
215cb93a386Sopenharmony_ci      cmake_target_name = location
216cb93a386Sopenharmony_ci    elif location:
217cb93a386Sopenharmony_ci      cmake_target_name = location + '_' + name
218cb93a386Sopenharmony_ci    else:
219cb93a386Sopenharmony_ci      cmake_target_name = name
220cb93a386Sopenharmony_ci    if toolchain:
221cb93a386Sopenharmony_ci      cmake_target_name += '--' + toolchain
222cb93a386Sopenharmony_ci    return CMakeTargetEscape(cmake_target_name)
223cb93a386Sopenharmony_ci
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ciclass Target(object):
226cb93a386Sopenharmony_ci  def __init__(self, gn_target_name, project):
227cb93a386Sopenharmony_ci    self.gn_name = gn_target_name
228cb93a386Sopenharmony_ci    self.properties = project.targets[self.gn_name]
229cb93a386Sopenharmony_ci    self.cmake_name = project.GetCMakeTargetName(self.gn_name)
230cb93a386Sopenharmony_ci    self.gn_type = self.properties.get('type', None)
231cb93a386Sopenharmony_ci    self.cmake_type = cmake_target_types.get(self.gn_type, None)
232cb93a386Sopenharmony_ci
233cb93a386Sopenharmony_ci
234cb93a386Sopenharmony_cidef WriteAction(out, target, project, sources, synthetic_dependencies):
235cb93a386Sopenharmony_ci  outputs = []
236cb93a386Sopenharmony_ci  output_directories = set()
237cb93a386Sopenharmony_ci  for output in target.properties.get('outputs', []):
238cb93a386Sopenharmony_ci    output_abs_path = project.GetAbsolutePath(output)
239cb93a386Sopenharmony_ci    outputs.append(output_abs_path)
240cb93a386Sopenharmony_ci    output_directory = posixpath.dirname(output_abs_path)
241cb93a386Sopenharmony_ci    if output_directory:
242cb93a386Sopenharmony_ci      output_directories.add(output_directory)
243cb93a386Sopenharmony_ci  outputs_name = '${target}__output'
244cb93a386Sopenharmony_ci  SetVariableList(out, outputs_name, outputs)
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ci  out.write('add_custom_command(OUTPUT ')
247cb93a386Sopenharmony_ci  WriteVariable(out, outputs_name)
248cb93a386Sopenharmony_ci  out.write('\n')
249cb93a386Sopenharmony_ci
250cb93a386Sopenharmony_ci  if output_directories:
251cb93a386Sopenharmony_ci    out.write('  COMMAND ${CMAKE_COMMAND} -E make_directory "')
252cb93a386Sopenharmony_ci    out.write('" "'.join(map(CMakeStringEscape, output_directories)))
253cb93a386Sopenharmony_ci    out.write('"\n')
254cb93a386Sopenharmony_ci
255cb93a386Sopenharmony_ci  script = target.properties['script']
256cb93a386Sopenharmony_ci  arguments = target.properties['args']
257cb93a386Sopenharmony_ci  out.write('  COMMAND python "')
258cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(project.GetAbsolutePath(script)))
259cb93a386Sopenharmony_ci  out.write('"')
260cb93a386Sopenharmony_ci  if arguments:
261cb93a386Sopenharmony_ci    out.write('\n    "')
262cb93a386Sopenharmony_ci    out.write('"\n    "'.join(map(CMakeStringEscape, arguments)))
263cb93a386Sopenharmony_ci    out.write('"')
264cb93a386Sopenharmony_ci  out.write('\n')
265cb93a386Sopenharmony_ci
266cb93a386Sopenharmony_ci  out.write('  DEPENDS ')
267cb93a386Sopenharmony_ci  for sources_type_name in sources.values():
268cb93a386Sopenharmony_ci    WriteVariable(out, sources_type_name, ' ')
269cb93a386Sopenharmony_ci  out.write('\n')
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci  #TODO: CMake 3.7 is introducing DEPFILE
272cb93a386Sopenharmony_ci
273cb93a386Sopenharmony_ci  out.write('  WORKING_DIRECTORY "')
274cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(project.build_path))
275cb93a386Sopenharmony_ci  out.write('"\n')
276cb93a386Sopenharmony_ci
277cb93a386Sopenharmony_ci  out.write('  COMMENT "Action: ${target}"\n')
278cb93a386Sopenharmony_ci
279cb93a386Sopenharmony_ci  out.write('  VERBATIM)\n')
280cb93a386Sopenharmony_ci
281cb93a386Sopenharmony_ci  synthetic_dependencies.add(outputs_name)
282cb93a386Sopenharmony_ci
283cb93a386Sopenharmony_ci
284cb93a386Sopenharmony_cidef ExpandPlaceholders(source, a):
285cb93a386Sopenharmony_ci  source_dir, source_file_part = posixpath.split(source)
286cb93a386Sopenharmony_ci  source_name_part, _ = posixpath.splitext(source_file_part)
287cb93a386Sopenharmony_ci  #TODO: {{source_gen_dir}}, {{source_out_dir}}, {{response_file_name}}
288cb93a386Sopenharmony_ci  return a.replace('{{source}}', source) \
289cb93a386Sopenharmony_ci          .replace('{{source_file_part}}', source_file_part) \
290cb93a386Sopenharmony_ci          .replace('{{source_name_part}}', source_name_part) \
291cb93a386Sopenharmony_ci          .replace('{{source_dir}}', source_dir) \
292cb93a386Sopenharmony_ci          .replace('{{source_root_relative_dir}}', source_dir)
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci
295cb93a386Sopenharmony_cidef WriteActionForEach(out, target, project, sources, synthetic_dependencies):
296cb93a386Sopenharmony_ci  all_outputs = target.properties.get('outputs', [])
297cb93a386Sopenharmony_ci  inputs = target.properties.get('sources', [])
298cb93a386Sopenharmony_ci  # TODO: consider expanding 'output_patterns' instead.
299cb93a386Sopenharmony_ci  outputs_per_input = len(all_outputs) / len(inputs)
300cb93a386Sopenharmony_ci  for count, source in enumerate(inputs):
301cb93a386Sopenharmony_ci    source_abs_path = project.GetAbsolutePath(source)
302cb93a386Sopenharmony_ci
303cb93a386Sopenharmony_ci    outputs = []
304cb93a386Sopenharmony_ci    output_directories = set()
305cb93a386Sopenharmony_ci    for output in all_outputs[outputs_per_input *  count:
306cb93a386Sopenharmony_ci                              outputs_per_input * (count+1)]:
307cb93a386Sopenharmony_ci      output_abs_path = project.GetAbsolutePath(output)
308cb93a386Sopenharmony_ci      outputs.append(output_abs_path)
309cb93a386Sopenharmony_ci      output_directory = posixpath.dirname(output_abs_path)
310cb93a386Sopenharmony_ci      if output_directory:
311cb93a386Sopenharmony_ci        output_directories.add(output_directory)
312cb93a386Sopenharmony_ci    outputs_name = '${target}__output_' + str(count)
313cb93a386Sopenharmony_ci    SetVariableList(out, outputs_name, outputs)
314cb93a386Sopenharmony_ci
315cb93a386Sopenharmony_ci    out.write('add_custom_command(OUTPUT ')
316cb93a386Sopenharmony_ci    WriteVariable(out, outputs_name)
317cb93a386Sopenharmony_ci    out.write('\n')
318cb93a386Sopenharmony_ci
319cb93a386Sopenharmony_ci    if output_directories:
320cb93a386Sopenharmony_ci      out.write('  COMMAND ${CMAKE_COMMAND} -E make_directory "')
321cb93a386Sopenharmony_ci      out.write('" "'.join(map(CMakeStringEscape, output_directories)))
322cb93a386Sopenharmony_ci      out.write('"\n')
323cb93a386Sopenharmony_ci
324cb93a386Sopenharmony_ci    script = target.properties['script']
325cb93a386Sopenharmony_ci    # TODO: need to expand {{xxx}} in arguments
326cb93a386Sopenharmony_ci    arguments = target.properties['args']
327cb93a386Sopenharmony_ci    out.write('  COMMAND python "')
328cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(project.GetAbsolutePath(script)))
329cb93a386Sopenharmony_ci    out.write('"')
330cb93a386Sopenharmony_ci    if arguments:
331cb93a386Sopenharmony_ci      out.write('\n    "')
332cb93a386Sopenharmony_ci      expand = functools.partial(ExpandPlaceholders, source_abs_path)
333cb93a386Sopenharmony_ci      out.write('"\n    "'.join(map(CMakeStringEscape, map(expand,arguments))))
334cb93a386Sopenharmony_ci      out.write('"')
335cb93a386Sopenharmony_ci    out.write('\n')
336cb93a386Sopenharmony_ci
337cb93a386Sopenharmony_ci    out.write('  DEPENDS')
338cb93a386Sopenharmony_ci    if 'input' in sources:
339cb93a386Sopenharmony_ci      WriteVariable(out, sources['input'], ' ')
340cb93a386Sopenharmony_ci    out.write(' "')
341cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(source_abs_path))
342cb93a386Sopenharmony_ci    out.write('"\n')
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ci    #TODO: CMake 3.7 is introducing DEPFILE
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci    out.write('  WORKING_DIRECTORY "')
347cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(project.build_path))
348cb93a386Sopenharmony_ci    out.write('"\n')
349cb93a386Sopenharmony_ci
350cb93a386Sopenharmony_ci    out.write('  COMMENT "Action ${target} on ')
351cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(source_abs_path))
352cb93a386Sopenharmony_ci    out.write('"\n')
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ci    out.write('  VERBATIM)\n')
355cb93a386Sopenharmony_ci
356cb93a386Sopenharmony_ci    synthetic_dependencies.add(outputs_name)
357cb93a386Sopenharmony_ci
358cb93a386Sopenharmony_ci
359cb93a386Sopenharmony_cidef WriteCopy(out, target, project, sources, synthetic_dependencies):
360cb93a386Sopenharmony_ci  inputs = target.properties.get('sources', [])
361cb93a386Sopenharmony_ci  raw_outputs = target.properties.get('outputs', [])
362cb93a386Sopenharmony_ci
363cb93a386Sopenharmony_ci  # TODO: consider expanding 'output_patterns' instead.
364cb93a386Sopenharmony_ci  outputs = []
365cb93a386Sopenharmony_ci  for output in raw_outputs:
366cb93a386Sopenharmony_ci    output_abs_path = project.GetAbsolutePath(output)
367cb93a386Sopenharmony_ci    outputs.append(output_abs_path)
368cb93a386Sopenharmony_ci  outputs_name = '${target}__output'
369cb93a386Sopenharmony_ci  SetVariableList(out, outputs_name, outputs)
370cb93a386Sopenharmony_ci
371cb93a386Sopenharmony_ci  out.write('add_custom_command(OUTPUT ')
372cb93a386Sopenharmony_ci  WriteVariable(out, outputs_name)
373cb93a386Sopenharmony_ci  out.write('\n')
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_ci  for src, dst in zip(inputs, outputs):
376cb93a386Sopenharmony_ci    abs_src_path = CMakeStringEscape(project.GetAbsolutePath(src))
377cb93a386Sopenharmony_ci    # CMake distinguishes between copying files and copying directories but
378cb93a386Sopenharmony_ci    # gn does not. We assume if the src has a period in its name then it is
379cb93a386Sopenharmony_ci    # a file and otherwise a directory.
380cb93a386Sopenharmony_ci    if "." in os.path.basename(abs_src_path):
381cb93a386Sopenharmony_ci      out.write('  COMMAND ${CMAKE_COMMAND} -E copy "')
382cb93a386Sopenharmony_ci    else:
383cb93a386Sopenharmony_ci      out.write('  COMMAND ${CMAKE_COMMAND} -E copy_directory "')
384cb93a386Sopenharmony_ci    out.write(abs_src_path)
385cb93a386Sopenharmony_ci    out.write('" "')
386cb93a386Sopenharmony_ci    out.write(CMakeStringEscape(dst))
387cb93a386Sopenharmony_ci    out.write('"\n')
388cb93a386Sopenharmony_ci
389cb93a386Sopenharmony_ci  out.write('  DEPENDS ')
390cb93a386Sopenharmony_ci  for sources_type_name in sources.values():
391cb93a386Sopenharmony_ci    WriteVariable(out, sources_type_name, ' ')
392cb93a386Sopenharmony_ci  out.write('\n')
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci  out.write('  WORKING_DIRECTORY "')
395cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(project.build_path))
396cb93a386Sopenharmony_ci  out.write('"\n')
397cb93a386Sopenharmony_ci
398cb93a386Sopenharmony_ci  out.write('  COMMENT "Copy ${target}"\n')
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_ci  out.write('  VERBATIM)\n')
401cb93a386Sopenharmony_ci
402cb93a386Sopenharmony_ci  synthetic_dependencies.add(outputs_name)
403cb93a386Sopenharmony_ci
404cb93a386Sopenharmony_ci
405cb93a386Sopenharmony_cidef WriteCompilerFlags(out, target, project, sources):
406cb93a386Sopenharmony_ci  # Hack, set linker language to c if no c or cxx files present.
407cb93a386Sopenharmony_ci  if not 'c' in sources and not 'cxx' in sources:
408cb93a386Sopenharmony_ci    SetCurrentTargetProperty(out, 'LINKER_LANGUAGE', ['C'])
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_ci  # Mark uncompiled sources as uncompiled.
411cb93a386Sopenharmony_ci  if 'input' in sources:
412cb93a386Sopenharmony_ci    SetFilesProperty(out, sources['input'], 'HEADER_FILE_ONLY', ('True',), '')
413cb93a386Sopenharmony_ci  if 'other' in sources:
414cb93a386Sopenharmony_ci    SetFilesProperty(out, sources['other'], 'HEADER_FILE_ONLY', ('True',), '')
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci  # Mark object sources as linkable.
417cb93a386Sopenharmony_ci  if 'obj' in sources:
418cb93a386Sopenharmony_ci    SetFilesProperty(out, sources['obj'], 'EXTERNAL_OBJECT', ('True',), '')
419cb93a386Sopenharmony_ci
420cb93a386Sopenharmony_ci  # TODO: 'output_name', 'output_dir', 'output_extension'
421cb93a386Sopenharmony_ci  # This includes using 'source_outputs' to direct compiler output.
422cb93a386Sopenharmony_ci
423cb93a386Sopenharmony_ci  # Includes
424cb93a386Sopenharmony_ci  includes = target.properties.get('include_dirs', [])
425cb93a386Sopenharmony_ci  if includes:
426cb93a386Sopenharmony_ci    out.write('set_property(TARGET "${target}" ')
427cb93a386Sopenharmony_ci    out.write('APPEND PROPERTY INCLUDE_DIRECTORIES')
428cb93a386Sopenharmony_ci    for include_dir in includes:
429cb93a386Sopenharmony_ci      out.write('\n  "')
430cb93a386Sopenharmony_ci      out.write(project.GetAbsolutePath(include_dir))
431cb93a386Sopenharmony_ci      out.write('"')
432cb93a386Sopenharmony_ci    out.write(')\n')
433cb93a386Sopenharmony_ci
434cb93a386Sopenharmony_ci  # Defines
435cb93a386Sopenharmony_ci  defines = target.properties.get('defines', [])
436cb93a386Sopenharmony_ci  if defines:
437cb93a386Sopenharmony_ci    SetCurrentTargetProperty(out, 'COMPILE_DEFINITIONS', defines, ';')
438cb93a386Sopenharmony_ci
439cb93a386Sopenharmony_ci  # Compile flags
440cb93a386Sopenharmony_ci  # "arflags", "asmflags", "cflags",
441cb93a386Sopenharmony_ci  # "cflags_c", "clfags_cc", "cflags_objc", "clfags_objcc"
442cb93a386Sopenharmony_ci  # CMake does not have per target lang compile flags.
443cb93a386Sopenharmony_ci  # TODO: $<$<COMPILE_LANGUAGE:CXX>:cflags_cc style generator expression.
444cb93a386Sopenharmony_ci  #       http://public.kitware.com/Bug/view.php?id=14857
445cb93a386Sopenharmony_ci  flags = []
446cb93a386Sopenharmony_ci  flags.extend(target.properties.get('cflags', []))
447cb93a386Sopenharmony_ci  cflags_asm = target.properties.get('asmflags', [])
448cb93a386Sopenharmony_ci  cflags_c = target.properties.get('cflags_c', [])
449cb93a386Sopenharmony_ci  cflags_cxx = target.properties.get('cflags_cc', [])
450cb93a386Sopenharmony_ci  cflags_objc = cflags_c[:]
451cb93a386Sopenharmony_ci  cflags_objc.extend(target.properties.get('cflags_objc', []))
452cb93a386Sopenharmony_ci  cflags_objcc = cflags_cxx[:]
453cb93a386Sopenharmony_ci  cflags_objcc.extend(target.properties.get('cflags_objcc', []))
454cb93a386Sopenharmony_ci
455cb93a386Sopenharmony_ci  if 'c' in sources and not any(k in sources for k in ('asm', 'cxx', 'objc', 'objcc')):
456cb93a386Sopenharmony_ci    flags.extend(cflags_c)
457cb93a386Sopenharmony_ci  elif 'cxx' in sources and not any(k in sources for k in ('asm', 'c', 'objc', 'objcc')):
458cb93a386Sopenharmony_ci    flags.extend(cflags_cxx)
459cb93a386Sopenharmony_ci  elif 'objc' in sources and not any(k in sources for k in ('asm', 'c', 'cxx', 'objcc')):
460cb93a386Sopenharmony_ci    flags.extend(cflags_objc)
461cb93a386Sopenharmony_ci  elif 'objcc' in sources and not any(k in sources for k in ('asm', 'c', 'cxx', 'objc')):
462cb93a386Sopenharmony_ci    flags.extend(cflags_objcc)
463cb93a386Sopenharmony_ci  else:
464cb93a386Sopenharmony_ci    # TODO: This is broken, one cannot generally set properties on files,
465cb93a386Sopenharmony_ci    # as other targets may require different properties on the same files.
466cb93a386Sopenharmony_ci    if 'asm' in sources and cflags_asm:
467cb93a386Sopenharmony_ci      SetFilesProperty(out, sources['asm'], 'COMPILE_FLAGS', cflags_asm, ' ')
468cb93a386Sopenharmony_ci    if 'c' in sources and cflags_c:
469cb93a386Sopenharmony_ci      SetFilesProperty(out, sources['c'], 'COMPILE_FLAGS', cflags_c, ' ')
470cb93a386Sopenharmony_ci    if 'cxx' in sources and cflags_cxx:
471cb93a386Sopenharmony_ci      SetFilesProperty(out, sources['cxx'], 'COMPILE_FLAGS', cflags_cxx, ' ')
472cb93a386Sopenharmony_ci    if 'objc' in sources and cflags_objc:
473cb93a386Sopenharmony_ci      SetFilesProperty(out, sources['objc'], 'COMPILE_FLAGS', cflags_objc, ' ')
474cb93a386Sopenharmony_ci    if 'objcc' in sources and cflags_objcc:
475cb93a386Sopenharmony_ci      SetFilesProperty(out, sources['objcc'], 'COMPILE_FLAGS', cflags_objcc, ' ')
476cb93a386Sopenharmony_ci  if flags:
477cb93a386Sopenharmony_ci    SetCurrentTargetProperty(out, 'COMPILE_FLAGS', flags, ' ')
478cb93a386Sopenharmony_ci
479cb93a386Sopenharmony_ci  # Linker flags
480cb93a386Sopenharmony_ci  ldflags = target.properties.get('ldflags', [])
481cb93a386Sopenharmony_ci  if ldflags:
482cb93a386Sopenharmony_ci    SetCurrentTargetProperty(out, 'LINK_FLAGS', ldflags, ' ')
483cb93a386Sopenharmony_ci
484cb93a386Sopenharmony_ci
485cb93a386Sopenharmony_cign_target_types_that_absorb_objects = (
486cb93a386Sopenharmony_ci  'executable',
487cb93a386Sopenharmony_ci  'loadable_module',
488cb93a386Sopenharmony_ci  'shared_library',
489cb93a386Sopenharmony_ci  'static_library'
490cb93a386Sopenharmony_ci)
491cb93a386Sopenharmony_ci
492cb93a386Sopenharmony_ci
493cb93a386Sopenharmony_cidef WriteSourceVariables(out, target, project):
494cb93a386Sopenharmony_ci  # gn separates the sheep from the goats based on file extensions.
495cb93a386Sopenharmony_ci  # A full separation is done here because of flag handing (see Compile flags).
496cb93a386Sopenharmony_ci  source_types = {'cxx':[], 'c':[], 'asm':[], 'objc':[], 'objcc':[],
497cb93a386Sopenharmony_ci                  'obj':[], 'obj_target':[], 'input':[], 'other':[]}
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ci  all_sources = target.properties.get('sources', [])
500cb93a386Sopenharmony_ci
501cb93a386Sopenharmony_ci  # As of cmake 3.11 add_library must have sources. If there are
502cb93a386Sopenharmony_ci  # no sources, add empty.cpp as the file to compile.
503cb93a386Sopenharmony_ci  if len(all_sources) == 0:
504cb93a386Sopenharmony_ci    all_sources.append(posixpath.join(project.build_path, 'empty.cpp'))
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci  # TODO .def files on Windows
507cb93a386Sopenharmony_ci  for source in all_sources:
508cb93a386Sopenharmony_ci    _, ext = posixpath.splitext(source)
509cb93a386Sopenharmony_ci    source_abs_path = project.GetAbsolutePath(source)
510cb93a386Sopenharmony_ci    source_types[source_file_types.get(ext, 'other')].append(source_abs_path)
511cb93a386Sopenharmony_ci
512cb93a386Sopenharmony_ci  for input_path in target.properties.get('inputs', []):
513cb93a386Sopenharmony_ci    input_abs_path = project.GetAbsolutePath(input_path)
514cb93a386Sopenharmony_ci    source_types['input'].append(input_abs_path)
515cb93a386Sopenharmony_ci
516cb93a386Sopenharmony_ci  # OBJECT library dependencies need to be listed as sources.
517cb93a386Sopenharmony_ci  # Only executables and non-OBJECT libraries may reference an OBJECT library.
518cb93a386Sopenharmony_ci  # https://gitlab.kitware.com/cmake/cmake/issues/14778
519cb93a386Sopenharmony_ci  if target.gn_type in gn_target_types_that_absorb_objects:
520cb93a386Sopenharmony_ci    object_dependencies = set()
521cb93a386Sopenharmony_ci    project.GetObjectSourceDependencies(target.gn_name, object_dependencies)
522cb93a386Sopenharmony_ci    for dependency in object_dependencies:
523cb93a386Sopenharmony_ci      cmake_dependency_name = project.GetCMakeTargetName(dependency)
524cb93a386Sopenharmony_ci      obj_target_sources = '$<TARGET_OBJECTS:' + cmake_dependency_name + '>'
525cb93a386Sopenharmony_ci      source_types['obj_target'].append(obj_target_sources)
526cb93a386Sopenharmony_ci
527cb93a386Sopenharmony_ci  sources = {}
528cb93a386Sopenharmony_ci  for source_type, sources_of_type in source_types.items():
529cb93a386Sopenharmony_ci    if sources_of_type:
530cb93a386Sopenharmony_ci      sources[source_type] = '${target}__' + source_type + '_srcs'
531cb93a386Sopenharmony_ci      SetVariableList(out, sources[source_type], sources_of_type)
532cb93a386Sopenharmony_ci  return sources
533cb93a386Sopenharmony_ci
534cb93a386Sopenharmony_ci
535cb93a386Sopenharmony_cidef WriteTarget(out, target, project):
536cb93a386Sopenharmony_ci  out.write('\n#')
537cb93a386Sopenharmony_ci  out.write(target.gn_name)
538cb93a386Sopenharmony_ci  out.write('\n')
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_ci  if target.cmake_type is None:
541cb93a386Sopenharmony_ci    print ('Target %s has unknown target type %s, skipping.' %
542cb93a386Sopenharmony_ci          (        target.gn_name,            target.gn_type ) )
543cb93a386Sopenharmony_ci    return
544cb93a386Sopenharmony_ci
545cb93a386Sopenharmony_ci  SetVariable(out, 'target', target.cmake_name)
546cb93a386Sopenharmony_ci
547cb93a386Sopenharmony_ci  sources = WriteSourceVariables(out, target, project)
548cb93a386Sopenharmony_ci
549cb93a386Sopenharmony_ci  synthetic_dependencies = set()
550cb93a386Sopenharmony_ci  if target.gn_type == 'action':
551cb93a386Sopenharmony_ci    WriteAction(out, target, project, sources, synthetic_dependencies)
552cb93a386Sopenharmony_ci  if target.gn_type == 'action_foreach':
553cb93a386Sopenharmony_ci    WriteActionForEach(out, target, project, sources, synthetic_dependencies)
554cb93a386Sopenharmony_ci  if target.gn_type == 'copy':
555cb93a386Sopenharmony_ci    WriteCopy(out, target, project, sources, synthetic_dependencies)
556cb93a386Sopenharmony_ci
557cb93a386Sopenharmony_ci  out.write(target.cmake_type.command)
558cb93a386Sopenharmony_ci  out.write('("${target}"')
559cb93a386Sopenharmony_ci  if target.cmake_type.modifier is not None:
560cb93a386Sopenharmony_ci    out.write(' ')
561cb93a386Sopenharmony_ci    out.write(target.cmake_type.modifier)
562cb93a386Sopenharmony_ci  for sources_type_name in sources.values():
563cb93a386Sopenharmony_ci    WriteVariable(out, sources_type_name, ' ')
564cb93a386Sopenharmony_ci  if synthetic_dependencies:
565cb93a386Sopenharmony_ci    out.write(' DEPENDS')
566cb93a386Sopenharmony_ci    for synthetic_dependencie in synthetic_dependencies:
567cb93a386Sopenharmony_ci      WriteVariable(out, synthetic_dependencie, ' ')
568cb93a386Sopenharmony_ci  out.write(')\n')
569cb93a386Sopenharmony_ci
570cb93a386Sopenharmony_ci  if target.cmake_type.command != 'add_custom_target':
571cb93a386Sopenharmony_ci    WriteCompilerFlags(out, target, project, sources)
572cb93a386Sopenharmony_ci
573cb93a386Sopenharmony_ci  libraries = set()
574cb93a386Sopenharmony_ci  nonlibraries = set()
575cb93a386Sopenharmony_ci
576cb93a386Sopenharmony_ci  dependencies = set(target.properties.get('deps', []))
577cb93a386Sopenharmony_ci  # Transitive OBJECT libraries are in sources.
578cb93a386Sopenharmony_ci  # Those sources are dependent on the OBJECT library dependencies.
579cb93a386Sopenharmony_ci  # Those sources cannot bring in library dependencies.
580cb93a386Sopenharmony_ci  object_dependencies = set()
581cb93a386Sopenharmony_ci  if target.gn_type != 'source_set':
582cb93a386Sopenharmony_ci    project.GetObjectLibraryDependencies(target.gn_name, object_dependencies)
583cb93a386Sopenharmony_ci  for object_dependency in object_dependencies:
584cb93a386Sopenharmony_ci    dependencies.update(project.targets.get(object_dependency).get('deps', []))
585cb93a386Sopenharmony_ci
586cb93a386Sopenharmony_ci  for dependency in dependencies:
587cb93a386Sopenharmony_ci    gn_dependency_type = project.targets.get(dependency, {}).get('type', None)
588cb93a386Sopenharmony_ci    cmake_dependency_type = cmake_target_types.get(gn_dependency_type, None)
589cb93a386Sopenharmony_ci    cmake_dependency_name = project.GetCMakeTargetName(dependency)
590cb93a386Sopenharmony_ci    if cmake_dependency_type.command != 'add_library':
591cb93a386Sopenharmony_ci      nonlibraries.add(cmake_dependency_name)
592cb93a386Sopenharmony_ci    elif cmake_dependency_type.modifier != 'OBJECT':
593cb93a386Sopenharmony_ci      if target.cmake_type.is_linkable:
594cb93a386Sopenharmony_ci        libraries.add(cmake_dependency_name)
595cb93a386Sopenharmony_ci      else:
596cb93a386Sopenharmony_ci        nonlibraries.add(cmake_dependency_name)
597cb93a386Sopenharmony_ci
598cb93a386Sopenharmony_ci  # Non-library dependencies.
599cb93a386Sopenharmony_ci  if nonlibraries:
600cb93a386Sopenharmony_ci    out.write('add_dependencies("${target}"')
601cb93a386Sopenharmony_ci    for nonlibrary in nonlibraries:
602cb93a386Sopenharmony_ci      out.write('\n  "')
603cb93a386Sopenharmony_ci      out.write(nonlibrary)
604cb93a386Sopenharmony_ci      out.write('"')
605cb93a386Sopenharmony_ci    out.write(')\n')
606cb93a386Sopenharmony_ci
607cb93a386Sopenharmony_ci  # Non-OBJECT library dependencies.
608cb93a386Sopenharmony_ci  combined_library_lists = [target.properties.get(key, []) for key in ['libs', 'frameworks']]
609cb93a386Sopenharmony_ci  external_libraries = list(itertools.chain(*combined_library_lists))
610cb93a386Sopenharmony_ci  if target.cmake_type.is_linkable and (external_libraries or libraries):
611cb93a386Sopenharmony_ci    library_dirs = target.properties.get('lib_dirs', [])
612cb93a386Sopenharmony_ci    if library_dirs:
613cb93a386Sopenharmony_ci      SetVariableList(out, '${target}__library_directories', library_dirs)
614cb93a386Sopenharmony_ci
615cb93a386Sopenharmony_ci    system_libraries = []
616cb93a386Sopenharmony_ci    for external_library in external_libraries:
617cb93a386Sopenharmony_ci      if '/' in external_library:
618cb93a386Sopenharmony_ci        libraries.add(project.GetAbsolutePath(external_library))
619cb93a386Sopenharmony_ci      else:
620cb93a386Sopenharmony_ci        if external_library.endswith('.framework'):
621cb93a386Sopenharmony_ci          external_library = external_library[:-len('.framework')]
622cb93a386Sopenharmony_ci        system_library = 'library__' + external_library
623cb93a386Sopenharmony_ci        if library_dirs:
624cb93a386Sopenharmony_ci          system_library = system_library + '__for_${target}'
625cb93a386Sopenharmony_ci        out.write('find_library("')
626cb93a386Sopenharmony_ci        out.write(CMakeStringEscape(system_library))
627cb93a386Sopenharmony_ci        out.write('" "')
628cb93a386Sopenharmony_ci        out.write(CMakeStringEscape(external_library))
629cb93a386Sopenharmony_ci        out.write('"')
630cb93a386Sopenharmony_ci        if library_dirs:
631cb93a386Sopenharmony_ci          out.write(' PATHS "')
632cb93a386Sopenharmony_ci          WriteVariable(out, '${target}__library_directories')
633cb93a386Sopenharmony_ci          out.write('"')
634cb93a386Sopenharmony_ci        out.write(')\n')
635cb93a386Sopenharmony_ci        system_libraries.append(system_library)
636cb93a386Sopenharmony_ci    out.write('target_link_libraries("${target}"')
637cb93a386Sopenharmony_ci    for library in libraries:
638cb93a386Sopenharmony_ci      out.write('\n  "')
639cb93a386Sopenharmony_ci      out.write(CMakeStringEscape(library))
640cb93a386Sopenharmony_ci      out.write('"')
641cb93a386Sopenharmony_ci    for system_library in system_libraries:
642cb93a386Sopenharmony_ci      WriteVariable(out, system_library, '\n  "')
643cb93a386Sopenharmony_ci      out.write('"')
644cb93a386Sopenharmony_ci    out.write(')\n')
645cb93a386Sopenharmony_ci
646cb93a386Sopenharmony_ci
647cb93a386Sopenharmony_cidef WriteProject(project):
648cb93a386Sopenharmony_ci  out = open(posixpath.join(project.build_path, 'CMakeLists.txt'), 'w+')
649cb93a386Sopenharmony_ci  extName = posixpath.join(project.build_path, 'CMakeLists.ext')
650cb93a386Sopenharmony_ci  out.write('# Generated by gn_to_cmake.py.\n')
651cb93a386Sopenharmony_ci  out.write('cmake_minimum_required(VERSION 3.7 FATAL_ERROR)\n')
652cb93a386Sopenharmony_ci  out.write('cmake_policy(VERSION 3.7)\n')
653cb93a386Sopenharmony_ci  out.write('project(Skia)\n\n')
654cb93a386Sopenharmony_ci
655cb93a386Sopenharmony_ci  out.write('file(WRITE "')
656cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(posixpath.join(project.build_path, "empty.cpp")))
657cb93a386Sopenharmony_ci  out.write('")\n')
658cb93a386Sopenharmony_ci
659cb93a386Sopenharmony_ci  # Update the gn generated ninja build.
660cb93a386Sopenharmony_ci  # If a build file has changed, this will update CMakeLists.ext if
661cb93a386Sopenharmony_ci  # gn gen out/config --ide=json --json-ide-script=../../gn/gn_to_cmake.py
662cb93a386Sopenharmony_ci  # style was used to create this config.
663cb93a386Sopenharmony_ci  out.write('execute_process(COMMAND\n')
664cb93a386Sopenharmony_ci  out.write('  ninja -C "')
665cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(project.build_path))
666cb93a386Sopenharmony_ci  out.write('" build.ninja\n')
667cb93a386Sopenharmony_ci  out.write('  RESULT_VARIABLE ninja_result)\n')
668cb93a386Sopenharmony_ci  out.write('if (ninja_result)\n')
669cb93a386Sopenharmony_ci  out.write('  message(WARNING ')
670cb93a386Sopenharmony_ci  out.write('"Regeneration failed running ninja: ${ninja_result}")\n')
671cb93a386Sopenharmony_ci  out.write('endif()\n')
672cb93a386Sopenharmony_ci
673cb93a386Sopenharmony_ci  out.write('include("')
674cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(extName))
675cb93a386Sopenharmony_ci  out.write('")\n')
676cb93a386Sopenharmony_ci  # This lets Clion find the emscripten header files when working with CanvasKit.
677cb93a386Sopenharmony_ci  out.write('include_directories(SYSTEM $ENV{EMSDK}/upstream/emscripten/system/include/)\n')
678cb93a386Sopenharmony_ci  out.close()
679cb93a386Sopenharmony_ci
680cb93a386Sopenharmony_ci  out = open(extName, 'w+')
681cb93a386Sopenharmony_ci  out.write('# Generated by gn_to_cmake.py.\n')
682cb93a386Sopenharmony_ci  out.write('cmake_minimum_required(VERSION 3.7 FATAL_ERROR)\n')
683cb93a386Sopenharmony_ci  out.write('cmake_policy(VERSION 3.7)\n')
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci  # The following appears to be as-yet undocumented.
686cb93a386Sopenharmony_ci  # http://public.kitware.com/Bug/view.php?id=8392
687cb93a386Sopenharmony_ci  out.write('enable_language(ASM)\n\n')
688cb93a386Sopenharmony_ci  # ASM-ATT does not support .S files.
689cb93a386Sopenharmony_ci  # output.write('enable_language(ASM-ATT)\n')
690cb93a386Sopenharmony_ci
691cb93a386Sopenharmony_ci  # Current issues with automatic re-generation:
692cb93a386Sopenharmony_ci  # The gn generated build.ninja target uses build.ninja.d
693cb93a386Sopenharmony_ci  #   but build.ninja.d does not contain the ide or gn.
694cb93a386Sopenharmony_ci  # Currently the ide is not run if the project.json file is not changed
695cb93a386Sopenharmony_ci  #   but the ide needs to be run anyway if it has itself changed.
696cb93a386Sopenharmony_ci  #   This can be worked around by deleting the project.json file.
697cb93a386Sopenharmony_ci  out.write('file(READ "')
698cb93a386Sopenharmony_ci  gn_deps_file = posixpath.join(project.build_path, 'build.ninja.d')
699cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(gn_deps_file))
700cb93a386Sopenharmony_ci  out.write('" "gn_deps_string" OFFSET ')
701cb93a386Sopenharmony_ci  out.write(str(len('build.ninja: ')))
702cb93a386Sopenharmony_ci  out.write(')\n')
703cb93a386Sopenharmony_ci  # One would think this would need to worry about escaped spaces
704cb93a386Sopenharmony_ci  # but gn doesn't escape spaces here (it generates invalid .d files).
705cb93a386Sopenharmony_ci  out.write('string(REPLACE " " ";" "gn_deps" ${gn_deps_string})\n')
706cb93a386Sopenharmony_ci  out.write('foreach("gn_dep" ${gn_deps})\n')
707cb93a386Sopenharmony_ci  out.write('  configure_file("')
708cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(project.build_path))
709cb93a386Sopenharmony_ci  out.write('${gn_dep}" "CMakeLists.devnull" COPYONLY)\n')
710cb93a386Sopenharmony_ci  out.write('endforeach("gn_dep")\n')
711cb93a386Sopenharmony_ci
712cb93a386Sopenharmony_ci  out.write('list(APPEND other_deps "')
713cb93a386Sopenharmony_ci  out.write(CMakeStringEscape(os.path.abspath(__file__)))
714cb93a386Sopenharmony_ci  out.write('")\n')
715cb93a386Sopenharmony_ci  out.write('foreach("other_dep" ${other_deps})\n')
716cb93a386Sopenharmony_ci  out.write('  configure_file("${other_dep}" "CMakeLists.devnull" COPYONLY)\n')
717cb93a386Sopenharmony_ci  out.write('endforeach("other_dep")\n')
718cb93a386Sopenharmony_ci
719cb93a386Sopenharmony_ci  for target_name in project.targets.keys():
720cb93a386Sopenharmony_ci    out.write('\n')
721cb93a386Sopenharmony_ci    WriteTarget(out, Target(target_name, project), project)
722cb93a386Sopenharmony_ci
723cb93a386Sopenharmony_ci
724cb93a386Sopenharmony_cidef main():
725cb93a386Sopenharmony_ci  if len(sys.argv) != 2:
726cb93a386Sopenharmony_ci    print('Usage: ' + sys.argv[0] + ' <json_file_name>')
727cb93a386Sopenharmony_ci    exit(1)
728cb93a386Sopenharmony_ci
729cb93a386Sopenharmony_ci  json_path = sys.argv[1]
730cb93a386Sopenharmony_ci  project = None
731cb93a386Sopenharmony_ci  with open(json_path, 'r') as json_file:
732cb93a386Sopenharmony_ci    project = json.loads(json_file.read())
733cb93a386Sopenharmony_ci
734cb93a386Sopenharmony_ci  WriteProject(Project(project))
735cb93a386Sopenharmony_ci
736cb93a386Sopenharmony_ci
737cb93a386Sopenharmony_ciif __name__ == "__main__":
738cb93a386Sopenharmony_ci  main()
739