1#!/usr/bin/python 2# Copyright 2017 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""" 7Builds and packages ChromeWebView.framework. 8""" 9 10import argparse 11import os 12import shutil 13import sys 14 15def target_dir_name(build_config, target_device): 16 """Returns a default output directory name string. 17 18 Args: 19 build_config: A string describing the build configuration. Ex: 'Debug' 20 target_device: A string describing the target device. Ex: 'simulator' 21 """ 22 return '%s-%s' % (build_config, target_device) 23 24def build(build_config, target_device, extra_gn_options, extra_ninja_options): 25 """Generates and builds ChromeWebView.framework. 26 27 Args: 28 build_config: A string describing the build configuration. Ex: 'Debug' 29 target_device: A string describing the target device. Ex: 'simulator' 30 extra_gn_options: A list of strings of gn args (key=value items) to 31 be appended to the gn gen command. 32 extra_ninja_options: A string of gn options to be appended to the ninja 33 command. 34 35 Returns: 36 The return code of generating ninja if it is non-zero, else the return code 37 of the ninja build command. 38 """ 39 gn_args = [ 40 'target_os="ios"', 41 'enable_websockets=false', 42 'is_component_build=false', 43 'use_xcode_clang=false', 44 'disable_file_support=true', 45 'disable_ftp_support=true', 46 'disable_brotli_filter=true', 47 'ios_enable_code_signing=false', 48 'enable_dsyms=true', 49 ] 50 51 if target_device == 'iphoneos': 52 gn_args.extend([ 53 'target_cpu="arm64"', 54 'target_environment="device"', 55 ]) 56 else: 57 gn_args.extend([ 58 'target_cpu="x64"', 59 'target_environment="simulator"', 60 ]) 61 62 if build_config == 'Debug': 63 gn_args.append('is_debug=true') 64 else: 65 gn_args.extend([ 66 'is_debug=false', 67 'enable_stripping=true', 68 'is_official_build=true', 69 ]) 70 71 if extra_gn_options: 72 gn_args.extend(extra_gn_options) 73 74 build_dir = os.path.join("out", target_dir_name(build_config, target_device)) 75 gn_command = 'gn gen %s --args=\'%s\'' % (build_dir, ' '.join(gn_args)) 76 print gn_command 77 gn_result = os.system(gn_command) 78 if gn_result != 0: 79 return gn_result 80 81 ninja_options = '-C %s' % build_dir 82 if extra_ninja_options: 83 ninja_options += ' %s' % extra_ninja_options 84 ninja_command = ('ninja %s ios/web_view:ios_web_view_package' % 85 ninja_options) 86 print ninja_command 87 return os.system(ninja_command) 88 89def copy_build_products(build_config, target_device, out_dir, output_name): 90 """Copies the resulting framework and symbols to out_dir. 91 92 Args: 93 build_config: A string describing the build configuration. Ex: 'Debug' 94 target_device: A string describing the target device. Ex: 'simulator' 95 out_dir: A string to the path which all build products will be copied. 96 """ 97 target_dir = target_dir_name(build_config, target_device) 98 build_dir = os.path.join("out", target_dir) 99 package_dir = os.path.join(build_dir, 'ios_web_view') 100 101 # # Copy framework. 102 framework_name = '%s.framework' % output_name 103 framework_source = os.path.join(build_dir, framework_name) 104 framework_dest = os.path.join(out_dir, target_dir, framework_name) 105 print 'Copying %s to %s' % (framework_source, framework_dest) 106 shutil.copytree(framework_source, framework_dest) 107 108 # Copy symbols. 109 symbols_name = '%s.dSYM' % output_name 110 symbols_source = os.path.join(build_dir, symbols_name) 111 symbols_dest = os.path.join(out_dir, target_dir, symbols_name) 112 print 'Copying %s to %s' % (symbols_source, symbols_dest) 113 shutil.copytree(symbols_source, symbols_dest) 114 115def package_framework(build_config, 116 target_device, 117 out_dir, 118 output_name, 119 extra_gn_options, 120 extra_ninja_options): 121 """Builds ChromeWebView.framework and copies the result to out_dir. 122 123 Args: 124 build_config: A string describing the build configuration. Ex: 'Debug' 125 target_device: A string describing the target device. Ex: 'simulator' 126 out_dir: A string to the path which all build products will be copied. 127 extra_gn_options: A list of strings of gn args (key=value items) to 128 be appended to the gn gen command. 129 extra_ninja_options: A string of gn options to be appended to the ninja 130 command. 131 132 Returns: 133 The return code of the build if it fails or 0 if the build was successful. 134 """ 135 print '\nBuilding for %s (%s)' % (target_device, build_config) 136 137 build_result = build(build_config, 138 target_device, 139 extra_gn_options, 140 extra_ninja_options) 141 if build_result != 0: 142 error = 'Building %s/%s failed with code: ' % (build_config, target_device) 143 print >>sys.stderr, error, build_result 144 return build_result 145 copy_build_products(build_config, target_device, out_dir, output_name) 146 return 0 147 148def package_all_frameworks(out_dir, output_name, extra_gn_options, 149 build_configs, target_devices, extra_ninja_options): 150 """Builds ChromeWebView.framework. 151 152 Builds Release and Debug versions of ChromeWebView.framework for both 153 iOS devices and simulator and copies the resulting frameworks into out_dir. 154 155 Args: 156 out_dir: A string to the path which all build products will be copied. 157 extra_gn_options: A list of strings of gn args (key=value items) to 158 be appended to the gn gen command. 159 build_configs: A list of configs to build. 160 target_devices: A list of devices to target. 161 extra_ninja_options: A string of gn options to be appended to the ninja 162 command. 163 164 Returns: 165 0 if all builds are successful or 1 if any build fails. 166 """ 167 print 'Building ChromeWebView.framework...' 168 169 # Package all builds in the output directory 170 os.makedirs(out_dir) 171 172 configs_and_devices = [(a,b) for a in build_configs for b in target_devices] 173 for build_config, target_device in configs_and_devices: 174 if package_framework(build_config, 175 target_device, 176 out_dir, 177 output_name, 178 extra_gn_options, 179 extra_ninja_options) != 0: 180 return 1 181 182 # Copy common files from last built package to out_dir. 183 build_dir = os.path.join('out', target_dir_name('Release', 'iphoneos')) 184 package_dir = os.path.join(build_dir, 'ios_web_view') 185 shutil.copy2(os.path.join(package_dir, 'AUTHORS'), out_dir) 186 shutil.copy2(os.path.join(package_dir, 'LICENSE'), out_dir) 187 shutil.copy2(os.path.join(package_dir, 'VERSION'), out_dir) 188 189 print '\nSuccess! ChromeWebView.framework is packaged into %s' % out_dir 190 191 return 0 192 193def main(): 194 description = 'Build and package //ios/web_view.' 195 parser = argparse.ArgumentParser(description=description) 196 197 parser.add_argument('out_dir', nargs='?', default='out/IOSWebViewBuild', 198 help='path to output directory') 199 parser.add_argument('--no_goma', action='store_true', 200 help='Prevents adding use_goma=true to the gn args.') 201 parser.add_argument('--ninja_args', 202 help='Additional gn args to pass through to ninja.') 203 parser.add_argument('--include_cronet', action='store_true', 204 help='Combines Cronet and ChromeWebView as 1 framework.') 205 build_configs = ['Debug', 'Release'] 206 target_devices = ['iphonesimulator', 'iphoneos'] 207 parser.add_argument('--build_configs', nargs='+', default=build_configs, 208 choices=build_configs, 209 help='Specify which configs to build.') 210 parser.add_argument('--target_devices', nargs='+', default=target_devices, 211 choices=target_devices, 212 help='Specify which devices to target.') 213 214 options, extra_options = parser.parse_known_args() 215 print 'Options:', options 216 217 if len(extra_options): 218 print >>sys.stderr, 'Unknown options: ', extra_options 219 return 1 220 221 out_dir = options.out_dir 222 # Make sure that the output directory does not exist 223 if os.path.exists(out_dir): 224 print >>sys.stderr, 'The output directory already exists: ' + out_dir 225 return 1 226 227 output_name = 'ChromeWebView' 228 extra_gn_options = [] 229 if not options.no_goma: 230 extra_gn_options.append('use_goma=true') 231 if options.include_cronet: 232 extra_gn_options.append('ios_web_view_include_cronet=true') 233 output_name = 'CronetChromeWebView' 234 else: 235 extra_gn_options.append('ios_web_view_include_cronet=false') 236 extra_gn_options.append('ios_web_view_output_name="%s"' % output_name) 237 # This prevents Breakpad from being included in the final binary to avoid 238 # duplicate symbols with the client app. 239 extra_gn_options.append('use_crash_key_stubs=true') 240 241 return package_all_frameworks(out_dir, output_name, extra_gn_options, 242 set(options.build_configs), 243 set(options.target_devices), 244 options.ninja_args) 245 246if __name__ == '__main__': 247 sys.exit(main()) 248