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