0

Android: Add basic Kotlin support

This CL adds initial build system support for compiling Kotlin code
alongside our existing support for compiling Java code. In order to
compile Kotlin code, we need to use the kotlinc binary (analogous to
javac), also added to DEPS in this CL.

Although kotlinc only compiles Kotlin code into .class files, for
targets that have a mix of Java and Kotlin source files, kotlinc needs
to also be passed the Java files in the same target. This is so that it
can resolve references from the Kotlin code to the Java code in the same
target. It does not compile the Java files passed to it. That is left to
a subsequent run of javac.

Similar to Bazel, Kotlin code is compiled first, a header .jar file for
the Kotlin code is created at the same time, then the header .jar file
is merged into the header .jar file for the Java files generated by
turbine, while the .class files from kotlinc are merged into the .class
files that are subsequently generated by javac. This way a single header
.jar file and a single .jar file with all .class files is the resulting
output of compilation steps.

Another change is that .sources files now contain both Java and Kotlin
files. This resulted in some updates to JaCoCo scripts (which are not
tested in this CL as no Kotlin code has been added, so JaCoCo should not
be affected). Android Lint should already support Kotlin code, so even
when Kotlin code is added Android Lint should continue to work.

Also add print_version.sh for kotlinc.

Bug: 1401205
Change-Id: Idbeda044a01ab58e819a98364b64ddcfbfc298d0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4179272
Reviewed-by: Andrew Grieve <agrieve@chromium.org>
Auto-Submit: Peter Wen <wnwen@chromium.org>
Commit-Queue: Peter Wen <wnwen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1095170}
This commit is contained in:
Peter Wen
2023-01-20 19:40:30 +00:00
committed by Chromium LUCI CQ
parent 7590897a14
commit eaa963f8b9
14 changed files with 512 additions and 109 deletions

11
DEPS

@ -1420,6 +1420,17 @@ deps = {
'condition': 'checkout_android',
},
'src/third_party/kotlinc/current': {
'packages': [
{
'package': 'chromium/third_party/kotlinc',
'version': 'F-v9Yy4tNQtjGB7TtAWc2J-3qhx9Q6ixZJyuGixVH08C',
},
],
'condition': 'checkout_android',
'dep_type': 'cipd',
},
'src/third_party/leveldatabase/src':
Var('chromium_git') + '/external/leveldb.git' + '@' + 'd019e3605f222ebc5a3a2484a2cb29db537551dd',

