Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protobuf compatibility findings and suggestions #1647

Open
mbland opened this issue Nov 10, 2024 · 3 comments
Open

Protobuf compatibility findings and suggestions #1647

mbland opened this issue Nov 10, 2024 · 3 comments

Comments

@mbland
Copy link
Contributor

mbland commented Nov 10, 2024

As a side quest to #1482, I've been experimenting with trying to update the Protobuf library beyond version 21.7, released 2022-09-29. The reason is that I anticipate potential complications after the Bzlmod update lands if users have later Protobuf versions in their MODULE.bazel dependency graph.

I've discovered the following details, which we may need to communicate to users through release notes and/or other documentation. Here are the combinations of various dependencies that work with one another. The first row is the current combination.

Protobuf abseil-cpp Bazel 6 ScalaPB Scala
v21.7 20220623.1 0.9.0 All
v21.7 20220623.1 0.9.8 All
v21.7 20220623.1 0.11.17 >= 2.12
v25.5 20240722.0 with --cxxopt 0.9.8 All
v25.5 20240722.0 with --cxxopt 0.11.17 >= 2.12
>= v28.2 20240722.0 with --cxxopt 1.0.0-alpha.1 >= 2.12

Suggestions

I'd suggest updating the .bazelversion to 7.4.0 and bumping Protobuf to v25.5. My reasoning is that these changes would bring rules_scala closer to recent Bazel and Protobuf updates, without potentially breaking existing users.

If we decide to build with Bazel 7 by default instead of Bazel 6, the Protobuf recompilation sensitivity won't be as much of an issue. In my experience, after merging #1619, #1620, and #1622, I haven't found any other Bazel 6 and 7 incompatibilities outside of building newer Protobuf versions.

It would be nice to bump to ScalaPB 1.0.0-alpha.1 to use the latest Protobuf v28.3. However, it seems like that might be too big a bump for existing users right now.

Takeaways

ScalaPB and the scala_proto_aspect are sensitive to the Protobuf version

The scala_proto_library rule uses an aspect that delegates to the protoc-bridge generator framework to generate code. protoc-bridge itself isn't very sensitive, but the ScalaPB.ScalaPbCodeGenerator implementations to which it delegates are very sensitive to the Protobuf library version.

See the protoc-bridge explanation section below for details on why this is the case.

The Protobuf Bazel module remaining at compatibility_level 1 is a problem

All current versions of the Protobuf Bazel module, from before 21.7 and up to the current 29.0-rc2.bcr.1, have a compatibility_level of 1. This means that all modules in the Bzlmod/MODULE.bazel dependency graph will resolve to a single Protobuf version, regardless of its major version number.

This means that rules_scala locks scala_proto users to the maximum Protobuf version that it supports (or to a minimum of v28.2 with ScalaPB 1.0.0-alpha.1). While already true when using WORKSPACE, this will also be the case under Bzlmod, until a Protobuf module release with a different compatibility_level.

Protobuf >= v22 requires C++14 or greater, --cxxopt flags in Bazel 6

Protobuf v22 dropped C++11 support, requiring C++14 or greater. This corresponds to the update in abseil-cpp from 20220623.2, the last to support C++11, to 20230125.0, the first to require C++14.

This is not a problem for Bazel 7. Bazel 6, however, does not use a C++14 or greater toolchain out of the box.

To build these more recent versions of abseil-cpp and Protobuf under Bazel 6, I've added these .bazelrc flags from bazelbuild/bazel#20785 in commit 03d4e20 from mbland/rules_scala:

build:linux --cxxopt=-std=c++17
build:linux --host_cxxopt=-std=c++17
build:macos --cxxopt=-std=c++17
build:macos --host_cxxopt=-std=c++17
build:windows --cxxopt=/std=c++17
build:windows --host_cxxopt=/std=c++17

--cxxopt flags in Bazel 6 cause Protobuf to rebuild more frequently

Protobuf is already notoriously sensitive to recompilation.

This recompilation became so bad, I thought test_scalafmt from test_cross_build.sh was hanging. It was actually recompiling Protobuf on every bazel run invocation. (I've since filed #1646 to resolve this.)

Protobuf v25.5 is the highest version compatible with ScalaPB 0.9.8, 0.11.17

I was able to confirm this by iterating through different configurations of the test_scala_version test case from test_version.sh. I used the RULES_SCALA_TEST_ONLY environment variable from #1646 and the test_version.sh changes from commit ff1a079 from mbland/rules_scala to do this fairly easily.

There is no combination that works with Protobuf v26 or v27

I was able to confirm this using the same methodolgy...

No Protobuf version < v28.2 works with ScalaPB 1.0.0-alpha.1

...as I was able to confirm this as well.

Working branches

I was able to reach the above conclusions by building up changes in the following branches:

protoc-bridge explanation

scala_proto_library uses scala_proto_aspect, which uses the scripts.ScalaPBWorker class from src/scala/scripts/ScalaPBWorker.scala, which calls ProtocBridge.runWithGenerators. This function ultimately runs generator classes in separate threads via Futures. It then runs protoc with --plugin flags pointing at shell wrappers communicating with these generator Futures over a local pipe.

The ScalaPB jars required by the generators (not so much the protoc-bridge framework itself) must be compatible with the current Protobuf library version. Not just with the protobuf-java Maven artifact, which can be a new as you like, but with the build's actual Protobuf repository that provides protoc. Otherwise, ScalaPB code will throw exceptions like java.lang.NoSuchMethodError or java.lang.IllegalAccessError.

For example, from the #1624 commit message:

Exception in thread "main" java.lang.NoSuchMethodError:
  'boolean com.google.protobuf.GeneratedMessageV3.isStringEmpty(java.lang.Object)'

From the #1630 commit message:

--jvm_extra_protobuf_generator_out: java.lang.NoSuchMethodError:
  'java.lang.Object com.google.protobuf.DescriptorProtos$MessageOptions.getExtension(com.google.protobuf.GeneratedMessage$GeneratedExtension)'
    at scalapb.compiler.DescriptorImplicits$ExtendedMessageDescriptor.messageOptions(DescriptorImplicits.scala:532)

From the #1637 commit message:

--jvm_extra_protobuf_generator_out: java.lang.IllegalAccessError:
  class scalapb.options.Scalapb$ScalaPbOptions tried to access method
  'com.google.protobuf.LazyStringArrayList
    com.google.protobuf.LazyStringArrayList.emptyList()'
  (scalapb.options.Scalapb$ScalaPbOptions and
   com.google.protobuf.LazyStringArrayList are in unnamed module
   of loader 'app')

From commit 6f702a6 from mbland/rules_scala, which I plan to submit when bumping to ScalaPB 0.11.17:

--scala_out: java.lang.NoSuchMethodError:
  'void com.google.protobuf.Descriptors$FileDescriptor.internalBuildGeneratedFileFrom(java.lang.String[],
    com.google.protobuf.Descriptors$FileDescriptor[],
    com.google.protobuf.Descriptors$FileDescriptor$InternalDescriptorAssigner)'
      at scalapb.options.compiler.Scalapb.<clinit>(Scalapb.java:10592)

