summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSorin Basca <sorinbasca@google.com>2024-02-22 17:58:29 +0000
committerSorin Basca <sorinbasca@google.com>2024-02-22 17:58:29 +0000
commit88a62bb6769aa02fba887a969041572fab07e6f7 (patch)
tree39ff62b6f6bd84cad9606cff57858fd55e8f6faa
parent572f3a37bb0d46c428bc816c42c3961a41357bdf (diff)
downloadkythe-master.tar.gz
Bring in compatibility shims for CommandLine from upstreamHEADmastermain
In order to support building with JDK21, Kythe needs to be able to deal with the move of CommandLine from com.sun.tools.javac.main to jdk.internal.opt, This change brings in the service loader infrastructure that can deal with this. Until we switch to JDK21 we will use the fallback (reflective) mechanism. Once JDK21 is in place, we can also enable the 21 compatibility implementation. Bug: 313924276 Test: prebuilts/build-tools/build-prebuilts.sh --skip-go --skip-asan \ --skip-soong-tests --resume Test: java --add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \ --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ --add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \ --add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED \ -jar ./out/soong/dist-common/framework/javac_extractor.jar \ # Using JDK11, JDK17 and JDK21 Change-Id: I10bae91e1203b919b6ca3012b208c01ea904ac76
-rw-r--r--Android.bp19
-rw-r--r--javac_extractor_manifest.txt2
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/15/JdkCompatibilityShimsImpl.java49
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/21/JdkCompatibilityShimsImpl.java48
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/9/JdkCompatibilityShimsImpl.java48
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java23
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/BUILD136
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/JavacWrapper.java (renamed from kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java)32
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/JdkCompatibilityShims.java37
-rw-r--r--kythe/java/com/google/devtools/kythe/extractors/java/standalone/ReflectiveJdkCompatibilityShims.java105
-rw-r--r--kythe/java/com/google/devtools/kythe/util/OrderedCompatibilityService.java115
11 files changed, 565 insertions, 49 deletions
diff --git a/Android.bp b/Android.bp
index 67d9d24a4..fffaeb0f6 100644
--- a/Android.bp
+++ b/Android.bp
@@ -29,7 +29,16 @@ java_library_host {
name: "javac_extractor",
srcs: [
"kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java",
- "kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java",
+ "kythe/java/com/google/devtools/kythe/extractors/java/standalone/JavacWrapper.java",
+ "kythe/java/com/google/devtools/kythe/extractors/java/standalone/JdkCompatibilityShims.java",
+ // Currently it is not possible to pick a specific JDK version implementation of
+ // JdkCompatibilityShim, so only use the fallback (reflective) one. Otherwise, if it becomes
+ // possible, either through bp file configuration, or once JDK 21 is used consistently, we
+ // could also select one the options below.
+ "kythe/java/com/google/devtools/kythe/extractors/java/standalone/ReflectiveJdkCompatibilityShims.java",
+ // "kythe/java/com/google/devtools/kythe/extractors/java/standalone/9/JdkCompatibilityShimsImpl.java",
+ // "kythe/java/com/google/devtools/kythe/extractors/java/standalone/15/JdkCompatibilityShimsImpl.java",
+ // "kythe/java/com/google/devtools/kythe/extractors/java/standalone/21/JdkCompatibilityShimsImpl.java",
"kythe/java/com/google/devtools/kythe/extractors/java/*.java",
"kythe/java/com/google/devtools/kythe/extractors/shared/*.java",
"kythe/java/com/google/devtools/kythe/platform/kzip/*.java",
@@ -38,6 +47,7 @@ java_library_host {
"kythe/java/com/google/devtools/kythe/platform/shared/CompilationUnits.java",
"kythe/java/com/google/devtools/kythe/util/DeleteRecursively.java",
"kythe/java/com/google/devtools/kythe/util/JsonUtil.java",
+ "kythe/java/com/google/devtools/kythe/util/OrderedCompatibilityService.java",
":kythe_protos",
"kythe/proto/java.proto",
],
@@ -48,7 +58,10 @@ java_library_host {
"--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
"--add-exports jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
"--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED",
"--add-modules java.compiler",
+ "--add-modules jdk.internal.opt",
],
manifest: "javac_extractor_manifest.txt",
proto: {
@@ -65,6 +78,10 @@ java_library_host {
"libprotobuf-java-util-full",
"guava",
"jsr305",
+ "auto_service_annotations",
+ ],
+ plugins: [
+ "auto_service_plugin",
],
java_version: "1.9",
}
diff --git a/javac_extractor_manifest.txt b/javac_extractor_manifest.txt
index 7e039cc35..d30b75ecc 100644
--- a/javac_extractor_manifest.txt
+++ b/javac_extractor_manifest.txt
@@ -1 +1 @@
-Main-Class: com.google.devtools.kythe.extractors.java.standalone.Javac9Wrapper
+Main-Class: com.google.devtools.kythe.extractors.java.standalone.JavacWrapper
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/15/JdkCompatibilityShimsImpl.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/15/JdkCompatibilityShimsImpl.java
new file mode 100644
index 000000000..e0be7547f
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/15/JdkCompatibilityShimsImpl.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.extractors.java.standalone;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Lists;
+import com.sun.tools.javac.main.Arguments;
+import com.sun.tools.javac.main.CommandLine;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/** JdkCompatibilityShims implementation for JDK15-compatible releases. */
+@AutoService(JdkCompatibilityShims.class)
+public final class JdkCompatibilityShimsImpl implements JdkCompatibilityShims {
+ private static final Runtime.Version minVersion = Runtime.Version.parse("15");
+ private static final Runtime.Version maxVersion = Runtime.Version.parse("21");
+
+ public JdkCompatibilityShimsImpl() {}
+
+ @Override
+ public CompatibilityRange getCompatibleRange() {
+ return new CompatibilityRange(minVersion, maxVersion);
+ }
+
+ @Override
+ public List<String> parseCompilerArguments(String[] args) throws IOException {
+ return Lists.newArrayList(CommandLine.parse(Arrays.asList(args)));
+ }
+
+ @Override
+ public void initializeArguments(Arguments arguments, String[] args) {
+ arguments.init("kythe_javac", Arrays.asList(args));
+ }
+}
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/21/JdkCompatibilityShimsImpl.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/21/JdkCompatibilityShimsImpl.java
new file mode 100644
index 000000000..a90082ed4
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/21/JdkCompatibilityShimsImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.extractors.java.standalone;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Lists;
+import com.sun.tools.javac.main.Arguments;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import jdk.internal.opt.CommandLine;
+
+/** JdkCompatibilityShims implementation for JDK21-compatible releases. */
+@AutoService(JdkCompatibilityShims.class)
+public final class JdkCompatibilityShimsImpl implements JdkCompatibilityShims {
+ private static final Runtime.Version minVersion = Runtime.Version.parse("21");
+
+ public JdkCompatibilityShimsImpl() {}
+
+ @Override
+ public CompatibilityRange getCompatibleRange() {
+ return new CompatibilityRange(minVersion);
+ }
+
+ @Override
+ public List<String> parseCompilerArguments(String[] args) throws IOException {
+ return Lists.newArrayList(CommandLine.parse(Arrays.asList(args)));
+ }
+
+ @Override
+ public void initializeArguments(Arguments arguments, String[] args) {
+ arguments.init("kythe_javac", Arrays.asList(args));
+ }
+}
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/9/JdkCompatibilityShimsImpl.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/9/JdkCompatibilityShimsImpl.java
new file mode 100644
index 000000000..45f41ee47
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/9/JdkCompatibilityShimsImpl.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.extractors.java.standalone;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.Lists;
+import com.sun.tools.javac.main.Arguments;
+import com.sun.tools.javac.main.CommandLine;
+import java.io.IOException;
+import java.util.List;
+
+/** JdkCompatibilityShims implementation for JDK9-compatible releases. */
+@AutoService(JdkCompatibilityShims.class)
+public final class JdkCompatibilityShimsImpl implements JdkCompatibilityShims {
+ private static final Runtime.Version minVersion = Runtime.Version.parse("9");
+ private static final Runtime.Version maxVersion = Runtime.Version.parse("15");
+
+ public JdkCompatibilityShimsImpl() {}
+
+ @Override
+ public CompatibilityRange getCompatibleRange() {
+ return new CompatibilityRange(minVersion, maxVersion);
+ }
+
+ @Override
+ public List<String> parseCompilerArguments(String[] args) throws IOException {
+ return Lists.newArrayList(CommandLine.parse(args));
+ }
+
+ @Override
+ public void initializeArguments(Arguments arguments, String[] args) {
+ arguments.init("kythe_javac", args);
+ }
+}
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
index 0c883ac6d..3a84d4a05 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/AbstractJavacWrapper.java
@@ -31,7 +31,6 @@ import com.google.devtools.kythe.extractors.shared.IndexInfoUtils;
import com.google.devtools.kythe.proto.Analysis.CompilationUnit;
import com.google.devtools.kythe.proto.Analysis.FileData;
import com.google.devtools.kythe.util.JsonUtil;
-import com.sun.tools.javac.main.CommandLine;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
@@ -66,6 +65,7 @@ import java.util.Optional;
*/
public abstract class AbstractJavacWrapper {
private static final Logger logger = Logger.getLogger(AbstractJavacWrapper.class.getName());
+ protected static final JdkCompatibilityShims shims = JdkCompatibilityShims.loadBest().get();
protected abstract Collection<CompilationDescription> processCompilation(
String[] arguments, JavaCompilationUnitExtractor javaCompilationUnitExtractor)
@@ -150,26 +150,7 @@ public abstract class AbstractJavacWrapper {
private static String[] getCleanedUpArguments(String[] args) throws IOException {
// Expand all @file arguments
- // JDK changed the signature of the CommandLine.parse method in JDK15,
- // support both versions
- List<String> expandedArgs = null;
- try {
- try {
- // JDK15+: the signature is
- // List<String> parse(List<String> args);
- expandedArgs = (List<String>)CommandLine.class.getMethod("parse", List.class).invoke(null, (Object)Arrays.asList(args));
- } catch (NoSuchMethodException nsme) {
- // pre-JDK15:
- // String[] parse(String[]);
- expandedArgs = Arrays.asList((String[])CommandLine.class.getMethod("parse", String[].class).invoke(null, (Object)args));
- }
- } catch (NoSuchMethodException ns2) {
- System.err.printf("Cannot locate com.sun.tools.javac.main.CommandLine.parse method, JDK version %s\n", System.getProperty("java.version"));
- System.exit(2);
- } catch (InvocationTargetException|IllegalAccessException ex) {
- System.err.printf("Cannot call com.sun.tools.javac.main.CommandLine.parse (JDK version %s):\n%s\n", System.getProperty("java.version"), ex);
- System.exit(2);
- }
+ List<String> expandedArgs = shims.parseCompilerArguments(args);
// We skip some arguments that would normally be passed to javac:
// -J, these are flags to the java environment running javac.
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/BUILD b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/BUILD
index 8b1a2f9f4..c118ef17a 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/BUILD
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/BUILD
@@ -1,5 +1,6 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@rules_java//java:defs.bzl", "java_binary", "java_library")
+load("//tools:build_rules/selects.bzl", select_with_or = "with_or")
package(default_visibility = ["//kythe:default_visibility"])
@@ -7,13 +8,21 @@ exports_files(["javac-wrapper.sh"])
java_binary(
name = "javac_extractor",
- srcs = ["Javac9Wrapper.java"],
+ srcs = ["JavacWrapper.java"],
javacopts = [
"--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
"--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
],
- main_class = "com.google.devtools.kythe.extractors.java.standalone.Javac9Wrapper",
+ jvm_flags = [
+ "--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ ],
+ main_class = "com.google.devtools.kythe.extractors.java.standalone.JavacWrapper",
visibility = ["//visibility:public"],
deps = [
":abstract_javac_wrapper",
@@ -31,7 +40,22 @@ java_library(
javacopts = [
"--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
],
+ runtime_deps = [
+ ":reflective_jdk_compatibility_shims",
+ ] + select_with_or({
+ (
+ "//buildenv/java:language_version_default",
+ "//buildenv/java:language_version_11",
+ ): [":jdk9_compatibility_shims"],
+ (
+ "//buildenv/java:language_version_17",
+ "//buildenv/java:language_version_19",
+ "//buildenv/java:language_version_20",
+ "//buildenv/java:language_version_21",
+ ): [":jdk15_compatibility_shims"],
+ }),
deps = [
+ ":jdk_compatibility_shims",
"//kythe/java/com/google/devtools/kythe/extractors/java",
"//kythe/java/com/google/devtools/kythe/extractors/shared",
"//kythe/java/com/google/devtools/kythe/extractors/shared:environment",
@@ -43,7 +67,115 @@ java_library(
],
)
+java_library(
+ name = "jdk_compatibility_shims",
+ srcs = ["JdkCompatibilityShims.java"],
+ javacopts = [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ ],
+ visibility = ["//visibility:private"],
+ deps = ["//kythe/java/com/google/devtools/kythe/util:ordered_compatibility_service"],
+)
+
+java_library(
+ name = "jdk9_compatibility_shims",
+ srcs = ["9/JdkCompatibilityShimsImpl.java"],
+ javacopts = [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ "-Xep:PackageLocation:OFF",
+ ],
+ target_compatible_with = select_with_or({
+ (
+ "//buildenv/java:language_version_default",
+ "//buildenv/java:language_version_11",
+ ): [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ visibility = ["//visibility:private"],
+ deps = [
+ ":jdk_compatibility_shims",
+ "//kythe/java/com/google/devtools/kythe/common:autoservice",
+ "//kythe/java/com/google/devtools/kythe/util:ordered_compatibility_service",
+ "//third_party/guava",
+ ],
+)
+
+java_library(
+ name = "jdk15_compatibility_shims",
+ srcs = ["15/JdkCompatibilityShimsImpl.java"],
+ javacopts = [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ "-Xep:PackageLocation:OFF",
+ ],
+ # This is incompatible with the default test configuration and
+ # bazel cquery doesn't work with objc_library targets.
+ tags = ["manual"],
+ target_compatible_with = select_with_or({
+ (
+ "//buildenv/java:language_version_17",
+ "//buildenv/java:language_version_19",
+ "//buildenv/java:language_version_20",
+ ): [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ visibility = ["//visibility:private"],
+ deps = [
+ ":jdk_compatibility_shims",
+ "//kythe/java/com/google/devtools/kythe/common:autoservice",
+ "//kythe/java/com/google/devtools/kythe/util:ordered_compatibility_service",
+ "//third_party/guava",
+ ],
+)
+
+java_library(
+ name = "jdk21_compatibility_shims",
+ srcs = ["21/JdkCompatibilityShimsImpl.java"],
+ javacopts = [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED",
+ "--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED",
+ "-Xep:PackageLocation:OFF",
+ ],
+ # This is incompatible with the default test configuration and
+ # bazel cquery doesn't work with objc_library targets.
+ tags = ["manual"],
+ target_compatible_with = select_with_or({
+ (
+ "//buildenv/java:language_version_21",
+ ): [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ visibility = ["//visibility:private"],
+ deps = [
+ ":jdk_compatibility_shims",
+ "//kythe/java/com/google/devtools/kythe/common:autoservice",
+ "//kythe/java/com/google/devtools/kythe/util:ordered_compatibility_service",
+ "//third_party/guava",
+ ],
+)
+
+java_library(
+ name = "reflective_jdk_compatibility_shims",
+ srcs = ["ReflectiveJdkCompatibilityShims.java"],
+ javacopts = [
+ "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED",
+ ] + select_with_or({
+ (
+ "//buildenv/java:language_version_21",
+ ): ["--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED"],
+ "//conditions:default": [],
+ }),
+ visibility = ["//visibility:private"],
+ deps = [
+ ":jdk_compatibility_shims",
+ "//kythe/java/com/google/devtools/kythe/common:autoservice",
+ "//kythe/java/com/google/devtools/kythe/util:ordered_compatibility_service",
+ "//third_party/guava",
+ ],
+)
+
bzl_library(
name = "aspect_bzl",
srcs = ["aspect.bzl"],
+ deps = ["@rules_java//java:utils"],
)
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/JavacWrapper.java
index 31bc66a7b..291145129 100644
--- a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/Javac9Wrapper.java
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/JavacWrapper.java
@@ -37,8 +37,12 @@ import java.util.List;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
-/** A class that wraps javac to extract compilation information and write it to an index file. */
-public class Javac9Wrapper extends AbstractJavacWrapper {
+/**
+ * A class that wraps javac to extract compilation information and write it to an index file.
+ *
+ * <p>This class works for Java 9 and later.
+ */
+public class JavacWrapper extends AbstractJavacWrapper {
@Override
protected Collection<CompilationDescription> processCompilation(
String[] arguments, JavaCompilationUnitExtractor javaCompilationUnitExtractor)
@@ -48,27 +52,7 @@ public class Javac9Wrapper extends AbstractJavacWrapper {
JavacFileManager fileManager = new JavacFileManager(context, true, null);
Arguments args = Arguments.instance(context);
- // JDK changed the signature of Arguments.init method, support both
- try {
- try {
- // JDK15+: the signature is
- // init(String, Iterable<String> args);
- Arguments.class.getMethod("init", String.class, Iterable.class)
- .invoke(args, "kythe_javac", (Object) Arrays.asList(arguments));
- } catch (NoSuchMethodException nsme) {
- // pre-JDK15:
- // init(String, String...);
- Arguments.class.getMethod("init", String.class,String[].class)
- .invoke(args, "kythe_javac", (Object)arguments);
- }
- } catch (NoSuchMethodException ns2) {
- System.err.printf("Cannot locate com.sun.tools.javac.main.Arguments.init method, JDK version %s\n", System.getProperty("java.version"));
- System.exit(2);
- } catch (InvocationTargetException|IllegalAccessException ex) {
- System.err.printf("Cannot call com.sun.tools.javac.main.Arguments.init (JDK version %s):\n%s\n", System.getProperty("java.version"), ex);
- System.exit(2);
- }
-
+ shims.initializeArguments(args, arguments);
fileManager.handleOptions(args.getDeferredFileManagerOptions());
Options options = Options.instance(context);
@@ -173,6 +157,6 @@ public class Javac9Wrapper extends AbstractJavacWrapper {
}
public static void main(String[] args) {
- new Javac9Wrapper().process(args);
+ new JavacWrapper().process(args);
}
}
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/JdkCompatibilityShims.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/JdkCompatibilityShims.java
new file mode 100644
index 000000000..3c042c5cf
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/JdkCompatibilityShims.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2022 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.extractors.java.standalone;
+
+import com.google.devtools.kythe.util.OrderedCompatibilityService;
+import com.sun.tools.javac.main.Arguments;
+import java.io.IOException;
+import java.util.List;
+import java.util.Optional;
+
+/** Shims for providing source-level compatibility between JDK versions. */
+public interface JdkCompatibilityShims extends OrderedCompatibilityService {
+ /** Loads the best service provider for this interface, if any. */
+ public static Optional<JdkCompatibilityShims> loadBest() {
+ return OrderedCompatibilityService.loadBest(JdkCompatibilityShims.class);
+ }
+
+ /** Parse the compiler arguments and returns them as an expanded list. */
+ List<String> parseCompilerArguments(String[] args) throws IOException;
+
+ /** Initialize the Arguments instance from the list of args. */
+ void initializeArguments(Arguments arguments, String[] args);
+}
diff --git a/kythe/java/com/google/devtools/kythe/extractors/java/standalone/ReflectiveJdkCompatibilityShims.java b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/ReflectiveJdkCompatibilityShims.java
new file mode 100644
index 000000000..80dacbe2f
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/extractors/java/standalone/ReflectiveJdkCompatibilityShims.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2022 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.extractors.java.standalone;
+
+import com.google.auto.service.AutoService;
+import com.google.common.collect.ImmutableList;
+import com.sun.tools.javac.main.Arguments;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+
+/** JdkCompatibilityShims implementation for JDK9-compatible releases. */
+@AutoService(JdkCompatibilityShims.class)
+public final class ReflectiveJdkCompatibilityShims implements JdkCompatibilityShims {
+ private static final Runtime.Version minVersion = Runtime.Version.parse("9");
+
+ public ReflectiveJdkCompatibilityShims() {}
+
+ @Override
+ public CompatibilityRange getCompatibleRange() {
+ return new CompatibilityRange(minVersion, Optional.empty(), CompatibilityLevel.FALLBACK);
+ }
+
+ @Override
+ @SuppressWarnings({"CheckedExceptionNotThrown", "unchecked"}) // Safe by specification.
+ public List<String> parseCompilerArguments(String[] args) throws IOException {
+ try {
+ Class<?> commandLine = loadCommandLineClass();
+ try {
+ // JDK15+: the signature is
+ // List<String> parse(List<String> args)
+ return (List<String>)
+ commandLine.getMethod("parse", List.class).invoke(null, (Object) Arrays.asList(args));
+ } catch (NoSuchMethodException nsme) {
+ // 9 <= JDK < 15: the signature is
+ // String[] parse(String[] args)
+ return Arrays.asList(
+ (String[]) commandLine.getMethod("parse", String[].class).invoke(null, (Object) args));
+ }
+ } catch (ClassCastException
+ | ClassNotFoundException
+ | InvocationTargetException
+ | IllegalAccessException
+ | NoSuchMethodException ex) {
+ throw new LinkageError(ex.getMessage(), ex);
+ }
+ }
+
+ @Override
+ public void initializeArguments(Arguments arguments, String[] args) {
+ try {
+ try {
+ // JDK15+: the signature is
+ // init(String, Iterable<String> args);
+ arguments
+ .getClass()
+ .getMethod("init", String.class, Iterable.class)
+ .invoke(arguments, "kythe_javac", (Object) Arrays.asList(args));
+ } catch (NoSuchMethodException nsme) {
+ // pre-JDK15:
+ // init(String, String...);
+ arguments
+ .getClass()
+ .getMethod("init", String.class, String[].class)
+ .invoke(arguments, "kythe_javac", (Object) args);
+ }
+ } catch (ClassCastException
+ | InvocationTargetException
+ | IllegalAccessException
+ | NoSuchMethodException ex) {
+ throw new LinkageError(ex.getMessage(), ex);
+ }
+ }
+
+ private static Class<?> loadCommandLineClass() throws ClassNotFoundException {
+ ImmutableList<String> classNames =
+ // < JDK21 the class is known as com.sun.tools.java.main.CommandLine
+ // >= JDK21 it's known as jdk.internal.opt.CommandLine
+ ImmutableList.of("com.sun.tools.javac.main.CommandLine", "jdk.internal.opt.CommandLine");
+ for (String name : classNames) {
+ try {
+ return ReflectiveJdkCompatibilityShims.class.getClassLoader().loadClass(name);
+ } catch (ClassNotFoundException unused) {
+ continue;
+ }
+ }
+ throw new ClassNotFoundException("unable to load JDK CommandLine class");
+ }
+}
diff --git a/kythe/java/com/google/devtools/kythe/util/OrderedCompatibilityService.java b/kythe/java/com/google/devtools/kythe/util/OrderedCompatibilityService.java
new file mode 100644
index 000000000..84db8c4cd
--- /dev/null
+++ b/kythe/java/com/google/devtools/kythe/util/OrderedCompatibilityService.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2022 The Kythe Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.devtools.kythe.util;
+
+import com.google.common.collect.Streams;
+import java.util.Comparator;
+import java.util.Optional;
+import java.util.ServiceLoader;
+
+/**
+ * OrderedCompatibilityService defines shared functionality between between JdkCompatibilityShim
+ * interfaces.
+ */
+public interface OrderedCompatibilityService {
+
+ /** The compatibility level of the provider. */
+ public enum CompatibilityLevel {
+ /** This provider is incompatible with the current runtime. */
+ INCOMPATIBLE,
+ /**
+ * This provider is compatible with the current runtime, but should only be used if a COMPATIBLE
+ * provider can't be found.
+ */
+ FALLBACK,
+ /**
+ * This provider is compatible with the current runtime and should be preferred over a fallback,
+ * if any.
+ */
+ COMPATIBLE
+ }
+
+ /** Indicates the range of runtime versions with which these shims are compatible. */
+ public static class CompatibilityRange {
+ private final Runtime.Version minVersion;
+ private final Optional<Runtime.Version> maxVersion;
+ private final CompatibilityLevel level;
+
+ public CompatibilityRange(Runtime.Version minVersion) {
+ this(minVersion, Optional.empty(), CompatibilityLevel.COMPATIBLE);
+ }
+
+ public CompatibilityRange(Runtime.Version minVersion, Runtime.Version maxVersion) {
+ this(minVersion, Optional.of(maxVersion), CompatibilityLevel.COMPATIBLE);
+ }
+
+ public CompatibilityRange(
+ Runtime.Version minVersion,
+ Optional<Runtime.Version> maxVersion,
+ CompatibilityLevel level) {
+ this.minVersion = minVersion;
+ this.maxVersion = maxVersion;
+ this.level = level;
+ }
+
+ /** Returns the minimum known compatible runtime version. */
+ public Runtime.Version getMinVersion() {
+ return minVersion;
+ }
+
+ /** Returns the maximum known compatible runtime version, if any. */
+ public Optional<Runtime.Version> getMaxVersion() {
+ return maxVersion;
+ }
+
+ /** Returns the compatibility level. */
+ public CompatibilityLevel getCompatibilityLevel() {
+ return level;
+ }
+ }
+
+ /** Returns the compatibility level of the service provider. */
+ CompatibilityRange getCompatibleRange();
+
+ public static <S extends OrderedCompatibilityService> Optional<S> loadBest(Class<S> klass) {
+ Runtime.Version version = Runtime.version();
+ return Streams.stream(ServiceLoader.load(klass))
+ // Filter out incompatible providers.
+ .filter(p -> isCompatible(version, p.getCompatibleRange()))
+ // Then find the best.
+ .max(OrderedCompatibilityService::compareProviders);
+ }
+
+ private static boolean isCompatible(Runtime.Version version, CompatibilityRange range) {
+ return range.getCompatibilityLevel() != CompatibilityLevel.INCOMPATIBLE
+ && version.compareToIgnoreOptional(range.getMinVersion()) >= 0
+ && range.getMaxVersion().map(max -> version.compareToIgnoreOptional(max) < 0).orElse(true);
+ }
+
+ private static int compareCompatibilityRanges(CompatibilityRange lhs, CompatibilityRange rhs) {
+ return Comparator.comparing(CompatibilityRange::getCompatibilityLevel)
+ .thenComparing(CompatibilityRange::getMinVersion, Runtime.Version::compareToIgnoreOptional)
+ .compare(lhs, rhs);
+ }
+
+ private static <S extends OrderedCompatibilityService> int compareProviders(S lhs, S rhs) {
+ return Comparator.comparing(
+ OrderedCompatibilityService::getCompatibleRange,
+ OrderedCompatibilityService::compareCompatibilityRanges)
+ .compare(lhs, rhs);
+ }
+}