@ -1525,6 +1525,7 @@ _GENERIC_PYDEPS_FILES = [
'build/android/gyp/bytecode_rewriter.pydeps',
'build/android/gyp/check_flag_expectations.pydeps',
'build/android/gyp/compile_java.pydeps',
'build/android/gyp/compile_kt.pydeps',
'build/android/gyp/compile_resources.pydeps',
'build/android/gyp/copy_ex.pydeps',
'build/android/gyp/create_apk_operations_script.pydeps',

@ -244,6 +244,34 @@ def ProcessJavacOutput(output, target_name):
return '\n'.join(lines)
def CreateJarFile(jar_path,
classes_dir,
service_provider_configuration_dir=None,
additional_jar_files=None,
extra_classes_jar=None):
"""Zips files from compilation into a single jar."""
logging.info('Start creating jar file: %s', jar_path)
with build_utils.AtomicOutput(jar_path) as f:
with zipfile.ZipFile(f.name, 'w') as z:
build_utils.ZipDir(z, classes_dir)
if service_provider_configuration_dir:
config_files = build_utils.FindInDirectory(
service_provider_configuration_dir)
for config_file in config_files:
zip_path = os.path.relpath(config_file,
service_provider_configuration_dir)
build_utils.AddToZipHermetic(z, zip_path, src_path=config_file)
if additional_jar_files:
for src_path, zip_path in additional_jar_files:
build_utils.AddToZipHermetic(z, zip_path, src_path=src_path)
if extra_classes_jar:
build_utils.MergeZips(
z, [extra_classes_jar],
path_transform=lambda p: p if p.endswith('.class') else None)
logging.info('Completed jar file: %s', jar_path)
def _ParsePackageAndClassNames(java_file):
package_name = ''
class_names = []
@ -366,26 +394,6 @@ class _InfoFileContext:
logging.info('Completed info file: %s', output_path)
def _CreateJarFile(jar_path, service_provider_configuration_dir,
additional_jar_files, classes_dir):
logging.info('Start creating jar file: %s', jar_path)
with build_utils.AtomicOutput(jar_path) as f:
with zipfile.ZipFile(f.name, 'w') as z:
build_utils.ZipDir(z, classes_dir)
if service_provider_configuration_dir:
config_files = build_utils.FindInDirectory(
service_provider_configuration_dir)
for config_file in config_files:
zip_path = os.path.relpath(config_file,
service_provider_configuration_dir)
build_utils.AddToZipHermetic(z, zip_path, src_path=config_file)
if additional_jar_files:
for src_path, zip_path in additional_jar_files:
build_utils.AddToZipHermetic(z, zip_path, src_path=src_path)
logging.info('Completed jar file: %s', jar_path)
def _OnStaleMd5(changes, options, javac_cmd, javac_args, java_files):
logging.info('Starting _OnStaleMd5')
if options.enable_kythe_annotations:
@ -567,8 +575,8 @@ def _RunCompiler(changes,
end = time.time() - start
logging.info('Java compilation took %ss', end)
_CreateJarFile(jar_path, service_provider_configuration,
options.additional_jar_files, classes_dir)
CreateJarFile(jar_path, classes_dir, service_provider_configuration,
options.additional_jar_files, options.kotlin_jar_path)
if save_info_file:
info_file_context.Commit(jar_info_path)
@ -653,6 +661,10 @@ def _ParseOptions(argv):
'--header-jar',
help='This is the header jar for the current target that contains '
'META-INF/services/* files to be included in the output jar.')
parser.add_option(
'--kotlin-jar-path',
help='Kotlin jar to be merged into the output jar. This contains the '
".class files from this target's .kt files.")
options, args = parser.parse_args(argv)
build_utils.CheckOptions(options, parser, required=('jar_path', ))
@ -669,13 +681,18 @@ def _ParseOptions(argv):
additional_jar_files.append((filepath, jar_filepath))
options.additional_jar_files = additional_jar_files
java_files = []
files = []
for arg in args:
# Interpret a path prefixed with @ as a file containing a list of sources.
if arg.startswith('@'):
java_files.extend(build_utils.ReadSourcesList(arg[1:]))
files.extend(build_utils.ReadSourcesList(arg[1:]))
else:
java_files.append(arg)
files.append(arg)
# The target's .sources file contains both Java and Kotlin files. We use
# compile_kt.py to compile the Kotlin files to .class and header jars. Javac
# is run only on .java files.
java_files = [f for f in files if f.endswith('.java')]
return options, java_files

166
build/android/gyp/compile_kt.py Executable file

@ -0,0 +1,166 @@
#!/usr/bin/env python3
#
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import argparse
import logging
import os
import shutil
import sys
import time
import compile_java
from util import build_utils
def _RunCompiler(args,
kotlinc_cmd,
source_files,
jar_path,
intermediates_out_dir=None):
"""Runs the Kotlin compiler."""
logging.info('Starting _RunCompiler')
source_files = source_files.copy()
kt_files = [f for f in source_files if f.endswith('.kt')]
assert len(kt_files) > 0, 'At least one .kt file must be passed in.'
java_srcjars = args.java_srcjars
# Use jar_path's directory to ensure paths are relative (needed for goma).
temp_dir = jar_path + '.staging'
build_utils.DeleteDirectory(temp_dir)
os.makedirs(temp_dir)
try:
classes_dir = os.path.join(temp_dir, 'classes')
os.makedirs(classes_dir)
input_srcjars_dir = os.path.join(intermediates_out_dir or temp_dir,
'input_srcjars')
if java_srcjars:
logging.info('Extracting srcjars to %s', input_srcjars_dir)
build_utils.MakeDirectory(input_srcjars_dir)
for srcjar in args.java_srcjars:
source_files += build_utils.ExtractAll(srcjar,
no_clobber=True,
path=input_srcjars_dir,
pattern='*.java')
logging.info('Done extracting srcjars')
# Don't include the output directory in the initial set of args since it
# being in a temp dir makes it unstable (breaks md5 stamping).
cmd = list(kotlinc_cmd)
cmd += ['-d', classes_dir]
if args.classpath:
cmd += ['-classpath', ':'.join(args.classpath)]
# This a kotlinc plugin to generate header files for .kt files, similar to
# turbine for .java files.
jvm_abi_path = os.path.join(build_utils.KOTLIN_HOME, 'lib',
'jvm-abi-gen.jar')
cmd += [
f'-Xplugin={jvm_abi_path}', '-P',
'plugin:org.jetbrains.kotlin.jvm.abi:outputDir=' +
args.interface_jar_path
]
# Pass source paths as response files to avoid extremely long command
# lines that are tedius to debug.
source_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
with open(source_files_rsp_path, 'w') as f:
f.write(' '.join(source_files))
cmd += ['@' + source_files_rsp_path]
logging.debug('Build command %s', cmd)
start = time.time()
build_utils.CheckOutput(cmd,
print_stdout=args.chromium_code,
fail_on_output=args.warnings_as_errors)
logging.info('Kotlin compilation took %ss', time.time() - start)
compile_java.CreateJarFile(jar_path, classes_dir)
logging.info('Completed all steps in _RunCompiler')
finally:
shutil.rmtree(temp_dir)
def _ParseOptions(argv):
parser = argparse.ArgumentParser()
build_utils.AddDepfileOption(parser)
parser.add_argument('--java-srcjars',
action='append',
default=[],
help='List of srcjars to include in compilation.')
parser.add_argument(
'--generated-dir',
help='Subdirectory within target_gen_dir to place extracted srcjars and '
'annotation processor output for codesearch to find.')
parser.add_argument('--classpath', action='append', help='Classpath to use.')
parser.add_argument(
'--chromium-code',
action='store_true',
help='Whether code being compiled should be built with stricter '
'warnings for chromium code.')
parser.add_argument('--gomacc-path',
help='When set, prefix kotlinc command with gomacc')
parser.add_argument('--warnings-as-errors',
action='store_true',
help='Treat all warnings as errors.')
parser.add_argument('--jar-path', help='Jar output path.', required=True)
parser.add_argument('--interface-jar-path',
help='Interface jar output path.',
required=True)
args, extra_args = parser.parse_known_args(argv)
args.classpath = build_utils.ParseGnList(args.classpath)
args.java_srcjars = build_utils.ParseGnList(args.java_srcjars)
source_files = []
for arg in extra_args:
# Interpret a path prefixed with @ as a file containing a list of sources.
if arg.startswith('@'):
source_files.extend(build_utils.ReadSourcesList(arg[1:]))
else:
assert not arg.startswith('--'), f'Undefined option {arg}'
source_files.append(arg)
return args, source_files
def main(argv):
build_utils.InitLogging('KOTLINC_DEBUG')
argv = build_utils.ExpandFileArgs(argv)
args, source_files = _ParseOptions(argv)
kotlinc_cmd = []
if args.gomacc_path:
kotlinc_cmd.append(args.gomacc_path)
kotlinc_cmd.append(build_utils.KOTLINC_PATH)
if args.generated_dir:
# Delete any stale files in the generated directory. The purpose of
# args.generated_dir is for codesearch.
shutil.rmtree(args.generated_dir, True)
_RunCompiler(args,
kotlinc_cmd,
source_files,
args.jar_path,
intermediates_out_dir=args.generated_dir)
if args.depfile:
# GN already knows of the source files, so avoid listing individual files
# in the depfile.
build_utils.WriteDepfile(args.depfile, args.jar_path, args.classpath)
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]))

