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