Move to proto_common for all upb aspects to fix numerous tricky edge cases and simplify the code

PiperOrigin-RevId: 527937369
diff --git a/.github/workflows/bazel_tests.yml b/.github/workflows/bazel_tests.yml
index 732bdea..76cdf27 100644
--- a/.github/workflows/bazel_tests.yml
+++ b/.github/workflows/bazel_tests.yml
@@ -30,8 +30,8 @@
           - { NAME: "macOS", BAZEL: bazel, CC: clang, os: macos-11 }
           - { NAME: "Windows", BAZEL: bazel, os: windows-2019, startup-flags: "--output_user_root=C:/tmp", flags: "--config=cpp17_msvc", targets: "upb/... upbc/... python/... protos/... protos_generator/..." }
           # We support two Bazel versions back per https://opensource.google/documentation/policies/cplusplus-support
+          - { NAME: "Bazel 4.1.0", BAZEL: bazel-4.1.0-linux-x86_64, CC: clang, os: ubuntu-20-large }
           - { NAME: "Bazel 5.3.0", BAZEL: bazel-5.3.0-linux-x86_64, CC: clang, os: ubuntu-20-large }
-          - { NAME: "Bazel 6.1.1", BAZEL: bazel-6.1.1-linux-x86_64, CC: clang, os: ubuntu-20-large }
 
     name: ${{ matrix.NAME }}
 
@@ -52,10 +52,10 @@
              wget -O $FILENAME https://github.com/bazelbuild/bazel/releases/download/$VERSION/${{ matrix.BAZEL }}
              chmod a+x $FILENAME
         if: ${{ matrix.BAZEL != 'bazel' }}
-      - name: Check compiler version
+      - name: Check compiler versions
         if: matrix.CC
         run: ${{ matrix.CC }} --version
-      - name: Check Bazel version
+      - name: Check Bazel versions
         run: ${{ matrix.BAZEL }} --version
       - id: bazel-cache
         name: Set up Bazel caching
diff --git a/.github/workflows/python_tests.yml b/.github/workflows/python_tests.yml
index 8f05f09..a847b31 100644
--- a/.github/workflows/python_tests.yml
+++ b/.github/workflows/python_tests.yml
@@ -29,9 +29,6 @@
           export_environment_variables: true
       - name: Use gcloud CLI
         run: gcloud info
-      - name: Check compiler version
-        if: matrix.CC
-        run: ${{ matrix.CC }} --version
       - name: Configure Docker
         run: gcloud auth configure-docker -q us-docker.pkg.dev
       - name: Pull Docker Image
diff --git a/WORKSPACE b/WORKSPACE
index 00907db..a9dd267 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -56,14 +56,12 @@
 )
 
 load("@com_google_googletest//:googletest_deps.bzl", "googletest_deps")
+
 googletest_deps()
 
 load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies")
-rules_pkg_dependencies()
 
-load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains")
-rules_proto_dependencies()
-rules_proto_toolchains()
+rules_pkg_dependencies()
 
 load("//bazel:system_python.bzl", "system_python")
 system_python(
diff --git a/bazel/BUILD b/bazel/BUILD
index ead4e50..3fc1d98 100644
--- a/bazel/BUILD
+++ b/bazel/BUILD
@@ -47,21 +47,12 @@
 )
 
 bzl_library(
-    name = "proto_common_wrapper_bzl",
-    srcs = ["proto_common_wrapper.bzl"],
-    visibility = ["//protos/bazel:__pkg__"],
-    deps = [
-        "@rules_proto//proto:defs",
-    ],
-)
-
-bzl_library(
     name = "upb_proto_library_bzl",
     srcs = ["upb_proto_library.bzl"],
     visibility = ["//visibility:public"],
     deps = [
-        ":proto_common_wrapper_bzl",
-        "@rules_proto//proto:defs",
+        "@bazel_skylib//lib:paths",
         "@bazel_tools//tools/cpp:toolchain_utils.bzl",
+        "@rules_proto//proto:defs",
     ],
 )
