Use internal kotlin gen rule
diff --git a/BUILD b/BUILD
index 27ee9e5..887e5e3 100644
--- a/BUILD
+++ b/BUILD
@@ -146,6 +146,7 @@
     "adapt_proto_library",
     "cc_proto_library",
     "internal_copied_filegroup",
+    "internal_gen_kt_protos",
     "internal_gen_well_known_protos_java",
     "internal_protobuf_py_tests",
     "py_proto_library",
@@ -891,6 +892,23 @@
     deps = [proto + "_proto" for proto in LITE_WELL_KNOWN_PROTO_MAP.keys()],
 )
 
+internal_gen_kt_protos(
+    name = "gen_well_known_protos_kotlin",
+    visibility = [
+        "//java:__subpackages__",
+    ],
+    deps = [proto + "_proto" for proto in WELL_KNOWN_PROTO_MAP.keys()],
+)
+
+internal_gen_kt_protos(
+    name = "gen_well_known_protos_kotlinlite",
+    visibility = [
+        "//java:__subpackages__",
+    ],
+    lite = True,
+    deps = [proto + "_proto" for proto in LITE_WELL_KNOWN_PROTO_MAP.keys()],
+)
+
 alias(
     name = "protobuf_java",
     actual = "//java/core",
@@ -1428,159 +1446,60 @@
 
 # Kotlin proto rules
 
-genrule(
-    name = "gen_kotlin_unittest_lite",
+proto_library(
+    name = "kt_unittest_lite",
     srcs = [
         "src/google/protobuf/unittest_lite.proto",
         "src/google/protobuf/unittest_import_lite.proto",
         "src/google/protobuf/unittest_import_public_lite.proto",
         "src/google/protobuf/map_lite_unittest.proto",
     ],
-    outs = [
-        "TestAllTypesLiteKt.kt",
-        "ForeignMessageLiteKt.kt",
-        "TestAllExtensionsLiteKt.kt",
-        "TestEmptyMessageLiteKt.kt",
-        "TestEmptyMessageWithExtensionsLiteKt.kt",
-        "TestMapLiteKt.kt",
-        "OptionalGroup_extension_liteKt.kt",
-        "RepeatedGroup_extension_liteKt.kt",
-    ],
-    visibility = ["//java:__subpackages__"],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) -Isrc/ " +
-          "$(locations src/google/protobuf/unittest_lite.proto) && " +
-          "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) -Isrc/ " +
-          "$(locations src/google/protobuf/map_lite_unittest.proto) && " +
-          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
-          "$(location TestAllTypesLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/ForeignMessageLiteKt.kt " +
-          "$(location ForeignMessageLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/TestAllExtensionsLiteKt.kt " +
-          "$(location TestAllExtensionsLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/TestAllTypesLiteKt.kt " +
-          "$(location TestAllTypesLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/TestEmptyMessageLiteKt.kt " +
-          "$(location TestEmptyMessageLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/TestEmptyMessageWithExtensionsLiteKt.kt " +
-          "$(location TestEmptyMessageWithExtensionsLiteKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestMapLiteKt.kt " +
-          "$(location TestMapLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/OptionalGroup_extension_liteKt.kt " +
-          "$(location OptionalGroup_extension_liteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/RepeatedGroup_extension_liteKt.kt " +
-          "$(location RepeatedGroup_extension_liteKt.kt)",
-    tools = [":protoc"],
+    strip_import_prefix = "src",
 )
 
-genrule(
-    name = "gen_kotlin_unittest",
+internal_gen_kt_protos(
+    name = "gen_kotlin_unittest_lite",
+    deps = [":kt_unittest_lite"],
+    lite = True,
+    visibility = ["//java:__subpackages__"],
+)
+
+proto_library(
+    name = "kt_unittest",
     srcs = [
         "src/google/protobuf/unittest.proto",
         "src/google/protobuf/unittest_import.proto",
         "src/google/protobuf/unittest_import_public.proto",
         "src/google/protobuf/map_proto2_unittest.proto",
     ],
-    outs = [
-        "TestAllTypesKt.kt",
-        "ForeignMessageKt.kt",
-        "Int32MessageKt.kt",
-        "TestAllExtensionsKt.kt",
-        "TestEmptyMessageKt.kt",
-        "TestEmptyMessageWithExtensionsKt.kt",
-        "TestIntIntMapKt.kt",
-        "TestEnumMapKt.kt",
-        "TestMapsKt.kt",
-        "OptionalGroup_extensionKt.kt",
-        "RepeatedGroup_extensionKt.kt",
-    ],
-    visibility = ["//java:__subpackages__"],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
-          "$(location src/google/protobuf/unittest.proto) && " +
-          "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " + 
-          "$(location src/google/protobuf/map_proto2_unittest.proto) && " +
-          "cp $(@D)/protobuf_unittest/TestAllTypesKt.kt " +
-          "$(location TestAllTypesKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/ForeignMessageKt.kt " +
-          "$(location ForeignMessageKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/Int32MessageKt.kt " +
-          "$(location Int32MessageKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestAllExtensionsKt.kt " +
-          "$(location TestAllExtensionsKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestEmptyMessageKt.kt " +
-          "$(location TestEmptyMessageKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestEmptyMessageWithExtensionsKt.kt " +
-          "$(location TestEmptyMessageWithExtensionsKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestIntIntMapKt.kt " +
-          "$(location TestIntIntMapKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestEnumMapKt.kt " +
-          "$(location TestEnumMapKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/TestMapsKt.kt " +
-          "$(location TestMapsKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/OptionalGroup_extensionKt.kt " +
-          "$(location OptionalGroup_extensionKt.kt) && " +
-          "cp $(@D)/protobuf_unittest/RepeatedGroup_extensionKt.kt " +
-          "$(location RepeatedGroup_extensionKt.kt)",
-    tools = ["//:protoc"],
+    strip_import_prefix = "src",
 )
 
-genrule(
+internal_gen_kt_protos(
+    name = "gen_kotlin_unittest",
+    deps = [":kt_unittest"],
+    visibility = ["//java:__subpackages__"],
+)
+
+proto_library(
+    name = "kt_proto3_unittest",
+    srcs = [
+        "src/google/protobuf/unittest_proto3.proto",
+        "src/google/protobuf/unittest_import.proto",
+        "src/google/protobuf/unittest_import_public.proto",
+    ],
+    strip_import_prefix = "src",
+)
+
+internal_gen_kt_protos(
     name = "gen_kotlin_proto3_unittest_lite",
-    srcs = [
-        "src/google/protobuf/unittest_proto3.proto",
-        "src/google/protobuf/unittest_import.proto",
-        "src/google/protobuf/unittest_import_public.proto",
-    ],
-    outs = [
-        "TestAllTypesProto3LiteKt.kt",
-        "TestEmptyMessageProto3LiteKt.kt",
-    ],
+    deps = [":kt_proto3_unittest"],
+    lite = True,
     visibility = ["//java:__subpackages__"],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) -Isrc/ " +
-          "$(location src/google/protobuf/unittest_proto3.proto) && " +
-          "cp $(@D)/proto3_unittest/TestAllTypesKt.kt " +
-          "$(location TestAllTypesProto3LiteKt.kt) && " +
-          "cp $(@D)/proto3_unittest/TestEmptyMessageKt.kt " +
-          "$(location TestEmptyMessageProto3LiteKt.kt)",
-    tools = ["//:protoc"],
 )
 
-genrule(
+internal_gen_kt_protos(
     name = "gen_kotlin_proto3_unittest",
-    srcs = [
-        "src/google/protobuf/unittest_proto3.proto",
-        "src/google/protobuf/unittest_import.proto",
-        "src/google/protobuf/unittest_import_public.proto",
-    ],
-    outs = [
-        "TestAllTypesProto3Kt.kt",
-        "TestEmptyMessageProto3Kt.kt",
-    ],
+    deps = [":kt_proto3_unittest"],
     visibility = ["//java:__subpackages__"],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
-          "$(location src/google/protobuf/unittest_proto3.proto) && " +
-          "cp $(@D)/proto3_unittest/TestAllTypesKt.kt " +
-          "$(location TestAllTypesProto3Kt.kt) && " +
-          "cp $(@D)/proto3_unittest/TestEmptyMessageKt.kt " +
-          "$(location TestEmptyMessageProto3Kt.kt)",
-    tools = ["//:protoc"],
 )
-
-genrule(
-  name = "gen_kotlin_any",
-  srcs = ["src/google/protobuf/any.proto"],
-  outs = ["AnyKt.kt"],
-  visibility = ["//java:__subpackages__"],
-  cmd = "$(location //:protoc) " +
-        "--kotlin_out=shared,immutable:$(@D) -Isrc/ " +
-        "$(location src/google/protobuf/any.proto) && " +
-        "cp $(@D)/com/google/protobuf/AnyKt.kt " +
-        "$(location AnyKt.kt)",
-  tools = ["//:protoc"],
-)
-
diff --git a/java/kotlin-lite/BUILD b/java/kotlin-lite/BUILD
index 0d1694c..a41584a 100644
--- a/java/kotlin-lite/BUILD
+++ b/java/kotlin-lite/BUILD
@@ -1,5 +1,6 @@
 load("@io_bazel_rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
 load("@rules_java//java:defs.bzl", "java_lite_proto_library")
+load("//:protobuf.bzl", "internal_gen_kt_protos")
 
 java_lite_proto_library(
     name = "example_extensible_message_java_proto_lite",
@@ -47,74 +48,31 @@
     deps = ["//java/kotlin:evil_names_proto2"],
 )
 
+internal_gen_kt_protos(
+    name = "gen_evil_names_proto2_lite",
+    deps = ["//java/kotlin:evil_names_proto2"],
+    lite = True,
+)
+
 java_lite_proto_library(
     name = "evil_names_proto3_java_proto_lite",
     deps = ["//java/kotlin:evil_names_proto3"],
 )
 
+internal_gen_kt_protos(
+    name = "gen_evil_names_proto3_lite",
+    deps = ["//java/kotlin:evil_names_proto3"],
+    lite = True,
+)
+
 java_lite_proto_library(
     name = "multiple_files_proto3_java_proto_lite",
     deps = ["//java/kotlin:multiple_files_proto3"],
 )
 
-genrule(
+internal_gen_kt_protos(
     name = "gen_kotlin_proto3_java_multiple_files_lite",
-    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
-    outs = [
-        "MultipleFilesMessageALiteKt.kt",
-        "MultipleFilesMessageBLiteKt.kt",
-        "MultipleFilesProto3LiteKt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
-          "$(location MultipleFilesMessageALiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
-          "$(location MultipleFilesMessageBLiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
-          "$(location MultipleFilesProto3LiteKt.kt)",
-    tools = ["//:protoc"],
-)
-
-genrule(
-    name = "gen_evil_names_proto2_lite",
-    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
-    outs = [
-        "EvilNamesProto2LiteKt.kt",
-        "HardKeywordsAllTypesProto2LiteKt.kt",
-        "InterfaceKt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
-          "$(location EvilNamesProto2LiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
-          "$(location HardKeywordsAllTypesProto2LiteKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
-          "$(location InterfaceKt.kt)",
-    tools = ["//:protoc"],
-)
-
-genrule(
-    name = "gen_evil_names_proto3_lite",
-    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
-    outs = [
-        "ClassKt.kt",
-        "EvilNamesProto3Kt.kt",
-        "HardKeywordsAllTypesProto3Kt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=lite:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
-          "$(location ClassKt.kt) && " + 
-          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
-          "$(location EvilNamesProto3Kt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
-          "$(location HardKeywordsAllTypesProto3Kt.kt)",
-    tools = ["//:protoc"],
+    deps = ["//java/kotlin:multiple_files_proto3"],
 )
 
 kt_jvm_library(
diff --git a/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto
deleted file mode 100644
index 3735baf..0000000
--- a/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto2.proto
+++ /dev/null
@@ -1,93 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// LINT: LEGACY_NAMES
-syntax = "proto2";
-
-package protobuf.kotlin.generator;
-
-option java_package = "com.google.protobuf.kotlin.generator";
-
-message EvilNamesProto2 {
-  optional bool initialized = 1;
-  optional bool has_foo = 2;
-  optional string Bar = 3;
-  optional bool is_initialized = 4;
-
-  oneof camelCase {
-    string fooBar = 5;
-  }
-
-  repeated string ALL_CAPS = 7;
-  map<int32, bool> ALL_CAPS_MAP = 8;
-
-  optional bool has_underbar_preceding_numeric_1foo = 9;
-  optional bool has_underbar_preceding_numeric_42bar = 13;
-  optional bool has_underbar_preceding_numeric_123foo42bar_baz = 14;
-
-  extensions 100 to max;
-
-  repeated string extension = 12;
-  repeated int32 class = 15;
-  optional double int = 16;
-  optional bool long = 17;
-  optional int64 boolean = 18;
-  optional string sealed = 19;
-  optional float interface = 20;
-  optional int32 in = 21;
-  optional string object = 22;
-  optional string cached_size = 23;
-  optional bool serialized_size = 24;
-  optional string by = 25;
-}
-
-message HardKeywordsAllTypesProto2 {
-  message NestedMessage {
-    optional int32 while = 1;
-  }
-
-  enum NestedEnum {
-    FOO = 1;
-    BAR = 2;
-  }
-
-  optional int32 as = 1;
-  optional string in = 2;
-  optional NestedEnum break = 3;
-  map<int32, int32> continue = 4;
-  optional NestedMessage do = 5;
-
-  repeated int32 else = 6;
-  repeated string for = 7;
-  repeated NestedEnum fun = 8;
-  repeated NestedMessage if = 9;
-}
-
-message Interface {}
diff --git a/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto
deleted file mode 100644
index f6b06d3..0000000
--- a/java/kotlin-lite/src/test/proto/com/google/protobuf/evil_names_proto3.proto
+++ /dev/null
@@ -1,107 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// LINT: LEGACY_NAMES
-syntax = "proto3";
-
-package protobuf.kotlin.generator;
-
-option java_package = "com.google.protobuf.kotlin.generator";
-
-message EvilNamesProto3 {
-  bool initialized = 1;
-  bool has_foo = 2;
-  string Bar = 3;
-  bool is_initialized = 4;
-
-  oneof camelCase {
-    string fooBar = 5;
-  }
-
-  repeated string ALL_CAPS = 7;
-  map<int32, bool> ALL_CAPS_MAP = 8;
-
-  bool has_underbar_preceding_numeric_1foo = 9;
-  bool has_underbar_preceding_numeric_42bar = 10;
-  bool has_underbar_preceding_numeric_123foo42bar_baz = 11;
-
-  repeated string extension = 12;
-
-  string class = 13;
-  double int = 14;
-  bool long = 15;
-  int64 boolean = 16;
-  string sealed = 17;
-  float interface = 18;
-  int32 in = 19;
-  string object = 20;
-  string cached_size = 21;
-  bool serialized_size = 22;
-  string value = 23;
-  int64 index = 24;
-  repeated string values = 25;
-  repeated string new_values = 26;
-  bool builder = 27;
-  map<int32, int32> k = 28;
-  map<string, string> v = 29;
-  map<string, int32> key = 30;
-  map<int32, string> map = 31;
-  map<string, int32> pairs = 32;
-
-  string _leading_underscore = 33;
-  oneof _leading_underscore_oneof {
-    int32 option = 34;
-  }
-}
-
-message HardKeywordsAllTypesProto3 {
-  message NestedMessage {
-    optional int32 while = 1;
-  }
-
-  enum NestedEnum {
-    ZERO = 0;
-    FOO = 1;
-    BAR = 2;
-  }
-
-  optional int32 as = 1;
-  optional string in = 2;
-  optional NestedEnum break = 3;
-  map<int32, int32> continue = 4;
-  optional NestedMessage do = 5;
-
-  repeated int32 else = 6;
-  repeated string for = 7;
-  repeated NestedEnum fun = 8;
-  repeated NestedMessage if = 9;
-}
-
-message Class {}
diff --git a/java/kotlin-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto b/java/kotlin-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
deleted file mode 100644
index 61141c5..0000000
--- a/java/kotlin-lite/src/test/proto/com/google/protobuf/multiple_files_proto3.proto
+++ /dev/null
@@ -1,42 +0,0 @@
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-syntax = "proto3";
-
-package protobuf.kotlin.generator;
-
-option java_package = "com.google.protobuf.kotlin.generator";
-option java_multiple_files = true;
-
-enum NestedEnum { FOO = 0; }
-
-message MultipleFilesMessageA {}
-
-message MultipleFilesMessageB {}
diff --git a/java/kotlin/BUILD b/java/kotlin/BUILD
index 0cb27e5..b4bdf73 100644
--- a/java/kotlin/BUILD
+++ b/java/kotlin/BUILD
@@ -2,6 +2,7 @@
 load("@rules_java//java:defs.bzl", "java_proto_library")
 load("@rules_proto//proto:defs.bzl", "proto_library")
 load("//:protobuf_version.bzl", "PROTOBUF_VERSION")
+load("//:protobuf.bzl", "internal_gen_kt_protos")
 
 exports_files([
   "src/test/kotlin/com/google/protobuf/Proto3Test.kt",
@@ -142,6 +143,16 @@
     visibility = ["//:__subpackages__"],
 )
 
+java_proto_library(
+    name = "evil_names_proto2_java_proto",
+    deps = [":evil_names_proto2"],
+)
+
+internal_gen_kt_protos(
+    name = "gen_evil_names_proto2",
+    deps = [":evil_names_proto2"],
+)
+
 proto_library(
     name = "evil_names_proto3",
     srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
@@ -149,12 +160,12 @@
 )
 
 java_proto_library(
-    name = "evil_names_proto2_java_proto",
-    deps = [":evil_names_proto2"],
+    name = "evil_names_proto3_java_proto",
+    deps = [":evil_names_proto3"],
 )
 
-java_proto_library(
-    name = "evil_names_proto3_java_proto",
+internal_gen_kt_protos(
+    name = "gen_evil_names_proto3",
     deps = [":evil_names_proto3"],
 )
 
@@ -164,75 +175,20 @@
     visibility = ["//:__subpackages__"],
 )
 
-java_proto_library( name = "multiple_files_proto3_java_proto",
+java_proto_library(
+    name = "multiple_files_proto3_java_proto",
     deps = [":multiple_files_proto3"],
 )
 
-genrule(
+internal_gen_kt_protos(
     name = "gen_kotlin_proto3_java_multiple_files",
-    srcs = ["src/test/proto/com/google/protobuf/multiple_files_proto3.proto"],
-    outs = [
-        "MultipleFilesMessageAKt.kt",
-        "MultipleFilesMessageBKt.kt",
-        "MultipleFilesProto3Kt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/multiple_files_proto3.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageAKt.kt " +
-          "$(location MultipleFilesMessageAKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesMessageBKt.kt " +
-          "$(location MultipleFilesMessageBKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/MultipleFilesProto3Kt.kt " +
-          "$(location MultipleFilesProto3Kt.kt)",
-    tools = ["//:protoc"],
-)
-
-genrule(
-    name = "gen_evil_names_proto2",
-    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto2.proto"],
-    outs = [
-        "EvilNamesProto2Kt.kt",
-        "HardKeywordsAllTypesProto2Kt.kt",
-        "InterfaceKt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/evil_names_proto2.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto2Kt.kt " +
-          "$(location EvilNamesProto2Kt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto2Kt.kt " +
-          "$(location HardKeywordsAllTypesProto2Kt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/InterfaceKt.kt " +
-          "$(location InterfaceKt.kt)",
-    tools = ["//:protoc"],
-)
-
-genrule(
-    name = "gen_evil_names_proto3",
-    srcs = ["src/test/proto/com/google/protobuf/evil_names_proto3.proto"],
-    outs = [
-        "ClassKt.kt",
-        "EvilNamesProto3Kt.kt",
-        "HardKeywordsAllTypesProto3Kt.kt",
-    ],
-    cmd = "$(location //:protoc) " +
-          "--kotlin_out=shared,immutable:$(@D) " +
-          "$(location src/test/proto/com/google/protobuf/evil_names_proto3.proto) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/ClassKt.kt " +
-          "$(location ClassKt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/EvilNamesProto3Kt.kt " +
-          "$(location EvilNamesProto3Kt.kt) && " +
-          "cp $(@D)/com/google/protobuf/kotlin/generator/HardKeywordsAllTypesProto3Kt.kt " +
-          "$(location HardKeywordsAllTypesProto3Kt.kt)",
-    tools = ["//:protoc"],
+    deps = [":multiple_files_proto3"],
 )
 
 kt_jvm_library(
     name = "kotlin_unittest",
     srcs = [
         ":gen_evil_names_proto2",
-        "//:gen_kotlin_any",
         "//:gen_kotlin_unittest",
     ],
     deps = [
@@ -240,6 +196,7 @@
         "//java/core:core",
         ":only_for_use_in_proto_generated_code_its_generator_and_tests",
         ":shared_runtime",
+        ":well_known_protos_kotlin",
         "//:java_test_protos",
     ],
 )
@@ -294,3 +251,15 @@
     runtime_deps = [":proto3_test_library"],
     test_class = "com.google.protobuf.kotlin.Proto3Test",
 )
+
+kt_jvm_library(
+    name = "well_known_protos_kotlin",
+    srcs = [
+        "//:gen_well_known_protos_kotlin",
+    ],
+    deps = [
+         "//java/core",
+         ":only_for_use_in_proto_generated_code_its_generator_and_tests",
+         ":shared_runtime",
+    ],
+)
diff --git a/protobuf.bzl b/protobuf.bzl
index 826b610..ffd7c8d 100644
--- a/protobuf.bzl
+++ b/protobuf.bzl
@@ -391,6 +391,70 @@
     },
 )
 
+def _internal_gen_kt_protos(ctx):
+    args = ctx.actions.args()
+
+    deps = [d[ProtoInfo] for d in ctx.attr.deps]
+
+    srcjar = ctx.actions.declare_file("{}.srcjar".format(ctx.attr.name))
+    if ctx.attr.lite:
+        out = "lite:%s" % srcjar.path
+    else:
+        out = srcjar
+
+    args.add("--kotlin_out", out)
+
+    descriptors = depset(
+        transitive = [dep.transitive_descriptor_sets for dep in deps],
+    )
+    args.add_joined(
+        "--descriptor_set_in",
+        descriptors,
+        join_with = ctx.configuration.host_path_separator,
+    )
+
+    for dep in deps:
+        if "." == dep.proto_source_root:
+            args.add_all([src.path for src in dep.direct_sources])
+        else:
+            source_root = dep.proto_source_root
+            offset = len(source_root) + 1  # + '/'.
+            args.add_all([src.path[offset:] for src in dep.direct_sources])
+
+    ctx.actions.run(
+        executable = ctx.executable._protoc,
+        inputs = descriptors,
+        outputs = [srcjar],
+        arguments = [args],
+        use_default_shell_env = True,
+    )
+
+    return [
+        DefaultInfo(
+            files = depset([srcjar]),
+        ),
+    ]
+
+internal_gen_kt_protos = rule(
+    implementation = _internal_gen_kt_protos,
+    attrs = {
+        "deps": attr.label_list(
+            mandatory = True,
+            providers = [ProtoInfo],
+        ),
+        "lite": attr.bool(
+            default = False,
+        ),
+        "_protoc": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "//:protoc",
+        ),
+    },
+)
+
+
+
 def internal_copied_filegroup(name, srcs, strip_prefix, dest, **kwargs):
     """Macro to copy files to a different directory and then create a filegroup.