@ -0,0 +1,31 @@
# Generated by running:
# build/print_python_deps.py --root build/android/gyp --output build/android/gyp/compile_kt.pydeps build/android/gyp/compile_kt.py
../../../third_party/catapult/devil/devil/__init__.py
../../../third_party/catapult/devil/devil/android/__init__.py
../../../third_party/catapult/devil/devil/android/constants/__init__.py
../../../third_party/catapult/devil/devil/android/constants/chrome.py
../../../third_party/catapult/devil/devil/android/sdk/__init__.py
../../../third_party/catapult/devil/devil/android/sdk/keyevent.py
../../../third_party/catapult/devil/devil/android/sdk/version_codes.py
../../../third_party/catapult/devil/devil/constants/__init__.py
../../../third_party/catapult/devil/devil/constants/exit_codes.py
../../../third_party/colorama/src/colorama/__init__.py
../../../third_party/colorama/src/colorama/ansi.py
../../../third_party/colorama/src/colorama/ansitowin32.py
../../../third_party/colorama/src/colorama/initialise.py
../../../third_party/colorama/src/colorama/win32.py
../../../third_party/colorama/src/colorama/winterm.py
../../../tools/android/modularization/convenience/lookup_dep.py
../../gn_helpers.py
../../print_python_deps.py
../list_java_targets.py
../pylib/__init__.py
../pylib/constants/__init__.py
compile_java.py
compile_kt.py
javac_output_processor.py
util/__init__.py
util/build_utils.py
util/jar_info_utils.py
util/md5_check.py
util/server_utils.py

@ -3,7 +3,6 @@
# Copyright 2013 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Instruments classes and jar files.
This script corresponds to the 'jacoco_instr' action in the Java build process.
@ -13,13 +12,11 @@ jacococli.jar.
"""
import argparse
import json
import os
import shutil
import sys
import tempfile
import zipfile
from util import build_utils
@ -48,9 +45,9 @@ def _AddArguments(parser):
help='File to create with the list of source directories '
'and input path.')
parser.add_argument(
'--java-sources-file',
'--target-sources-file',
required=True,
help='File containing newline-separated .java paths')
help='File containing newline-separated .java and .kt paths')
parser.add_argument(
'--jacococli-jar', required=True, help='Path to jacococli.jar.')
parser.add_argument(
@ -134,7 +131,8 @@ def _GetAffectedClasses(jar_file, source_files):
if index == -1:
index = member.find('.class')
for source_file in source_files:
if source_file.endswith(member[:index] + '.java'):
if source_file.endswith(
(member[:index] + '.java', member[:index] + '.kt')):
affected_classes.append(member)
is_affected = True
break
@ -196,8 +194,8 @@ def _RunInstrumentCommand(parser):
args = parser.parse_args()
source_files = []
if args.java_sources_file:
source_files.extend(build_utils.ReadSourcesList(args.java_sources_file))
if args.target_sources_file:
source_files.extend(build_utils.ReadSourcesList(args.target_sources_file))
with build_utils.TempDir() as temp_dir:
instrument_cmd = build_utils.JavaCmd() + [

@ -5,7 +5,6 @@
# found in the LICENSE file.
"""Runs Android's lint tool."""
import argparse
import logging
import os
@ -423,8 +422,9 @@ def _ParseArgs(argv):
parser.add_argument('--warnings-as-errors',
action='store_true',
help='Treat all warnings as errors.')
parser.add_argument('--java-sources',
help='File containing a list of java sources files.')
parser.add_argument('--sources',
help='A list of files containing java and kotlin source '
'files.')
parser.add_argument('--aars', help='GN list of included aars.')
parser.add_argument('--srcjars', help='GN list of included srcjars.')
parser.add_argument('--manifest-path',
@ -450,7 +450,7 @@ def _ParseArgs(argv):
'on new errors.')
args = parser.parse_args(build_utils.ExpandFileArgs(argv))
args.java_sources = build_utils.ParseGnList(args.java_sources)
args.sources = build_utils.ParseGnList(args.sources)
args.aars = build_utils.ParseGnList(args.aars)
args.srcjars = build_utils.ParseGnList(args.srcjars)
args.resource_sources = build_utils.ParseGnList(args.resource_sources)
@ -483,8 +483,8 @@ def main():
return
sources = []
for java_sources_file in args.java_sources:
sources.extend(build_utils.ReadSourcesList(java_sources_file))
for sources_file in args.sources:
sources.extend(build_utils.ReadSourcesList(sources_file))
resource_sources = []
for resource_sources_file in args.resource_sources:
resource_sources.extend(build_utils.ReadSourcesList(resource_sources_file))

