blob: 783377479eaf2665bf1f77e6d008ddef875b66cd [file] [log] [blame]
#!/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()