diff --git a/bazel/proto_common_wrapper.bzl b/bazel/proto_common_wrapper.bzl
deleted file mode 100644
index 0383b78..0000000
--- a/bazel/proto_common_wrapper.bzl
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (c) 2023, Google LLC
-# All rights reserved.
-#
-# 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 LLC 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 Google LLC 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.
-
-"""A wrapper around proto_common.compile() that fixes some surprising behaviors.
-
-More info in: https://github.com/bazelbuild/bazel/issues/18263
-"""
-
-load("@rules_proto//proto:defs.bzl", "proto_common")
-
-def output_dir(ctx, proto_info):
-    """Returns the output directory where generated proto files will be placed.
-
-    Args:
-      ctx: Rule context.
-      proto_info: ProtoInfo provider.
-
-    Returns:
-      A string specifying the output directory
-    """
-    proto_root = proto_info.proto_source_root
-    if proto_root.startswith(ctx.bin_dir.path):
-        path = proto_root
-    else:
-        path = ctx.bin_dir.path + "/" + proto_root
-
-    if proto_root == ".":
-        path = ctx.bin_dir.path
-    return path
-
-def proto_common_compile(ctx, proto_info, proto_lang_toolchain_info, generated_files):
-    """A wrapper around proto_common.compile that automatically calculates the output dir.
-
-    Args:
-      ctx: Rule context.
-      proto_info: ProtoInfo provider.
-      proto_lang_toolchain_info: ProtoLangToolchainInfo provider.
-      generated_files: The files we expect to be generated from this protoc invocation.
-    """
-    proto_common.compile(
-        actions = ctx.actions,
-        proto_info = proto_info,
-        proto_lang_toolchain_info = proto_lang_toolchain_info,
-        generated_files = generated_files,
-        plugin_output = output_dir(ctx, proto_info),
-    )
diff --git a/bazel/upb_proto_library.bzl b/bazel/upb_proto_library.bzl
index bc17964..3185353 100644
--- a/bazel/upb_proto_library.bzl
+++ b/bazel/upb_proto_library.bzl
@@ -28,9 +28,19 @@
   - upb_proto_reflection_library()
 """
 
-load(":proto_common_wrapper.bzl", "output_dir", "proto_common_compile")
-load("@rules_proto//proto:defs.bzl", "proto_common")
-load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+load("@bazel_skylib//lib:paths.bzl", "paths")
+
+# begin:google_only
+# load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+# end:google_only
+
+# begin:github_only
+# Compatibility code for Bazel 4.x. Remove this when we drop support for Bazel 4.x.
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def use_cpp_toolchain():
+    return ["@bazel_tools//tools/cpp:toolchain_type"]
+# end:github_only
 
 # Generic support code #########################################################
 
@@ -42,6 +52,61 @@
 # _is_google3 = True
 # end:google_only
 
+def _get_real_short_path(file):
+    # For some reason, files from other archives have short paths that look like:
+    #   ../com_google_protobuf/google/protobuf/descriptor.proto
+    short_path = file.short_path
+    if short_path.startswith("../"):
+        second_slash = short_path.index("/", 3)
+        short_path = short_path[second_slash + 1:]
+
+    # Sometimes it has another few prefixes like:
+    #   _virtual_imports/any_proto/google/protobuf/any.proto
+    #   benchmarks/_virtual_imports/100_msgs_proto/benchmarks/100_msgs.proto
+    # We want just google/protobuf/any.proto.
+    virtual_imports = "_virtual_imports/"
+    if virtual_imports in short_path:
+        short_path = short_path.split(virtual_imports)[1].split("/", 1)[1]
+    return short_path
+
+def _get_real_root(ctx, file):
+    real_short_path = _get_real_short_path(file)
+    root = file.path[:-len(real_short_path) - 1]
+
+    if not _is_google3 and ctx.rule.attr.strip_import_prefix:
+        root = paths.join(root, ctx.rule.attr.strip_import_prefix[1:])
+    return root
+
+def _generate_output_file(ctx, src, extension):
+    package = ctx.label.package
+    if not _is_google3:
+        strip_import_prefix = ctx.rule.attr.strip_import_prefix
+        if strip_import_prefix and strip_import_prefix != "/":
+            if not package.startswith(strip_import_prefix[1:]):
+                fail("%s does not begin with prefix %s" % (package, strip_import_prefix))
+            package = package[len(strip_import_prefix):]
+
+    real_short_path = _get_real_short_path(src)
+    real_short_path = paths.relativize(real_short_path, package)
+    output_filename = paths.replace_extension(real_short_path, extension)
+    ret = ctx.actions.declare_file(output_filename)
+    return ret
+
+def _generate_include_path(src, out, extension):
+    short_path = _get_real_short_path(src)
+    short_path = paths.replace_extension(short_path, extension)
+    if not out.path.endswith(short_path):
+        fail("%s does not end with %s" % (out.path, short_path))
+
+    return out.path[:-len(short_path)]
+
+def _filter_none(elems):
+    out = []
+    for elem in elems:
+        if elem:
+            out.append(elem)
+    return out
+
 def _cc_library_func(ctx, name, hdrs, srcs, copts, includes, dep_ccinfos):
     """Like cc_library(), but callable from rules.
 