The changes from #1637 and the last commit above catch ScalaPB generator exceptions and return the stack trace as a proper error response. This is how I collected the stack traces above. Without these changes, the build hangs on uncaught exceptions, since the scripts.ScalaPBWorker will wait forever for a dead generator to respond.

Here's an example of a scripts.ScalaPBWorker command generated when building scala_proto_library targets in //test/proto/..., with long path prefixes and many jar paths elided:

.../scalapb_worker.runfiles/io_bazel_rules_scala/../remotejdk11_.../bin/java
  -classpath
    .../io_bazel_rules_scala/src/scala/scripts/scalapb_worker.jar:
    .../io_bazel_rules_scala/src/scala/scripts/scalapb_worker_lib.jar:
    [ ...protobuf, core Scala, and ScalaPB jars... ]
  -DGEN_jvm_extra_protobuf_generator=
   scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator
  -DGEN_scala=scripts.ScalaPbCodeGenerator
  -DPROTOC=bazel-out/.../bin/external/com_google_protobuf/protoc
  -DJARS=
    .../bin/test/src/main/scala/scalarules/test/extra_protobuf_generator/extra_protobuf_generator.jar:
    [ ...protobuf, core Scala, and ScalaPB jars... ]
  scripts.ScalaPBWorker --persistent_worker

The scripts.ScalaPBWorker class calling ProtocBridge.runWithGenerators launches protoc processes like this, with $VARDIR representing the generated /var path:

bazel-out/.../bin/external/com_google_protobuf/protoc
  --plugin=protoc-gen-scala=$VARDIR/protocbridge11068409970088580527
  --plugin=protoc-gen-jvm_extra_protobuf_generator=
    $VARDIR/protocbridge7908074065015031242
  --jvm_extra_protobuf_generator_out
    bazel-out/.../bin/test/proto/
    test2_jvm_extra_protobuf_generator_scalapb.srcjar
  --jvm_extra_protobuf_generator_opt grpc,single_line_to_proto_string
  --scala_out bazel-out/.../bin/test/proto/test2_scala_scalapb.srcjar
  --scala_opt grpc,single_line_to_proto_string
  --descriptor_set_in
    bazel-out/.../bin/test/proto2/test-descriptor-set.proto.bin:
    bazel-out/.../bin/test/proto/test2-descriptor-set.proto.bin
  test/proto/test2.proto

Notice the --plugin= flags above, which specify scripts generated by protoc-bridge that look like this:

#!/bin/sh
set -e
cat /dev/stdin > "$VARDIR/protopipe-14656650241271353812/input"
cat "$VARDIR/protopipe-14656650241271353812/output"

This command will show the scripts.ScalaPBWorker parent process, all the plugin script child processes, and the cat "$VARDIR/protopipe-.../output" grandchild processes if they're still running:

ps -ef | grep -E '[p]roto(cbridge|pipe)'

Without the aforementioned changes, you have to kill the build with CTRL-C when it hangs. bazel shutdown will then clean up the processes that haven't yet become zombified, but such zombified processes must be cleaned up with:

ps -ef | grep -E '[p]roto(cbridge|pipe)' | awk '{print $2}' | xargs kill
@mbland
Copy link
Contributor Author

mbland commented Nov 19, 2024

I just ran a small experiment to confirm my understanding of how potential Bzlmod users could accommodate our Protobuf dependency and theirs, whereby they rely on a version that isn't currently compatible with rules_scala. The mechanism relies on:

I created a new repo consisting of only the following three files:

.bazelversion (for Bazelisk):

7.4.1

MODULE.bazel:

module(name = "multiple-module-repo-experiment")

bazel_dep(
    name = "protobuf",
    version = "21.7",
    repo_name = "com_google_protobuf",
)

bazel_dep(
    name = "protobuf",
    version = "28.3",
)

multiple_version_override(
    module_name = "protobuf",
    versions = ["21.7", "28.3"],
)

BUILD:

load("@com_google_protobuf//:protobuf.bzl", "cc_proto_library")
load("@protobuf//bazel:proto_library.bzl", "proto_library")

This builds successfully and produces the following repos:

$ ls -ld "$(bazel info output_base)"/external/protobuf*
drwxr-xr-x  54 user  group  1728 Nov 19 14:18 .../external/protobuf~v21.7/
drwxr-xr-x  66 user  group  2112 Nov 19 14:18 .../external/protobuf~v28.3/

So we'd need to put in the release notes or documentation something like the following:

  • If your repository doesn't use Protobuf, uses Protobuf v21.7 to v25.5, or doesn't use the scala_proto or scalafmt toolchains from rules_scala, there's nothing to do.
  • Projects using Protobuf v26 and higher must use something like the MODULE.bazel stanza above to accommodate both its own required Protobuf version and that required by rules_scala.
  • The bazel_dep for the rules_scala version must specify repo_name = "com_google_protobuf", or some other name not used by the host project.
  • Per the multiple_version_override documentation, this only applies to the main repository; it does not convey to other repositories that depend on the repository using the multiple_version_override.

I also confirmed that multiple_version_override would be required even if the compatibility_level of the Protobuf module versions were different. I extended my experiment to try it with rules_erlang. I added the following to MODULE.bazel:

bazel_dep(
    name = "rules_erlang",
    version = "2.5.2",
    repo_name = "rules_erlang_v2",
)

bazel_dep(
    name = "rules_erlang",
    version = "3.16.0",
)

and the following to BUILD:

load("@rules_erlang_v2//:erlang_app.bzl", "test_erlang_app")
load("@rules_erlang//:erlang_app.bzl", "erlang_app")

Without multiple_version_override, the build failed with:

$ bazel build //:all                                                                          

ERROR: Error computing the main repository mapping:
  <root> depends on [email protected] with compatibility level 3,
  but <root> depends on [email protected] with compatibility level 2
  which is different                           

