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 <scroggo@google.com>
Commit-Queue: Derek Sollenberger <djsollen@google.com>
This commit is contained in:
Derek Sollenberger 2022-01-06 16:39:39 -05:00 committed by SkCQ
parent 0056f3f006
commit 8b2513a986
7 changed files with 183 additions and 266 deletions

View File

@ -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),

View File

@ -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)

46
gn/skqp_gn_args.py Normal file
View File

@ -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

View File

@ -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)

View File

@ -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),

View File

@ -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']),
})

View File

@ -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