OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright 2015 The Chromium Authors. All rights reserved. | 2 # Copyright 2015 The Chromium Authors. 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 import argparse | 6 import argparse |
7 import logging | 7 import logging |
8 import os | 8 import os |
9 import sys | 9 import sys |
10 import subprocess | 10 import subprocess |
| 11 import json |
| 12 |
| 13 |
| 14 def library_paths(build_dir): |
| 15 for name in os.listdir(build_dir): |
| 16 path = os.path.realpath(os.path.join(build_dir, name)) |
| 17 if not os.path.isfile(path): |
| 18 continue |
| 19 |
| 20 # Only include suffixes we care about: |
| 21 basename, ext = os.path.splitext(name) |
| 22 if ext not in ('', '.mojo', '.so'): |
| 23 continue |
| 24 |
| 25 # Ignore ninja's dot-files. |
| 26 if basename.startswith('.'): |
| 27 continue |
| 28 yield path |
| 29 |
| 30 |
| 31 def get_cached_app_id(path, cache, cache_mtime): |
| 32 if not cache_mtime: |
| 33 return None |
| 34 try: |
| 35 if os.path.getmtime(path) > cache_mtime: |
| 36 return None |
| 37 except: |
| 38 return None |
| 39 return cache.get(path) |
| 40 |
| 41 |
| 42 def compute_path_to_app_id_map(paths, cache, cache_mtime): |
| 43 path_to_app_id_map = {} |
| 44 for path in paths: |
| 45 app_id = get_cached_app_id(path, cache, cache_mtime) |
| 46 if not app_id: |
| 47 logging.info('md5sum %s' % path) |
| 48 # Example output: |
| 49 # f82a3551478a9a0e010adccd675053b9 png_viewer.mojo |
| 50 output = subprocess.check_output(['md5sum', path]) |
| 51 app_id = output.strip().split()[0] |
| 52 path_to_app_id_map[path] = app_id |
| 53 return path_to_app_id_map |
| 54 |
| 55 |
| 56 def read_app_id_cache(cache_path): |
| 57 try: |
| 58 with open(cache_path, 'r') as cache_file: |
| 59 return json.load(cache_file), os.path.getmtime(cache_path) |
| 60 except: |
| 61 logging.warn('Failed to read file: %s' % cache_path) |
| 62 return {}, None |
| 63 |
| 64 |
| 65 def write_app_id_cache(cache_path, cache): |
| 66 try: |
| 67 with open(cache_path, 'w') as cache_file: |
| 68 json.dump(cache, cache_file, indent=2, sort_keys=True) |
| 69 except: |
| 70 logging.warn('Failed to write file: %s' % cache_path) |
| 71 |
11 | 72 |
12 # TODO(eseidel): Share logic with tools/android_stack_parser/stack | 73 # TODO(eseidel): Share logic with tools/android_stack_parser/stack |
13 def main(): | 74 def main(): |
14 logging.basicConfig(level=logging.INFO) | 75 logging.basicConfig(level=logging.WARN) |
15 parser = argparse.ArgumentParser( | 76 parser = argparse.ArgumentParser( |
16 description='Builds a directory of app_id symlinks to symbols' | 77 description='Builds a directory of app_id symlinks to symbols' |
17 ' to match expected dlopen names from mojo_shell\'s NetworkLoader.') | 78 ' to match expected dlopen names from mojo_shell\'s NetworkLoader.') |
18 parser.add_argument('links_dir', type=str) | 79 parser.add_argument('links_dir', type=str) |
19 parser.add_argument('build_dir', type=str) | 80 parser.add_argument('build_dir', type=str) |
20 args = parser.parse_args() | 81 args = parser.parse_args() |
21 | 82 |
22 if not os.path.isdir(args.links_dir): | 83 if not os.path.isdir(args.links_dir): |
23 logging.fatal('links_dir: %s is not a directory' % args.links_dir) | 84 logging.fatal('links_dir: %s is not a directory' % args.links_dir) |
24 sys.exit(1) | 85 sys.exit(1) |
25 | 86 |
26 for name in os.listdir(args.build_dir): | 87 # Some of the .so files are 100s of megabytes. Cache the md5s to save time. |
27 path = os.path.join(args.build_dir, name) | 88 cache_path = os.path.join(args.build_dir, '.app_id_cache') |
28 if not os.path.isfile(path): | 89 cache, cache_mtime = read_app_id_cache(cache_path) |
29 continue | |
30 | 90 |
31 # md5sum is slow, so only bother for suffixes we care about: | 91 paths = library_paths(args.build_dir) |
32 basename, ext = os.path.splitext(name) | 92 path_to_app_id_map = compute_path_to_app_id_map(list(paths), |
33 if ext not in ('', '.mojo', '.so'): | 93 cache, cache_mtime) |
34 continue | |
35 | 94 |
36 # Ignore ninja's dot-files. | 95 # The cache contains unmodified app-ids. |
37 if basename.startswith('.'): | 96 write_app_id_cache(cache_path, path_to_app_id_map) |
38 continue | |
39 | 97 |
40 # Example output: | 98 for path, app_id in path_to_app_id_map.items(): |
41 # f82a3551478a9a0e010adccd675053b9 png_viewer.mojo | 99 basename = os.path.basename(path) |
42 md5 = subprocess.check_output(['md5sum', path]).strip().split()[0] | 100 root_name, ext = os.path.splitext(basename) |
43 link_path = os.path.join(args.links_dir, '%s.mojo' % md5) | |
44 | |
45 lib_path = os.path.realpath(os.path.join(args.build_dir, name)) | |
46 | 101 |
47 # On android foo.mojo is stripped, but libfoo_library.so is not. | 102 # On android foo.mojo is stripped, but libfoo_library.so is not. |
48 if ext == '.mojo': | 103 if ext == '.mojo': |
49 symboled_name = 'lib%s_library.so' % basename | 104 symboled_name = 'lib%s_library.so' % root_name |
50 symboled_path = os.path.realpath( | 105 symboled_path = os.path.realpath( |
51 os.path.join(args.build_dir, symboled_name)) | 106 os.path.join(args.build_dir, symboled_name)) |
52 if os.path.exists(symboled_path): | 107 if os.path.exists(symboled_path): |
53 lib_path = symboled_path | 108 path = symboled_path |
54 | 109 |
55 print "%s -> %s" % (link_path, lib_path) | 110 link_path = os.path.join(args.links_dir, '%s.mojo' % app_id) |
| 111 |
| 112 logging.info("%s -> %s" % (link_path, path)) |
56 | 113 |
57 if os.path.lexists(link_path): | 114 if os.path.lexists(link_path): |
58 logging.debug('link already exists %s, replacing' % lib_path) | 115 logging.debug('link already exists %s, replacing' % path) |
59 os.unlink(link_path) | 116 os.unlink(link_path) |
60 | 117 |
61 os.symlink(lib_path, link_path) | 118 os.symlink(path, link_path) |
| 119 |
62 | 120 |
63 if __name__ == '__main__': | 121 if __name__ == '__main__': |
64 main() | 122 main() |
OLD | NEW |