1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*6777b538SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Worker"""usage: rc.py [options] input.res 7*6777b538SAndroid Build Coastguard WorkerA resource compiler for .rc files. 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard Workeroptions: 10*6777b538SAndroid Build Coastguard Worker-h, --help Print this message. 11*6777b538SAndroid Build Coastguard Worker-I<dir> Add include path, used for both headers and resources. 12*6777b538SAndroid Build Coastguard Worker-imsvc<dir> Add system include path, used for preprocessing only. 13*6777b538SAndroid Build Coastguard Worker/winsysroot<d> Set winsysroot, used for preprocessing only. 14*6777b538SAndroid Build Coastguard Worker-D<sym> Define a macro for the preprocessor. 15*6777b538SAndroid Build Coastguard Worker/fo<out> Set path of output .res file. 16*6777b538SAndroid Build Coastguard Worker/nologo Ignored (rc.py doesn't print a logo by default). 17*6777b538SAndroid Build Coastguard Worker/showIncludes Print referenced header and resource files.""" 18*6777b538SAndroid Build Coastguard Worker 19*6777b538SAndroid Build Coastguard Workerfrom collections import namedtuple 20*6777b538SAndroid Build Coastguard Workerimport codecs 21*6777b538SAndroid Build Coastguard Workerimport os 22*6777b538SAndroid Build Coastguard Workerimport re 23*6777b538SAndroid Build Coastguard Workerimport subprocess 24*6777b538SAndroid Build Coastguard Workerimport sys 25*6777b538SAndroid Build Coastguard Workerimport tempfile 26*6777b538SAndroid Build Coastguard Worker 27*6777b538SAndroid Build Coastguard Worker 28*6777b538SAndroid Build Coastguard WorkerTHIS_DIR = os.path.abspath(os.path.dirname(__file__)) 29*6777b538SAndroid Build Coastguard WorkerSRC_DIR = \ 30*6777b538SAndroid Build Coastguard Worker os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(THIS_DIR)))) 31*6777b538SAndroid Build Coastguard Worker 32*6777b538SAndroid Build Coastguard Worker 33*6777b538SAndroid Build Coastguard Workerdef ParseFlags(): 34*6777b538SAndroid Build Coastguard Worker """Parses flags off sys.argv and returns the parsed flags.""" 35*6777b538SAndroid Build Coastguard Worker # Can't use optparse / argparse because of /fo flag :-/ 36*6777b538SAndroid Build Coastguard Worker includes = [] 37*6777b538SAndroid Build Coastguard Worker imsvcs = [] 38*6777b538SAndroid Build Coastguard Worker winsysroot = [] 39*6777b538SAndroid Build Coastguard Worker defines = [] 40*6777b538SAndroid Build Coastguard Worker output = None 41*6777b538SAndroid Build Coastguard Worker input = None 42*6777b538SAndroid Build Coastguard Worker show_includes = False 43*6777b538SAndroid Build Coastguard Worker # Parse. 44*6777b538SAndroid Build Coastguard Worker for flag in sys.argv[1:]: 45*6777b538SAndroid Build Coastguard Worker if flag == '-h' or flag == '--help': 46*6777b538SAndroid Build Coastguard Worker print(__doc__) 47*6777b538SAndroid Build Coastguard Worker sys.exit(0) 48*6777b538SAndroid Build Coastguard Worker if flag.startswith('-I'): 49*6777b538SAndroid Build Coastguard Worker includes.append(flag) 50*6777b538SAndroid Build Coastguard Worker elif flag.startswith('-imsvc'): 51*6777b538SAndroid Build Coastguard Worker imsvcs.append(flag) 52*6777b538SAndroid Build Coastguard Worker elif flag.startswith('/winsysroot'): 53*6777b538SAndroid Build Coastguard Worker winsysroot = [flag] 54*6777b538SAndroid Build Coastguard Worker elif flag.startswith('-D'): 55*6777b538SAndroid Build Coastguard Worker defines.append(flag) 56*6777b538SAndroid Build Coastguard Worker elif flag.startswith('/fo'): 57*6777b538SAndroid Build Coastguard Worker if output: 58*6777b538SAndroid Build Coastguard Worker print('rc.py: error: multiple /fo flags', '/fo' + output, flag, 59*6777b538SAndroid Build Coastguard Worker file=sys.stderr) 60*6777b538SAndroid Build Coastguard Worker sys.exit(1) 61*6777b538SAndroid Build Coastguard Worker output = flag[3:] 62*6777b538SAndroid Build Coastguard Worker elif flag == '/nologo': 63*6777b538SAndroid Build Coastguard Worker pass 64*6777b538SAndroid Build Coastguard Worker elif flag == '/showIncludes': 65*6777b538SAndroid Build Coastguard Worker show_includes = True 66*6777b538SAndroid Build Coastguard Worker elif (flag.startswith('-') or 67*6777b538SAndroid Build Coastguard Worker (flag.startswith('/') and not os.path.exists(flag))): 68*6777b538SAndroid Build Coastguard Worker print('rc.py: error: unknown flag', flag, file=sys.stderr) 69*6777b538SAndroid Build Coastguard Worker print(__doc__, file=sys.stderr) 70*6777b538SAndroid Build Coastguard Worker sys.exit(1) 71*6777b538SAndroid Build Coastguard Worker else: 72*6777b538SAndroid Build Coastguard Worker if input: 73*6777b538SAndroid Build Coastguard Worker print('rc.py: error: multiple inputs:', input, flag, file=sys.stderr) 74*6777b538SAndroid Build Coastguard Worker sys.exit(1) 75*6777b538SAndroid Build Coastguard Worker input = flag 76*6777b538SAndroid Build Coastguard Worker # Validate and set default values. 77*6777b538SAndroid Build Coastguard Worker if not input: 78*6777b538SAndroid Build Coastguard Worker print('rc.py: error: no input file', file=sys.stderr) 79*6777b538SAndroid Build Coastguard Worker sys.exit(1) 80*6777b538SAndroid Build Coastguard Worker if not output: 81*6777b538SAndroid Build Coastguard Worker output = os.path.splitext(input)[0] + '.res' 82*6777b538SAndroid Build Coastguard Worker Flags = namedtuple('Flags', [ 83*6777b538SAndroid Build Coastguard Worker 'includes', 'defines', 'output', 'imsvcs', 'winsysroot', 'input', 84*6777b538SAndroid Build Coastguard Worker 'show_includes' 85*6777b538SAndroid Build Coastguard Worker ]) 86*6777b538SAndroid Build Coastguard Worker return Flags(includes=includes, 87*6777b538SAndroid Build Coastguard Worker defines=defines, 88*6777b538SAndroid Build Coastguard Worker output=output, 89*6777b538SAndroid Build Coastguard Worker imsvcs=imsvcs, 90*6777b538SAndroid Build Coastguard Worker winsysroot=winsysroot, 91*6777b538SAndroid Build Coastguard Worker input=input, 92*6777b538SAndroid Build Coastguard Worker show_includes=show_includes) 93*6777b538SAndroid Build Coastguard Worker 94*6777b538SAndroid Build Coastguard Worker 95*6777b538SAndroid Build Coastguard Workerdef ReadInput(input): 96*6777b538SAndroid Build Coastguard Worker """"Reads input and returns it. For UTF-16LEBOM input, converts to UTF-8.""" 97*6777b538SAndroid Build Coastguard Worker # Microsoft's rc.exe only supports unicode in the form of UTF-16LE with a BOM. 98*6777b538SAndroid Build Coastguard Worker # Our rc binary sniffs for UTF-16LE. If that's not found, if /utf-8 is 99*6777b538SAndroid Build Coastguard Worker # passed, the input is treated as UTF-8. If /utf-8 is not passed and the 100*6777b538SAndroid Build Coastguard Worker # input is not UTF-16LE, then our rc errors out on characters outside of 101*6777b538SAndroid Build Coastguard Worker # 7-bit ASCII. Since the driver always converts UTF-16LE to UTF-8 here (for 102*6777b538SAndroid Build Coastguard Worker # the preprocessor, which doesn't support UTF-16LE), our rc will either see 103*6777b538SAndroid Build Coastguard Worker # UTF-8 with the /utf-8 flag (for UTF-16LE input), or ASCII input. 104*6777b538SAndroid Build Coastguard Worker # This is compatible with Microsoft rc.exe. If we wanted, we could expose 105*6777b538SAndroid Build Coastguard Worker # a /utf-8 flag for the driver for UTF-8 .rc inputs too. 106*6777b538SAndroid Build Coastguard Worker # TODO(thakis): Microsoft's rc.exe supports BOM-less UTF-16LE. We currently 107*6777b538SAndroid Build Coastguard Worker # don't, but for chrome it currently doesn't matter. 108*6777b538SAndroid Build Coastguard Worker is_utf8 = False 109*6777b538SAndroid Build Coastguard Worker try: 110*6777b538SAndroid Build Coastguard Worker with open(input, 'rb') as rc_file: 111*6777b538SAndroid Build Coastguard Worker rc_file_data = rc_file.read() 112*6777b538SAndroid Build Coastguard Worker if rc_file_data.startswith(codecs.BOM_UTF16_LE): 113*6777b538SAndroid Build Coastguard Worker rc_file_data = rc_file_data[2:].decode('utf-16le').encode('utf-8') 114*6777b538SAndroid Build Coastguard Worker is_utf8 = True 115*6777b538SAndroid Build Coastguard Worker except IOError: 116*6777b538SAndroid Build Coastguard Worker print('rc.py: failed to open', input, file=sys.stderr) 117*6777b538SAndroid Build Coastguard Worker sys.exit(1) 118*6777b538SAndroid Build Coastguard Worker except UnicodeDecodeError: 119*6777b538SAndroid Build Coastguard Worker print('rc.py: failed to decode UTF-16 despite BOM', input, file=sys.stderr) 120*6777b538SAndroid Build Coastguard Worker sys.exit(1) 121*6777b538SAndroid Build Coastguard Worker return rc_file_data, is_utf8 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Worker 124*6777b538SAndroid Build Coastguard Workerdef Preprocess(rc_file_data, flags): 125*6777b538SAndroid Build Coastguard Worker """Runs the input file through the preprocessor.""" 126*6777b538SAndroid Build Coastguard Worker clang = os.path.join(SRC_DIR, 'third_party', 'llvm-build', 127*6777b538SAndroid Build Coastguard Worker 'Release+Asserts', 'bin', 'clang-cl') 128*6777b538SAndroid Build Coastguard Worker # Let preprocessor write to a temp file so that it doesn't interfere 129*6777b538SAndroid Build Coastguard Worker # with /showIncludes output on stdout. 130*6777b538SAndroid Build Coastguard Worker if sys.platform == 'win32': 131*6777b538SAndroid Build Coastguard Worker clang += '.exe' 132*6777b538SAndroid Build Coastguard Worker temp_handle, temp_file = tempfile.mkstemp(suffix='.i') 133*6777b538SAndroid Build Coastguard Worker # Closing temp_handle immediately defeats the purpose of mkstemp(), but I 134*6777b538SAndroid Build Coastguard Worker # can't figure out how to let write to the temp file on Windows otherwise. 135*6777b538SAndroid Build Coastguard Worker os.close(temp_handle) 136*6777b538SAndroid Build Coastguard Worker clang_cmd = [clang, '/P', '/DRC_INVOKED', '/TC', '-', '/Fi' + temp_file] 137*6777b538SAndroid Build Coastguard Worker if flags.imsvcs: 138*6777b538SAndroid Build Coastguard Worker clang_cmd += ['/X'] 139*6777b538SAndroid Build Coastguard Worker if os.path.dirname(flags.input): 140*6777b538SAndroid Build Coastguard Worker # This must precede flags.includes. 141*6777b538SAndroid Build Coastguard Worker clang_cmd.append('-I' + os.path.dirname(flags.input)) 142*6777b538SAndroid Build Coastguard Worker if flags.show_includes: 143*6777b538SAndroid Build Coastguard Worker clang_cmd.append('/showIncludes') 144*6777b538SAndroid Build Coastguard Worker clang_cmd += flags.imsvcs + flags.winsysroot + flags.includes + flags.defines 145*6777b538SAndroid Build Coastguard Worker p = subprocess.Popen(clang_cmd, stdin=subprocess.PIPE) 146*6777b538SAndroid Build Coastguard Worker p.communicate(input=rc_file_data) 147*6777b538SAndroid Build Coastguard Worker if p.returncode != 0: 148*6777b538SAndroid Build Coastguard Worker sys.exit(p.returncode) 149*6777b538SAndroid Build Coastguard Worker preprocessed_output = open(temp_file, 'rb').read() 150*6777b538SAndroid Build Coastguard Worker os.remove(temp_file) 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker # rc.exe has a wacko preprocessor: 153*6777b538SAndroid Build Coastguard Worker # https://msdn.microsoft.com/en-us/library/windows/desktop/aa381033(v=vs.85).aspx 154*6777b538SAndroid Build Coastguard Worker # """RC treats files with the .c and .h extensions in a special manner. It 155*6777b538SAndroid Build Coastguard Worker # assumes that a file with one of these extensions does not contain 156*6777b538SAndroid Build Coastguard Worker # resources. If a file has the .c or .h file name extension, RC ignores all 157*6777b538SAndroid Build Coastguard Worker # lines in the file except the preprocessor directives.""" 158*6777b538SAndroid Build Coastguard Worker # Thankfully, the Microsoft headers are mostly good about putting everything 159*6777b538SAndroid Build Coastguard Worker # in the system headers behind `if !defined(RC_INVOKED)`, so regular 160*6777b538SAndroid Build Coastguard Worker # preprocessing with RC_INVOKED defined works. 161*6777b538SAndroid Build Coastguard Worker return preprocessed_output 162*6777b538SAndroid Build Coastguard Worker 163*6777b538SAndroid Build Coastguard Worker 164*6777b538SAndroid Build Coastguard Workerdef RunRc(preprocessed_output, is_utf8, flags): 165*6777b538SAndroid Build Coastguard Worker if sys.platform.startswith('linux'): 166*6777b538SAndroid Build Coastguard Worker rc = os.path.join(THIS_DIR, 'linux64', 'rc') 167*6777b538SAndroid Build Coastguard Worker elif sys.platform == 'darwin': 168*6777b538SAndroid Build Coastguard Worker rc = os.path.join(THIS_DIR, 'mac', 'rc') 169*6777b538SAndroid Build Coastguard Worker elif sys.platform == 'win32': 170*6777b538SAndroid Build Coastguard Worker rc = os.path.join(THIS_DIR, 'win', 'rc.exe') 171*6777b538SAndroid Build Coastguard Worker else: 172*6777b538SAndroid Build Coastguard Worker print('rc.py: error: unsupported platform', sys.platform, file=sys.stderr) 173*6777b538SAndroid Build Coastguard Worker sys.exit(1) 174*6777b538SAndroid Build Coastguard Worker rc_cmd = [rc] 175*6777b538SAndroid Build Coastguard Worker # Make sure rc-relative resources can be found: 176*6777b538SAndroid Build Coastguard Worker if os.path.dirname(flags.input): 177*6777b538SAndroid Build Coastguard Worker rc_cmd.append('/cd' + os.path.dirname(flags.input)) 178*6777b538SAndroid Build Coastguard Worker rc_cmd.append('/fo' + flags.output) 179*6777b538SAndroid Build Coastguard Worker if is_utf8: 180*6777b538SAndroid Build Coastguard Worker rc_cmd.append('/utf-8') 181*6777b538SAndroid Build Coastguard Worker # TODO(thakis): cl currently always prints full paths for /showIncludes, 182*6777b538SAndroid Build Coastguard Worker # but clang-cl /P doesn't. Which one is right? 183*6777b538SAndroid Build Coastguard Worker if flags.show_includes: 184*6777b538SAndroid Build Coastguard Worker rc_cmd.append('/showIncludes') 185*6777b538SAndroid Build Coastguard Worker # Microsoft rc.exe searches for referenced files relative to -I flags in 186*6777b538SAndroid Build Coastguard Worker # addition to the pwd, so -I flags need to be passed both to both 187*6777b538SAndroid Build Coastguard Worker # the preprocessor and rc. 188*6777b538SAndroid Build Coastguard Worker rc_cmd += flags.includes 189*6777b538SAndroid Build Coastguard Worker p = subprocess.Popen(rc_cmd, stdin=subprocess.PIPE) 190*6777b538SAndroid Build Coastguard Worker p.communicate(input=preprocessed_output) 191*6777b538SAndroid Build Coastguard Worker 192*6777b538SAndroid Build Coastguard Worker if flags.show_includes and p.returncode == 0: 193*6777b538SAndroid Build Coastguard Worker TOOL_DIR = os.path.dirname(os.path.relpath(THIS_DIR)).replace("\\", "/") 194*6777b538SAndroid Build Coastguard Worker # Since tool("rc") can't have deps, add deps on this script and on rc.py 195*6777b538SAndroid Build Coastguard Worker # and its deps here, so that rc edges become dirty if rc.py changes. 196*6777b538SAndroid Build Coastguard Worker print('Note: including file: {}/tool_wrapper.py'.format(TOOL_DIR)) 197*6777b538SAndroid Build Coastguard Worker print('Note: including file: {}/rc/rc.py'.format(TOOL_DIR)) 198*6777b538SAndroid Build Coastguard Worker print( 199*6777b538SAndroid Build Coastguard Worker 'Note: including file: {}/rc/linux64/rc.sha1'.format(TOOL_DIR)) 200*6777b538SAndroid Build Coastguard Worker print('Note: including file: {}/rc/mac/rc.sha1'.format(TOOL_DIR)) 201*6777b538SAndroid Build Coastguard Worker print( 202*6777b538SAndroid Build Coastguard Worker 'Note: including file: {}/rc/win/rc.exe.sha1'.format(TOOL_DIR)) 203*6777b538SAndroid Build Coastguard Worker 204*6777b538SAndroid Build Coastguard Worker return p.returncode 205*6777b538SAndroid Build Coastguard Worker 206*6777b538SAndroid Build Coastguard Worker 207*6777b538SAndroid Build Coastguard Workerdef CompareToMsRcOutput(preprocessed_output, is_utf8, flags): 208*6777b538SAndroid Build Coastguard Worker msrc_in = flags.output + '.preprocessed.rc' 209*6777b538SAndroid Build Coastguard Worker 210*6777b538SAndroid Build Coastguard Worker # Strip preprocessor line markers. 211*6777b538SAndroid Build Coastguard Worker preprocessed_output = re.sub(br'^#.*$', b'', preprocessed_output, flags=re.M) 212*6777b538SAndroid Build Coastguard Worker if is_utf8: 213*6777b538SAndroid Build Coastguard Worker preprocessed_output = preprocessed_output.decode('utf-8').encode('utf-16le') 214*6777b538SAndroid Build Coastguard Worker with open(msrc_in, 'wb') as f: 215*6777b538SAndroid Build Coastguard Worker f.write(preprocessed_output) 216*6777b538SAndroid Build Coastguard Worker 217*6777b538SAndroid Build Coastguard Worker msrc_out = flags.output + '_ms_rc' 218*6777b538SAndroid Build Coastguard Worker msrc_cmd = ['rc', '/nologo', '/x', '/fo' + msrc_out] 219*6777b538SAndroid Build Coastguard Worker 220*6777b538SAndroid Build Coastguard Worker # Make sure rc-relative resources can be found. rc.exe looks for external 221*6777b538SAndroid Build Coastguard Worker # resource files next to the file, but the preprocessed file isn't where the 222*6777b538SAndroid Build Coastguard Worker # input was. 223*6777b538SAndroid Build Coastguard Worker # Note that rc searches external resource files in the order of 224*6777b538SAndroid Build Coastguard Worker # 1. next to the input file 225*6777b538SAndroid Build Coastguard Worker # 2. relative to cwd 226*6777b538SAndroid Build Coastguard Worker # 3. next to -I directories 227*6777b538SAndroid Build Coastguard Worker # Changing the cwd means we'd have to rewrite all -I flags, so just add 228*6777b538SAndroid Build Coastguard Worker # the input file dir as -I flag. That technically gets the order of 1 and 2 229*6777b538SAndroid Build Coastguard Worker # wrong, but in Chromium's build the cwd is the gn out dir, and generated 230*6777b538SAndroid Build Coastguard Worker # files there are in obj/ and gen/, so this difference doesn't matter in 231*6777b538SAndroid Build Coastguard Worker # practice. 232*6777b538SAndroid Build Coastguard Worker if os.path.dirname(flags.input): 233*6777b538SAndroid Build Coastguard Worker msrc_cmd += [ '-I' + os.path.dirname(flags.input) ] 234*6777b538SAndroid Build Coastguard Worker 235*6777b538SAndroid Build Coastguard Worker # Microsoft rc.exe searches for referenced files relative to -I flags in 236*6777b538SAndroid Build Coastguard Worker # addition to the pwd, so -I flags need to be passed both to both 237*6777b538SAndroid Build Coastguard Worker # the preprocessor and rc. 238*6777b538SAndroid Build Coastguard Worker msrc_cmd += flags.includes 239*6777b538SAndroid Build Coastguard Worker 240*6777b538SAndroid Build Coastguard Worker # Input must come last. 241*6777b538SAndroid Build Coastguard Worker msrc_cmd += [ msrc_in ] 242*6777b538SAndroid Build Coastguard Worker 243*6777b538SAndroid Build Coastguard Worker rc_exe_exit_code = subprocess.call(msrc_cmd) 244*6777b538SAndroid Build Coastguard Worker # Assert Microsoft rc.exe and rc.py produced identical .res files. 245*6777b538SAndroid Build Coastguard Worker if rc_exe_exit_code == 0: 246*6777b538SAndroid Build Coastguard Worker import filecmp 247*6777b538SAndroid Build Coastguard Worker assert filecmp.cmp(msrc_out, flags.output) 248*6777b538SAndroid Build Coastguard Worker return rc_exe_exit_code 249*6777b538SAndroid Build Coastguard Worker 250*6777b538SAndroid Build Coastguard Worker 251*6777b538SAndroid Build Coastguard Workerdef main(): 252*6777b538SAndroid Build Coastguard Worker # This driver has to do these things: 253*6777b538SAndroid Build Coastguard Worker # 1. Parse flags. 254*6777b538SAndroid Build Coastguard Worker # 2. Convert the input from UTF-16LE to UTF-8 if needed. 255*6777b538SAndroid Build Coastguard Worker # 3. Pass the input through a preprocessor (and clean up the preprocessor's 256*6777b538SAndroid Build Coastguard Worker # output in minor ways). 257*6777b538SAndroid Build Coastguard Worker # 4. Call rc for the heavy lifting. 258*6777b538SAndroid Build Coastguard Worker flags = ParseFlags() 259*6777b538SAndroid Build Coastguard Worker rc_file_data, is_utf8 = ReadInput(flags.input) 260*6777b538SAndroid Build Coastguard Worker preprocessed_output = Preprocess(rc_file_data, flags) 261*6777b538SAndroid Build Coastguard Worker rc_exe_exit_code = RunRc(preprocessed_output, is_utf8, flags) 262*6777b538SAndroid Build Coastguard Worker 263*6777b538SAndroid Build Coastguard Worker # 5. On Windows, we also call Microsoft's rc.exe and check that we produced 264*6777b538SAndroid Build Coastguard Worker # the same output. 265*6777b538SAndroid Build Coastguard Worker # Since Microsoft's rc has a preprocessor that only accepts 32 characters 266*6777b538SAndroid Build Coastguard Worker # for macro names, feed the clang-preprocessed source into it instead 267*6777b538SAndroid Build Coastguard Worker # of using ms rc's preprocessor. 268*6777b538SAndroid Build Coastguard Worker if sys.platform == 'win32' and rc_exe_exit_code == 0: 269*6777b538SAndroid Build Coastguard Worker rc_exe_exit_code = CompareToMsRcOutput(preprocessed_output, is_utf8, flags) 270*6777b538SAndroid Build Coastguard Worker 271*6777b538SAndroid Build Coastguard Worker return rc_exe_exit_code 272*6777b538SAndroid Build Coastguard Worker 273*6777b538SAndroid Build Coastguard Worker 274*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 275*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 276