Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: pylib/gyp/mac_tool.py

Issue 1745173002: Add support for iOS Frameworks with header maps. (Closed) Base URL: https://chromium.googlesource.com/external/gyp.git@master
Patch Set: rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | pylib/gyp/xcode_emulation.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 Google Inc. All rights reserved. 2 # Copyright (c) 2012 Google Inc. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Utility functions to perform Xcode-style build steps. 6 """Utility functions to perform Xcode-style build steps.
7 7
8 These functions are executed via gyp-mac-tool when using the Makefile generator. 8 These functions are executed via gyp-mac-tool when using the Makefile generator.
9 """ 9 """
10 10
11 import fcntl 11 import fcntl
12 import fnmatch 12 import fnmatch
13 import glob 13 import glob
14 import json 14 import json
15 import os 15 import os
16 import plistlib 16 import plistlib
17 import re 17 import re
18 import shutil 18 import shutil
19 import string 19 import string
20 import struct
20 import subprocess 21 import subprocess
21 import sys 22 import sys
22 import tempfile 23 import tempfile
23 24
24 25
25 def main(args): 26 def main(args):
26 executor = MacTool() 27 executor = MacTool()
27 exit_code = executor.Dispatch(args) 28 exit_code = executor.Dispatch(args)
28 if exit_code is not None: 29 if exit_code is not None:
29 sys.exit(exit_code) 30 sys.exit(exit_code)
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 print >>sys.stderr, line 266 print >>sys.stderr, line
266 # Unconditionally touch the output .a file on the command line if present 267 # Unconditionally touch the output .a file on the command line if present
267 # and the command succeeded. A bit hacky. 268 # and the command succeeded. A bit hacky.
268 if not libtoolout.returncode: 269 if not libtoolout.returncode:
269 for i in range(len(cmd_list) - 1): 270 for i in range(len(cmd_list) - 1):
270 if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'): 271 if cmd_list[i] == "-o" and cmd_list[i+1].endswith('.a'):
271 os.utime(cmd_list[i+1], None) 272 os.utime(cmd_list[i+1], None)
272 break 273 break
273 return libtoolout.returncode 274 return libtoolout.returncode
274 275
276 def ExecPackageIosFramework(self, framework):
277 # Find the name of the binary based on the part before the ".framework".
278 binary = os.path.basename(framework).split('.')[0]
279 module_path = os.path.join(framework, 'Modules');
280 if not os.path.exists(module_path):
281 os.mkdir(module_path)
282 module_template = 'framework module %s {\n' \
283 ' umbrella header "%s.h"\n' \
284 '\n' \
285 ' export *\n' \
286 ' module * { export * }\n' \
287 '}\n' % (binary, binary)
288
289 module_file = open(os.path.join(module_path, 'module.modulemap'), "w")
290 module_file.write(module_template)
291 module_file.close()
292
293
275 def ExecPackageFramework(self, framework, version): 294 def ExecPackageFramework(self, framework, version):
276 """Takes a path to Something.framework and the Current version of that and 295 """Takes a path to Something.framework and the Current version of that and
277 sets up all the symlinks.""" 296 sets up all the symlinks."""
278 # Find the name of the binary based on the part before the ".framework". 297 # Find the name of the binary based on the part before the ".framework".
279 binary = os.path.basename(framework).split('.')[0] 298 binary = os.path.basename(framework).split('.')[0]
280 299
281 CURRENT = 'Current' 300 CURRENT = 'Current'
282 RESOURCES = 'Resources' 301 RESOURCES = 'Resources'
283 VERSIONS = 'Versions' 302 VERSIONS = 'Versions'
284 303
(...skipping 16 matching lines...) Expand all
301 # Back to where we were before! 320 # Back to where we were before!
302 os.chdir(pwd) 321 os.chdir(pwd)
303 322
304 def _Relink(self, dest, link): 323 def _Relink(self, dest, link):
305 """Creates a symlink to |dest| named |link|. If |link| already exists, 324 """Creates a symlink to |dest| named |link|. If |link| already exists,
306 it is overwritten.""" 325 it is overwritten."""
307 if os.path.lexists(link): 326 if os.path.lexists(link):
308 os.remove(link) 327 os.remove(link)
309 os.symlink(dest, link) 328 os.symlink(dest, link)
310 329
330 def ExecCompileIosFrameworkHeaderMap(self, out, framework, *all_headers):
331 framework_name = os.path.basename(framework).split('.')[0]
332 all_headers = map(os.path.abspath, all_headers)
333 filelist = {}
334 for header in all_headers:
335 filename = os.path.basename(header)
336 filelist[filename] = header
337 filelist[os.path.join(framework_name, filename)] = header
338 self._writeHmap(out, filelist)
339
340 def ExecCopyIosFrameworkHeaders(self, framework, *copy_headers):
341 header_path = os.path.join(framework, 'Headers');
342 if not os.path.exists(header_path):
343 os.makedirs(header_path)
344 for header in copy_headers:
345 shutil.copy2(header, os.path.join(header_path, os.path.basename(header)))
346
311 def ExecCompileXcassets(self, keys, *inputs): 347 def ExecCompileXcassets(self, keys, *inputs):
312 """Compiles multiple .xcassets files into a single .car file. 348 """Compiles multiple .xcassets files into a single .car file.
313 349
314 This invokes 'actool' to compile all the inputs .xcassets files. The 350 This invokes 'actool' to compile all the inputs .xcassets files. The
315 |keys| arguments is a json-encoded dictionary of extra arguments to 351 |keys| arguments is a json-encoded dictionary of extra arguments to
316 pass to 'actool' when the asset catalogs contains an application icon 352 pass to 'actool' when the asset catalogs contains an application icon
317 or a launch image. 353 or a launch image.
318 354
319 Note that 'actool' does not create the Assets.car file if the asset 355 Note that 'actool' does not create the Assets.car file if the asset
320 catalogs does not contains imageset. 356 catalogs does not contains imageset.
(...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 if isinstance(data, str): 630 if isinstance(data, str):
595 for key, value in substitutions.iteritems(): 631 for key, value in substitutions.iteritems():
596 data = data.replace('$(%s)' % key, value) 632 data = data.replace('$(%s)' % key, value)
597 return data 633 return data
598 if isinstance(data, list): 634 if isinstance(data, list):
599 return [self._ExpandVariables(v, substitutions) for v in data] 635 return [self._ExpandVariables(v, substitutions) for v in data]
600 if isinstance(data, dict): 636 if isinstance(data, dict):
601 return {k: self._ExpandVariables(data[k], substitutions) for k in data} 637 return {k: self._ExpandVariables(data[k], substitutions) for k in data}
602 return data 638 return data
603 639
640 def _next_greater_power_of_2(self, x):
sdefresne 2016/03/15 14:14:33 This does not need to be an instance method, can b
justincohen 2016/03/17 02:49:05 Done.
641 return 2**(x-1).bit_length()
642
643 def _writeHmap(self, output_name, filelist):
sdefresne 2016/03/15 14:14:33 This does not need to be an instance method, can b
justincohen 2016/03/17 02:49:05 Done.
644 magic = 1751998832
645 version = 1
646 _reserved = 0
647 count = len(filelist)
648 capacity = self._next_greater_power_of_2(count)
649 strings_offset = 24 + (12 * capacity)
650 max_value_length = len(max(filelist.items(), key=lambda (k,v):len(v))[1])
651
652 out = open(output_name, "wb")
653 out.write(struct.pack('<LHHLLLL', magic, version, _reserved, strings_offset,
654 count, capacity, max_value_length))
655
656 # Create empty hashmap buckets.
657 buckets = [None] * capacity
658 for file, path in filelist.items():
659 key = 0
660 for c in file:
661 key += ord(c.lower()) * 13
662
663 # Fill next empty bucket.
664 while buckets[key & capacity - 1] is not None:
665 key = key + 1
666 buckets[key & capacity - 1] = (file, path)
667
668 next_offset = 1
669 for bucket in buckets:
670 if bucket is None:
671 out.write(struct.pack('<LLL', 0, 0, 0))
672 else:
673 (file, path) = bucket
674 key_offset = next_offset
675 prefix_offset = key_offset + len(file) + 1
676 suffix_offset = prefix_offset + len(os.path.dirname(path) + os.sep) + 1
677 next_offset = suffix_offset + len(os.path.basename(path)) + 1
678 out.write(struct.pack('<LLL', key_offset, prefix_offset, suffix_offset))
679
680 # Pad byte since next offset starts at 1.
681 out.write(struct.pack('<x'))
682
683 for bucket in buckets:
684 if bucket is not None:
685 (file, path) = bucket
686 out.write(struct.pack('<%ds' % len(file), file))
687 out.write(struct.pack('<s', '\0'))
688 base = os.path.dirname(path) + os.sep
689 out.write(struct.pack('<%ds' % len(base), base))
690 out.write(struct.pack('<s', '\0'))
691 path = os.path.basename(path)
692 out.write(struct.pack('<%ds' % len(path), path))
693 out.write(struct.pack('<s', '\0'))
694
604 if __name__ == '__main__': 695 if __name__ == '__main__':
605 sys.exit(main(sys.argv[1:])) 696 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « pylib/gyp/generator/ninja.py ('k') | pylib/gyp/xcode_emulation.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698