@ -9,6 +9,7 @@ import functools
import logging
import sys
import time
import zipfile
import javac_output_processor
from util import build_utils
@ -55,6 +56,8 @@ def main(argv):
parser.add_argument('--warnings-as-errors',
action='store_true',
help='Treat all warnings as errors.')
parser.add_argument('--kotlin-jar-path',
help='Kotlin jar to be merged into the output jar.')
options, unknown_args = parser.parse_known_args(argv)
options.classpath = build_utils.ParseGnList(options.classpath)
@ -68,6 +71,11 @@ def main(argv):
if arg.startswith('@'):
files.extend(build_utils.ReadSourcesList(arg[1:]))
# The target's .sources file contains both Java and Kotlin files. We use
# compile_kt.py to compile the Kotlin files to .class and header jars.
# Turbine is run only on .java files.
java_files = [f for f in files if f.endswith('.java')]
cmd = build_utils.JavaCmd(options.warnings_as_errors) + [
'-classpath', options.turbine_jar_path, 'com.google.turbine.main.Main'
]
@ -100,11 +108,11 @@ def main(argv):
cmd += ['--source_jars']
cmd += options.java_srcjars
if files:
if java_files:
# Use jar_path to ensure paths are relative (needed for goma).
files_rsp_path = options.jar_path + '.files_list.txt'
files_rsp_path = options.jar_path + '.java_files_list.txt'
with open(files_rsp_path, 'w') as f:
f.write(' '.join(files))
f.write(' '.join(java_files))
# Pass source paths as response files to avoid extremely long command lines
# that are tedius to debug.
cmd += ['--sources']
@ -132,6 +140,11 @@ def main(argv):
fail_on_output=options.warnings_as_errors)
end = time.time() - start
logging.info('Header compilation took %ss', end)
if options.kotlin_jar_path:
with zipfile.ZipFile(output_jar.name, 'a') as out_zip:
build_utils.MergeZips(
out_zip, [options.kotlin_jar_path],
path_transform=lambda p: p if p.endswith('.class') else None)
if options.depfile:
# GN already knows of the java files, so avoid listing individual java files

@ -37,6 +37,8 @@ DIR_SOURCE_ROOT = os.path.relpath(
JAVA_HOME = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'jdk', 'current')
JAVAC_PATH = os.path.join(JAVA_HOME, 'bin', 'javac')
JAVAP_PATH = os.path.join(JAVA_HOME, 'bin', 'javap')
KOTLIN_HOME = os.path.join(DIR_SOURCE_ROOT, 'third_party', 'kotlinc', 'current')
KOTLINC_PATH = os.path.join(KOTLIN_HOME, 'bin', 'kotlinc')
try:
string_types = basestring

