15d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger#!/usr/bin/env python
25d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger#
35d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger# Copyright 2018 Google Inc.
45d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger#
55d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger# Use of this source code is governed by a BSD-style license that can be
65d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger# found in the LICENSE file.
75d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
85d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger# Generate Android.bp for Skia from GN configuration.
95d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
105d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport argparse
115d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport json
125d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport os
135d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport pprint
145d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport string
155d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport subprocess
165d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerimport tempfile
175d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
185d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerparser = argparse.ArgumentParser(description='Process some cmdline flags.')
195d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerparser.add_argument('--gn', dest='gn_cmd', default='gn')
205d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerargs = parser.parse_args()
215d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
225d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef GenerateJSONFromGN(gn_args):
235d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  gn_args = ' '.join(sorted('%s=%s' % (k,v) for (k,v) in gn_args.iteritems()))
245d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  tmp = tempfile.mkdtemp()
255d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  subprocess.check_call([args.gn_cmd, 'gen', tmp, '--args=%s' % gn_args,
265d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger                         '--ide=json'])
275d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return json.load(open(os.path.join(tmp, 'project.json')))
285d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
295d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef _strip_slash(lst):
305d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return {str(p.lstrip('/')) for p in lst}
315d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
325d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef GrabDependentValues(js, name, value_type, list_to_extend, exclude):
335d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Grab the values from other targets that $name depends on (e.g. optional
345d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Skia components, gms, tests, etc).
355d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  for dep in js['targets'][name]['deps']:
365d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    if 'third_party' in dep:
375d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger      continue   # We've handled all third-party DEPS as static or shared_libs.
385d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    if 'none' in dep:
395d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger      continue   # We'll handle all cpu-specific sources manually later.
405d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    if exclude and exclude in dep:
415d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger      continue
425d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    list_to_extend.update(_strip_slash(js['targets'][dep].get(value_type, [])))
435d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    GrabDependentValues(js, dep, value_type, list_to_extend, exclude)
445d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
455d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef CleanupCFlags(cflags):
465d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Only use the generated flags related to warnings.
475d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags = {s for s in cflags if s.startswith('-W')}
485d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Add the rest of the flags we want.
495d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags = cflags.union([
505d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-fvisibility=hidden",
515d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-D_FORTIFY_SOURCE=1",
525d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-DSKIA_DLL",
535d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-DSKIA_IMPLEMENTATION=1",
545d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-DATRACE_TAG=ATRACE_TAG_VIEW",
555d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    "-DSK_PRINT_CODEC_MESSAGES",
565d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  ])
575d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
585d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # We need to undefine FORTIFY_SOURCE before we define it. Insert it at the
595d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # beginning after sorting.
605d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags = sorted(cflags)
615d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags.insert(0, "-U_FORTIFY_SOURCE")
625d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return cflags
635d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
645d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef CleanupCCFlags(cflags_cc):
655d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Only use the generated flags related to warnings.
665d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags_cc       = {s for s in cflags_cc      if s.startswith('-W')}
675d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Add the rest of the flags we want.
685d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  cflags_cc.add("-fexceptions")
695d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return cflags_cc
705d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
715d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef _get_path_info(path, kind):
725d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  assert path == "../src"
735d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  assert kind == "abspath"
745d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # While we want absolute paths in GN, relative paths work best here.
755d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return "src"
765d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
775d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef GetArchSources(opts_file):
785d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # For architecture specific files, it's easier to just read the same source
795d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # that GN does (opts.gni) rather than re-run GN once for each architecture.
805d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
815d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # This .gni file we want to read is close enough to Python syntax
825d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # that we can use execfile() if we supply definitions for GN builtins.
835d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  builtins = { 'get_path_info': _get_path_info }
845d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  defs = {}
855d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  execfile(opts_file, builtins, defs)
865d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
875d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Perform any string substitutions.
885d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  for arch in defs:
895d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    defs[arch] = [ p.replace('$_src', 'src') for p in defs[arch]]
905d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
915d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  return defs
925d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
935d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenbergerdef WriteUserConfig(userConfigPath, defines):
945d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  # Most defines go into SkUserConfig.h
955d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  defines.remove('NDEBUG')                 # Controlled by the Android build
965d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  defines.remove('SKIA_IMPLEMENTATION=1')  # don't export this define.
975d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger
985d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  #... and all the #defines we want to put in SkUserConfig.h.
995d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger  with open(userConfigPath, 'w') as f:
1005d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '// DO NOT MODIFY! This file is autogenerated by gn_to_bp.py.'
1015d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '// If need to change a define, modify SkUserConfigManual.h'
1025d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '#ifndef SkUserConfig_DEFINED'
1035d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '#define SkUserConfig_DEFINED'
1045d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '#include "SkUserConfigManual.h"'
1055d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    for define in sorted(defines):
1065d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger      print >>f, '  #define', define.replace('=', ' ')
1075d3f7704bf9f3b4a075dc55b6951eec6f574c333Derek Sollenberger    print >>f, '#endif//SkUserConfig_DEFINED'
108