Then I added the following to MODULE.bazel, and it worked:

multiple_version_override(
    module_name = "rules_erlang",
    versions = ["2.5.2", "3.16.0"],
)

And we can see the different repo versions in this case, too:

$ ls -ld "$(bazel info output_base)"/external/rules_erlang*

drwxr-xr-x  34 user  group  1088 Nov 19 16:07 .../external/rules_erlang~v2.5.2/
drwxr-xr-x  60 user  group  1920 Nov 19 16:07 .../external/rules_erlang~v3.16.0/

At least in the rules_erlang case, where the compatibility_levels were different, we got an error message up front pointing at the problem. Without it, we potentially have to decipher a cryptic build breakage and diagnose the root cause, as I demonstrated in the original issue description.

@mbland
Copy link
Contributor Author

mbland commented Nov 22, 2024

Just filed scalapb/ScalaPB#1771 to see about applying fixes upstream to avoid scalapb.ScalaPbCodeGenerator hangs.

@mbland
Copy link
Contributor Author

mbland commented Nov 26, 2024

Bazel 8 further complicates things. See #1652 for details, and bazelbuild/bazel#24235 for a cross reference.

Repeating most of my summary from the latter issue for convenience:

Most of the Bazel 8 and rules_java 8 incompatibilities can be easily addressed once Bzlmodification lands, and what I think is the only remaining one may be resolved by a protobuf-java:4.29.0 release (without -RC2).

The tradeoffs are that users will be forced to upgrade to Protobuf v28.3 under Bazel 6 and 7, and Protobuf v29 under Bazel 8. , and the load("@rules_java") statements required by Bazel 8 will break WORKSPACE users for good. Then again, that may be all the more reason to suggest folks migrate to Bzlmod sooner than later.

Update: I've scratched out that last statement, because as noted in #1652, I could get a WORKSPACE build under Bazel 8 to reach the same failure point as the Bzlmod build. But these changes broke in what appears to be an unresolvable way under Bazel 7.4.1.

mbland added a commit to mbland/rules_scala that referenced this issue Nov 30, 2024
Ensures we get all the versions of dependencies we want in `WORKSPACE`,
while providing a new API to consumers. Part of bazelbuild#1652.

Bumps several packages as high as they can go and still be compatible
with Bazel 6 and 7:

- `bazel_skylib`: 1.4.1 => 1.7.1
- `rules_cc`: 0.0.6 => 0.0.9
- `rules_python`: 0.36.0 => 0.38.0
- `rules_go`: 0.50.1

The following packages are at the maximum version to prevent breakages
under Bazel 6.5.0.

---

`abseil-cpp` and `protobuf` have to stay at 20220623.1 and v27.1,
respectively, for Bazel 6 compatibility per bazelbuild#1647. `protobuf` up to
v25.5 is compatible with Bazel 6 provided users set the compiler flags
mentioned in that issue.

---

`rules_python` 0.38.0 => 0.39.0 requires at least `rules_cc` 0.0.10,
which introduced `cc/common/cc_info.bzl`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]
ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:19:6:
  Label '@rules_cc//cc/common:cc_info.bzl' is invalid
    because 'cc/common' is not a package;
    perhaps you meant to put the colon here:
    '@rules_cc//cc:common/cc_info.bzl'?
```

---

`rules_cc` 0.0.9 => 0.10.0 requires Bazel 7, which defines
`CcSharedLibraryHintInfo`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_cc/cc/private/rules_impl/native.bzl:40:33:
  name 'CcSharedLibraryHintInfo' is not defined (did you mean
  'CcSharedLibraryInfo'?)

[ ...snip... ]

ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:18:6:
  at .../external/rules_cc/cc/common/cc_common.bzl:17:6:
  compilation of module 'cc/private/rules_impl/native.bzl' failed
```

---

`rules_java` remains at 7.9.0 due to the more complicated situation it
presents. The current version that could be compatible with Bazel 6 and
7 is 7.12.2.

As it turns out, we could include `rules_java` versions up to and
including 7.12.2 if we don't call the following in `WORKSPACE`:

```py
load("@rules_java//java:repositories.bzl", "rules_java_dependencies",
"rules_java_toolchains")
rules_java_dependencies()
rules_java_toolchains()
```

In fact, __we don't do that today__. When we do, Bazel 7.4.1 builds
successfully, but Bazel 6.5.2 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/toolchains/java_toolchain_alias.bzl:83:34:
  Use of Starlark transition without allowlist attribute
  '_allowlist_function_transition'.
  See Starlark transitions documentation for details and usage:
  @rules_java//toolchains:java_toolchain_alias.bzl NORMAL

ERROR:
  .../src/java/io/bazel/rulesscala/coverage/instrumenter/BUILD:3:12:
  While resolving toolchains for target
  //src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter:
  invalid registered toolchain '//toolchains:all':
  while parsing '//toolchains:all':
  error loading package '@rules_java//toolchains':
  initialization of module 'toolchains/java_toolchain_alias.bzl' failed

ERROR: Analysis of target
  '//src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter'
  failed; build aborted:
```

When we bump to rules_java 7.10.0, which contains
bazelbuild/rules_java#210, Bazel 7.4.1 fails
with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_java_builtin/toolchains/BUILD:254:14:
  While resolving toolchains for target
  @@rules_java_builtin//toolchains:platformclasspath (096dcc8):
  No matching toolchains found for types
  @@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type.

To debug, rerun with
  --toolchain_resolution_debug='@@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type'
If platforms or toolchains are a new concept for you, we'd encourage
  reading https://bazel.build/concepts/platforms-intro.

ERROR: Analysis of target '//test/toolchains:java21_toolchain' failed;
  build aborted: Analysis failed
```

This is the error I described in bazelbuild#1619, under "Bump to rules_java 7.9.0
for Bazel 7 compatibility" in the message for
commit cd22d88.

Today I rediscovered:

- bazelbuild/rules_java: Regression with
  @@rules_java//toolchains:bootstrap_runtime_toolchain_type in 7.10.0
  bazelbuild/rules_java#214

But even worse, Bazel 6.5.0 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]

ERROR: .../test/src/main/resources/java_sources/BUILD:5:14:
  Building test/src/main/resources/java_sources/CompiledWithJava8_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---

ERROR: .../test/src/main/resources/java_sources/BUILD:11:14:
  Building test/src/main/resources/java_sources/CompiledWithJava11_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---
