diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-03-16 05:12:10 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2023-03-16 05:12:10 +0000 |
commit | 5d3198b5a82b57dcf22c33c96f452d633bf442e1 (patch) | |
tree | 216876fcf590f1cafc7bd635dc86e972521ed9d8 | |
parent | 0f80a73bcfbfe68325763f2905916c4f414b3446 (diff) | |
parent | 387dfdee29c1b6ca280261a88f4bfef63370dbaa (diff) | |
download | bazelbuild-kotlin-rules-android14-gsi.tar.gz |
Snap for 9754537 from c66e2fa10dfc93fd11e75e9ce00e4a5141ae7137 to udc-release am: 387dfdee29android14-gsi
Original change: https://googleplex-android-review.googlesource.com/c/platform/external/bazelbuild-kotlin-rules/+/22111280
Change-Id: Ia420645bff177f856c52de34e3aaa08b0634d847
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
53 files changed, 1430 insertions, 575 deletions
@@ -12,6 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + licenses(["notice"]) exports_files(["LICENSE"]) @@ -11,8 +11,8 @@ third_party { type: GIT value: "https://team.googlesource.com/kotlin-rules/rules" } - version: "0904db290987a7e48a708369e5093b6d033769e7" - last_upgrade_date { year: 2022 month: 12 day: 14} + version: "6c074b6ce60b1ccfdc17bcf5e0566f497a869790" + last_upgrade_date { year: 2023 month: 3 day: 13} license_type: NOTICE } @@ -59,10 +59,10 @@ java_tools_repos() http_archive( name = "dagger", - strip_prefix = "dagger-dagger-2.28.1", + strip_prefix = "dagger-dagger-2.44.2", build_file = "@//bazel:dagger.BUILD", - sha256 = "9e69ab2f9a47e0f74e71fe49098bea908c528aa02fa0c5995334447b310d0cdd", - urls = ["https://github.com/google/dagger/archive/dagger-2.28.1.zip"], + sha256 = "cbff42063bfce78a08871d5a329476eb38c96af9cf20d21f8b412fee76296181", + urls = ["https://github.com/google/dagger/archive/dagger-2.44.2.zip"], ) load("@dagger//:workspace_defs.bzl", "DAGGER_ARTIFACTS", "DAGGER_REPOSITORIES") @@ -70,7 +70,7 @@ load("@//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "KT_VERSION") http_archive( name = "kotlinc", build_file = "@//bazel:kotlinc.BUILD", - sha256 = "8412b31b808755f0c0d336dbb8c8443fa239bf32ddb3cdb81b305b25f0ad279e", + sha256 = "4c3fa7bc1bb9ef3058a2319d8bcc3b7196079f88e92fdcd8d304a46f4b6b5787", strip_prefix = "kotlinc", urls = [ "https://github.com/JetBrains/kotlin/releases/download/v{0}/kotlin-compiler-{0}.zip".format(KT_VERSION[1:].replace("_", ".")), diff --git a/bazel/BUILD b/bazel/BUILD index cc77038..303a377 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -43,3 +43,10 @@ java_binary( "@maven//:org_jacoco_org_jacoco_cli", ], ) + +genrule( + name = "stub_tool", + outs = ["stub_tool.sh"], + cmd = "exit 1", + executable = True, +) diff --git a/bazel/deploy_jar_freshness_golden_test.bzl b/bazel/deploy_jar_freshness_golden_test.bzl index 9e36132..a6524eb 100644 --- a/bazel/deploy_jar_freshness_golden_test.bzl +++ b/bazel/deploy_jar_freshness_golden_test.bzl @@ -14,6 +14,8 @@ """Test on *_deploy.jar freshness""" +load("//:visibility.bzl", "RULES_KOTLIN") + def _deploy_jar_freshness_golden_test_impl(ctx): test_command = """ if ! cmp $1 $2 ; then diff --git a/bazel/stubs.bzl b/bazel/stubs.bzl index 95f5b87..5d041f4 100644 --- a/bazel/stubs.bzl +++ b/bazel/stubs.bzl @@ -15,10 +15,13 @@ """Stubs""" load("@bazel_skylib//lib:sets.bzl", "sets") +load("//:visibility.bzl", "RULES_KOTLIN") -def register_extension_info(**_kwargs): +def _empty_fn(*_args, **_kwargs): pass +register_extension_info = _empty_fn + FORBIDDEN_DEP_PACKAGES = sets.make([]) EXEMPT_DEPS = sets.make([]) @@ -33,5 +36,21 @@ DEFAULT_BUILTIN_PROCESSORS = [ BASE_JVMOPTS = [] -def select_java_language_version(**_kwargs): +def select_java_language_level(**_kwargs): return "11" + +registry_checks_for_package = _empty_fn + +LINT_REGISTRY = None # Only ever passed to registry_checks_for_package + +def _run_lint_on_library(ctx, output, *_args, **_kwargs): + ctx.actions.write(output, "Android Lint Disabled") + return output + +lint_actions = struct( + run_lint_on_library = _run_lint_on_library, + get_android_lint_baseline_file = _empty_fn, +) + +def check_compiler_opt_allowlist(_label): + pass diff --git a/kotlin/common.bzl b/kotlin/common.bzl index 3789b0c..76bb57b 100644 --- a/kotlin/common.bzl +++ b/kotlin/common.bzl @@ -14,42 +14,22 @@ """Common Kotlin definitions.""" +# go/keep-sorted start +load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory") +load("//kotlin/jvm/internal_do_not_use/util:run_deploy_jar.bzl", "kt_run_deploy_jar") +load("//kotlin/jvm/internal_do_not_use/util:srcjars.bzl", "kt_srcjars") +load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains") +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") load("@bazel_skylib//lib:sets.bzl", "sets") +load("//bazel:stubs.bzl", "lint_actions") load("//bazel:stubs.bzl", "BASE_JVMOPTS") load("//bazel:stubs.bzl", "DEFAULT_BUILTIN_PROCESSORS") -load(":file_factory.bzl", "FileFactory") +# go/keep-sorted end # TODO: Remove the _ALLOWED_*_RULES lists to determine which rules # are accepted dependencies to Kotlin rules as the approach does not scale # because it will require a cl + release for every new rule. -_ALLOWED_ANDROID_RULES = [ - "aar_import", - "android_library", - "kt_android_library_helper", -] - -_ALLOWED_JVM_RULES = [ - "_java_grpc_library", - "_java_lite_grpc_library", - "af_internal_guice_module", # b/142743220 - "af_internal_jbcsrc_library", # added with b/143872075 - "af_internal_soyinfo_generator", # b/143872075 - "java_import", - "java_library", - "java_lite_proto_library", - "java_mutable_proto_library", - "java_proto_library", - "java_wrap_cc", # b/152799927 - "jvm_import", - "_kmp_library", - "kt_grpc_library_helper", - "kt_jvm_library_helper", - "kt_jvm_import", - "kt_proto_library_helper", - "_j2kt_jvm_library_rule", # b/233055549 -] - _EXT = struct( KT = ".kt", JAVA = ".java", @@ -78,6 +58,9 @@ _RULE_FAMILY = struct( def _is_dir(file, basename): return file.is_directory and file.basename == basename +def _is_file(file, extension): + return (not file.is_directory) and file.path.endswith(extension) + def _is_kt_src(src): """Decides if `src` Kotlin code. @@ -86,7 +69,7 @@ def _is_kt_src(src): - a tree-artifact expected to contain only Kotlin source files """ - return src.path.endswith(_EXT.KT) or _is_dir(src, "kotlin") + return _is_file(src, _EXT.KT) or _is_dir(src, "kotlin") # Compute module name based on target (b/139403883), similar to Swift def _derive_module_name(ctx): @@ -142,11 +125,11 @@ def _kapt( # Create a srcjar for the .java stubs generated by kapt, # mostly to filter out non-.java stub outputs, e.g. .kapt_metadata. - stub_srcjars.append(_create_jar( + stub_srcjars.append(kt_srcjars.zip( ctx, toolchain, file_factory.declare_file("stubs-srcjar.jar"), - kt_inputs = [stubs_dir], + srcs = [stubs_dir], ignore_not_allowed_files = True, )) @@ -319,7 +302,7 @@ def _run_turbine( java_runtime = toolchain.turbine_java_runtime if not java_runtime: java_runtime = toolchain.java_runtime - _actions_run_deploy_jar( + kt_run_deploy_jar( ctx = ctx, java_runtime = java_runtime, deploy_jar = toolchain.turbine, @@ -331,53 +314,24 @@ def _run_turbine( progress_message = progress_message, ) -def _derive_gen_class_jar( - ctx, - toolchain, - manifest_proto, - javac_jar, - java_srcs = []): - """Returns the annotation processor-generated classes contained in given Jar.""" - if not manifest_proto: - return None - if not javac_jar: - fail("There must be a javac Jar if there was annotation processing") - if not java_srcs: - # If there weren't any hand-written .java srcs, just use Javac's output - return javac_jar - - # Run GenClass tool to derive gen_class_jar by filtering hand-written sources. - # cf. Bazel's JavaCompilationHelper#createGenJarAction - result = FileFactory(ctx, javac_jar).declare_file("-gen.jar") - - genclass_args = ctx.actions.args() - genclass_args.add("--manifest_proto", manifest_proto) - genclass_args.add("--class_jar", javac_jar) - genclass_args.add("--output_jar", result) - - _actions_run_deploy_jar( - ctx = ctx, - java_runtime = toolchain.java_runtime, - deploy_jar = toolchain.genclass, - inputs = [manifest_proto, javac_jar], - outputs = [result], - args = [genclass_args], - mnemonic = "KtGenClassJar", - progress_message = "Deriving %{output}", - ) - - return result - def _kt_plugins_map( + android_lint_singlejar_plugins = depset(), + android_lint_libjar_plugin_infos = [], java_plugin_infos = [], kt_compiler_plugin_infos = []): """A struct containing all the plugin types understood by rules_kotlin. Args: - java_plugin_infos: (list[JavaPluginInfo]) - kt_compiler_plugin_infos: (list[KtCompilerPluginInfo]) + android_lint_singlejar_plugins: (depset[File]) Android Lint checkers. + Each JAR is self-contained and should be loaded in an isolated classloader. + android_lint_libjar_plugin_infos: (list[JavaInfo]) Android Lint checkers. + All infos share transitive dependencies and should be loaded in a combined classloader. + java_plugin_infos: (list[JavaPluginInfo]) + kt_compiler_plugin_infos: (list[KtCompilerPluginInfo]) """ return struct( + android_lint_singlejar_plugins = android_lint_singlejar_plugins, + android_lint_libjar_plugin_infos = android_lint_libjar_plugin_infos, java_plugin_infos = java_plugin_infos, kt_compiler_plugin_infos = kt_compiler_plugin_infos, ) @@ -387,7 +341,6 @@ def _run_kotlinc( file_factory, kt_srcs = [], common_srcs = [], - coverage_srcs = [], java_srcs_and_dirs = [], kotlincopts = [], compile_jdeps = depset(), @@ -397,7 +350,9 @@ def _run_kotlinc( plugins = _kt_plugins_map(), friend_jars = depset(), enforce_strict_deps = False, - enforce_complete_jdeps = False): + enforce_complete_jdeps = False, + mnemonic = None, + message_prefix = ""): direct_inputs = [] transitive_inputs = [] outputs = [] @@ -435,7 +390,7 @@ def _run_kotlinc( output = file_factory.declare_file(".jar") kotlinc_args.add("-d", output) - outputs.append(output) + outputs.insert(0, output) # The param file name is derived from the 0th output kotlinc_args.add_all(kt_srcs) direct_inputs.extend(kt_srcs) kotlinc_args.add_all(common_srcs) @@ -459,36 +414,126 @@ def _run_kotlinc( arguments = [kotlinc_args], inputs = depset(direct = direct_inputs, transitive = transitive_inputs), outputs = outputs, - mnemonic = "Kt2JavaCompile", - progress_message = "Compiling Kotlin For Java Runtime: %s" % _get_original_kt_target_label(ctx), + mnemonic = mnemonic, + progress_message = message_prefix + str(_get_original_kt_target_label(ctx)), execution_requirements = { "worker-key-mnemonic": "Kt2JavaCompile", }, ) - srcjar = _create_jar( + return struct( + output_jar = output, + compile_jar = kt_ijar, + ) + +def _kt_compile( + ctx, + file_factory, + kt_srcs = [], + common_srcs = [], + coverage_srcs = [], + java_srcs_and_dirs = [], + kt_hdrs = None, + common_hdrs = None, + kotlincopts = [], + compile_jdeps = depset(), + toolchain = None, + classpath = [], + directdep_jars = depset(), + plugins = _kt_plugins_map(), + friend_jars = depset(), + enforce_strict_deps = False, + enforce_complete_jdeps = False): + # TODO: don't run jvm-abi-gen plugin here if we have headers + kotlinc_full_result = _run_kotlinc( + ctx, + kt_srcs = kt_srcs, + common_srcs = common_srcs, + java_srcs_and_dirs = java_srcs_and_dirs, + file_factory = file_factory, + kotlincopts = kotlincopts, + compile_jdeps = compile_jdeps, + toolchain = toolchain, + classpath = classpath, + directdep_jars = directdep_jars, + plugins = plugins, + friend_jars = friend_jars, + enforce_strict_deps = enforce_strict_deps, + enforce_complete_jdeps = enforce_complete_jdeps, + mnemonic = "Kt2JavaCompile", + message_prefix = "Compiling for Java runtime: ", + ) + + srcjar = kt_srcjars.zip( ctx, toolchain, file_factory.declare_file("-kt-src.jar"), - kt_inputs = kt_srcs, - common_inputs = common_srcs, + srcs = kt_srcs, + common_srcs = common_srcs, ) + output_jar = kotlinc_full_result.output_jar if ctx.coverage_instrumented(): - output = _offline_instrument_jar( + output_jar = _offline_instrument_jar( ctx, toolchain, - output, + output_jar, kt_srcs + common_srcs + coverage_srcs, ) + # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions + # (see b/110763361 for the comparable Gradle issue) + compile_jar = kotlinc_full_result.compile_jar + if toolchain.header_gen_tool: + kotlinc_header_result = _run_kotlinc( + ctx, + kt_srcs = kt_hdrs, + common_srcs = common_hdrs, + java_srcs_and_dirs = java_srcs_and_dirs, + file_factory = file_factory.derive("-abi"), + kotlincopts = kotlincopts, + compile_jdeps = compile_jdeps, + toolchain = toolchain, + classpath = classpath, + directdep_jars = directdep_jars, + plugins = plugins, + friend_jars = friend_jars, + enforce_strict_deps = enforce_strict_deps, + enforce_complete_jdeps = enforce_complete_jdeps, + mnemonic = "Kt2JavaHeaderCompile", + message_prefix = "Computing Kotlin ABI interface Jar: ", + ) + compile_jar = kotlinc_header_result.compile_jar + result = dict( - output_jar = output, - compile_jar = kt_ijar, + output_jar = output_jar, + compile_jar = compile_jar, source_jar = srcjar, ) return struct(java_info = JavaInfo(**result), **result) +def _derive_headers( + ctx, + toolchain, + file_factory, + srcs): + if not srcs or not toolchain.header_gen_tool: + return srcs + + output_dir = file_factory.declare_directory("-headers") + args = ctx.actions.args() + args.add(output_dir.path, format = "-output_dir=%s") + args.add_joined(srcs, format_joined = "-sources=%s", join_with = ",") + ctx.actions.run( + executable = toolchain.header_gen_tool, + arguments = [args], + inputs = srcs, + outputs = [output_dir], + mnemonic = "KtDeriveHeaders", + progress_message = "Deriving %s: %s" % (output_dir.basename, _get_original_kt_target_label(ctx)), + ) + return [output_dir] + def _get_original_kt_target_label(ctx): label = ctx.label if label.name.find("_DO_NOT_DEPEND") > 0: @@ -534,7 +579,7 @@ def _run_import_deps_checker( ) def _offline_instrument_jar(ctx, toolchain, jar, srcs = []): - if not jar.basename.endswith(".jar"): + if not _is_file(jar, _EXT.JAR): fail("Expect JAR input but got %s" % jar) file_factory = FileFactory(ctx, jar) @@ -613,174 +658,6 @@ def _merge_jdeps(ctx, kt_jvm_toolchain, jdeps_files, file_factory): return merged_jdeps_file -def _expand_zip(ctx, toolchain, dir, input): - args = ctx.actions.args() - args.add("unzip", input) - args.add(dir.path) - - _actions_run_deploy_jar( - ctx = ctx, - java_runtime = toolchain.java_runtime, - deploy_jar = toolchain.source_jar_zipper, - inputs = [input], - outputs = [dir], - args = [args], - mnemonic = "SrcJarUnzip", - ) - - return dir - -def _create_jar(ctx, toolchain, out_jar, kt_inputs = [], common_inputs = [], ignore_not_allowed_files = False): - args = ctx.actions.args() - args.add("zip") - args.add(out_jar) - args.add_joined("--kotlin_srcs", kt_inputs, join_with = ",") - args.add_joined("--common_srcs", common_inputs, join_with = ",") - if ignore_not_allowed_files: - args.add("-i") - - _actions_run_deploy_jar( - ctx = ctx, - java_runtime = toolchain.java_runtime, - deploy_jar = toolchain.source_jar_zipper, - inputs = kt_inputs + common_inputs, - outputs = [out_jar], - args = [args], - mnemonic = "KtJar", - progress_message = "Create Jar (kotlin/common.bzl): %{output}", - ) - - return out_jar - -def _create_jar_from_tree_artifacts(ctx, toolchain, output_jar, input_dirs): - """Packs a sequence of tree artifacts into a single jar. - - Given the following file directory structure, - /usr/home/a/x/1.txt - /usr/home/b/y/1.txt - with an input_dirs as [ - "/usr/home/a", - "/usr/home/b", - ], - The tool produces a jar with in-archive structure of, - x/1.txt - y/1.txt - - The function fails on the duplicate jar entry case. e.g. if we pass an - input_dirs as [ - "/usr/home/a/x", - "/usr/home/b/y", - ], - then the blaze action would fail with an error message. - "java.lang.IllegalStateException: 1.txt has the same path as 1.txt! - If it is intended behavior rename one or both of them." - - Args: - ctx: The build rule context. - toolchain: Toolchain containing the jar tool. - output_jar: The jar to be produced by this action. - input_dirs: A sequence of tree artifacts to be zipped. - - Returns: - The generated output jar, i.e. output_jar - """ - - args = ctx.actions.args() - args.add("zip_resources") - args.add(output_jar) - args.add_joined( - "--input_dirs", - input_dirs, - join_with = ",", - omit_if_empty = False, - expand_directories = False, - ) - - _actions_run_deploy_jar( - ctx = ctx, - java_runtime = toolchain.java_runtime, - deploy_jar = toolchain.source_jar_zipper, - inputs = input_dirs, - outputs = [output_jar], - args = [args], - mnemonic = "KtJarActionFromTreeArtifacts", - progress_message = "Create Jar %{output}", - ) - - return output_jar - -def _DirSrcjarSyncer(ctx, kt_toolchain, file_factory): - _dirs = [] - _srcjars = [] - - def add_dirs(dirs): - if not dirs: - return - - _dirs.extend(dirs) - _srcjars.append( - _create_jar_from_tree_artifacts( - ctx, - kt_toolchain, - file_factory.declare_file("%s.srcjar" % len(_srcjars)), - dirs, - ), - ) - - def add_srcjars(srcjars): - if not srcjars: - return - - for srcjar in srcjars: - _dirs.append( - _expand_zip( - ctx, - kt_toolchain, - file_factory.declare_directory("%s.expand" % len(_dirs)), - srcjar, - ), - ) - _srcjars.extend(srcjars) - - return struct( - add_dirs = add_dirs, - add_srcjars = add_srcjars, - dirs = _dirs, - srcjars = _srcjars, - ) - -def _actions_run_deploy_jar( - ctx, - java_runtime, - deploy_jar, - inputs, - args = [], - deploy_jsa = None, - **kwargs): - java_args = ctx.actions.args() - java_inputs = [] - if deploy_jsa: - java_args.add("-Xshare:auto") - java_args.add(deploy_jsa, format = "-XX:SharedArchiveFile=%s") - java_args.add("-XX:-VerifySharedSpaces") - java_args.add("-XX:-ValidateSharedClassPaths") - java_inputs.append(deploy_jsa) - java_args.add("-jar", deploy_jar) - java_inputs.append(deploy_jar) - - java_depset = depset(direct = java_inputs, transitive = [java_runtime[DefaultInfo].files]) - if type(inputs) == "depset": - all_inputs = depset(transitive = [java_depset, inputs]) - else: - all_inputs = depset(direct = inputs, transitive = [java_depset]) - - ctx.actions.run( - executable = str(java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path), - inputs = all_inputs, - arguments = BASE_JVMOPTS + [java_args] + args, - **kwargs - ) - def _check_srcs_package(target_package, srcs, attr_name): """Makes sure the given srcs live in the given package.""" @@ -790,6 +667,27 @@ def _check_srcs_package(target_package, srcs, attr_name): fail(("Please do not depend on %s directly in %s. Either move it to this package or " + "depend on an appropriate rule in its package.") % (src.owner, attr_name)) +def _split_srcs_by_language(srcs, common_srcs, java_syncer): + srcs_set = sets.make(srcs) + common_srcs_set = sets.make(common_srcs) + + overlapping_srcs_set = sets.intersection(srcs_set, common_srcs_set) + if sets.length(overlapping_srcs_set) != 0: + fail("Overlap between srcs and common_srcs: %s" % sets.to_list(overlapping_srcs_set)) + + # Split sources, as java requires a separate compile step. + kt_srcs = [s for s in srcs if _is_kt_src(s)] + java_srcs = [s for s in srcs if _is_file(s, _EXT.JAVA)] + java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")]) + java_syncer.add_srcjars([s for s in srcs if _is_file(s, _EXT.SRCJAR)]) + + expected_srcs_set = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars) + unexpected_srcs_set = sets.difference(srcs_set, expected_srcs_set) + if sets.length(unexpected_srcs_set) != 0: + fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs_set)) + + return (kt_srcs, java_srcs) + # TODO: Streamline API to generate less actions. def _kt_jvm_library( ctx, @@ -804,15 +702,11 @@ def _kt_jvm_library( output = None, output_srcjar = None, # Will derive default filename if not set. deps = [], - codegen_output_java_infos = [], # JavaInfo sequence from kt_codegen_plugin. exports = [], # passthrough for JavaInfo constructor runtime_deps = [], # passthrough for JavaInfo constructor native_libraries = [], # passthrough of CcInfo for JavaInfo constructor plugins = _kt_plugins_map(), - pre_processed_java_plugin_processors = sets.make([]), exported_plugins = [], - android_lint_plugins = [], - android_lint_rules_jars = depset(), # Depset with standalone Android Lint rules Jars javacopts = [], kotlincopts = [], compile_jdeps = depset(), @@ -832,26 +726,25 @@ def _kt_jvm_library( fail("Missing or invalid kt_toolchain") file_factory = FileFactory(ctx, output) - deps = list(deps) # Defensive copy + static_deps = list(deps) # Defensive copy - # Split sources, as java requires a separate compile step. - kt_srcs = [s for s in srcs if _is_kt_src(s)] - java_srcs = [s for s in srcs if s.path.endswith(_EXT.JAVA)] - java_syncer = _DirSrcjarSyncer(ctx, kt_toolchain, file_factory) - java_syncer.add_dirs([s for s in srcs if _is_dir(s, "java")]) - java_syncer.add_srcjars([s for s in srcs if s.path.endswith(_EXT.SRCJAR)]) + kt_codegen_processing_env = dict( + pre_processed_processors = depset(), + codegen_output_java_infos = [], + ) + + pre_processed_processors = kt_codegen_processing_env["pre_processed_processors"] + generative_deps = kt_codegen_processing_env["codegen_output_java_infos"] - expected_srcs = sets.make(kt_srcs + java_srcs + java_syncer.dirs + java_syncer.srcjars) - unexpected_srcs = sets.difference(sets.make(srcs), expected_srcs) - if sets.length(unexpected_srcs) != 0: - fail("Unexpected srcs: %s" % sets.to_list(unexpected_srcs)) + java_syncer = kt_srcjars.DirSrcjarSyncer(ctx, kt_toolchain, file_factory) + kt_srcs, java_srcs = _split_srcs_by_language(srcs, common_srcs, java_syncer) # TODO: Remove this special case if kt_srcs and ("flogger" in [p.plugin_id for p in plugins.kt_compiler_plugin_infos]): - deps.append(kt_toolchain.flogger_runtime) + static_deps.append(kt_toolchain.flogger_runtime) - if srcs or common_srcs or rule_family != _RULE_FAMILY.ANDROID_LIBRARY: - deps.extend(kt_toolchain.kotlin_libs) + if kt_srcs or common_srcs or rule_family != _RULE_FAMILY.ANDROID_LIBRARY: + static_deps.extend(kt_toolchain.kotlin_libs) # Skip srcs package check for android_library targets with no kotlin sources: b/239725424 if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or kt_srcs: @@ -859,17 +752,19 @@ def _kt_jvm_library( _check_srcs_package(ctx.label.package, common_srcs, "common_srcs") _check_srcs_package(ctx.label.package, coverage_srcs, "coverage_srcs") - full_classpath = _create_classpath(java_toolchain, deps + codegen_output_java_infos) + # Includes generative deps from codegen. + extended_deps = static_deps + generative_deps + full_classpath = _create_classpath(java_toolchain, extended_deps) # Collect all plugin data, including processors to run and all plugin classpaths, # whether they have processors or not (b/120995492). # This may include go/errorprone plugin classpaths that kapt will ignore. - java_plugin_datas = [info.plugins for info in plugins.java_plugin_infos] + [dep.plugins for dep in deps] + java_plugin_datas = [info.plugins for info in plugins.java_plugin_infos] + [dep.plugins for dep in static_deps] plugin_processors = [ cls for p in java_plugin_datas for cls in p.processor_classes.to_list() - if not sets.contains(pre_processed_java_plugin_processors, cls) + if cls not in pre_processed_processors.to_list() ] plugin_classpaths = depset(transitive = [p.processor_jars for p in java_plugin_datas]) @@ -877,6 +772,20 @@ def _kt_jvm_library( out_srcjars = [] out_compilejars = [] + kt_hdrs = _derive_headers( + ctx, + toolchain = kt_toolchain, + file_factory = file_factory.derive("-kt"), + # TODO: prohibit overlap of srcs and common_srcs + srcs = kt_srcs, + ) + common_hdrs = _derive_headers( + ctx, + toolchain = kt_toolchain, + file_factory = file_factory.derive("-common"), + srcs = common_srcs, + ) + # Kotlin compilation requires two passes when annotation processing is # required. The initial pass processes the annotations and generates # additional sources and the following pass compiles the Kotlin code. @@ -887,8 +796,8 @@ def _kt_jvm_library( kapt_outputs = _kapt( ctx, file_factory = file_factory, - kt_srcs = kt_srcs, - common_srcs = common_srcs, + kt_srcs = kt_hdrs, + common_srcs = common_hdrs, java_srcs = java_srcs, plugin_processors = plugin_processors, plugin_classpaths = plugin_classpaths, @@ -908,12 +817,14 @@ def _kt_jvm_library( kotlinc_result = None if kt_srcs or common_srcs: - kotlinc_result = _run_kotlinc( + kotlinc_result = _kt_compile( ctx, kt_srcs = kt_srcs, common_srcs = common_srcs, coverage_srcs = coverage_srcs, java_srcs_and_dirs = java_srcs + java_syncer.dirs, + kt_hdrs = kt_hdrs, + common_hdrs = common_hdrs, file_factory = file_factory.derive("-kt"), kotlincopts = kotlincopts, compile_jdeps = compile_jdeps, @@ -924,9 +835,6 @@ def _kt_jvm_library( enforce_strict_deps = enforce_strict_deps, enforce_complete_jdeps = enforce_complete_jdeps, ) - - # Use un-instrumented Jar at compile-time to avoid double-instrumenting inline functions - # (see b/110763361 for the comparable Gradle issue) out_compilejars.append(kotlinc_result.compile_jar) out_srcjars.append(kotlinc_result.source_jar) out_jars.append(kotlinc_result.output_jar) @@ -937,7 +845,7 @@ def _kt_jvm_library( ) if classpath_resources_dirs: out_jars.append( - _create_jar_from_tree_artifacts( + kt_srcjars.zip_resources( ctx, kt_toolchain, file_factory.declare_file("-dir-res.jar"), @@ -947,11 +855,10 @@ def _kt_jvm_library( javac_java_info = None java_native_headers_jar = None - java_gensrcjar = None - java_genjar = None is_android_library_without_kt_srcs = rule_family == _RULE_FAMILY.ANDROID_LIBRARY and not kt_srcs + if java_srcs or java_syncer.srcjars or classpath_resources: - javac_deps = deps + codegen_output_java_infos # Defensive copy + javac_deps = extended_deps # Defensive copy if kapt_outputs.java_info: javac_deps.append(kapt_outputs.java_info) if kotlinc_result: @@ -963,6 +870,12 @@ def _kt_jvm_library( javac_deps.append(kt_toolchain.coverage_runtime) javac_out = output if is_android_library_without_kt_srcs else file_factory.declare_file("-java.jar") + + annotation_plugins = list(plugins.java_plugin_infos) + + # Enable annotation processing for java-only sources to enable data binding + enable_annotation_processing = not kt_srcs + javac_java_info = java_common.compile( ctx, source_files = java_srcs, @@ -978,17 +891,16 @@ def _kt_jvm_library( # all sources of default flags (for Ellipsis builds, see b/125452475). # TODO: remove default_javac_flags here once java_common.compile is fixed. javac_opts = ctx.fragments.java.default_javac_flags + javacopts, - plugins = plugins.java_plugin_infos, + plugins = annotation_plugins, strict_deps = "DEFAULT", java_toolchain = java_toolchain, neverlink = neverlink, - # Enable annotation processing for java-only sources to enable data binding - enable_annotation_processing = not kt_srcs, + enable_annotation_processing = enable_annotation_processing, annotation_processor_additional_outputs = annotation_processor_additional_outputs, annotation_processor_additional_inputs = annotation_processor_additional_inputs, ) - # Directly return the JavaInfo from java.compile() for java-only andorid_library targets + # Directly return the JavaInfo from java.compile() for java-only android_library targets # to avoid creating a new JavaInfo. See b/239847857 for additional context. if is_android_library_without_kt_srcs: return struct( @@ -1001,14 +913,25 @@ def _kt_jvm_library( out_compilejars.extend(javac_java_info.compile_jars.to_list()) # unpack singleton depset java_native_headers_jar = javac_java_info.outputs.native_headers - if kt_srcs: - java_gensrcjar = kapt_outputs.srcjar - java_genjar = _derive_gen_class_jar(ctx, kt_toolchain, kapt_outputs.manifest, javac_out, java_srcs) - else: - java_gensrcjar = javac_java_info.annotation_processing.source_jar - java_genjar = javac_java_info.annotation_processing.class_jar - if java_gensrcjar: - java_syncer.add_srcjars([java_gensrcjar]) + java_gensrcjar = None + java_genjar = None + if pre_processed_processors: + java_gen_srcjars = kt_codegen_processing_env["java_gen_srcjar"] + kt_gen_srcjars = kt_codegen_processing_env["kt_gen_srcjar"] + java_gensrcjar = file_factory.declare_file("-java_info_generated_source_jar.srcjar") + _singlejar( + ctx, + inputs = java_gen_srcjars + kt_gen_srcjars, + output = java_gensrcjar, + singlejar = java_toolchain.single_jar, + mnemonic = "JavaInfoGeneratedSourceJar", + ) + + elif javac_java_info: + java_gensrcjar = javac_java_info.annotation_processing.source_jar + java_genjar = javac_java_info.annotation_processing.class_jar + if java_gensrcjar: + java_syncer.add_srcjars([java_gensrcjar]) jdeps_output = None compile_jdeps_output = None @@ -1017,6 +940,54 @@ def _kt_jvm_library( # TODO: Move severity overrides to config file when possible again blocking_action_outs = [] + # TODO: Remove the is_android_library_without_kt_srcs condition once KtAndroidLint + # uses the same lint checks with AndroidLint + + if not is_android_library_without_kt_srcs: + lint_flags = [ + "--java-language-level", # b/159950410 + kt_toolchain.java_language_version, + "--kotlin-language-level", + kt_toolchain.kotlin_language_version, + "--nowarn", # Check for "errors", which includes custom checks that report errors. + "--XallowBaselineSuppress", # allow baseline exemptions of otherwise unsuppressable errors + "--exitcode", # fail on error + "--fullpath", # reduce file path clutter in reported issues + "--text", + "stdout", # also log to stdout + ] + if disable_lint_checks and disable_lint_checks != [""]: + lint_flags.append("--disable") + lint_flags.append(",".join(disable_lint_checks)) + + android_lint_out = lint_actions.run_lint_on_library( + ctx, + runner = kt_toolchain.android_lint_runner, + output = file_factory.declare_file("_android_lint_output.xml"), + srcs = kt_srcs + java_srcs + common_srcs, + source_jars = java_syncer.srcjars, + classpath = full_classpath, + manifest = manifest, + merged_manifest = merged_manifest, + resource_files = resource_files, + baseline_file = androidlint_toolchains.get_baseline(ctx), + config = kt_toolchain.android_lint_config, + android_lint_plugins_depset = depset( + order = "preorder", + transitive = [plugin_classpaths] + [ + dep.transitive_runtime_jars + for dep in plugins.android_lint_libjar_plugin_infos + ], + ), + android_lint_rules = plugins.android_lint_singlejar_plugins, + lint_flags = lint_flags, + extra_input_depsets = [p.processor_data for p in java_plugin_datas] + [depset([java_genjar] if java_genjar else [])], + testonly = testonly, + android_java8_libs = kt_toolchain.android_java8_apis_desugared, + mnemonic = "KtAndroidLint", # so LSA extractor can distinguish Kotlin (b/189442586) + ) + blocking_action_outs.append(android_lint_out) + if output_srcjar == None: output_srcjar = file_factory.declare_file("-src.jar") compile_jar = file_factory.declare_file("-compile.jar") @@ -1045,7 +1016,7 @@ def _kt_jvm_library( output_jar = output, compile_jar = compile_jar, source_jar = output_srcjar, - deps = deps, + deps = static_deps, exports = exports, exported_plugins = exported_plugins, runtime_deps = runtime_deps, @@ -1079,6 +1050,10 @@ def _kt_jvm_import( if not jars: fail("Must import at least one JAR") + _check_srcs_package(ctx.label.package, jars, "jars") + if srcjar: + _check_srcs_package(ctx.label.package, [srcjar], "srcjar") + file_factory = FileFactory(ctx, jars[0]) deps = java_common.merge(deps + kt_toolchain.kotlin_libs) @@ -1186,8 +1161,6 @@ def _partition(sequence, filter): return pos, neg common = struct( - ALLOWED_ANDROID_RULES = _ALLOWED_ANDROID_RULES, - ALLOWED_JVM_RULES = _ALLOWED_JVM_RULES, JAR_FILE_TYPE = _JAR_FILE_TYPE, JVM_FLAGS = BASE_JVMOPTS, KT_FILE_TYPES = _KT_FILE_TYPES, @@ -1196,7 +1169,7 @@ common = struct( SRCJAR_FILE_TYPES = _SRCJAR_FILE_TYPES, collect_proguard_specs = _collect_proguard_specs, collect_providers = _collect_providers, - create_jar_from_tree_artifacts = _create_jar_from_tree_artifacts, + create_jar_from_tree_artifacts = kt_srcjars.zip_resources, common_kapt_and_kotlinc_args = _common_kapt_and_kotlinc_args, is_kt_src = _is_kt_src, kt_jvm_import = _kt_jvm_import, diff --git a/kotlin/compiler_opt.bzl b/kotlin/compiler_opt.bzl index e7a89d5..a44fdfc 100644 --- a/kotlin/compiler_opt.bzl +++ b/kotlin/compiler_opt.bzl @@ -24,23 +24,22 @@ be passed to the `custom_kotlincopts` attribute. The set of directories that all `kt_compiler_opt` targets is also limited, to prevent misuse. """ +load("//bazel:stubs.bzl", "check_compiler_opt_allowlist") +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") + # Intentionally private to prevent misuse. _KtCompilerOptInfo = provider( doc = "A restricted set of kotlinc opts", fields = {"opts": "list[string]"}, ) -_ALLOWED_ROOTS = [ -] - _ALLOWED_VISIBILITY_NAMES = [ "__pkg__", "__subpackages__", ] def _kt_compiler_opt_impl(ctx): - if not any([ctx.label.package.startswith(p) for p in _ALLOWED_ROOTS]): - fail("kt_compiler_opt is only allowed under " + str(_ALLOWED_ROOTS)) + check_compiler_opt_allowlist(ctx.label) visibility_groups = [v for v in ctx.attr.visibility if not v.name in _ALLOWED_VISIBILITY_NAMES] if len(visibility_groups) > 0: diff --git a/kotlin/compiler_plugin.bzl b/kotlin/compiler_plugin.bzl index 3527aee..15b7ff7 100644 --- a/kotlin/compiler_plugin.bzl +++ b/kotlin/compiler_plugin.bzl @@ -14,6 +14,8 @@ """A rule for declaring and passing kotlinc plugins.""" +load("//:visibility.bzl", "RULES_KOTLIN") + _KtCompilerPluginInfo = provider( doc = "Info for running a plugin that directly registers itself to kotlinc extension points", fields = dict( @@ -69,14 +71,3 @@ kt_compiler_plugin = rule( KtCompilerPluginInfo, ], ) - -def _get_exported_plugins(_target, ctx_rule): - return [t[KtCompilerPluginInfo] for t in getattr(ctx_rule.attr, "exported_plugins", []) if (KtCompilerPluginInfo in t)] - -kt_compiler_plugin_visitor = struct( - name = "compiler_plugins", - visit_target = _get_exported_plugins, - filter_edge = None, - finish_expansion = None, - process_unvisited_target = None, -) diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/BUILD b/kotlin/jvm/internal_do_not_use/traverse_exports/BUILD new file mode 100644 index 0000000..6db3c1e --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/BUILD @@ -0,0 +1,29 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +package(default_visibility = ["//:internal"]) + +licenses(["notice"]) + +bzl_library( + name = "traverse_exports_bzl", + srcs = glob(["*.bzl"]), + deps = [ + "//:visibility_bzl", + "//kotlin:for_traverse_exports_bzl", + "@bazel_skylib//lib:sets", + ], +) diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl new file mode 100644 index 0000000..84a0960 --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/codegen_plugin.bzl @@ -0,0 +1,33 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_codegen_plugin_visitor""" + +load("//kotlin:codegen_plugin.internal.bzl", "KtCodegenPluginInfo") +load("//:visibility.bzl", "RULES_KOTLIN") + +def _get_kt_codegen_plugins(_target, ctx_rule): + return [ + t[KtCodegenPluginInfo] + for t in getattr(ctx_rule.attr, "exported_plugins", []) + if KtCodegenPluginInfo in t + ] + +kt_codegen_plugin_visitor = struct( + name = "codegen_plugins", + visit_target = _get_kt_codegen_plugins, + filter_edge = None, + finish_expansion = None, + process_unvisited_target = None, +) diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl new file mode 100644 index 0000000..a5c65c4 --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/compiler_plugin.bzl @@ -0,0 +1,33 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_compiler_plugin_visitor""" + +load("//:visibility.bzl", "RULES_KOTLIN") +load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo") + +def _get_exported_plugins(_target, ctx_rule): + return [ + t[KtCompilerPluginInfo] + for t in getattr(ctx_rule.attr, "exported_plugins", []) + if (KtCompilerPluginInfo in t) + ] + +kt_compiler_plugin_visitor = struct( + name = "compiler_plugins", + visit_target = _get_exported_plugins, + filter_edge = None, + finish_expansion = None, + process_unvisited_target = None, +) diff --git a/kotlin/direct_jdeps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/direct_jdeps.bzl index f242989..8bbb75f 100644 --- a/kotlin/direct_jdeps.bzl +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/direct_jdeps.bzl @@ -14,8 +14,14 @@ """kt_traverse_exports visitor for exposing jdeps files from direct deps.""" +load("//:visibility.bzl", "RULES_KOTLIN") + def _get_jdeps(target, _ctx_rule): - return [out.compile_jdeps for out in target[JavaInfo].java_outputs if out.compile_jdeps] + return [ + out.compile_jdeps + for out in target[JavaInfo].java_outputs + if out.compile_jdeps + ] kt_direct_jdeps_visitor = struct( name = "direct_jdeps", diff --git a/kotlin/forbidden_deps.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/forbidden_deps.bzl index 67a04fb..fa1db86 100644 --- a/kotlin/forbidden_deps.bzl +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/forbidden_deps.bzl @@ -22,6 +22,7 @@ Currently this system recognizes: load("@bazel_skylib//lib:sets.bzl", "sets") load("//bazel:stubs.bzl", "EXEMPT_DEPS", "FORBIDDEN_DEP_PACKAGES") +load("//:visibility.bzl", "RULES_KOTLIN") def _error(target, msg): return (str(target.label), msg) diff --git a/kotlin/friend_jars.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/friend_jars.bzl index 1be3f63..68cf1a6 100644 --- a/kotlin/friend_jars.bzl +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/friend_jars.bzl @@ -12,7 +12,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""TODO: Write module docstring.""" +"""kt_friend_visitor""" + +load("//:visibility.bzl", "RULES_KOTLIN") def is_eligible_friend(target, friend): """ @@ -25,7 +27,7 @@ def is_eligible_friend(target, friend): 4. `target` in `test/java/` pkg, `friend` in parallel `main/java/` pkg Args: - target: (target) The current target + target: (Target) The current target friend: (Target) A potential friend of `target` Returns: diff --git a/kotlin/java_plugin.internal.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/java_plugin.bzl index 69e7bb5..b993b75 100644 --- a/kotlin/java_plugin.internal.bzl +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/java_plugin.bzl @@ -19,11 +19,12 @@ Due to cross plugin type processing, the plugin info search processor differs from the way that java targets handles plugins. """ +load("//:visibility.bzl", "RULES_KOTLIN") + def _get_java_plugins(_target, ctx_rule): - exported_plugins = getattr(ctx_rule.attr, "exported_plugins", []) return [ t[JavaPluginInfo].plugins - for t in exported_plugins + for t in getattr(ctx_rule.attr, "exported_plugins", []) if JavaPluginInfo in t ] diff --git a/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl b/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl new file mode 100644 index 0000000..f0f9e6a --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/traverse_exports/traverse_exports.bzl @@ -0,0 +1,122 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Combined aspect for all rules_kotlin behaviours that need to traverse exports.""" + +load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor") +load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor") +load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor") +load(":friend_jars.bzl", "kt_friend_jars_visitor", "kt_friend_labels_visitor") +load(":java_plugin.bzl", "java_plugin_visitor") +load("//:visibility.bzl", "RULES_KOTLIN") + +# java_xxx_proto_library don't populate java_outputs but we can get them through +# required_aspect_providers from their proto_library deps. +_DEPS_AS_EXPORTS_RULES = [ + "java_proto_library", + "java_lite_proto_library", + "java_mutable_proto_library", +] + +_NO_SRCS_DEPS_AS_EXPORTS_RULES = [ + "proto_library", +] + +# visitor = struct[T]( +# name = string, +# visit_target = function(Target, ctx.rule): list[T], +# filter_edge = None|(function(src: ?, dest: Target): bool), +# process_unvisited_target = None|(function(Target): list[T]), +# finish_expansion = None|(function(depset[T]): depset[T]), +# ) +_VISITORS = [ + kt_forbidden_deps_visitor, + kt_direct_jdeps_visitor, + kt_compiler_plugin_visitor, + kt_friend_jars_visitor, + kt_friend_labels_visitor, + java_plugin_visitor, +] + +_KtTraverseExportsInfo = provider( + doc = "depsets for transitive info about exports", + fields = { + v.name: ("depset[%s]" % v.name) + for v in _VISITORS + }, +) + +_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{ + v.name: depset() + for v in _VISITORS +}) + +def _aspect_impl(target, ctx): + if not (JavaInfo in target): + # Ignore non-JVM targets. This also chops-up the + # traversal domain at these targets. + # TODO: Support non-JVM targets for KMP + return _EMPTY_KT_TRAVERSE_EXPORTS_INFO + + exports = [] + exports.extend(getattr(ctx.rule.attr, "exports", [])) # exports list is frozen + if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES: + exports.extend(ctx.rule.attr.deps) + elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs: + exports.extend(ctx.rule.attr.deps) + + return _KtTraverseExportsInfo(**{ + v.name: depset( + direct = v.visit_target(target, ctx.rule), + transitive = [ + getattr(e[_KtTraverseExportsInfo], v.name) + for e in exports + if (not v.filter_edge or v.filter_edge(target, e)) + ], + ) + for v in _VISITORS + }) + +_aspect = aspect( + implementation = _aspect_impl, + provides = [_KtTraverseExportsInfo], + # Transitively check exports, since they are effectively directly depended on. + # "deps" needed for rules that treat deps as exports (usually absent srcs). + attr_aspects = ["exports", "deps"], + required_aspect_providers = [JavaInfo], # to get at JavaXxxProtoAspects' JavaInfos +) + +def _create_visitor_expand(visitor): + def _visitor_expand(targets, root = None): + direct = [] + transitive = [] + for t in targets: + if (not visitor.filter_edge or visitor.filter_edge(root, t)): + if _KtTraverseExportsInfo in t: + transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name)) + elif visitor.process_unvisited_target: + direct.extend(visitor.process_unvisited_target(t)) + + expanded_set = depset(direct = direct, transitive = transitive) + return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set + + return _visitor_expand + +kt_traverse_exports = struct( + aspect = _aspect, + **{ + "expand_" + v.name: _create_visitor_expand(v) + for v in _VISITORS + } +) diff --git a/kotlin/jvm/internal_do_not_use/util/BUILD b/kotlin/jvm/internal_do_not_use/util/BUILD new file mode 100644 index 0000000..bcfec8d --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/util/BUILD @@ -0,0 +1,28 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("@bazel_skylib//:bzl_library.bzl", "bzl_library") + +package(default_visibility = ["//:internal"]) + +licenses(["notice"]) + +bzl_library( + name = "util_bzl", + srcs = glob(["*.bzl"]), + deps = [ + "//:visibility_bzl", + "@bazel_tools//tools/jdk:jvmopts", + ], +) diff --git a/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl b/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl new file mode 100644 index 0000000..d5341c8 --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/util/class_file_selectors.bzl @@ -0,0 +1,57 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Selects bytecode class files with a matched source file in srcjars.""" + +load("//:visibility.bzl", "RULES_KOTLIN") + +def gen_java_info_generated_class_jar(ctx, file_factory, kt_toolchain, input_jars, srcjars): + """Generates a class jar with class file jar entries matching files in the give srcjars. + + Args: + ctx: A rule context. + file_factory: A file factory in responsible for file creation under the current context. + kt_toolchain: The toolchain for kotlin builds. + input_jars: A sequence of jar files from which class files are selected. + srcjars: A sequence of source jar files that the selection references to. + Returns: + The output jar file, i.e. output_jar. + """ + output_jar = file_factory.declare_file("-java_info_generated_class_jar.jar") + input_jars = depset(input_jars) + transformer_env_files = depset(srcjars) + + transformer_entry_point = "com.google.devtools.jar.transformation.ClassFileSelectorBySourceFile" + transformer_jars = kt_toolchain.class_file_selector_by_source_file[JavaInfo].transitive_runtime_jars + jar_transformer = kt_toolchain.jar_transformer[DefaultInfo].files_to_run + + args = ctx.actions.args() + args.add_joined("--input_jars", input_jars, join_with = ",") + args.add_joined("--transformer_jars", transformer_jars, join_with = ",") + args.add("--transformer_entry_point", transformer_entry_point) + args.add_joined("--transformer_env_files", transformer_env_files, join_with = ",") + args.add("--result", output_jar) + ctx.actions.run( + inputs = depset(transitive = [ + input_jars, + transformer_jars, + transformer_env_files, + ]), + outputs = [output_jar], + arguments = [args], + progress_message = "Generating JavaInfo.generated_class_jar into %{output}", + mnemonic = "ClassFileSelectorBySourceFile", + executable = jar_transformer, + ) + return output_jar diff --git a/kotlin/file_factory.bzl b/kotlin/jvm/internal_do_not_use/util/file_factory.bzl index 25c2837..2e076c3 100644 --- a/kotlin/file_factory.bzl +++ b/kotlin/jvm/internal_do_not_use/util/file_factory.bzl @@ -14,8 +14,10 @@ """FileFactory""" -def FileFactory(ctx, base, suffix = None): - """Creates files with names derived from some base file +load("//:visibility.bzl", "RULES_KOTLIN") + +def FileFactory(ctx, base): + """Creates files with names derived from some base file or prefix Including the name of a rule is not always enough to guarantee unique filenames. For example, helper functions that declare their own output files may be called multiple times in the same @@ -23,26 +25,35 @@ def FileFactory(ctx, base, suffix = None): Args: ctx: ctx - base: [File] The file to derive other filenames from - suffix: [Optional[string]] An additional suffix to differentiate declared files + base: [File|string] The file to derive other filenames from, or an exact base prefix Returns: FileFactory """ - base_name = base.basename.rsplit(".", 1)[0] + (suffix or "") + if type(base) == "File": + base = _scrub_base_file(ctx, base) def declare_directory(suffix): - return ctx.actions.declare_directory(base_name + suffix, sibling = base) + return ctx.actions.declare_directory(base + suffix) def declare_file(suffix): - return ctx.actions.declare_file(base_name + suffix, sibling = base) + return ctx.actions.declare_file(base + suffix) def derive(suffix): - return FileFactory(ctx, base, suffix) + return FileFactory(ctx, base + suffix) return struct( + base_as_path = ctx.bin_dir.path + "/" + ctx.label.package + "/" + base, declare_directory = declare_directory, declare_file = declare_file, derive = derive, ) + +def _scrub_base_file(ctx, file): + if not file.extension: + fail("Base file must have an extension: was %s" % (file.path)) + if file.owner.package != ctx.label.package: + fail("Base file must be from ctx package: was %s expected %s" % (file.owner.package, ctx.label.package)) + + return file.short_path.removeprefix(ctx.label.package + "/").rsplit(".", 1)[0] diff --git a/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl b/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl new file mode 100644 index 0000000..14c784b --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/util/run_deploy_jar.bzl @@ -0,0 +1,54 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_run_deploy_jar""" + +# go/keep-sorted start +load("//:visibility.bzl", "RULES_KOTLIN") +load("//bazel:stubs.bzl", "BASE_JVMOPTS") +# go/keep-sorted end + +def kt_run_deploy_jar( + ctx, + java_runtime, + deploy_jar, + inputs, + args = [], + deploy_jsa = None, + **kwargs): + """An analogue to ctx.actions.run for _deploy.jar executables.""" + + java_args = ctx.actions.args() + java_inputs = [] + if deploy_jsa: + java_args.add("-Xshare:auto") + java_args.add(deploy_jsa, format = "-XX:SharedArchiveFile=%s") + java_args.add("-XX:-VerifySharedSpaces") + java_args.add("-XX:-ValidateSharedClassPaths") + java_inputs.append(deploy_jsa) + java_args.add("-jar", deploy_jar) + java_inputs.append(deploy_jar) + + java_depset = depset(direct = java_inputs, transitive = [java_runtime[DefaultInfo].files]) + if type(inputs) == "depset": + all_inputs = depset(transitive = [java_depset, inputs]) + else: + all_inputs = depset(direct = inputs, transitive = [java_depset]) + + ctx.actions.run( + executable = str(java_runtime[java_common.JavaRuntimeInfo].java_executable_exec_path), + inputs = all_inputs, + arguments = BASE_JVMOPTS + [java_args] + args, + **kwargs + ) diff --git a/kotlin/jvm/internal_do_not_use/util/srcjars.bzl b/kotlin/jvm/internal_do_not_use/util/srcjars.bzl new file mode 100644 index 0000000..becf573 --- /dev/null +++ b/kotlin/jvm/internal_do_not_use/util/srcjars.bzl @@ -0,0 +1,183 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""kt_srcjars""" + +# go/keep-sorted start +load("//:visibility.bzl", "RULES_KOTLIN") +load(":run_deploy_jar.bzl", "kt_run_deploy_jar") +# go/keep-sorted end + +def _zip( + ctx, + kt_jvm_toolchain, + out_jar, + srcs = [], + common_srcs = [], + ignore_not_allowed_files = False): + """Creates a srcjar from a set of Kotlin and Java srcs + + Paths inside the srcjar are derived from the package name in the source file. + """ + + args = ctx.actions.args() + args.add("zip") + args.add(out_jar) + args.add_joined("--kotlin_srcs", srcs, join_with = ",") + args.add_joined("--common_srcs", common_srcs, join_with = ",") + if ignore_not_allowed_files: + args.add("-i") + + kt_run_deploy_jar( + ctx = ctx, + java_runtime = kt_jvm_toolchain.java_runtime, + deploy_jar = kt_jvm_toolchain.source_jar_zipper, + inputs = srcs + common_srcs, + outputs = [out_jar], + args = [args], + mnemonic = "KtJar", + progress_message = "Create Jar (kotlin/common.bzl): %{output}", + ) + + return out_jar + +def _unzip( + ctx, + kt_jvm_toolchain, + dir, + input): + args = ctx.actions.args() + args.add("unzip", input) + args.add(dir.path) + + kt_run_deploy_jar( + ctx = ctx, + java_runtime = kt_jvm_toolchain.java_runtime, + deploy_jar = kt_jvm_toolchain.source_jar_zipper, + inputs = [input], + outputs = [dir], + args = [args], + mnemonic = "SrcJarUnzip", + ) + + return dir + +def _zip_resources(ctx, kt_jvm_toolchain, output_jar, input_dirs): + """Packs a sequence of tree artifacts into a single jar. + + Given the following file directory structure, + /usr/home/a/x/1.txt + /usr/home/b/y/1.txt + with an input_dirs as [ + "/usr/home/a", + "/usr/home/b", + ], + The tool produces a jar with in-archive structure of, + x/1.txt + y/1.txt + + The function fails on the duplicate jar entry case. e.g. if we pass an + input_dirs as [ + "/usr/home/a/x", + "/usr/home/b/y", + ], + then the blaze action would fail with an error message. + "java.lang.IllegalStateException: 1.txt has the same path as 1.txt! + If it is intended behavior rename one or both of them." + + Args: + ctx: The build rule context. + kt_jvm_toolchain: Toolchain containing the jar tool. + output_jar: The jar to be produced by this action. + input_dirs: A sequence of tree artifacts to be zipped. + + Returns: + The generated output jar, i.e. output_jar + """ + + args = ctx.actions.args() + args.add("zip_resources") + args.add(output_jar) + args.add_joined( + "--input_dirs", + input_dirs, + join_with = ",", + omit_if_empty = False, + expand_directories = False, + ) + + kt_run_deploy_jar( + ctx = ctx, + java_runtime = kt_jvm_toolchain.java_runtime, + deploy_jar = kt_jvm_toolchain.source_jar_zipper, + inputs = input_dirs, + outputs = [output_jar], + args = [args], + mnemonic = "KtJarActionFromTreeArtifacts", + progress_message = "Create Jar %{output}", + ) + + return output_jar + +def _DirSrcjarSyncer( + ctx, + kt_jvm_toolchain, + file_factory): + """Synchronizes the contents of a set of srcjar files and tree-artifacts""" + + _dirs = [] + _srcjars = [] + + def add_dirs(dirs): + if not dirs: + return + + _dirs.extend(dirs) + _srcjars.append( + _zip_resources( + ctx, + kt_jvm_toolchain, + file_factory.declare_file("%s-codegen.srcjar" % len(_srcjars)), + dirs, + ), + ) + + def add_srcjars(srcjars): + if not srcjars: + return + + for srcjar in srcjars: + _dirs.append( + _unzip( + ctx, + kt_jvm_toolchain, + file_factory.declare_directory("%s.expand" % len(_dirs)), + srcjar, + ), + ) + _srcjars.extend(srcjars) + + return struct( + add_dirs = add_dirs, + add_srcjars = add_srcjars, + dirs = _dirs, + srcjars = _srcjars, + ) + +kt_srcjars = struct( + zip = _zip, + unzip = _unzip, + zip_resources = _zip_resources, + DirSrcjarSyncer = _DirSrcjarSyncer, +) diff --git a/kotlin/jvm_compile.bzl b/kotlin/jvm_compile.bzl index 4139150..9b195b4 100644 --- a/kotlin/jvm_compile.bzl +++ b/kotlin/jvm_compile.bzl @@ -17,7 +17,7 @@ load(":common.bzl", "common") load(":compiler_plugin.bzl", "KtCompilerPluginInfo") load(":traverse_exports.bzl", "kt_traverse_exports") -load("@bazel_skylib//lib:sets.bzl", "sets") +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") _RULE_FAMILY = common.RULE_FAMILY @@ -115,10 +115,7 @@ def kt_jvm_compile( # Allow passing either a target or a provider until all callers are updated java_toolchain = java_toolchain[java_common.JavaToolchainInfo] - srcs = list(srcs) - classpath_resources = list(classpath_resources) java_infos = [] - codegen_output_java_infos = [] # The r_java field only support Android resources Jar files. For now, verify # that the name of the jar matches "_resources.jar". This check does not to @@ -132,17 +129,13 @@ def kt_jvm_compile( "'*_resources.jar'.") r_java_infos.append(r_java) - pre_processed_java_plugin_processors = sets.make([]) - # Skip deps validation check for any android_library target with no kotlin sources: b/239721906 has_kt_srcs = any([common.is_kt_src(src) for src in srcs]) if rule_family != _RULE_FAMILY.ANDROID_LIBRARY or has_kt_srcs: kt_traverse_exports.expand_forbidden_deps(deps + runtime_deps + exports) for dep in deps: - if False: - pass - elif JavaInfo in dep: + if JavaInfo in dep: java_infos.append(dep[JavaInfo]) else: fail("Unexpected dependency (must provide JavaInfo): %s" % dep.label) @@ -152,13 +145,10 @@ def kt_jvm_compile( return common.kt_jvm_library( ctx, - android_lint_plugins = [p[JavaInfo] for p in android_lint_plugins], - android_lint_rules_jars = android_lint_rules_jars, classpath_resources = classpath_resources, common_srcs = common_srcs, coverage_srcs = coverage_srcs, deps = r_java_infos + java_infos, - codegen_output_java_infos = codegen_output_java_infos, disable_lint_checks = disable_lint_checks, exported_plugins = [e[JavaPluginInfo] for e in exported_plugins if (JavaPluginInfo in e)], # Not all exported targets contain a JavaInfo (e.g. some only have CcInfo) @@ -176,7 +166,13 @@ def kt_jvm_compile( output = output, output_srcjar = output_srcjar, plugins = common.kt_plugins_map( - java_plugin_infos = [plugin[JavaPluginInfo] for plugin in plugins if (JavaPluginInfo in plugin)], + android_lint_singlejar_plugins = android_lint_rules_jars, + android_lint_libjar_plugin_infos = [p[JavaInfo] for p in android_lint_plugins], + java_plugin_infos = [ + plugin[JavaPluginInfo] + for plugin in plugins + if (JavaPluginInfo in plugin) + ], kt_compiler_plugin_infos = kt_traverse_exports.expand_compiler_plugins(deps).to_list() + [ plugin[KtCompilerPluginInfo] @@ -184,7 +180,6 @@ def kt_jvm_compile( if (KtCompilerPluginInfo in plugin) ], ), - pre_processed_java_plugin_processors = pre_processed_java_plugin_processors, resource_files = resource_files, runtime_deps = [d[JavaInfo] for d in runtime_deps if JavaInfo in d], srcs = srcs, diff --git a/kotlin/jvm_import.bzl b/kotlin/jvm_import.bzl index c42bb96..5f7c6ed 100644 --- a/kotlin/jvm_import.bzl +++ b/kotlin/jvm_import.bzl @@ -20,6 +20,7 @@ load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") load("@bazel_skylib//lib:dicts.bzl", "dicts") load(":compiler_plugin.bzl", "KtCompilerPluginInfo") +load("//:visibility.bzl", "RULES_KOTLIN") def _kt_jvm_import_impl(ctx): kt_jvm_toolchain = kt_jvm_toolchains.get(ctx) @@ -72,12 +73,10 @@ _KT_JVM_IMPORT_ATTRS = dicts.add( java_toolchains.attrs, kt_jvm_toolchains.attrs, deps = attr.label_list( - # We allow android rule deps to make importing android JARs easier. - allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES, aspects = [kt_traverse_exports.aspect], providers = [ # Each provider-set expands on allow_rules - [JavaInfo], + [JavaInfo], # We allow android rule deps to make importing android JARs easier. ], doc = """The list of libraries this library directly depends on at compile-time. For Java and Kotlin libraries listed, the Jars they build as well as the transitive closure @@ -115,10 +114,9 @@ _KT_JVM_IMPORT_ATTRS = dicts.add( doc = """Proguard specifications to go along with this library.""", ), runtime_deps = attr.label_list( - # TODO: Delete common.ALLOWED_ANDROID_RULES - allow_rules = common.ALLOWED_JVM_RULES + common.ALLOWED_ANDROID_RULES, providers = [ # Each provider-set expands on allow_rules + [JavaInfo], [CcInfo], # for JNI / native dependencies ], aspects = [kt_traverse_exports.aspect], diff --git a/kotlin/jvm_library.bzl b/kotlin/jvm_library.bzl index 916e358..9485bcf 100644 --- a/kotlin/jvm_library.bzl +++ b/kotlin/jvm_library.bzl @@ -17,6 +17,10 @@ load(":jvm_library.internal.bzl", "kt_jvm_library_helper") load("//bazel:stubs.bzl", "register_extension_info") load("@bazel_skylib//lib:dicts.bzl", "dicts") +load("//bazel:stubs.bzl", "lint_actions") +load("//bazel:stubs.bzl", "LINT_REGISTRY") +load("//bazel:stubs.bzl", "registry_checks_for_package") +load("//:visibility.bzl", "RULES_KOTLIN") def kt_jvm_library( name, @@ -106,6 +110,11 @@ def kt_jvm_library( transitive_configs = transitive_configs, **dicts.add( kwargs, + { + # Dictionary necessary to set private attributes. + "$android_lint_baseline_file": lint_actions.get_android_lint_baseline_file(native.package_name()), + "$android_lint_plugins": registry_checks_for_package(LINT_REGISTRY, native.package_name()), + }, ) ) diff --git a/kotlin/jvm_library.internal.bzl b/kotlin/jvm_library.internal.bzl index 85b9e52..22e6ef1 100644 --- a/kotlin/jvm_library.internal.bzl +++ b/kotlin/jvm_library.internal.bzl @@ -15,6 +15,7 @@ """Kotlin kt_jvm_library rule.""" load("//kotlin:compiler_opt.bzl", "kotlincopts_attrs", "merge_kotlincopts") +load("//toolchains/kotlin_jvm:androidlint_toolchains.bzl", "androidlint_toolchains") load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") load("@bazel_skylib//lib:dicts.bzl", "dicts") @@ -124,6 +125,7 @@ def _jvm_library_impl(ctx): ] _KT_JVM_LIBRARY_ATTRS = dicts.add( + androidlint_toolchains.attrs, java_toolchains.attrs, kotlincopts_attrs(), kt_jvm_toolchains.attrs, @@ -137,9 +139,9 @@ _KT_JVM_LIBRARY_ATTRS = dicts.add( allow_files = True, ), deps = attr.label_list( - allow_rules = common.ALLOWED_JVM_RULES, providers = [ # Each provider-set expands on allow_rules + [JavaInfo], ], aspects = [ kt_traverse_exports.aspect, @@ -171,9 +173,9 @@ _KT_JVM_LIBRARY_ATTRS = dicts.add( will not run kotlinc plugins""", ), exports = attr.label_list( - allow_rules = common.ALLOWED_JVM_RULES, providers = [ # Each provider-set expands on allow_rules + [JavaInfo], ], aspects = [ kt_traverse_exports.aspect, @@ -214,9 +216,9 @@ _KT_JVM_LIBRARY_ATTRS = dicts.add( go/be#java_library.resources.""", ), runtime_deps = attr.label_list( - allow_rules = common.ALLOWED_JVM_RULES, providers = [ # Each provider-set expands on allow_rules + [JavaInfo], [CcInfo], # for JNI / native dependencies ], aspects = [ diff --git a/kotlin/jvm_test.bzl b/kotlin/jvm_test.bzl index 1c19902..2a85a66 100644 --- a/kotlin/jvm_test.bzl +++ b/kotlin/jvm_test.bzl @@ -16,6 +16,7 @@ load(":jvm_library.bzl", "kt_jvm_library") load("//bazel:stubs.bzl", "register_extension_info") +load("//:visibility.bzl", "RULES_KOTLIN") def _lib_name(name): return "%s_DO_NOT_DEPEND_LIB" % name diff --git a/kotlin/rules.bzl b/kotlin/rules.bzl index 8d0188b..f08a1f2 100644 --- a/kotlin/rules.bzl +++ b/kotlin/rules.bzl @@ -14,10 +14,16 @@ """Kotlin rules.""" +load("//kotlin:compiler_opt.bzl", _kt_compiler_opt = "kt_compiler_opt") +load("//kotlin:compiler_plugin_export.bzl", _kt_compiler_plugin_export = "kt_compiler_plugin_export") load("//kotlin:jvm_import.bzl", _kt_jvm_import = "kt_jvm_import") load("//kotlin:jvm_library.bzl", _kt_jvm_library = "kt_jvm_library") load("//kotlin:jvm_test.bzl", _kt_jvm_test = "kt_jvm_test") +kt_compiler_opt = _kt_compiler_opt + +kt_compiler_plugin_export = _kt_compiler_plugin_export + kt_jvm_import = _kt_jvm_import kt_jvm_library = _kt_jvm_library diff --git a/kotlin/traverse_exports.bzl b/kotlin/traverse_exports.bzl index a8ce86f..8157ec1 100644 --- a/kotlin/traverse_exports.bzl +++ b/kotlin/traverse_exports.bzl @@ -14,108 +14,7 @@ """Combined aspect for all rules_kotlin behaviours that need to traverse exports.""" -load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor") -load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor") -load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor") -load(":friend_jars.bzl", "kt_friend_jars_visitor", "kt_friend_labels_visitor") -load(":java_plugin.internal.bzl", "java_plugin_visitor") +load("//kotlin/jvm/internal_do_not_use/traverse_exports:traverse_exports.bzl", _kt_traverse_exports = "kt_traverse_exports") +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") -# java_xxx_proto_library don't populate java_outputs but we can get them through -# required_aspect_providers from their proto_library deps. -_DEPS_AS_EXPORTS_RULES = [ - "java_proto_library", - "java_lite_proto_library", - "java_mutable_proto_library", -] - -_NO_SRCS_DEPS_AS_EXPORTS_RULES = [ - "proto_library", -] - -# visitor = struct[T]( -# name = string, -# visit_target = function(Target, ctx.rule): list[T], -# filter_edge = None|(function(src: ?, dest: Target): bool), -# process_unvisited_target = None|(function(Target): list[T]), -# finish_expansion = None|(function(depset[T]): depset[T]), -# ) -_VISITORS = [ - kt_forbidden_deps_visitor, - kt_direct_jdeps_visitor, - kt_compiler_plugin_visitor, - kt_friend_jars_visitor, - kt_friend_labels_visitor, - java_plugin_visitor, -] - -_KtTraverseExportsInfo = provider( - doc = "depsets for transitive info about exports", - fields = { - v.name: ("depset[%s]" % v.name) - for v in _VISITORS - }, -) - -_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{ - v.name: depset() - for v in _VISITORS -}) - -def _aspect_impl(target, ctx): - if not (JavaInfo in target): - # Ignore non-JVM targets. This also chops-up the - # traversal domain at these targets. - # TODO: Support non-JVM targets for KMP - return _EMPTY_KT_TRAVERSE_EXPORTS_INFO - - exports = [] - exports.extend(getattr(ctx.rule.attr, "exports", [])) # exports list is frozen - if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES: - exports.extend(ctx.rule.attr.deps) - elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs: - exports.extend(ctx.rule.attr.deps) - - return _KtTraverseExportsInfo(**{ - v.name: depset( - direct = v.visit_target(target, ctx.rule), - transitive = [ - getattr(e[_KtTraverseExportsInfo], v.name) - for e in exports - if (not v.filter_edge or v.filter_edge(target, e)) - ], - ) - for v in _VISITORS - }) - -_aspect = aspect( - implementation = _aspect_impl, - provides = [_KtTraverseExportsInfo], - # Transitively check exports, since they are effectively directly depended on. - # "deps" needed for rules that treat deps as exports (usually absent srcs). - attr_aspects = ["exports", "deps"], - required_aspect_providers = [JavaInfo], # to get at JavaXxxProtoAspects' JavaInfos -) - -def _create_visitor_expand(visitor): - def _visitor_expand(targets, root = None): - direct = [] - transitive = [] - for t in targets: - if (not visitor.filter_edge or visitor.filter_edge(root, t)): - if _KtTraverseExportsInfo in t: - transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name)) - elif visitor.process_unvisited_target: - direct.extend(visitor.process_unvisited_target(t)) - - expanded_set = depset(direct = direct, transitive = transitive) - return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set - - return _visitor_expand - -kt_traverse_exports = struct( - aspect = _aspect, - **{ - "expand_" + v.name: _create_visitor_expand(v) - for v in _VISITORS - } -) +kt_traverse_exports = _kt_traverse_exports diff --git a/tests/analysis/assert_failure_test.bzl b/tests/analysis/assert_failure_test.bzl index b266c2a..2a742c3 100644 --- a/tests/analysis/assert_failure_test.bzl +++ b/tests/analysis/assert_failure_test.bzl @@ -15,6 +15,7 @@ """An assertion for analysis failure.""" load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//:visibility.bzl", "RULES_KOTLIN") def _assert_failure_test_impl(ctx): env = analysistest.begin(ctx) diff --git a/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl index fe8c9dc..0c1b02a 100644 --- a/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl +++ b/tests/analysis/compiler_plugin/propagation/assert_propagation_test.bzl @@ -17,6 +17,7 @@ load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//rules:build_test.bzl", "build_test") load("//kotlin:traverse_exports.bzl", "kt_traverse_exports") +load("//:visibility.bzl", "RULES_KOTLIN") def _assert_propagation_impl(ctx): expected_ids = sets.make(ctx.attr.expected_plugin_ids) diff --git a/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl index d4a6bac..194025d 100644 --- a/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl +++ b/tests/analysis/compiler_plugin/provider_ctor/fake_compiler_plugin.bzl @@ -15,6 +15,7 @@ """A fake impl of kt_compiler_plugin.""" load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo") +load("//:visibility.bzl", "RULES_KOTLIN") def _kt_fake_compiler_plugin_impl(ctx): return [ diff --git a/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl index 9b2951e..f4e1849 100644 --- a/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl +++ b/tests/analysis/compiler_plugin/provider_output/assert_compiler_plugin_test.bzl @@ -16,6 +16,7 @@ load("//kotlin:compiler_plugin.bzl", "KtCompilerPluginInfo") load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//:visibility.bzl", "RULES_KOTLIN") def _test_impl(ctx): env = analysistest.begin(ctx) diff --git a/tests/analysis/for_test.bzl b/tests/analysis/for_test.bzl index 434c1a4..2a75726 100644 --- a/tests/analysis/for_test.bzl +++ b/tests/analysis/for_test.bzl @@ -16,6 +16,7 @@ load("//kotlin:jvm_library.bzl", "kt_jvm_library") load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") +load("//:visibility.bzl", "RULES_KOTLIN") def _kt_jvm_library_for_test(name, **kwargs): kt_jvm_library( diff --git a/tests/analysis/internal_do_not_use/util/file_factory/BUILD b/tests/analysis/internal_do_not_use/util/file_factory/BUILD new file mode 100644 index 0000000..d92e379 --- /dev/null +++ b/tests/analysis/internal_do_not_use/util/file_factory/BUILD @@ -0,0 +1,41 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load(":happy_test.bzl", "file_factory_happy_test") +load(":check_base_file_valid.bzl", "check_base_file_valid") +load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test") + +licenses(["notice"]) + +file_factory_happy_test( + name = "happy_test", +) + +assert_failure_test( + name = "base_without_extension_test", + msg_contains = "file must have an extension", + target_under_test = check_base_file_valid( + name = "base_without_extension", + base_file = "BUILD", + ), +) + +assert_failure_test( + name = "base_from_other_package_test", + msg_contains = "file must be from ctx package", + target_under_test = check_base_file_valid( + name = "base_from_other_package", + base_file = "//tests/analysis/internal_do_not_use/util/file_factory/sub", + ), +) diff --git a/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl b/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl new file mode 100644 index 0000000..9ca1f05 --- /dev/null +++ b/tests/analysis/internal_do_not_use/util/file_factory/check_base_file_valid.bzl @@ -0,0 +1,38 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Happy tests for FileFactory.""" + +load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS") +load("//:visibility.bzl", "RULES_KOTLIN") + +def _check_base_file_valid_impl(ctx): + FileFactory(ctx, ctx.file.base_file) + return [] + +_check_base_file_valid = rule( + implementation = _check_base_file_valid_impl, + attrs = dict( + base_file = attr.label(allow_single_file = True, mandatory = True), + ), +) + +def check_base_file_valid(name, tags = [], **kwargs): + _check_base_file_valid( + name = name, + tags = tags + ONLY_FOR_ANALYSIS_TEST_TAGS, + **kwargs + ) + return name diff --git a/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl b/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl new file mode 100644 index 0000000..1a2a655 --- /dev/null +++ b/tests/analysis/internal_do_not_use/util/file_factory/happy_test.bzl @@ -0,0 +1,78 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""file_factory_happy_test""" + +load("//kotlin/jvm/internal_do_not_use/util:file_factory.bzl", "FileFactory") +load("//:visibility.bzl", "RULES_KOTLIN") + +def _test_base_from_file(ctx, pkg_path): + base_file = ctx.actions.declare_file("file/base.txt") + factory = FileFactory(ctx, base_file) + + _assert_equals(pkg_path + "/file/base", factory.base_as_path) + + return [base_file] + +def _test_declare(ctx, pkg_path): + factory = FileFactory(ctx, "string/base") + + _assert_equals(pkg_path + "/string/base", factory.base_as_path) + + a_file = factory.declare_file("a.txt") + _assert_equals(pkg_path + "/string/basea.txt", a_file.path) + + b_dir = factory.declare_directory("b_dir") + _assert_equals(pkg_path + "/string/baseb_dir", b_dir.path) + + return [a_file, b_dir] + +def _test_derive(ctx, pkg_path): + factory = FileFactory(ctx, "") + + # Once + factory_once = factory.derive("once") + _assert_equals(pkg_path + "/once", factory_once.base_as_path) + + # Twice + factory_twice = factory_once.derive("/twice") + _assert_equals(pkg_path + "/once/twice", factory_twice.base_as_path) + +def _assert_equals(expected, actual): + if expected != actual: + fail("Expected '%s' but was '%s'" % (expected, actual)) + +def _file_factory_happy_test_impl(ctx): + pkg_path = ctx.bin_dir.path + "/" + ctx.label.package + all_files = [] + + all_files.extend(_test_base_from_file(ctx, pkg_path)) + all_files.extend(_test_declare(ctx, pkg_path)) + _test_derive(ctx, pkg_path) + + ctx.actions.run_shell( + outputs = all_files, + command = "exit 1", + ) + + test_script = ctx.actions.declare_file(ctx.label.name + "_test.sh") + ctx.actions.write(test_script, "#!/bin/bash", True) + return [ + DefaultInfo(executable = test_script), + ] + +file_factory_happy_test = rule( + implementation = _file_factory_happy_test_impl, + test = True, +) diff --git a/tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD b/tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD new file mode 100644 index 0000000..db873cf --- /dev/null +++ b/tests/analysis/internal_do_not_use/util/file_factory/sub/BUILD @@ -0,0 +1,22 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +licenses(["notice"]) + +genrule( + name = "sub", + outs = ["sub.txt"], + cmd = "touch $(OUTS)", + visibility = ["//tests/analysis/internal_do_not_use/util/file_factory:__pkg__"], +) diff --git a/tests/analysis/jvm_compile_test.bzl b/tests/analysis/jvm_compile_test.bzl index b361f5a..a8fd460 100644 --- a/tests/analysis/jvm_compile_test.bzl +++ b/tests/analysis/jvm_compile_test.bzl @@ -22,6 +22,7 @@ load("//toolchains/kotlin_jvm:java_toolchains.bzl", "java_toolchains") load("//toolchains/kotlin_jvm:kt_jvm_toolchains.bzl", "kt_jvm_toolchains") load("@bazel_skylib//rules:build_test.bzl", "build_test") load(":assert_failure_test.bzl", "assert_failure_test") +load("//:visibility.bzl", "RULES_KOTLIN") def _impl(ctx): # As additional capabilites need to be tested, this rule should support diff --git a/tests/analysis/jvm_import_test.bzl b/tests/analysis/jvm_import_test.bzl index a3bfd19..6e56c02 100644 --- a/tests/analysis/jvm_import_test.bzl +++ b/tests/analysis/jvm_import_test.bzl @@ -19,6 +19,7 @@ load("//kotlin:jvm_library.bzl", "kt_jvm_library") load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file") load(":assert_failure_test.bzl", "assert_failure_test") +load("//:visibility.bzl", "RULES_KOTLIN") def _impl(ctx): env = analysistest.begin(ctx) diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/BUILD b/tests/analysis/jvm_library/treeartifacts_srcs/BUILD new file mode 100644 index 0000000..3d724c4 --- /dev/null +++ b/tests/analysis/jvm_library/treeartifacts_srcs/BUILD @@ -0,0 +1,104 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +load("//tests/analysis:for_test.bzl", "rules_for_test") +load("//tests/analysis:assert_failure_test.bzl", "assert_failure_test") +load("//tests/analysis:jvm_library_test.bzl", "jvm_library_test") +load("//tests/analysis:util.bzl", "create_dir") + +package(default_testonly = True) + +licenses(["notice"]) + +jvm_library_test( + name = "treeartifact_basename_kotlin_test", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_basename_kotlin", + srcs = [ + create_dir( + name = "treeartifact_extension/kotlin", + srcs = [ + "Input.java", # TODO: Reject this source + ], + ), + ], + ), +) + +jvm_library_test( + name = "treeartifact_basename_java_test", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_basename_java", + srcs = [ + create_dir( + name = "treeartifact_extension/java", + srcs = [ + "Input.kt", # TODO: Reject this source + ], + ), + ], + ), +) + +assert_failure_test( + name = "treeartifact_extension_kt_test", + msg_contains = "/treeartifact_extension.kt", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_extension_kt", + srcs = [ + create_dir( + name = "treeartifact_extension.kt", + ), + ], + ), +) + +assert_failure_test( + name = "treeartifact_extension_java_test", + msg_contains = "/treeartifact_extension.java", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_extension_java", + srcs = [ + create_dir( + name = "treeartifact_extension.java", + ), + ], + ), +) + +assert_failure_test( + name = "treeartifact_extension_srcjar_test", + msg_contains = "/treeartifact_extension.srcjar", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_extension_srcjar", + srcs = [ + create_dir( + name = "treeartifact_extension.srcjar", + ), + ], + ), +) + +assert_failure_test( + name = "treeartifact_no_extension_test", + msg_contains = "/treeartifact_no_extension", + target_under_test = rules_for_test.kt_jvm_library( + name = "treeartifact_no_extension", + srcs = [ + create_dir( + name = "treeartifact_no_extension_dir", + ), + ], + ), +) diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/Input.java b/tests/analysis/jvm_library/treeartifacts_srcs/Input.java new file mode 100644 index 0000000..e675bc1 --- /dev/null +++ b/tests/analysis/jvm_library/treeartifacts_srcs/Input.java @@ -0,0 +1,16 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt b/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt new file mode 100644 index 0000000..e675bc1 --- /dev/null +++ b/tests/analysis/jvm_library/treeartifacts_srcs/Input.kt @@ -0,0 +1,16 @@ +/* + * * Copyright 2022 Google LLC. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + diff --git a/tests/analysis/jvm_library_test.bzl b/tests/analysis/jvm_library_test.bzl index 6435cc5..d51e6e1 100644 --- a/tests/analysis/jvm_library_test.bzl +++ b/tests/analysis/jvm_library_test.bzl @@ -15,10 +15,11 @@ """Kotlin kt_jvm_library rule tests.""" load("//kotlin:jvm_library.bzl", "kt_jvm_library") -load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file", "get_action_arg") +load("//tests/analysis:util.bzl", "ONLY_FOR_ANALYSIS_TEST_TAGS", "create_file", "get_action", "get_arg") load("@bazel_skylib//lib:sets.bzl", "sets") load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") load(":assert_failure_test.bzl", "assert_failure_test") +load("//:visibility.bzl", "RULES_KOTLIN") _DEFAULT_LIST = ["__default__"] @@ -84,8 +85,17 @@ def _test_impl(ctx): actual[JavaInfo].plugins.processor_classes.to_list(), ) + kt_2_java_compile = get_action(actions, "Kt2JavaCompile") + + if kt_2_java_compile: + asserts.true( + env, + kt_2_java_compile.outputs.to_list()[0].basename.endswith(".jar"), + "Expected first output to be a JAR (this affects the param file name).", + ) + if ctx.attr.expected_friend_jar_names != _DEFAULT_LIST: - friend_paths_arg = get_action_arg(actions, "Kt2JavaCompile", "-Xfriend-paths=") + friend_paths_arg = get_arg(kt_2_java_compile, "-Xfriend-paths=") friend_jar_names = [p.rsplit("/", 1)[1] for p in friend_paths_arg.split(",")] if friend_paths_arg else [] asserts.set_equals(env, sets.make(ctx.attr.expected_friend_jar_names), sets.make(friend_jar_names)) diff --git a/tests/analysis/util.bzl b/tests/analysis/util.bzl index cec0cc3..5e7e487 100644 --- a/tests/analysis/util.bzl +++ b/tests/analysis/util.bzl @@ -14,6 +14,8 @@ """Some utils""" +load("//:visibility.bzl", "RULES_KOTLIN") + # Mark targets that's aren't expected to build, but are needed for analysis test assertions. ONLY_FOR_ANALYSIS_TEST_TAGS = ["manual", "nobuilder", "only_for_analysis_test"] @@ -35,23 +37,17 @@ EOF def _create_dir_impl(ctx): dir = ctx.actions.declare_directory(ctx.attr.name) - if ctx.files.srcs: - ctx.actions.run_shell( - command = "mkdir -p {0} && cp {1} {0}".format( - dir.path + "/" + ctx.attr.subdir, - " ".join([s.path for s in ctx.files.srcs]), - ), - inputs = ctx.files.srcs, - outputs = [dir], - ) - else: - ctx.actions.run_shell( - command = "mkdir -p {0}".format( - dir.path + "/" + ctx.attr.subdir, - ), - inputs = ctx.files.srcs, - outputs = [dir], - ) + + command = "mkdir -p {0} " + ("&& cp {1} {0}" if ctx.files.srcs else "# {1}") + ctx.actions.run_shell( + command = command.format( + dir.path + "/" + ctx.attr.subdir, + " ".join([s.path for s in ctx.files.srcs]), + ), + inputs = ctx.files.srcs, + outputs = [dir], + ) + return [DefaultInfo(files = depset([dir]))] _create_dir = rule( @@ -62,7 +58,10 @@ _create_dir = rule( ), ) -def create_dir(name, subdir, srcs): +def create_dir( + name, + subdir = None, + srcs = None): _create_dir( name = name, subdir = subdir, @@ -70,16 +69,15 @@ def create_dir(name, subdir, srcs): ) return name -def get_action_arg(actions, mnemonic, arg_name): - """Get a named arg from a specific action +def get_action(actions, mnemonic): + """Get a specific action Args: actions: [List[Action]] mnemonic: [string] Identify the action whose args to search - arg_name: [string] Returns: - [Optional[string]] The arg value, or None if it couldn't be found + [Optional[action]] The arg value, or None if it couldn't be found """ menmonic_actions = [a for a in actions if a.mnemonic == mnemonic] if len(menmonic_actions) == 0: @@ -87,8 +85,22 @@ def get_action_arg(actions, mnemonic, arg_name): elif len(menmonic_actions) > 1: fail("Expected a single '%s' action" % mnemonic) - mnemonic_action = menmonic_actions[0] - arg_values = [a for a in mnemonic_action.argv if a.startswith(arg_name)] + return menmonic_actions[0] + +def get_arg(action, arg_name): + """Get a named arg from a specific action + + Args: + action: [Optional[Action]] + arg_name: [string] + + Returns: + [Optional[string]] The arg value, or None if it couldn't be found + """ + if not action: + return None + + arg_values = [a for a in action.argv if a.startswith(arg_name)] if len(arg_values) == 0: return None elif len(arg_values) > 1: diff --git a/tests/jvm/java/functions/BUILD b/tests/jvm/java/functions/BUILD index 67c0e9e..677869f 100644 --- a/tests/jvm/java/functions/BUILD +++ b/tests/jvm/java/functions/BUILD @@ -13,7 +13,7 @@ # limitations under the License. # This package tests importing extension functions. -load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library") +load("//kotlin:rules.bzl", "kt_jvm_library") licenses(["notice"]) @@ -41,53 +41,34 @@ java_test( ], ) -java_import( - name = "car-jar", - jars = ["//tests/jvm/java/functions/car:car_lib-jar"], - tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, -) - kt_jvm_library( - name = "car_demo_jar_lib", + name = "car_demo_import_lib", srcs = ["CarDemo.kt"], tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, deps = [ - ":car-jar", + "//tests/jvm/java/functions/car:car_lib_import", ], ) # This binary includes extension functions defined in an separate jar file, which # may be problematic if the metadata is stripped by ijar. java_test( - name = "car_jar_demo", + name = "car_import_demo", main_class = "functions.CarDemo", - tags = ["darwin_x86_64_compatible"] + - _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, + tags = ["darwin_x86_64_compatible"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, runtime_deps = [ - ":car_demo_jar_lib", + ":car_demo_import_lib", "@kotlinc//:kotlin_stdlib", ], ) -kt_jvm_import( - name = "car-inline-jar", - jars = [ - "//tests/jvm/java/functions/car:car_inline_lib-jar", - "//tests/jvm/java/functions/car:car_extra_lib-jar", - ], - tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, - deps = [ - ":car-jar", - ], -) - kt_jvm_library( name = "car_demo_inline_lib", srcs = ["CarInlineDemo.kt"], tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, deps = [ - ":car-inline-jar", - ":car-jar", + "//tests/jvm/java/functions/car:car_inline_and_extra_lib_import", + "//tests/jvm/java/functions/car:car_lib_import", ], ) @@ -96,8 +77,7 @@ kt_jvm_library( java_test( name = "car_inline_demo", main_class = "functions.CarInlineDemo", - tags = ["darwin_x86_64_compatible"] + - _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, + tags = ["darwin_x86_64_compatible"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, runtime_deps = [ ":car_demo_inline_lib", "@kotlinc//:kotlin_stdlib", diff --git a/tests/jvm/java/functions/car/BUILD b/tests/jvm/java/functions/car/BUILD index 81f0f43..5417fd4 100644 --- a/tests/jvm/java/functions/car/BUILD +++ b/tests/jvm/java/functions/car/BUILD @@ -12,27 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("//kotlin:rules.bzl", "kt_jvm_library") +load("//kotlin:rules.bzl", "kt_jvm_import", "kt_jvm_library") package(default_visibility = ["//tests/jvm/java/functions:__subpackages__"]) licenses(["notice"]) -# Make Jar files produced by helper targets visible to tests in parent package -filegroup( - name = "car_lib-jar", - srcs = ["libcar_lib.jar"], -) - -filegroup( - name = "car_inline_lib-jar", - srcs = ["libcar_inline_lib.jar"], -) - -filegroup( - name = "car_extra_lib-jar", - srcs = ["libcar_extra_lib.jar"], -) +# During coverage builds, every library gets a dep on JaCoCo (Java Code Coverage). +# Libjars, from libraries, only include their direct sources. Together, these behaviours +# trigger an ImportDepsChecker error for :car-jar and :car-inline-jar. To prevent that, we disable +# coverage builds on all downstream targets. +_NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO = ["nozapfhahn"] kt_jvm_library( name = "car_lib", @@ -40,8 +30,12 @@ kt_jvm_library( "Car.kt", "CarUtils.kt", ], - deps = [ - ], +) + +java_import( + name = "car_lib_import", + jars = [":libcar_lib.jar"], + tags = ["incomplete-deps"] + _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, ) kt_jvm_library( @@ -49,6 +43,7 @@ kt_jvm_library( srcs = [ "CarInlineUtils.kt", ], + visibility = ["//visibility:private"], deps = [ ":car_lib", ], @@ -59,7 +54,20 @@ kt_jvm_library( srcs = [ "CarExtraUtils.kt", ], + visibility = ["//visibility:private"], deps = [ ":car_lib", ], ) + +kt_jvm_import( + name = "car_inline_and_extra_lib_import", + jars = [ + ":libcar_inline_lib.jar", + ":libcar_extra_lib.jar", + ], + tags = _NO_ZAPFHAHN_BECAUSE_LIBJARS_EXCLUDE_JACOCO, + deps = [ + ":car_lib_import", + ], +) diff --git a/kotlin/dex_aspects.bzl b/toolchains/kotlin_jvm/androidlint_toolchains.bzl index 3d2730b..b4c2208 100644 --- a/kotlin/dex_aspects.bzl +++ b/toolchains/kotlin_jvm/androidlint_toolchains.bzl @@ -12,25 +12,26 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""kt_dex_aspects""" +"""Android Lint toolchain for Kotlin.""" -# (b/259111128) Magic provider to get DexArchiveAspect to traverse into this rule -_TraverseMeInfo = platform_common.ToolchainInfo +load("//bazel:stubs.bzl", "lint_actions") +load("//:visibility.bzl", "RULES_KOTLIN") -_EXTRA_DEPS_ATTRS = dict( - _build_stamp_deps = attr.label_list( - doc = """ - (b/259111128) Magic attr to get DexArchiveAspect to traverse into this rule - """, +_ATTRS = dict( + _android_lint_baseline_file = attr.label( + allow_single_file = True, + cfg = "exec", ), ) -def _set_extra_deps_attrs(deps): - return {"$build_stamp_deps": deps} +def _set_baselines(): + return { + # `$foo` is used to set `_foo` + "$android_lint_baseline_file": lint_actions.get_android_lint_baseline_file(native.package_name()), + } -kt_dex_aspects = struct( - TraverseMeInfo = _TraverseMeInfo, - TRAVERSE_ME_INFO = _TraverseMeInfo(), - extra_deps_attrs = _EXTRA_DEPS_ATTRS, - set_extra_deps_attrs = _set_extra_deps_attrs, +androidlint_toolchains = struct( + attrs = _ATTRS, + get_baseline = lambda ctx: getattr(ctx.file, "_android_lint_baseline_file", None), + set_baselines = _set_baselines, ) diff --git a/toolchains/kotlin_jvm/java_toolchains.bzl b/toolchains/kotlin_jvm/java_toolchains.bzl index 63dec4e..74095de 100644 --- a/toolchains/kotlin_jvm/java_toolchains.bzl +++ b/toolchains/kotlin_jvm/java_toolchains.bzl @@ -14,6 +14,8 @@ """Java toolchain for Kotlin.""" +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") + _ATTRS = dict( _java_toolchain = attr.label( default = Label( diff --git a/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl index cc73d81..41fb769 100644 --- a/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl +++ b/toolchains/kotlin_jvm/kt_jvm_toolchains.bzl @@ -14,14 +14,15 @@ """Kotlin toolchain.""" -load("//bazel:stubs.bzl", "select_java_language_version") +load("//bazel:stubs.bzl", "select_java_language_level") +load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") # Work around to toolchains in Google3. KtJvmToolchainInfo = provider() -KT_VERSION = "v1_7_21" +KT_VERSION = "v1_8_10" -KT_LANG_VERSION = "1.7" +KT_LANG_VERSION = "1.8" # Kotlin JVM toolchain type label _TYPE = Label("//toolchains/kotlin_jvm:kt_jvm_toolchain_type") @@ -78,6 +79,12 @@ def _kotlinc_common_flags(ctx, other_flags): # Allows a no source files to create an empty jar. "-Xallow-no-source-files", + + # TODO: Remove this flag + "-Xuse-old-innerclasses-logic", + + # TODO: Remove this flag + "-Xno-source-debug-extension", ] + other_flags # --define=extra_kt_jvm_opts is for overriding from command line. @@ -98,11 +105,15 @@ def _kotlinc_cli_flags(ctx): def _kt_jvm_toolchain_impl(ctx): kt_jvm_toolchain = dict( + android_java8_apis_desugared = ctx.attr.android_java8_apis_desugared, + android_lint_config = ctx.file.android_lint_config, + android_lint_runner = ctx.attr.android_lint_runner[DefaultInfo].files_to_run, build_marker = ctx.file.build_marker, coverage_instrumenter = ctx.attr.coverage_instrumenter[DefaultInfo].files_to_run, # Don't require JavaInfo provider for integration test convenience. coverage_runtime = ctx.attr.coverage_runtime[JavaInfo] if JavaInfo in ctx.attr.coverage_runtime else None, genclass = ctx.file.genclass, + header_gen_tool = ctx.attr.header_gen_tool[DefaultInfo].files_to_run if ctx.attr.header_gen_tool else None, jar_tool = ctx.attr.jar_tool[DefaultInfo].files_to_run, java_language_version = ctx.attr.java_language_version, java_runtime = ctx.attr.java_runtime, @@ -129,6 +140,20 @@ def _kt_jvm_toolchain_impl(ctx): kt_jvm_toolchain = rule( attrs = dict( + android_java8_apis_desugared = attr.bool( + # Reflects a select in build rules. + doc = "Whether Java 8 API desugaring is enabled", + mandatory = True, + ), + android_lint_config = attr.label( + cfg = "exec", + allow_single_file = [".xml"], + ), + android_lint_runner = attr.label( + default = "//bazel:stub_tool", + executable = True, + cfg = "exec", + ), build_marker = attr.label( default = "//tools:build_marker", allow_single_file = [".jar"], @@ -151,6 +176,11 @@ kt_jvm_toolchain = rule( cfg = "exec", allow_single_file = True, ), + header_gen_tool = attr.label( + executable = True, + allow_single_file = True, + cfg = "exec", + ), jar_tool = attr.label( default = "@bazel_tools//tools/jdk:jar", executable = True, @@ -200,8 +230,6 @@ kt_jvm_toolchain = rule( default = [ "@kotlinc//:kotlin_reflect", "@kotlinc//:kotlin_stdlib", - "@kotlinc//:kotlin_stdlib_jdk7", - "@kotlinc//:kotlin_stdlib_jdk8", "@kotlinc//:kotlin_test_not_testonly", ], cfg = "target", @@ -250,13 +278,12 @@ kt_jvm_toolchain = rule( def _declare(**kwargs): kt_jvm_toolchain( - # TODO: use select_java_language_level() after support for Java 8 is dropped - jvm_target = select_java_language_version( - # The JVM bytecode version to output - java8 = "1.8", - java11 = "11", - java_head = "18", # https://kotlinlang.org/docs/compiler-reference.html#jvm-target-version - ), + android_java8_apis_desugared = select({ + "//conditions:default": False, + }), + # The JVM bytecode version to output + # https://kotlinlang.org/docs/compiler-reference.html#jvm-target-version + jvm_target = "11", **kwargs ) diff --git a/tools/bin/source_jar_zipper_deploy.jar b/tools/bin/source_jar_zipper_deploy.jar Binary files differindex 5f283fe..8c6309e 100755 --- a/tools/bin/source_jar_zipper_deploy.jar +++ b/tools/bin/source_jar_zipper_deploy.jar diff --git a/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt b/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt index ac57efe..c2d34d8 100644 --- a/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt +++ b/tools/java/com/google/devtools/kotlin/SourceJarZipper.kt @@ -52,15 +52,16 @@ fun main(args: Array<String>) { } /** - * Checks for duplicates and add an entry into [errors] if found any, otherwise adds a pair - * of [zipPath] and [sourcePath] to the receiver - * @receiver a mutable map of path to path, where keys are relative paths of files inside the - * resulting .jar, and values are full paths of files - * @param[zipPath] relative path inside the jar, built either from package name - * (e.g. package com.google.foo -> com/google/foo/FileName.kt) or by resolving the file name - * relatively the directory it came from (e.g. foo/bar/1/2.txt came from foo/bar -> 1/2.txt) + * Checks for duplicates and adds an entry into [errors] if one is found, otherwise adds a pair of + * [zipPath] and [sourcePath] to the receiver + * + * @param[zipPath] relative path inside the jar, built either from package name (e.g. package + * com.google.foo -> com/google/foo/FileName.kt) or by resolving the file name relative to the + * directory it came from (e.g. foo/bar/1/2.txt came from foo/bar -> 1/2.txt) * @param[sourcePath] full path of file into its file system * @param[errors] list of strings describing catched errors + * @receiver a mutable map of path to path, where keys are relative paths of files inside the + * resulting .jar, and values are full paths of files */ fun MutableMap<Path, Path>.checkForDuplicatesAndSetFilePathToPathInsideJar( zipPath: Path, @@ -78,6 +79,12 @@ fun MutableMap<Path, Path>.checkForDuplicatesAndSetFilePathToPathInsideJar( } } +private fun clearSingletonEmptyPath(list: MutableList<Path>) { + if (list.size == 1 && list[0].toString() == "") { + list.clear() + } +} + fun MutableMap<Path, Path>.writeToStream( zipper: ZipOutputStream, prefix: String = "", @@ -124,9 +131,8 @@ class Zip : Runnable { } override fun run() { - check(kotlinSrcs.isNotEmpty() or commonSrcs.isNotEmpty()) { - "Expected at least one source file." - } + clearSingletonEmptyPath(kotlinSrcs) + clearSingletonEmptyPath(commonSrcs) // Validating files and getting paths for resulting .jar in one cycle // for each _srcs list @@ -188,9 +194,6 @@ class Zip : Runnable { } } - if (ktZipPathToSourcePath.isEmpty() && commonZipPathToSourcePath.isEmpty()) { - errors.add("Expected at least one valid source file .kt or .java") - } check(errors.isEmpty()) { errors.joinToString("\n") } ZipOutputStream(BufferedOutputStream(Files.newOutputStream(outputJar))).use { zipper -> @@ -243,6 +246,8 @@ class ZipResources : Runnable { val inputDirs = mutableListOf<Path>() override fun run() { + clearSingletonEmptyPath(inputDirs) + val filePathToOutputPath = mutableMapOf<Path, Path>() val errors = mutableListOf<String>() diff --git a/visibility.bzl b/visibility.bzl new file mode 100644 index 0000000..328e2e5 --- /dev/null +++ b/visibility.bzl @@ -0,0 +1,25 @@ +# Copyright 2022 Google LLC. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the License); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Bzl visibility lists for rules_kotlin""" + +RULES_KOTLIN = ["//..."] + +TOOLS_KOTLIN = [ +] + +# bzl files in these packages have access to internal parts of rules_kotlin, so think carefully +# before expanding the list. +RULES_DEFS_THAT_COMPILE_KOTLIN = RULES_KOTLIN + [ +] |