Index: build/config/ios/write_framework_hmap.py |
diff --git a/build/config/ios/write_framework_hmap.py b/build/config/ios/write_framework_hmap.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..8f6b1439d0d632d33b3db940f0db65128027dadf |
--- /dev/null |
+++ b/build/config/ios/write_framework_hmap.py |
@@ -0,0 +1,97 @@ |
+# Copyright 2016 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+import os |
+import struct |
+import sys |
+ |
+def Main(args): |
+ if len(args) < 4: |
+ print >> sys.stderr, "Usage: %s output.hmap Foo.framework header1.h..." %\ |
+ (args[0]) |
+ return 1 |
+ |
+ (out, framework, all_headers) = args[1], args[2], args[3:] |
+ |
+ framework_name = os.path.basename(framework).split('.')[0] |
+ all_headers = map(os.path.abspath, all_headers) |
+ filelist = {} |
+ for header in all_headers: |
+ filename = os.path.basename(header) |
+ filelist[filename] = header |
+ filelist[os.path.join(framework_name, filename)] = header |
+ WriteHmap(out, filelist) |
+ return 0 |
+ |
+ |
+def NextGreaterPowerOf2(x): |
+ return 2**(x).bit_length() |
+ |
+ |
+def WriteHmap(output_name, filelist): |
+ """Generates a header map based on |filelist|. |
+ |
+ Per Mark Mentovai: |
+ A header map is structured essentially as a hash table, keyed by names used |
+ in #includes, and providing pathnames to the actual files. |
+ |
+ The implementation below and the comment above comes from inspecting: |
+ http://www.opensource.apple.com/source/distcc/distcc-2503/distcc_dist/include_server/headermap.py?txt |
+ while also looking at the implementation in clang in: |
+ https://llvm.org/svn/llvm-project/cfe/trunk/lib/Lex/HeaderMap.cpp |
+ """ |
+ magic = 1751998832 |
+ version = 1 |
+ _reserved = 0 |
+ count = len(filelist) |
+ capacity = NextGreaterPowerOf2(count) |
+ strings_offset = 24 + (12 * capacity) |
+ max_value_length = len(max(filelist.items(), key=lambda (k,v):len(v))[1]) |
+ |
+ out = open(output_name, 'wb') |
+ out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset, |
+ count, capacity, max_value_length)) |
+ |
+ # Create empty hashmap buckets. |
+ buckets = [None] * capacity |
+ for file, path in filelist.items(): |
+ key = 0 |
+ for c in file: |
+ key += ord(c.lower()) * 13 |
+ |
+ # Fill next empty bucket. |
+ while buckets[key & capacity - 1] is not None: |
+ key = key + 1 |
+ buckets[key & capacity - 1] = (file, path) |
+ |
+ next_offset = 1 |
+ for bucket in buckets: |
+ if bucket is None: |
+ out.write(struct.pack('<LLL', 0, 0, 0)) |
+ else: |
+ (file, path) = bucket |
+ key_offset = next_offset |
+ prefix_offset = key_offset + len(file) + 1 |
+ suffix_offset = prefix_offset + len(os.path.dirname(path) + os.sep) + 1 |
+ next_offset = suffix_offset + len(os.path.basename(path)) + 1 |
+ out.write(struct.pack('<LLL', key_offset, prefix_offset, suffix_offset)) |
+ |
+ # Pad byte since next offset starts at 1. |
+ out.write(struct.pack('<x')) |
+ |
+ for bucket in buckets: |
+ if bucket is not None: |
+ (file, path) = bucket |
+ out.write(struct.pack('<%ds' % len(file), file)) |
+ out.write(struct.pack('<s', '\0')) |
+ base = os.path.dirname(path) + os.sep |
+ out.write(struct.pack('<%ds' % len(base), base)) |
+ out.write(struct.pack('<s', '\0')) |
+ path = os.path.basename(path) |
+ out.write(struct.pack('<%ds' % len(path), path)) |
+ out.write(struct.pack('<s', '\0')) |
+ |
+ |
+if __name__ == '__main__': |
+ sys.exit(Main(sys.argv)) |