platform_build_soong/java/java.go
Colin Cross 6510f91a1c Replace ModuleContext.AConfig() with Config()
AConfig() now duplicates Config().  Replace the uses of AConfig()
with Config().  Leave AConfig() for now until code in other
projects is cleaned up.

Test: m checkbuild
Change-Id: Ic88be643049d21dba45dbd1a65588ed94bf43bdc
2017-11-30 00:44:18 +00:00

1147 lines
34 KiB
Go

// Copyright 2015 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
// This file contains the module types for compiling Java for Android, and converts the properties
// into the flags and filenames necessary to pass to the Module. The final creation of the rules
// is handled in builder.go
import (
"fmt"
"path/filepath"
"strconv"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/java/config"
)
func init() {
android.RegisterModuleType("java_defaults", defaultsFactory)
android.RegisterModuleType("java_library", LibraryFactory(true))
android.RegisterModuleType("java_library_static", LibraryFactory(false))
android.RegisterModuleType("java_library_host", LibraryHostFactory)
android.RegisterModuleType("java_binary", BinaryFactory)
android.RegisterModuleType("java_binary_host", BinaryHostFactory)
android.RegisterModuleType("java_import", ImportFactory)
android.RegisterModuleType("java_import_host", ImportFactoryHost)
android.RegisterModuleType("android_app", AndroidAppFactory)
android.RegisterSingletonType("logtags", LogtagsSingleton)
}
// TODO:
// Autogenerated files:
// Renderscript
// Post-jar passes:
// Proguard
// Rmtypedefs
// DroidDoc
// Findbugs
type CompilerProperties struct {
// list of source files used to compile the Java module. May be .java, .logtags, .proto,
// or .aidl files.
Srcs []string `android:"arch_variant"`
// list of source files that should not be used to build the Java module.
// This is most useful in the arch/multilib variants to remove non-common files
Exclude_srcs []string `android:"arch_variant"`
// list of directories containing Java resources
Java_resource_dirs []string `android:"arch_variant"`
// list of directories that should be excluded from java_resource_dirs
Exclude_java_resource_dirs []string `android:"arch_variant"`
// list of files to use as Java resources
Java_resources []string `android:"arch_variant"`
// list of files that should be excluded from java_resources
Exclude_java_resources []string `android:"arch_variant"`
// don't build against the default libraries (bootclasspath, legacy-test, core-junit,
// ext, and framework for device targets)
No_standard_libs *bool
// don't build against the framework libraries (legacy-test, core-junit,
// ext, and framework for device targets)
No_framework_libs *bool
// list of module-specific flags that will be used for javac compiles
Javacflags []string `android:"arch_variant"`
// list of of java libraries that will be in the classpath
Libs []string `android:"arch_variant"`
// list of java libraries that will be compiled into the resulting jar
Static_libs []string `android:"arch_variant"`
// manifest file to be included in resulting jar
Manifest *string
// if not blank, run jarjar using the specified rules file
Jarjar_rules *string `android:"arch_variant"`
// If not blank, set the java version passed to javac as -source and -target
Java_version *string
// If set to false, don't allow this module to be installed. Defaults to true.
Installable *bool
// 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
Annotation_processors []string
// List of classes to pass to javac to use as annotation processors
Annotation_processor_classes []string
// The number of Java source entries each Javac instance can process
Javac_shard_size *int64
Openjdk9 struct {
// List of source files that should only be used when passing -source 1.9
Srcs []string
// List of javac flags that should only be used when passing -source 1.9
Javacflags []string
}
Jacoco struct {
// List of classes to include for instrumentation with jacoco to collect coverage
// information at runtime when building with coverage enabled. If unset defaults to all
// classes.
// Supports '*' as the last character of an entry in the list as a wildcard match.
// If preceded by '.' it matches all classes in the package and subpackages, otherwise
// it matches classes in the package that have the class name as a prefix.
Include_filter []string
// List of classes to exclude from instrumentation with jacoco to collect coverage
// information at runtime when building with coverage enabled. Overrides classes selected
// by the include_filter property.
// Supports '*' as the last character of an entry in the list as a wildcard match.
// If preceded by '.' it matches all classes in the package and subpackages, otherwise
// it matches classes in the package that have the class name as a prefix.
Exclude_filter []string
}
Instrument bool `blueprint:"mutated"`
}
type CompilerDeviceProperties struct {
// list of module-specific flags that will be used for dex compiles
Dxflags []string `android:"arch_variant"`
// if not blank, set to the version of the sdk to compile against
Sdk_version *string
Aidl struct {
// Top level directories to pass to aidl tool
Include_dirs []string
// Directories rooted at the Android.bp file to pass to aidl tool
Local_include_dirs []string
// directories that should be added as include directories for any aidl sources of modules
// that depend on this module, as well as to aidl for this module.
Export_include_dirs []string
}
// If true, export a copy of the module as a -hostdex module for host testing.
Hostdex *bool
// If false, prevent dexpreopting and stripping the dex file from the final jar. Defaults to
// true.
Dex_preopt *bool
// When targeting 1.9, override the modules to use with --system
System_modules *string
}
// Module contains the properties and members used by all java module types
type Module struct {
android.ModuleBase
android.DefaultableModuleBase
properties CompilerProperties
protoProperties android.ProtoProperties
deviceProperties CompilerDeviceProperties
// header jar file suitable for inserting into the bootclasspath/classpath of another compile
headerJarFile android.Path
// full implementation jar file suitable for static dependency of another module compile
implementationJarFile android.Path
// output file containing classes.dex
dexJarFile android.Path
// output file containing uninstrumented classes that will be instrumented by jacoco
jacocoReportClassesFile android.Path
// output file suitable for installing or running
outputFile android.Path
exportAidlIncludeDirs android.Paths
logtagsSrcs android.Paths
// installed file for binary dependency
installFile android.Path
}
type Dependency interface {
HeaderJars() android.Paths
ImplementationJars() android.Paths
AidlIncludeDirs() android.Paths
}
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
android.InitAndroidArchModule(module, hod, android.MultilibCommon)
android.InitDefaultableModule(module)
}
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
}
var (
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
frameworkResTag = dependencyTag{name: "framework-res"}
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
)
type sdkDep struct {
useModule, useFiles, useDefaultLibs, invalidVersion bool
module string
systemModules string
jar android.Path
aidl android.Path
}
func sdkStringToNumber(ctx android.BaseContext, v string) int {
switch v {
case "", "current", "system_current", "test_current":
return 10000
default:
if i, err := strconv.Atoi(v); err != nil {
ctx.PropertyErrorf("sdk_version", "invalid sdk version")
return -1
} else {
return i
}
}
}
func decodeSdkDep(ctx android.BaseContext, v string) sdkDep {
i := sdkStringToNumber(ctx, v)
if i == -1 {
// Invalid sdk version, error handled by sdkStringToNumber.
return sdkDep{}
}
toFile := func(v string) sdkDep {
dir := filepath.Join("prebuilts/sdk", v)
jar := filepath.Join(dir, "android.jar")
aidl := filepath.Join(dir, "framework.aidl")
jarPath := android.ExistentPathForSource(ctx, "sdkdir", jar)
aidlPath := android.ExistentPathForSource(ctx, "sdkdir", aidl)
if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
return sdkDep{
invalidVersion: true,
module: "sdk_v" + v,
}
}
if !jarPath.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar)
return sdkDep{}
}
if !aidlPath.Valid() {
ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl)
return sdkDep{}
}
return sdkDep{
useFiles: true,
jar: jarPath.Path(),
aidl: aidlPath.Path(),
}
}
//toModule := func(m string) sdkDep {
// return sdkDep{
// useModule: true,
// module: m,
// systemModules: m + "_system_modules",
// }
//}
if ctx.Config().UnbundledBuild() && v != "" {
return toFile(v)
}
switch v {
case "":
return sdkDep{
useDefaultLibs: true,
}
// TODO(ccross): re-enable these once we generate stubs, until then
// use the stubs in prebuilts/sdk/*current
//case "current":
// return toModule("android_stubs_current")
//case "system_current":
// return toModule("android_system_stubs_current")
//case "test_current":
// return toModule("android_test_stubs_current")
default:
return toFile(v)
}
}
func (j *Module) deps(ctx android.BottomUpMutatorContext) {
if ctx.Device() {
if !proptools.Bool(j.properties.No_standard_libs) {
sdkDep := decodeSdkDep(ctx, String(j.deviceProperties.Sdk_version))
if sdkDep.useDefaultLibs {
ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
if ctx.Config().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, config.DefaultSystemModules)
}
if !proptools.Bool(j.properties.No_framework_libs) {
ctx.AddDependency(ctx.Module(), libTag, config.DefaultLibraries...)
}
} else if sdkDep.useModule {
if ctx.Config().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, sdkDep.systemModules)
}
ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
}
} else if j.deviceProperties.System_modules == nil {
ctx.PropertyErrorf("no_standard_libs",
"system_modules is required to be set when no_standard_libs is true, did you mean no_framework_libs?")
} else if *j.deviceProperties.System_modules != "none" && ctx.Config().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, *j.deviceProperties.System_modules)
}
}
ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
ctx.AddDependency(ctx.Module(), staticLibTag, j.properties.Static_libs...)
ctx.AddDependency(ctx.Module(), libTag, j.properties.Annotation_processors...)
android.ExtractSourcesDeps(ctx, j.properties.Srcs)
android.ExtractSourcesDeps(ctx, j.properties.Java_resources)
if j.hasSrcExt(".proto") {
protoDeps(ctx, &j.protoProperties)
}
if j.hasSrcExt(".kt") {
// TODO(ccross): move this to a mutator pass that can tell if generated sources contain
// Kotlin files
ctx.AddDependency(ctx.Module(), kotlinStdlibTag, "kotlin-stdlib")
}
}
func hasSrcExt(srcs []string, ext string) bool {
for _, src := range srcs {
if filepath.Ext(src) == ext {
return true
}
}
return false
}
func shardPaths(paths android.Paths, shardSize int) []android.Paths {
ret := make([]android.Paths, 0, (len(paths)+shardSize-1)/shardSize)
for len(paths) > shardSize {
ret = append(ret, paths[0:shardSize])
paths = paths[shardSize:]
}
if len(paths) > 0 {
ret = append(ret, paths)
}
return ret
}
func (j *Module) hasSrcExt(ext string) bool {
return hasSrcExt(j.properties.Srcs, ext)
}
func (j *Module) aidlFlags(ctx android.ModuleContext, aidlPreprocess android.OptionalPath,
aidlIncludeDirs android.Paths) []string {
aidlIncludes := android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Local_include_dirs)
aidlIncludes = append(aidlIncludes,
android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)...)
aidlIncludes = append(aidlIncludes,
android.PathsForSource(ctx, j.deviceProperties.Aidl.Include_dirs)...)
var flags []string
if aidlPreprocess.Valid() {
flags = append(flags, "-p"+aidlPreprocess.String())
} else {
flags = append(flags, android.JoinWithPrefix(aidlIncludeDirs.Strings(), "-I"))
}
flags = append(flags, android.JoinWithPrefix(j.exportAidlIncludeDirs.Strings(), "-I"))
flags = append(flags, android.JoinWithPrefix(aidlIncludes.Strings(), "-I"))
flags = append(flags, "-I"+android.PathForModuleSrc(ctx).String())
if src := android.ExistentPathForSource(ctx, "", ctx.ModuleDir(), "src"); src.Valid() {
flags = append(flags, "-I"+src.String())
}
return flags
}
type deps struct {
classpath android.Paths
bootClasspath android.Paths
staticJars android.Paths
staticHeaderJars android.Paths
staticJarResources android.Paths
aidlIncludeDirs android.Paths
srcJars android.Paths
systemModules android.Path
aidlPreprocess android.OptionalPath
kotlinStdlib android.Paths
}
func (j *Module) collectDeps(ctx android.ModuleContext) deps {
var deps deps
sdkDep := decodeSdkDep(ctx, String(j.deviceProperties.Sdk_version))
if sdkDep.invalidVersion {
ctx.AddMissingDependencies([]string{sdkDep.module})
} else if sdkDep.useFiles {
// sdkDep.jar is actually equivalent to turbine header.jar.
deps.classpath = append(deps.classpath, sdkDep.jar)
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, sdkDep.aidl)
}
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
dep, _ := module.(Dependency)
if dep == nil {
switch tag {
case android.DefaultsDepTag, android.SourceDepTag:
// Nothing to do
case systemModulesTag:
if deps.systemModules != nil {
panic("Found two system module dependencies")
}
sm := module.(*SystemModules)
if sm.outputFile == nil {
panic("Missing directory for system module dependency")
}
deps.systemModules = sm.outputFile
default:
ctx.ModuleErrorf("depends on non-java module %q", otherName)
}
return
}
switch tag {
case bootClasspathTag:
deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
case libTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
case staticLibTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
case frameworkResTag:
if ctx.ModuleName() == "framework" {
// framework.jar has a one-off dependency on the R.java and Manifest.java files
// generated by framework-res.apk
deps.srcJars = append(deps.srcJars, dep.(*AndroidApp).aaptSrcJar)
}
case kotlinStdlibTag:
deps.kotlinStdlib = dep.HeaderJars()
default:
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
}
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
})
return deps
}
func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaBuilderFlags {
var flags javaBuilderFlags
// javac flags.
javacFlags := j.properties.Javacflags
if ctx.Config().TargetOpenJDK9() {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
}
if ctx.Config().MinimizeJavaDebugInfo() {
// Override the -g flag passed globally to remove local variable debug info to reduce
// disk and memory usage.
javacFlags = append(javacFlags, "-g:source,lines")
}
if len(javacFlags) > 0 {
// optimization.
ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
flags.javacFlags = "$javacFlags"
}
// javaVersion flag.
sdk := sdkStringToNumber(ctx, String(j.deviceProperties.Sdk_version))
if j.properties.Java_version != nil {
flags.javaVersion = *j.properties.Java_version
} else if ctx.Device() && sdk <= 23 {
flags.javaVersion = "1.7"
} else if ctx.Device() && sdk <= 26 || !ctx.Config().TargetOpenJDK9() {
flags.javaVersion = "1.8"
} else if ctx.Device() && String(j.deviceProperties.Sdk_version) != "" && sdk == 10000 {
// TODO(ccross): once we generate stubs we should be able to use 1.9 for sdk_version: "current"
flags.javaVersion = "1.8"
} else {
flags.javaVersion = "1.9"
}
// classpath
flags.bootClasspath.AddPaths(deps.bootClasspath)
flags.classpath.AddPaths(deps.classpath)
// systemModules
if deps.systemModules != nil {
flags.systemModules = append(flags.systemModules, deps.systemModules)
}
// aidl flags.
aidlFlags := j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
if len(aidlFlags) > 0 {
// optimization.
ctx.Variable(pctx, "aidlFlags", strings.Join(aidlFlags, " "))
flags.aidlFlags = "$aidlFlags"
}
return flags
}
func (j *Module) compile(ctx android.ModuleContext, extraSrcJars ...android.Path) {
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
deps := j.collectDeps(ctx)
flags := j.collectBuilderFlags(ctx, deps)
if ctx.Config().TargetOpenJDK9() {
j.properties.Srcs = append(j.properties.Srcs, j.properties.Openjdk9.Srcs...)
}
srcFiles := ctx.ExpandSources(j.properties.Srcs, j.properties.Exclude_srcs)
if hasSrcExt(srcFiles.Strings(), ".proto") {
flags = protoFlags(ctx, &j.protoProperties, flags)
}
srcFiles = j.genSources(ctx, srcFiles, flags)
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
srcJars = append(srcJars, extraSrcJars...)
var jars android.Paths
jarName := ctx.ModuleName() + ".jar"
if srcFiles.HasExt(".kt") {
// If there are kotlin files, compile them first but pass all the kotlin and java files
// kotlinc will use the java files to resolve types referenced by the kotlin files, but
// won't emit any classes for them.
flags.kotlincFlags = "-no-stdlib"
if ctx.Device() {
flags.kotlincFlags += " -no-jdk"
}
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.kotlinStdlib...)
flags.kotlincClasspath = append(flags.kotlincClasspath, deps.classpath...)
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
TransformKotlinToClasses(ctx, kotlinJar, srcFiles, srcJars, flags)
if ctx.Failed() {
return
}
// Make javac rule depend on the kotlinc rule
flags.classpath = append(flags.classpath, kotlinJar)
// Jar kotlin classes into the final jar after javac
jars = append(jars, kotlinJar)
jars = append(jars, deps.kotlinStdlib...)
}
javaSrcFiles := srcFiles.FilterByExt(".java")
var uniqueSrcFiles android.Paths
set := make(map[string]bool)
for _, v := range javaSrcFiles {
if _, found := set[v.String()]; !found {
set[v.String()] = true
uniqueSrcFiles = append(uniqueSrcFiles, v)
}
}
enable_sharding := false
if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") {
if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 {
enable_sharding = true
if len(j.properties.Annotation_processors) != 0 ||
len(j.properties.Annotation_processor_classes) != 0 {
ctx.PropertyErrorf("javac_shard_size",
"%q cannot be set when annotation processors are enabled.",
j.properties.Javac_shard_size)
}
}
// If sdk jar is java module, then directly return classesJar as header.jar
if j.Name() != "android_stubs_current" && j.Name() != "android_system_stubs_current" &&
j.Name() != "android_test_stubs_current" {
j.headerJarFile = j.compileJavaHeader(ctx, uniqueSrcFiles, srcJars, deps, flags, jarName)
if ctx.Failed() {
return
}
}
}
if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
var extraJarDeps android.Paths
if ctx.Config().IsEnvTrue("RUN_ERROR_PRONE") {
// If error-prone is enabled, add an additional rule to compile the java files into
// a separate set of classes (so that they don't overwrite the normal ones and require
// a rebuild when error-prone is turned off).
// TODO(ccross): Once we always compile with javac9 we may be able to conditionally
// enable error-prone without affecting the output class files.
errorprone := android.PathForModuleOut(ctx, "errorprone", jarName)
RunErrorProne(ctx, errorprone, uniqueSrcFiles, srcJars, flags)
extraJarDeps = append(extraJarDeps, errorprone)
}
if enable_sharding {
flags.classpath.AddPaths([]android.Path{j.headerJarFile})
shardSize := int(*(j.properties.Javac_shard_size))
var shardSrcs []android.Paths
if len(uniqueSrcFiles) > 0 {
shardSrcs = shardPaths(uniqueSrcFiles, shardSize)
for idx, shardSrc := range shardSrcs {
classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(idx))
TransformJavaToClasses(ctx, classes, idx, shardSrc, nil, flags, extraJarDeps)
jars = append(jars, classes)
}
}
if len(srcJars) > 0 {
classes := android.PathForModuleOut(ctx, "javac", jarName+strconv.Itoa(len(shardSrcs)))
TransformJavaToClasses(ctx, classes, len(shardSrcs), nil, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
} else {
classes := android.PathForModuleOut(ctx, "javac", jarName)
TransformJavaToClasses(ctx, classes, -1, uniqueSrcFiles, srcJars, flags, extraJarDeps)
jars = append(jars, classes)
}
if ctx.Failed() {
return
}
}
dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs)
fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources)
var resArgs []string
var resDeps android.Paths
resArgs = append(resArgs, dirArgs...)
resDeps = append(resDeps, dirDeps...)
resArgs = append(resArgs, fileArgs...)
resDeps = append(resDeps, fileDeps...)
if proptools.Bool(j.properties.Include_srcs) {
srcArgs, srcDeps := SourceFilesToJarArgs(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
resArgs = append(resArgs, srcArgs...)
resDeps = append(resDeps, srcDeps...)
}
if len(resArgs) > 0 {
resourceJar := android.PathForModuleOut(ctx, "res", jarName)
TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps)
if ctx.Failed() {
return
}
jars = append(jars, resourceJar)
}
// static classpath jars have the resources in them, so the resource jars aren't necessary here
jars = append(jars, deps.staticJars...)
manifest := android.OptionalPathForModuleSrc(ctx, j.properties.Manifest)
// Combine the classes built from sources, any manifests, and any static libraries into
// classes.jar. If there is only one input jar this step will be skipped.
var outputFile android.Path
if len(jars) == 1 && !manifest.Valid() {
// Optimization: skip the combine step if there is nothing to do
outputFile = jars[0]
} else {
combinedJar := android.PathForModuleOut(ctx, "combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for javac", jars, manifest, false, nil)
outputFile = combinedJar
}
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "jarjar", jarName)
TransformJarJar(ctx, jarjarFile, outputFile, jarjar_rules)
outputFile = jarjarFile
if ctx.Failed() {
return
}
}
j.implementationJarFile = outputFile
if j.headerJarFile == nil {
j.headerJarFile = j.implementationJarFile
}
if ctx.Device() && j.installable() {
outputFile = j.desugar(ctx, flags, outputFile, jarName)
}
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
if inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
j.properties.Instrument = true
}
}
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") && j.properties.Instrument {
outputFile = j.instrument(ctx, flags, outputFile, jarName)
}
if ctx.Device() && j.installable() {
outputFile = j.compileDex(ctx, flags, outputFile, jarName)
if ctx.Failed() {
return
}
}
ctx.CheckbuildFile(outputFile)
j.outputFile = outputFile
}
func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths,
deps deps, flags javaBuilderFlags, jarName string) android.Path {
var jars android.Paths
if len(srcFiles) > 0 || len(srcJars) > 0 {
// Compile java sources into turbine.jar.
turbineJar := android.PathForModuleOut(ctx, "turbine", jarName)
TransformJavaToHeaderClasses(ctx, turbineJar, srcFiles, srcJars, flags)
if ctx.Failed() {
return nil
}
jars = append(jars, turbineJar)
}
// Combine any static header libraries into classes-header.jar. If there is only
// one input jar this step will be skipped.
var headerJar android.Path
jars = append(jars, deps.staticHeaderJars...)
// we cannot skip the combine step for now if there is only one jar
// since we have to strip META-INF/TRANSITIVE dir from turbine.jar
combinedJar := android.PathForModuleOut(ctx, "turbine-combined", jarName)
TransformJarsToJar(ctx, combinedJar, "for turbine", jars, android.OptionalPath{}, false, []string{"META-INF"})
headerJar = combinedJar
if j.properties.Jarjar_rules != nil {
jarjar_rules := android.PathForModuleSrc(ctx, *j.properties.Jarjar_rules)
// Transform classes.jar into classes-jarjar.jar
jarjarFile := android.PathForModuleOut(ctx, "turbine-jarjar", jarName)
TransformJarJar(ctx, jarjarFile, headerJar, jarjar_rules)
headerJar = jarjarFile
if ctx.Failed() {
return nil
}
}
return headerJar
}
func (j *Module) desugar(ctx android.ModuleContext, flags javaBuilderFlags,
classesJar android.Path, jarName string) android.Path {
desugarFlags := []string{
"--min_sdk_version " + j.minSdkVersionNumber(ctx),
"--desugar_try_with_resources_if_needed=false",
"--allow_empty_bootclasspath",
}
if inList("--core-library", j.deviceProperties.Dxflags) {
desugarFlags = append(desugarFlags, "--core_library")
}
flags.desugarFlags = strings.Join(desugarFlags, " ")
desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
TransformDesugar(ctx, desugarJar, classesJar, flags)
return desugarJar
}
func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags,
classesJar android.Path, jarName string) android.Path {
specs := j.jacocoStripSpecs(ctx)
jacocoReportClassesFile := android.PathForModuleOut(ctx, "jacoco", "jacoco-report-classes.jar")
instrumentedJar := android.PathForModuleOut(ctx, "jacoco", jarName)
jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs)
j.jacocoReportClassesFile = jacocoReportClassesFile
return instrumentedJar
}
func (j *Module) compileDex(ctx android.ModuleContext, flags javaBuilderFlags,
classesJar android.Path, jarName string) android.Path {
dxFlags := j.deviceProperties.Dxflags
if false /* emma enabled */ {
// If you instrument class files that have local variable debug information in
// them emma does not correctly maintain the local variable table.
// This will cause an error when you try to convert the class files for Android.
// The workaround here is to build different dex file here based on emma switch
// then later copy into classes.dex. When emma is on, dx is run with --no-locals
// option to remove local variable information
dxFlags = append(dxFlags, "--no-locals")
}
if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
dxFlags = append(dxFlags, "--no-optimize")
}
if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
dxFlags = append(dxFlags,
"--debug",
"--verbose",
"--dump-to="+android.PathForModuleOut(ctx, "classes.lst").String(),
"--dump-width=1000")
}
dxFlags = append(dxFlags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
flags.dxFlags = strings.Join(dxFlags, " ")
// Compile classes.jar into classes.dex and then javalib.jar
javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
TransformClassesJarToDexJar(ctx, javalibJar, classesJar, flags)
j.dexJarFile = javalibJar
return javalibJar
}
// Returns a sdk version as a string that is guaranteed to be a parseable as a number. For
// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns "10000".
func (j *Module) minSdkVersionNumber(ctx android.ModuleContext) string {
switch String(j.deviceProperties.Sdk_version) {
case "", "current", "test_current", "system_current":
return strconv.Itoa(ctx.Config().DefaultAppTargetSdkInt())
default:
return String(j.deviceProperties.Sdk_version)
}
}
func (j *Module) installable() bool {
return j.properties.Installable == nil || *j.properties.Installable
}
var _ Dependency = (*Library)(nil)
func (j *Module) HeaderJars() android.Paths {
return android.Paths{j.headerJarFile}
}
func (j *Module) ImplementationJars() android.Paths {
return android.Paths{j.implementationJarFile}
}
func (j *Module) AidlIncludeDirs() android.Paths {
return j.exportAidlIncludeDirs
}
var _ logtagsProducer = (*Module)(nil)
func (j *Module) logtags() android.Paths {
return j.logtagsSrcs
}
//
// Java libraries (.jar file)
//
type Library struct {
Module
}
func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.compile(ctx)
if j.installable() {
j.installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
ctx.ModuleName()+".jar", j.outputFile)
}
}
func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
}
func LibraryFactory(installable bool) func() android.Module {
return func() android.Module {
module := &Library{}
if !installable {
module.properties.Installable = proptools.BoolPtr(false)
}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
}
func LibraryHostFactory() android.Module {
module := &Library{}
module.AddProperties(
&module.Module.properties,
&module.Module.protoProperties)
InitJavaModule(module, android.HostSupported)
return module
}
//
// Java Binaries (.jar file plus wrapper script)
//
type binaryProperties struct {
// installable script to execute the resulting jar
Wrapper *string
}
type Binary struct {
Library
binaryProperties binaryProperties
wrapperFile android.SourcePath
binaryFile android.OutputPath
}
func (j *Binary) HostToolPath() android.OptionalPath {
return android.OptionalPathForPath(j.binaryFile)
}
func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.Library.GenerateAndroidBuildActions(ctx)
// Depend on the installed jar (j.installFile) so that the wrapper doesn't get executed by
// another build rule before the jar has been installed.
if String(j.binaryProperties.Wrapper) != "" {
j.wrapperFile = android.PathForModuleSrc(ctx, String(j.binaryProperties.Wrapper)).SourcePath
} else {
j.wrapperFile = android.PathForSource(ctx, "build/soong/scripts/jar-wrapper.sh")
}
j.binaryFile = ctx.InstallExecutable(android.PathForModuleInstall(ctx, "bin"),
ctx.ModuleName(), j.wrapperFile, j.installFile)
}
func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
j.deps(ctx)
}
func BinaryFactory() android.Module {
module := &Binary{}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties,
&module.binaryProperties)
InitJavaModule(module, android.HostAndDeviceSupported)
return module
}
func BinaryHostFactory() android.Module {
module := &Binary{}
module.AddProperties(
&module.Module.properties,
&module.Module.deviceProperties,
&module.Module.protoProperties,
&module.binaryProperties)
InitJavaModule(module, android.HostSupported)
return module
}
//
// Java prebuilts
//
type ImportProperties struct {
Jars []string
Sdk_version *string
Installable *bool
}
type Import struct {
android.ModuleBase
prebuilt android.Prebuilt
properties ImportProperties
classpathFiles android.Paths
combinedClasspathFile android.Path
}
func (j *Import) Prebuilt() *android.Prebuilt {
return &j.prebuilt
}
func (j *Import) PrebuiltSrcs() []string {
return j.properties.Jars
}
func (j *Import) Name() string {
return j.prebuilt.Name(j.ModuleBase.Name())
}
func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.classpathFiles = android.PathsForModuleSrc(ctx, j.properties.Jars)
outputFile := android.PathForModuleOut(ctx, "classes.jar")
TransformJarsToJar(ctx, outputFile, "for prebuilts", j.classpathFiles, android.OptionalPath{}, false, nil)
j.combinedClasspathFile = outputFile
}
var _ Dependency = (*Import)(nil)
func (j *Import) HeaderJars() android.Paths {
return j.classpathFiles
}
func (j *Import) ImplementationJars() android.Paths {
return j.classpathFiles
}
func (j *Import) AidlIncludeDirs() android.Paths {
return nil
}
var _ android.PrebuiltInterface = (*Import)(nil)
func ImportFactory() android.Module {
module := &Import{}
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
return module
}
func ImportFactoryHost() android.Module {
module := &Import{}
module.AddProperties(&module.properties)
android.InitPrebuiltModule(module, &module.properties.Jars)
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
return module
}
func inList(s string, l []string) bool {
for _, e := range l {
if e == s {
return true
}
}
return false
}
//
// Defaults
//
type Defaults struct {
android.ModuleBase
android.DefaultsModuleBase
}
func (*Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (d *Defaults) DepsMutator(ctx android.BottomUpMutatorContext) {
}
func defaultsFactory() android.Module {
return DefaultsFactory()
}
func DefaultsFactory(props ...interface{}) android.Module {
module := &Defaults{}
module.AddProperties(props...)
module.AddProperties(
&CompilerProperties{},
&CompilerDeviceProperties{},
)
android.InitDefaultsModule(module)
return module
}
var Bool = proptools.Bool
var String = proptools.String