```

In bazelbuild#1619, I thought we wanted to keep `@bazel_tools//tools/jdk:` as the
canonical Java toolchains package, instead of
`@rules_java//toolchains:`. But based on this comment from @fmeum, I'm
inclined to believe switching to `@rules_java//toolchains:` actually is
the preferred, futureproof approach:

- bazelbuild/rules_java#214 (comment)

---

Bazel 8 requires `rules_java` 8, per bazelbuild#1652. We can't update to
`rules_java` 8 right now, unless we decided to do the following:

- Tell Bazel 6 users to add C++ compiler flags to support the newer
  `abseil-cpp` versions required by newer `protobuf` versions.

- Abandon Bazel 6 support in favor of supporting Bazel 7 at a minimum.

- In addition to either of the above cases, update ScalaPB to
  1.0.0-alpha.1 or higher to support `protobuf` v28.

Here are the details explaining why `rules_java` 8 currently breaks.

`rules_java` 8.0.0 requires Bazel >= 7.3.2, which provides the `subrule`
API. Compatibility with Bazel >= 6.3.0 isn't restored until `rules_java`
8.3.2.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/java/common/rules/android_lint.bzl:142:24:
  name 'subrule' is not defined (did you mean 'rule'?)

ERROR: Error computing the main repository mapping:
  at .../scala/private/extensions/dev_deps.bzl:8:6:
  at .../external/rules_java/java/repositories.bzl:20:6:
  at .../external/rules_java/toolchains/local_java_repository.bzl:17:6:
  at .../external/rules_java/java/defs.bzl:18:6:
  at .../external/rules_java/java/java_library.bzl:16:6:
  at .../external/rules_java/java/bazel/rules/bazel_java_library.bzl:21:6:
  compilation of module 'java/common/rules/android_lint.bzl' failed
```

`rules_java` 8.3.0 is broken, as it can't find its own
`@compatibility_proxy` repo:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: error loading package under directory 'src':
  error loading package 'src/protobuf/io/bazel/rules_scala':
  at .../external/rules_java/java/defs.bzl:22:6:
  at .../external/rules_java/java/java_test.bzl:16:6:
  Unable to find package for @compatibility_proxy//:proxy.bzl:
  The repository '@compatibility_proxy' could not be resolved:
  Repository '@compatibility_proxy' is not defined.
```

`rules_java` 8.3.1 seems to fix this, presumably by importing the
`protobuf` repo as `com_google_protobuf`. However, it now requires at
least `protobuf` v27.0, which adds `bazel/java/lite_proto_library.bzl`.
Per bazelbuild#1647, we'd have to update to ScalaPB 1.0.0-alpha.1 to support
`protobuf` v28, abandoning users of previous `protobuf` versions or
forcing them to upgrade.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[...snip...]
ERROR: error loading package under directory 'src':
  error loading package 'src/java/io/bazel/rulesscala/worker':
  at .../external/rules_java/java/defs.bzl:16:6:
  Label '@com_google_protobuf//bazel:java_lite_proto_library.bzl'
  is invalid because 'bazel' is not a package;
  perhaps you meant to put the colon here:
  '@com_google_protobuf//:bazel/java_lite_proto_library.bzl'?
```
mbland added a commit to mbland/rules_scala that referenced this issue Dec 1, 2024
Ensures we get all the versions of dependencies we want in `WORKSPACE`,
while providing a new API to consumers. Part of bazelbuild#1652.

Bumps several packages as high as they can go and still be compatible
with Bazel 6 and 7:

- `bazel_skylib`: 1.4.1 => 1.7.1
- `rules_cc`: 0.0.6 => 0.0.9
- `rules_python`: 0.36.0 => 0.38.0
- `rules_go`: 0.50.1

The following packages are at the maximum version to prevent breakages
under Bazel 6.5.0.

---

`abseil-cpp` and `protobuf` have to stay at 20220623.1 and v27.1,
respectively, for Bazel 6 compatibility per bazelbuild#1647. `protobuf` up to
v25.5 is compatible with Bazel 6 provided users set the compiler flags
mentioned in that issue.

---

`rules_python` 0.38.0 => 0.39.0 requires at least `rules_cc` 0.0.10,
which introduced `cc/common/cc_info.bzl`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]
ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:19:6:
  Label '@rules_cc//cc/common:cc_info.bzl' is invalid
    because 'cc/common' is not a package;
    perhaps you meant to put the colon here:
    '@rules_cc//cc:common/cc_info.bzl'?
```

---

`rules_cc` 0.0.9 => 0.10.0 requires Bazel 7, which defines
`CcSharedLibraryHintInfo`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_cc/cc/private/rules_impl/native.bzl:40:33:
  name 'CcSharedLibraryHintInfo' is not defined (did you mean
  'CcSharedLibraryInfo'?)

[ ...snip... ]

ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:18:6:
  at .../external/rules_cc/cc/common/cc_common.bzl:17:6:
  compilation of module 'cc/private/rules_impl/native.bzl' failed
```

---

`rules_java` remains at 7.9.0 due to the more complicated situation it
presents. The current version that could be compatible with Bazel 6 and
7 is 7.12.2.

As it turns out, we could include `rules_java` versions up to and
including 7.12.2 if we don't call the following in `WORKSPACE`:

```py
load("@rules_java//java:repositories.bzl", "rules_java_dependencies",
"rules_java_toolchains")
rules_java_dependencies()
rules_java_toolchains()
```

In fact, __we don't do that today__. When we do, Bazel 7.4.1 builds
successfully, but Bazel 6.5.2 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/toolchains/java_toolchain_alias.bzl:83:34:
  Use of Starlark transition without allowlist attribute
  '_allowlist_function_transition'.
  See Starlark transitions documentation for details and usage:
  @rules_java//toolchains:java_toolchain_alias.bzl NORMAL

ERROR:
  .../src/java/io/bazel/rulesscala/coverage/instrumenter/BUILD:3:12:
  While resolving toolchains for target
  //src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter:
  invalid registered toolchain '//toolchains:all':
  while parsing '//toolchains:all':
  error loading package '@rules_java//toolchains':
  initialization of module 'toolchains/java_toolchain_alias.bzl' failed

ERROR: Analysis of target
  '//src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter'
  failed; build aborted:
```

When we bump to rules_java 7.10.0, which contains
bazelbuild/rules_java#210, Bazel 7.4.1 fails
with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_java_builtin/toolchains/BUILD:254:14:
  While resolving toolchains for target
  @@rules_java_builtin//toolchains:platformclasspath (096dcc8):
  No matching toolchains found for types
  @@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type.

