[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | """This script should be run manually on occasion to make sure all PPAPI types |
| 7 | have appropriate size checking. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 8 | """ |
| 9 | |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 10 | from __future__ import print_function |
| 11 | |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 12 | import optparse |
| 13 | import os |
| 14 | import subprocess |
| 15 | import sys |
| 16 | |
| 17 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 18 | # The string that the PrintNamesAndSizes plugin uses to indicate a type is |
| 19 | # expected to have architecture-dependent size. |
| 20 | ARCH_DEPENDENT_STRING = "ArchDependentSize" |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 21 | |
| 22 | |
[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 23 | COPYRIGHT_STRING_C = ( |
| 24 | """/* Copyright (c) %s The Chromium Authors. All rights reserved. |
| 25 | * Use of this source code is governed by a BSD-style license that can be |
| 26 | * found in the LICENSE file. |
| 27 | * |
| 28 | * This file has compile assertions for the sizes of types that are dependent |
| 29 | * on the architecture for which they are compiled (i.e., 32-bit vs 64-bit). |
| 30 | */ |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 31 | |
[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 32 | """) % datetime.date.today().year |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 33 | |
[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 34 | |
| 35 | class SourceLocation(object): |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 36 | """A class representing the source location of a definiton.""" |
| 37 | |
| 38 | def __init__(self, filename="", start_line=-1, end_line=-1): |
| 39 | self.filename = os.path.normpath(filename) |
| 40 | self.start_line = start_line |
| 41 | self.end_line = end_line |
| 42 | |
| 43 | |
[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 44 | class TypeInfo(object): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 45 | """A class representing information about a C++ type. It contains the |
| 46 | following fields: |
| 47 | - kind: The Clang TypeClassName (Record, Enum, Typedef, Union, etc) |
| 48 | - name: The unmangled string name of the type. |
| 49 | - size: The size in bytes of the type. |
| 50 | - arch_dependent: True if the type may have architecture dependent size |
| 51 | according to PrintNamesAndSizes. False otherwise. Types |
| 52 | which are considered architecture-dependent from 32-bit |
| 53 | to 64-bit are pointers, longs, unsigned longs, and any |
| 54 | type that contains an architecture-dependent type. |
| 55 | - source_location: A SourceLocation describing where the type is defined. |
| 56 | - target: The target Clang was compiling when it found the type definition. |
| 57 | This is used only for diagnostic output. |
| 58 | - parsed_line: The line which Clang output which was used to create this |
| 59 | TypeInfo (as the info_string parameter to __init__). This is |
| 60 | used only for diagnostic output. |
| 61 | """ |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 62 | |
| 63 | def __init__(self, info_string, target): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 64 | """Create a TypeInfo from a given info_string. Also store the name of the |
| 65 | target for which the TypeInfo was first created just so we can print useful |
| 66 | error information. |
| 67 | info_string is a comma-delimited string of the following form: |
| 68 | kind,name,size,arch_dependent,source_file,start_line,end_line |
| 69 | Where: |
| 70 | - kind: The Clang TypeClassName (Record, Enum, Typedef, Union, etc) |
| 71 | - name: The unmangled string name of the type. |
| 72 | - size: The size in bytes of the type. |
| 73 | - arch_dependent: 'ArchDependentSize' if the type has architecture-dependent |
| 74 | size, NotArchDependentSize otherwise. |
| 75 | - source_file: The source file in which the type is defined. |
| 76 | - first_line: The first line of the definition (counting from 0). |
| 77 | - last_line: The last line of the definition (counting from 0). |
| 78 | This should match the output of the PrintNamesAndSizes plugin. |
| 79 | """ |
| 80 | [self.kind, self.name, self.size, arch_dependent_string, source_file, |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 81 | start_line, end_line] = info_string.split(',') |
| 82 | self.target = target |
| 83 | self.parsed_line = info_string |
| 84 | # Note that Clang counts line numbers from 1, but we want to count from 0. |
| 85 | self.source_location = SourceLocation(source_file, |
| 86 | int(start_line)-1, |
| 87 | int(end_line)-1) |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 88 | self.arch_dependent = (arch_dependent_string == ARCH_DEPENDENT_STRING) |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 89 | |
| 90 | |
[email protected] | 2ec654a | 2012-01-10 17:47:00 | [diff] [blame] | 91 | class FilePatch(object): |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 92 | """A class representing a set of line-by-line changes to a particular file. |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 93 | None of the changes are applied until Apply is called. All line numbers are |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 94 | counted from 0. |
| 95 | """ |
| 96 | |
| 97 | def __init__(self, filename): |
| 98 | self.filename = filename |
| 99 | self.linenums_to_delete = set() |
| 100 | # A dictionary from line number to an array of strings to be inserted at |
| 101 | # that line number. |
| 102 | self.lines_to_add = {} |
| 103 | |
| 104 | def Delete(self, start_line, end_line): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 105 | """Make the patch delete the lines starting with |start_line| up to but not |
| 106 | including |end_line|. |
| 107 | """ |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 108 | self.linenums_to_delete |= set(range(start_line, end_line)) |
| 109 | |
| 110 | def Add(self, text, line_number): |
| 111 | """Add the given text before the text on the given line number.""" |
| 112 | if line_number in self.lines_to_add: |
| 113 | self.lines_to_add[line_number].append(text) |
| 114 | else: |
| 115 | self.lines_to_add[line_number] = [text] |
| 116 | |
| 117 | def Apply(self): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 118 | """Apply the patch by writing it to self.filename.""" |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 119 | # Read the lines of the existing file in to a list. |
| 120 | sourcefile = open(self.filename, "r") |
| 121 | file_lines = sourcefile.readlines() |
| 122 | sourcefile.close() |
| 123 | # Now apply the patch. Our strategy is to keep the array at the same size, |
| 124 | # and just edit strings in the file_lines list as necessary. When we delete |
| 125 | # lines, we just blank the line and keep it in the list. When we add lines, |
| 126 | # we just prepend the added source code to the start of the existing line at |
| 127 | # that line number. This way, all the line numbers we cached from calls to |
| 128 | # Add and Delete remain valid list indices, and we don't have to worry about |
| 129 | # maintaining any offsets. Each element of file_lines at the end may |
| 130 | # contain any number of lines (0 or more) delimited by carriage returns. |
| 131 | for linenum_to_delete in self.linenums_to_delete: |
| 132 | file_lines[linenum_to_delete] = ""; |
| 133 | for linenum, sourcelines in self.lines_to_add.items(): |
| 134 | # Sort the lines we're adding so we get relatively consistent results. |
| 135 | sourcelines.sort() |
| 136 | # Prepend the new lines. When we output |
| 137 | file_lines[linenum] = "".join(sourcelines) + file_lines[linenum] |
| 138 | newsource = open(self.filename, "w") |
| 139 | for line in file_lines: |
| 140 | newsource.write(line) |
| 141 | newsource.close() |
| 142 | |
| 143 | |
| 144 | def CheckAndInsert(typeinfo, typeinfo_map): |
| 145 | """Check if a TypeInfo exists already in the given map with the same name. If |
| 146 | so, make sure the size is consistent. |
| 147 | - If the name exists but the sizes do not match, print a message and |
| 148 | exit with non-zero exit code. |
| 149 | - If the name exists and the sizes match, do nothing. |
| 150 | - If the name does not exist, insert the typeinfo in to the map. |
| 151 | |
| 152 | """ |
| 153 | # If the type is unnamed, ignore it. |
| 154 | if typeinfo.name == "": |
| 155 | return |
| 156 | # If the size is 0, ignore it. |
| 157 | elif int(typeinfo.size) == 0: |
| 158 | return |
| 159 | # If the type is not defined under ppapi, ignore it. |
| 160 | elif typeinfo.source_location.filename.find("ppapi") == -1: |
| 161 | return |
| 162 | # If the type is defined under GLES2, ignore it. |
| 163 | elif typeinfo.source_location.filename.find("GLES2") > -1: |
| 164 | return |
| 165 | # If the type is an interface (by convention, starts with PPP_ or PPB_), |
| 166 | # ignore it. |
| 167 | elif (typeinfo.name[:4] == "PPP_") or (typeinfo.name[:4] == "PPB_"): |
| 168 | return |
| 169 | elif typeinfo.name in typeinfo_map: |
| 170 | if typeinfo.size != typeinfo_map[typeinfo.name].size: |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 171 | print("Error: '" + typeinfo.name + "' is", \ |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 172 | typeinfo_map[typeinfo.name].size, \ |
| 173 | "bytes on target '" + typeinfo_map[typeinfo.name].target + \ |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 174 | "', but", typeinfo.size, "on target '" + typeinfo.target + "'") |
| 175 | print(typeinfo_map[typeinfo.name].parsed_line) |
| 176 | print(typeinfo.parsed_line) |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 177 | sys.exit(1) |
| 178 | else: |
| 179 | # It's already in the map and the sizes match. |
| 180 | pass |
| 181 | else: |
| 182 | typeinfo_map[typeinfo.name] = typeinfo |
| 183 | |
| 184 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 185 | def ProcessTarget(clang_command, target, types): |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 186 | """Run clang using the given clang_command for the given target string. Parse |
| 187 | the output to create TypeInfos for each discovered type. Insert each type in |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 188 | to the 'types' dictionary. If the type already exists in the types |
| 189 | dictionary, make sure that the size matches what's already in the map. If |
| 190 | not, exit with an error message. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 191 | """ |
| 192 | p = subprocess.Popen(clang_command + " -triple " + target, |
| 193 | shell=True, |
| 194 | stdout=subprocess.PIPE) |
| 195 | lines = p.communicate()[0].split() |
| 196 | for line in lines: |
| 197 | typeinfo = TypeInfo(line, target) |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 198 | CheckAndInsert(typeinfo, types) |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 199 | |
| 200 | |
| 201 | def ToAssertionCode(typeinfo): |
| 202 | """Convert the TypeInfo to an appropriate C compile assertion. |
| 203 | If it's a struct (Record in Clang terminology), we want a line like this: |
| 204 | PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(<name>, <size>);\n |
| 205 | Enums: |
| 206 | PP_COMPILE_ASSERT_ENUM_SIZE_IN_BYTES(<name>, <size>);\n |
| 207 | Typedefs: |
| 208 | PP_COMPILE_ASSERT_SIZE_IN_BYTES(<name>, <size>);\n |
| 209 | |
| 210 | """ |
| 211 | line = "PP_COMPILE_ASSERT_" |
| 212 | if typeinfo.kind == "Enum": |
| 213 | line += "ENUM_" |
| 214 | elif typeinfo.kind == "Record": |
| 215 | line += "STRUCT_" |
| 216 | line += "SIZE_IN_BYTES(" |
| 217 | line += typeinfo.name |
| 218 | line += ", " |
| 219 | line += typeinfo.size |
| 220 | line += ");\n" |
| 221 | return line |
| 222 | |
| 223 | |
| 224 | def IsMacroDefinedName(typename): |
| 225 | """Return true iff the given typename came from a PPAPI compile assertion.""" |
| 226 | return typename.find("PP_Dummy_Struct_For_") == 0 |
| 227 | |
| 228 | |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 229 | def WriteArchSpecificCode(types, root, filename): |
| 230 | """Write a header file that contains a compile-time assertion for the size of |
| 231 | each of the given typeinfos, in to a file named filename rooted at root. |
| 232 | """ |
| 233 | assertion_lines = [ToAssertionCode(typeinfo) for typeinfo in types] |
| 234 | assertion_lines.sort() |
| 235 | outfile = open(os.path.join(root, filename), "w") |
| 236 | header_guard = "PPAPI_TESTS_" + filename.upper().replace(".", "_") + "_" |
| 237 | outfile.write(COPYRIGHT_STRING_C) |
| 238 | outfile.write('#ifndef ' + header_guard + '\n') |
| 239 | outfile.write('#define ' + header_guard + '\n\n') |
| 240 | outfile.write('#include "ppapi/tests/test_struct_sizes.c"\n\n') |
| 241 | for line in assertion_lines: |
| 242 | outfile.write(line) |
| 243 | outfile.write('\n#endif /* ' + header_guard + ' */\n') |
| 244 | |
| 245 | |
| 246 | def main(argv): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 247 | # See README file for example command-line invocation. This script runs the |
| 248 | # PrintNamesAndSizes Clang plugin with 'test_struct_sizes.c' as input, which |
| 249 | # should include all C headers and all existing size checks. It runs the |
| 250 | # plugin multiple times; once for each of a set of targets, some 32-bit and |
| 251 | # some 64-bit. It verifies that wherever possible, types have a consistent |
| 252 | # size on both platforms. Types that can't easily have consistent size (e.g. |
| 253 | # ones that contain a pointer) are checked to make sure they are consistent |
| 254 | # for all 32-bit platforms and consistent on all 64-bit platforms, but the |
| 255 | # sizes on 32 vs 64 are allowed to differ. |
| 256 | # |
| 257 | # Then, if all the types have consistent size as expected, compile assertions |
| 258 | # are added to the source code. Types whose size is independent of |
| 259 | # architectureacross have their compile assertions placed immediately after |
| 260 | # their definition in the C API header. Types whose size differs on 32-bit |
| 261 | # vs 64-bit have a compile assertion placed in each of: |
| 262 | # ppapi/tests/arch_dependent_sizes_32.h and |
| 263 | # ppapi/tests/arch_dependent_sizes_64.h. |
| 264 | # |
| 265 | # Note that you should always check the results of the tool to make sure |
| 266 | # they are sane. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 267 | parser = optparse.OptionParser() |
| 268 | parser.add_option( |
| 269 | '-c', '--clang-path', dest='clang_path', |
| 270 | default=(''), |
| 271 | help='the path to the clang binary (default is to get it from your path)') |
| 272 | parser.add_option( |
| 273 | '-p', '--plugin', dest='plugin', |
| 274 | default='tests/clang/libPrintNamesAndSizes.so', |
| 275 | help='The path to the PrintNamesAndSizes plugin library.') |
| 276 | parser.add_option( |
| 277 | '--targets32', dest='targets32', |
| 278 | default='i386-pc-linux,arm-pc-linux,i386-pc-win32', |
| 279 | help='Which 32-bit target triples to provide to clang.') |
| 280 | parser.add_option( |
| 281 | '--targets64', dest='targets64', |
| 282 | default='x86_64-pc-linux,x86_64-pc-win', |
| 283 | help='Which 32-bit target triples to provide to clang.') |
| 284 | parser.add_option( |
| 285 | '-r', '--ppapi-root', dest='ppapi_root', |
| 286 | default='.', |
| 287 | help='The root directory of ppapi.') |
| 288 | options, args = parser.parse_args(argv) |
| 289 | if args: |
| 290 | parser.print_help() |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 291 | print('ERROR: invalid argument') |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 292 | sys.exit(1) |
| 293 | |
| 294 | clang_executable = os.path.join(options.clang_path, 'clang') |
| 295 | clang_command = clang_executable + " -cc1" \ |
| 296 | + " -load " + options.plugin \ |
| 297 | + " -plugin PrintNamesAndSizes" \ |
| 298 | + " -I" + os.path.join(options.ppapi_root, "..") \ |
| 299 | + " " \ |
| 300 | + os.path.join(options.ppapi_root, "tests", "test_struct_sizes.c") |
| 301 | |
| 302 | # Dictionaries mapping type names to TypeInfo objects. |
| 303 | # Types that have size dependent on architecture, for 32-bit |
| 304 | types32 = {} |
| 305 | # Types that have size dependent on architecture, for 64-bit |
| 306 | types64 = {} |
| 307 | # Note that types32 and types64 should contain the same types, but with |
| 308 | # different sizes. |
| 309 | |
| 310 | # Types whose size should be consistent regardless of architecture. |
| 311 | types_independent = {} |
| 312 | |
| 313 | # Now run clang for each target. Along the way, make sure architecture- |
| 314 | # dependent types are consistent sizes on all 32-bit platforms and consistent |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 315 | # on all 64-bit platforms. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 316 | targets32 = options.targets32.split(','); |
| 317 | for target in targets32: |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 318 | # For each 32-bit target, run the PrintNamesAndSizes Clang plugin to get |
| 319 | # information about all types in the translation unit, and add a TypeInfo |
| 320 | # for each of them to types32. If any size mismatches are found, |
| 321 | # ProcessTarget will spit out an error and exit. |
| 322 | ProcessTarget(clang_command, target, types32) |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 323 | targets64 = options.targets64.split(','); |
| 324 | for target in targets64: |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 325 | # Do the same as above for each 64-bit target; put all types in types64. |
| 326 | ProcessTarget(clang_command, target, types64) |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 327 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 328 | # Now for each dictionary, find types whose size are consistent regardless of |
| 329 | # architecture, and move those in to types_independent. Anywhere sizes |
| 330 | # differ, make sure they are expected to be architecture-dependent based on |
| 331 | # their structure. If we find types which could easily be consistent but |
| 332 | # aren't, spit out an error and exit. |
| 333 | types_independent = {} |
| 334 | for typename, typeinfo32 in types32.items(): |
| 335 | if (typename in types64): |
| 336 | typeinfo64 = types64[typename] |
| 337 | if (typeinfo64.size == typeinfo32.size): |
| 338 | # The types are the same size, so we can treat it as arch-independent. |
| 339 | types_independent[typename] = typeinfo32 |
| 340 | del types32[typename] |
| 341 | del types64[typename] |
| 342 | elif (typeinfo32.arch_dependent or typeinfo64.arch_dependent): |
| 343 | # The type is defined in such a way that it would be difficult to make |
| 344 | # its size consistent. E.g., it has pointers. We'll leave it in the |
| 345 | # arch-dependent maps so that we can put arch-dependent size checks in |
| 346 | # test code. |
| 347 | pass |
| 348 | else: |
| 349 | # The sizes don't match, but there's no reason they couldn't. It's |
| 350 | # probably due to an alignment mismatch between Win32/NaCl vs Linux32/ |
| 351 | # Mac32. |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 352 | print("Error: '" + typename + "' is", typeinfo32.size, \ |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 353 | "bytes on target '" + typeinfo32.target + \ |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 354 | "', but", typeinfo64.size, "on target '" + typeinfo64.target + "'") |
| 355 | print(typeinfo32.parsed_line) |
| 356 | print(typeinfo64.parsed_line) |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 357 | sys.exit(1) |
| 358 | else: |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 359 | print("WARNING: Type '", typename, "' was defined for target '") |
| 360 | print(typeinfo32.target, ", but not for any 64-bit targets.") |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 361 | |
| 362 | # Now we have all the information we need to generate our static assertions. |
| 363 | # Types that have consistent size across architectures will have the static |
| 364 | # assertion placed immediately after their definition. Types whose size |
| 365 | # depends on 32-bit vs 64-bit architecture will have checks placed in |
| 366 | # tests/arch_dependent_sizes_32/64.h. |
| 367 | |
| 368 | # This dictionary maps file names to FilePatch objects. We will add items |
| 369 | # to it as needed. Each FilePatch represents a set of changes to make to the |
| 370 | # associated file (additions and deletions). |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 371 | file_patches = {} |
| 372 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 373 | # Find locations of existing macros, and just delete them all. Note that |
| 374 | # normally, only things in 'types_independent' need to be deleted, as arch- |
| 375 | # dependent checks exist in tests/arch_dependent_sizes_32/64.h, which are |
| 376 | # always completely over-ridden. However, it's possible that a type that used |
| 377 | # to be arch-independent has changed to now be arch-dependent (e.g., because |
| 378 | # a pointer was added), and we want to delete the old check in that case. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 379 | for name, typeinfo in \ |
| 380 | types_independent.items() + types32.items() + types64.items(): |
| 381 | if IsMacroDefinedName(name): |
| 382 | sourcefile = typeinfo.source_location.filename |
| 383 | if sourcefile not in file_patches: |
| 384 | file_patches[sourcefile] = FilePatch(sourcefile) |
| 385 | file_patches[sourcefile].Delete(typeinfo.source_location.start_line, |
| 386 | typeinfo.source_location.end_line+1) |
| 387 | |
| 388 | # Add a compile-time assertion for each type whose size is independent of |
| 389 | # architecture. These assertions go immediately after the class definition. |
| 390 | for name, typeinfo in types_independent.items(): |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 391 | # Ignore dummy types that were defined by macros and also ignore types that |
| 392 | # are 0 bytes (i.e., typedefs to void). |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 393 | if not IsMacroDefinedName(name) and typeinfo.size > 0: |
| 394 | sourcefile = typeinfo.source_location.filename |
| 395 | if sourcefile not in file_patches: |
| 396 | file_patches[sourcefile] = FilePatch(sourcefile) |
| 397 | # Add the assertion code just after the definition of the type. |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 398 | # E.g.: |
| 399 | # struct Foo { |
| 400 | # int32_t x; |
| 401 | # }; |
| 402 | # PP_COMPILE_ASSERT_STRUCT_SIZE_IN_BYTES(Foo, 4); <---Add this line |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 403 | file_patches[sourcefile].Add(ToAssertionCode(typeinfo), |
| 404 | typeinfo.source_location.end_line+1) |
| 405 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 406 | # Apply our patches. This actually edits the files containing the definitions |
| 407 | # for the types in types_independent. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 408 | for filename, patch in file_patches.items(): |
| 409 | patch.Apply() |
| 410 | |
[email protected] | 01fbb66 | 2010-12-22 15:42:15 | [diff] [blame] | 411 | # Write out a file of checks for 32-bit architectures and a separate file for |
| 412 | # 64-bit architectures. These only have checks for types that are |
| 413 | # architecture-dependent. |
[email protected] | 8b3adbb | 2010-12-16 23:23:03 | [diff] [blame] | 414 | c_source_root = os.path.join(options.ppapi_root, "tests") |
| 415 | WriteArchSpecificCode(types32.values(), |
| 416 | c_source_root, |
| 417 | "arch_dependent_sizes_32.h") |
| 418 | WriteArchSpecificCode(types64.values(), |
| 419 | c_source_root, |
| 420 | "arch_dependent_sizes_64.h") |
| 421 | |
| 422 | return 0 |
| 423 | |
| 424 | |
| 425 | if __name__ == '__main__': |
Raul Tambre | a4895d8 | 2019-04-08 19:18:26 | [diff] [blame] | 426 | sys.exit(main(sys.argv[1:])) |