1# Copyright 2022 Google LLC. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the License); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Common Kotlin definitions.""" 16 17load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") 18load("//kotlin/jvm/util:file_factory.bzl", "FileFactory") 19load("//kotlin/jvm/util:srcjars.bzl", "kt_srcjars") 20load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains") 21load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") 22load("@bazel_skylib//lib:sets.bzl", "sets") 23load("//bazel:stubs.bzl", "lint_actions") 24load("//bazel:stubs.bzl", "jspecify_flags") 25load("//bazel:stubs.bzl", "is_android_lint_exempt") 26load("//bazel:stubs.bzl", "BASE_JVMOPTS") 27 28visibility(RULES_DEFS_THAT_COMPILE_KOTLIN) 29 30# TODO: Remove the _ALLOWED_*_RULES lists to determine which rules 31# are accepted dependencies to Kotlin rules as the approach does not scale 32# because it will require a cl + release for every new rule. 33 34_EXT = struct( 35 KT = ".kt", 36 JAVA = ".java", 37 JAR = ".jar", 38 SRCJAR = ".srcjar", 39) 40 41_KT_FILE_TYPES = [_EXT.KT] 42 43_KT_JVM_FILE_TYPES = [ 44 _EXT.JAVA, 45 _EXT.KT, 46 _EXT.SRCJAR, 47] 48 49_JAR_FILE_TYPE = [_EXT.JAR] 50 51_SRCJAR_FILE_TYPES = [_EXT.JAR, _EXT.SRCJAR] 52 53_RULE_FAMILY = struct( 54 UNKNOWN = 0, 55 JVM_LIBRARY = 1, 56 ANDROID_LIBRARY = 2, 57) 58 59def _is_dir(file, basename): 60 return file.is_directory and file.basename == basename 61 62def _is_file(file, extension): 63 return (not file.is_directory) and file.path.endswith(extension) 64 65def _is_kt_src(src): 66 """Decides if `src` Kotlin code. 67 68 Either: 69 - a Kotlin source file 70 - a tree-artifact expected to contain only Kotlin source files 71 """ 72 73 return _is_file(src, _EXT.KT) or _is_dir(src, "kotlin") 74 75# Compute module name based on target (b/139403883), similar to Swift 76def _derive_module_name(ctx): 77 label = _get_original_kt_target_label(ctx) 78 package_part = label.package.replace("/", ".") # .package has no leading '//' 79 name_part = label.name 80 if package_part: 81 return package_part + "_" + name_part 82 return name_part 83 84def _get_common_and_user_kotlinc_args(ctx, toolchain, extra_kotlinc_args): 85 return toolchain.kotlinc_cli_flags + [ 86 # Set module name so module-level metadata is preserved when merging Jars (b/139403883) 87 "-module-name", 88 _derive_module_name(ctx), 89 ] + jspecify_flags(ctx) + extra_kotlinc_args 90 91def _kt_plugins_map( 92 android_lint_rulesets = [], 93 java_plugin_datas = depset(), 94 java_plugin_infos = [], 95 kt_codegen_plugin_infos = depset(), 96 kt_compiler_plugin_infos = []): 97 """A struct containing all the plugin types understood by rules_kotlin. 98 99 Args: 100 android_lint_rulesets: (list[lint_actions.AndroidLintRulesInfo]) Android Lint checkers. 101 Each JAR is self-contained and should be loaded in an isolated classloader. 102 java_plugin_datas: (depset[JavaPluginData]) for KtCodegenProcessing. 103 java_plugin_infos: (list[JavaPluginInfo]) 104 kt_codegen_plugin_infos: (depset[KtCodegenPluginInfo]) for KtCodegenProcessing. 105 kt_compiler_plugin_infos: (list[KtCompilerPluginInfo]) 106 """ 107 return struct( 108 android_lint_rulesets = android_lint_rulesets, 109 java_plugin_datas = java_plugin_datas, 110 java_plugin_infos = java_plugin_infos, 111 kt_codegen_plugin_infos = kt_codegen_plugin_infos, 112 kt_compiler_plugin_infos = kt_compiler_plugin_infos, 113 ) 114 115def _run_kotlinc( 116 ctx, 117 file_factory, 118 kt_srcs = [], 119 common_srcs = [], 120 java_srcs_and_dirs = [], 121 kotlincopts = [], 122 compile_jdeps = depset(), 123 toolchain = None, 124 classpath = [], 125 directdep_jars = depset(), 126 plugins = _kt_plugins_map(), 127 friend_jars = depset(), 128 enforce_strict_deps = False, 129 enforce_complete_jdeps = False, 130 mnemonic = None, 131 message_prefix = ""): 132 direct_inputs = [] 133 transitive_inputs = [] 134 outputs = [] 135 136 # Args to kotlinc. 137 # 138 # These go at the end of the commandline. They should be passed through all wrapper 139 # layers without post-processing, except to unpack param files. 140 kotlinc_args = ctx.actions.args() 141 kotlinc_args.use_param_file("@%s", use_always = True) # Use params file to handle long classpaths (b/76185759) 142 kotlinc_args.set_param_file_format("multiline") # kotlinc only supports double-quotes ("): https://youtrack.jetbrains.com/issue/KT-24472 143 144 # Args to the kotlinc JVM 145 # 146 # These cannot use a param file because the file wouldn't be read until after the JVM launches. 147 # Values will be prepended with --jvm_flag= for detection. 148 jvm_args = [] 149 150 kotlinc_args.add_joined("-cp", classpath, join_with = ":") 151 transitive_inputs.append(classpath) 152 kotlinc_args.add_all(_get_common_and_user_kotlinc_args(ctx, toolchain, kotlincopts)) 153 154 kotlinc_args.add(toolchain.jvm_abi_gen_plugin, format = "-Xplugin=%s") 155 direct_inputs.append(toolchain.jvm_abi_gen_plugin) 156 kt_ijar = file_factory.declare_file("-ijar.jar") 157 kotlinc_args.add("-P", kt_ijar, format = "plugin:org.jetbrains.kotlin.jvm.abi:outputDir=%s") 158 outputs.append(kt_ijar) 159 160 for p in plugins.kt_compiler_plugin_infos: 161 kotlinc_args.add(p.jar, format = "-Xplugin=%s") 162 direct_inputs.append(p.jar) 163 kotlinc_args.add_all(p.args, before_each = "-P") 164 165 # Common sources must also be specified as -Xcommon-sources= in addition to appearing in the 166 # source list. 167 if common_srcs: 168 kotlinc_args.add("-Xmulti-platform=true") 169 kotlinc_args.add_all(common_srcs, format_each = "-Xcommon-sources=%s") 170 direct_inputs.extend(common_srcs) 171 172 output = file_factory.declare_file(".jar") 173 kotlinc_args.add("-d", output) 174 outputs.insert(0, output) # The param file name is derived from the 0th output 175 kotlinc_args.add_all(kt_srcs) 176 direct_inputs.extend(kt_srcs) 177 kotlinc_args.add_all(common_srcs) 178 direct_inputs.extend(common_srcs) 179 180 if java_srcs_and_dirs: 181 # This expands any directories into their contained files 182 kotlinc_args.add_all(java_srcs_and_dirs) 183 direct_inputs.extend(java_srcs_and_dirs) 184 185 kotlinc_args.add_joined(friend_jars, format_joined = "-Xfriend-paths=%s", join_with = ",") 186 transitive_inputs.append(friend_jars) 187 188 # Do not change the "shape" or mnemonic of this action without consulting Kythe team 189 # (kythe-eng@), to avoid breaking the Kotlin Kythe extractor which "shadows" this action. In 190 # particular, the extractor expects this to be a vanilla "spawn" (ctx.actions.run) so don't 191 # change this to ctx.actions.run_shell or something else without considering Kythe implications 192 # (b/112439843). 193 ctx.actions.run( 194 executable = toolchain.kotlin_compiler, 195 arguments = ["--jvm_flag=" + x for x in jvm_args] + [kotlinc_args], 196 inputs = depset(direct = direct_inputs, transitive = transitive_inputs), 197 outputs = outputs, 198 mnemonic = mnemonic, 199 progress_message = message_prefix + str(_get_original_kt_target_label(ctx)), 200 execution_requirements = { 201 # Ensure comparable results across runs (cold builds, same machine) 202 "no-cache": "1", 203 "no-remote": "1", 204 } if toolchain.is_profiling_enabled(ctx.label) else { 205 "worker-key-mnemonic": "Kt2JavaCompile", 206 }, 207 toolchain = toolchain.toolchain_type, 208 ) 209 210 return struct( 211 output_jar = output, 212 compile_jar = kt_ijar, 213 ) 214 215def _kt_compile( 216 ctx, 217 file_factory, 218 kt_srcs = [], 219 common_srcs = [], 220 coverage_srcs = [], 221 java_srcs_and_dirs = [], 222 kt_hdrs = None, 223 common_hdrs = None, 224 kotlincopts = [], 225 compile_jdeps = depset(), 226 toolchain = None, 227 classpath = [], 228 directdep_jars = depset(), 229 plugins = _kt_plugins_map(), 230 friend_jars = depset(), 231 enforce_strict_deps = False, 232 enforce_complete_jdeps = False): 233 # TODO: don't run jvm-abi-gen plugin here if we have headers 234 kotlinc_full_result = _run_kotlinc( 235 ctx, 236 kt_srcs = kt_srcs, 237 common_srcs = common_srcs, 238 java_srcs_and_dirs = java_srcs_and_dirs, 239 file_factory = file_factory, 240 kotlincopts = kotlincopts, 241 compile_jdeps = compile_jdeps, 242 toolchain = toolchain, 243 classpath = classpath, 244 directdep_jars = directdep_jars, 245 plugins = plugins, 246 friend_jars = friend_jars, 247 enforce_strict_deps = enforce_strict_deps, 248 enforce_complete_jdeps = enforce_complete_jdeps, 249 mnemonic = "Kt2JavaCompile", 250 message_prefix = "Compiling Kotlin For Java Runtime: ", 251 ) 252 253 srcjar = kt_srcjars.zip( 254 ctx, 255 toolchain, 256 file_factory.declare_file("-kt-src.jar"), 257 srcs = kt_srcs, 258 common_srcs = common_srcs, 259 ) 260 261 output_jar = kotlinc_full_result.output_jar 262 if ctx.coverage_instrumented(): 263 output_jar = _offline_instrument_jar( 264 ctx, 265 toolchain, 266 output_jar, 267 kt_srcs + common_srcs + coverage_srcs, 268 ) 269 270 # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions 271 # (see b/110763361 for the comparable Gradle issue) 272 compile_jar = kotlinc_full_result.compile_jar 273 if toolchain.header_gen_tool: 274 kotlinc_header_result = _run_kotlinc( 275 ctx, 276 kt_srcs = kt_hdrs, 277 common_srcs = common_hdrs, 278 java_srcs_and_dirs = java_srcs_and_dirs, 279 file_factory = file_factory.derive("-abi"), 280 kotlincopts = kotlincopts, 281 compile_jdeps = compile_jdeps, 282 toolchain = toolchain, 283 classpath = classpath, 284 directdep_jars = directdep_jars, 285 plugins = plugins, 286 friend_jars = friend_jars, 287 enforce_strict_deps = enforce_strict_deps, 288 enforce_complete_jdeps = enforce_complete_jdeps, 289 mnemonic = "Kt2JavaHeaderCompile", 290 message_prefix = "Computing Kotlin ABI interface Jar: ", 291 ) 292 compile_jar = kotlinc_header_result.compile_jar 293 294 result = dict( 295 output_jar = output_jar, 296 compile_jar = compile_jar, 297 source_jar = srcjar, 298 ) 299 return struct(java_info = JavaInfo(**result), **result) 300 301def _derive_headers( 302 ctx, 303 toolchain, 304 file_factory, 305 srcs): 306 if not srcs or not toolchain.header_gen_tool: 307 return srcs 308 309 output_dir = file_factory.declare_directory("-headers") 310 args = ctx.actions.args() 311 args.add(output_dir.path, format = "-output_dir=%s") 312 args.add_joined(srcs, format_joined = "-sources=%s", join_with = ",") 313 ctx.actions.run( 314 executable = toolchain.header_gen_tool, 315 arguments = [args], 316 inputs = srcs, 317 outputs = [output_dir], 318 mnemonic = "KtDeriveHeaders", 319 progress_message = "Deriving %s: %s" % (output_dir.basename, _get_original_kt_target_label(ctx)), 320 toolchain = toolchain.toolchain_type, 321 ) 322 return [output_dir] 323 324def _get_original_kt_target_label(ctx): 325 label = ctx.label 326 if label.name.find("_DO_NOT_DEPEND") > 0: 327 # Remove rule suffix added by android_library( 328 label = label.relative(":%s" % label.name[0:label.name.find("_DO_NOT_DEPEND")]) 329 elif hasattr(ctx.attr, "_kt_codegen_plugin_build_tool") and label.name.endswith("_processed_srcs"): 330 # Remove rule suffix added by kt_codegen_filegroup. b/259984258 331 label = label.relative(":{}".format(label.name.removesuffix("_processed_srcs"))) 332 return label 333 334def _run_import_deps_checker( 335 ctx, 336 jars_to_check = [], 337 merged_deps = None, 338 enforce_strict_deps = True, 339 jdeps_output = None, 340 deps_checker = None, 341 java_toolchain = None): 342 full_classpath = _create_classpath(java_toolchain, [merged_deps]) 343 label = _get_original_kt_target_label(ctx) 344 345 args = ctx.actions.args() 346 args.add("--jdeps_output", jdeps_output) 347 args.add_all(jars_to_check, before_each = "--input") 348 args.add_all(java_toolchain.bootclasspath, before_each = "--bootclasspath_entry") 349 args.add_all(full_classpath, before_each = "--classpath_entry") 350 if enforce_strict_deps: 351 args.add_all(merged_deps.compile_jars, before_each = "--directdep") 352 args.add("error" if enforce_strict_deps else "silence", format = "--checking_mode=%s") 353 args.add("--nocheck_missing_members") # compiler was happy so no need 354 args.add("--rule_label", label) 355 356 ctx.actions.run( 357 executable = deps_checker, 358 arguments = [args], 359 inputs = depset(jars_to_check, transitive = [full_classpath]), 360 outputs = [jdeps_output], 361 mnemonic = "KtCheckStrictDeps" if enforce_strict_deps else "KtJdeps", 362 progress_message = "%s deps for %s" % ( 363 "Checking strict" if enforce_strict_deps else "Computing", 364 label, 365 ), 366 ) 367 368def _offline_instrument_jar(ctx, toolchain, jar, srcs = []): 369 if not _is_file(jar, _EXT.JAR): 370 fail("Expect JAR input but got %s" % jar) 371 file_factory = FileFactory(ctx, jar) 372 373 paths_for_coverage_file = file_factory.declare_file("-kt-paths-for-coverage.txt") 374 paths = ctx.actions.args() 375 paths.set_param_file_format("multiline") # don't shell-quote, just list file names 376 paths.add_all([src for src in srcs if src.is_source]) 377 ctx.actions.write(paths_for_coverage_file, paths) 378 379 output = file_factory.declare_file("-instrumented.jar") 380 args = ctx.actions.args() 381 args.add(jar) 382 args.add(output) 383 args.add(paths_for_coverage_file) 384 ctx.actions.run( 385 executable = toolchain.coverage_instrumenter, 386 arguments = [args], 387 inputs = [jar, paths_for_coverage_file], 388 outputs = [output], 389 mnemonic = "KtJaCoCoInstrument", 390 progress_message = "Instrumenting Kotlin for coverage collection: %s" % _get_original_kt_target_label(ctx), 391 toolchain = toolchain.toolchain_type, 392 ) 393 394 return output 395 396def _singlejar( 397 ctx, 398 inputs, 399 output, 400 singlejar, 401 mnemonic = "KtMergeJar", 402 content = "final Jar", 403 preserve_compression = False, 404 pseudo_inputs = []): 405 label = _get_original_kt_target_label(ctx) 406 args = ctx.actions.args() 407 args.add("--normalize") 408 args.add("--add_missing_directories") # make output more similar to jar tool (b/114414678) 409 args.add("--exclude_build_data") 410 args.add("--no_duplicates") # No Kt/Java classname collisions (b/216841985) 411 args.add("--output") 412 args.add(output) 413 args.add("--sources") 414 args.add_all(inputs) 415 args.add("--deploy_manifest_lines") 416 args.add("Target-Label: %s" % label) 417 if preserve_compression: 418 args.add("--dont_change_compression") 419 420 ctx.actions.run( 421 executable = singlejar, 422 arguments = [args], 423 inputs = inputs + pseudo_inputs, 424 outputs = [output], 425 mnemonic = mnemonic, 426 progress_message = "Merging %s: %s" % (content, label), 427 toolchain = "@bazel_tools//tools/jdk:toolchain_type", 428 ) 429 430def _merge_jdeps(ctx, kt_jvm_toolchain, jdeps_files, file_factory): 431 merged_jdeps_file = file_factory.declare_file("-merged.jdeps") 432 433 args = ctx.actions.args() 434 args.add("--kind=jdeps") 435 args.add(merged_jdeps_file, format = "--output=%s") 436 args.add(_get_original_kt_target_label(ctx), format = "--rule_label=%s") 437 args.add_all(jdeps_files) 438 439 ctx.actions.run( 440 executable = kt_jvm_toolchain.jdeps_merger, 441 inputs = jdeps_files, 442 outputs = [merged_jdeps_file], 443 arguments = [args], 444 mnemonic = "KtMergeJdeps", 445 progress_message = "Merging jdeps files %{output}", 446 toolchain = kt_jvm_toolchain.toolchain_type, 447 ) 448 449 return merged_jdeps_file 450 451def _check_srcs_package(target_package, srcs, attr_name): 452 """Makes sure the given srcs live in the given package.""" 453 454 # Analogous to RuleContext.checkSrcsSamePackage 455 for src in srcs: 456 if target_package != src.owner.package: 457 fail(("Please do not depend on %s directly in %s. Either move it to this package or " + 458 "depend on an appropriate rule in its package.") % (src.owner, attr_name)) 459 460def _split_srcs_by_language(srcs, common_srcs, java_syncer): 461 srcs_set = sets.make(srcs) 462 common_srcs_set = sets.make(common_srcs) 463 464 overlapping_srcs_set = sets.intersection(srcs_set, common_srcs_set) 465 if sets.length(overlapping_srcs_set) != 0: 466 fail("Overlap between srcs and common_srcs: %s" % sets.to_list(overlapping_srcs_set)) 467 468 # Split sources, as java requires a separate compile step. 469 kt_srcs = [s for s in srcs if _is_kt_src(s)] 470 java_srcs = [s for s in srcs if _is_file(s, _EXT.JAVA)] 471 java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")]) 472 java_syncer.add_srcjars([s for s in srcs if _is_file(s, _EXT.SRCJAR)]) 473 474 expected_srcs_set = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars) 475 unexpected_srcs_set = sets.difference(srcs_set, expected_srcs_set) 476 if sets.length(unexpected_srcs_set) != 0: 477 fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs_set)) 478 479 return (kt_srcs, java_srcs) 480 481def _merge_exported_plugins(exported_plugins_map): 482 for field in ["java_plugin_datas", "kt_codegen_plugin_infos", "kt_compiler_plugin_infos"]: 483 if getattr(exported_plugins_map, field): 484 fail("exported_plugins doesn't support %s. These are propagated with aspects" % field) 485 486 android_lint_ruleset_jars = [] 487 488 return exported_plugins_map.java_plugin_infos + [ 489 JavaPluginInfo( 490 processor_class = None, 491 runtime_deps = [ 492 # Assume this list is short 493 JavaInfo(output_jar = jar, compile_jar = jar) 494 for jar in android_lint_ruleset_jars 495 ], 496 ), 497 ] 498 499# TODO: Streamline API to generate less actions. 500def _kt_jvm_library( 501 ctx, 502 kt_toolchain, 503 srcs = [], 504 common_srcs = [], 505 coverage_srcs = [], 506 java_android_lint_config = None, 507 manifest = None, # set for Android libs, otherwise None. 508 merged_manifest = None, # set for Android libs, otherwise None. 509 resource_files = [], # set for Android libs, otherwise empty. 510 classpath_resources = [], # set for kt_jvm_library, otherwise empty. 511 output = None, 512 output_srcjar = None, # Will derive default filename if not set. 513 deps = [], 514 exports = [], # passthrough for JavaInfo constructor 515 runtime_deps = [], # passthrough for JavaInfo constructor 516 native_libraries = [], # passthrough of CcInfo for JavaInfo constructor 517 plugins = _kt_plugins_map(), 518 exported_plugins = _kt_plugins_map(), 519 javacopts = [], 520 kotlincopts = [], 521 compile_jdeps = depset(), 522 disable_lint_checks = [], 523 neverlink = False, 524 testonly = False, # used by Android Lint 525 enforce_strict_deps = True, 526 rule_family = _RULE_FAMILY.UNKNOWN, 527 enforce_complete_jdeps = False, 528 java_toolchain = None, 529 friend_jars = depset(), 530 annotation_processor_additional_outputs = [], 531 annotation_processor_additional_inputs = []): 532 if not java_toolchain: 533 fail("Missing or invalid java_toolchain") 534 if not kt_toolchain: 535 fail("Missing or invalid kt_toolchain") 536 537 file_factory = FileFactory(ctx, output) 538 static_deps = list(deps) # Defensive copy 539 540 kt_codegen_processing_env = dict() 541 codegen_plugin_output = None 542 543 kt_codegen_processors = kt_codegen_processing_env.get("processors_for_kt_codegen_processing", depset()).to_list() 544 codegen_tags = kt_codegen_processing_env.get("codegen_tags", []) 545 generative_deps = kt_codegen_processing_env.get("codegen_output_java_infos", depset()).to_list() 546 547 java_syncer = kt_srcjars.DirSrcjarSyncer(ctx, kt_toolchain, file_factory) 548 kt_srcs, java_srcs = _split_srcs_by_language(srcs, common_srcs, java_syncer) 549 550 is_android_library_without_kt_srcs = rule_family == _RULE_FAMILY.ANDROID_LIBRARY and not kt_srcs and not common_srcs 551 is_android_library_without_kt_srcs_without_generative_deps = is_android_library_without_kt_srcs and not generative_deps 552 553 # TODO: Remove this special case 554 if kt_srcs and ("flogger" in [p.plugin_id for p in plugins.kt_compiler_plugin_infos]): 555 static_deps.append(kt_toolchain.flogger_runtime) 556 557 if not is_android_library_without_kt_srcs_without_generative_deps: 558 static_deps.extend(kt_toolchain.kotlin_libs) 559 560 # Skip srcs package check for android_library targets with no kotlin sources: b/239725424 561 if not is_android_library_without_kt_srcs: 562 if "check_srcs_package_against_kt_srcs_only" in codegen_tags: 563 _check_srcs_package(ctx.label.package, kt_srcs, "srcs") 564 else: 565 _check_srcs_package(ctx.label.package, srcs, "srcs") 566 567 _check_srcs_package(ctx.label.package, common_srcs, "common_srcs") 568 _check_srcs_package(ctx.label.package, coverage_srcs, "coverage_srcs") 569 570 # Includes generative deps from codegen. 571 extended_deps = static_deps + generative_deps 572 full_classpath = _create_classpath(java_toolchain, extended_deps) 573 exported_plugins = _merge_exported_plugins(exported_plugins) 574 575 # Collect all plugin data, including processors to run and all plugin classpaths, 576 # whether they have processors or not (b/120995492). 577 # This may include go/errorprone plugin classpaths that kapt will ignore. 578 java_plugin_datas = kt_codegen_processing_env.get("java_plugin_data_set", plugins.java_plugin_datas).to_list() 579 processors_for_java_srcs = kt_codegen_processing_env.get("processors_for_java_srcs", depset(transitive = [p.processor_classes for p in java_plugin_datas])).to_list() 580 java_plugin_classpaths_for_java_srcs = depset(transitive = [p.processor_jars for p in java_plugin_datas]) 581 out_jars = kt_codegen_processing_env.get("codegen_runtime_output_jars", []) 582 out_srcjars = kt_codegen_processing_env.get("codegen_source_jars", []) 583 out_compilejars = kt_codegen_processing_env.get("codegen_compile_jars", []) 584 585 kt_hdrs = _derive_headers( 586 ctx, 587 toolchain = kt_toolchain, 588 file_factory = file_factory.derive("-kt"), 589 # TODO: prohibit overlap of srcs and common_srcs 590 srcs = kt_srcs, 591 ) 592 common_hdrs = _derive_headers( 593 ctx, 594 toolchain = kt_toolchain, 595 file_factory = file_factory.derive("-common"), 596 srcs = common_srcs, 597 ) 598 599 kotlinc_result = None 600 if kt_srcs or common_srcs: 601 kotlinc_result = _kt_compile( 602 ctx, 603 kt_srcs = kt_srcs, 604 common_srcs = common_srcs, 605 coverage_srcs = coverage_srcs, 606 java_srcs_and_dirs = java_srcs + java_syncer.dirs, 607 kt_hdrs = kt_hdrs, 608 common_hdrs = common_hdrs, 609 file_factory = file_factory.derive("-kt"), 610 kotlincopts = kotlincopts, 611 compile_jdeps = compile_jdeps, 612 toolchain = kt_toolchain, 613 classpath = full_classpath, 614 plugins = plugins, 615 friend_jars = friend_jars, 616 enforce_strict_deps = enforce_strict_deps, 617 enforce_complete_jdeps = enforce_complete_jdeps, 618 ) 619 out_compilejars.append(kotlinc_result.compile_jar) 620 out_srcjars.append(kotlinc_result.source_jar) 621 out_jars.append(kotlinc_result.output_jar) 622 623 classpath_resources_dirs, classpath_resources_non_dirs = _partition( 624 classpath_resources, 625 filter = lambda res: res.is_directory, 626 ) 627 if classpath_resources_dirs: 628 out_jars.append( 629 kt_srcjars.zip_resources( 630 ctx, 631 kt_toolchain, 632 file_factory.declare_file("-dir-res.jar"), 633 classpath_resources_dirs, 634 ), 635 ) 636 637 javac_java_info = None 638 java_native_headers_jar = None 639 640 if java_srcs or java_syncer.srcjars or classpath_resources: 641 javac_deps = list(extended_deps) # Defensive copy 642 if kotlinc_result: 643 javac_deps.append(kotlinc_result.java_info) 644 if ctx.coverage_instrumented(): 645 # Including the coverage runtime improves jdeps computation (b/130747644), but it 646 # could be runtime-only if we computed compile-time jdeps using the compile JAR 647 # (which doesn't contain instrumentation). See b/117897097. 648 javac_deps.append(kt_toolchain.coverage_runtime) 649 650 javac_out = output if is_android_library_without_kt_srcs_without_generative_deps else file_factory.declare_file("-libjvm-java.jar") 651 652 annotation_plugins = kt_codegen_processing_env.get("java_common_annotation_plugins", list(plugins.java_plugin_infos)) 653 enable_annotation_processing = kt_codegen_processing_env.get("enable_java_common_annotation_processing", True) 654 655 javac_java_info = java_common.compile( 656 ctx, 657 source_files = java_srcs, 658 source_jars = java_syncer.srcjars, 659 resources = classpath_resources_non_dirs, 660 # For targets that are not android_library with java-only srcs, exports will be passed 661 # to the final constructed JavaInfo. 662 exports = exports if is_android_library_without_kt_srcs_without_generative_deps else [], 663 output = javac_out, 664 exported_plugins = exported_plugins, 665 deps = javac_deps, 666 # Include default_javac_flags, which reflect Blaze's --javacopt flag, so they win over 667 # all sources of default flags (for Ellipsis builds, see b/125452475). 668 # TODO: remove default_javac_flags here once java_common.compile is fixed. 669 javac_opts = ctx.fragments.java.default_javac_flags + javacopts, 670 plugins = annotation_plugins, 671 strict_deps = "DEFAULT", 672 java_toolchain = java_toolchain, 673 neverlink = neverlink, 674 enable_annotation_processing = enable_annotation_processing, 675 annotation_processor_additional_outputs = annotation_processor_additional_outputs, 676 annotation_processor_additional_inputs = annotation_processor_additional_inputs, 677 ) 678 679 out_jars.append(javac_out) 680 out_srcjars.extend(javac_java_info.source_jars) 681 out_compilejars.extend(javac_java_info.compile_jars.to_list()) # unpack singleton depset 682 java_native_headers_jar = javac_java_info.outputs.native_headers 683 684 java_gensrcjar = None 685 java_genjar = None 686 687 if codegen_plugin_output: 688 pass 689 690 elif javac_java_info: 691 java_gensrcjar = javac_java_info.annotation_processing.source_jar 692 java_genjar = javac_java_info.annotation_processing.class_jar 693 if java_gensrcjar: 694 java_syncer.add_srcjars([java_gensrcjar]) 695 696 jdeps_output = None 697 compile_jdeps_output = None 698 manifest_proto = None 699 700 # TODO: Move severity overrides to config file when possible again 701 blocking_action_outs = [] 702 703 # TODO: Remove the is_android_library_without_kt_srcs condition once KtAndroidLint 704 # uses the same lint checks with AndroidLint 705 706 if (srcs or common_srcs or resource_files) and not is_android_lint_exempt(ctx): 707 lint_flags = [ 708 "--java-language-level", # b/159950410 709 kt_toolchain.java_language_version, 710 "--kotlin-language-level", 711 kt_toolchain.kotlin_language_version, 712 "--nowarn", # Check for "errors", which includes custom checks that report errors. 713 "--XallowBaselineSuppress", # allow baseline exemptions of otherwise unsuppressable errors 714 "--exitcode", # fail on error 715 "--fullpath", # reduce file path clutter in reported issues 716 "--text", 717 "stdout", # also log to stdout 718 ] 719 if disable_lint_checks and disable_lint_checks != [""]: 720 lint_flags.append("--disable") 721 lint_flags.append(",".join(disable_lint_checks)) 722 723 android_lint_out = lint_actions.run_lint_on_library( 724 ctx, 725 runner = kt_toolchain.android_lint_runner, 726 output = file_factory.declare_file("_android_lint_output.xml"), 727 srcs = kt_srcs + java_srcs + common_srcs, 728 source_jars = java_syncer.srcjars, 729 classpath = full_classpath, 730 manifest = manifest, 731 merged_manifest = merged_manifest, 732 resource_files = resource_files, 733 baseline_file = androidlint_toolchains.get_baseline(ctx), 734 config = (None if (kt_srcs or common_srcs) else java_android_lint_config) or kt_toolchain.android_lint_config, 735 android_lint_rules = plugins.android_lint_rulesets + [ 736 lint_actions.AndroidLintRulesetInfo(singlejars = java_plugin_classpaths_for_java_srcs), 737 ], 738 lint_flags = lint_flags, 739 extra_input_depsets = [p.processor_data for p in java_plugin_datas], 740 testonly = testonly, 741 android_java8_libs = kt_toolchain.android_java8_apis_desugared, 742 mnemonic = "AndroidLint" if is_android_library_without_kt_srcs else "KtAndroidLint", # so LSA extractor can distinguish Kotlin (b/189442586) 743 ) 744 blocking_action_outs.append(android_lint_out) 745 746 # Directly return the JavaInfo from java.compile() for java-only android_library targets 747 # to avoid creating a new JavaInfo. See b/239847857 for additional context. 748 if javac_java_info and is_android_library_without_kt_srcs_without_generative_deps: 749 return struct( 750 java_info = javac_java_info, 751 validations = blocking_action_outs, 752 ) 753 754 if output_srcjar == None: 755 output_srcjar = file_factory.declare_file("-src.jar") 756 compile_jar = file_factory.declare_file("-compile.jar") 757 single_jar = java_toolchain.single_jar 758 _singlejar(ctx, out_srcjars, output_srcjar, single_jar, mnemonic = "KtMergeSrcjar", content = "srcjar", preserve_compression = True) 759 760 # Don't block compile-time Jar on Android Lint and other validations (b/117991324). 761 _singlejar(ctx, out_compilejars, compile_jar, single_jar, mnemonic = "KtMergeCompileJar", content = "compile-time Jar") 762 763 # Disable validation for Guitar BUILD targets (b/144326858). 764 # TODO Remove use of RUN_ANALYSIS_TIME_VALIDATION once Guitar disables validations 765 use_validation = ctx.var.get("RUN_ANALYSIS_TIME_VALIDATION", "true") # will be "0" if set by Guitar 766 use_validation = ctx.var.get("kt_use_validations", use_validation) 767 768 # Include marker file in runtime Jar so we can reliably identify 1P Kotlin code 769 # TODO: consider only doing this for android_library( 770 _singlejar( 771 ctx, 772 out_jars + ([kt_toolchain.build_marker] if kt_srcs and ctx.label.package.startswith("java/") else []), 773 output, 774 single_jar, 775 preserve_compression = True, 776 pseudo_inputs = ([] if use_validation == "true" else blocking_action_outs), 777 ) 778 result_java_info = JavaInfo( 779 output_jar = output, 780 compile_jar = compile_jar, 781 source_jar = output_srcjar, 782 deps = static_deps, 783 exports = exports, 784 exported_plugins = exported_plugins, 785 runtime_deps = runtime_deps, 786 manifest_proto = manifest_proto, 787 neverlink = neverlink, 788 jdeps = jdeps_output, 789 compile_jdeps = compile_jdeps_output, 790 native_libraries = native_libraries, 791 native_headers_jar = java_native_headers_jar, 792 generated_source_jar = java_gensrcjar, 793 generated_class_jar = java_genjar, 794 ) 795 796 return struct( 797 java_info = result_java_info, 798 validations = (blocking_action_outs if use_validation == "true" else []), 799 ) 800 801def _kt_jvm_import( 802 ctx, 803 kt_toolchain, 804 jars = [], 805 srcjar = None, 806 deps = [], 807 runtime_deps = [], 808 neverlink = False, 809 java_toolchain = None, 810 deps_checker = None): 811 if not java_toolchain: 812 fail("Missing or invalid java_toolchain") 813 if not jars: 814 fail("Must import at least one JAR") 815 816 _check_srcs_package(ctx.label.package, jars, "jars") 817 if srcjar: 818 _check_srcs_package(ctx.label.package, [srcjar], "srcjar") 819 820 file_factory = FileFactory(ctx, jars[0]) 821 deps = java_common.merge(deps + kt_toolchain.kotlin_libs) 822 823 # Check that any needed deps are declared unless neverlink, in which case Jars won't be used 824 # at runtime so we skip the check, though we'll populate jdeps either way. 825 jdeps_output = file_factory.declare_file(".jdeps") 826 _run_import_deps_checker( 827 ctx, 828 jars_to_check = jars, 829 merged_deps = deps, 830 enforce_strict_deps = not neverlink, 831 jdeps_output = jdeps_output, 832 deps_checker = deps_checker, 833 java_toolchain = java_toolchain, 834 ) 835 836 java_info = java_common.merge([ 837 JavaInfo( 838 output_jar = jar, 839 compile_jar = java_common.run_ijar( 840 actions = ctx.actions, 841 jar = jar, 842 target_label = _get_original_kt_target_label(ctx), 843 java_toolchain = java_toolchain, 844 ), 845 source_jar = srcjar, 846 deps = [deps], 847 runtime_deps = runtime_deps, 848 neverlink = neverlink, 849 # TODO: Set compile-time jdeps to help reduce Javac classpaths downstream 850 jdeps = jdeps_output, # not clear this is useful but let's populate since we have it 851 ) 852 for jar in jars 853 ]) 854 855 # TODO Remove use of RUN_ANALYSIS_TIME_VALIDATION once Guitar disables validations 856 use_validation = ctx.var.get("RUN_ANALYSIS_TIME_VALIDATION", "true") # will be "0" if set by Guitar 857 858 return struct( 859 java_info = java_info, 860 validations = [jdeps_output] if use_validation == "true" and not neverlink else [], 861 ) 862 863def _validate_proguard_specs( 864 ctx, 865 proguard_specs, 866 proguard_allowlister): 867 validated_proguard_specs = [] 868 for proguard_spec in proguard_specs: 869 validated_proguard_spec = ctx.actions.declare_file( 870 "validated_proguard/%s/%s_valid" % (ctx.label.name, proguard_spec.path), 871 ) 872 validated_proguard_specs.append(validated_proguard_spec) 873 874 args = ctx.actions.args() 875 args.add("--path", proguard_spec) 876 args.add("--output", validated_proguard_spec) 877 878 ctx.actions.run( 879 executable = proguard_allowlister, 880 toolchain = kt_jvm_toolchains.type, 881 arguments = [args], 882 inputs = [proguard_spec], 883 outputs = [validated_proguard_spec], 884 mnemonic = "ValidateProguard", 885 progress_message = ( 886 "Validating proguard configuration %s" % proguard_spec 887 ), 888 ) 889 return validated_proguard_specs 890 891def _collect_proguard_specs( 892 ctx, 893 proguard_specs, 894 propagated_deps, 895 proguard_allowlister): 896 validated_proguard_specs = _validate_proguard_specs( 897 ctx, 898 proguard_specs, 899 proguard_allowlister, 900 ) 901 902 return depset( 903 validated_proguard_specs, 904 transitive = [p.specs for p in _collect_providers(ProguardSpecProvider, propagated_deps)], 905 order = "preorder", 906 ) 907 908def _collect_providers(provider, deps): 909 """Collects the requested provider from the given list of deps.""" 910 return [dep[provider] for dep in deps if provider in dep] 911 912def _create_classpath(java_toolchain, deps): 913 # To not confuse strictdeps, order as boot > direct > transitive JARs (b/149107867). 914 return depset( 915 order = "preorder", 916 transitive = ( 917 [java_toolchain.bootclasspath] + 918 [dep.compile_jars for dep in deps] + 919 [dep.transitive_compile_time_jars for dep in deps] 920 ), 921 ) 922 923def _partition(sequence, filter): 924 pos, neg = [], [] 925 for element in sequence: 926 if filter(element): 927 pos.append(element) 928 else: 929 neg.append(element) 930 return pos, neg 931 932common = struct( 933 JAR_FILE_TYPE = _JAR_FILE_TYPE, 934 JVM_FLAGS = BASE_JVMOPTS, 935 KT_FILE_TYPES = _KT_FILE_TYPES, 936 KT_JVM_FILE_TYPES = _KT_JVM_FILE_TYPES, 937 RULE_FAMILY = _RULE_FAMILY, 938 SRCJAR_FILE_TYPES = _SRCJAR_FILE_TYPES, 939 collect_proguard_specs = _collect_proguard_specs, 940 collect_providers = _collect_providers, 941 create_jar_from_tree_artifacts = kt_srcjars.zip_resources, 942 get_common_and_user_kotlinc_args = _get_common_and_user_kotlinc_args, 943 is_kt_src = _is_kt_src, 944 kt_jvm_import = _kt_jvm_import, 945 kt_jvm_library = _kt_jvm_library, 946 kt_plugins_map = _kt_plugins_map, 947 partition = _partition, 948) 949