To debug, rerun with
  --toolchain_resolution_debug='@@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type'
If platforms or toolchains are a new concept for you, we'd encourage
  reading https://bazel.build/concepts/platforms-intro.

ERROR: Analysis of target '//test/toolchains:java21_toolchain' failed;
  build aborted: Analysis failed
```

This is the error I described in bazelbuild#1619, under "Bump to rules_java 7.9.0
for Bazel 7 compatibility" in the message for
commit cd22d88.

Today I rediscovered:

- bazelbuild/rules_java: Regression with
  @@rules_java//toolchains:bootstrap_runtime_toolchain_type in 7.10.0
  bazelbuild/rules_java#214

But even worse, Bazel 6.5.0 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]

ERROR: .../test/src/main/resources/java_sources/BUILD:5:14:
  Building test/src/main/resources/java_sources/CompiledWithJava8_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---

ERROR: .../test/src/main/resources/java_sources/BUILD:11:14:
  Building test/src/main/resources/java_sources/CompiledWithJava11_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---
```

In bazelbuild#1619, I thought we wanted to keep `@bazel_tools//tools/jdk:` as the
canonical Java toolchains package, instead of
`@rules_java//toolchains:`. But based on this comment from @fmeum, I'm
inclined to believe switching to `@rules_java//toolchains:` actually is
the preferred, futureproof approach:

- bazelbuild/rules_java#214 (comment)

---

Bazel 8 requires `rules_java` 8, per bazelbuild#1652. We can't update to
`rules_java` 8 right now, unless we decided to do the following:

- Tell Bazel 6 users to add C++ compiler flags to support the newer
  `abseil-cpp` versions required by newer `protobuf` versions.

- Abandon Bazel 6 support in favor of supporting Bazel 7 at a minimum.

- In addition to either of the above cases, update ScalaPB to
  1.0.0-alpha.1 or higher to support `protobuf` v28.

Here are the details explaining why `rules_java` 8 currently breaks.

`rules_java` 8.0.0 requires Bazel >= 7.3.2, which provides the `subrule`
API. Compatibility with Bazel >= 6.3.0 isn't restored until `rules_java`
8.3.2.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/java/common/rules/android_lint.bzl:142:24:
  name 'subrule' is not defined (did you mean 'rule'?)

ERROR: Error computing the main repository mapping:
  at .../scala/private/extensions/dev_deps.bzl:8:6:
  at .../external/rules_java/java/repositories.bzl:20:6:
  at .../external/rules_java/toolchains/local_java_repository.bzl:17:6:
  at .../external/rules_java/java/defs.bzl:18:6:
  at .../external/rules_java/java/java_library.bzl:16:6:
  at .../external/rules_java/java/bazel/rules/bazel_java_library.bzl:21:6:
  compilation of module 'java/common/rules/android_lint.bzl' failed
```

`rules_java` 8.3.0 is broken, as it can't find its own
`@compatibility_proxy` repo:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: error loading package under directory 'src':
  error loading package 'src/protobuf/io/bazel/rules_scala':
  at .../external/rules_java/java/defs.bzl:22:6:
  at .../external/rules_java/java/java_test.bzl:16:6:
  Unable to find package for @compatibility_proxy//:proxy.bzl:
  The repository '@compatibility_proxy' could not be resolved:
  Repository '@compatibility_proxy' is not defined.
```

`rules_java` 8.3.1 seems to fix this, presumably by importing the
`protobuf` repo as `com_google_protobuf`. However, it now requires at
least `protobuf` v27.0, which adds `bazel/java/lite_proto_library.bzl`.
Per bazelbuild#1647, we'd have to update to ScalaPB 1.0.0-alpha.1 to support
`protobuf` v28, abandoning users of previous `protobuf` versions or
forcing them to upgrade.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[...snip...]
ERROR: error loading package under directory 'src':
  error loading package 'src/java/io/bazel/rulesscala/worker':
  at .../external/rules_java/java/defs.bzl:16:6:
  Label '@com_google_protobuf//bazel:java_lite_proto_library.bzl'
  is invalid because 'bazel' is not a package;
  perhaps you meant to put the colon here:
  '@com_google_protobuf//:bazel/java_lite_proto_library.bzl'?
```
mbland added a commit to mbland/rules_scala that referenced this issue Dec 2, 2024
Moves functions out of `//scala:scala.bzl` and updates `WORKSPACE` to
load `//scala:toolchains.bzl` to avoid importing macros that depend on
`JavaInfo` and `java_common` during `WORKSPACE` evaluation. Based on
advice from @hvadehra in bazelbuild#1652.

Also bumps `.bazelversion` to 7.4.1 in order to upgrade `abseil-cpp` to
20240722.0 and `protobuf` to v29.0. This is instead of keeping
`.bazelversion` at 6.5.0 and setting C++ compiler flags in `.bazelrc` as
described in bazelbuild#1647.

I haven't tried this under Bzlmod yet, and it still fails with the
following error. Bumping to ScalaPB 1.0.0-alpha.1 in the next commit
fixes this.

