Replace annotation_processors with plugins
Follow bazel's modules for annotation processors by introducing
a java_plugin module type that can contain extra metadata about
the annotation processor, the processor class and a flag to
specify if the annotation processor is compatible with the
turbine optimization. Deprecate the annotation_processors
property, which took a list of java_library_host modules, in
favor of the plugins property, which takes a list of java_plugin
modules. The annotation_processors property will be removed
once all uses have been replaced with plugins.
Bug: 77284273
Test: plugin_test.go
Test: m caliper
Change-Id: I37c1e80eba71ae2d6a06199fb102194a51994989
diff --git a/java/builder.go b/java/builder.go
index 40f72e1..67e8235 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -44,7 +44,7 @@
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
`(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` +
`${config.SoongJavacWrapper} ${config.JavacWrapper}${config.JavacCmd} ${config.JavacHeapFlags} ${config.CommonJdkFlags} ` +
- `$processorpath $javacFlags $bootClasspath $classpath ` +
+ `$processorpath $processor $javacFlags $bootClasspath $classpath ` +
`-source $javaVersion -target $javaVersion ` +
`-d $outDir -s $annoDir @$out.rsp @$srcJarDir/list ; fi ) && ` +
`${config.SoongZipCmd} -jar -o $out -C $outDir -D $outDir`,
@@ -57,7 +57,7 @@
Rspfile: "$out.rsp",
RspfileContent: "$in",
},
- "javacFlags", "bootClasspath", "classpath", "processorpath", "srcJars", "srcJarDir",
+ "javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJars", "srcJarDir",
"outDir", "annoDir", "javaVersion")
turbine = pctx.AndroidStaticRule("turbine",
@@ -141,6 +141,7 @@
bootClasspath classpath
classpath classpath
processorPath classpath
+ processor string
systemModules classpath
aidlFlags string
javaVersion string
@@ -254,6 +255,12 @@
deps = append(deps, flags.classpath...)
deps = append(deps, flags.processorPath...)
+ // TODO(b/77284273): pass -processor:none if no plugins are listed
+ processor := ""
+ if flags.processor != "" {
+ processor = "-processor " + flags.processor
+ }
+
srcJarDir := "srcjars"
outDir := "classes"
annoDir := "anno"
@@ -274,6 +281,7 @@
"bootClasspath": bootClasspath,
"classpath": flags.classpath.FormJavaClassPath("-classpath"),
"processorpath": flags.processorPath.FormJavaClassPath("-processorpath"),
+ "processor": processor,
"srcJars": strings.Join(srcJars.Strings(), " "),
"srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(),
"outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(),
diff --git a/java/java.go b/java/java.go
index e64b99e..7014668 100644
--- a/java/java.go
+++ b/java/java.go
@@ -114,11 +114,11 @@
// If set to true, include sources used to compile the module in to the final jar
Include_srcs *bool
- // List of modules to use as annotation processors
+ // List of modules to use as annotation processors. Deprecated, use plugins instead.
Annotation_processors []string
- // List of classes to pass to javac to use as annotation processors
- Annotation_processor_classes []string
+ // List of modules to use as annotation processors
+ Plugins []string
// The number of Java source entries each Javac instance can process
Javac_shard_size *int64
@@ -377,6 +377,7 @@
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
annoTag = dependencyTag{name: "annotation processor"}
+ pluginTag = dependencyTag{name: "plugin"}
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
frameworkResTag = dependencyTag{name: "framework-res"}
@@ -474,6 +475,10 @@
{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
}, annoTag, j.properties.Annotation_processors...)
+ ctx.AddFarVariationDependencies([]blueprint.Variation{
+ {Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant},
+ }, pluginTag, j.properties.Plugins...)
+
android.ExtractSourcesDeps(ctx, j.properties.Srcs)
android.ExtractSourcesDeps(ctx, j.properties.Exclude_srcs)
android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
@@ -563,6 +568,7 @@
classpath classpath
bootClasspath classpath
processorPath classpath
+ processorClasses []string
staticJars android.Paths
staticHeaderJars android.Paths
staticResourceJars android.Paths
@@ -573,6 +579,8 @@
aidlPreprocess android.OptionalPath
kotlinStdlib android.Paths
kotlinAnnotations android.Paths
+
+ disableTurbine bool
}
func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) {
@@ -712,6 +720,16 @@
j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
case annoTag:
deps.processorPath = append(deps.processorPath, dep.ImplementationAndResourcesJars()...)
+ case pluginTag:
+ if plugin, ok := dep.(*Plugin); ok {
+ deps.processorPath = append(deps.processorPath, dep.ImplementationAndResourcesJars()...)
+ if plugin.pluginProperties.Processor_class != nil {
+ deps.processorClasses = append(deps.processorClasses, *plugin.pluginProperties.Processor_class)
+ }
+ deps.disableTurbine = deps.disableTurbine || Bool(plugin.pluginProperties.Generates_api)
+ } else {
+ ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
+ }
case frameworkResTag:
if (ctx.ModuleName() == "framework") || (ctx.ModuleName() == "framework-annotation-proc") {
// framework.jar has a one-off dependency on the R.java and Manifest.java files
@@ -859,6 +877,8 @@
flags.classpath = append(flags.classpath, deps.classpath...)
flags.processorPath = append(flags.processorPath, deps.processorPath...)
+ flags.processor = strings.Join(deps.processorClasses, ",")
+
if len(flags.bootClasspath) == 0 && ctx.Host() && flags.javaVersion != "1.9" &&
!Bool(j.properties.No_standard_libs) &&
inList(flags.javaVersion, []string{"1.6", "1.7", "1.8"}) {
@@ -1020,7 +1040,7 @@
j.compiledSrcJars = srcJars
enable_sharding := false
- if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
+ if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !deps.disableTurbine {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enable_sharding = true
// Formerly, there was a check here that prevented annotation processors
diff --git a/java/java_test.go b/java/java_test.go
index 9f805bb..a0d962e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -83,6 +83,7 @@
ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(SystemModulesFactory))
ctx.RegisterModuleType("java_genrule", android.ModuleFactoryAdaptor(genRuleFactory))
+ ctx.RegisterModuleType("java_plugin", android.ModuleFactoryAdaptor(PluginFactory))
ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(android.FileGroupFactory))
ctx.RegisterModuleType("genrule", android.ModuleFactoryAdaptor(genrule.GenRuleFactory))
ctx.RegisterModuleType("droiddoc", android.ModuleFactoryAdaptor(DroiddocFactory))
diff --git a/java/kotlin.go b/java/kotlin.go
index c72f2de..1b2e642 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -87,6 +87,7 @@
`-P plugin:org.jetbrains.kotlin.kapt3:aptMode=stubsAndApt ` +
`-P plugin:org.jetbrains.kotlin.kapt3:javacArguments=$encodedJavacFlags ` +
`$kaptProcessorPath ` +
+ `$kaptProcessor ` +
`-Xbuild-file=$kotlinBuildFile && ` +
`${config.SoongZipCmd} -jar -o $out -C $kaptDir/sources -D $kaptDir/sources`,
CommandDeps: []string{
@@ -100,7 +101,8 @@
Rspfile: "$out.rsp",
RspfileContent: `$in`,
},
- "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile")
+ "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
+ "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile")
// kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs
// annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be
@@ -117,6 +119,11 @@
kaptProcessorPath := flags.processorPath.FormTurbineClasspath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
+ kaptProcessor := ""
+ if flags.processor != "" {
+ kaptProcessor = "-P plugin:org.jetbrains.kotlin.kapt3:processor=" + flags.processor
+ }
+
encodedJavacFlags := kaptEncodeFlags([][2]string{
{"-source", flags.javaVersion},
{"-target", flags.javaVersion},
@@ -135,6 +142,7 @@
"srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(),
"kotlinBuildFile": android.PathForModuleOut(ctx, "kapt", "build.xml").String(),
"kaptProcessorPath": strings.Join(kaptProcessorPath, " "),
+ "kaptProcessor": kaptProcessor,
"kaptDir": android.PathForModuleOut(ctx, "kapt/gen").String(),
"encodedJavacFlags": encodedJavacFlags,
},
diff --git a/java/kotlin_test.go b/java/kotlin_test.go
index 1069f42..3deea13 100644
--- a/java/kotlin_test.go
+++ b/java/kotlin_test.go
@@ -87,10 +87,10 @@
java_library {
name: "foo",
srcs: ["a.java", "b.kt"],
- annotation_processors: ["bar"],
+ plugins: ["bar"],
}
- java_library_host {
+ java_plugin {
name: "bar",
}
`)
diff --git a/java/plugin.go b/java/plugin.go
new file mode 100644
index 0000000..a5e8292
--- /dev/null
+++ b/java/plugin.go
@@ -0,0 +1,50 @@
+// Copyright 2019 Google Inc. 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 java
+
+import "android/soong/android"
+
+func init() {
+ android.RegisterModuleType("java_plugin", PluginFactory)
+}
+
+// A java_plugin module describes a host java library that will be used by javac as an annotation processor.
+func PluginFactory() android.Module {
+ module := &Plugin{}
+
+ module.AddProperties(
+ &module.Module.properties,
+ &module.Module.protoProperties,
+ &module.pluginProperties)
+
+ InitJavaModule(module, android.HostSupported)
+ return module
+}
+
+type Plugin struct {
+ Library
+
+ pluginProperties PluginProperties
+}
+
+type PluginProperties struct {
+ // The optional name of the class that javac will use to run the annotation processor.
+ Processor_class *string
+
+ // If true, assume the annotation processor will generate classes that are referenced from outside the module.
+ // This necessitates disabling the turbine optimization on modules that use this plugin, which will reduce
+ // parallelism and cause more recompilation for modules that depend on modules that use this plugin.
+ Generates_api *bool
+}
diff --git a/java/plugin_test.go b/java/plugin_test.go
new file mode 100644
index 0000000..7aa0164
--- /dev/null
+++ b/java/plugin_test.go
@@ -0,0 +1,124 @@
+// Copyright 2019 Google Inc. 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 java
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestNoPlugin(t *testing.T) {
+ ctx := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+ `)
+
+ javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+ turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
+
+ if turbine.Rule == nil {
+ t.Errorf("expected turbine to be enabled")
+ }
+
+ if javac.Args["processsorpath"] != "" {
+ t.Errorf("want empty processorpath, got %q", javac.Args["processorpath"])
+ }
+
+ // TODO(b/77284273): test for -processor:none if no plugins are enabled
+ if javac.Args["processor"] != "" {
+ t.Errorf("want no -processor argument, got %q", javac.Args["processor"])
+ }
+}
+
+func TestPlugin(t *testing.T) {
+ ctx := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ plugins: ["bar"],
+ }
+
+ java_plugin {
+ name: "bar",
+ processor_class: "com.bar",
+ srcs: ["b.java"],
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+
+ javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+ turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
+
+ if turbine.Rule == nil {
+ t.Errorf("expected turbine to be enabled")
+ }
+
+ bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+
+ if !inList(bar, javac.Implicits.Strings()) {
+ t.Errorf("foo implicits %v does not contain %q", javac.Implicits.Strings(), bar)
+ }
+
+ if javac.Args["processorpath"] != "-processorpath "+bar {
+ t.Errorf("foo processorpath %q != '-processorpath %s'", javac.Args["processorpath"], bar)
+ }
+
+ if javac.Args["processor"] != "-processor com.bar" {
+ t.Errorf("foo processor %q != '-processor com.bar'", javac.Args["processor"])
+ }
+}
+
+func TestPluginGeneratesApi(t *testing.T) {
+ ctx := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ plugins: ["bar"],
+ }
+
+ java_plugin {
+ name: "bar",
+ processor_class: "com.bar",
+ generates_api: true,
+ srcs: ["b.java"],
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+
+ javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
+ turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine")
+
+ if turbine.Rule != nil {
+ t.Errorf("expected turbine to be disabled")
+ }
+
+ bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String()
+
+ if !inList(bar, javac.Implicits.Strings()) {
+ t.Errorf("foo implicits %v does not contain %q", javac.Implicits.Strings(), bar)
+ }
+
+ if javac.Args["processorpath"] != "-processorpath "+bar {
+ t.Errorf("foo processorpath %q != '-processorpath %s'", javac.Args["processorpath"], bar)
+ }
+
+ if javac.Args["processor"] != "-processor com.bar" {
+ t.Errorf("foo processor %q != '-processor com.bar'", javac.Args["processor"])
+ }
+}