@@ -140,12 +205,57 @@
     fields = ["srcs"],
 )
 
-def _filter_none(elems):
-    out = []
-    for elem in elems:
-        if elem:
-            out.append(elem)
-    return out
+def _compile_upb_protos(ctx, generator, proto_info, proto_sources):
+    if len(proto_sources) == 0:
+        return GeneratedSrcsInfo(srcs = [], hdrs = [], thunks = [], includes = [])
+
+    ext = "." + generator
+    tool = getattr(ctx.executable, "_gen_" + generator)
+    srcs = [_generate_output_file(ctx, name, ext + ".c") for name in proto_sources]
+    hdrs = [_generate_output_file(ctx, name, ext + ".h") for name in proto_sources]
+    thunks = []
+    if generator == "upb":
+        thunks = [_generate_output_file(ctx, name, ext + ".thunks.c") for name in proto_sources]
+    transitive_sets = proto_info.transitive_descriptor_sets.to_list()
+
+    args = ctx.actions.args()
+    args.use_param_file(param_file_arg = "@%s")
+    args.set_param_file_format("multiline")
+
+    args.add("--" + generator + "_out=" + _get_real_root(ctx, srcs[0]))
+    args.add("--plugin=protoc-gen-" + generator + "=" + tool.path)
+    args.add("--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]))
+    args.add_all(proto_sources, map_each = _get_real_short_path)
+
+    ctx.actions.run(
+        inputs = depset(
+            direct = [proto_info.direct_descriptor_set],
+            transitive = [proto_info.transitive_descriptor_sets],
+        ),
+        tools = [tool],
+        outputs = srcs + hdrs,
+        executable = ctx.executable._protoc,
+        arguments = [args],
+        progress_message = "Generating upb protos for :" + ctx.label.name,
+        mnemonic = "GenUpbProtos",
+    )
+    if generator == "upb":
+        ctx.actions.run_shell(
+            inputs = hdrs,
+            outputs = thunks,
+            command = " && ".join([
+                "sed 's/UPB_INLINE //' {} > {}".format(hdr.path, thunk.path)
+                for (hdr, thunk) in zip(hdrs, thunks)
+            ]),
+            progress_message = "Generating thunks for upb protos API for: " + ctx.label.name,
+            mnemonic = "GenUpbProtosThunks",
+        )
+    return GeneratedSrcsInfo(
+        srcs = srcs,
+        hdrs = hdrs,
+        thunks = thunks,
+        includes = [_generate_include_path(proto_sources[0], hdrs[0], ext + ".h")],
+    )
 
 def _upb_proto_rule_impl(ctx):
     if len(ctx.attr.deps) != 1:
@@ -180,64 +290,10 @@
         cc_info,
     ]
 
-def _get_lang_toolchain(ctx, generator):
-    lang_toolchain_name = "_" + generator + "_toolchain"
-    return getattr(ctx.attr, lang_toolchain_name)[proto_common.ProtoLangToolchainInfo]
-
-def _compile_upb_protos(ctx, generator, proto_info):
-    proto_sources = proto_info.direct_sources
-    if len(proto_sources) == 0:
-        return [], []
-
-    srcs = proto_common.declare_generated_files(
-        ctx.actions,
-        extension = "." + generator + ".c",
-        proto_info = proto_info,
-    )
-    hdrs = proto_common.declare_generated_files(
-        ctx.actions,
-        extension = "." + generator + ".h",
-        proto_info = proto_info,
-    )
-
-    proto_common_compile(
-        ctx = ctx,
-        proto_info = proto_info,
-        proto_lang_toolchain_info = _get_lang_toolchain(ctx, generator),
-        generated_files = srcs + hdrs,
-    )
-
-    if generator == "upb":
-        thunks = proto_common.declare_generated_files(
-            ctx.actions,
-            extension = "." + generator + ".thunks.c",
-            proto_info = proto_info,
-        )
-        ctx.actions.run_shell(
-            inputs = hdrs,
-            outputs = thunks,
-            command = " && ".join([
-                "sed 's/UPB_INLINE //' {} > {}".format(hdr.path, thunk.path)
-                for (hdr, thunk) in zip(hdrs, thunks)
-            ]),
-            progress_message = "Generating thunks for upb protos API for: " + ctx.label.name,
-            mnemonic = "GenUpbProtosThunks",
-        )
-    else:
-        thunks = []
-
-    return srcs, hdrs, thunks
-
 def _upb_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider):
     proto_info = target[ProtoInfo]
-    srcs, hdrs, thunks = _compile_upb_protos(ctx, generator, proto_info)
-    files = GeneratedSrcsInfo(
-        srcs = srcs,
-        hdrs = hdrs,
-        thunks = thunks,
-    )
-    runtime = _get_lang_toolchain(ctx, generator).runtime
-    deps = ctx.rule.attr.deps + [runtime]
+    files = _compile_upb_protos(ctx, generator, proto_info, proto_info.direct_sources)
+    deps = ctx.rule.attr.deps + getattr(ctx.attr, "_" + generator)
     dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep]
     dep_ccinfos += [dep[UpbWrappedCcInfo].cc_info for dep in deps if UpbWrappedCcInfo in dep]
     dep_ccinfos += [dep[_UpbDefsWrappedCcInfo].cc_info for dep in deps if _UpbDefsWrappedCcInfo in dep]
@@ -250,7 +306,7 @@
         name = ctx.rule.attr.name + "." + generator,
         hdrs = files.hdrs,
         srcs = files.srcs,
-        includes = [output_dir(ctx, proto_info)],
+        includes = files.includes,
         copts = ctx.attr._copts[UpbProtoLibraryCoptsInfo].copts,
         dep_ccinfos = dep_ccinfos,
     )
@@ -261,7 +317,7 @@
             name = ctx.rule.attr.name + "." + generator + ".thunks",
             hdrs = [],
             srcs = files.thunks,
-            includes = [output_dir(ctx, proto_info)],
+            includes = files.includes,
             copts = ctx.attr._copts[UpbProtoLibraryCoptsInfo].copts,
             dep_ccinfos = dep_ccinfos + [cc_info],
         )
@@ -291,10 +347,6 @@
             cfg = "exec",
             default = "@bazel_tools//tools/cpp:grep-includes",
         )
-    else:
-        d["_cc_toolchain"] = attr.label(
-            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
-        )
     return d
 
 # upb_proto_library() ##########################################################
@@ -304,10 +356,23 @@
         "_copts": attr.label(
             default = "//:upb_proto_library_copts__for_generated_code_only_do_not_use",
         ),
-        "_upb_toolchain": attr.label(
-            default = Label("//upbc:protoc-gen-upb_toolchain"),
-            cfg = getattr(proto_common, "proto_lang_toolchain_cfg", "target"),
+        "_gen_upb": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "//upbc:protoc-gen-upb_stage1",
         ),
+        "_protoc": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "@com_google_protobuf//:protoc",
+        ),
+        "_cc_toolchain": attr.label(
+            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
+        ),
+        "_upb": attr.label_list(default = [
+            "//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
+        ]),
+        "_fasttable_enabled": attr.label(default = "//:fasttable_enabled"),
     }),
     implementation = upb_proto_library_aspect_impl,
     provides = [
@@ -321,6 +386,7 @@
 )
 
 upb_proto_library = rule(
+    output_to_genfiles = True,
     implementation = _upb_proto_rule_impl,
     attrs = {
         "deps": attr.label_list(
@@ -338,9 +404,23 @@
         "_copts": attr.label(
             default = "//:upb_proto_library_copts__for_generated_code_only_do_not_use",
         ),
-        "_upbdefs_toolchain": attr.label(
-            default = Label("//upbc:protoc-gen-upbdefs_toolchain"),
-            cfg = getattr(proto_common, "proto_lang_toolchain_cfg", "target"),
+        "_gen_upbdefs": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "//upbc:protoc-gen-upbdefs",
+        ),
+        "_protoc": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "@com_google_protobuf//:protoc",
+        ),
+        "_cc_toolchain": attr.label(
+            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
+        ),
+        "_upbdefs": attr.label_list(
+            default = [
+                "//:generated_reflection_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
+            ],
         ),
     }),
     implementation = _upb_proto_reflection_library_aspect_impl,
