Add gn_to_bp.py.

The general idea here is, run GN in --ide=json mode to get most information.

Then, read a couple .gni files to get the rest (platform specific source lists, Android framework defines).

For now, I'm generating Android.bp and SkUserConfig.h.  I figure we can do DM and nanobench once these work?

Change-Id: I8e7f60d6572f2d4769760cf872895518a15d841b
Reviewed-on: https://skia-review.googlesource.com/5554
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Mike Klein <mtklein@chromium.org>
diff --git a/BUILD.gn b/BUILD.gn
index 790dd21..29acd54d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -697,6 +697,11 @@
 
 # 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 0000000..170cfb0
--- /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'