blob: 357dc2c76e8471405a55e944d8703fbea80d805a [file] [log] [blame] [edit]
// 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)...)
}