1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2017 The Chromium Authors 2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 4*8975f5c5SAndroid Build Coastguard Worker 5*8975f5c5SAndroid Build Coastguard Workerfrom __future__ import division 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Workerimport array 8*8975f5c5SAndroid Build Coastguard Workerimport difflib 9*8975f5c5SAndroid Build Coastguard Workerimport filecmp 10*8975f5c5SAndroid Build Coastguard Workerimport io 11*8975f5c5SAndroid Build Coastguard Workerimport operator 12*8975f5c5SAndroid Build Coastguard Workerimport os 13*8975f5c5SAndroid Build Coastguard Workerimport posixpath 14*8975f5c5SAndroid Build Coastguard Workerimport re 15*8975f5c5SAndroid Build Coastguard Workerimport shutil 16*8975f5c5SAndroid Build Coastguard Workerimport struct 17*8975f5c5SAndroid Build Coastguard Workerimport subprocess 18*8975f5c5SAndroid Build Coastguard Workerimport sys 19*8975f5c5SAndroid Build Coastguard Workerimport tempfile 20*8975f5c5SAndroid Build Coastguard Workerimport uuid 21*8975f5c5SAndroid Build Coastguard Worker 22*8975f5c5SAndroid Build Coastguard Workerfrom functools import reduce 23*8975f5c5SAndroid Build Coastguard Worker 24*8975f5c5SAndroid Build Coastguard Worker 25*8975f5c5SAndroid Build Coastguard Workerdef ZapTimestamp(filename): 26*8975f5c5SAndroid Build Coastguard Worker contents = open(filename, 'rb').read() 27*8975f5c5SAndroid Build Coastguard Worker # midl.exe writes timestamp 2147483647 (2^31 - 1) as creation date into its 28*8975f5c5SAndroid Build Coastguard Worker # outputs, but using the local timezone. To make the output timezone- 29*8975f5c5SAndroid Build Coastguard Worker # independent, replace that date with a fixed string of the same length. 30*8975f5c5SAndroid Build Coastguard Worker # Also blank out the minor version number. 31*8975f5c5SAndroid Build Coastguard Worker if filename.endswith('.tlb'): 32*8975f5c5SAndroid Build Coastguard Worker # See https://chromium-review.googlesource.com/c/chromium/src/+/693223 for 33*8975f5c5SAndroid Build Coastguard Worker # a fairly complete description of the .tlb binary format. 34*8975f5c5SAndroid Build Coastguard Worker # TLB files start with a 54 byte header. Offset 0x20 stores how many types 35*8975f5c5SAndroid Build Coastguard Worker # are defined in the file, and the header is followed by that many uint32s. 36*8975f5c5SAndroid Build Coastguard Worker # After that, 15 section headers appear. Each section header is 16 bytes, 37*8975f5c5SAndroid Build Coastguard Worker # starting with offset and length uint32s. 38*8975f5c5SAndroid Build Coastguard Worker # Section 12 in the file contains custom() data. custom() data has a type 39*8975f5c5SAndroid Build Coastguard Worker # (int, string, etc). Each custom data chunk starts with a uint16_t 40*8975f5c5SAndroid Build Coastguard Worker # describing its type. Type 8 is string data, consisting of a uint32_t 41*8975f5c5SAndroid Build Coastguard Worker # len, followed by that many data bytes, followed by 'W' bytes to pad to a 42*8975f5c5SAndroid Build Coastguard Worker # 4 byte boundary. Type 0x13 is uint32 data, followed by 4 data bytes, 43*8975f5c5SAndroid Build Coastguard Worker # followed by two 'W' to pad to a 4 byte boundary. 44*8975f5c5SAndroid Build Coastguard Worker # The custom block always starts with one string containing "Created by 45*8975f5c5SAndroid Build Coastguard Worker # MIDL version 8...", followed by one uint32 containing 0x7fffffff, 46*8975f5c5SAndroid Build Coastguard Worker # followed by another uint32 containing the MIDL compiler version (e.g. 47*8975f5c5SAndroid Build Coastguard Worker # 0x0801026e for v8.1.622 -- 0x26e == 622). These 3 fields take 0x54 bytes. 48*8975f5c5SAndroid Build Coastguard Worker # There might be more custom data after that, but these 3 blocks are always 49*8975f5c5SAndroid Build Coastguard Worker # there for file-level metadata. 50*8975f5c5SAndroid Build Coastguard Worker # All data is little-endian in the file. 51*8975f5c5SAndroid Build Coastguard Worker assert contents[0:8] == b'MSFT\x02\x00\x01\x00' 52*8975f5c5SAndroid Build Coastguard Worker ntypes, = struct.unpack_from('<I', contents, 0x20) 53*8975f5c5SAndroid Build Coastguard Worker custom_off, custom_len = struct.unpack_from( 54*8975f5c5SAndroid Build Coastguard Worker '<II', contents, 0x54 + 4*ntypes + 11*16) 55*8975f5c5SAndroid Build Coastguard Worker assert custom_len >= 0x54 56*8975f5c5SAndroid Build Coastguard Worker # First: Type string (0x8), followed by 0x3e characters. 57*8975f5c5SAndroid Build Coastguard Worker assert contents[custom_off:custom_off + 6] == b'\x08\x00\x3e\x00\x00\x00' 58*8975f5c5SAndroid Build Coastguard Worker assert re.match( 59*8975f5c5SAndroid Build Coastguard Worker br'Created by MIDL version 8\.\d\d\.\d{4} ' 60*8975f5c5SAndroid Build Coastguard Worker br'at ... Jan 1. ..:..:.. 2038\n', 61*8975f5c5SAndroid Build Coastguard Worker contents[custom_off + 6:custom_off + 6 + 0x3e]) 62*8975f5c5SAndroid Build Coastguard Worker # Second: Type uint32 (0x13) storing 0x7fffffff (followed by WW / 0x57 pad) 63*8975f5c5SAndroid Build Coastguard Worker assert contents[custom_off+6+0x3e:custom_off+6+0x3e+8] == \ 64*8975f5c5SAndroid Build Coastguard Worker b'\x13\x00\xff\xff\xff\x7f\x57\x57' 65*8975f5c5SAndroid Build Coastguard Worker # Third: Type uint32 (0x13) storing MIDL compiler version. 66*8975f5c5SAndroid Build Coastguard Worker assert contents[custom_off + 6 + 0x3e + 8:custom_off + 6 + 0x3e + 8 + 67*8975f5c5SAndroid Build Coastguard Worker 2] == b'\x13\x00' 68*8975f5c5SAndroid Build Coastguard Worker # Replace "Created by" string with fixed string, and fixed MIDL version with 69*8975f5c5SAndroid Build Coastguard Worker # 8.1.622 always. 70*8975f5c5SAndroid Build Coastguard Worker contents = ( 71*8975f5c5SAndroid Build Coastguard Worker contents[0:custom_off + 6] + 72*8975f5c5SAndroid Build Coastguard Worker b'Created by MIDL version 8.xx.xxxx at a redacted point in time\n' + 73*8975f5c5SAndroid Build Coastguard Worker # uint32 (0x13) val 0x7fffffff, WW, uint32 (0x13), val 0x0801026e, WW 74*8975f5c5SAndroid Build Coastguard Worker b'\x13\x00\xff\xff\xff\x7f\x57\x57\x13\x00\x6e\x02\x01\x08\x57\x57' + 75*8975f5c5SAndroid Build Coastguard Worker contents[custom_off + 0x54:]) 76*8975f5c5SAndroid Build Coastguard Worker else: 77*8975f5c5SAndroid Build Coastguard Worker contents = re.sub( 78*8975f5c5SAndroid Build Coastguard Worker br'File created by MIDL compiler version 8\.\d\d\.\d{4} \*/\r\n' 79*8975f5c5SAndroid Build Coastguard Worker br'/\* at ... Jan 1. ..:..:.. 2038', 80*8975f5c5SAndroid Build Coastguard Worker br'File created by MIDL compiler version 8.xx.xxxx */\r\n' 81*8975f5c5SAndroid Build Coastguard Worker br'/* at a redacted point in time', contents) 82*8975f5c5SAndroid Build Coastguard Worker contents = re.sub( 83*8975f5c5SAndroid Build Coastguard Worker br' Oicf, W1, Zp8, env=(.....) \(32b run\), ' 84*8975f5c5SAndroid Build Coastguard Worker br'target_arch=(AMD64|X86) 8\.\d\d\.\d{4}', 85*8975f5c5SAndroid Build Coastguard Worker br' Oicf, W1, Zp8, env=\1 (32b run), target_arch=\2 8.xx.xxxx', 86*8975f5c5SAndroid Build Coastguard Worker contents) 87*8975f5c5SAndroid Build Coastguard Worker # TODO(thakis): If we need more hacks than these, try to verify checked-in 88*8975f5c5SAndroid Build Coastguard Worker # outputs when we're using the hermetic toolchain. 89*8975f5c5SAndroid Build Coastguard Worker # midl.exe older than 8.1.622 omit '//' after #endif, fix that: 90*8975f5c5SAndroid Build Coastguard Worker contents = contents.replace(b'#endif !_MIDL_USE_GUIDDEF_', 91*8975f5c5SAndroid Build Coastguard Worker b'#endif // !_MIDL_USE_GUIDDEF_') 92*8975f5c5SAndroid Build Coastguard Worker # midl.exe puts the midl version into code in one place. To have 93*8975f5c5SAndroid Build Coastguard Worker # predictable output, lie about the midl version if it's not 8.1.622. 94*8975f5c5SAndroid Build Coastguard Worker # This is unfortunate, but remember that there's beauty too in imperfection. 95*8975f5c5SAndroid Build Coastguard Worker contents = contents.replace(b'0x801026c, /* MIDL Version 8.1.620 */', 96*8975f5c5SAndroid Build Coastguard Worker b'0x801026e, /* MIDL Version 8.1.622 */') 97*8975f5c5SAndroid Build Coastguard Worker open(filename, 'wb').write(contents) 98*8975f5c5SAndroid Build Coastguard Worker 99*8975f5c5SAndroid Build Coastguard Worker 100*8975f5c5SAndroid Build Coastguard Workerdef get_tlb_contents(tlb_file): 101*8975f5c5SAndroid Build Coastguard Worker # See ZapTimestamp() for a short overview of the .tlb format. 102*8975f5c5SAndroid Build Coastguard Worker contents = open(tlb_file, 'rb').read() 103*8975f5c5SAndroid Build Coastguard Worker assert contents[0:8] == b'MSFT\x02\x00\x01\x00' 104*8975f5c5SAndroid Build Coastguard Worker ntypes, = struct.unpack_from('<I', contents, 0x20) 105*8975f5c5SAndroid Build Coastguard Worker type_off, type_len = struct.unpack_from('<II', contents, 0x54 + 4*ntypes) 106*8975f5c5SAndroid Build Coastguard Worker 107*8975f5c5SAndroid Build Coastguard Worker guid_off, guid_len = struct.unpack_from( 108*8975f5c5SAndroid Build Coastguard Worker '<II', contents, 0x54 + 4*ntypes + 5*16) 109*8975f5c5SAndroid Build Coastguard Worker assert guid_len % 24 == 0 110*8975f5c5SAndroid Build Coastguard Worker 111*8975f5c5SAndroid Build Coastguard Worker contents = array.array('B', contents) 112*8975f5c5SAndroid Build Coastguard Worker 113*8975f5c5SAndroid Build Coastguard Worker return contents, ntypes, type_off, guid_off, guid_len 114*8975f5c5SAndroid Build Coastguard Worker 115*8975f5c5SAndroid Build Coastguard Worker 116*8975f5c5SAndroid Build Coastguard Workerdef recreate_guid_hashtable(contents, ntypes, guid_off, guid_len): 117*8975f5c5SAndroid Build Coastguard Worker # This function is called after changing guids in section 6 (the "guid" 118*8975f5c5SAndroid Build Coastguard Worker # section). This function recreates the GUID hashtable in section 5. Since the 119*8975f5c5SAndroid Build Coastguard Worker # hash table uses chaining, it's easiest to recompute it from scratch rather 120*8975f5c5SAndroid Build Coastguard Worker # than trying to patch it up. 121*8975f5c5SAndroid Build Coastguard Worker hashtab = [0xffffffff] * (0x80 // 4) 122*8975f5c5SAndroid Build Coastguard Worker for guidind in range(guid_off, guid_off + guid_len, 24): 123*8975f5c5SAndroid Build Coastguard Worker guidbytes, typeoff, nextguid = struct.unpack_from( 124*8975f5c5SAndroid Build Coastguard Worker '<16sII', contents, guidind) 125*8975f5c5SAndroid Build Coastguard Worker words = struct.unpack('<8H', guidbytes) 126*8975f5c5SAndroid Build Coastguard Worker # midl seems to use the following simple hash function for GUIDs: 127*8975f5c5SAndroid Build Coastguard Worker guidhash = reduce(operator.xor, [w for w in words]) % (0x80 // 4) 128*8975f5c5SAndroid Build Coastguard Worker nextguid = hashtab[guidhash] 129*8975f5c5SAndroid Build Coastguard Worker struct.pack_into('<I', contents, guidind + 0x14, nextguid) 130*8975f5c5SAndroid Build Coastguard Worker hashtab[guidhash] = guidind - guid_off 131*8975f5c5SAndroid Build Coastguard Worker hash_off, hash_len = struct.unpack_from( 132*8975f5c5SAndroid Build Coastguard Worker '<II', contents, 0x54 + 4*ntypes + 4*16) 133*8975f5c5SAndroid Build Coastguard Worker for i, hashval in enumerate(hashtab): 134*8975f5c5SAndroid Build Coastguard Worker struct.pack_into('<I', contents, hash_off + 4*i, hashval) 135*8975f5c5SAndroid Build Coastguard Worker 136*8975f5c5SAndroid Build Coastguard Worker 137*8975f5c5SAndroid Build Coastguard Workerdef overwrite_guids_h(h_file, dynamic_guids): 138*8975f5c5SAndroid Build Coastguard Worker contents = open(h_file, 'rb').read() 139*8975f5c5SAndroid Build Coastguard Worker for key in dynamic_guids: 140*8975f5c5SAndroid Build Coastguard Worker contents = re.sub(key, dynamic_guids[key], contents, flags=re.I) 141*8975f5c5SAndroid Build Coastguard Worker open(h_file, 'wb').write(contents) 142*8975f5c5SAndroid Build Coastguard Worker 143*8975f5c5SAndroid Build Coastguard Worker 144*8975f5c5SAndroid Build Coastguard Workerdef get_uuid_format(guid, prefix): 145*8975f5c5SAndroid Build Coastguard Worker formatted_uuid = b'0x%s,0x%s,0x%s,' % (guid[0:8], guid[9:13], guid[14:18]) 146*8975f5c5SAndroid Build Coastguard Worker formatted_uuid += b'%s0x%s,0x%s' % (prefix, guid[19:21], guid[21:23]) 147*8975f5c5SAndroid Build Coastguard Worker for i in range(24, len(guid), 2): 148*8975f5c5SAndroid Build Coastguard Worker formatted_uuid += b',0x' + guid[i:i + 2] 149*8975f5c5SAndroid Build Coastguard Worker return formatted_uuid 150*8975f5c5SAndroid Build Coastguard Worker 151*8975f5c5SAndroid Build Coastguard Worker 152*8975f5c5SAndroid Build Coastguard Workerdef get_uuid_format_iid_file(guid): 153*8975f5c5SAndroid Build Coastguard Worker # Convert from "D0E1CACC-C63C-4192-94AB-BF8EAD0E3B83" to 154*8975f5c5SAndroid Build Coastguard Worker # 0xD0E1CACC,0xC63C,0x4192,0x94,0xAB,0xBF,0x8E,0xAD,0x0E,0x3B,0x83. 155*8975f5c5SAndroid Build Coastguard Worker return get_uuid_format(guid, b'') 156*8975f5c5SAndroid Build Coastguard Worker 157*8975f5c5SAndroid Build Coastguard Worker 158*8975f5c5SAndroid Build Coastguard Workerdef overwrite_guids_iid(iid_file, dynamic_guids): 159*8975f5c5SAndroid Build Coastguard Worker contents = open(iid_file, 'rb').read() 160*8975f5c5SAndroid Build Coastguard Worker for key in dynamic_guids: 161*8975f5c5SAndroid Build Coastguard Worker contents = re.sub(get_uuid_format_iid_file(key), 162*8975f5c5SAndroid Build Coastguard Worker get_uuid_format_iid_file(dynamic_guids[key]), 163*8975f5c5SAndroid Build Coastguard Worker contents, 164*8975f5c5SAndroid Build Coastguard Worker flags=re.I) 165*8975f5c5SAndroid Build Coastguard Worker open(iid_file, 'wb').write(contents) 166*8975f5c5SAndroid Build Coastguard Worker 167*8975f5c5SAndroid Build Coastguard Worker 168*8975f5c5SAndroid Build Coastguard Workerdef get_uuid_format_proxy_file(guid): 169*8975f5c5SAndroid Build Coastguard Worker # Convert from "D0E1CACC-C63C-4192-94AB-BF8EAD0E3B83" to 170*8975f5c5SAndroid Build Coastguard Worker # {0xD0E1CACC,0xC63C,0x4192,{0x94,0xAB,0xBF,0x8E,0xAD,0x0E,0x3B,0x83}}. 171*8975f5c5SAndroid Build Coastguard Worker return get_uuid_format(guid, b'{') 172*8975f5c5SAndroid Build Coastguard Worker 173*8975f5c5SAndroid Build Coastguard Worker 174*8975f5c5SAndroid Build Coastguard Workerdef overwrite_guids_proxy(proxy_file, dynamic_guids): 175*8975f5c5SAndroid Build Coastguard Worker contents = open(proxy_file, 'rb').read() 176*8975f5c5SAndroid Build Coastguard Worker for key in dynamic_guids: 177*8975f5c5SAndroid Build Coastguard Worker contents = re.sub(get_uuid_format_proxy_file(key), 178*8975f5c5SAndroid Build Coastguard Worker get_uuid_format_proxy_file(dynamic_guids[key]), 179*8975f5c5SAndroid Build Coastguard Worker contents, 180*8975f5c5SAndroid Build Coastguard Worker flags=re.I) 181*8975f5c5SAndroid Build Coastguard Worker open(proxy_file, 'wb').write(contents) 182*8975f5c5SAndroid Build Coastguard Worker 183*8975f5c5SAndroid Build Coastguard Worker 184*8975f5c5SAndroid Build Coastguard Workerdef getguid(contents, offset): 185*8975f5c5SAndroid Build Coastguard Worker # Returns a guid string of the form "D0E1CACC-C63C-4192-94AB-BF8EAD0E3B83". 186*8975f5c5SAndroid Build Coastguard Worker g0, g1, g2, g3 = struct.unpack_from('<IHH8s', contents, offset) 187*8975f5c5SAndroid Build Coastguard Worker g3 = b''.join([b'%02X' % g for g in bytearray(g3)]) 188*8975f5c5SAndroid Build Coastguard Worker return b'%08X-%04X-%04X-%s-%s' % (g0, g1, g2, g3[0:4], g3[4:]) 189*8975f5c5SAndroid Build Coastguard Worker 190*8975f5c5SAndroid Build Coastguard Worker 191*8975f5c5SAndroid Build Coastguard Workerdef setguid(contents, offset, guid): 192*8975f5c5SAndroid Build Coastguard Worker guid = uuid.UUID(guid.decode('utf-8')) 193*8975f5c5SAndroid Build Coastguard Worker struct.pack_into('<IHH8s', contents, offset, 194*8975f5c5SAndroid Build Coastguard Worker *(guid.fields[0:3] + (guid.bytes[8:], ))) 195*8975f5c5SAndroid Build Coastguard Worker 196*8975f5c5SAndroid Build Coastguard Worker 197*8975f5c5SAndroid Build Coastguard Workerdef overwrite_guids_tlb(tlb_file, dynamic_guids): 198*8975f5c5SAndroid Build Coastguard Worker contents, ntypes, type_off, guid_off, guid_len = get_tlb_contents(tlb_file) 199*8975f5c5SAndroid Build Coastguard Worker 200*8975f5c5SAndroid Build Coastguard Worker for i in range(0, guid_len, 24): 201*8975f5c5SAndroid Build Coastguard Worker current_guid = getguid(contents, guid_off + i) 202*8975f5c5SAndroid Build Coastguard Worker for key in dynamic_guids: 203*8975f5c5SAndroid Build Coastguard Worker if key.lower() == current_guid.lower(): 204*8975f5c5SAndroid Build Coastguard Worker setguid(contents, guid_off + i, dynamic_guids[key]) 205*8975f5c5SAndroid Build Coastguard Worker 206*8975f5c5SAndroid Build Coastguard Worker recreate_guid_hashtable(contents, ntypes, guid_off, guid_len) 207*8975f5c5SAndroid Build Coastguard Worker open(tlb_file, 'wb').write(contents) 208*8975f5c5SAndroid Build Coastguard Worker 209*8975f5c5SAndroid Build Coastguard Worker 210*8975f5c5SAndroid Build Coastguard Worker# Handle multiple guid substitutions, where |dynamic_guids| is of the form 211*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-158428a4-6014-4978-83ba-9fad0dabe791=" 212*8975f5c5SAndroid Build Coastguard Worker# "3d852661-c795-4d20-9b95-5561e9a1d2d9," 213*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-63B8FFB1-5314-48C9-9C57-93EC8BC6184B=" 214*8975f5c5SAndroid Build Coastguard Worker# "D0E1CACC-C63C-4192-94AB-BF8EAD0E3B83". 215*8975f5c5SAndroid Build Coastguard Worker# 216*8975f5c5SAndroid Build Coastguard Worker# Before specifying |dynamic_guids| in the build, the IDL file is first compiled 217*8975f5c5SAndroid Build Coastguard Worker# with "158428a4-6014-4978-83ba-9fad0dabe791" and 218*8975f5c5SAndroid Build Coastguard Worker# "63B8FFB1-5314-48C9-9C57-93EC8BC6184B". These are the "replaceable" guids, 219*8975f5c5SAndroid Build Coastguard Worker# i.e., guids that can be replaced in future builds. The resulting MIDL outputs 220*8975f5c5SAndroid Build Coastguard Worker# are copied over to src\third_party\win_build_output\. 221*8975f5c5SAndroid Build Coastguard Worker# 222*8975f5c5SAndroid Build Coastguard Worker# Then, in the future, any changes to these guids can be accomplished by 223*8975f5c5SAndroid Build Coastguard Worker# providing |dynamic_guids| of the format above in the build file. These 224*8975f5c5SAndroid Build Coastguard Worker# "dynamic" guid changes by themselves will not require the MIDL compiler and 225*8975f5c5SAndroid Build Coastguard Worker# therefore will not require copying output over to 226*8975f5c5SAndroid Build Coastguard Worker# src\third_party\win_build_output\. 227*8975f5c5SAndroid Build Coastguard Worker# 228*8975f5c5SAndroid Build Coastguard Worker# The pre-generated src\third_party\win_build_output\ files are used for 229*8975f5c5SAndroid Build Coastguard Worker# cross-compiling on other platforms, since the MIDL compiler is Windows-only. 230*8975f5c5SAndroid Build Coastguard Workerdef overwrite_guids(h_file, iid_file, proxy_file, tlb_file, dynamic_guids): 231*8975f5c5SAndroid Build Coastguard Worker # Fix up GUIDs in .h, _i.c, _p.c, and .tlb. 232*8975f5c5SAndroid Build Coastguard Worker overwrite_guids_h(h_file, dynamic_guids) 233*8975f5c5SAndroid Build Coastguard Worker overwrite_guids_iid(iid_file, dynamic_guids) 234*8975f5c5SAndroid Build Coastguard Worker overwrite_guids_proxy(proxy_file, dynamic_guids) 235*8975f5c5SAndroid Build Coastguard Worker if tlb_file: 236*8975f5c5SAndroid Build Coastguard Worker overwrite_guids_tlb(tlb_file, dynamic_guids) 237*8975f5c5SAndroid Build Coastguard Worker 238*8975f5c5SAndroid Build Coastguard Worker 239*8975f5c5SAndroid Build Coastguard Worker# This function removes all occurrences of 'PLACEHOLDER-GUID-' from the 240*8975f5c5SAndroid Build Coastguard Worker# template, and if |dynamic_guids| is specified, also replaces the guids within 241*8975f5c5SAndroid Build Coastguard Worker# the file. Finally, it writes the resultant output to the |idl| file. 242*8975f5c5SAndroid Build Coastguard Workerdef generate_idl_from_template(idl_template, dynamic_guids, idl): 243*8975f5c5SAndroid Build Coastguard Worker contents = open(idl_template, 'rb').read() 244*8975f5c5SAndroid Build Coastguard Worker contents = re.sub(b'PLACEHOLDER-GUID-', b'', contents, flags=re.I) 245*8975f5c5SAndroid Build Coastguard Worker if dynamic_guids: 246*8975f5c5SAndroid Build Coastguard Worker for key in dynamic_guids: 247*8975f5c5SAndroid Build Coastguard Worker contents = re.sub(key, dynamic_guids[key], contents, flags=re.I) 248*8975f5c5SAndroid Build Coastguard Worker open(idl, 'wb').write(contents) 249*8975f5c5SAndroid Build Coastguard Worker 250*8975f5c5SAndroid Build Coastguard Worker 251*8975f5c5SAndroid Build Coastguard Worker# This function runs the MIDL compiler with the provided arguments. It creates 252*8975f5c5SAndroid Build Coastguard Worker# and returns a tuple of |0,midl_output_dir| on success. 253*8975f5c5SAndroid Build Coastguard Workerdef run_midl(args, env_dict): 254*8975f5c5SAndroid Build Coastguard Worker midl_output_dir = tempfile.mkdtemp() 255*8975f5c5SAndroid Build Coastguard Worker delete_midl_output_dir = True 256*8975f5c5SAndroid Build Coastguard Worker 257*8975f5c5SAndroid Build Coastguard Worker try: 258*8975f5c5SAndroid Build Coastguard Worker popen = subprocess.Popen(args + ['/out', midl_output_dir], 259*8975f5c5SAndroid Build Coastguard Worker shell=True, 260*8975f5c5SAndroid Build Coastguard Worker universal_newlines=True, 261*8975f5c5SAndroid Build Coastguard Worker env=env_dict, 262*8975f5c5SAndroid Build Coastguard Worker stdout=subprocess.PIPE, 263*8975f5c5SAndroid Build Coastguard Worker stderr=subprocess.STDOUT) 264*8975f5c5SAndroid Build Coastguard Worker out, _ = popen.communicate() 265*8975f5c5SAndroid Build Coastguard Worker 266*8975f5c5SAndroid Build Coastguard Worker # Filter junk out of stdout, and write filtered versions. Output we want 267*8975f5c5SAndroid Build Coastguard Worker # to filter is pairs of lines that look like this: 268*8975f5c5SAndroid Build Coastguard Worker # Processing C:\Program Files (x86)\Microsoft SDKs\...\include\objidl.idl 269*8975f5c5SAndroid Build Coastguard Worker # objidl.idl 270*8975f5c5SAndroid Build Coastguard Worker lines = out.splitlines() 271*8975f5c5SAndroid Build Coastguard Worker prefixes = ('Processing ', '64 bit Processing ') 272*8975f5c5SAndroid Build Coastguard Worker processing = set( 273*8975f5c5SAndroid Build Coastguard Worker os.path.basename(x) for x in lines if x.startswith(prefixes)) 274*8975f5c5SAndroid Build Coastguard Worker for line in lines: 275*8975f5c5SAndroid Build Coastguard Worker if not line.startswith(prefixes) and line not in processing: 276*8975f5c5SAndroid Build Coastguard Worker print(line) 277*8975f5c5SAndroid Build Coastguard Worker 278*8975f5c5SAndroid Build Coastguard Worker if popen.returncode != 0: 279*8975f5c5SAndroid Build Coastguard Worker return popen.returncode, midl_output_dir 280*8975f5c5SAndroid Build Coastguard Worker 281*8975f5c5SAndroid Build Coastguard Worker for f in os.listdir(midl_output_dir): 282*8975f5c5SAndroid Build Coastguard Worker ZapTimestamp(os.path.join(midl_output_dir, f)) 283*8975f5c5SAndroid Build Coastguard Worker 284*8975f5c5SAndroid Build Coastguard Worker delete_midl_output_dir = False 285*8975f5c5SAndroid Build Coastguard Worker finally: 286*8975f5c5SAndroid Build Coastguard Worker if os.path.exists(midl_output_dir) and delete_midl_output_dir: 287*8975f5c5SAndroid Build Coastguard Worker shutil.rmtree(midl_output_dir) 288*8975f5c5SAndroid Build Coastguard Worker 289*8975f5c5SAndroid Build Coastguard Worker return 0, midl_output_dir 290*8975f5c5SAndroid Build Coastguard Worker 291*8975f5c5SAndroid Build Coastguard Worker 292*8975f5c5SAndroid Build Coastguard Worker# This function adds support for dynamic generation of guids: when values are 293*8975f5c5SAndroid Build Coastguard Worker# specified as 'uuid5:name', this function will substitute the values with 294*8975f5c5SAndroid Build Coastguard Worker# generated dynamic guids using the uuid5 function. The uuid5 function generates 295*8975f5c5SAndroid Build Coastguard Worker# a guid based on the SHA-1 hash of a namespace identifier (which is the guid 296*8975f5c5SAndroid Build Coastguard Worker# that comes after 'PLACEHOLDER-GUID-') and a name (which is a string, such as a 297*8975f5c5SAndroid Build Coastguard Worker# version string "87.1.2.3"). 298*8975f5c5SAndroid Build Coastguard Worker# 299*8975f5c5SAndroid Build Coastguard Worker# For instance, when |dynamic_guid| is of the form: 300*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-158428a4-6014-4978-83ba-9fad0dabe791=uuid5:88.0.4307.0 301*8975f5c5SAndroid Build Coastguard Worker# ," 302*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-63B8FFB1-5314-48C9-9C57-93EC8BC6184B=uuid5:88.0.4307.0 303*8975f5c5SAndroid Build Coastguard Worker# " 304*8975f5c5SAndroid Build Coastguard Worker# 305*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-158428a4-6014-4978-83ba-9fad0dabe791" would be substituted 306*8975f5c5SAndroid Build Coastguard Worker# with uuid5("158428a4-6014-4978-83ba-9fad0dabe791", "88.0.4307.0"), which is 307*8975f5c5SAndroid Build Coastguard Worker# "64700170-AD80-5DE3-924E-2F39D862CFD5". And 308*8975f5c5SAndroid Build Coastguard Worker# "PLACEHOLDER-GUID-63B8FFB1-5314-48C9-9C57-93EC8BC6184B" would be 309*8975f5c5SAndroid Build Coastguard Worker# substituted with uuid5("63B8FFB1-5314-48C9-9C57-93EC8BC6184B", "88.0.4307.0"), 310*8975f5c5SAndroid Build Coastguard Worker# which is "7B6E7538-3C38-5565-BC92-42BCEE268D76". 311*8975f5c5SAndroid Build Coastguard Workerdef uuid5_substitutions(dynamic_guids): 312*8975f5c5SAndroid Build Coastguard Worker for key, value in dynamic_guids.items(): 313*8975f5c5SAndroid Build Coastguard Worker if value.startswith('uuid5:'): 314*8975f5c5SAndroid Build Coastguard Worker name = value.split('uuid5:', 1)[1] 315*8975f5c5SAndroid Build Coastguard Worker assert name 316*8975f5c5SAndroid Build Coastguard Worker dynamic_guids[key] = str(uuid.uuid5(uuid.UUID(key), name)).upper() 317*8975f5c5SAndroid Build Coastguard Worker 318*8975f5c5SAndroid Build Coastguard Worker 319*8975f5c5SAndroid Build Coastguard Workerdef main(arch, gendir, outdir, dynamic_guids, tlb, h, dlldata, iid, proxy, 320*8975f5c5SAndroid Build Coastguard Worker clang, idl, *flags): 321*8975f5c5SAndroid Build Coastguard Worker # Copy checked-in outputs to final location. 322*8975f5c5SAndroid Build Coastguard Worker source = gendir 323*8975f5c5SAndroid Build Coastguard Worker if os.path.isdir(os.path.join(source, os.path.basename(idl))): 324*8975f5c5SAndroid Build Coastguard Worker source = os.path.join(source, os.path.basename(idl)) 325*8975f5c5SAndroid Build Coastguard Worker source = os.path.join(source, arch.split('.')[1]) # Append 'x86' or 'x64'. 326*8975f5c5SAndroid Build Coastguard Worker source = os.path.normpath(source) 327*8975f5c5SAndroid Build Coastguard Worker 328*8975f5c5SAndroid Build Coastguard Worker source_exists = True 329*8975f5c5SAndroid Build Coastguard Worker if not os.path.isdir(source): 330*8975f5c5SAndroid Build Coastguard Worker source_exists = False 331*8975f5c5SAndroid Build Coastguard Worker if sys.platform != 'win32': 332*8975f5c5SAndroid Build Coastguard Worker print('Directory %s needs to be populated from Windows first' % source) 333*8975f5c5SAndroid Build Coastguard Worker return 1 334*8975f5c5SAndroid Build Coastguard Worker 335*8975f5c5SAndroid Build Coastguard Worker # This is a brand new IDL file that does not have outputs under 336*8975f5c5SAndroid Build Coastguard Worker # third_party\win_build_output\midl. We create an empty directory for now. 337*8975f5c5SAndroid Build Coastguard Worker os.makedirs(source) 338*8975f5c5SAndroid Build Coastguard Worker 339*8975f5c5SAndroid Build Coastguard Worker common_files = [h, iid] 340*8975f5c5SAndroid Build Coastguard Worker if tlb != 'none': 341*8975f5c5SAndroid Build Coastguard Worker # Not all projects use tlb files. 342*8975f5c5SAndroid Build Coastguard Worker common_files += [tlb] 343*8975f5c5SAndroid Build Coastguard Worker else: 344*8975f5c5SAndroid Build Coastguard Worker tlb = None 345*8975f5c5SAndroid Build Coastguard Worker 346*8975f5c5SAndroid Build Coastguard Worker if dlldata != 'none': 347*8975f5c5SAndroid Build Coastguard Worker # Not all projects use dlldta files. 348*8975f5c5SAndroid Build Coastguard Worker common_files += [dlldata] 349*8975f5c5SAndroid Build Coastguard Worker else: 350*8975f5c5SAndroid Build Coastguard Worker dlldata = None 351*8975f5c5SAndroid Build Coastguard Worker 352*8975f5c5SAndroid Build Coastguard Worker # Not all projects use proxy files 353*8975f5c5SAndroid Build Coastguard Worker if proxy != 'none': 354*8975f5c5SAndroid Build Coastguard Worker # Not all projects use proxy files. 355*8975f5c5SAndroid Build Coastguard Worker common_files += [proxy] 356*8975f5c5SAndroid Build Coastguard Worker else: 357*8975f5c5SAndroid Build Coastguard Worker proxy = None 358*8975f5c5SAndroid Build Coastguard Worker 359*8975f5c5SAndroid Build Coastguard Worker for source_file in common_files: 360*8975f5c5SAndroid Build Coastguard Worker file_path = os.path.join(source, source_file) 361*8975f5c5SAndroid Build Coastguard Worker if not os.path.isfile(file_path): 362*8975f5c5SAndroid Build Coastguard Worker source_exists = False 363*8975f5c5SAndroid Build Coastguard Worker if sys.platform != 'win32': 364*8975f5c5SAndroid Build Coastguard Worker print('File %s needs to be generated from Windows first' % file_path) 365*8975f5c5SAndroid Build Coastguard Worker return 1 366*8975f5c5SAndroid Build Coastguard Worker 367*8975f5c5SAndroid Build Coastguard Worker # Either this is a brand new IDL file that does not have outputs under 368*8975f5c5SAndroid Build Coastguard Worker # third_party\win_build_output\midl or the file is (unexpectedly) missing. 369*8975f5c5SAndroid Build Coastguard Worker # We create an empty file for now. The rest of the machinery below will 370*8975f5c5SAndroid Build Coastguard Worker # then generate the correctly populated file using the MIDL compiler and 371*8975f5c5SAndroid Build Coastguard Worker # instruct the developer to copy that file under 372*8975f5c5SAndroid Build Coastguard Worker # third_party\win_build_output\midl. 373*8975f5c5SAndroid Build Coastguard Worker open(file_path, 'wb').close() 374*8975f5c5SAndroid Build Coastguard Worker shutil.copy(file_path, outdir) 375*8975f5c5SAndroid Build Coastguard Worker 376*8975f5c5SAndroid Build Coastguard Worker if dynamic_guids != 'none': 377*8975f5c5SAndroid Build Coastguard Worker assert '=' in dynamic_guids 378*8975f5c5SAndroid Build Coastguard Worker if dynamic_guids.startswith("ignore_proxy_stub,"): 379*8975f5c5SAndroid Build Coastguard Worker # TODO(ganesh): The custom proxy/stub file ("_p.c") is not generated 380*8975f5c5SAndroid Build Coastguard Worker # correctly for dynamic IIDs (but correctly if there are only dynamic 381*8975f5c5SAndroid Build Coastguard Worker # CLSIDs). The proxy/stub lookup functions generated by MIDL.exe within 382*8975f5c5SAndroid Build Coastguard Worker # "_p.c" rely on a sorted set of vtable lists, which we are not currently 383*8975f5c5SAndroid Build Coastguard Worker # regenerating. At the moment, no project in Chromium that uses dynamic 384*8975f5c5SAndroid Build Coastguard Worker # IIDs is relying on the custom proxy/stub file. So for now, if 385*8975f5c5SAndroid Build Coastguard Worker # |dynamic_guids| is prefixed with "ignore_proxy_stub,", we exclude the 386*8975f5c5SAndroid Build Coastguard Worker # custom proxy/stub file from the directory comparisons. 387*8975f5c5SAndroid Build Coastguard Worker common_files.remove(proxy) 388*8975f5c5SAndroid Build Coastguard Worker dynamic_guids = dynamic_guids.split("ignore_proxy_stub,", 1)[1] 389*8975f5c5SAndroid Build Coastguard Worker dynamic_guids = re.sub('PLACEHOLDER-GUID-', '', dynamic_guids, flags=re.I) 390*8975f5c5SAndroid Build Coastguard Worker dynamic_guids = dynamic_guids.split(',') 391*8975f5c5SAndroid Build Coastguard Worker dynamic_guids = dict(s.split('=') for s in dynamic_guids) 392*8975f5c5SAndroid Build Coastguard Worker uuid5_substitutions(dynamic_guids) 393*8975f5c5SAndroid Build Coastguard Worker dynamic_guids_bytes = { 394*8975f5c5SAndroid Build Coastguard Worker k.encode('utf-8'): v.encode('utf-8') 395*8975f5c5SAndroid Build Coastguard Worker for k, v in dynamic_guids.items() 396*8975f5c5SAndroid Build Coastguard Worker } 397*8975f5c5SAndroid Build Coastguard Worker if source_exists: 398*8975f5c5SAndroid Build Coastguard Worker overwrite_guids(*(os.path.join(outdir, file) if file else None 399*8975f5c5SAndroid Build Coastguard Worker for file in [h, iid, proxy, tlb]), 400*8975f5c5SAndroid Build Coastguard Worker dynamic_guids=dynamic_guids_bytes) 401*8975f5c5SAndroid Build Coastguard Worker else: 402*8975f5c5SAndroid Build Coastguard Worker dynamic_guids = None 403*8975f5c5SAndroid Build Coastguard Worker 404*8975f5c5SAndroid Build Coastguard Worker # On non-Windows, that's all we can do. 405*8975f5c5SAndroid Build Coastguard Worker if sys.platform != 'win32': 406*8975f5c5SAndroid Build Coastguard Worker return 0 407*8975f5c5SAndroid Build Coastguard Worker 408*8975f5c5SAndroid Build Coastguard Worker idl_template = None 409*8975f5c5SAndroid Build Coastguard Worker if dynamic_guids: 410*8975f5c5SAndroid Build Coastguard Worker idl_template = idl 411*8975f5c5SAndroid Build Coastguard Worker 412*8975f5c5SAndroid Build Coastguard Worker # posixpath is used here to keep the MIDL-generated files with a uniform 413*8975f5c5SAndroid Build Coastguard Worker # separator of '/' instead of mixed '/' and '\\'. 414*8975f5c5SAndroid Build Coastguard Worker idl = posixpath.join( 415*8975f5c5SAndroid Build Coastguard Worker outdir, 416*8975f5c5SAndroid Build Coastguard Worker os.path.splitext(os.path.basename(idl_template))[0] + '.idl') 417*8975f5c5SAndroid Build Coastguard Worker 418*8975f5c5SAndroid Build Coastguard Worker # |idl_template| can contain one or more occurrences of guids that are 419*8975f5c5SAndroid Build Coastguard Worker # substituted with |dynamic_guids|, and then MIDL is run on the substituted 420*8975f5c5SAndroid Build Coastguard Worker # IDL file. 421*8975f5c5SAndroid Build Coastguard Worker generate_idl_from_template(idl_template, dynamic_guids_bytes, idl) 422*8975f5c5SAndroid Build Coastguard Worker 423*8975f5c5SAndroid Build Coastguard Worker # On Windows, run midl.exe on the input and check that its outputs are 424*8975f5c5SAndroid Build Coastguard Worker # identical to the checked-in outputs (after replacing guids if 425*8975f5c5SAndroid Build Coastguard Worker # |dynamic_guids| is specified). 426*8975f5c5SAndroid Build Coastguard Worker 427*8975f5c5SAndroid Build Coastguard Worker # Read the environment block from the file. This is stored in the format used 428*8975f5c5SAndroid Build Coastguard Worker # by CreateProcess. Drop last 2 NULs, one for list terminator, one for 429*8975f5c5SAndroid Build Coastguard Worker # trailing vs. separator. 430*8975f5c5SAndroid Build Coastguard Worker env_pairs = open(arch).read()[:-2].split('\0') 431*8975f5c5SAndroid Build Coastguard Worker env_dict = dict([item.split('=', 1) for item in env_pairs]) 432*8975f5c5SAndroid Build Coastguard Worker 433*8975f5c5SAndroid Build Coastguard Worker # Extract the /D options and send them to the preprocessor. 434*8975f5c5SAndroid Build Coastguard Worker preprocessor_options = '-E -nologo -Wno-nonportable-include-path' 435*8975f5c5SAndroid Build Coastguard Worker preprocessor_options += ''.join( 436*8975f5c5SAndroid Build Coastguard Worker [' ' + flag for flag in flags if flag.startswith('/D')]) 437*8975f5c5SAndroid Build Coastguard Worker args = ['midl', '/nologo'] + list(flags) + (['/tlb', tlb] if tlb else []) + [ 438*8975f5c5SAndroid Build Coastguard Worker '/h', h 439*8975f5c5SAndroid Build Coastguard Worker ] + (['/dlldata', dlldata] if dlldata else []) + ['/iid', iid] + ( 440*8975f5c5SAndroid Build Coastguard Worker ['/proxy', proxy] if proxy else 441*8975f5c5SAndroid Build Coastguard Worker []) + ['/cpp_cmd', clang, '/cpp_opt', preprocessor_options, idl] 442*8975f5c5SAndroid Build Coastguard Worker 443*8975f5c5SAndroid Build Coastguard Worker returncode, midl_output_dir = run_midl(args, env_dict) 444*8975f5c5SAndroid Build Coastguard Worker if returncode != 0: 445*8975f5c5SAndroid Build Coastguard Worker return returncode 446*8975f5c5SAndroid Build Coastguard Worker 447*8975f5c5SAndroid Build Coastguard Worker # Now compare the output in midl_output_dir to the copied-over outputs. 448*8975f5c5SAndroid Build Coastguard Worker _, mismatch, errors = filecmp.cmpfiles(midl_output_dir, outdir, common_files) 449*8975f5c5SAndroid Build Coastguard Worker assert not errors 450*8975f5c5SAndroid Build Coastguard Worker 451*8975f5c5SAndroid Build Coastguard Worker if mismatch: 452*8975f5c5SAndroid Build Coastguard Worker print('midl.exe output different from files in %s, see %s' % 453*8975f5c5SAndroid Build Coastguard Worker (outdir, midl_output_dir)) 454*8975f5c5SAndroid Build Coastguard Worker for f in mismatch: 455*8975f5c5SAndroid Build Coastguard Worker if f.endswith('.tlb'): continue 456*8975f5c5SAndroid Build Coastguard Worker fromfile = os.path.join(outdir, f) 457*8975f5c5SAndroid Build Coastguard Worker tofile = os.path.join(midl_output_dir, f) 458*8975f5c5SAndroid Build Coastguard Worker print(''.join( 459*8975f5c5SAndroid Build Coastguard Worker difflib.unified_diff( 460*8975f5c5SAndroid Build Coastguard Worker io.open(fromfile).readlines(), 461*8975f5c5SAndroid Build Coastguard Worker io.open(tofile).readlines(), fromfile, tofile))) 462*8975f5c5SAndroid Build Coastguard Worker 463*8975f5c5SAndroid Build Coastguard Worker if dynamic_guids: 464*8975f5c5SAndroid Build Coastguard Worker # |idl_template| can contain one or more occurrences of guids prefixed 465*8975f5c5SAndroid Build Coastguard Worker # with 'PLACEHOLDER-GUID-'. We first remove the extraneous 466*8975f5c5SAndroid Build Coastguard Worker # 'PLACEHOLDER-GUID-' prefix and then run MIDL on the substituted IDL 467*8975f5c5SAndroid Build Coastguard Worker # file. 468*8975f5c5SAndroid Build Coastguard Worker # No guid substitutions are done at this point, because we want to compile 469*8975f5c5SAndroid Build Coastguard Worker # with the placeholder guids and then instruct the user to copy the output 470*8975f5c5SAndroid Build Coastguard Worker # over to |source| which is typically src\third_party\win_build_output\. 471*8975f5c5SAndroid Build Coastguard Worker # In future runs, the placeholder guids in |source| are replaced with the 472*8975f5c5SAndroid Build Coastguard Worker # guids specified in |dynamic_guids|. 473*8975f5c5SAndroid Build Coastguard Worker generate_idl_from_template(idl_template, None, idl) 474*8975f5c5SAndroid Build Coastguard Worker returncode, midl_output_dir = run_midl(args, env_dict) 475*8975f5c5SAndroid Build Coastguard Worker if returncode != 0: 476*8975f5c5SAndroid Build Coastguard Worker return returncode 477*8975f5c5SAndroid Build Coastguard Worker 478*8975f5c5SAndroid Build Coastguard Worker print('To rebaseline:') 479*8975f5c5SAndroid Build Coastguard Worker print(r' copy /y %s\* %s' % (midl_output_dir, source)) 480*8975f5c5SAndroid Build Coastguard Worker return 1 481*8975f5c5SAndroid Build Coastguard Worker 482*8975f5c5SAndroid Build Coastguard Worker return 0 483*8975f5c5SAndroid Build Coastguard Worker 484*8975f5c5SAndroid Build Coastguard Worker 485*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 486*8975f5c5SAndroid Build Coastguard Worker sys.exit(main(*sys.argv[1:])) 487