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