From 8b2513a9866328b6cc393e3019ac58036e94d5ce Mon Sep 17 00:00:00 2001 From: Derek Sollenberger Date: Thu, 6 Jan 2022 16:39:39 -0500 Subject: [PATCH] Build the NDK compliant shared library to be used by JNI in SkQP. This CL creates a new build target with a customized set of GN flags that enable the native components of SkQP to be built using NDK APIs. Bug: skia:12777 Change-Id: I8341eafa7fc794cfb759045b7c7238e69c29b0a3 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/491447 Reviewed-by: Leon Scroggins Commit-Queue: Derek Sollenberger --- gn/gn_to_bp.py | 148 +++++++++++++++++++++----- gn/gn_to_bp_utils.py | 9 ++ gn/skqp_gn_args.py | 46 +++++++++ tests/ShaperTest.cpp | 4 +- tools/skqp/create_apk.py | 4 +- tools/skqp/gn_to_bp.py | 206 ------------------------------------- tools/skqp/skqp_gn_args.py | 32 ------ 7 files changed, 183 insertions(+), 266 deletions(-) create mode 100644 gn/skqp_gn_args.py delete mode 100755 tools/skqp/gn_to_bp.py delete mode 100644 tools/skqp/skqp_gn_args.py diff --git a/gn/gn_to_bp.py b/gn/gn_to_bp.py index 7bbc40d477..d69d202196 100755 --- a/gn/gn_to_bp.py +++ b/gn/gn_to_bp.py @@ -15,6 +15,7 @@ import string import subprocess import tempfile +import skqp_gn_args import gn_to_bp_utils # First we start off with a template for Android.bp, @@ -73,23 +74,7 @@ license { } cc_defaults { - name: "skia_defaults", - cflags: [ - $cflags - ], - - cppflags:[ - $cflags_cc - ], - - export_include_dirs: [ - $export_includes - ], - - local_include_dirs: [ - $local_includes - ], - + name: "skia_arch_defaults", arch: { arm: { srcs: [ @@ -134,6 +119,26 @@ cc_defaults { }, } +cc_defaults { + name: "skia_defaults", + defaults: ["skia_arch_defaults"], + cflags: [ + $cflags + ], + + cppflags:[ + $cflags_cc + ], + + export_include_dirs: [ + $export_includes + ], + + local_include_dirs: [ + $local_includes + ] +} + cc_library_static { // Smaller version of Skia, without e.g. codecs, intended for use by RenderEngine. name: "libskia_renderengine", @@ -384,6 +389,58 @@ cc_test { ], } +cc_library_shared { + name: "libskqp_jni", + sdk_version: "$skqp_sdk_version", + stl: "libc++_static", + compile_multilib: "both", + + defaults: [ + "skia_arch_defaults", + ], + + cflags: [ + $skqp_cflags + "-Wno-unused-parameter", + "-Wno-unused-variable", + ], + + cppflags:[ + $skqp_cflags_cc + ], + + local_include_dirs: [ + "skqp", + $skqp_includes + ], + + export_include_dirs: [ + "skqp", + ], + + srcs: [ + $skqp_srcs + ], + + header_libs: ["jni_headers"], + + shared_libs: [ + "libandroid", + "libEGL", + "libGLESv2", + "liblog", + "libvulkan", + "libz", + ], + static_libs: [ + "libexpat", + "libjpeg_static_ndk", + "libpng_ndk", + "libwebp-decode", + "libwebp-encode", + "libwuffs_mirror_release_c", + ] +} ''') # We'll run GN to get the main source lists and include directories for Skia. @@ -531,13 +588,6 @@ linux_srcs = linux_srcs.difference(srcs) mac_srcs = mac_srcs.difference(srcs) win_srcs = win_srcs.difference(srcs) -js_renderengine = gn_to_bp_utils.GenerateJSONFromGN(gn_args_renderengine) -renderengine_srcs = strip_slashes( - js_renderengine['targets']['//:skia']['sources']) -gn_to_bp_utils.GrabDependentValues(js_renderengine, '//:skia', 'sources', - renderengine_srcs, None) -renderengine_srcs = strip_headers(renderengine_srcs) - gm_srcs = strip_headers(gm_srcs) test_srcs = strip_headers(test_srcs) dm_srcs = strip_headers(dm_srcs).difference(gm_srcs).difference(test_srcs) @@ -549,6 +599,42 @@ test_minus_gm_srcs = test_srcs.difference(gm_srcs) cflags = gn_to_bp_utils.CleanupCFlags(cflags) cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc) +# Execute GN for specialized RenderEngine target +js_renderengine = gn_to_bp_utils.GenerateJSONFromGN(gn_args_renderengine) +renderengine_srcs = strip_slashes( + js_renderengine['targets']['//:skia']['sources']) +gn_to_bp_utils.GrabDependentValues(js_renderengine, '//:skia', 'sources', + renderengine_srcs, None) +renderengine_srcs = strip_headers(renderengine_srcs) + +# Execute GN for specialized SkQP target +skqp_sdk_version = 26 +js_skqp = gn_to_bp_utils.GenerateJSONFromGN(skqp_gn_args.GetGNArgs(api_level=skqp_sdk_version, + debug=False, + is_android_bp=True)) +skqp_srcs = strip_slashes(js_skqp['targets']['//:libskqp_app']['sources']) +skqp_includes = strip_slashes(js_skqp['targets']['//:libskqp_app']['include_dirs']) +skqp_cflags = strip_slashes(js_skqp['targets']['//:libskqp_app']['cflags']) +skqp_cflags_cc = strip_slashes(js_skqp['targets']['//:libskqp_app']['cflags_cc']) +skqp_defines = strip_slashes(js_skqp['targets']['//:libskqp_app']['defines']) + +skqp_includes.update(strip_slashes(js_skqp['targets']['//:public']['include_dirs'])) + +gn_to_bp_utils.GrabDependentValues(js_skqp, '//:libskqp_app', 'sources', + skqp_srcs, None) +gn_to_bp_utils.GrabDependentValues(js_skqp, '//:libskqp_app', 'include_dirs', + skqp_includes, ['//:gif']) +gn_to_bp_utils.GrabDependentValues(js_skqp, '//:libskqp_app', 'cflags', + skqp_cflags, None) +gn_to_bp_utils.GrabDependentValues(js_skqp, '//:libskqp_app', 'cflags_cc', + skqp_cflags_cc, None) +gn_to_bp_utils.GrabDependentValues(js_skqp, '//:libskqp_app', 'defines', + skqp_defines, None) + +skqp_srcs = strip_headers(skqp_srcs) +skqp_cflags = gn_to_bp_utils.CleanupCFlags(skqp_cflags) +skqp_cflags_cc = gn_to_bp_utils.CleanupCCFlags(skqp_cflags_cc) + here = os.path.dirname(__file__) defs = gn_to_bp_utils.GetArchSources(os.path.join(here, 'opts.gni')) @@ -569,6 +655,7 @@ mkdir_if_not_exists('linux/include/config/') mkdir_if_not_exists('mac/include/config/') mkdir_if_not_exists('win/include/config/') mkdir_if_not_exists('renderengine/include/config/') +mkdir_if_not_exists('skqp/include/config/') platforms = { 'IOS', 'MAC', 'WIN', 'ANDROID', 'UNIX' } @@ -590,7 +677,7 @@ def append_to_file(config, s): with open(config, 'a') as f: print(s, file=f) -def write_android_config(config_path, defines): +def write_android_config(config_path, defines, isNDKConfig = False): gn_to_bp_utils.WriteUserConfig(config_path, defines) append_to_file(config_path, ''' #ifndef SK_BUILD_FOR_ANDROID @@ -598,8 +685,13 @@ def write_android_config(config_path, defines): #endif''') disallow_platforms(config_path, 'ANDROID') + if isNDKConfig: + append_to_file(config_path, ''' +#undef SK_BUILD_FOR_ANDROID_FRAMEWORK''') + write_android_config('android/include/config/SkUserConfig.h', android_defines) write_android_config('renderengine/include/config/SkUserConfig.h', renderengine_defines) +write_android_config('skqp/include/config/SkUserConfig.h', skqp_defines, True) def write_config(config_path, defines, platform): gn_to_bp_utils.WriteUserConfig(config_path, defines) @@ -657,6 +749,12 @@ with open('Android.bp', 'w') as Android_bp: 'nanobench_includes' : bpfmt(8, nanobench_includes), 'nanobench_srcs' : bpfmt(8, nanobench_srcs), + 'skqp_sdk_version': skqp_sdk_version, + 'skqp_includes': bpfmt(8, skqp_includes), + 'skqp_srcs': bpfmt(8, skqp_srcs), + 'skqp_cflags': bpfmt(8, skqp_cflags, False), + 'skqp_cflags_cc': bpfmt(8, skqp_cflags_cc), + 'android_srcs': bpfmt(10, android_srcs), 'linux_srcs': bpfmt(10, linux_srcs), 'mac_srcs': bpfmt(10, mac_srcs), diff --git a/gn/gn_to_bp_utils.py b/gn/gn_to_bp_utils.py index 04ef05561a..40d5a66f0b 100755 --- a/gn/gn_to_bp_utils.py +++ b/gn/gn_to_bp_utils.py @@ -71,6 +71,10 @@ def CleanupCFlags(cflags): "-DATRACE_TAG=ATRACE_TAG_VIEW", ]) + # Android does not want -Weverything set, it blocks toolchain updates. + if "-Weverything" in cflags: + cflags.remove("-Weverything") + # We need to undefine FORTIFY_SOURCE before we define it. Insert it at the # beginning after sorting. cflags = sorted(cflags) @@ -78,6 +82,10 @@ def CleanupCFlags(cflags): return cflags def CleanupCCFlags(cflags_cc): + # Android does not want -Weverything set, it blocks toolchain updates. + if "-Weverything" in cflags_cc: + cflags_cc.remove("-Weverything") + # Only use the generated flags related to warnings. return {s for s in cflags_cc if s.startswith('-W')} @@ -120,6 +128,7 @@ def WriteUserConfig(userConfigPath, defines): print('// If need to change a define, modify SkUserConfigManual.h', file=f) print('#pragma once', file=f) print('#include "SkUserConfigManual.h"', file=f) + for define in sorted(defines): print('', file=f) print('#ifndef', define.split('=')[0], file=f) diff --git a/gn/skqp_gn_args.py b/gn/skqp_gn_args.py new file mode 100644 index 0000000000..6105396670 --- /dev/null +++ b/gn/skqp_gn_args.py @@ -0,0 +1,46 @@ +# Copyright 2019 Google LLC. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +def GetGNArgs(api_level, debug, arch=None, ndk=None, is_android_bp=False): + gn_args = { + 'ndk_api': api_level, + 'is_debug': 'true' if debug else 'false', + 'extra_cflags': '[ "-DSK_ENABLE_DUMP_GPU", "-DSK_BUILD_FOR_SKQP" ]', + 'skia_enable_fontmgr_android': 'false', + 'skia_enable_fontmgr_empty': 'true', + 'skia_enable_pdf': 'false', + 'skia_enable_skshaper': 'false', + 'skia_enable_skottie': 'false', + 'skia_enable_skrive': 'false', + 'skia_enable_sktext': 'false', + 'skia_enable_tools': 'true', + 'skia_enable_svg': 'false', + 'skia_tools_require_resources': 'true', + 'skia_use_dng_sdk': 'false', + 'skia_use_expat': 'true', + 'skia_use_freetype': 'false', + 'skia_use_icu': 'false', + 'skia_use_libgifcodec': 'false', + 'skia_use_libheif': 'false', + 'skia_use_lua': 'false', + 'skia_use_piex': 'false', + 'skia_use_vulkan': 'true', + 'skia_use_wuffs': 'true', + } + + def gn_quote(s): + return '"%s"' % s + + if is_android_bp is True: + gn_args.update({ + 'target_os': gn_quote("android"), + 'target_cpu': gn_quote("none"), + 'is_official_build': 'true', + }) + else: + gn_args.update({ + 'target_cpu': gn_quote(arch), + 'ndk': gn_quote(ndk), + }) + return gn_args diff --git a/tests/ShaperTest.cpp b/tests/ShaperTest.cpp index 8d12de9d05..b8e3558674 100644 --- a/tests/ShaperTest.cpp +++ b/tests/ShaperTest.cpp @@ -3,7 +3,7 @@ #include "tests/Test.h" -#if !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && !defined(SK_BUILD_FOR_GOOGLE3) +#if defined(SKSHAPER_IMPLEMENTATION) && !defined(SK_BUILD_FOR_GOOGLE3) #include "include/core/SkData.h" #include "include/core/SkFont.h" @@ -134,4 +134,4 @@ SHAPER_TEST(vai) //SHAPER_TEST(tamil) #undef SHAPER_TEST -#endif // !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK) && !defined(SK_BUILD_FOR_GOOGLE3) +#endif // defined(SKSHAPER_IMPLEMENTATION) && !defined(SK_BUILD_FOR_GOOGLE3) diff --git a/tools/skqp/create_apk.py b/tools/skqp/create_apk.py index 27bff792fb..fd62393487 100755 --- a/tools/skqp/create_apk.py +++ b/tools/skqp/create_apk.py @@ -39,6 +39,7 @@ import sys import shutil import time +sys.path.append(os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + "../../../gn")) import skqp_gn_args def print_cmd(cmd, o): @@ -215,7 +216,8 @@ class SkQP_Build_Options(object): self.debug = bool(os.environ.get('SKQP_DEBUG', '')) def gn_args(self, arch): - return skqp_gn_args.GetGNArgs(arch, self.android_ndk, self.debug, 26) + return skqp_gn_args.GetGNArgs(arch=arch, ndk=self.android_ndk, debug=self.debug, + api_level=26) def write(self, o): for k, v in [('ANDROID_NDK', self.android_ndk), diff --git a/tools/skqp/gn_to_bp.py b/tools/skqp/gn_to_bp.py deleted file mode 100755 index 99b022c567..0000000000 --- a/tools/skqp/gn_to_bp.py +++ /dev/null @@ -1,206 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2016 Google Inc. -# -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -# Generate Android.bp for Skia from GN configuration. - -import argparse -import json -import os -import pprint -import string -import subprocess -import sys -import tempfile - -root_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), - os.pardir, os.pardir) -skia_gn_dir = os.path.join(root_dir, 'gn') -sys.path.insert(0, skia_gn_dir) - -import gn_to_bp_utils - -from skqp_gn_args import SkqpGnArgs - -# First we start off with a template for Android.bp, -# with holes for source lists and include directories. -bp = string.Template('''// This file is autogenerated by tools/skqp/gn_to_bp.py. - -cc_library_shared { - name: "libskqp_app", - sdk_version: "26", - stl: "libc++_static", - compile_multilib: "both", - - cflags: [ - $cflags - "-Wno-unused-parameter", - "-Wno-unused-variable", - ], - - cppflags:[ - $cflags_cc - ], - - local_include_dirs: [ - $local_includes - ], - - srcs: [ - "third_party/vulkanmemoryallocator/GrVulkanMemoryAllocator.cpp", - $srcs - ], - - arch: { - arm: { - srcs: [ - $arm_srcs - ], - - neon: { - srcs: [ - $arm_neon_srcs - ], - }, - }, - - arm64: { - srcs: [ - $arm64_srcs - ], - }, - - mips: { - srcs: [ - $none_srcs - ], - }, - - mips64: { - srcs: [ - $none_srcs - ], - }, - - x86: { - srcs: [ - $x86_srcs - ], - }, - - x86_64: { - srcs: [ - $x86_srcs - ], - }, - }, - - shared_libs: [ - "libandroid", - "libEGL", - "libGLESv2", - "liblog", - "libvulkan", - "libz", - ], - static_libs: [ - "libexpat", - "libjpeg_static_ndk", - "libpng_ndk", - "libwebp-decode", - "libwebp-encode", - ] -}''') - -# We'll run GN to get the main source lists and include directories for Skia. -gn_args = { - 'target_cpu': '"none"', - 'target_os': '"android"', - - # setup skqp - 'is_debug': 'false', - 'ndk_api': '26', - - # specify that the Android.bp will supply the necessary components - 'skia_use_system_expat': 'true', # removed this when gn is fixed - 'skia_use_system_libpng': 'true', - 'skia_use_system_libwebp': 'true', - 'skia_use_system_libjpeg_turbo': 'true', - 'skia_use_system_zlib': 'true', -} - -for k, v in SkqpGnArgs.iteritems(): - gn_args[k] = v - -js = gn_to_bp_utils.GenerateJSONFromGN(gn_args) - -def strip_slashes(lst): - return {str(p.lstrip('/')) for p in lst} - -srcs = strip_slashes(js['targets']['//:libskqp_app']['sources']) -cflags = strip_slashes(js['targets']['//:libskqp_app']['cflags']) -cflags_cc = strip_slashes(js['targets']['//:libskqp_app']['cflags_cc']) -local_includes = strip_slashes(js['targets']['//:libskqp_app']['include_dirs']) -defines = {str(d) for d in js['targets']['//:libskqp_app']['defines']} - -defines.update(["SK_ENABLE_DUMP_GPU", "SK_BUILD_FOR_SKQP"]) -cflags_cc.update(['-Wno-extra-semi-stmt']) - -# Android does not want -Weverything set, it blocks toolchain updates. -assert '-Weverything' not in cflags - -gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'sources', srcs, None) -gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'include_dirs', - local_includes, 'freetype') -gn_to_bp_utils.GrabDependentValues(js, '//:libskqp_app', 'defines', - defines, None) - -# No need to list headers or other extra flags. -srcs = {s for s in srcs if not s.endswith('.h')} -cflags = gn_to_bp_utils.CleanupCFlags(cflags) -cflags_cc = gn_to_bp_utils.CleanupCCFlags(cflags_cc) - -# We need to add the include path to the vulkan defines and header file set in -# then skia_vulkan_header gn arg that is used for framework builds. -local_includes.add("platform_tools/android/vulkan") - -# Get architecture specific source files -defs = gn_to_bp_utils.GetArchSources(os.path.join(skia_gn_dir, 'opts.gni')) - -# Add source file until fix lands in -# https://skia-review.googlesource.com/c/skia/+/101820 -srcs.add("src/ports/SkFontMgr_empty_factory.cpp") - -# Turn a list of strings into the style bpfmt outputs. -def bpfmt(indent, lst, sort=True): - if sort: - lst = sorted(lst) - return ('\n' + ' '*indent).join('"%s",' % v for v in lst) - -# Most defines go into SkUserConfig.h, where they're seen by Skia and its users. -gn_to_bp_utils.WriteUserConfig('include/config/SkUserConfig.h', defines) - -# OK! We have everything to fill in Android.bp... -with open('Android.bp', 'w') as f: - print >>f, bp.substitute({ - 'local_includes': bpfmt(8, local_includes), - 'srcs': bpfmt(8, srcs), - 'cflags': bpfmt(8, cflags, False), - 'cflags_cc': bpfmt(8, cflags_cc), - - 'arm_srcs': bpfmt(16, defs['armv7']), - 'arm_neon_srcs': bpfmt(20, defs['neon']), - 'arm64_srcs': bpfmt(16, defs['arm64'] + - defs['crc32']), - 'none_srcs': bpfmt(16, defs['none']), - 'x86_srcs': bpfmt(16, defs['sse2'] + - defs['ssse3'] + - defs['sse41'] + - defs['sse42'] + - defs['avx'] + - defs['hsw']), - }) - diff --git a/tools/skqp/skqp_gn_args.py b/tools/skqp/skqp_gn_args.py deleted file mode 100644 index 1f1f052050..0000000000 --- a/tools/skqp/skqp_gn_args.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2019 Google LLC. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -SkqpGnArgs = { - 'extra_cflags': '[ "-DSK_ENABLE_DUMP_GPU", "-DSK_BUILD_FOR_SKQP" ]', - 'skia_enable_fontmgr_android': 'false', - 'skia_enable_fontmgr_empty': 'true', - 'skia_enable_pdf': 'false', - 'skia_enable_skottie': 'false', - 'skia_skqp_global_error_tolerance': '8', - 'skia_tools_require_resources': 'true', - 'skia_use_dng_sdk': 'false', - 'skia_use_expat': 'true', - 'skia_use_icu': 'false', - 'skia_use_libheif': 'false', - 'skia_use_lua': 'false', - 'skia_use_piex': 'false', - 'skia_use_vulkan': 'true', -} - -def GetGNArgs(arch, android_ndk, debug, api_level): - def gn_quote(s): - return '"%s"' % s - gn_args = { - 'target_cpu': gn_quote(arch), - 'ndk': gn_quote(android_ndk), - 'is_debug': 'true' if debug else 'false', - 'ndk_api': api_level, - } - gn_args.update(SkqpGnArgs) - return gn_args