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