```txt
ERROR: .../external/com_google_protobuf/src/google/protobuf/BUILD.bazel:23:14:
  ProtoScalaPBRule external/com_google_protobuf/src/google/protobuf/any_proto_jvm_extra_protobuf_generator_scalapb.srcjar
  failed: (Exit 1): scalapb_worker failed:
  error executing ProtoScalaPBRule command
  (from target @@com_google_protobuf//src/google/protobuf:any_proto)
  bazel-out/.../bin/src/scala/scripts/scalapb_worker
    ... (remaining 2 arguments skipped)

--jvm_extra_protobuf_generator_out:
  java.lang.NoSuchMethodError:
  'java.lang.Object com.google.protobuf.DescriptorProtos$FieldOptions.getExtension(com.google.protobuf.GeneratedMessage$GeneratedExtension)'
    at scalapb.compiler.DescriptorImplicits$ExtendedFieldDescriptor.fieldOptions(DescriptorImplicits.scala:329)
    at scalapb.compiler.DescriptorImplicits$ExtendedFieldDescriptor.scalaName(DescriptorImplicits.scala:207)
    at scalapb.compiler.ProtoValidation.validateField(ProtoValidation.scala:121)
    at scalapb.compiler.ProtoValidation.$anonfun$validateMessage$3(ProtoValidation.scala:56)
    at scalapb.compiler.ProtoValidation.$anonfun$validateMessage$3$adapted(ProtoValidation.scala:56)
    at scala.collection.Iterator.foreach(Iterator.scala:943)
    at scala.collection.Iterator.foreach$(Iterator.scala:943)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
    at scala.collection.IterableLike.foreach(IterableLike.scala:74)
    at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
    at scalapb.compiler.ProtoValidation.validateMessage(ProtoValidation.scala:56)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFile$2(ProtoValidation.scala:17)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFile$2$adapted(ProtoValidation.scala:17)
    at scala.collection.Iterator.foreach(Iterator.scala:943)
    at scala.collection.Iterator.foreach$(Iterator.scala:943)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
    at scala.collection.IterableLike.foreach(IterableLike.scala:74)
    at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
    at scalapb.compiler.ProtoValidation.validateFile(ProtoValidation.scala:17)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFiles$1(ProtoValidation.scala:10)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFiles$1$adapted(ProtoValidation.scala:10)
    at scala.collection.immutable.Stream.foreach(Stream.scala:533)
    at scalapb.compiler.ProtoValidation.validateFiles(ProtoValidation.scala:10)
    at scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator$.handleCodeGeneratorRequest(ExtraProtobufGenerator.scala:86)
    at scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator$.run(ExtraProtobufGenerator.scala:55)
    at protocbridge.frontend.PluginFrontend$.$anonfun$runWithBytes$1(PluginFrontend.scala:51)
    at scala.util.Try$.apply(Try.scala:213)
    at protocbridge.frontend.PluginFrontend$.runWithBytes(PluginFrontend.scala:51)
    at protocbridge.frontend.PluginFrontend$.runWithInputStream(PluginFrontend.scala:121)
    at protocbridge.frontend.PosixPluginFrontend$.$anonfun$prepare$2(PosixPluginFrontend.scala:40)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
    at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1$$anon$2.block(ExecutionContextImpl.scala:75)
    at java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3118)
    at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1.blockOn(ExecutionContextImpl.scala:87)
    at scala.concurrent.package$.blocking(package.scala:146)
    at protocbridge.frontend.PosixPluginFrontend$.$anonfun$prepare$1(PosixPluginFrontend.scala:38)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
    at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:659)
    at scala.util.Success.$anonfun$map$1(Try.scala:255)
    at scala.util.Success.map(Try.scala:213)
    at scala.concurrent.Future.$anonfun$map$1(Future.scala:292)
    at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:42)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:74)
    at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

java.lang.RuntimeException: Exit with code 1
    at scala.sys.package$.error(package.scala:30)
    at scripts.ScalaPBWorker$.work(ScalaPBWorker.scala:44)
    at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:96)
    at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49)
    at scripts.ScalaPBWorker$.main(ScalaPBWorker.scala:39)
    at scripts.ScalaPBWorker.main(ScalaPBWorker.scala)

ERROR: .../external/com_google_protobuf/src/google/protobuf/BUILD.bazel:23:14
  Building source jar external/com_google_protobuf/src/google/protobuf/any_proto_scalapb-src.jar
  failed: (Exit 1): scalapb_worker failed:
  error executing ProtoScalaPBRule command
  (from target @@com_google_protobuf//src/google/protobuf:any_proto)
  bazel-out/darwin_arm64-opt-exec-ST-a828a81199fe/bin/src/scala/scripts/scalapb_worker
    ... (remaining 2 arguments skipped)
```
mbland added a commit to mbland/rules_scala that referenced this issue Dec 2, 2024
Ensures we get all the versions of dependencies we want in `WORKSPACE`,
while providing a new API to consumers. Part of bazelbuild#1652.

Bumps several packages as high as they can go and still be compatible
with Bazel 6 and 7:

- `bazel_skylib`: 1.4.1 => 1.7.1
- `rules_cc`: 0.0.6 => 0.0.9
- `rules_python`: 0.36.0 => 0.38.0
- `rules_go`: 0.50.1

The following packages are at the maximum version to prevent breakages
under Bazel 6.5.0.

---

`abseil-cpp` and `protobuf` have to stay at 20220623.1 and v27.1,
respectively, for Bazel 6 compatibility per bazelbuild#1647. `protobuf` up to
v25.5 is compatible with Bazel 6 provided users set the compiler flags
mentioned in that issue.

---

`rules_python` 0.38.0 => 0.39.0 requires at least `rules_cc` 0.0.10,
which introduced `cc/common/cc_info.bzl`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]
ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:19:6:
  Label '@rules_cc//cc/common:cc_info.bzl' is invalid
    because 'cc/common' is not a package;
    perhaps you meant to put the colon here:
    '@rules_cc//cc:common/cc_info.bzl'?
```

---

`rules_cc` 0.0.9 => 0.10.0 requires Bazel 7, which defines
`CcSharedLibraryHintInfo`:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_cc/cc/private/rules_impl/native.bzl:40:33:
  name 'CcSharedLibraryHintInfo' is not defined (did you mean
  'CcSharedLibraryInfo'?)

[ ...snip... ]

ERROR: error loading package under directory 'test':
  error loading package 'test':
  at .../external/rules_python/python/defs.bzl:17:6:
  at .../external/rules_python/python/py_binary.bzl:18:6:
  at .../external/rules_python/python/private/py_binary_macro.bzl:16:6:
  at .../external/rules_python/python/private/common_bazel.bzl:18:6:
  at .../external/rules_cc/cc/common/cc_common.bzl:17:6:
  compilation of module 'cc/private/rules_impl/native.bzl' failed
```

---

`rules_java` remains at 7.9.0 due to the more complicated situation it
presents. The current version that could be compatible with Bazel 6 and
7 is 7.12.2.

As it turns out, we could include `rules_java` versions up to and
including 7.12.2 if we don't call the following in `WORKSPACE`:

```py
load("@rules_java//java:repositories.bzl", "rules_java_dependencies",
"rules_java_toolchains")
rules_java_dependencies()
rules_java_toolchains()
```

In fact, __we don't do that today__. When we do, Bazel 7.4.1 builds
successfully, but Bazel 6.5.2 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/toolchains/java_toolchain_alias.bzl:83:34:
  Use of Starlark transition without allowlist attribute
  '_allowlist_function_transition'.
  See Starlark transitions documentation for details and usage:
  @rules_java//toolchains:java_toolchain_alias.bzl NORMAL

ERROR:
  .../src/java/io/bazel/rulesscala/coverage/instrumenter/BUILD:3:12:
  While resolving toolchains for target
  //src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter:
  invalid registered toolchain '//toolchains:all':
  while parsing '//toolchains:all':
  error loading package '@rules_java//toolchains':
  initialization of module 'toolchains/java_toolchain_alias.bzl' failed

