diff --git a/BUILD.gn b/BUILD.gn index 790dd21a23..29acd54dec 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -697,6 +697,11 @@ component("skia") { # Targets guarded by skia_enable_tools may use //third_party freely. if (skia_enable_tools) { + # Used by gn_to_bp.py to list our public include dirs. + source_set("public") { + configs += [ ":skia_public" ] + } + config("skia.h_config") { include_dirs = [ "$target_gen_dir" ] } diff --git a/gn/gn_to_bp.py b/gn/gn_to_bp.py new file mode 100644 index 0000000000..170cfb017b --- /dev/null +++ b/gn/gn_to_bp.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# +# Copyright 2016 Google Inc. +# +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Generate Android.bp for Skia from GN configuration. + +import json +import os +import pprint +import string +import subprocess +import sys +import tempfile + +# First we start off with a template for Android.bp, +# with holes for source lists and include directories. +bp = string.Template('''// This file is autogenerated by gn_to_bp.py. + +cc_library { + name: "libskia", + cflags: [ + "-fexceptions", + "-Wno-unused-parameter", + "-U_FORTIFY_SOURCE", + "-D_FORTIFY_SOURCE=1", + "-DSKIA_IMPLEMENTATION=1", + ], + + export_include_dirs: $export_includes, + local_include_dirs: $local_includes, + srcs: $srcs, + + arch: { + arm: { + srcs: $arm_srcs, + armv7_a_neon: { + srcs: $arm_neon_srcs, + }, + }, + arm64: { + srcs: $arm64_srcs, + }, + + mips: { + srcs: $mips_srcs, + }, + mips64: { + srcs: $mips64_srcs, + }, + + x86: { + srcs: $x86_srcs, + }, + x86_64: { + srcs: $x86_srcs, + }, + } + + shared_libs: [ + "libEGL", + "libGLESv2", + "libdng_sdk", + "libexpat", + "libft2", + "libicui18n", + "libicuuc", + "libjpeg", + "liblog", + "libpiex", + "libpng", + "libvulkan", + "libz", + ], + static_libs: [ + "cpufeatures", // TODO: use this for CRC32 detection + "libsfntly", + "libwebp-decode", + "libwebp-encode", + ], +} +''') + +# We'll run GN to get the main source lists and include directories for Skia. +gn_args = { + 'skia_enable_vulkan_debug_layers': 'false', + 'skia_use_vulkan': 'true', + 'target_os': '"android"', +} +gn_args = ' '.join(sorted('%s=%s' % (k,v) for (k,v) in gn_args.iteritems())) + +tmp = tempfile.mkdtemp() +subprocess.check_call(['gn', 'gen', tmp, '--args=%s' % gn_args, '--ide=json']) + +js = json.load(open(os.path.join(tmp, 'project.json'))) + +def strip_slashes(lst): + return [p.lstrip('/') for p in lst] +srcs = strip_slashes(js['targets']['//:skia']['sources']) +local_includes = strip_slashes(js['targets']['//:skia']['include_dirs']) +export_includes = strip_slashes(js['targets']['//:public']['include_dirs']) + +# Most defines go into SkUserConfig.h, where they're seen by Skia and its users. +# Start with the defines :skia uses, minus a couple. We'll add more in a bit. +defines = [str(d) for d in js['targets']['//:skia']['defines']] +defines.remove('SKIA_IMPLEMENTATION=1') # Only libskia should have this define. +defines.remove('XML_STATIC') # On Android, libexpat is dynamically linked. + +# For architecture specific files, it's easier to just read the same source +# that GN does (opts.gni) rather than re-run GN once for each architecture. + +# This .gni file we want to read is close enough to Python syntax +# that we can use execfile() if we supply definitions for GN builtins. +# While we're at it, grab defines specific to Android Framework the same way. + +def get_path_info(path, kind): + assert kind == "abspath" + # While we want absolute paths in GN, relative paths work best here. + return path + +builtins = { 'get_path_info': get_path_info } +defs = {} +here = os.path.dirname(sys.argv[0]) +execfile(os.path.join(here, 'opts.gni'), builtins, defs) +execfile(os.path.join(here, 'android_framework_defines.gni'), builtins, defs) + +# This should finish off the defines. +defines += defs['android_framework_defines'] +defines.extend([ + 'GR_GL_CUSTOM_SETUP_HEADER "gl/GrGLConfig_chrome.h"', + 'SKIA_DLL', + 'SK_BUILD_FOR_ANDROID_FRAMEWORK', + 'SK_DEFAULT_FONT_CACHE_LIMIT (768 * 1024)', + 'SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE (512 * 1024)', + 'SK_IGNORE_ETC1_SUPPORT', + 'SK_USE_FREETYPE_EMBOLDEN', +]) +defines.sort() + +# Turns paths from opts.gni into paths relative to external/skia. +def scrub(lst): + # Perform any string substitutions. + for var in defs: + if type(defs[var]) is str: + lst = [ p.replace('$'+var, defs[var]) for p in lst ] + # Relativize paths to top-level skia/ directory. + return [os.path.relpath(p, '..') for p in lst] + +# Turn a list of strings into a pretty string version of a list of strings. +def pretty(lst): + return pprint.pformat(lst).replace("'", '"') + +# OK! We have everything to fill in Android.bp... +with open('Android.bp', 'w') as f: + print >>f, bp.substitute({ + 'export_includes': pretty(export_includes), + 'local_includes': pretty(local_includes), + 'srcs': pretty(srcs), + + 'arm_srcs': pretty(scrub(defs['armv7'])), + 'arm_neon_srcs': pretty(scrub(defs['neon'])), + 'arm64_srcs': pretty(scrub(defs['arm64'] + + defs['crc32'])), + 'mips_srcs': pretty(scrub(defs['mips_dsp'])), + 'mips64_srcs': pretty(scrub(defs['none'])), + 'x86_srcs': pretty(scrub(defs['sse2'] + + defs['ssse3'] + + defs['sse41'] + + defs['sse42'] + + defs['avx' ] + + defs['hsw' ])) + }) + +#... and all the #defines we want to put in SkUserConfig.h. +with open('SkUserConfig.h', 'w') as f: + print >>f, '// This file is autogenerated by gn_to_bp.py.' + print >>f, '#ifndef SkUserConfig_DEFINED' + print >>f, '#define SkUserConfig_DEFINED' + for define in defines: + print >>f, ' #define', define + print >>f, '#endif//SkUserConfig_DEFINED'