Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: build/android/gradle/gn_to_cmake.py

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

Powered by Google App Engine
This is Rietveld 408576698