xref: /aosp_15_r20/external/angle/build/toolchain/win/midl.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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