Support java libraries, binaries, and prebuilts
Add support for compiling java libraries (.jar files with or without .dex), java binaries (.jar files with a wrapper script to run them), and java prebuilts (for the SDK .jars) Change-Id: Id624da64c92cf20c6d9577c6bb06e5b212af0d1b
This commit is contained in:
403
java/java.go
Normal file
403
java/java.go
Normal file
@@ -0,0 +1,403 @@
|
||||
// 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 compiler. The final creation of the rules
|
||||
// is handled in builder.go
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
"github.com/google/blueprint/pathtools"
|
||||
|
||||
"android/soong/common"
|
||||
)
|
||||
|
||||
type Config interface {
|
||||
SrcDir() string
|
||||
PrebuiltOS() string
|
||||
HostBinTool(string) (string, error)
|
||||
Getenv(string) string
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// Autogenerated files:
|
||||
// AIDL
|
||||
// Proto
|
||||
// Renderscript
|
||||
// Post-jar passes:
|
||||
// Proguard
|
||||
// Emma
|
||||
// Jarjar
|
||||
// Dex
|
||||
// Rmtypedefs
|
||||
// Jack
|
||||
// DroidDoc
|
||||
// Findbugs
|
||||
|
||||
// javaBase contains the properties and members used by all java module types, and implements
|
||||
// the blueprint.Module interface.
|
||||
type javaBase struct {
|
||||
common.AndroidModuleBase
|
||||
module JavaModuleType
|
||||
|
||||
properties struct {
|
||||
// srcs: list of source files used to compile the Java module. May be .java, .logtags, .proto,
|
||||
// or .aidl files.
|
||||
Srcs []string `android:"arch_variant,arch_subtract"`
|
||||
|
||||
// resource_dirs: list of directories containing resources
|
||||
Resource_dirs []string `android:"arch_variant"`
|
||||
|
||||
// no_standard_libraries: don't build against the default libraries (core-libart, core-junit,
|
||||
// ext, and framework for device targets)
|
||||
No_standard_libraries bool
|
||||
|
||||
// javacflags: list of module-specific flags that will be used for javac compiles
|
||||
Javacflags []string `android:"arch_variant"`
|
||||
|
||||
// dxflags: list of module-specific flags that will be used for dex compiles
|
||||
Dxflags []string `android:"arch_variant"`
|
||||
|
||||
// java_libs: list of of java libraries that will be in the classpath
|
||||
Java_libs []string `android:"arch_variant"`
|
||||
|
||||
// java_static_libs: list of java libraries that will be compiled into the resulting jar
|
||||
Java_static_libs []string `android:"arch_variant"`
|
||||
|
||||
// manifest: manifest file to be included in resulting jar
|
||||
Manifest string
|
||||
|
||||
// sdk_version: if not blank, set to the version of the sdk to compile against
|
||||
Sdk_version string
|
||||
|
||||
// Set for device java libraries, and for host versions of device java libraries
|
||||
// built for testing
|
||||
Dex bool `blueprint:"mutated"`
|
||||
}
|
||||
|
||||
// output file suitable for inserting into the classpath of another compile
|
||||
classpathFile string
|
||||
|
||||
// jarSpecs suitable for inserting classes from a static library into another jar
|
||||
classJarSpecs []jarSpec
|
||||
|
||||
// jarSpecs suitable for inserting resources from a static library into another jar
|
||||
resourceJarSpecs []jarSpec
|
||||
|
||||
// installed file for binary dependency
|
||||
installFile string
|
||||
}
|
||||
|
||||
type JavaModuleType interface {
|
||||
GenerateJavaBuildActions(ctx common.AndroidModuleContext)
|
||||
}
|
||||
|
||||
type JavaDependency interface {
|
||||
ClasspathFile() string
|
||||
ClassJarSpecs() []jarSpec
|
||||
ResourceJarSpecs() []jarSpec
|
||||
}
|
||||
|
||||
func NewJavaBase(base *javaBase, module JavaModuleType, hod common.HostOrDeviceSupported,
|
||||
props ...interface{}) (blueprint.Module, []interface{}) {
|
||||
|
||||
base.module = module
|
||||
|
||||
props = append(props, &base.properties)
|
||||
|
||||
return common.InitAndroidArchModule(base, hod, common.MultilibCommon, props...)
|
||||
}
|
||||
|
||||
func (j *javaBase) BootClasspath(ctx common.AndroidBaseContext) string {
|
||||
if ctx.Device() {
|
||||
if j.properties.Sdk_version == "" {
|
||||
return "core-libart"
|
||||
} else if j.properties.Sdk_version == "current" {
|
||||
// TODO: !TARGET_BUILD_APPS
|
||||
return "android_stubs_current"
|
||||
} else if j.properties.Sdk_version == "system_current" {
|
||||
return "android_system_stubs_current"
|
||||
} else {
|
||||
return "sdk_v" + j.properties.Sdk_version
|
||||
}
|
||||
} else {
|
||||
if j.properties.Dex {
|
||||
return "core-libart"
|
||||
} else {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (j *javaBase) AndroidDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
|
||||
var deps []string
|
||||
|
||||
if !j.properties.No_standard_libraries {
|
||||
bootClasspath := j.BootClasspath(ctx)
|
||||
if bootClasspath != "" {
|
||||
deps = append(deps, bootClasspath)
|
||||
}
|
||||
}
|
||||
deps = append(deps, j.properties.Java_libs...)
|
||||
deps = append(deps, j.properties.Java_static_libs...)
|
||||
|
||||
return deps
|
||||
}
|
||||
|
||||
func (j *javaBase) collectDeps(ctx common.AndroidModuleContext) (classpath []string,
|
||||
bootClasspath string, classJarSpecs, resourceJarSpecs []jarSpec) {
|
||||
|
||||
ctx.VisitDirectDeps(func(module blueprint.Module) {
|
||||
otherName := ctx.OtherModuleName(module)
|
||||
if javaDep, ok := module.(JavaDependency); ok {
|
||||
if inList(otherName, j.properties.Java_libs) {
|
||||
classpath = append(classpath, javaDep.ClasspathFile())
|
||||
} else if inList(otherName, j.properties.Java_static_libs) {
|
||||
classpath = append(classpath, javaDep.ClasspathFile())
|
||||
classJarSpecs = append(classJarSpecs, javaDep.ClassJarSpecs()...)
|
||||
resourceJarSpecs = append(resourceJarSpecs, javaDep.ResourceJarSpecs()...)
|
||||
} else if otherName == j.BootClasspath(ctx) {
|
||||
bootClasspath = javaDep.ClasspathFile()
|
||||
} else {
|
||||
panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
|
||||
}
|
||||
} else {
|
||||
ctx.ModuleErrorf("unknown dependency module type for %q", otherName)
|
||||
}
|
||||
})
|
||||
|
||||
return classpath, bootClasspath, classJarSpecs, resourceJarSpecs
|
||||
}
|
||||
|
||||
func (j *javaBase) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
|
||||
j.module.GenerateJavaBuildActions(ctx)
|
||||
}
|
||||
|
||||
func (j *javaBase) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
|
||||
flags := javaBuilderFlags{
|
||||
javacFlags: strings.Join(j.properties.Javacflags, " "),
|
||||
}
|
||||
|
||||
var javacDeps []string
|
||||
|
||||
srcFiles := j.properties.Srcs
|
||||
srcFiles = pathtools.PrefixPaths(srcFiles, common.ModuleSrcDir(ctx))
|
||||
srcFiles = common.ExpandGlobs(ctx, srcFiles)
|
||||
|
||||
classpath, bootClasspath, classJarSpecs, resourceJarSpecs := j.collectDeps(ctx)
|
||||
|
||||
if bootClasspath != "" {
|
||||
flags.bootClasspath = "-bootclasspath " + bootClasspath
|
||||
javacDeps = append(javacDeps, bootClasspath)
|
||||
}
|
||||
|
||||
if len(classpath) > 0 {
|
||||
flags.classpath = "-classpath " + strings.Join(classpath, ":")
|
||||
javacDeps = append(javacDeps, classpath...)
|
||||
}
|
||||
|
||||
// Compile java sources into .class files
|
||||
classes := TransformJavaToClasses(ctx, srcFiles, flags, javacDeps)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
resourceJarSpecs = append(ResourceDirsToJarSpecs(ctx, j.properties.Resource_dirs), resourceJarSpecs...)
|
||||
classJarSpecs = append([]jarSpec{classes}, classJarSpecs...)
|
||||
|
||||
manifest := j.properties.Manifest
|
||||
if manifest != "" {
|
||||
manifest = filepath.Join(common.ModuleSrcDir(ctx), manifest)
|
||||
}
|
||||
|
||||
allJarSpecs := append([]jarSpec(nil), classJarSpecs...)
|
||||
allJarSpecs = append(allJarSpecs, resourceJarSpecs...)
|
||||
|
||||
// Combine classes + resources into classes-full-debug.jar
|
||||
outputFile := TransformClassesToJar(ctx, allJarSpecs, manifest)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
j.classJarSpecs = classJarSpecs
|
||||
j.resourceJarSpecs = resourceJarSpecs
|
||||
j.classpathFile = outputFile
|
||||
|
||||
if j.properties.Dex {
|
||||
dxFlags := j.properties.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().(Config).Getenv("NO_OPTIMIZE_DX") != "" {
|
||||
dxFlags = append(dxFlags, "--no-optimize")
|
||||
}
|
||||
|
||||
if ctx.Config().(Config).Getenv("GENERATE_DEX_DEBUG") != "" {
|
||||
dxFlags = append(dxFlags,
|
||||
"--debug",
|
||||
"--verbose",
|
||||
"--dump-to="+filepath.Join(common.ModuleOutDir(ctx), "classes.lst"),
|
||||
"--dump-width=1000")
|
||||
}
|
||||
|
||||
flags.dxFlags = strings.Join(dxFlags, " ")
|
||||
|
||||
// Compile classes.jar into classes.dex
|
||||
dexFile := TransformClassesJarToDex(ctx, outputFile, flags)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
// Combine classes.dex + resources into javalib.jar
|
||||
outputFile = TransformDexToJavaLib(ctx, resourceJarSpecs, dexFile)
|
||||
}
|
||||
|
||||
j.installFile = ctx.InstallFileName("framework", ctx.ModuleName()+".jar", outputFile)
|
||||
}
|
||||
|
||||
var _ JavaDependency = (*JavaLibrary)(nil)
|
||||
|
||||
func (j *javaBase) ClasspathFile() string {
|
||||
return j.classpathFile
|
||||
}
|
||||
|
||||
func (j *javaBase) ClassJarSpecs() []jarSpec {
|
||||
return j.classJarSpecs
|
||||
}
|
||||
|
||||
func (j *javaBase) ResourceJarSpecs() []jarSpec {
|
||||
return j.resourceJarSpecs
|
||||
}
|
||||
|
||||
//
|
||||
// Java libraries (.jar file)
|
||||
//
|
||||
|
||||
type JavaLibrary struct {
|
||||
javaBase
|
||||
}
|
||||
|
||||
func JavaLibraryFactory() (blueprint.Module, []interface{}) {
|
||||
module := &JavaLibrary{}
|
||||
|
||||
module.properties.Dex = true
|
||||
|
||||
return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported)
|
||||
}
|
||||
|
||||
func JavaLibraryHostFactory() (blueprint.Module, []interface{}) {
|
||||
module := &JavaLibrary{}
|
||||
|
||||
return NewJavaBase(&module.javaBase, module, common.HostSupported)
|
||||
}
|
||||
|
||||
//
|
||||
// Java Binaries (.jar file plus wrapper script)
|
||||
//
|
||||
|
||||
type JavaBinary struct {
|
||||
JavaLibrary
|
||||
|
||||
binaryProperties struct {
|
||||
// wrapper: installable script to execute the resulting jar
|
||||
Wrapper string
|
||||
}
|
||||
}
|
||||
|
||||
func (j *JavaBinary) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
|
||||
j.JavaLibrary.GenerateJavaBuildActions(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.
|
||||
ctx.InstallFile("bin", filepath.Join(common.ModuleSrcDir(ctx), j.binaryProperties.Wrapper),
|
||||
j.installFile)
|
||||
}
|
||||
|
||||
func JavaBinaryFactory() (blueprint.Module, []interface{}) {
|
||||
module := &JavaBinary{}
|
||||
|
||||
module.properties.Dex = true
|
||||
|
||||
return NewJavaBase(&module.javaBase, module, common.HostAndDeviceSupported, &module.binaryProperties)
|
||||
}
|
||||
|
||||
func JavaBinaryHostFactory() (blueprint.Module, []interface{}) {
|
||||
module := &JavaBinary{}
|
||||
|
||||
return NewJavaBase(&module.javaBase, module, common.HostSupported, &module.binaryProperties)
|
||||
}
|
||||
|
||||
//
|
||||
// Java prebuilts
|
||||
//
|
||||
|
||||
type JavaPrebuilt struct {
|
||||
common.AndroidModuleBase
|
||||
|
||||
properties struct {
|
||||
Srcs []string
|
||||
}
|
||||
|
||||
classpathFile string
|
||||
}
|
||||
|
||||
func (j *JavaPrebuilt) GenerateAndroidBuildActions(ctx common.AndroidModuleContext) {
|
||||
if len(j.properties.Srcs) != 1 {
|
||||
ctx.ModuleErrorf("expected exactly one jar in srcs")
|
||||
return
|
||||
}
|
||||
j.classpathFile = filepath.Join(common.ModuleSrcDir(ctx), j.properties.Srcs[0])
|
||||
}
|
||||
|
||||
var _ JavaDependency = (*JavaPrebuilt)(nil)
|
||||
|
||||
func (j *JavaPrebuilt) ClasspathFile() string {
|
||||
return j.classpathFile
|
||||
}
|
||||
|
||||
func (j *JavaPrebuilt) ClassJarSpecs() []jarSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *JavaPrebuilt) ResourceJarSpecs() []jarSpec {
|
||||
return nil
|
||||
}
|
||||
|
||||
func JavaPrebuiltFactory() (blueprint.Module, []interface{}) {
|
||||
module := &JavaPrebuilt{}
|
||||
|
||||
return common.InitAndroidArchModule(module, common.HostAndDeviceSupported,
|
||||
common.MultilibCommon, &module.properties)
|
||||
}
|
||||
|
||||
func inList(s string, l []string) bool {
|
||||
for _, e := range l {
|
||||
if e == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Reference in New Issue
Block a user