@ -264,17 +264,18 @@ True to indicate that this target corresponds to a prebuilt `.jar` file.
In this case, `deps_info['unprocessed_jar_path']` will point to the source
`.jar` file. Otherwise, it will be point to a build-generated file.
* `deps_info['java_sources_file']`:
Path to a single `.sources` file listing all the Java sources that were used
to generate the library (simple text format, one `.jar` path per line).
* `deps_info['target_sources_file']`:
Path to a single `.sources` file listing all the Java and Kotlin sources that
were used to generate the library (simple text format, one `.jar` path per
line).
* `deps_info['lint_android_manifest']`:
Path to an AndroidManifest.xml file to use for this lint target.
* `deps_info['lint_java_sources']`:
The list of all `deps_info['java_sources_file']` entries for all library
* `deps_info['lint_sources']`:
The list of all `deps_info['target_sources_file']` entries for all library
dependencies that are chromium code. Note: this is a list of files, where each
file contains a list of Java source files. This is used for lint.
file contains a list of Java and Kotlin source files. This is used for lint.
* `deps_info['lint_aars']`:
List of all aars from transitive java dependencies. This allows lint to collect
@ -431,9 +432,10 @@ into the final APK as-is.
NOTE: This has nothing to do with *Android* resources.
* `jni['all_source']`
The list of all `deps_info['java_sources_file']` entries for all library
The list of all `deps_info['target_sources_file']` entries for all library
dependencies for this APK. Note: this is a list of files, where each file
contains a list of Java source files. This is used for JNI registration.
contains a list of Java and Kotlin source files. This is used for JNI
registration.
* `deps_info['proguard_all_configs']`:
The collection of all 'deps_info['proguard_configs']` values from this target
@ -1086,7 +1088,7 @@ def main(argv):
help='Path to the interface .jar to use for javac classpath purposes.')
parser.add_option('--is-prebuilt', action='store_true',
help='Whether the jar was compiled or pre-compiled.')
parser.add_option('--java-sources-file', help='Path to .sources file')
parser.add_option('--target-sources-file', help='Path to .sources file')
parser.add_option('--bundled-srcjars',
help='GYP-list of .srcjars that have been included in this java_library.')
parser.add_option('--supports-android', action='store_true',
@ -1423,8 +1425,8 @@ def main(argv):
deps_info['bundled_srcjars'] = build_utils.ParseGnList(
options.bundled_srcjars)
if options.java_sources_file:
deps_info['java_sources_file'] = options.java_sources_file
if options.target_sources_file:
deps_info['target_sources_file'] = options.target_sources_file
if is_java_target:
if options.main_class:
@ -1456,10 +1458,12 @@ def main(argv):
'robolectric_binary',
'dist_aar'):
deps_info['jni'] = {}
all_java_sources = [c['java_sources_file'] for c in all_library_deps
if 'java_sources_file' in c]
if options.java_sources_file:
all_java_sources.append(options.java_sources_file)
all_target_sources = [
c['target_sources_file'] for c in all_library_deps
if 'target_sources_file' in c
]
if options.target_sources_file:
all_target_sources.append(options.target_sources_file)
if is_apk_or_module_target or options.type in ('group', 'java_library',
'robolectric_binary'):
@ -1746,18 +1750,18 @@ def main(argv):
# Collect all sources and resources at the apk/bundle_module level.
lint_aars = set()
lint_srcjars = set()
lint_java_sources = set()
lint_sources = set()
lint_resource_sources = set()
lint_resource_zips = set()
if options.java_sources_file:
lint_java_sources.add(options.java_sources_file)
if options.target_sources_file:
lint_sources.add(options.target_sources_file)
if options.bundled_srcjars:
lint_srcjars.update(deps_info['bundled_srcjars'])
for c in all_library_deps:
if c['chromium_code'] and c['requires_android']:
if 'java_sources_file' in c:
lint_java_sources.add(c['java_sources_file'])
if 'target_sources_file' in c:
lint_sources.add(c['target_sources_file'])
lint_srcjars.update(c['bundled_srcjars'])
if 'aar_path' in c:
lint_aars.add(c['aar_path'])
@ -1777,7 +1781,7 @@ def main(argv):
deps_info['lint_aars'] = sorted(lint_aars)
deps_info['lint_srcjars'] = sorted(lint_srcjars)
deps_info['lint_java_sources'] = sorted(lint_java_sources)
deps_info['lint_sources'] = sorted(lint_sources)
deps_info['lint_resource_sources'] = sorted(lint_resource_sources)
deps_info['lint_resource_zips'] = sorted(lint_resource_zips)
deps_info['lint_extra_android_manifests'] = []
@ -1797,7 +1801,7 @@ def main(argv):
jni_all_source = set()
lint_aars = set()
lint_srcjars = set()
lint_java_sources = set()
lint_sources = set()
lint_resource_sources = set()
lint_resource_zips = set()
lint_extra_android_manifests = set()
@ -1816,7 +1820,7 @@ def main(argv):
jni_all_source.update(c['jni']['all_source'])
lint_aars.update(c['lint_aars'])
lint_srcjars.update(c['lint_srcjars'])
lint_java_sources.update(c['lint_java_sources'])
lint_sources.update(c['lint_sources'])
lint_resource_sources.update(c['lint_resource_sources'])
lint_resource_zips.update(c['lint_resource_zips'])
module = modules[n] = {}
@ -1826,7 +1830,7 @@ def main(argv):
deps_info['jni'] = {'all_source': sorted(jni_all_source)}
deps_info['lint_aars'] = sorted(lint_aars)
deps_info['lint_srcjars'] = sorted(lint_srcjars)
deps_info['lint_java_sources'] = sorted(lint_java_sources)
deps_info['lint_sources'] = sorted(lint_sources)
deps_info['lint_resource_sources'] = sorted(lint_resource_sources)
deps_info['lint_resource_zips'] = sorted(lint_resource_zips)
deps_info['lint_extra_android_manifests'] = sorted(
@ -1838,7 +1842,7 @@ def main(argv):
if is_apk_or_module_target or options.type in ('group', 'java_library',
'robolectric_binary',
'dist_aar'):
deps_info['jni']['all_source'] = sorted(set(all_java_sources))
deps_info['jni']['all_source'] = sorted(set(all_target_sources))
system_jars = [c['unprocessed_jar_path'] for c in system_library_deps]
system_interface_jars = [c['interface_jar_path'] for c in system_library_deps]

@ -253,6 +253,12 @@ template("write_build_config") {
rebase_path(invoker.ijar_path, root_build_dir),
]
}
if (defined(invoker.kotlinc_jar_path)) {
args += [
"--kotlinc-jar-path",
rebase_path(invoker.kotlinc_jar_path, root_build_dir),
]
}
if (defined(invoker.java_resources_jar)) {
args += [
"--java-resources-jar-path",
@ -474,10 +480,10 @@ template("write_build_config") {
}
}
if (defined(invoker.java_sources_file)) {
if (defined(invoker.target_sources_file)) {
args += [
"--java-sources-file",
rebase_path(invoker.java_sources_file, root_build_dir),
"--target-sources-file",
rebase_path(invoker.target_sources_file, root_build_dir),
]
}
if (defined(invoker.srcjar)) {
@ -1132,7 +1138,7 @@ if (enable_java_templates) {
# Lint requires all source and all resource files to be passed in the
# same invocation for checks like UnusedResources.
"--java-sources=@FileArg($_rebased_build_config:deps_info:lint_java_sources)",
"--sources=@FileArg($_rebased_build_config:deps_info:lint_sources)",
"--aars=@FileArg($_rebased_build_config:deps_info:lint_aars)",
"--srcjars=@FileArg($_rebased_build_config:deps_info:lint_srcjars)",
"--resource-sources=@FileArg($_rebased_build_config:deps_info:lint_resource_sources)",
@ -1719,7 +1725,7 @@ if (enable_java_templates) {
_jacococli_jar = "//third_party/jacoco/lib/jacococli.jar"
script = "//build/android/gyp/jacoco_instr.py"
inputs = invoker.java_files + [
inputs = invoker.source_files + [
_jacococli_jar,
invoker.input_jar_path,
]
@ -1734,8 +1740,8 @@ if (enable_java_templates) {
rebase_path(invoker.output_jar_path, root_build_dir),
"--sources-json-file",
rebase_path(_sources_json_file, root_build_dir),
"--java-sources-file",
rebase_path(invoker.java_sources_file, root_build_dir),
"--target-sources-file",
rebase_path(invoker.target_sources_file, root_build_dir),
"--jacococli-jar",
rebase_path(_jacococli_jar, root_build_dir),
]
@ -1819,8 +1825,8 @@ if (enable_java_templates) {
deps = [ ":$_filter_jar_target_name" ] + invoker.deps
forward_variables_from(invoker,
[
"java_files",
"java_sources_file",
"source_files",
"target_sources_file",
])
input_jar_path = _filter_jar_output_jar
@ -2820,22 +2826,23 @@ if (enable_java_templates) {
# target that includes javac:processor_classes entries (i.e. there is no
# variable here that can be used for this purpose).
#
# Note also the peculiar use of java_files / java_sources_file. The content
# of the java_files list and the java_sources_file file must match exactly.
# This rule uses java_files only to list the inputs to the action that
# calls compile_java.py, but will pass the list of Java source files
# with the '@${java_sources_file}" command-line syntax. Not a problem in
# practice since this is only called from java_library_impl() that sets up
# the variables properly.
# Note also the peculiar use of java_files / target_sources_file. The content
# of the java_files list and the .java files in target_sources_file file must
# match exactly (extra .kt files in target_sources_file will be ignored by
# compile_java.py). This rule uses java_files only to list the inputs to the
# action that calls compile_java.py, but will pass the list of all target
# source files with the '@${target_sources_file}" command-line syntax. Not a
# problem in practice since this is only called from java_library_impl() that
# sets up the variables properly.
#
# Variables:
# main_target_name: Used when extracting srcjars for codesearch.
# java_files: Optional list of Java source file paths.
# srcjar_deps: Optional list of .srcjar dependencies (not file paths).
# The corresponding source files they contain will be compiled too.
# java_sources_file: Optional path to file containing list of Java source
# file paths. This must always be provided if java_files is not empty
# and must match it exactly.
# target_sources_file: Optional path to file containing list of source file
# paths. This must always be provided if java_files is not empty and the
# .java files in it must match the list of java_files exactly.
# build_config: Path to the .build_config.json file of the corresponding
# java_library_impl() target. The following entries will be used by this
# template: javac:srcjars, deps_info:javac_full_classpath,
@ -2880,7 +2887,7 @@ if (enable_java_templates) {
_srcjar_deps = []
if (defined(invoker.srcjar_deps)) {
_srcjar_deps += invoker.srcjar_deps
_srcjar_deps = invoker.srcjar_deps
}
_java_srcjars = []
@ -2924,7 +2931,7 @@ if (enable_java_templates) {
}
inputs = invoker.java_files + _java_srcjars + [ _build_config ]
if (invoker.java_files != []) {
inputs += [ invoker.java_sources_file ]
inputs += [ invoker.target_sources_file ]
}
_rebased_build_config = rebase_path(_build_config, root_build_dir)
@ -2960,6 +2967,16 @@ if (enable_java_templates) {
args += [ "--classpath=$_header_jar_classpath" ]
}
if (defined(invoker.kotlin_jar_path)) {
inputs += [ invoker.kotlin_jar_path ]
_rebased_kotlin_jar_path =
rebase_path(invoker.kotlin_jar_path, root_build_dir)
args += [
"--kotlin-jar-path=$_rebased_kotlin_jar_path",
"--classpath=$_rebased_kotlin_jar_path",
]
}
if (invoker.use_turbine) {
# Prefer direct deps for turbine as much as possible.
args += [ "--classpath=@FileArg($_rebased_build_config:javac:interface_classpath)" ]
@ -3041,7 +3058,8 @@ if (enable_java_templates) {
rebase_path(file_tuple[0], root_build_dir) + ":" + file_tuple[1] ]
}
if (invoker.java_files != []) {
args += [ "@" + rebase_path(invoker.java_sources_file, root_build_dir) ]
args +=
[ "@" + rebase_path(invoker.target_sources_file, root_build_dir) ]
}
foreach(e, _javac_args) {
args += [ "--javac-arg=" + e ]
@ -3049,6 +3067,95 @@ if (enable_java_templates) {
}
}
# Compile Kotlin source files into .class files and store them in a .jar.
# This explicitly does not run annotation processing on the Kotlin files.
# Java files and srcjars are also passed to kotlinc for reference, although
# no .class files will be generated for any Java files. A subsequent call to
# javac will be required to actually compile Java files into .class files.
#
# This action also creates a "header" .jar file for the Kotlin source files.
# It is similar to using turbine to create headers for Java files, but since
# turbine does not support Kotlin files, this is done via a plugin for
# kotlinc instead, at the same time as compilation (whereas turbine is run as
# a separate action before javac compilation).
template("compile_kt") {
forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
_build_config = invoker.build_config
_chromium_code = invoker.chromium_code
_srcjar_deps = []
if (defined(invoker.srcjar_deps)) {
_srcjar_deps = invoker.srcjar_deps
}
_java_srcjars = []
foreach(dep, _srcjar_deps) {
_dep_gen_dir = get_label_info(dep, "target_gen_dir")
_dep_name = get_label_info(dep, "name")
_java_srcjars += [ "$_dep_gen_dir/$_dep_name.srcjar" ]
}
action_with_pydeps(target_name) {
script = "//build/android/gyp/compile_kt.py"
depfile = "$target_gen_dir/$target_name.d"
deps = _srcjar_deps
if (defined(invoker.deps)) {
deps += invoker.deps
}
outputs = [
invoker.output_jar_path,
invoker.output_interface_jar_path,
]
inputs = invoker.source_files + _java_srcjars + [
_build_config,
invoker.target_sources_file,
]
_rebased_build_config = rebase_path(_build_config, root_build_dir)
_rebased_output_jar_path =
rebase_path(invoker.output_jar_path, root_build_dir)
_rebased_output_interface_jar_path =
rebase_path(invoker.output_interface_jar_path, root_build_dir)
_rebased_java_srcjars = rebase_path(_java_srcjars, root_build_dir)
_rebased_depfile = rebase_path(depfile, root_build_dir)
_rebased_generated_dir = rebase_path(
"$target_gen_dir/${invoker.main_target_name}/generated_java",
root_build_dir)
args = [
"--depfile=$_rebased_depfile",
"--generated-dir=$_rebased_generated_dir",
"--jar-path=$_rebased_output_jar_path",
"--interface-jar-path=$_rebased_output_interface_jar_path",
"--java-srcjars=$_rebased_java_srcjars",
]
# SDK jar must be first on classpath.
if (invoker.include_android_sdk) {
args += [ "--classpath=@FileArg($_rebased_build_config:android:sdk_interface_jars)" ]
}
args += [ "--classpath=@FileArg($_rebased_build_config:deps_info:javac_full_interface_classpath)" ]
if (use_java_goma) {
args += [ "--gomacc-path=$goma_dir/gomacc" ]
# Override the default action_pool when goma is enabled.
pool = "//build/config/android:goma_javac_pool"
}
if (_chromium_code) {
args += [ "--chromium-code" ]
if (treat_warnings_as_errors) {
args += [ "--warnings-as-errors" ]
}
}
args += [ "@" + rebase_path(invoker.target_sources_file, root_build_dir) ]
}
}
# Create an interface jar from a normal jar.
#
# Variables
@ -3242,15 +3349,16 @@ if (enable_java_templates) {
_main_target_name = invoker.main_target_name
}
_java_files = []
_source_files = []
if (defined(invoker.sources)) {
_java_files = invoker.sources
_source_files = invoker.sources
}
_srcjar_deps = []
if (defined(invoker.srcjar_deps)) {
_srcjar_deps = invoker.srcjar_deps
}
_has_sources = _java_files != [] || _srcjar_deps != []
_has_sources = _source_files != [] || _srcjar_deps != []
if (_is_prebuilt) {
assert(!_has_sources)
@ -3277,10 +3385,10 @@ if (enable_java_templates) {
_chromium_code =
filter_exclude([ get_label_info(":$_main_target_name", "dir") ],
[ "*\bthird_party\b*" ]) != []
if (!_chromium_code && !_is_prebuilt && _java_files != []) {
if (!_chromium_code && !_is_prebuilt && _source_files != []) {
# Unless third_party code has an org.chromium file in it.
_chromium_code =
filter_exclude(_java_files, [ "*\bchromium\b*" ]) != _java_files
filter_exclude(_source_files, [ "*\bchromium\b*" ]) != _source_files
}
}
@ -3307,7 +3415,7 @@ if (enable_java_templates) {
_build_device_jar = _type != "system_java_library" && _supports_android
_jacoco_instrument =
use_jacoco_coverage && _chromium_code && _java_files != [] &&
use_jacoco_coverage && _chromium_code && _source_files != [] &&
_build_device_jar && (!defined(invoker.testonly) || !invoker.testonly)
if (defined(invoker.jacoco_never_instrument)) {
_jacoco_instrument =
@ -3452,12 +3560,10 @@ if (enable_java_templates) {
"_javac_classpath_deps",
])
if (_java_files != []) {
_java_sources_file = "$target_gen_dir/$_main_target_name.sources"
if (defined(invoker.java_sources_file)) {
_java_sources_file = invoker.java_sources_file
}
write_file(_java_sources_file, rebase_path(_java_files, root_build_dir))
if (_source_files != []) {
_target_sources_file = "$target_gen_dir/$_main_target_name.sources"
write_file(_target_sources_file,
rebase_path(_source_files, root_build_dir))
}
write_build_config(_build_config_target_name) {
@ -3559,8 +3665,8 @@ if (enable_java_templates) {
device_jar_path = _device_processed_jar_path
dex_path = _dex_path
}
if (_java_files != []) {
java_sources_file = _java_sources_file
if (_source_files != []) {
target_sources_file = _target_sources_file
}
bundled_srcjars = []
@ -3586,6 +3692,9 @@ if (enable_java_templates) {
}
if (_has_sources) {
_kt_files = filter_include(_source_files, [ "*.kt" ])
_java_files = filter_exclude(_source_files, [ "*.kt" ])
if (defined(invoker.enable_errorprone)) {
_enable_errorprone = invoker.enable_errorprone
} else {
@ -3617,6 +3726,25 @@ if (enable_java_templates) {
_srcjar_deps += [ ":$_fake_rjava_target" ]
}
if (_kt_files != []) {
_compile_kt_target_name = "${_main_target_name}__compile_kt"
_kotlinc_jar_path = "$target_out_dir/$_output_name.kotlinc.jar"
_kotlin_interface_jar_path =
"$target_out_dir/$_output_name.kt-jvm-abi.jar"
compile_kt(_compile_kt_target_name) {
deps = _header_classpath_deps
output_jar_path = _kotlinc_jar_path
output_interface_jar_path = _kotlin_interface_jar_path
main_target_name = _main_target_name
build_config = _build_config
srcjar_deps = _srcjar_deps
source_files = _source_files
target_sources_file = _target_sources_file
chromium_code = _chromium_code
include_android_sdk = _is_robolectric || _requires_android
}
}
template("compile_java_helper") {
_enable_errorprone =
defined(invoker.enable_errorprone) && invoker.enable_errorprone
@ -3642,6 +3770,10 @@ if (enable_java_templates) {
deps += invoker.deps
}
output_jar_path = invoker.output_jar_path
if (defined(invoker.kotlin_jar_path)) {
deps += [ ":$_compile_kt_target_name" ]
kotlin_jar_path = invoker.kotlin_jar_path
}
enable_errorprone = _enable_errorprone
use_turbine = defined(invoker.use_turbine) && invoker.use_turbine
@ -3656,7 +3788,7 @@ if (enable_java_templates) {
}
if (java_files != []) {
java_sources_file = _java_sources_file
target_sources_file = _target_sources_file
}
chromium_code = _chromium_code
include_android_sdk = _is_robolectric || _requires_android
@ -3682,6 +3814,9 @@ if (enable_java_templates) {
output_jar_path = _final_ijar_path
generated_jar_path = _generated_jar_path
deps = _annotation_processor_deps
if (_kt_files != []) {
kotlin_jar_path = _kotlin_interface_jar_path
}
}
_compile_java_target = "${_main_target_name}__compile_java"
@ -3691,6 +3826,9 @@ if (enable_java_templates) {
deps = [ ":$_header_target_name" ]
header_jar_path = _final_ijar_path
generated_jar_path = _generated_jar_path
if (_kt_files != []) {
kotlin_jar_path = _kotlinc_jar_path
}
}
if (_enable_errorprone) {
_compile_java_errorprone_target = "${_main_target_name}__errorprone"
@ -3704,6 +3842,9 @@ if (enable_java_templates) {
javac_args += invoker.errorprone_args
}
deps = [ ":$_header_target_name" ]
if (_kt_files != []) {
kotlin_jar_path = _kotlinc_jar_path
}
header_jar_path = _final_ijar_path
generated_jar_path = _generated_jar_path
output_jar_path = "$target_out_dir/$target_name.errorprone.stamp"
@ -3818,8 +3959,8 @@ if (enable_java_templates) {
output_jar_path = _host_processed_jar_path
jacoco_instrument = _jacoco_instrument
if (_jacoco_instrument) {
java_files = _java_files
java_sources_file = _java_sources_file
source_files = _source_files
target_sources_file = _target_sources_file
}
# _java_host_deps isn't necessary for process_java_library(), but is
@ -3853,8 +3994,8 @@ if (enable_java_templates) {
output_jar_path = _device_processed_jar_path
jacoco_instrument = _jacoco_instrument
if (_jacoco_instrument) {
java_files = _java_files
java_sources_file = _java_sources_file
source_files = _source_files
target_sources_file = _target_sources_file
}
}
_process_device_jar_deps = [ ":${_process_device_jar_target_name}" ]

@ -418,7 +418,7 @@ if (enable_java_templates && is_android) {
inputs += [ _build_config ]
if (defined(invoker.no_transitive_deps) && invoker.no_transitive_deps) {
args += [ "--sources-files=@FileArg($_rebased_build_config:deps_info:java_sources_file)" ]
args += [ "--sources-files=@FileArg($_rebased_build_config:deps_info:target_sources_file)" ]
} else {
args += [
# This is a list of .sources files.

@ -17,6 +17,9 @@ How to update:
3. Upload and land the CL.
4. Wait for the 3pp packager (https://ci.chromium.org/p/chromium/builders/ci/3pp-linux-amd64-packager)
to create the new instance at https://chrome-infra-packages.appspot.com/p/chromium/third_party/kotlinc/+/
* The bot runs at regular intervals. Ping a trooper or build@chromium.org to
trigger it if you need it sooner:
https://luci-scheduler.appspot.com/jobs/chromium/3pp-linux-amd64-packager
5. Update instance ID in //DEPS
Local Modifications:

16
third_party/kotlinc/print_version.sh vendored Executable file

@ -0,0 +1,16 @@
#!/bin/bash
# Copyright 2023 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
set -e
DIR_SRC_ROOT=$(pwd)/
DIR_SRC_ROOT=${DIR_SRC_ROOT%/src/*}/src
SUBDIR=$(cd $(dirname $0); pwd)
SUBDIR="${SUBDIR#$DIR_SRC_ROOT/}"
CIPD_PACKAGE=chromium/$SUBDIR
exec $DIR_SRC_ROOT/build/android/print_cipd_version.py \
--subdir "$SUBDIR/current" \
--cipd-package "$CIPD_PACKAGE" \
"$@"