1#!/usr/bin/env python
2#
3# Copyright 2018 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8# Generate Android.bp for Skia from GN configuration.
9
10import argparse
11import json
12import os
13import pprint
14import string
15import subprocess
16import tempfile
17
18parser = argparse.ArgumentParser(description='Process some cmdline flags.')
19parser.add_argument('--gn', dest='gn_cmd', default='gn')
20args = parser.parse_args()
21
22def GenerateJSONFromGN(gn_args):
23  gn_args = ' '.join(sorted('%s=%s' % (k,v) for (k,v) in gn_args.iteritems()))
24  tmp = tempfile.mkdtemp()
25  subprocess.check_call([args.gn_cmd, 'gen', tmp, '--args=%s' % gn_args,
26                         '--ide=json'])
27  return json.load(open(os.path.join(tmp, 'project.json')))
28
29def _strip_slash(lst):
30  return {str(p.lstrip('/')) for p in lst}
31
32def GrabDependentValues(js, name, value_type, list_to_extend, exclude):
33  # Grab the values from other targets that $name depends on (e.g. optional
34  # Skia components, gms, tests, etc).
35  for dep in js['targets'][name]['deps']:
36    if 'third_party' in dep:
37      continue   # We've handled all third-party DEPS as static or shared_libs.
38    if 'none' in dep:
39      continue   # We'll handle all cpu-specific sources manually later.
40    if exclude and exclude in dep:
41      continue
42    list_to_extend.update(_strip_slash(js['targets'][dep].get(value_type, [])))
43    GrabDependentValues(js, dep, value_type, list_to_extend, exclude)
44
45def CleanupCFlags(cflags):
46  # Only use the generated flags related to warnings.
47  cflags = {s for s in cflags if s.startswith('-W')}
48  # Add the rest of the flags we want.
49  cflags = cflags.union([
50    "-fvisibility=hidden",
51    "-D_FORTIFY_SOURCE=1",
52    "-DSKIA_DLL",
53    "-DSKIA_IMPLEMENTATION=1",
54    "-DATRACE_TAG=ATRACE_TAG_VIEW",
55    "-DSK_PRINT_CODEC_MESSAGES",
56  ])
57
58  # We need to undefine FORTIFY_SOURCE before we define it. Insert it at the
59  # beginning after sorting.
60  cflags = sorted(cflags)
61  cflags.insert(0, "-U_FORTIFY_SOURCE")
62  return cflags
63
64def CleanupCCFlags(cflags_cc):
65  # Only use the generated flags related to warnings.
66  cflags_cc       = {s for s in cflags_cc      if s.startswith('-W')}
67  # Add the rest of the flags we want.
68  cflags_cc.add("-fexceptions")
69  return cflags_cc
70
71def _get_path_info(path, kind):
72  assert path == "../src"
73  assert kind == "abspath"
74  # While we want absolute paths in GN, relative paths work best here.
75  return "src"
76
77def GetArchSources(opts_file):
78  # For architecture specific files, it's easier to just read the same source
79  # that GN does (opts.gni) rather than re-run GN once for each architecture.
80
81  # This .gni file we want to read is close enough to Python syntax
82  # that we can use execfile() if we supply definitions for GN builtins.
83  builtins = { 'get_path_info': _get_path_info }
84  defs = {}
85  execfile(opts_file, builtins, defs)
86
87  # Perform any string substitutions.
88  for arch in defs:
89    defs[arch] = [ p.replace('$_src', 'src') for p in defs[arch]]
90
91  return defs
92
93def WriteUserConfig(userConfigPath, defines):
94  # Most defines go into SkUserConfig.h
95  defines.remove('NDEBUG')                 # Controlled by the Android build
96  defines.remove('SKIA_IMPLEMENTATION=1')  # don't export this define.
97
98  #... and all the #defines we want to put in SkUserConfig.h.
99  with open(userConfigPath, 'w') as f:
100    print >>f, '// DO NOT MODIFY! This file is autogenerated by gn_to_bp.py.'
101    print >>f, '// If need to change a define, modify SkUserConfigManual.h'
102    print >>f, '#ifndef SkUserConfig_DEFINED'
103    print >>f, '#define SkUserConfig_DEFINED'
104    print >>f, '#include "SkUserConfigManual.h"'
105    for define in sorted(defines):
106      print >>f, '  #define', define.replace('=', ' ')
107    print >>f, '#endif//SkUserConfig_DEFINED'
108