| #!/usr/bin/env python |
| # Copyright 2015 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 argparse |
| import logging |
| import os |
| import sys |
| import subprocess |
| import json |
| import platform |
| |
| |
| def library_paths(build_dir): |
| for name in os.listdir(build_dir): |
| path = os.path.realpath(os.path.join(build_dir, name)) |
| if not os.path.isfile(path): |
| continue |
| |
| # Only include suffixes we care about: |
| basename, ext = os.path.splitext(name) |
| if ext not in ('', '.mojo', '.so'): |
| continue |
| |
| # Ignore ninja's dot-files. |
| if basename.startswith('.'): |
| continue |
| yield path |
| |
| |
| def get_cached_app_id(path, cache, cache_mtime): |
| if not cache_mtime: |
| return None |
| try: |
| if os.path.getmtime(path) > cache_mtime: |
| return None |
| except: |
| return None |
| return cache.get(path) |
| |
| |
| def compute_path_to_app_id_map(paths, cache, cache_mtime): |
| path_to_app_id_map = {} |
| for path in paths: |
| app_id = get_cached_app_id(path, cache, cache_mtime) |
| if not app_id: |
| if platform.system() == 'Darwin': |
| logging.info('shasum -a 256 %s' % path) |
| output = subprocess.check_output(['shasum', '-a', '256', path]) |
| else: |
| logging.info('sha256sum %s' % path) |
| output = subprocess.check_output(['sha256sum', path]) |
| # Example output: |
| # f82a3551478a9a0e010adccd675053b9 png_viewer.mojo |
| app_id = output.strip().split()[0] |
| path_to_app_id_map[path] = app_id |
| return path_to_app_id_map |
| |
| |
| def read_app_id_cache(cache_path): |
| try: |
| with open(cache_path, 'r') as cache_file: |
| return json.load(cache_file), os.path.getmtime(cache_path) |
| except: |
| logging.warn('Failed to read file: %s' % cache_path) |
| return {}, None |
| |
| |
| def write_app_id_cache(cache_path, cache): |
| try: |
| with open(cache_path, 'w') as cache_file: |
| json.dump(cache, cache_file, indent=2, sort_keys=True) |
| except: |
| logging.warn('Failed to write file: %s' % cache_path) |
| |
| |
| # TODO(eseidel): Share logic with tools/android_stack_parser/stack |
| def main(): |
| logging.basicConfig(level=logging.WARN) |
| parser = argparse.ArgumentParser( |
| description='Builds a directory of app_id symlinks to symbols' |
| ' to match expected dlopen names from mojo_shell\'s NetworkLoader.') |
| parser.add_argument('links_dir', type=str) |
| parser.add_argument('build_dir', type=str) |
| parser.add_argument('-f', '--force', action='store_true') |
| parser.add_argument('-v', '--verbose', action='store_true') |
| args = parser.parse_args() |
| |
| if args.verbose: |
| logging.getLogger().setLevel(logging.INFO) |
| |
| if not os.path.isdir(args.links_dir): |
| logging.fatal('links_dir: %s is not a directory' % args.links_dir) |
| sys.exit(1) |
| |
| # Some of the .so files are 100s of megabytes. Cache the md5s to save time. |
| cache_path = os.path.join(args.build_dir, '.app_id_cache') |
| cache, cache_mtime = read_app_id_cache(cache_path) |
| if args.force: |
| cache_mtime = None |
| |
| paths = library_paths(args.build_dir) |
| path_to_app_id_map = compute_path_to_app_id_map(list(paths), |
| cache, cache_mtime) |
| |
| # The cache contains unmodified app-ids. |
| write_app_id_cache(cache_path, path_to_app_id_map) |
| |
| for path, app_id in path_to_app_id_map.items(): |
| basename = os.path.basename(path) |
| root_name, ext = os.path.splitext(basename) |
| |
| # On android foo.mojo is stripped, but libfoo_library.so is not. |
| if ext == '.mojo': |
| symboled_name = 'lib%s_library.so' % root_name |
| symboled_path = os.path.realpath( |
| os.path.join(args.build_dir, symboled_name)) |
| if os.path.exists(symboled_path): |
| path = symboled_path |
| |
| link_path = os.path.join(args.links_dir, '%s.mojo' % app_id) |
| |
| logging.info("%s -> %s" % (link_path, path)) |
| |
| if os.path.lexists(link_path): |
| logging.debug('link already exists %s, replacing' % path) |
| os.unlink(link_path) |
| |
| os.symlink(path, link_path) |
| |
| |
| if __name__ == '__main__': |
| main() |