Files
build_soong/java/app.go
Colin Cross 8f101b45fc Allow common.Glob to be called by singletons
Make common.Glob take an interface that is the intersection of
blueprint.ModuleContext and blueprint.SingletonContext used by
Glob and GlobRule, allowing it to be called on either.  Also
move ExpandSources and Glob into AndroidModuleContext.

Change-Id: I8d1a3160c5dd201033afdb37210e82d8065b137d
2015-06-17 15:36:48 -07:00

318 lines
9.9 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 Android apps.
import (
"os"
"path/filepath"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"android/soong/common"
)
// AAR prebuilts
// AndroidManifest.xml merging
// package splits
type AndroidApp struct {
javaBase
appProperties struct {
// certificate: path to a certificate, or the name of a certificate in the default
// certificate directory, or blank to use the default product certificate
Certificate string
// additional_certificates: paths to extra certificates to sign the apk with
Additional_certificates []string
// export_package_resources: If set, create package-export.apk, which other packages can
// use to get PRODUCT-agnostic resource data like IDs and type definitions.
Export_package_resources bool
// aaptflags: flags passed to aapt when creating the apk
Aaptflags []string
// package_splits: list of resource labels to generate individual resource packages
Package_splits []string
// asset_dirs: list of directories relative to the Blueprints file containing assets.
// Defaults to "assets"
Asset_dirs []string
// android_resource_dirs: list of directories relative to the Blueprints file containing
// Java resources
Android_resource_dirs []string
}
aaptJavaFileList string
exportPackage string
}
func (a *AndroidApp) JavaDynamicDependencies(ctx common.AndroidDynamicDependerModuleContext) []string {
deps := a.javaBase.JavaDynamicDependencies(ctx)
if !a.properties.No_standard_libraries {
switch a.properties.Sdk_version { // TODO: Res_sdk_version?
case "current", "system_current", "":
deps = append(deps, "framework-res")
default:
// We'll already have a dependency on an sdk prebuilt android.jar
}
}
return deps
}
func (a *AndroidApp) GenerateJavaBuildActions(ctx common.AndroidModuleContext) {
aaptFlags, aaptDeps, hasResources := a.aaptFlags(ctx)
if hasResources {
// First generate R.java so we can build the .class files
aaptRJavaFlags := append([]string(nil), aaptFlags...)
publicResourcesFile, proguardOptionsFile, aaptJavaFileList :=
CreateResourceJavaFiles(ctx, aaptRJavaFlags, aaptDeps)
a.aaptJavaFileList = aaptJavaFileList
a.ExtraSrcLists = append(a.ExtraSrcLists, aaptJavaFileList)
if a.appProperties.Export_package_resources {
aaptPackageFlags := append([]string(nil), aaptFlags...)
var hasProduct bool
for _, f := range aaptPackageFlags {
if strings.HasPrefix(f, "--product") {
hasProduct = true
break
}
}
if !hasProduct {
aaptPackageFlags = append(aaptPackageFlags,
"--product "+ctx.AConfig().ProductAaptCharacteristics())
}
a.exportPackage = CreateExportPackage(ctx, aaptPackageFlags, aaptDeps)
ctx.CheckbuildFile(a.exportPackage)
}
ctx.CheckbuildFile(publicResourcesFile)
ctx.CheckbuildFile(proguardOptionsFile)
ctx.CheckbuildFile(aaptJavaFileList)
}
// apps manifests are handled by aapt, don't let javaBase see them
a.properties.Manifest = ""
//if !ctx.ContainsProperty("proguard.enabled") {
// a.properties.Proguard.Enabled = true
//}
a.javaBase.GenerateJavaBuildActions(ctx)
aaptPackageFlags := append([]string(nil), aaptFlags...)
var hasProduct bool
for _, f := range aaptPackageFlags {
if strings.HasPrefix(f, "--product") {
hasProduct = true
break
}
}
if !hasProduct {
aaptPackageFlags = append(aaptPackageFlags,
"--product "+ctx.AConfig().ProductAaptCharacteristics())
}
certificate := a.appProperties.Certificate
if certificate == "" {
certificate = ctx.AConfig().DefaultAppCertificate()
} else if dir, _ := filepath.Split(certificate); dir == "" {
certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(), certificate)
} else {
certificate = filepath.Join(ctx.AConfig().SrcDir(), certificate)
}
certificates := []string{certificate}
for _, c := range a.appProperties.Additional_certificates {
certificates = append(certificates, filepath.Join(ctx.AConfig().SrcDir(), c))
}
a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
ctx.InstallFileName("app", ctx.ModuleName()+".apk", a.outputFile)
}
var aaptIgnoreFilenames = []string{
".svn",
".git",
".ds_store",
"*.scc",
".*",
"CVS",
"thumbs.db",
"picasa.ini",
"*~",
}
func (a *AndroidApp) aaptFlags(ctx common.AndroidModuleContext) ([]string, []string, bool) {
aaptFlags := a.appProperties.Aaptflags
hasVersionCode := false
hasVersionName := false
for _, f := range aaptFlags {
if strings.HasPrefix(f, "--version-code") {
hasVersionCode = true
} else if strings.HasPrefix(f, "--version-name") {
hasVersionName = true
}
}
if true /* is not a test */ {
aaptFlags = append(aaptFlags, "-z")
}
assetDirs := a.appProperties.Asset_dirs
if len(assetDirs) == 0 {
defaultAssetDir := filepath.Join(common.ModuleSrcDir(ctx), "assets")
if _, err := os.Stat(defaultAssetDir); err == nil {
assetDirs = []string{defaultAssetDir}
} else {
// Default asset directory doesn't exist, add a dep on the parent directory to
// regenerate the manifest if it is created later
// TODO: use glob to avoid rerunning whole regenerate if a different file is created?
ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx))
}
} else {
assetDirs = pathtools.PrefixPaths(assetDirs, common.ModuleSrcDir(ctx))
}
resourceDirs := a.appProperties.Android_resource_dirs
if len(resourceDirs) == 0 {
defaultResourceDir := filepath.Join(common.ModuleSrcDir(ctx), "res")
if _, err := os.Stat(defaultResourceDir); err == nil {
resourceDirs = []string{defaultResourceDir}
} else {
// Default resource directory doesn't exist, add a dep on the parent directory to
// regenerate the manifest if it is created later
// TODO: use glob to avoid rerunning whole regenerate if a different file is created?
ctx.AddNinjaFileDeps(common.ModuleSrcDir(ctx))
}
} else {
resourceDirs = pathtools.PrefixPaths(resourceDirs, common.ModuleSrcDir(ctx))
}
rootSrcDir := ctx.AConfig().SrcDir()
var overlayResourceDirs []string
// For every resource directory, check if there is an overlay directory with the same path.
// If found, it will be prepended to the list of resource directories.
for _, overlayDir := range ctx.AConfig().ResourceOverlays() {
for _, resourceDir := range resourceDirs {
relResourceDir, err := filepath.Rel(rootSrcDir, resourceDir)
if err != nil {
ctx.ModuleErrorf("resource directory %q is not in source tree", resourceDir)
continue
}
overlayResourceDir := filepath.Join(overlayDir, relResourceDir)
if _, err := os.Stat(overlayResourceDir); err == nil {
overlayResourceDirs = append(overlayResourceDirs, overlayResourceDir)
} else {
// Overlay resource directory doesn't exist, add a dep to regenerate the manifest if
// it is created later
ctx.AddNinjaFileDeps(overlayResourceDir)
}
}
}
if len(overlayResourceDirs) > 0 {
resourceDirs = append(overlayResourceDirs, resourceDirs...)
}
// aapt needs to rerun if any files are added or modified in the assets or resource directories,
// use glob to create a filelist.
var aaptDeps []string
var hasResources bool
for _, d := range resourceDirs {
newDeps := ctx.Glob(filepath.Join(d, "**/*"), aaptIgnoreFilenames)
aaptDeps = append(aaptDeps, newDeps...)
if len(newDeps) > 0 {
hasResources = true
}
}
for _, d := range assetDirs {
newDeps := ctx.Glob(filepath.Join(d, "**/*"), aaptIgnoreFilenames)
aaptDeps = append(aaptDeps, newDeps...)
}
manifestFile := a.properties.Manifest
if manifestFile == "" {
manifestFile = "AndroidManifest.xml"
}
manifestFile = filepath.Join(common.ModuleSrcDir(ctx), manifestFile)
aaptDeps = append(aaptDeps, manifestFile)
aaptFlags = append(aaptFlags, "-M "+manifestFile)
aaptFlags = append(aaptFlags, common.JoinWithPrefix(assetDirs, "-A "))
aaptFlags = append(aaptFlags, common.JoinWithPrefix(resourceDirs, "-S "))
ctx.VisitDirectDeps(func(module blueprint.Module) {
var depFile string
if sdkDep, ok := module.(sdkDependency); ok {
depFile = sdkDep.ClasspathFile()
} else if javaDep, ok := module.(JavaDependency); ok {
if ctx.OtherModuleName(module) == "framework-res" {
depFile = javaDep.(*javaBase).module.(*AndroidApp).exportPackage
}
}
if depFile != "" {
aaptFlags = append(aaptFlags, "-I "+depFile)
aaptDeps = append(aaptDeps, depFile)
}
})
sdkVersion := a.properties.Sdk_version
if sdkVersion == "" {
sdkVersion = ctx.AConfig().PlatformSdkVersion()
}
aaptFlags = append(aaptFlags, "--min-sdk-version "+sdkVersion)
aaptFlags = append(aaptFlags, "--target-sdk-version "+sdkVersion)
if !hasVersionCode {
aaptFlags = append(aaptFlags, "--version-code "+ctx.AConfig().PlatformSdkVersion())
}
if !hasVersionName {
aaptFlags = append(aaptFlags,
"--version-name "+ctx.AConfig().PlatformVersion()+"-"+ctx.AConfig().BuildNumber())
}
// TODO: LOCAL_PACKAGE_OVERRIDES
// $(addprefix --rename-manifest-package , $(PRIVATE_MANIFEST_PACKAGE_NAME)) \
// TODO: LOCAL_INSTRUMENTATION_FOR
// $(addprefix --rename-instrumentation-target-package , $(PRIVATE_MANIFEST_INSTRUMENTATION_FOR))
return aaptFlags, aaptDeps, hasResources
}
func AndroidAppFactory() (blueprint.Module, []interface{}) {
module := &AndroidApp{}
module.properties.Dex = true
return NewJavaBase(&module.javaBase, module, common.DeviceSupported, &module.appProperties)
}