ERROR: Analysis of target
  '//src/java/io/bazel/rulesscala/coverage/instrumenter:instrumenter'
  failed; build aborted:
```

When we bump to rules_java 7.10.0, which contains
bazelbuild/rules_java#210, Bazel 7.4.1 fails
with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: .../external/rules_java_builtin/toolchains/BUILD:254:14:
  While resolving toolchains for target
  @@rules_java_builtin//toolchains:platformclasspath (096dcc8):
  No matching toolchains found for types
  @@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type.

To debug, rerun with
  --toolchain_resolution_debug='@@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type'
If platforms or toolchains are a new concept for you, we'd encourage
  reading https://bazel.build/concepts/platforms-intro.

ERROR: Analysis of target '//test/toolchains:java21_toolchain' failed;
  build aborted: Analysis failed
```

This is the error I described in bazelbuild#1619, under "Bump to rules_java 7.9.0
for Bazel 7 compatibility" in the message for
commit cd22d88.

Today I rediscovered:

- bazelbuild/rules_java: Regression with
  @@rules_java//toolchains:bootstrap_runtime_toolchain_type in 7.10.0
  bazelbuild/rules_java#214

But even worse, Bazel 6.5.0 fails with:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[ ...snip... ]

ERROR: .../test/src/main/resources/java_sources/BUILD:5:14:
  Building test/src/main/resources/java_sources/CompiledWithJava8_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---

