xref: /aosp_15_r20/external/cronet/build/android/gyp/compile_kt.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1#!/usr/bin/env python3
2#
3# Copyright 2023 The Chromium Authors
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6
7import argparse
8import logging
9import os
10import shutil
11import sys
12import time
13
14import compile_java
15
16from util import build_utils
17import action_helpers  # build_utils adds //build to sys.path.
18
19
20def _RunCompiler(args,
21                 kotlinc_cmd,
22                 source_files,
23                 jar_path,
24                 intermediates_out_dir=None):
25  """Runs the Kotlin compiler."""
26  logging.info('Starting _RunCompiler')
27
28  source_files = source_files.copy()
29  kt_files = [f for f in source_files if f.endswith('.kt')]
30  assert len(kt_files) > 0, 'At least one .kt file must be passed in.'
31
32  java_srcjars = args.java_srcjars
33
34  # Use jar_path's directory to ensure paths are relative (needed for goma).
35  temp_dir = jar_path + '.staging'
36  build_utils.DeleteDirectory(temp_dir)
37  os.makedirs(temp_dir)
38  try:
39    classes_dir = os.path.join(temp_dir, 'classes')
40    os.makedirs(classes_dir)
41
42    input_srcjars_dir = os.path.join(intermediates_out_dir or temp_dir,
43                                     'input_srcjars')
44
45    if java_srcjars:
46      logging.info('Extracting srcjars to %s', input_srcjars_dir)
47      build_utils.MakeDirectory(input_srcjars_dir)
48      for srcjar in args.java_srcjars:
49        source_files += build_utils.ExtractAll(srcjar,
50                                               no_clobber=True,
51                                               path=input_srcjars_dir,
52                                               pattern='*.java')
53      logging.info('Done extracting srcjars')
54
55    # Don't include the output directory in the initial set of args since it
56    # being in a temp dir makes it unstable (breaks md5 stamping).
57    cmd = list(kotlinc_cmd)
58    cmd += ['-d', classes_dir]
59
60    if args.classpath:
61      cmd += ['-classpath', ':'.join(args.classpath)]
62
63    # This a kotlinc plugin to generate header files for .kt files, similar to
64    # turbine for .java files.
65    jvm_abi_path = os.path.join(build_utils.KOTLIN_HOME, 'lib',
66                                'jvm-abi-gen.jar')
67    cmd += [
68        f'-Xplugin={jvm_abi_path}', '-P',
69        'plugin:org.jetbrains.kotlin.jvm.abi:outputDir=' +
70        args.interface_jar_path
71    ]
72
73    # Pass source paths as response files to avoid extremely long command
74    # lines that are tedius to debug.
75    source_files_rsp_path = os.path.join(temp_dir, 'files_list.txt')
76    with open(source_files_rsp_path, 'w') as f:
77      f.write(' '.join(source_files))
78    cmd += ['@' + source_files_rsp_path]
79
80    # Explicitly set JAVA_HOME since some bots do not have this already set.
81    env = os.environ.copy()
82    env['JAVA_HOME'] = build_utils.JAVA_HOME
83
84    logging.debug('Build command %s', cmd)
85    start = time.time()
86    build_utils.CheckOutput(cmd,
87                            env=env,
88                            print_stdout=args.chromium_code,
89                            fail_on_output=args.warnings_as_errors)
90    logging.info('Kotlin compilation took %ss', time.time() - start)
91
92    compile_java.CreateJarFile(jar_path, classes_dir)
93
94    logging.info('Completed all steps in _RunCompiler')
95  finally:
96    shutil.rmtree(temp_dir)
97
98
99def _ParseOptions(argv):
100  parser = argparse.ArgumentParser()
101  action_helpers.add_depfile_arg(parser)
102
103  parser.add_argument('--java-srcjars',
104                      action='append',
105                      default=[],
106                      help='List of srcjars to include in compilation.')
107  parser.add_argument(
108      '--generated-dir',
109      help='Subdirectory within target_gen_dir to place extracted srcjars and '
110      'annotation processor output for codesearch to find.')
111  parser.add_argument('--classpath', action='append', help='Classpath to use.')
112  parser.add_argument(
113      '--chromium-code',
114      action='store_true',
115      help='Whether code being compiled should be built with stricter '
116      'warnings for chromium code.')
117  parser.add_argument('--gomacc-path',
118                      help='When set, prefix kotlinc command with gomacc')
119  parser.add_argument('--warnings-as-errors',
120                      action='store_true',
121                      help='Treat all warnings as errors.')
122  parser.add_argument('--jar-path', help='Jar output path.', required=True)
123  parser.add_argument('--interface-jar-path',
124                      help='Interface jar output path.',
125                      required=True)
126
127  args, extra_args = parser.parse_known_args(argv)
128
129  args.classpath = action_helpers.parse_gn_list(args.classpath)
130  args.java_srcjars = action_helpers.parse_gn_list(args.java_srcjars)
131
132  source_files = []
133  for arg in extra_args:
134    # Interpret a path prefixed with @ as a file containing a list of sources.
135    if arg.startswith('@'):
136      source_files.extend(build_utils.ReadSourcesList(arg[1:]))
137    else:
138      assert not arg.startswith('--'), f'Undefined option {arg}'
139      source_files.append(arg)
140
141  return args, source_files
142
143
144def main(argv):
145  build_utils.InitLogging('KOTLINC_DEBUG')
146  argv = build_utils.ExpandFileArgs(argv)
147  args, source_files = _ParseOptions(argv)
148
149  kotlinc_cmd = []
150  if args.gomacc_path:
151    kotlinc_cmd.append(args.gomacc_path)
152  kotlinc_cmd.append(build_utils.KOTLINC_PATH)
153
154  kotlinc_cmd += [
155      '-no-jdk',  # Avoid depending on the bundled JDK.
156      # Avoid depending on the bundled Kotlin stdlib. This may have a version
157      # skew with the one in //third_party/android_deps (which is the one we
158      # prefer to use).
159      '-no-stdlib',
160      # Avoid depending on the bundled Kotlin reflect libs.
161      '-no-reflect',
162  ]
163
164  if args.generated_dir:
165    # Delete any stale files in the generated directory. The purpose of
166    # args.generated_dir is for codesearch.
167    shutil.rmtree(args.generated_dir, True)
168
169  _RunCompiler(args,
170               kotlinc_cmd,
171               source_files,
172               args.jar_path,
173               intermediates_out_dir=args.generated_dir)
174
175  if args.depfile:
176    # GN already knows of the source files, so avoid listing individual files
177    # in the depfile.
178    action_helpers.write_depfile(args.depfile, args.jar_path, args.classpath)
179
180
181if __name__ == '__main__':
182  sys.exit(main(sys.argv[1:]))
183