From 82e3afa99d1478add461b26e88b67470b2d54eb7 Mon Sep 17 00:00:00 2001 From: Hal Canary Date: Mon, 19 Aug 2019 15:04:24 -0400 Subject: [PATCH] SkQP: split make_apk script into create_apk and make_apk gn_to_bp: wrap defines in ifndef create_apk.py assumes you are either run from the aosp tree, or you are being run from make_universal_apk.py, which now defers to create_apk.py for all functionality, even argument parsing. tools/skqp/generate_gn_args moved some functionity into skqp_gn_args.py, which is now used by create_apk.py create_apk now accepts android sdk license for you. create_apk and make_universal_apk.py now are better about cleaning up after exceptions happen. Old script make_apk.sh now just points at make_universal_apk.py CQ_INCLUDE_TRYBOTS=skia.primary:Build-Debian9-Clang-x86-devrel-Android_SKQP,Test-Debian9-Clang-NUC7i5BNK-CPU-Emulator-x86-devrel-All-Android_SKQP Change-Id: I2dba20ef7017987cabb2bd49f070e2b1594785d5 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/235678 Reviewed-by: Ben Wagner Commit-Queue: Hal Canary --- gn/gn_to_bp_utils.py | 5 +- tools/skqp/create_apk.py | 235 +++++++++++++++++++++++++++++++ tools/skqp/download_model | 71 +--------- tools/skqp/download_model.py | 69 +++++++++ tools/skqp/generate_gn_args | 33 ++--- tools/skqp/make_apk.sh | 48 +------ tools/skqp/make_universal_apk.py | 214 +++------------------------- tools/skqp/skqp_gn_args.py | 13 ++ 8 files changed, 359 insertions(+), 329 deletions(-) create mode 100755 tools/skqp/create_apk.py create mode 100755 tools/skqp/download_model.py diff --git a/gn/gn_to_bp_utils.py b/gn/gn_to_bp_utils.py index 938024cc7d..90acc61eed 100644 --- a/gn/gn_to_bp_utils.py +++ b/gn/gn_to_bp_utils.py @@ -116,4 +116,7 @@ def WriteUserConfig(userConfigPath, defines): print >>f, '#pragma once' print >>f, '#include "SkUserConfigManual.h"' for define in sorted(defines): - print >>f, '#define', define.replace('=', ' ') + print >>f, '' + print >>f, '#ifndef', define.split('=')[0] + print >>f, '#define', define.replace('=', ' ', 1) + print >>f, '#endif' diff --git a/tools/skqp/create_apk.py b/tools/skqp/create_apk.py new file mode 100755 index 0000000000..2f6d94eeb2 --- /dev/null +++ b/tools/skqp/create_apk.py @@ -0,0 +1,235 @@ +#! /usr/bin/env python +# Copyright 2019 Google LLC. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +''' +This script can be run with no arguments, in which case it will produce an +APK with native libraries for all four architectures: arm, arm64, x86, and +x64. You can instead list the architectures you want as arguments to this +script. For example: + + python create_apk.py arm x86 + +The environment variables ANDROID_NDK and ANDROID_HOME must be set to the +locations of the Android NDK and SDK. + +Additionally, `ninja` should be in your path. + +It assumes that the source tree is in the desired state, e.g. by having +run 'python tools/git-sync-deps' in the root of the skia checkout. + +We also assume that the 'resources' directory has been copied to +'platform_tools/android/apps/skqp/src/main/assets', and the +'tools/skqp/download_model' script has been run. + +Also: + * If the environment variable SKQP_BUILD_DIR is set, many of the + intermediate build objects will be placed here. + * If the environment variable SKQP_OUTPUT_DIR is set, the final APK + will be placed in this directory. + * If the environment variable SKQP_DEBUG is set, Skia will be compiled + in debug mode. +''' + +import os +import re +import subprocess +import sys +import shutil +import time + +import skqp_gn_args + +def print_cmd(cmd, o): + m = re.compile('[^A-Za-z0-9_./-]') + o.write('+ ') + for c in cmd: + if m.search(c) is not None: + o.write(repr(c) + ' ') + else: + o.write(c + ' ') + o.write('\n') + o.flush() + +def check_call(cmd, **kwargs): + print_cmd(cmd, sys.stdout) + return subprocess.check_call(cmd, **kwargs) + +def find_name(searchpath, filename): + for dirpath, _, filenames in os.walk(searchpath): + if filename in filenames: + yield os.path.join(dirpath, filename) + +def check_ninja(): + with open(os.devnull, 'w') as devnull: + return subprocess.call(['ninja', '--version'], + stdout=devnull, stderr=devnull) == 0 + +def remove(p): + if not os.path.islink(p) and os.path.isdir(p): + shutil.rmtree(p) + elif os.path.lexists(p): + os.remove(p) + assert not os.path.exists(p) + +def makedirs(dst): + if not os.path.exists(dst): + os.makedirs(dst) + +class RemoveFiles(object): + def __init__(self, *args): + self.args = args + def __enter__(self): + pass + def __exit__(self, a, b, c): + for arg in self.args: + remove(arg) + +class ChDir(object): + def __init__(self, d): + self.orig = os.getcwd() + os.chdir(d) + def __enter__(self): + pass + def __exit__(self, a, b, c): + os.chdir(self.orig) + +def make_symlinked_subdir(target, working_dir): + newdir = os.path.join(working_dir, os.path.basename(target)) + makedirs(newdir) + os.symlink(os.path.relpath(newdir, os.path.dirname(target)), target) + +def accept_android_license(android_home): + proc = subprocess.Popen( + [android_home + '/tools/bin/sdkmanager', '--licenses'], + stdin=subprocess.PIPE) + while proc.poll() is None: + proc.stdin.write('y\n') + time.sleep(1) + +# pylint: disable=bad-whitespace +skia_to_android_arch_name_map = {'arm' : 'armeabi-v7a', + 'arm64': 'arm64-v8a' , + 'x86' : 'x86' , + 'x64' : 'x86_64' } + +def create_apk_impl(opts): + build_dir, final_output_dir = opts.build_dir, opts.final_output_dir + + assert os.path.exists('bin/gn') # Did you `tools/git-syc-deps`? + + for d in [build_dir, final_output_dir]: + makedirs(d) + + apps_dir = 'platform_tools/android/apps' + app = 'skqp' + lib = 'lib%s_app.so' % app + + # These are the locations in the tree where the gradle needs or will create + # not-checked-in files. Treat them specially to keep the tree clean. + remove(build_dir + '/libs') + build_paths = [apps_dir + '/.gradle', + apps_dir + '/' + app + '/build', + apps_dir + '/' + app + '/src/main/libs'] + for path in build_paths: + remove(path) + try: + make_symlinked_subdir(path, build_dir) + except OSError: + sys.stderr.write('failed to create symlink "%s"\n' % path) + + lib_dir = '%s/%s/src/main/libs' % (apps_dir, app) + apk_build_dir = '%s/%s/build/outputs/apk' % (apps_dir, app) + for d in [lib_dir, apk_build_dir]: + shutil.rmtree(d, True) # force rebuild + + with RemoveFiles(*build_paths): + for arch in opts.architectures: + build = os.path.join(build_dir, arch) + gn_args = opts.gn_args(arch) + args = ' '.join('%s=%s' % (k, v) for k, v in gn_args.items()) + check_call(['bin/gn', 'gen', build, '--args=' + args]) + check_call(['ninja', '-C', build, lib]) + dst = '%s/%s' % (lib_dir, skia_to_android_arch_name_map[arch]) + makedirs(dst) + shutil.copy(os.path.join(build, lib), dst) + + accept_android_license(opts.android_home) + env_copy = os.environ.copy() + env_copy['ANDROID_HOME'] = opts.android_home + env_copy['ANDROID_NDK_HOME'] = opts.android_ndk + # Why does gradlew need to be called from this directory? + check_call(['apps/gradlew', '-p' 'apps/' + app, + '-P', 'suppressNativeBuild', + ':%s:assembleUniversalDebug' % app], + env=env_copy, cwd='platform_tools/android') + + apk_name = app + "-universal-debug.apk" + + apk_list = list(find_name(apk_build_dir, apk_name)) + assert len(apk_list) == 1 + + out = os.path.join(final_output_dir, apk_name) + shutil.move(apk_list[0], out) + sys.stdout.write(out + '\n') + + arches = '_'.join(sorted(opts.architectures)) + copy = os.path.join(final_output_dir, "%s-%s-debug.apk" % (app, arches)) + shutil.copyfile(out, copy) + sys.stdout.write(copy + '\n') + + sys.stdout.write('* * * COMPLETE * * *\n\n') + + +def create_apk(opts): + skia_dir = os.path.abspath(os.path.dirname(__file__) + '/../..') + assert os.path.exists(skia_dir) + with ChDir(skia_dir): + create_apk_impl(opts) + +class SkQP_Build_Options(object): + def __init__(self): + assert '/' in [os.sep, os.altsep] # 'a/b' over os.path.join('a', 'b') + self.error = '' + if not check_ninja(): + self.error += '`ninja` is not in the path.\n' + for var in ['ANDROID_NDK', 'ANDROID_HOME']: + if not os.path.exists(os.environ.get(var, '')): + self.error += 'Environment variable `%s` is not set.\n' % var + self.android_ndk = os.path.abspath(os.environ['ANDROID_NDK']) + self.android_home = os.path.abspath(os.environ['ANDROID_HOME']) + args = sys.argv[1:] + for arg in args: + if arg not in skia_to_android_arch_name_map: + self.error += ('Argument %r is not in %r\n' % + (arg, skia_to_android_arch_name_map.keys())) + self.architectures = args if args else skia_to_android_arch_name_map.keys() + default_build = os.path.dirname(__file__) + '/../../out/skqp' + self.build_dir = os.path.abspath(os.environ.get('SKQP_BUILD_DIR', default_build)) + self.final_output_dir = os.path.abspath(os.environ.get('SKQP_OUTPUT_DIR', default_build)) + self.debug = bool(os.environ.get('SKQP_DEBUG', '')) + + def gn_args(self, arch): + return skqp_gn_args.GetGNArgs(arch, self.android_ndk, self.debug, 26) + + def write(self, o): + for k, v in [('ANDROID_NDK', self.android_ndk), + ('ANDROID_HOME', self.android_home), + ('SKQP_OUTPUT_DIR', self.final_output_dir), + ('SKQP_BUILD_DIR', self.build_dir), + ('SKQP_DEBUG', self.debug), + ('Architectures', self.architectures)]: + o.write('%s = %r\n' % (k, v)) + o.flush() + +def main(): + options = SkQP_Build_Options() + if options.error: + sys.stderr.write(options.error + __doc__) + sys.exit(1) + options.write(sys.stdout) + create_apk(options) + +if __name__ == '__main__': + main() diff --git a/tools/skqp/download_model b/tools/skqp/download_model index 209f550590..68ef50daae 100755 --- a/tools/skqp/download_model +++ b/tools/skqp/download_model @@ -1,71 +1,6 @@ #! /usr/bin/env python - -# Copyright 2018 Google Inc. +# Copyright 2019 Google LLC. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - -import hashlib -import multiprocessing -import os -import shutil -import sys -import tempfile -import urllib2 - -def checksum(path): - if not os.path.exists(path): - return None - m = hashlib.md5() - with open(path, 'rb') as f: - while True: - buf = f.read(4096) - if 0 == len(buf): - return m.hexdigest() - m.update(buf) - -def download(md5, path): - if not md5 == checksum(path): - dirname = os.path.dirname(path) - if dirname and not os.path.exists(dirname): - try: - os.makedirs(dirname) - except: - # ignore race condition - if not os.path.exists(dirname): - raise - url = 'https://storage.googleapis.com/skia-skqp-assets/' + md5 - with open(path, 'wb') as o: - shutil.copyfileobj(urllib2.urlopen(url), o) - -def tmp(prefix): - fd, path = tempfile.mkstemp(prefix=prefix) - os.close(fd) - return path - -def main(): - target_dir = os.path.join('platform_tools', 'android', 'apps', 'skqp', 'src', 'main', 'assets') - os.chdir(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, target_dir)) - checksum_path = 'files.checksum' - if not os.path.isfile(checksum_path): - sys.stderr.write('Error: "%s" is missing.\n' % os.path.join(target_dir, checksum_path)) - sys.exit(1) - file_list_file = tmp('files_') - with open(checksum_path, 'r') as f: - md5 = f.read().strip() - assert(len(md5) == 32) - download(md5, file_list_file) - with open(file_list_file, 'r') as f: - records = [] - for line in f: - md5, path = line.strip().split(';', 1) - records.append((md5, path)) - sys.stderr.write('Downloading %d files.\n' % len(records)) - pool = multiprocessing.Pool(processes=multiprocessing.cpu_count() * 2) - for record in records: - pool.apply_async(download, record, callback=lambda x: sys.stderr.write('.')) - pool.close() - pool.join() - sys.stderr.write('\n') - -if __name__ == '__main__': - main() +import download_model +download_model.main() diff --git a/tools/skqp/download_model.py b/tools/skqp/download_model.py new file mode 100755 index 0000000000..fb0020e481 --- /dev/null +++ b/tools/skqp/download_model.py @@ -0,0 +1,69 @@ +#! /usr/bin/env python + +# Copyright 2018 Google Inc. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import hashlib +import multiprocessing +import os +import shutil +import sys +import tempfile +import urllib2 + +def checksum(path): + if not os.path.exists(path): + return None + m = hashlib.md5() + with open(path, 'rb') as f: + while True: + buf = f.read(4096) + if not buf: + return m.hexdigest() + m.update(buf) + +def download(md5, path): + if not md5 == checksum(path): + dirname = os.path.dirname(path) + if dirname and not os.path.exists(dirname): + try: + os.makedirs(dirname) + except OSError: + pass # ignore race condition + url = 'https://storage.googleapis.com/skia-skqp-assets/' + md5 + with open(path, 'wb') as o: + shutil.copyfileobj(urllib2.urlopen(url), o) + +def tmp(prefix): + fd, path = tempfile.mkstemp(prefix=prefix) + os.close(fd) + return path + +def main(): + target_dir = os.path.join('platform_tools', 'android', 'apps', 'skqp', 'src', 'main', 'assets') + os.chdir(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, target_dir)) + checksum_path = 'files.checksum' + if not os.path.isfile(checksum_path): + sys.stderr.write('Error: "%s" is missing.\n' % os.path.join(target_dir, checksum_path)) + sys.exit(1) + file_list_file = tmp('files_') + with open(checksum_path, 'r') as f: + md5 = f.read().strip() + assert(len(md5) == 32) + download(md5, file_list_file) + with open(file_list_file, 'r') as f: + records = [] + for line in f: + md5, path = line.strip().split(';', 1) + records.append((md5, path)) + sys.stderr.write('Downloading %d files.\n' % len(records)) + pool = multiprocessing.Pool(processes=multiprocessing.cpu_count() * 2) + for record in records: + pool.apply_async(download, record, callback=lambda x: sys.stderr.write('.')) + pool.close() + pool.join() + sys.stderr.write('\n') + +if __name__ == '__main__': + main() diff --git a/tools/skqp/generate_gn_args b/tools/skqp/generate_gn_args index f707fa4ebc..ad1db01a22 100755 --- a/tools/skqp/generate_gn_args +++ b/tools/skqp/generate_gn_args @@ -8,14 +8,7 @@ import argparse import os import sys -from skqp_gn_args import SkqpGnArgs - -fmt = ''' -target_cpu = "{arch}" -ndk = "{android_ndk_dir}" -is_debug = {debug} -ndk_api = {api_level} -''' +import skqp_gn_args def parse_args(): parser = argparse.ArgumentParser(description='Generate args.gn file.') @@ -25,23 +18,19 @@ def parse_args(): help='defaults to "arm", valid values: "arm" "arm64" "x86" "x64"') parser.add_argument('--api_level', type=int, metavar='api_level', default=26, help='android API level, defaults to 26') - parser.add_argument('--enable_workarounds', default=False, - action='store_true', help="enable GPU work-arounds, defaults to false") parser.add_argument('--debug', default=False, action='store_true', help='compile native code in debug mode, defaults to false') - - # parse the args and convert bools to strings. args = parser.parse_args() - gn_bool = lambda b : 'true' if b else 'false' - args.enable_workarounds = gn_bool(args.enable_workarounds) - args.debug = gn_bool(args.debug) - args.android_ndk_dir = os.path.abspath(args.android_ndk_dir) - return args + result = skqp_gn_args.GetGNArgs(args.arch, + os.path.abspath(args.android_ndk_dir), + args.debug, + args.api_level) + return args.target_build_dir, result) def write_gn(o, args): - o.write(fmt.format(**args)) - for k, v in SkqpGnArgs.iteritems(): - o.write('%s = %s\n' % (k,v) ) + l = max(len(k) for k in args) + for k, v in sorted(args.items()): + o.write('%-*s = %s\n' % (l, k, v)) def make_args_gn(out_dir, args): if out_dir == '-': @@ -53,5 +42,5 @@ def make_args_gn(out_dir, args): write_gn(o, args) if __name__ == '__main__': - args = parse_args() - make_args_gn(args.target_build_dir, vars(args)) + build_dir, args = parse_args() + make_args_gn(build_dir, args) diff --git a/tools/skqp/make_apk.sh b/tools/skqp/make_apk.sh index 6da2063fe3..cd1bb7b14b 100755 --- a/tools/skqp/make_apk.sh +++ b/tools/skqp/make_apk.sh @@ -1,49 +1,5 @@ #! /bin/sh - -# Copyright 2018 Google Inc. +# Copyright 2019 Google Inc. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. - -set -e - -ANDROID_NDK="$1" - -if ! [ -d "$ANDROID_NDK" ] || ! [ -x "${ANDROID_NDK}/ndk-build" ]; then - printf "\nUsage:\n %s ANDROID_NDK_PATH\n" "$0" >&2 - exit 1 -fi - -case ":${PATH}:" in - */depot_tools:*) ;; - *) - printf '\ndepot_tools should be in your $PATH.\n' >&2 - exit 1;; -esac - -if ! [ -d "$ANDROID_HOME" ] || ! [ -x "${ANDROID_HOME}/platform-tools/adb" ]; then - printf '\n$ANDROID_HOME not set or is broken.\n' >&2 - exit 1 -fi - -set -x - -ARCH=${SKQP_ARCH:-arm} - -cd "$(dirname "$0")/../.." - -BUILD=out/skqp-${ARCH} - -python tools/skqp/generate_gn_args $BUILD "$ANDROID_NDK" $ARCH - -GIT_SYNC_DEPS_QUIET=Y tools/git-sync-deps - -bin/gn gen $BUILD - -rm -rf $BUILD/gen - -platform_tools/android/bin/android_build_app -C $BUILD skqp - -set +x - -printf '\n\nAPK built: "%s/skqp.apk"\n\n' "$(pwd)/$BUILD" - +exec python "$(dirname "$0")"/make_universal_apk.py "$@" diff --git a/tools/skqp/make_universal_apk.py b/tools/skqp/make_universal_apk.py index 6039f3f5c3..bbddeb10b8 100755 --- a/tools/skqp/make_universal_apk.py +++ b/tools/skqp/make_universal_apk.py @@ -21,7 +21,7 @@ run 'python tools/git-sync-deps' in the root of the skia checkout. Also: * If the environment variable SKQP_BUILD_DIR is set, many of the - intermediate build objects will be places here. + intermediate build objects will be placed here. * If the environment variable SKQP_OUTPUT_DIR is set, the final APK will be placed in this directory. * If the environment variable SKQP_DEBUG is set, Skia will be compiled @@ -29,211 +29,41 @@ Also: ''' import os -import glob -import re -import subprocess import sys -import shutil -def print_cmd(cmd, o): - m = re.compile('[^A-Za-z0-9_./-]') - o.write('+ ') - for c in cmd: - if m.search(c) is not None: - o.write(repr(c) + ' ') - else: - o.write(c + ' ') - o.write('\n') - o.flush() +import create_apk +import download_model -def check_call(cmd, **kwargs): - print_cmd(cmd, sys.stdout) - return subprocess.check_call(cmd, **kwargs) - -def find_name(searchpath, filename): - for dirpath, _, filenames in os.walk(searchpath): - if filename in filenames: - yield os.path.join(dirpath, filename) - -def check_ninja(): - with open(os.devnull, 'w') as devnull: - return 0 == subprocess.call(['ninja', '--version'], - stdout=devnull, stderr=devnull) - -def remove(p): - if not os.path.islink(p) and os.path.isdir(p): - shutil.rmtree(p) - elif os.path.lexists(p): - os.remove(p) - assert not os.path.exists(p) - -skia_to_android_arch_name_map = {'arm' : 'armeabi-v7a', - 'arm64': 'arm64-v8a' , - 'x86' : 'x86' , - 'x64' : 'x86_64' } - -def make_apk(architectures, - android_ndk, - android_home, - build_dir, - final_output_dir, - debug, - skia_dir): +def make_apk(opts): assert '/' in [os.sep, os.altsep] # 'a/b' over os.path.join('a', 'b') - assert check_ninja() - assert os.path.exists(android_ndk) - assert os.path.exists(android_home) - assert os.path.exists(skia_dir) - assert os.path.exists(skia_dir + '/bin/gn') # Did you `tools/git-syc-deps`? - assert architectures - assert all(arch in skia_to_android_arch_name_map - for arch in architectures) - for d in [build_dir, final_output_dir]: - if not os.path.exists(d): - os.makedirs(d) + skia_dir = os.path.dirname(__file__) + '/../..' + create_apk.makedirs(opts.build_dir) + assets_dir = skia_dir + '/platform_tools/android/apps/skqp/src/main/assets' + gmkb = assets_dir + '/gmkb' + resources_path = assets_dir + '/resources' - os.chdir(skia_dir) - apps_dir = 'platform_tools/android/apps' + with create_apk.RemoveFiles(resources_path, gmkb): # always clean up + create_apk.remove(gmkb) + create_apk.make_symlinked_subdir(gmkb, opts.build_dir) - # These are the locations in the tree where the gradle needs or will create - # not-checked-in files. Treat them specially to keep the tree clean. - aosp_mode = os.path.exists('MODULE_LICENSE_BSD') - build_paths = [apps_dir + '/.gradle', - apps_dir + '/skqp/build', - apps_dir + '/skqp/src/main/libs'] - if not aosp_mode: - build_paths.append(apps_dir + '/skqp/src/main/assets/gmkb') - remove(build_dir + '/libs') - for path in build_paths: - remove(path) - newdir = os.path.join(build_dir, os.path.basename(path)) - if not os.path.exists(newdir): - os.makedirs(newdir) - try: - os.symlink(os.path.relpath(newdir, os.path.dirname(path)), path) - except OSError: - pass - - if not aosp_mode: - resources_path = apps_dir + '/skqp/src/main/assets/resources' - remove(resources_path) + create_apk.remove(resources_path) os.symlink('../../../../../../../resources', resources_path) - build_paths.append(resources_path) - app = 'skqp' - lib = 'libskqp_app.so' - - shutil.rmtree(apps_dir + '/%s/src/main/libs' % app, True) - - if not aosp_mode: - if os.path.exists(apps_dir + '/skqp/src/main/assets/files.checksum'): - check_call([sys.executable, 'tools/skqp/download_model']) + if os.path.exists(assets_dir + '/files.checksum'): + download_model.main() else: sys.stderr.write( - '\n* * *\n\nNote: SkQP models are missing!!!!\n\n* * *\n\n') - if aosp_mode: - with open('include/config/SkUserConfig.h') as f: - user_config = f.readlines() - with open('include/config/SkUserConfig.h', 'w') as o: - for line in user_config: - m = re.match(r'^#define\s+([A-Za-z0-9_]+)(|\s.*)$', line) - if m: - o.write('#ifndef %s\n%s\n#endif\n' % (m.group(1), m.group(0).strip())) - else: - o.write(line) - - for arch in architectures: - build = os.path.join(build_dir, arch) - gn_args = [android_ndk, '--arch', arch] - if debug: - build += '-debug' - gn_args += ['--debug'] - check_call([sys.executable, 'tools/skqp/generate_gn_args', build] - + gn_args) - check_call(['bin/gn', 'gen', build]) - check_call(['ninja', '-C', build, lib]) - dst = apps_dir + '/%s/src/main/libs/%s' % ( - app, skia_to_android_arch_name_map[arch]) - if not os.path.isdir(dst): - os.makedirs(dst) - shutil.copy(os.path.join(build, lib), dst) - - if aosp_mode: - subprocess.call('git', 'checkout', 'HEAD', 'include/config/SkUserConfig.h') - - apk_build_dir = apps_dir + '/%s/build/outputs/apk' % app - shutil.rmtree(apk_build_dir, True) # force rebuild - - # Why does gradlew need to be called from this directory? - os.chdir('platform_tools/android') - env_copy = os.environ.copy() - env_copy['ANDROID_HOME'] = android_home - check_call(['apps/gradlew', '-p' 'apps/' + app, '-P', 'suppressNativeBuild', - ':%s:assembleUniversalDebug' % app], env=env_copy) - os.chdir(skia_dir) - - apk_name = app + "-universal-debug.apk" - - apk_list = list(find_name(apk_build_dir, apk_name)) - assert len(apk_list) == 1 - - out = os.path.join(final_output_dir, apk_name) - shutil.move(apk_list[0], out) - sys.stdout.write(out + '\n') - - for path in build_paths: - remove(path) - - arches = '_'.join(sorted(architectures)) - copy = os.path.join(final_output_dir, "%s-%s-debug.apk" % (app, arches)) - shutil.copyfile(out, copy) - sys.stdout.write(copy + '\n') - - sys.stdout.write('* * * COMPLETE * * *\n\n') + '\n* * * Note: SkQP models are missing! * * *\n\n') + create_apk.create_apk(opts) def main(): - def error(s): - sys.stderr.write(s + __doc__) + options = create_apk.SkQP_Build_Options() + if options.error: + sys.stderr.write(options.error + __doc__) sys.exit(1) - if not check_ninja(): - error('`ninja` is not in the path.\n') - for var in ['ANDROID_NDK', 'ANDROID_HOME']: - if not os.path.exists(os.environ.get(var, '')): - error('Environment variable `%s` is not set.\n' % var) - architectures = sys.argv[1:] - for arg in sys.argv[1:]: - if arg not in skia_to_android_arch_name_map: - error('Argument %r is not in %r\n' % - (arg, skia_to_android_arch_name_map.keys())) - if not architectures: - architectures = skia_to_android_arch_name_map.keys() - skia_dir = os.path.abspath( - os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)) - default_build = os.path.join(skia_dir, 'out', 'skqp') - build_dir = os.path.abspath(os.environ.get('SKQP_BUILD_DIR', default_build)) - final_output_dir = os.path.abspath( - os.environ.get('SKQP_OUTPUT_DIR', default_build)) - debug = bool(os.environ.get('SKQP_DEBUG', '')) - android_ndk = os.path.abspath(os.environ['ANDROID_NDK']) - android_home = os.path.abspath(os.environ['ANDROID_HOME']) - - for k, v in [('ANDROID_NDK', android_ndk), - ('ANDROID_HOME', android_home), - ('skia root directory', skia_dir), - ('SKQP_OUTPUT_DIR', final_output_dir), - ('SKQP_BUILD_DIR', build_dir), - ('Architectures', architectures)]: - sys.stdout.write('%s = %r\n' % (k, v)) - sys.stdout.flush() - make_apk(architectures, - android_ndk, - android_home, - build_dir, - final_output_dir, - debug, - skia_dir) + options.write(sys.stdout) + make_apk(options) if __name__ == '__main__': main() - diff --git a/tools/skqp/skqp_gn_args.py b/tools/skqp/skqp_gn_args.py index 1c551947fd..1f1f052050 100644 --- a/tools/skqp/skqp_gn_args.py +++ b/tools/skqp/skqp_gn_args.py @@ -1,6 +1,7 @@ # Copyright 2019 Google LLC. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. + SkqpGnArgs = { 'extra_cflags': '[ "-DSK_ENABLE_DUMP_GPU", "-DSK_BUILD_FOR_SKQP" ]', 'skia_enable_fontmgr_android': 'false', @@ -17,3 +18,15 @@ SkqpGnArgs = { 'skia_use_piex': 'false', 'skia_use_vulkan': 'true', } + +def GetGNArgs(arch, android_ndk, debug, api_level): + def gn_quote(s): + return '"%s"' % s + gn_args = { + 'target_cpu': gn_quote(arch), + 'ndk': gn_quote(android_ndk), + 'is_debug': 'true' if debug else 'false', + 'ndk_api': api_level, + } + gn_args.update(SkqpGnArgs) + return gn_args