ERROR: .../test/src/main/resources/java_sources/BUILD:11:14:
  Building test/src/main/resources/java_sources/CompiledWithJava11_java.jar
  (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at .../bazel-workers/multiplex-worker-18-Javac.log ---8<---8<---
Error thrown by worker thread, shutting down worker.
java.lang.NoSuchMethodError:
  'java.lang.Iterable
   com.google.devtools.build.buildjar.javac.BlazeJavacMain$ClassloaderMaskingFileManager.getJavaFileObjectsFromPaths(java.util.Collection)'
    at com.google.devtools.build.buildjar.javac.BlazeJavacMain.compile(BlazeJavacMain.java:142)
    at com.google.devtools.build.buildjar.ReducedClasspathJavaLibraryBuilder.compileSources(ReducedClasspathJavaLibraryBuilder.java:57)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.compileJavaLibrary(SimpleJavaLibraryBuilder.java:110)
    at com.google.devtools.build.buildjar.SimpleJavaLibraryBuilder.run(SimpleJavaLibraryBuilder.java:118)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.build(BazelJavaBuilder.java:111)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.parseAndBuild(BazelJavaBuilder.java:91)
    at com.google.devtools.build.buildjar.BazelJavaBuilder.lambda$main$0(BazelJavaBuilder.java:52)
    at com.google.devtools.build.lib.worker.WorkRequestHandler$WorkRequestCallback.apply(WorkRequestHandler.java:252)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.respondToRequest(WorkRequestHandler.java:480)
    at com.google.devtools.build.lib.worker.WorkRequestHandler.lambda$startResponseThread$1(WorkRequestHandler.java:433)
    at java.base/java.lang.Thread.run(Thread.java:829)
---8<---8<--- End of log ---8<---8<---
```

In bazelbuild#1619, I thought we wanted to keep `@bazel_tools//tools/jdk:` as the
canonical Java toolchains package, instead of
`@rules_java//toolchains:`. But based on this comment from @fmeum, I'm
inclined to believe switching to `@rules_java//toolchains:` actually is
the preferred, futureproof approach:

- bazelbuild/rules_java#214 (comment)

---

Bazel 8 requires `rules_java` 8, per bazelbuild#1652. We can't update to
`rules_java` 8 right now, unless we decided to do the following:

- Tell Bazel 6 users to add C++ compiler flags to support the newer
  `abseil-cpp` versions required by newer `protobuf` versions.

- Abandon Bazel 6 support in favor of supporting Bazel 7 at a minimum.

- In addition to either of the above cases, update ScalaPB to
  1.0.0-alpha.1 or higher to support `protobuf` v28.

Here are the details explaining why `rules_java` 8 currently breaks.

`rules_java` 8.0.0 requires Bazel >= 7.3.2, which provides the `subrule`
API. Compatibility with Bazel >= 6.3.0 isn't restored until `rules_java`
8.3.2.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR:
  .../external/rules_java/java/common/rules/android_lint.bzl:142:24:
  name 'subrule' is not defined (did you mean 'rule'?)

ERROR: Error computing the main repository mapping:
  at .../scala/private/extensions/dev_deps.bzl:8:6:
  at .../external/rules_java/java/repositories.bzl:20:6:
  at .../external/rules_java/toolchains/local_java_repository.bzl:17:6:
  at .../external/rules_java/java/defs.bzl:18:6:
  at .../external/rules_java/java/java_library.bzl:16:6:
  at .../external/rules_java/java/bazel/rules/bazel_java_library.bzl:21:6:
  compilation of module 'java/common/rules/android_lint.bzl' failed
```

`rules_java` 8.3.0 is broken, as it can't find its own
`@compatibility_proxy` repo:

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

ERROR: error loading package under directory 'src':
  error loading package 'src/protobuf/io/bazel/rules_scala':
  at .../external/rules_java/java/defs.bzl:22:6:
  at .../external/rules_java/java/java_test.bzl:16:6:
  Unable to find package for @compatibility_proxy//:proxy.bzl:
  The repository '@compatibility_proxy' could not be resolved:
  Repository '@compatibility_proxy' is not defined.
```

`rules_java` 8.3.1 seems to fix this, presumably by importing the
`protobuf` repo as `com_google_protobuf`. However, it now requires at
least `protobuf` v27.0, which adds `bazel/java/lite_proto_library.bzl`.
Per bazelbuild#1647, we'd have to update to ScalaPB 1.0.0-alpha.1 to support
`protobuf` v28, abandoning users of previous `protobuf` versions or
forcing them to upgrade.

```txt
$ bazel build //{src,test,third_party,scala_proto}/...

[...snip...]
ERROR: error loading package under directory 'src':
  error loading package 'src/java/io/bazel/rulesscala/worker':
  at .../external/rules_java/java/defs.bzl:16:6:
  Label '@com_google_protobuf//bazel:java_lite_proto_library.bzl'
  is invalid because 'bazel' is not a package;
  perhaps you meant to put the colon here:
  '@com_google_protobuf//:bazel/java_lite_proto_library.bzl'?
```
mbland added a commit to mbland/rules_scala that referenced this issue Dec 2, 2024
Moves functions out of `//scala:scala.bzl` and updates `WORKSPACE` to
load `//scala:toolchains.bzl` to avoid importing macros that depend on
`JavaInfo` and `java_common` during `WORKSPACE` evaluation. Based on
advice from @hvadehra in bazelbuild#1652.

Also bumps `.bazelversion` to 7.4.1 in order to upgrade `abseil-cpp` to
20240722.0 and `protobuf` to v29.0. This is instead of keeping
`.bazelversion` at 6.5.0 and setting C++ compiler flags in `.bazelrc` as
described in bazelbuild#1647.

I haven't tried this under Bzlmod yet, and it still fails with the
following error. Bumping to ScalaPB 1.0.0-alpha.1 in the next commit
fixes this.

```txt
ERROR: .../external/com_google_protobuf/src/google/protobuf/BUILD.bazel:23:14:
  ProtoScalaPBRule external/com_google_protobuf/src/google/protobuf/any_proto_jvm_extra_protobuf_generator_scalapb.srcjar
  failed: (Exit 1): scalapb_worker failed:
  error executing ProtoScalaPBRule command
  (from target @@com_google_protobuf//src/google/protobuf:any_proto)
  bazel-out/.../bin/src/scala/scripts/scalapb_worker
    ... (remaining 2 arguments skipped)

--jvm_extra_protobuf_generator_out:
  java.lang.NoSuchMethodError:
  'java.lang.Object com.google.protobuf.DescriptorProtos$FieldOptions.getExtension(com.google.protobuf.GeneratedMessage$GeneratedExtension)'
    at scalapb.compiler.DescriptorImplicits$ExtendedFieldDescriptor.fieldOptions(DescriptorImplicits.scala:329)
    at scalapb.compiler.DescriptorImplicits$ExtendedFieldDescriptor.scalaName(DescriptorImplicits.scala:207)
    at scalapb.compiler.ProtoValidation.validateField(ProtoValidation.scala:121)
    at scalapb.compiler.ProtoValidation.$anonfun$validateMessage$3(ProtoValidation.scala:56)
    at scalapb.compiler.ProtoValidation.$anonfun$validateMessage$3$adapted(ProtoValidation.scala:56)
    at scala.collection.Iterator.foreach(Iterator.scala:943)
    at scala.collection.Iterator.foreach$(Iterator.scala:943)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
    at scala.collection.IterableLike.foreach(IterableLike.scala:74)
    at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
    at scalapb.compiler.ProtoValidation.validateMessage(ProtoValidation.scala:56)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFile$2(ProtoValidation.scala:17)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFile$2$adapted(ProtoValidation.scala:17)
    at scala.collection.Iterator.foreach(Iterator.scala:943)
    at scala.collection.Iterator.foreach$(Iterator.scala:943)
    at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
    at scala.collection.IterableLike.foreach(IterableLike.scala:74)
    at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
    at scalapb.compiler.ProtoValidation.validateFile(ProtoValidation.scala:17)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFiles$1(ProtoValidation.scala:10)
    at scalapb.compiler.ProtoValidation.$anonfun$validateFiles$1$adapted(ProtoValidation.scala:10)
    at scala.collection.immutable.Stream.foreach(Stream.scala:533)
    at scalapb.compiler.ProtoValidation.validateFiles(ProtoValidation.scala:10)
    at scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator$.handleCodeGeneratorRequest(ExtraProtobufGenerator.scala:86)
    at scalarules.test.extra_protobuf_generator.ExtraProtobufGenerator$.run(ExtraProtobufGenerator.scala:55)
    at protocbridge.frontend.PluginFrontend$.$anonfun$runWithBytes$1(PluginFrontend.scala:51)
    at scala.util.Try$.apply(Try.scala:213)
    at protocbridge.frontend.PluginFrontend$.runWithBytes(PluginFrontend.scala:51)
    at protocbridge.frontend.PluginFrontend$.runWithInputStream(PluginFrontend.scala:121)
    at protocbridge.frontend.PosixPluginFrontend$.$anonfun$prepare$2(PosixPluginFrontend.scala:40)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
    at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1$$anon$2.block(ExecutionContextImpl.scala:75)
    at java.base/java.util.concurrent.ForkJoinPool.managedBlock(ForkJoinPool.java:3118)
    at scala.concurrent.impl.ExecutionContextImpl$DefaultThreadFactory$$anon$1.blockOn(ExecutionContextImpl.scala:87)
    at scala.concurrent.package$.blocking(package.scala:146)
    at protocbridge.frontend.PosixPluginFrontend$.$anonfun$prepare$1(PosixPluginFrontend.scala:38)
    at scala.runtime.java8.JFunction0$mcV$sp.apply(JFunction0$mcV$sp.java:23)
    at scala.concurrent.Future$.$anonfun$apply$1(Future.scala:659)
    at scala.util.Success.$anonfun$map$1(Try.scala:255)
    at scala.util.Success.map(Try.scala:213)
    at scala.concurrent.Future.$anonfun$map$1(Future.scala:292)
    at scala.concurrent.impl.Promise.$anonfun$transform$1(Promise.scala:42)
    at scala.concurrent.impl.CallbackRunnable.run(Promise.scala:74)
    at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

java.lang.RuntimeException: Exit with code 1
    at scala.sys.package$.error(package.scala:30)
    at scripts.ScalaPBWorker$.work(ScalaPBWorker.scala:44)
    at io.bazel.rulesscala.worker.Worker.persistentWorkerMain(Worker.java:96)
    at io.bazel.rulesscala.worker.Worker.workerMain(Worker.java:49)
    at scripts.ScalaPBWorker$.main(ScalaPBWorker.scala:39)
    at scripts.ScalaPBWorker.main(ScalaPBWorker.scala)

ERROR: .../external/com_google_protobuf/src/google/protobuf/BUILD.bazel:23:14
  Building source jar external/com_google_protobuf/src/google/protobuf/any_proto_scalapb-src.jar
  failed: (Exit 1): scalapb_worker failed:
  error executing ProtoScalaPBRule command
  (from target @@com_google_protobuf//src/google/protobuf:any_proto)
  bazel-out/darwin_arm64-opt-exec-ST-a828a81199fe/bin/src/scala/scripts/scalapb_worker
    ... (remaining 2 arguments skipped)
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant