Commit a531e3b1 authored by Eric Stevenson's avatar Eric Stevenson Committed by Commit Bot

Android: Fix JNI headers not being regenerated.

Previously, moving Java files used by JNI to new locations could cause
build failures. This CL addressed stale generated files by deleting
stale files from the output directory before creating new ones.

Also merge the two generate_jni() templates since they're pretty much
the same.

Bug: 951701
Change-Id: Id066d8e74a52ed0c4c6fd29e92108c2e0bbfe96b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1610749
Commit-Queue: Eric Stevenson <estevenson@chromium.org>
Reviewed-by: default avatarAndrew Grieve <agrieve@chromium.org>
Cr-Commit-Position: refs/heads/master@{#660651}
parent 38a703d6
...@@ -12,6 +12,7 @@ import base64 ...@@ -12,6 +12,7 @@ import base64
import collections import collections
import errno import errno
import hashlib import hashlib
import itertools
import optparse import optparse
import os import os
import re import re
...@@ -1503,35 +1504,6 @@ def WrapOutput(output): ...@@ -1503,35 +1504,6 @@ def WrapOutput(output):
return '\n'.join(ret) return '\n'.join(ret)
def ExtractJarInputFile(jar_file, input_file, out_dir):
"""Extracts input file from jar and returns the filename.
The input file is extracted to the same directory that the generated jni
headers will be placed in. This is passed as an argument to script.
Args:
jar_file: the jar file containing the input files to extract.
input_files: the list of files to extract from the jar file.
out_dir: the name of the directories to extract to.
Returns:
the name of extracted input file.
"""
jar_file = zipfile.ZipFile(jar_file)
out_dir = os.path.join(out_dir, os.path.dirname(input_file))
try:
os.makedirs(out_dir)
except OSError as e:
if e.errno != errno.EEXIST:
raise
extracted_file_name = os.path.join(out_dir, os.path.basename(input_file))
with open(extracted_file_name, 'wb') as outfile:
outfile.write(jar_file.read(input_file))
return extracted_file_name
def GenerateJNIHeader(input_file, output_file, options): def GenerateJNIHeader(input_file, output_file, options):
try: try:
if os.path.splitext(input_file)[1] == '.class': if os.path.splitext(input_file)[1] == '.class':
...@@ -1579,13 +1551,13 @@ See SampleForTests.java for more details. ...@@ -1579,13 +1551,13 @@ See SampleForTests.java for more details.
help='Uses as a namespace in the generated header ' help='Uses as a namespace in the generated header '
'instead of the javap class name, or when there is ' 'instead of the javap class name, or when there is '
'no JNINamespace annotation in the java source.') 'no JNINamespace annotation in the java source.')
option_parser.add_option('--input_file', option_parser.add_option('--input_files',
help='Single input file name. The output file name ' help='Input file names, or paths within a .jar if '
'will be derived from it. Must be used with ' '--jar-file is used.')
'--output_dir.') option_parser.add_option('--output_files',
help='Output file names.')
option_parser.add_option('--output_dir', option_parser.add_option('--output_dir',
help='The output directory. Must be used with ' help='The output directory.')
'--input')
option_parser.add_option('--script_name', default=GetScriptName(), option_parser.add_option('--script_name', default=GetScriptName(),
help='The name of this script in the generated ' help='The name of this script in the generated '
'header.') 'header.')
...@@ -1614,20 +1586,23 @@ See SampleForTests.java for more details. ...@@ -1614,20 +1586,23 @@ See SampleForTests.java for more details.
'in @JniNatives interface. And uses a shorter name and package' 'in @JniNatives interface. And uses a shorter name and package'
' than GEN_JNI.') ' than GEN_JNI.')
options, args = option_parser.parse_args(argv) options, args = option_parser.parse_args(argv)
input_files = build_utils.ParseGnList(options.input_files)
output_files = build_utils.ParseGnList(options.output_files)
# Prevent stale file issues when moving file locations (crbug.com/951701).
if options.output_dir and os.path.exists(options.output_dir):
build_utils.DeleteDirectory(options.output_dir)
build_utils.MakeDirectory(options.output_dir)
with build_utils.TempDir() as temp_dir:
if options.jar_file: if options.jar_file:
input_file = ExtractJarInputFile(options.jar_file, options.input_file, with zipfile.ZipFile(options.jar_file) as z:
options.output_dir) z.extractall(temp_dir, input_files)
elif options.input_file: input_files = [os.path.join(temp_dir, f) for f in input_files]
input_file = options.input_file
else: for java_path, header_path in itertools.izip_longest(
option_parser.print_help() input_files, output_files):
print('\nError: Must specify --jar_file or --input_file.') GenerateJNIHeader(java_path, header_path, options)
return 1
output_file = None
if options.output_dir:
root_name = os.path.splitext(os.path.basename(input_file))[0]
output_file = os.path.join(options.output_dir, root_name) + '_jni.h'
GenerateJNIHeader(input_file, output_file, options)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -189,30 +189,14 @@ if (enable_java_templates) { ...@@ -189,30 +189,14 @@ if (enable_java_templates) {
import("//build/config/sanitizers/sanitizers.gni") import("//build/config/sanitizers/sanitizers.gni")
import("//tools/grit/grit_rule.gni") import("//tools/grit/grit_rule.gni")
# Declare a jni target # JNI target implementation. See generate_jni or generate_jar_jni for usage.
# template("generate_jni_impl") {
# This target generates the native jni bindings for a set of .java files.
#
# See base/android/jni_generator/jni_generator.py for more info about the
# format of generating JNI bindings.
#
# Variables
# sources: list of .java files to generate jni for
# jni_package: subdirectory path for generated bindings
#
# Example
# generate_jni("foo_jni") {
# sources = [
# "android/java/src/org/chromium/foo/Foo.java",
# "android/java/src/org/chromium/foo/FooUtil.java",
# ]
# jni_package = "foo"
# }
template("generate_jni") {
set_sources_assignment_filter([]) set_sources_assignment_filter([])
forward_variables_from(invoker, [ "testonly" ]) forward_variables_from(invoker, [ "testonly" ])
_base_output_dir = "${target_gen_dir}/${target_name}" # TODO(crbug.com/963471): Change include paths to be relative to
# $root_gen_dir to prevent issues when moving JNI targets.
_base_output_dir = "${target_gen_dir}/${target_name}_"
_package_output_dir = "${_base_output_dir}/${invoker.jni_package}" _package_output_dir = "${_base_output_dir}/${invoker.jni_package}"
_jni_output_dir = "${_package_output_dir}/jni" _jni_output_dir = "${_package_output_dir}/jni"
...@@ -232,16 +216,13 @@ if (enable_java_templates) { ...@@ -232,16 +216,13 @@ if (enable_java_templates) {
] ]
} }
_foreach_target_name = "${target_name}__jni_gen" _jni_target_name = "${target_name}__jni"
action_foreach_with_pydeps(_foreach_target_name) { action_with_pydeps(_jni_target_name) {
# The sources aren't compiled so don't check their dependencies.
check_includes = false
script = "//base/android/jni_generator/jni_generator.py" script = "//base/android/jni_generator/jni_generator.py"
sources = invoker.sources inputs = []
outputs = [
"${_jni_output_dir}/{{source_name_part}}_jni.h",
]
args = [ args = [
"--input_file={{source}}",
"--ptr_type=long", "--ptr_type=long",
"--output_dir", "--output_dir",
rebase_path(_jni_output_dir, root_build_dir), rebase_path(_jni_output_dir, root_build_dir),
...@@ -249,23 +230,54 @@ if (enable_java_templates) { ...@@ -249,23 +230,54 @@ if (enable_java_templates) {
rebase_path(_jni_generator_include, _jni_output_dir), rebase_path(_jni_generator_include, _jni_output_dir),
] ]
if (defined(invoker.classes)) {
if (defined(invoker.jar_file)) {
_jar_file = invoker.jar_file
} else {
_jar_file = android_sdk_jar
}
inputs += [ _jar_file ]
args += [
"--jar_file",
rebase_path(_jar_file, root_build_dir),
"--input_files=${invoker.classes}",
]
_input_names = invoker.classes
if (defined(invoker.always_mangle) && invoker.always_mangle) {
args += [ "--always_mangle" ]
}
} else {
assert(defined(invoker.sources))
inputs += invoker.sources
_rebased_sources = rebase_path(invoker.sources, root_build_dir)
args += [ "--input_files=$_rebased_sources" ]
_input_names = invoker.sources
if (use_hashed_jni_names) { if (use_hashed_jni_names) {
args += [ "--use_proxy_hash" ] args += [ "--use_proxy_hash" ]
} }
if (defined(invoker.namespace)) {
args += [ "-n ${invoker.namespace}" ]
}
}
outputs = []
foreach(_name, _input_names) {
_name_part = get_path_info(_name, "name")
outputs += [ "${_jni_output_dir}/${_name_part}_jni.h" ]
}
_rebased_outputs = rebase_path(outputs, root_build_dir)
args += [ "--output_files=$_rebased_outputs" ]
if (enable_profiling) { if (enable_profiling) {
args += [ "--enable_profiling" ] args += [ "--enable_profiling" ]
} }
if (defined(invoker.namespace)) {
args += [ "-n ${invoker.namespace}" ]
}
if (enable_jni_tracing) { if (enable_jni_tracing) {
args += [ "--enable_tracing" ] args += [ "--enable_tracing" ]
} }
} }
config("jni_includes_${target_name}") { config("jni_includes_${target_name}") {
# TODO(cjhopman): #includes should probably all be relative to # TODO: #includes should probably all be relative to
# _base_output_dir. Remove that from this config once the includes are # _base_output_dir. Remove that from this config once the includes are
# updated. # updated.
include_dirs = [ include_dirs = [
...@@ -284,12 +296,38 @@ if (enable_java_templates) { ...@@ -284,12 +296,38 @@ if (enable_java_templates) {
if (!defined(public_deps)) { if (!defined(public_deps)) {
public_deps = [] public_deps = []
} }
public_deps += [ ":$_foreach_target_name" ] public_deps += [ ":$_jni_target_name" ]
public_deps += _jni_generator_include_deps public_deps += _jni_generator_include_deps
public_configs = [ ":jni_includes_${target_name}" ] public_configs = [ ":jni_includes_${target_name}" ]
} }
} }
# Declare a jni target
#
# This target generates the native jni bindings for a set of .java files.
#
# See base/android/jni_generator/jni_generator.py for more info about the
# format of generating JNI bindings.
#
# Variables
# sources: list of .java files to generate jni for
# jni_package: subdirectory path for generated bindings
# namespace: Specify the namespace for the generated header file.
#
# Example
# generate_jni("foo_jni") {
# sources = [
# "android/java/src/org/chromium/foo/Foo.java",
# "android/java/src/org/chromium/foo/FooUtil.java",
# ]
# jni_package = "foo"
# }
template("generate_jni") {
generate_jni_impl(target_name) {
forward_variables_from(invoker, "*")
}
}
# Declare a jni target for a prebuilt jar # Declare a jni target for a prebuilt jar
# #
# This target generates the native jni bindings for a set of classes in a .jar. # This target generates the native jni bindings for a set of classes in a .jar.
...@@ -316,82 +354,8 @@ if (enable_java_templates) { ...@@ -316,82 +354,8 @@ if (enable_java_templates) {
# jni_package = "foo" # jni_package = "foo"
# } # }
template("generate_jar_jni") { template("generate_jar_jni") {
forward_variables_from(invoker, [ "testonly" ]) generate_jni_impl(target_name) {
forward_variables_from(invoker, "*")
if (defined(invoker.jar_file)) {
_jar_file = invoker.jar_file
} else {
_jar_file = android_sdk_jar
}
_always_mangle = defined(invoker.always_mangle) && invoker.always_mangle
_base_output_dir = "${target_gen_dir}/${target_name}/${invoker.jni_package}"
_jni_output_dir = "${_base_output_dir}/jni"
if (defined(invoker.jni_generator_include)) {
_jni_generator_include = invoker.jni_generator_include
} else {
_jni_generator_include =
"//base/android/jni_generator/jni_generator_helper.h"
}
# TODO(cjhopman): make jni_generator.py support generating jni for multiple
# .class files from a .jar.
_jni_actions = []
foreach(_class, invoker.classes) {
_classname = get_path_info(_class, "name")
_jni_target_name = "${target_name}__jni_${_classname}"
_jni_actions += [ ":$_jni_target_name" ]
action_with_pydeps(_jni_target_name) {
# The sources aren't compiled so don't check their dependencies.
check_includes = false
script = "//base/android/jni_generator/jni_generator.py"
inputs = [
_jar_file,
]
outputs = [
"${_jni_output_dir}/${_classname}_jni.h",
]
args = [
"--jar_file",
rebase_path(_jar_file, root_build_dir),
"--input_file",
_class,
"--ptr_type=long",
"--output_dir",
rebase_path(_jni_output_dir, root_build_dir),
"--includes",
rebase_path(_jni_generator_include, _jni_output_dir),
]
if (enable_profiling) {
args += [ "--enable_profiling" ]
}
if (enable_jni_tracing) {
args += [ "--enable_tracing" ]
}
if (_always_mangle) {
args += [ "--always_mangle" ]
}
}
}
config("jni_includes_${target_name}") {
include_dirs = [ _base_output_dir ]
}
group(target_name) {
public_deps = []
forward_variables_from(invoker,
[
"deps",
"public_deps",
"visibility",
])
public_deps += _jni_actions
public_configs = [ ":jni_includes_${target_name}" ]
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment