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