| // 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 ( |
| "fmt" |
| "io" |
| |
| "android/soong/android" |
| "android/soong/dexpreopt" |
| |
| "github.com/google/blueprint/depset" |
| "github.com/google/blueprint/proptools" |
| ) |
| |
| type GenruleCombiner struct { |
| android.ModuleBase |
| android.DefaultableModuleBase |
| |
| genruleCombinerProperties GenruleCombinerProperties |
| |
| headerJars android.Paths |
| implementationJars android.Paths |
| implementationAndResourceJars android.Paths |
| resourceJars android.Paths |
| aconfigProtoFiles android.Paths |
| |
| srcJarArgs []string |
| srcJarDeps android.Paths |
| |
| headerDirs android.Paths |
| |
| combinedHeaderJar android.Path |
| combinedImplementationJar android.Path |
| } |
| |
| type GenruleCombinerProperties struct { |
| // List of modules whose implementation (and resources) jars will be visible to modules |
| // that depend on this module. |
| Static_libs proptools.Configurable[[]string] `android:"arch_variant"` |
| |
| // List of modules whose header jars will be visible to modules that depend on this module. |
| Headers proptools.Configurable[[]string] `android:"arch_variant"` |
| } |
| |
| // java_genrule_combiner provides the implementation and resource jars from `static_libs`, with |
| // the header jars from `headers`. |
| // |
| // This is useful when a java_genrule is used to change the implementation of a java library |
| // without requiring a change in the header jars. |
| func GenruleCombinerFactory() android.Module { |
| module := &GenruleCombiner{} |
| |
| module.AddProperties(&module.genruleCombinerProperties) |
| InitJavaModule(module, android.HostAndDeviceSupported) |
| return module |
| } |
| |
| var genruleCombinerHeaderDepTag = dependencyTag{name: "genrule_combiner_header"} |
| |
| func (j *GenruleCombiner) DepsMutator(ctx android.BottomUpMutatorContext) { |
| ctx.AddVariationDependencies(nil, staticLibTag, |
| j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) |
| ctx.AddVariationDependencies(nil, genruleCombinerHeaderDepTag, |
| j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) |
| } |
| |
| func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) { |
| if len(j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)) < 1 { |
| ctx.PropertyErrorf("static_libs", "at least one dependency is required") |
| } |
| |
| if len(j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)) < 1 { |
| ctx.PropertyErrorf("headers", "at least one dependency is required") |
| } |
| |
| var transitiveHeaderJars []depset.DepSet[android.Path] |
| var transitiveImplementationJars []depset.DepSet[android.Path] |
| var transitiveResourceJars []depset.DepSet[android.Path] |
| var sdkVersion android.SdkSpec |
| var stubsLinkType StubsLinkType |
| moduleWithSdkDepInfo := &ModuleWithSdkDepInfo{} |
| |
| // Collect the headers first, so that aconfig flag values for the libraries will override |
| // values from the headers (if they are different). |
| ctx.VisitDirectDepsWithTag(genruleCombinerHeaderDepTag, func(m android.Module) { |
| if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { |
| j.headerJars = append(j.headerJars, dep.HeaderJars...) |
| |
| j.srcJarArgs = append(j.srcJarArgs, dep.SrcJarArgs...) |
| j.srcJarDeps = append(j.srcJarDeps, dep.SrcJarDeps...) |
| j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) |
| sdkVersion = dep.SdkVersion |
| stubsLinkType = dep.StubsLinkType |
| *moduleWithSdkDepInfo = *dep.ModuleWithSdkDepInfo |
| |
| transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars) |
| } else if dep, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { |
| j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) |
| } else { |
| ctx.PropertyErrorf("headers", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) |
| } |
| }) |
| ctx.VisitDirectDepsWithTag(staticLibTag, func(m android.Module) { |
| if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { |
| j.implementationJars = append(j.implementationJars, dep.ImplementationJars...) |
| j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) |
| j.resourceJars = append(j.resourceJars, dep.ResourceJars...) |
| |
| transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars) |
| transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars) |
| j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) |
| } else if dep, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok { |
| // This is provided by `java_genrule` modules. |
| j.implementationJars = append(j.implementationJars, dep.DefaultOutputFiles...) |
| j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.DefaultOutputFiles...) |
| stubsLinkType = Implementation |
| } else { |
| ctx.PropertyErrorf("static_libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) |
| } |
| }) |
| |
| jarName := ctx.ModuleName() + ".jar" |
| |
| if len(j.implementationAndResourceJars) > 1 { |
| outputFile := android.PathForModuleOut(ctx, "combined", jarName) |
| TransformJarsToJar(ctx, outputFile, "combine", j.implementationAndResourceJars, |
| android.OptionalPath{}, false, nil, nil) |
| j.combinedImplementationJar = outputFile |
| } else if len(j.implementationAndResourceJars) == 1 { |
| j.combinedImplementationJar = j.implementationAndResourceJars[0] |
| } |
| |
| if len(j.headerJars) > 1 { |
| outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) |
| TransformJarsToJar(ctx, outputFile, "turbine combine", j.headerJars, |
| android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) |
| j.combinedHeaderJar = outputFile |
| j.headerDirs = append(j.headerDirs, android.PathForModuleOut(ctx, "turbine-combined")) |
| } else if len(j.headerJars) == 1 { |
| j.combinedHeaderJar = j.headerJars[0] |
| } |
| |
| javaInfo := &JavaInfo{ |
| HeaderJars: android.Paths{j.combinedHeaderJar}, |
| LocalHeaderJars: android.Paths{j.combinedHeaderJar}, |
| TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.Paths{j.combinedHeaderJar}, transitiveHeaderJars), |
| TransitiveStaticLibsImplementationJars: depset.New(depset.PREORDER, android.Paths{j.combinedImplementationJar}, transitiveImplementationJars), |
| TransitiveStaticLibsResourceJars: depset.New(depset.PREORDER, nil, transitiveResourceJars), |
| GeneratedSrcjars: android.Paths{j.combinedImplementationJar}, |
| ImplementationAndResourcesJars: android.Paths{j.combinedImplementationJar}, |
| ImplementationJars: android.Paths{j.combinedImplementationJar}, |
| ModuleWithSdkDepInfo: moduleWithSdkDepInfo, |
| ResourceJars: j.resourceJars, |
| OutputFile: j.combinedImplementationJar, |
| SdkVersion: sdkVersion, |
| SrcJarArgs: j.srcJarArgs, |
| SrcJarDeps: j.srcJarDeps, |
| StubsLinkType: stubsLinkType, |
| AconfigIntermediateCacheOutputPaths: j.aconfigProtoFiles, |
| } |
| setExtraJavaInfo(ctx, j, javaInfo) |
| ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, "") |
| ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, android.DefaultDistTag) |
| ctx.SetOutputFiles(javaInfo.ImplementationAndResourcesJars, ".jar") |
| ctx.SetOutputFiles(javaInfo.HeaderJars, ".hjar") |
| android.SetProvider(ctx, JavaInfoProvider, javaInfo) |
| |
| } |
| |
| func (j *GenruleCombiner) GeneratedSourceFiles() android.Paths { |
| return append(android.Paths{}, j.combinedImplementationJar) |
| } |
| |
| func (j *GenruleCombiner) GeneratedHeaderDirs() android.Paths { |
| return append(android.Paths{}, j.headerDirs...) |
| } |
| |
| func (j *GenruleCombiner) GeneratedDeps() android.Paths { |
| return append(android.Paths{}, j.combinedImplementationJar) |
| } |
| |
| func (j *GenruleCombiner) Srcs() android.Paths { |
| return append(android.Paths{}, j.implementationAndResourceJars...) |
| } |
| |
| func (j *GenruleCombiner) HeaderJars() android.Paths { |
| return j.headerJars |
| } |
| |
| func (j *GenruleCombiner) ImplementationAndResourcesJars() android.Paths { |
| return j.implementationAndResourceJars |
| } |
| |
| func (j *GenruleCombiner) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path { |
| return nil |
| } |
| |
| func (j *GenruleCombiner) DexJarInstallPath() android.Path { |
| return nil |
| } |
| |
| func (j *GenruleCombiner) AidlIncludeDirs() android.Paths { |
| return nil |
| } |
| |
| func (j *GenruleCombiner) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { |
| return nil |
| } |
| |
| func (j *GenruleCombiner) JacocoReportClassesFile() android.Path { |
| return nil |
| } |
| |
| func (j *GenruleCombiner) AndroidMk() android.AndroidMkData { |
| return android.AndroidMkData{ |
| Class: "JAVA_LIBRARIES", |
| OutputFile: android.OptionalPathForPath(j.combinedImplementationJar), |
| // Make does not support Windows Java modules |
| Disabled: j.Os() == android.Windows, |
| Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", |
| Extra: []android.AndroidMkExtraFunc{ |
| func(w io.Writer, outputFile android.Path) { |
| fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") |
| fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", j.combinedHeaderJar.String()) |
| fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", j.combinedImplementationJar.String()) |
| }, |
| }, |
| } |
| } |
| |
| // implement the following interface for IDE completion. |
| var _ android.IDEInfo = (*GenruleCombiner)(nil) |
| |
| func (j *GenruleCombiner) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) { |
| ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) |
| ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) |
| ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) |
| ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) |
| } |