1#!/usr/bin/env python 2# Copyright 2013 The Flutter 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 6import argparse 7import subprocess 8import sys 9import os 10 11SRC_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 12 13def get_out_dir(args): 14 if args.target_os is not None: 15 target_dir = [args.target_os] 16 else: 17 target_dir = ['host'] 18 19 runtime_mode = args.runtime_mode 20 if args.dynamic and runtime_mode in ['profile', 'release']: 21 target_dir.append('dynamic') 22 23 target_dir.append(args.runtime_mode) 24 25 if args.simulator: 26 target_dir.append('sim') 27 28 if args.unoptimized: 29 target_dir.append('unopt') 30 31 if args.target_os != 'ios' and args.interpreter: 32 target_dir.append('interpreter') 33 34 if args.android_cpu != 'arm': 35 target_dir.append(args.android_cpu) 36 37 if args.ios_cpu != 'arm64': 38 target_dir.append(args.ios_cpu) 39 40 if args.linux_cpu is not None: 41 target_dir.append(args.linux_cpu) 42 43 if args.target_os == 'fuchsia' and args.fuchsia_cpu is not None: 44 target_dir.append(args.fuchsia_cpu) 45 46 if args.enable_vulkan: 47 target_dir.append('vulkan') 48 49 if args.enable_metal: 50 target_dir.append('metal') 51 52 return os.path.join(args.out_dir, 'out', '_'.join(target_dir)) 53 54def to_command_line(gn_args): 55 def merge(key, value): 56 if type(value) is bool: 57 return '%s=%s' % (key, 'true' if value else 'false') 58 return '%s="%s"' % (key, value) 59 return [merge(x, y) for x, y in gn_args.iteritems()] 60 61def cpu_for_target_arch(arch): 62 if arch in ['ia32', 'arm', 'armv6', 'armv5te', 'mips', 63 'simarm', 'simarmv6', 'simarmv5te', 'simmips', 'simdbc', 64 'armsimdbc']: 65 return 'x86' 66 if arch in ['x64', 'arm64', 'simarm64', 'simdbc64', 'armsimdbc64']: 67 return 'x64' 68 69def to_gn_args(args): 70 if args.simulator: 71 if args.target_os == 'android': 72 raise Exception('--simulator is not supported on Android') 73 elif args.target_os == 'ios': 74 if args.runtime_mode != 'debug': 75 raise Exception('iOS simulator only supports the debug runtime mode') 76 77 if args.target_os != 'android' and args.enable_vulkan: 78 raise Exception('--enable-vulkan is only supported on Android') 79 80 if args.target_os != 'ios' and args.enable_metal: 81 raise Exception('--enable-metal is only supported on iOS') 82 83 runtime_mode = args.runtime_mode 84 if args.dynamic and runtime_mode in ['profile', 'release']: 85 runtime_mode = 'dynamic_' + runtime_mode 86 87 gn_args = {} 88 89 if args.bitcode: 90 if args.target_os != 'ios': 91 raise Exception('Bitcode is only supported for iOS') 92 93 gn_args['enable_bitcode'] = args.bitcode 94 95 # Skia GN args. 96 gn_args['skia_enable_flutter_defines'] = True # Enable Flutter API guards in Skia. 97 gn_args['skia_use_dng_sdk'] = False # RAW image handling. 98 gn_args['skia_use_sfntly'] = False # PDF handling dependency. 99 gn_args['skia_enable_pdf'] = False # PDF handling. 100 gn_args['skia_use_x11'] = False # Never add the X11 dependency (only takes effect on Linux). 101 gn_args['skia_use_wuffs'] = True 102 gn_args['skia_use_expat'] = args.target_os == 'android' 103 gn_args['skia_use_fontconfig'] = args.enable_fontconfig 104 gn_args['flutter_use_fontconfig'] = args.enable_fontconfig 105 gn_args['flutter_enable_skshaper'] = args.enable_skshaper 106 gn_args['is_official_build'] = True # Disable Skia test utilities. 107 gn_args['dart_component_kind'] = 'static_library' # Always link Dart in statically. 108 gn_args['is_debug'] = args.unoptimized 109 gn_args['android_full_debug'] = args.target_os == 'android' and args.unoptimized 110 gn_args['is_clang'] = not sys.platform.startswith(('cygwin', 'win')) 111 112 if args.target_os == 'android' or args.target_os == 'ios': 113 gn_args['skia_gl_standard'] = 'gles' 114 else: 115 # We explicitly don't want to pick GL because we run GLES tests using SwiftShader. 116 gn_args['skia_gl_standard'] = '' 117 118 if not sys.platform.startswith(('cygwin', 'win')): 119 gn_args['use_clang_static_analyzer'] = args.clang_static_analyzer 120 121 gn_args['embedder_for_target'] = args.embedder_for_target 122 123 gn_args['enable_coverage'] = args.coverage 124 125 if args.operator_new_alignment is not None: 126 gn_args['operator_new_alignment'] = args.operator_new_alignment 127 128 enable_lto = args.lto 129 if args.unoptimized: 130 # There is no point in enabling LTO in unoptimized builds. 131 enable_lto = False 132 133 if not sys.platform.startswith('win'): 134 # The GN arg is not available in the windows toolchain. 135 gn_args['enable_lto'] = enable_lto 136 137 if args.target_os == 'android': 138 gn_args['target_os'] = 'android' 139 elif args.target_os == 'ios': 140 gn_args['target_os'] = 'ios' 141 gn_args['use_ios_simulator'] = args.simulator 142 elif args.target_os is not None: 143 gn_args['target_os'] = args.target_os 144 145 gn_args['dart_lib_export_symbols'] = False 146 147 if runtime_mode == 'debug': 148 gn_args['dart_runtime_mode'] = 'develop' 149 elif runtime_mode == 'dynamic_profile': 150 gn_args['dart_runtime_mode'] = 'profile' 151 elif runtime_mode == 'dynamic_release': 152 gn_args['dart_runtime_mode'] = 'release' 153 else: 154 gn_args['dart_runtime_mode'] = runtime_mode 155 156 if args.dart_debug: 157 gn_args['dart_debug'] = True 158 159 if args.full_dart_debug: 160 gn_args['dart_debug'] = True 161 gn_args['dart_debug_optimization_level'] = '0' 162 163 if args.target_os == 'android': 164 gn_args['target_cpu'] = args.android_cpu 165 elif args.target_os == 'ios': 166 if args.simulator: 167 gn_args['target_cpu'] = 'x64' 168 else: 169 gn_args['target_cpu'] = args.ios_cpu 170 elif args.target_os == 'linux': 171 gn_args['target_cpu'] = args.linux_cpu 172 elif args.target_os == 'fuchsia': 173 gn_args['target_cpu'] = args.fuchsia_cpu 174 else: 175 # Building host artifacts 176 gn_args['target_cpu'] = 'x64' 177 178 # DBC is not supported anymore. 179 if args.interpreter: 180 raise Exception('--interpreter is no longer needed on any supported platform.') 181 gn_args['dart_target_arch'] = gn_args['target_cpu'] 182 183 if sys.platform.startswith(('cygwin', 'win')): 184 if 'target_cpu' in gn_args: 185 gn_args['target_cpu'] = cpu_for_target_arch(gn_args['target_cpu']) 186 187 if args.target_os is None: 188 if sys.platform.startswith(('cygwin', 'win')): 189 gn_args['dart_use_fallback_root_certificates'] = True 190 191 192 gn_args['dart_custom_version_for_pub'] = 'flutter' 193 194 # Make sure host_cpu matches the bit width of target_cpu on x86. 195 if gn_args['target_cpu'] == 'x86': 196 gn_args['host_cpu'] = 'x86' 197 198 gn_args['flutter_runtime_mode'] = runtime_mode 199 200 if args.target_sysroot: 201 gn_args['target_sysroot'] = args.target_sysroot 202 gn_args['custom_sysroot'] = args.target_sysroot 203 204 if args.target_toolchain: 205 gn_args['custom_toolchain'] = args.target_toolchain 206 207 if args.target_triple: 208 gn_args['custom_target_triple'] = args.target_triple 209 210 if args.toolchain_prefix: 211 gn_args['toolchain_prefix'] = args.toolchain_prefix 212 213 goma_dir = os.environ.get('GOMA_DIR') 214 goma_home_dir = os.path.join(os.getenv('HOME', ''), 'goma') 215 216 # GOMA has a different default (home) path on gWindows. 217 if not os.path.exists(goma_home_dir) and sys.platform.startswith(('cygwin', 'win')): 218 goma_home_dir = os.path.join('c:\\', 'src', 'goma', 'goma-win64') 219 220 if args.goma and goma_dir: 221 gn_args['use_goma'] = True 222 gn_args['goma_dir'] = goma_dir 223 elif args.goma and os.path.exists(goma_home_dir): 224 gn_args['use_goma'] = True 225 gn_args['goma_dir'] = goma_home_dir 226 else: 227 gn_args['use_goma'] = False 228 gn_args['goma_dir'] = None 229 230 if args.enable_metal: 231 gn_args['skia_use_metal'] = True 232 gn_args['shell_enable_metal'] = True 233 gn_args['ios_deployment_target'] = '11' 234 gn_args['allow_deprecated_api_calls'] = True 235 236 if args.enable_vulkan: 237 # Enable vulkan in the Flutter shell. 238 gn_args['shell_enable_vulkan'] = True 239 # Configure Skia for Vulkan support. 240 gn_args['skia_use_vulkan'] = True 241 242 # The buildroot currently isn't set up to support Vulkan in the 243 # Windows ANGLE build, so disable it regardless of enable_vulkan's value. 244 if sys.platform.startswith(('cygwin', 'win')): 245 gn_args['angle_enable_vulkan'] = False 246 247 # We should not need a special case for x86, but this seems to introduce text relocations 248 # even with -fPIC everywhere. 249 # gn_args['enable_profiling'] = args.runtime_mode != 'release' and args.android_cpu != 'x86' 250 251 if args.arm_float_abi: 252 gn_args['arm_float_abi'] = args.arm_float_abi 253 254 # Whether to build trained Dart SDK snapshots of dart2js and dartdevc, 255 # including the web sdk kernel and source files. 256 if args.target_os is None: 257 # dart_platform_sdk is not declared for Android targets. 258 gn_args['dart_platform_sdk'] = not args.full_dart_sdk 259 gn_args['full_dart_sdk'] = args.full_dart_sdk 260 261 if sys.platform == 'darwin': 262 if args.build_glfw_shell: 263 gn_args['build_glfw_shell'] = True 264 265 return gn_args 266 267def parse_args(args): 268 args = args[1:] 269 parser = argparse.ArgumentParser(description='A script run` gn gen`.') 270 271 parser.add_argument('--unoptimized', default=False, action='store_true') 272 273 parser.add_argument('--runtime-mode', type=str, choices=['debug', 'profile', 'release'], default='debug') 274 parser.add_argument('--dynamic', default=False, action='store_true') 275 parser.add_argument('--interpreter', default=False, action='store_true') 276 parser.add_argument('--dart-debug', default=False, action='store_true', help='Enables assertsion in the Dart VM. ' + 277 'Does not affect optimization levels. If you need to disable optimizations in Dart, use --full-dart-debug') 278 parser.add_argument('--full-dart-debug', default=False, action='store_true', help='Implies --dart-debug ' + 279 'and also disables optimizations in the Dart VM making it easier to step through VM code in the debugger.') 280 281 parser.add_argument('--target-os', type=str, choices=['android', 'ios', 'linux', 'fuchsia']) 282 parser.add_argument('--android', dest='target_os', action='store_const', const='android') 283 parser.add_argument('--android-cpu', type=str, choices=['arm', 'x64', 'x86', 'arm64'], default='arm') 284 parser.add_argument('--ios', dest='target_os', action='store_const', const='ios') 285 parser.add_argument('--ios-cpu', type=str, choices=['arm', 'arm64'], default='arm64') 286 parser.add_argument('--simulator', action='store_true', default=False) 287 parser.add_argument('--fuchsia', dest='target_os', action='store_const', const='fuchsia') 288 parser.add_argument('--linux-cpu', type=str, choices=['x64', 'x86', 'arm64', 'arm']) 289 parser.add_argument('--fuchsia-cpu', type=str, choices=['x64', 'arm64'], default = 'x64') 290 parser.add_argument('--arm-float-abi', type=str, choices=['hard', 'soft', 'softfp']) 291 292 parser.add_argument('--goma', default=True, action='store_true') 293 parser.add_argument('--no-goma', dest='goma', action='store_false') 294 295 parser.add_argument('--lto', default=True, action='store_true') 296 parser.add_argument('--no-lto', dest='lto', action='store_false') 297 298 parser.add_argument('--clang', default=True, action='store_true') 299 parser.add_argument('--no-clang', dest='clang', action='store_false') 300 301 parser.add_argument('--clang-static-analyzer', default=False, action='store_true') 302 parser.add_argument('--no-clang-static-analyzer', dest='clang_static_analyzer', action='store_false') 303 304 parser.add_argument('--target-sysroot', type=str) 305 parser.add_argument('--target-toolchain', type=str) 306 parser.add_argument('--target-triple', type=str) 307 parser.add_argument('--toolchain-prefix', type=str) 308 parser.add_argument('--operator-new-alignment', dest='operator_new_alignment', type=str, default=None) 309 310 parser.add_argument('--enable-vulkan', action='store_true', default=False) 311 parser.add_argument('--enable-metal', action='store_true', default=False) 312 313 parser.add_argument('--enable-fontconfig', action='store_true', default=False) 314 parser.add_argument('--enable-skshaper', action='store_true', default=False) 315 316 parser.add_argument('--embedder-for-target', dest='embedder_for_target', action='store_true', default=False) 317 318 parser.add_argument('--coverage', default=False, action='store_true') 319 320 parser.add_argument('--out-dir', default='', type=str) 321 322 parser.add_argument('--full-dart-sdk', default=False, action='store_true', 323 help='include trained dart2js and dartdevc snapshots. Enable only on steps that create an SDK') 324 parser.add_argument('--no-full-dart-sdk', dest='full_dart_sdk', action='store_false') 325 326 parser.add_argument('--ide', default='', type=str, 327 help='The IDE files to generate using GN. Use `gn gen help` and look for the --ide flag to' + 328 ' see supported IDEs. If this flag is not specified, a platform specific default is selected.') 329 330 parser.add_argument('--build-glfw-shell', dest='build_glfw_shell', default=False, action='store_true', 331 help='Force building the GLFW shell on desktop platforms where it is not built by default.') 332 333 parser.add_argument('--bitcode', default=False, action='store_true', 334 help='Enable bitcode for iOS targets.') 335 336 return parser.parse_args(args) 337 338def main(argv): 339 args = parse_args(argv) 340 341 exe = '.exe' if sys.platform.startswith(('cygwin', 'win')) else '' 342 343 command = [ 344 '%s/flutter/third_party/gn/gn%s' % (SRC_ROOT, exe), 345 'gen', 346 '--check', 347 ] 348 349 if args.ide != '': 350 command.append('--ide=%s' % args.ide) 351 elif sys.platform == 'darwin': 352 # On the Mac, generate an Xcode project by default. 353 command.append('--ide=xcode') 354 elif sys.platform.startswith('win'): 355 # On Windows, generate a Visual Studio project. 356 command.append('--ide=vs') 357 358 gn_args = to_command_line(to_gn_args(args)) 359 out_dir = get_out_dir(args) 360 command.append(out_dir) 361 command.append('--args=%s' % ' '.join(gn_args)) 362 print "Generating GN files in: %s" % out_dir 363 try: 364 gn_call_result = subprocess.call(command, cwd=SRC_ROOT) 365 except subprocess.CalledProcessError as exc: 366 print "Failed to generate gn files: ", exc.returncode, exc.output 367 sys.exit(1) 368 369 if gn_call_result == 0: 370 # Generate/Replace the compile commands database in out. 371 compile_cmd_gen_cmd = [ 372 'ninja', 373 '-C', 374 out_dir, 375 '-t', 376 'compdb', 377 'cc', 378 'cxx', 379 'objc', 380 'objcxx', 381 'asm', 382 ] 383 384 try: 385 contents = subprocess.check_output(compile_cmd_gen_cmd, cwd=SRC_ROOT) 386 except subprocess.CalledProcessError as exc: 387 print "Failed to run ninja: ", exc.returncode, exc.output 388 sys.exit(1) 389 compile_commands = open('%s/out/compile_commands.json' % SRC_ROOT, 'w+') 390 compile_commands.write(contents) 391 compile_commands.close() 392 393 return gn_call_result 394 395if __name__ == '__main__': 396 sys.exit(main(sys.argv)) 397