@@ -359,6 +439,7 @@
 )
 
 upb_proto_reflection_library = rule(
+    output_to_genfiles = True,
     implementation = _upb_proto_rule_impl,
     attrs = {
         "deps": attr.label_list(
diff --git a/bazel/workspace_deps.bzl b/bazel/workspace_deps.bzl
index 4a765cf..cfe532e 100644
--- a/bazel/workspace_deps.bzl
+++ b/bazel/workspace_deps.bzl
@@ -47,16 +47,6 @@
     )
 
     maybe(
-        http_archive,
-        name = "rules_proto",
-        sha256 = "dc3fb206a2cb3441b485eb1e423165b231235a1ea9b031b4433cf7bc1fa460dd",
-        strip_prefix = "rules_proto-5.3.0-21.7",
-        urls = [
-            "https://github.com/bazelbuild/rules_proto/archive/refs/tags/5.3.0-21.7.tar.gz",
-        ],
-    )
-
-    maybe(
         _github_archive,
         name = "rules_python",
         repo = "https://github.com/bazelbuild/rules_python",
diff --git a/cmake/make_cmakelists.py b/cmake/make_cmakelists.py
index 614b377..6e552ba 100755
--- a/cmake/make_cmakelists.py
+++ b/cmake/make_cmakelists.py
@@ -280,12 +280,6 @@
   def googletest_deps(self):
     pass
 
-  def rules_proto_dependencies(self):
-    pass
-
-  def rules_proto_toolchains(self):
-    pass
-
 
 class Converter(object):
   def __init__(self):
diff --git a/protos/BUILD b/protos/BUILD
index ad3da72..f68a1ec 100644
--- a/protos/BUILD
+++ b/protos/BUILD
@@ -68,7 +68,6 @@
 cc_library(
     name = "generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
     hdrs = [
-        "protos.h",
         "protos_internal.h",
     ],
     copts = UPB_DEFAULT_CPPOPTS,
@@ -76,10 +75,6 @@
     deps = [
         ":protos",
         ":protos_internal",
-        "//:mini_table_internal",
-        "//:upb",
-        "@com_google_absl//absl/status",
-        "@com_google_absl//absl/status:statusor",
     ],
 )
 
diff --git a/protos/bazel/BUILD b/protos/bazel/BUILD
index b762b6a..607edae 100644
--- a/protos/bazel/BUILD
+++ b/protos/bazel/BUILD
@@ -32,7 +32,7 @@
     srcs = ["upb_cc_proto_library.bzl"],
     visibility = ["//visibility:public"],
     deps = [
-        "//bazel:proto_common_wrapper_bzl",
+        "@bazel_skylib//lib:paths",
         "//bazel:upb_proto_library_bzl",
         "@bazel_tools//tools/cpp:toolchain_utils.bzl",
     ],
diff --git a/protos/bazel/upb_cc_proto_library.bzl b/protos/bazel/upb_cc_proto_library.bzl
index 601d880..8fad95a 100644
--- a/protos/bazel/upb_cc_proto_library.bzl
+++ b/protos/bazel/upb_cc_proto_library.bzl
@@ -27,10 +27,20 @@
   - upb_cc_proto_library()
 """
 
-load("//bazel:proto_common_wrapper.bzl", "proto_common_compile")
+load("@bazel_skylib//lib:paths.bzl", "paths")
 load("//bazel:upb_proto_library.bzl", "GeneratedSrcsInfo", "UpbWrappedCcInfo", "upb_proto_library_aspect")
-load("@rules_proto//proto:defs.bzl", "proto_common")
-load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+
+# begin:google_only
+# load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain")
+#
+# end:google_only
+# begin:github_only
+# Compatibility code for Bazel 4.x. Remove this when we drop support for Bazel 4.x.
+load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
+
+def use_cpp_toolchain():
+    return ["@bazel_tools//tools/cpp:toolchain_type"]
+# end:github_only
 
 # Generic support code #########################################################
 
@@ -42,6 +52,34 @@
 # _is_google3 = True
 # end:google_only
 
+def _get_real_short_path(file):
+    # For some reason, files from other archives have short paths that look like:
+    #   ../com_google_protobuf/google/protobuf/descriptor.proto
+    short_path = file.short_path
+    if short_path.startswith("../"):
+        second_slash = short_path.index("/", 3)
+        short_path = short_path[second_slash + 1:]
+
+    # Sometimes it has another few prefixes like:
+    #   _virtual_imports/any_proto/google/protobuf/any.proto
+    #   benchmarks/_virtual_imports/100_msgs_proto/benchmarks/100_msgs.proto
+    # We want just google/protobuf/any.proto.
+    virtual_imports = "_virtual_imports/"
+    if virtual_imports in short_path:
+        short_path = short_path.split(virtual_imports)[1].split("/", 1)[1]
+    return short_path
+
+def _get_real_root(file):
+    real_short_path = _get_real_short_path(file)
+    return file.path[:-len(real_short_path) - 1]
+
+def _generate_output_file(ctx, src, extension):
+    real_short_path = _get_real_short_path(src)
+    real_short_path = paths.relativize(real_short_path, ctx.label.package)
+    output_filename = paths.replace_extension(real_short_path, extension)
+    ret = ctx.actions.declare_file(output_filename)
+    return ret
+
 def _filter_none(elems):
     out = []
     for elem in elems:
@@ -127,37 +165,36 @@
 _UpbCcWrappedCcInfo = provider("Provider for cc_info for protos", fields = ["cc_info"])
 _WrappedCcGeneratedSrcsInfo = provider("Provider for generated sources", fields = ["srcs"])
 
-def _get_lang_toolchain(ctx, generator):
-    lang_toolchain_name = "_" + generator + "_toolchain"
-    return getattr(ctx.attr, lang_toolchain_name)[proto_common.ProtoLangToolchainInfo]
-
 def _compile_upb_cc_protos(ctx, generator, proto_info, proto_sources):
     if len(proto_sources) == 0:
         return GeneratedSrcsInfo(srcs = [], hdrs = [])
 
-    srcs = proto_common.declare_generated_files(
-        ctx.actions,
-        extension = ".upb.proto.cc",
-        proto_info = proto_info,
-    )
-    hdrs = proto_common.declare_generated_files(
-        ctx.actions,
-        extension = ".upb.proto.h",
-        proto_info = proto_info,
-    )
-    hdrs += proto_common.declare_generated_files(
-        ctx.actions,
-        extension = ".upb.fwd.h",
-        proto_info = proto_info,
-    )
+    tool = getattr(ctx.executable, "_gen_" + generator)
+    srcs = [_generate_output_file(ctx, name, ".upb.proto.cc") for name in proto_sources]
+    hdrs = [_generate_output_file(ctx, name, ".upb.proto.h") for name in proto_sources]
+    hdrs += [_generate_output_file(ctx, name, ".upb.fwd.h") for name in proto_sources]
+    transitive_sets = proto_info.transitive_descriptor_sets.to_list()
 
-    proto_common_compile(
-        ctx = ctx,
-        proto_info = proto_info,
-        proto_lang_toolchain_info = _get_lang_toolchain(ctx, generator),
-        generated_files = srcs + hdrs,
-    )
+    args = ctx.actions.args()
+    args.use_param_file(param_file_arg = "@%s")
+    args.set_param_file_format("multiline")
 
+    args.add("--" + generator + "_out=" + _get_real_root(srcs[0]))
+    args.add("--plugin=protoc-gen-" + generator + "=" + tool.path)
+    args.add("--descriptor_set_in=" + ctx.configuration.host_path_separator.join([f.path for f in transitive_sets]))
+    args.add_all(proto_sources, map_each = _get_real_short_path)
+
+    ctx.actions.run(
+        inputs = depset(
+            direct = [proto_info.direct_descriptor_set],
+            transitive = [proto_info.transitive_descriptor_sets],
+        ),
+        tools = [tool],
+        outputs = srcs + hdrs,
+        executable = ctx.executable._protoc,
+        arguments = [args],
+        progress_message = "Generating upb cc protos for :" + ctx.label.name,
+    )
     return GeneratedSrcsInfo(srcs = srcs, hdrs = hdrs)
 
 def _upb_cc_proto_rule_impl(ctx):
@@ -194,8 +231,7 @@
 def _upb_cc_proto_aspect_impl(target, ctx, generator, cc_provider, file_provider):
     proto_info = target[ProtoInfo]
     files = _compile_upb_cc_protos(ctx, generator, proto_info, proto_info.direct_sources)
-    runtime = _get_lang_toolchain(ctx, generator).runtime
-    deps = ctx.rule.attr.deps + [runtime] + ctx.attr._aspect_deps
+    deps = ctx.rule.attr.deps + getattr(ctx.attr, "_" + generator)
     dep_ccinfos = [dep[CcInfo] for dep in deps if CcInfo in dep]
     dep_ccinfos += [dep[UpbWrappedCcInfo].cc_info for dep in deps if UpbWrappedCcInfo in dep]
     dep_ccinfos += [dep[_UpbCcWrappedCcInfo].cc_info for dep in deps if _UpbCcWrappedCcInfo in dep]
@@ -222,10 +258,6 @@
             cfg = "exec",
             default = "@bazel_tools//tools/cpp:grep-includes",
         )
-    else:
-        d["_cc_toolchain"] = attr.label(
-            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
-        )
     return d
 
 _upb_cc_proto_library_aspect = aspect(
@@ -233,14 +265,22 @@
         "_ccopts": attr.label(
             default = "//protos:upb_cc_proto_library_copts__for_generated_code_only_do_not_use",
         ),
-        "_upbprotos_toolchain": attr.label(
-            default = Label("//protos_generator:protoc-gen-upbprotos_toolchain"),
-            cfg = getattr(proto_common, "proto_lang_toolchain_cfg", "target"),
+        "_gen_upbprotos": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "//protos_generator:protoc-gen-upb-protos",
         ),
-        # proto_lang_toolchain(runtime="//xyz") only allows a single "runtime", so we need to add
-        # extra deps here.
-        "_aspect_deps": attr.label_list(
+        "_protoc": attr.label(
+            executable = True,
+            cfg = "exec",
+            default = "@com_google_protobuf//:protoc",
+        ),
+        "_cc_toolchain": attr.label(
+            default = "@bazel_tools//tools/cpp:current_cc_toolchain",
+        ),
+        "_upbprotos": attr.label_list(
             default = [
+                # TODO: Add dependencies for cc runtime (absl/string etc..)
                 "//:generated_cpp_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
                 "//protos:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
                 "@com_google_absl//absl/strings",
diff --git a/protos_generator/BUILD b/protos_generator/BUILD
index 90d13f2..825b92e 100644
--- a/protos_generator/BUILD
+++ b/protos_generator/BUILD
@@ -81,13 +81,3 @@
         "@com_google_protobuf//src/google/protobuf/compiler:code_generator",
     ],
 )
-
-proto_lang_toolchain(
-    name = "protoc-gen-upbprotos_toolchain",
-    command_line = "--upbprotos_out=%s",
-    plugin = ":protoc-gen-upb-protos",
-    plugin_format_flag = "--plugin=protoc-gen-upbprotos=%s",
-    progress_message = "Generating upb C++ protos",
-    runtime = "//protos:generated_protos_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
-    visibility = ["//visibility:public"],
-)
diff --git a/protos_generator/protoc-gen-upb-protos.cc b/protos_generator/protoc-gen-upb-protos.cc
index a174214..462898b 100644
--- a/protos_generator/protoc-gen-upb-protos.cc
+++ b/protos_generator/protoc-gen-upb-protos.cc
@@ -129,6 +129,11 @@
 
 #include "protos/protos.h"
 #include "protos/protos_internal.h"
+#include "upb/upb.hpp"
+
+#include "absl/strings/string_view.h"
+#include "absl/status/statusor.h"
+#include "upb/message/internal.h"
 #include "upb/message/copy.h"
       )cc",
       ToPreproc(file->name()));
@@ -144,6 +149,8 @@
     }
   }
 
+  output("#include \"upb/port/def.inc\"\n");
+
   const std::vector<const protobuf::Descriptor*> this_file_messages =
       SortedMessages(file);
   const std::vector<const protobuf::FieldDescriptor*> this_file_exts =
@@ -175,6 +182,7 @@
 
   WriteEndNamespace(file, output);
 
+  output("\n#include \"upb/port/undef.inc\"\n\n");
   // End of "C" section.
 
   output("#endif  /* $0_UPB_PROTO_H_ */\n", ToPreproc(file->name()));
@@ -188,6 +196,8 @@
   output(
       R"cc(
 #include <stddef.h>
+#include "absl/strings/string_view.h"
+#include "upb/message/copy.h"
 #include "upb/message/internal.h"
 #include "protos/protos.h"
 #include "$0"
@@ -197,6 +207,7 @@
   for (int i = 0; i < file->dependency_count(); i++) {
     output("#include \"$0\"\n", CppHeaderFilename(file->dependency(i)));
   }
+  output("#include \"upb/port/def.inc\"\n");
 
   WriteStartNamespace(file, output);
   WriteMessageImplementations(file, output);
@@ -204,6 +215,8 @@
       SortedExtensions(file);
   WriteExtensionIdentifiers(this_file_exts, output);
   WriteEndNamespace(file, output);
+
+  output("#include \"upb/port/undef.inc\"\n\n");
 }
 
 void WriteMessageImplementations(const protobuf::FileDescriptor* file,
diff --git a/upbc/BUILD b/upbc/BUILD
index ebcfc90..7e02058 100644
--- a/upbc/BUILD
+++ b/upbc/BUILD
@@ -255,16 +255,6 @@
     ],
 )
 
-proto_lang_toolchain(
-    name = "protoc-gen-upb_toolchain",
-    command_line = "--upb_out=%s",
-    plugin = ":protoc-gen-upb_stage1",
-    plugin_format_flag = "--plugin=protoc-gen-upb=%s",
-    progress_message = "Generating upb protos",
-    runtime = "//:generated_code_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
-    visibility = ["//visibility:public"],
-)
-
 cc_binary(
     name = "protoc-gen-upbdefs",
     srcs = [
@@ -287,16 +277,6 @@
     ],
 )
 
-proto_lang_toolchain(
-    name = "protoc-gen-upbdefs_toolchain",
-    command_line = "--upbdefs_out=%s",
-    plugin = ":protoc-gen-upbdefs",
-    plugin_format_flag = "--plugin=protoc-gen-upbdefs=%s",
-    progress_message = "Generating upb protos",
-    runtime = "//:generated_reflection_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me",
-    visibility = ["//visibility:public"],
-)
-
 cc_binary(
     name = "protoc-gen-upbdev",
     srcs = [