Merge "Revert "Revert "Change Python in Soong to support device side build."""
diff --git a/Android.bp b/Android.bp
index e89f908..6d2b804 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,6 +56,7 @@
"android/prebuilt.go",
"android/proto.go",
"android/register.go",
+ "android/singleton.go",
"android/testing.go",
"android/util.go",
"android/variable.go",
@@ -208,17 +209,20 @@
"soong-java-config",
],
srcs: [
+ "java/aapt2.go",
"java/androidmk.go",
"java/app_builder.go",
"java/app.go",
"java/builder.go",
"java/gen.go",
+ "java/jacoco.go",
"java/java.go",
"java/proto.go",
"java/resources.go",
"java/system_modules.go",
],
testSrcs: [
+ "java/app_test.go",
"java/java_test.go",
],
pluginFor: ["soong_build"],
diff --git a/android/androidmk.go b/android/androidmk.go
index 19d5ea6..d88ba8f 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -53,30 +53,26 @@
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
-func AndroidMkSingleton() blueprint.Singleton {
+func AndroidMkSingleton() Singleton {
return &androidMkSingleton{}
}
type androidMkSingleton struct{}
-func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
- config := ctx.Config().(Config)
-
- if !config.EmbeddedInMake() {
+func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) {
+ if !ctx.Config().EmbeddedInMake() {
return
}
var androidMkModulesList []Module
- ctx.VisitAllModules(func(module blueprint.Module) {
- if amod, ok := module.(Module); ok {
- androidMkModulesList = append(androidMkModulesList, amod)
- }
+ ctx.VisitAllModules(func(module Module) {
+ androidMkModulesList = append(androidMkModulesList, module)
})
sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
- transMk := PathForOutput(ctx, "Android"+String(config.ProductVariables.Make_suffix)+".mk")
+ transMk := PathForOutput(ctx, "Android"+String(ctx.Config().ProductVariables.Make_suffix)+".mk")
if ctx.Failed() {
return
}
@@ -86,14 +82,13 @@
ctx.Errorf(err.Error())
}
- ctx.Build(pctx, blueprint.BuildParams{
- Rule: blueprint.Phony,
- Outputs: []string{transMk.String()},
- Optional: true,
+ ctx.Build(pctx, BuildParams{
+ Rule: blueprint.Phony,
+ Output: transMk,
})
}
-func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []Module) error {
+func translateAndroidMk(ctx SingletonContext, mkFile string, mods []Module) error {
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
@@ -145,7 +140,7 @@
return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
}
-func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
+func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error {
provider, ok := mod.(AndroidMkDataProvider)
if !ok {
return nil
@@ -187,8 +182,7 @@
}
- config := ctx.Config().(Config)
- if amod.Arch().ArchType != config.Targets[amod.Os().Class][0].Arch.ArchType {
+ if amod.Arch().ArchType != ctx.Config().Targets[amod.Os().Class][0].Arch.ArchType {
prefix = "2ND_" + prefix
}
}
diff --git a/android/api_levels.go b/android/api_levels.go
index 2c4ae1a..a519117 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -16,22 +16,19 @@
import (
"encoding/json"
- "path/filepath"
-
- "github.com/google/blueprint"
)
func init() {
RegisterSingletonType("api_levels", ApiLevelsSingleton)
}
-func ApiLevelsSingleton() blueprint.Singleton {
+func ApiLevelsSingleton() Singleton {
return &apiLevelsSingleton{}
}
type apiLevelsSingleton struct{}
-func createApiLevelsJson(ctx blueprint.SingletonContext, file string,
+func createApiLevelsJson(ctx SingletonContext, file WritablePath,
apiLevelsMap map[string]int) {
jsonStr, err := json.Marshal(apiLevelsMap)
@@ -39,21 +36,21 @@
ctx.Errorf(err.Error())
}
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: WriteFile,
- Description: "generate " + filepath.Base(file),
- Outputs: []string{file},
+ Description: "generate " + file.Base(),
+ Output: file,
Args: map[string]string{
"content": string(jsonStr[:]),
},
})
}
-func GetApiLevelsJson(ctx PathContext) Path {
+func GetApiLevelsJson(ctx PathContext) WritablePath {
return PathForOutput(ctx, "api_levels.json")
}
-func (a *apiLevelsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
baseApiLevel := 9000
apiLevelsMap := map[string]int{
"G": 9,
@@ -69,10 +66,10 @@
"N-MR1": 25,
"O": 26,
}
- for i, codename := range ctx.Config().(Config).PlatformVersionCombinedCodenames() {
+ for i, codename := range ctx.Config().PlatformVersionCombinedCodenames() {
apiLevelsMap[codename] = baseApiLevel + i
}
apiLevelsJson := GetApiLevelsJson(ctx)
- createApiLevelsJson(ctx, apiLevelsJson.String(), apiLevelsMap)
+ createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
}
diff --git a/android/arch.go b/android/arch.go
index 5ea9759..7f9abc6 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -305,7 +305,7 @@
primaryModules := make(map[int]bool)
for _, class := range osClasses {
- targets := mctx.AConfig().Targets[class]
+ targets := mctx.Config().Targets[class]
if len(targets) == 0 {
continue
}
@@ -325,7 +325,7 @@
var prefer32 bool
switch class {
case Device:
- prefer32 = mctx.AConfig().DevicePrefer32BitExecutables()
+ prefer32 = mctx.Config().DevicePrefer32BitExecutables()
case HostCross:
// Windows builds always prefer 32-bit
prefer32 = true
@@ -774,7 +774,7 @@
// that are being compiled for 64-bit. Its expected use case is binaries like linker and
// debuggerd that need to know when they are a 32-bit process running on a 64-bit device
if os.Class == Device {
- if ctx.AConfig().Android64() {
+ if ctx.Config().Android64() {
field := "Android64"
prefix := "target.android64"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
@@ -785,13 +785,13 @@
}
if arch.ArchType == X86 && (hasArmAbi(arch) ||
- hasArmAndroidArch(ctx.AConfig().Targets[Device])) {
+ hasArmAndroidArch(ctx.Config().Targets[Device])) {
field := "Arm_on_x86"
prefix := "target.arm_on_x86"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
}
if arch.ArchType == X86_64 && (hasArmAbi(arch) ||
- hasArmAndroidArch(ctx.AConfig().Targets[Device])) {
+ hasArmAndroidArch(ctx.Config().Targets[Device])) {
field := "Arm_on_x86_64"
prefix := "target.arm_on_x86_64"
a.appendProperties(ctx, genProps, targetProp, field, prefix)
diff --git a/android/config.go b/android/config.go
index 79ff32a..2589f71 100644
--- a/android/config.go
+++ b/android/config.go
@@ -175,7 +175,12 @@
func TestConfig(buildDir string, env map[string]string) Config {
config := &config{
ProductVariables: productVariables{
- DeviceName: stringPtr("test_device"),
+ DeviceName: stringPtr("test_device"),
+ Platform_sdk_version: intPtr(26),
+ AAPTConfig: &[]string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
+ AAPTPreferredConfig: stringPtr("xhdpi"),
+ AAPTCharacteristics: stringPtr("nosdcard"),
+ AAPTPrebuiltDPI: &[]string{"xhdpi", "xxhdpi"},
},
buildDir: buildDir,
@@ -417,12 +422,11 @@
return true
}
-func (c *config) ResourceOverlays() []SourcePath {
- return nil
-}
-
-func (c *config) PlatformVersion() string {
- return "M"
+func (c *config) ResourceOverlays() []string {
+ if c.ProductVariables.ResourceOverlays == nil {
+ return nil
+ }
+ return *c.ProductVariables.ResourceOverlays
}
func (c *config) PlatformSdkVersionInt() int {
@@ -445,6 +449,10 @@
}
}
+func (c *config) AppsDefaultVersionName() string {
+ return String(c.ProductVariables.AppsDefaultVersionName)
+}
+
// Codenames that are active in the current lunch target.
func (c *config) PlatformVersionActiveCodenames() []string {
return c.ProductVariables.Platform_version_active_codenames
@@ -466,10 +474,6 @@
return combined
}
-func (c *config) BuildNumber() string {
- return "000000"
-}
-
func (c *config) ProductAAPTConfig() []string {
return *c.ProductVariables.AAPTConfig
}
diff --git a/android/env.go b/android/env.go
index ec5794e..469dfff 100644
--- a/android/env.go
+++ b/android/env.go
@@ -19,8 +19,6 @@
"strings"
"android/soong/env"
-
- "github.com/google/blueprint"
)
// This file supports dependencies on environment variables. During build manifest generation,
@@ -43,14 +41,14 @@
os.Clearenv()
}
-func EnvSingleton() blueprint.Singleton {
+func EnvSingleton() Singleton {
return &envSingleton{}
}
type envSingleton struct{}
-func (c *envSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
- envDeps := ctx.Config().(Config).EnvDeps()
+func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) {
+ envDeps := ctx.Config().EnvDeps()
envFile := PathForOutput(ctx, ".soong.environment")
if ctx.Failed() {
diff --git a/android/hooks.go b/android/hooks.go
index a9bfd33..57560d2 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -26,7 +26,7 @@
// before the module has been split into architecture variants, and before defaults modules have
// been applied.
type LoadHookContext interface {
- // TODO: a new context that includes AConfig() but not Target(), etc.?
+ // TODO: a new context that includes Config() but not Target(), etc.?
BaseContext
AppendProperties(...interface{})
PrependProperties(...interface{})
diff --git a/android/makevars.go b/android/makevars.go
index 024e015..00a20f5 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -21,7 +21,6 @@
"os"
"strconv"
- "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -66,7 +65,7 @@
type MakeVarsProvider func(ctx MakeVarsContext)
-func RegisterMakeVarsProvider(pctx blueprint.PackageContext, provider MakeVarsProvider) {
+func RegisterMakeVarsProvider(pctx PackageContext, provider MakeVarsProvider) {
makeVarsProviders = append(makeVarsProviders, makeVarsProvider{pctx, provider})
}
@@ -76,14 +75,14 @@
RegisterSingletonType("makevars", makeVarsSingletonFunc)
}
-func makeVarsSingletonFunc() blueprint.Singleton {
+func makeVarsSingletonFunc() Singleton {
return &makeVarsSingleton{}
}
type makeVarsSingleton struct{}
type makeVarsProvider struct {
- pctx blueprint.PackageContext
+ pctx PackageContext
call MakeVarsProvider
}
@@ -91,8 +90,8 @@
type makeVarsContext struct {
config Config
- ctx blueprint.SingletonContext
- pctx blueprint.PackageContext
+ ctx SingletonContext
+ pctx PackageContext
vars []makeVarsVariable
}
@@ -105,14 +104,12 @@
strict bool
}
-func (s *makeVarsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
- config := ctx.Config().(Config)
-
- if !config.EmbeddedInMake() {
+func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
+ if !ctx.Config().EmbeddedInMake() {
return
}
- outFile := PathForOutput(ctx, "make_vars"+proptools.String(config.ProductVariables.Make_suffix)+".mk").String()
+ outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().ProductVariables.Make_suffix)+".mk").String()
if ctx.Failed() {
return
@@ -121,7 +118,7 @@
vars := []makeVarsVariable{}
for _, provider := range makeVarsProviders {
mctx := &makeVarsContext{
- config: config,
+ config: ctx.Config(),
ctx: ctx,
pctx: provider.pctx,
}
diff --git a/android/module.go b/android/module.go
index 66859fa..c728487 100644
--- a/android/module.go
+++ b/android/module.go
@@ -17,7 +17,9 @@
import (
"fmt"
"path/filepath"
+ "sort"
"strings"
+ "text/scanner"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
@@ -69,16 +71,39 @@
}
type BaseContext interface {
- blueprint.BaseModuleContext
+ BaseModuleContext
androidBaseContext
}
+// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
+// a Config instead of an interface{}.
+type BaseModuleContext interface {
+ ModuleName() string
+ ModuleDir() string
+ Config() Config
+
+ ContainsProperty(name string) bool
+ Errorf(pos scanner.Position, fmt string, args ...interface{})
+ ModuleErrorf(fmt string, args ...interface{})
+ PropertyErrorf(property, fmt string, args ...interface{})
+ Failed() bool
+
+ // GlobWithDeps returns a list of files that match the specified pattern but do not match any
+ // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
+ // builder whenever a file matching the pattern as added or removed, without rerunning if a
+ // file that does not match the pattern is added to a searched directory.
+ GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+ Fs() pathtools.FileSystem
+ AddNinjaFileDeps(deps ...string)
+}
+
type ModuleContext interface {
androidBaseContext
- blueprint.BaseModuleContext
+ BaseModuleContext
// Deprecated: use ModuleContext.Build instead.
- ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams)
+ ModuleBuild(pctx PackageContext, params ModuleBuildParams)
ExpandSources(srcFiles, excludes []string) Paths
ExpandSourcesSubDir(srcFiles, excludes []string, subDir string) Paths
@@ -115,15 +140,15 @@
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
WalkDeps(visit func(Module, Module) bool)
- Variable(pctx blueprint.PackageContext, name, value string)
- Rule(pctx blueprint.PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
+ Variable(pctx PackageContext, name, value string)
+ Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
// and performs more verification.
- Build(pctx blueprint.PackageContext, params BuildParams)
+ Build(pctx PackageContext, params BuildParams)
- PrimaryModule() blueprint.Module
- FinalModule() blueprint.Module
- VisitAllModuleVariants(visit func(blueprint.Module))
+ PrimaryModule() Module
+ FinalModule() Module
+ VisitAllModuleVariants(visit func(Module))
GetMissingDependencies() []string
}
@@ -325,8 +350,8 @@
// Used by buildTargetSingleton to create checkbuild and per-directory build targets
// Only set on the final variant of each module
- installTarget string
- checkbuildTarget string
+ installTarget WritablePath
+ checkbuildTarget WritablePath
blueprintDir string
hooks hooks
@@ -464,36 +489,35 @@
return false
}
-func (a *ModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
+func (a *ModuleBase) generateModuleTarget(ctx ModuleContext) {
allInstalledFiles := Paths{}
allCheckbuildFiles := Paths{}
- ctx.VisitAllModuleVariants(func(module blueprint.Module) {
- a := module.(Module).base()
+ ctx.VisitAllModuleVariants(func(module Module) {
+ a := module.base()
allInstalledFiles = append(allInstalledFiles, a.installFiles...)
allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...)
})
- deps := []string{}
+ var deps Paths
if len(allInstalledFiles) > 0 {
- name := ctx.ModuleName() + "-install"
- ctx.Build(pctx, blueprint.BuildParams{
+ name := PathForPhony(ctx, ctx.ModuleName()+"-install")
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{name},
- Implicits: allInstalledFiles.Strings(),
- Optional: ctx.Config().(Config).EmbeddedInMake(),
+ Output: name,
+ Implicits: allInstalledFiles,
+ Default: !ctx.Config().EmbeddedInMake(),
})
deps = append(deps, name)
a.installTarget = name
}
if len(allCheckbuildFiles) > 0 {
- name := ctx.ModuleName() + "-checkbuild"
- ctx.Build(pctx, blueprint.BuildParams{
+ name := PathForPhony(ctx, ctx.ModuleName()+"-checkbuild")
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{name},
- Implicits: allCheckbuildFiles.Strings(),
- Optional: true,
+ Output: name,
+ Implicits: allCheckbuildFiles,
})
deps = append(deps, name)
a.checkbuildTarget = name
@@ -501,15 +525,14 @@
if len(deps) > 0 {
suffix := ""
- if ctx.Config().(Config).EmbeddedInMake() {
+ if ctx.Config().EmbeddedInMake() {
suffix = "-soong"
}
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{ctx.ModuleName() + suffix},
+ Output: PathForPhony(ctx, ctx.ModuleName()+suffix),
Implicits: deps,
- Optional: true,
})
a.blueprintDir = ctx.ModuleDir()
@@ -525,23 +548,23 @@
}
}
-func (a *ModuleBase) GenerateBuildActions(ctx blueprint.ModuleContext) {
- androidCtx := &androidModuleContext{
+func (a *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) {
+ ctx := &androidModuleContext{
module: a.module,
- ModuleContext: ctx,
- androidBaseContextImpl: a.androidBaseContextFactory(ctx),
- installDeps: a.computeInstallDeps(ctx),
+ ModuleContext: blueprintCtx,
+ androidBaseContextImpl: a.androidBaseContextFactory(blueprintCtx),
+ installDeps: a.computeInstallDeps(blueprintCtx),
installFiles: a.installFiles,
- missingDeps: ctx.GetMissingDependencies(),
+ missingDeps: blueprintCtx.GetMissingDependencies(),
}
desc := "//" + ctx.ModuleDir() + ":" + ctx.ModuleName() + " "
var suffix []string
- if androidCtx.Os().Class != Device && androidCtx.Os().Class != Generic {
- suffix = append(suffix, androidCtx.Os().String())
+ if ctx.Os().Class != Device && ctx.Os().Class != Generic {
+ suffix = append(suffix, ctx.Os().String())
}
- if !androidCtx.PrimaryArch() {
- suffix = append(suffix, androidCtx.Arch().ArchType.String())
+ if !ctx.PrimaryArch() {
+ suffix = append(suffix, ctx.Arch().ArchType.String())
}
ctx.Variable(pctx, "moduleDesc", desc)
@@ -553,13 +576,13 @@
ctx.Variable(pctx, "moduleDescSuffix", s)
if a.Enabled() {
- a.module.GenerateAndroidBuildActions(androidCtx)
+ a.module.GenerateAndroidBuildActions(ctx)
if ctx.Failed() {
return
}
- a.installFiles = append(a.installFiles, androidCtx.installFiles...)
- a.checkbuildFiles = append(a.checkbuildFiles, androidCtx.checkbuildFiles...)
+ a.installFiles = append(a.installFiles, ctx.installFiles...)
+ a.checkbuildFiles = append(a.checkbuildFiles, ctx.checkbuildFiles...)
}
if a == ctx.FinalModule().(Module).base() {
@@ -569,7 +592,7 @@
}
}
- a.buildParams = androidCtx.buildParams
+ a.buildParams = ctx.buildParams
}
type androidBaseContextImpl struct {
@@ -594,7 +617,7 @@
}
func (a *androidModuleContext) ninjaError(desc string, outputs []string, err error) {
- a.ModuleContext.Build(pctx, blueprint.BuildParams{
+ a.ModuleContext.Build(pctx.PackageContext, blueprint.BuildParams{
Rule: ErrorRule,
Description: desc,
Outputs: outputs,
@@ -606,17 +629,18 @@
return
}
-func (a *androidModuleContext) ModuleBuild(pctx blueprint.PackageContext, params ModuleBuildParams) {
+func (a *androidModuleContext) Config() Config {
+ return a.ModuleContext.Config().(Config)
+}
+
+func (a *androidModuleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
a.Build(pctx, BuildParams(params))
}
-func (a *androidModuleContext) Build(pctx blueprint.PackageContext, params BuildParams) {
- if a.config.captureBuild {
- a.buildParams = append(a.buildParams, params)
- }
-
+func convertBuildParams(params BuildParams) blueprint.BuildParams {
bparams := blueprint.BuildParams{
Rule: params.Rule,
+ Description: params.Description,
Deps: params.Deps,
Outputs: params.Outputs.Strings(),
ImplicitOutputs: params.ImplicitOutputs.Strings(),
@@ -627,10 +651,6 @@
Optional: !params.Default,
}
- if params.Description != "" {
- bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
- }
-
if params.Depfile != nil {
bparams.Depfile = params.Depfile.String()
}
@@ -647,6 +667,30 @@
bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
}
+ return bparams
+}
+
+func (a *androidModuleContext) Variable(pctx PackageContext, name, value string) {
+ a.ModuleContext.Variable(pctx.PackageContext, name, value)
+}
+
+func (a *androidModuleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
+ argNames ...string) blueprint.Rule {
+
+ return a.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...)
+}
+
+func (a *androidModuleContext) Build(pctx PackageContext, params BuildParams) {
+ if a.config.captureBuild {
+ a.buildParams = append(a.buildParams, params)
+ }
+
+ bparams := convertBuildParams(params)
+
+ if bparams.Description != "" {
+ bparams.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
+ }
+
if a.missingDeps != nil {
a.ninjaError(bparams.Description, bparams.Outputs,
fmt.Errorf("module %s missing dependencies: %s\n",
@@ -654,7 +698,7 @@
return
}
- a.ModuleContext.Build(pctx, bparams)
+ a.ModuleContext.Build(pctx.PackageContext, bparams)
}
func (a *androidModuleContext) GetMissingDependencies() []string {
@@ -676,7 +720,7 @@
}
if !aModule.Enabled() {
- if a.AConfig().AllowMissingDependencies() {
+ if a.Config().AllowMissingDependencies() {
a.AddMissingDependencies([]string{a.OtherModuleName(aModule)})
} else {
a.ModuleErrorf("depends on disabled module %q", a.OtherModuleName(aModule))
@@ -751,6 +795,20 @@
})
}
+func (a *androidModuleContext) VisitAllModuleVariants(visit func(Module)) {
+ a.ModuleContext.VisitAllModuleVariants(func(module blueprint.Module) {
+ visit(module.(Module))
+ })
+}
+
+func (a *androidModuleContext) PrimaryModule() Module {
+ return a.ModuleContext.PrimaryModule().(Module)
+}
+
+func (a *androidModuleContext) FinalModule() Module {
+ return a.ModuleContext.FinalModule().(Module)
+}
+
func (a *androidBaseContextImpl) Target() Target {
return a.target
}
@@ -820,11 +878,11 @@
}
if a.Device() {
- if a.AConfig().SkipDeviceInstall() {
+ if a.Config().SkipDeviceInstall() {
return true
}
- if a.AConfig().SkipMegaDeviceInstall(fullInstallPath.String()) {
+ if a.Config().SkipMegaDeviceInstall(fullInstallPath.String()) {
return true
}
}
@@ -869,7 +927,7 @@
Input: srcPath,
Implicits: implicitDeps,
OrderOnly: orderOnlyDeps,
- Default: !a.AConfig().EmbeddedInMake(),
+ Default: !a.Config().EmbeddedInMake(),
})
a.installFiles = append(a.installFiles, fullInstallPath)
@@ -889,7 +947,7 @@
Description: "install symlink " + fullInstallPath.Base(),
Output: fullInstallPath,
OrderOnly: Paths{srcPath},
- Default: !a.AConfig().EmbeddedInMake(),
+ Default: !a.Config().EmbeddedInMake(),
Args: map[string]string{
"fromPath": srcPath.String(),
},
@@ -1027,7 +1085,7 @@
RegisterSingletonType("buildtarget", BuildTargetSingleton)
}
-func BuildTargetSingleton() blueprint.Singleton {
+func BuildTargetSingleton() Singleton {
return &buildTargetSingleton{}
}
@@ -1038,50 +1096,57 @@
type buildTargetSingleton struct{}
-func (c *buildTargetSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
- checkbuildDeps := []string{}
+func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
+ var checkbuildDeps Paths
- mmTarget := func(dir string) string {
- return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
+ mmTarget := func(dir string) WritablePath {
+ return PathForPhony(ctx,
+ "MODULES-IN-"+strings.Replace(filepath.Clean(dir), "/", "-", -1))
}
- modulesInDir := make(map[string][]string)
+ modulesInDir := make(map[string]Paths)
- ctx.VisitAllModules(func(module blueprint.Module) {
- if a, ok := module.(Module); ok {
- blueprintDir := a.base().blueprintDir
- installTarget := a.base().installTarget
- checkbuildTarget := a.base().checkbuildTarget
+ ctx.VisitAllModules(func(module Module) {
+ blueprintDir := module.base().blueprintDir
+ installTarget := module.base().installTarget
+ checkbuildTarget := module.base().checkbuildTarget
- if checkbuildTarget != "" {
- checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
- modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], checkbuildTarget)
- }
+ if checkbuildTarget != nil {
+ checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
+ modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], checkbuildTarget)
+ }
- if installTarget != "" {
- modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget)
- }
+ if installTarget != nil {
+ modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget)
}
})
suffix := ""
- if ctx.Config().(Config).EmbeddedInMake() {
+ if ctx.Config().EmbeddedInMake() {
suffix = "-soong"
}
// Create a top-level checkbuild target that depends on all modules
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{"checkbuild" + suffix},
+ Output: PathForPhony(ctx, "checkbuild"+suffix),
Implicits: checkbuildDeps,
- Optional: true,
})
// Make will generate the MODULES-IN-* targets
- if ctx.Config().(Config).EmbeddedInMake() {
+ if ctx.Config().EmbeddedInMake() {
return
}
+ sortedKeys := func(m map[string]Paths) []string {
+ s := make([]string, 0, len(m))
+ for k := range m {
+ s = append(s, k)
+ }
+ sort.Strings(s)
+ return s
+ }
+
// Ensure ancestor directories are in modulesInDir
dirs := sortedKeys(modulesInDir)
for _, dir := range dirs {
@@ -1108,28 +1173,26 @@
// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
// files.
for _, dir := range dirs {
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{mmTarget(dir)},
+ Output: mmTarget(dir),
Implicits: modulesInDir[dir],
// HACK: checkbuild should be an optional build, but force it
// enabled for now in standalone builds
- Optional: ctx.Config().(Config).EmbeddedInMake(),
+ Default: !ctx.Config().EmbeddedInMake(),
})
}
// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild.
osDeps := map[OsType]Paths{}
- ctx.VisitAllModules(func(module blueprint.Module) {
- if a, ok := module.(Module); ok {
- if a.Enabled() {
- os := a.Target().Os
- osDeps[os] = append(osDeps[os], a.base().checkbuildFiles...)
- }
+ ctx.VisitAllModules(func(module Module) {
+ if module.Enabled() {
+ os := module.Target().Os
+ osDeps[os] = append(osDeps[os], module.base().checkbuildFiles...)
}
})
- osClass := make(map[string][]string)
+ osClass := make(map[string]Paths)
for os, deps := range osDeps {
var className string
@@ -1144,25 +1207,23 @@
continue
}
- name := className + "-" + os.Name
+ name := PathForPhony(ctx, className+"-"+os.Name)
osClass[className] = append(osClass[className], name)
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{name},
- Implicits: deps.Strings(),
- Optional: true,
+ Output: name,
+ Implicits: deps,
})
}
// Wrap those into host|host-cross|target phony rules
osClasses := sortedKeys(osClass)
for _, class := range osClasses {
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{class},
+ Output: PathForPhony(ctx, class),
Implicits: osClass[class],
- Optional: true,
})
}
}
diff --git a/android/mutator.go b/android/mutator.go
index cc3f1f3..db3eaa3 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -108,7 +108,7 @@
type AndroidTopDownMutator func(TopDownMutatorContext)
type TopDownMutatorContext interface {
- blueprint.BaseModuleContext
+ BaseModuleContext
androidBaseContext
OtherModuleExists(name string) bool
@@ -139,8 +139,22 @@
type AndroidBottomUpMutator func(BottomUpMutatorContext)
type BottomUpMutatorContext interface {
- blueprint.BottomUpMutatorContext
+ BaseModuleContext
androidBaseContext
+
+ OtherModuleExists(name string) bool
+ Rename(name string)
+ Module() blueprint.Module
+
+ AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string)
+ AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string)
+ CreateVariations(...string) []blueprint.Module
+ CreateLocalVariations(...string) []blueprint.Module
+ SetDependencyVariation(string)
+ AddVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+ AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
+ AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
+ ReplaceDependencies(string)
}
type androidBottomUpMutatorContext struct {
@@ -193,6 +207,14 @@
}
}
+func (a *androidTopDownMutatorContext) Config() Config {
+ return a.config
+}
+
+func (a *androidBottomUpMutatorContext) Config() Config {
+ return a.config
+}
+
func (a *androidTopDownMutatorContext) Module() Module {
module, _ := a.TopDownMutatorContext.Module().(Module)
return module
diff --git a/android/package_ctx.go b/android/package_ctx.go
index d32e82b..3f6a253 100644
--- a/android/package_ctx.go
+++ b/android/package_ctx.go
@@ -16,20 +16,21 @@
import (
"fmt"
+ "runtime"
"strings"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
)
-// AndroidPackageContext is a wrapper for blueprint.PackageContext that adds
+// PackageContext is a wrapper for blueprint.PackageContext that adds
// some android-specific helper functions.
-type AndroidPackageContext struct {
+type PackageContext struct {
blueprint.PackageContext
}
-func NewPackageContext(pkgPath string) AndroidPackageContext {
- return AndroidPackageContext{blueprint.NewPackageContext(pkgPath)}
+func NewPackageContext(pkgPath string) PackageContext {
+ return PackageContext{blueprint.NewPackageContext(pkgPath)}
}
// configErrorWrapper can be used with Path functions when a Context is not
@@ -39,7 +40,7 @@
// The most common use here will be with VariableFunc, where only a config is
// provided, and an error should be returned.
type configErrorWrapper struct {
- pctx AndroidPackageContext
+ pctx PackageContext
config Config
errors []error
}
@@ -47,7 +48,7 @@
var _ PathContext = &configErrorWrapper{}
var _ errorfContext = &configErrorWrapper{}
-func (e *configErrorWrapper) Config() interface{} {
+func (e *configErrorWrapper) Config() Config {
return e.config
}
func (e *configErrorWrapper) Errorf(format string, args ...interface{}) {
@@ -61,13 +62,43 @@
return nil
}
+// VariableFunc wraps blueprint.PackageContext.VariableFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) VariableFunc(name string,
+ f func(Config) (string, error)) blueprint.Variable {
+
+ return p.PackageContext.VariableFunc(name, func(config interface{}) (string, error) {
+ return f(config.(Config))
+ })
+}
+
+// PoolFunc wraps blueprint.PackageContext.PoolFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) PoolFunc(name string,
+ f func(Config) (blueprint.PoolParams, error)) blueprint.Pool {
+
+ return p.PackageContext.PoolFunc(name, func(config interface{}) (blueprint.PoolParams, error) {
+ return f(config.(Config))
+ })
+}
+
+// RuleFunc wraps blueprint.PackageContext.RuleFunc, converting the interface{} config
+// argument to a Config.
+func (p PackageContext) RuleFunc(name string,
+ f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
+
+ return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
+ return f(config.(Config))
+ }, argNames...)
+}
+
// SourcePathVariable returns a Variable whose value is the source directory
// appended with the supplied path. It may only be called during a Go package's
// initialization - either from the init() function or as part of a
// package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathVariable(name, path string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathVariable(name, path string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
p := safePathForSource(ctx, path)
if len(ctx.errors) > 0 {
return "", ctx.errors[0]
@@ -80,9 +111,9 @@
// appended with the supplied paths, joined with separator. It may only be
// called during a Go package's initialization - either from the init()
// function or as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathsVariable(name, separator string, paths ...string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
var ret []string
for _, path := range paths {
p := safePathForSource(ctx, path)
@@ -100,23 +131,23 @@
// The environment variable is not required to point to a path inside the source tree.
// It may only be called during a Go package's initialization - either from the init() function or
// as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) SourcePathVariableWithEnvOverride(name, path, env string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
p := safePathForSource(ctx, path)
if len(ctx.errors) > 0 {
return "", ctx.errors[0]
}
- return config.(Config).GetenvWithDefault(env, p.String()), nil
+ return config.GetenvWithDefault(env, p.String()), nil
})
}
-// HostBinVariable returns a Variable whose value is the path to a host tool
+// HostBinToolVariable returns a Variable whose value is the path to a host tool
// in the bin directory for host targets. It may only be called during a Go
// package's initialization - either from the init() function or as part of a
// package-scoped variable's initialization.
-func (p AndroidPackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
+func (p PackageContext) HostBinToolVariable(name, path string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
po, err := p.HostBinToolPath(config, path)
if err != nil {
return "", err
@@ -125,8 +156,8 @@
})
}
-func (p AndroidPackageContext) HostBinToolPath(config interface{}, path string) (Path, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostBinToolPath(config Config, path string) (Path, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "bin", path)
if len(ctx.errors) > 0 {
return nil, ctx.errors[0]
@@ -134,13 +165,40 @@
return pa, nil
}
+// HostJNIToolVariable returns a Variable whose value is the path to a host tool
+// in the lib directory for host targets. It may only be called during a Go
+// package's initialization - either from the init() function or as part of a
+// package-scoped variable's initialization.
+func (p PackageContext) HostJNIToolVariable(name, path string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ po, err := p.HostJNIToolPath(config, path)
+ if err != nil {
+ return "", err
+ }
+ return po.String(), nil
+ })
+}
+
+func (p PackageContext) HostJNIToolPath(config Config, path string) (Path, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
+ ext := ".so"
+ if runtime.GOOS == "darwin" {
+ ext = ".dylib"
+ }
+ pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "lib64", path+ext)
+ if len(ctx.errors) > 0 {
+ return nil, ctx.errors[0]
+ }
+ return pa, nil
+}
+
// HostJavaToolVariable returns a Variable whose value is the path to a host
// tool in the frameworks directory for host targets. It may only be called
// during a Go package's initialization - either from the init() function or as
// part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostJavaToolVariable(name, path string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
p := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
if len(ctx.errors) > 0 {
return "", ctx.errors[0]
@@ -149,8 +207,8 @@
})
}
-func (p AndroidPackageContext) HostJavaToolPath(config interface{}, path string) (Path, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) HostJavaToolPath(config Config, path string) (Path, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
pa := PathForOutput(ctx, "host", ctx.config.PrebuiltOS(), "framework", path)
if len(ctx.errors) > 0 {
return nil, ctx.errors[0]
@@ -162,9 +220,9 @@
// directory appended with the supplied path. It may only be called during a Go
// package's initialization - either from the init() function or as part of a
// package-scoped variable's initialization.
-func (p AndroidPackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+func (p PackageContext) IntermediatesPathVariable(name, path string) blueprint.Variable {
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
p := PathForIntermediates(ctx, path)
if len(ctx.errors) > 0 {
return "", ctx.errors[0]
@@ -177,11 +235,11 @@
// list of present source paths prefixed with the supplied prefix. It may only
// be called during a Go package's initialization - either from the init()
// function or as part of a package-scoped variable's initialization.
-func (p AndroidPackageContext) PrefixedExistentPathsForSourcesVariable(
+func (p PackageContext) PrefixedExistentPathsForSourcesVariable(
name, prefix string, paths []string) blueprint.Variable {
- return p.VariableFunc(name, func(config interface{}) (string, error) {
- ctx := &configErrorWrapper{p, config.(Config), []error{}}
+ return p.VariableFunc(name, func(config Config) (string, error) {
+ ctx := &configErrorWrapper{p, config, []error{}}
paths := ExistentPathsForSources(ctx, "", paths)
if len(ctx.errors) > 0 {
return "", ctx.errors[0]
@@ -196,7 +254,7 @@
}
// AndroidStaticRule wraps blueprint.StaticRule and provides a default Pool if none is specified
-func (p AndroidPackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
+func (p PackageContext) AndroidStaticRule(name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
return p.AndroidRuleFunc(name, func(Config) (blueprint.RuleParams, error) {
return params, nil
@@ -204,16 +262,16 @@
}
// AndroidGomaStaticRule wraps blueprint.StaticRule but uses goma's parallelism if goma is enabled
-func (p AndroidPackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
+func (p PackageContext) AndroidGomaStaticRule(name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
return p.StaticRule(name, params, argNames...)
}
-func (p AndroidPackageContext) AndroidRuleFunc(name string,
+func (p PackageContext) AndroidRuleFunc(name string,
f func(Config) (blueprint.RuleParams, error), argNames ...string) blueprint.Rule {
- return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) {
- params, err := f(config.(Config))
- if config.(Config).UseGoma() && params.Pool == nil {
+ return p.RuleFunc(name, func(config Config) (blueprint.RuleParams, error) {
+ params, err := f(config)
+ if config.UseGoma() && params.Pool == nil {
// When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the
// local parallelism value
params.Pool = localPool
diff --git a/android/paths.go b/android/paths.go
index 4adaa2d..e0cbd21 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -29,7 +29,7 @@
// Path methods.
type PathContext interface {
Fs() pathtools.FileSystem
- Config() interface{}
+ Config() Config
AddNinjaFileDeps(deps ...string)
}
@@ -37,8 +37,8 @@
GlobWithDeps(globPattern string, excludes []string) ([]string, error)
}
-var _ PathContext = blueprint.SingletonContext(nil)
-var _ PathContext = blueprint.ModuleContext(nil)
+var _ PathContext = SingletonContext(nil)
+var _ PathContext = ModuleContext(nil)
type ModuleInstallPathContext interface {
PathContext
@@ -67,15 +67,6 @@
var _ moduleErrorf = blueprint.ModuleContext(nil)
-// pathConfig returns the android Config interface associated to the context.
-// Panics if the context isn't affiliated with an android build.
-func pathConfig(ctx PathContext) Config {
- if ret, ok := ctx.Config().(Config); ok {
- return ret
- }
- panic("Paths may only be used on Soong builds")
-}
-
// reportPathError will register an error with the attached context. It
// attempts ctx.ModuleErrorf for a better error message first, then falls
// back to ctx.Errorf.
@@ -197,7 +188,7 @@
// PathsForSource returns Paths rooted from SrcDir
func PathsForSource(ctx PathContext, paths []string) Paths {
- if pathConfig(ctx).AllowMissingDependencies() {
+ if ctx.Config().AllowMissingDependencies() {
if modCtx, ok := ctx.(ModuleContext); ok {
ret := make(Paths, 0, len(paths))
intermediates := pathForModule(modCtx).withRel("missing")
@@ -247,7 +238,7 @@
// source directory, but strip the local source directory from the beginning of
// each string.
func pathsForModuleSrcFromFullPath(ctx ModuleContext, paths []string) Paths {
- prefix := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir()) + "/"
+ prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/"
if prefix == "./" {
prefix = ""
}
@@ -271,7 +262,7 @@
}
// Use Glob so that if the default doesn't exist, a dependency is added so that when it
// is created, we're run again.
- path := filepath.Join(ctx.AConfig().srcDir, ctx.ModuleDir(), def)
+ path := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir(), def)
return ctx.Glob(path, []string{})
}
@@ -428,6 +419,18 @@
return ret
}
+// Paths returns the WritablePaths as a Paths
+func (p WritablePaths) Paths() Paths {
+ if p == nil {
+ return nil
+ }
+ ret := make(Paths, len(p))
+ for i, path := range p {
+ ret[i] = path
+ }
+ return ret
+}
+
type basePath struct {
path string
config Config
@@ -449,6 +452,10 @@
return p.path
}
+func (p basePath) String() string {
+ return p.path
+}
+
// SourcePath is a Path representing a file path rooted from SrcDir
type SourcePath struct {
basePath
@@ -460,14 +467,14 @@
// code that is embedding ninja variables in paths
func safePathForSource(ctx PathContext, path string) SourcePath {
p := validateSafePath(ctx, path)
- ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+ ret := SourcePath{basePath{p, ctx.Config(), ""}}
abs, err := filepath.Abs(ret.String())
if err != nil {
reportPathError(ctx, "%s", err.Error())
return ret
}
- buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+ buildroot, err := filepath.Abs(ctx.Config().buildDir)
if err != nil {
reportPathError(ctx, "%s", err.Error())
return ret
@@ -485,14 +492,14 @@
// On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
p := validatePath(ctx, pathComponents...)
- ret := SourcePath{basePath{p, pathConfig(ctx), ""}}
+ ret := SourcePath{basePath{p, ctx.Config(), ""}}
abs, err := filepath.Abs(ret.String())
if err != nil {
reportPathError(ctx, "%s", err.Error())
return ret
}
- buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+ buildroot, err := filepath.Abs(ctx.Config().buildDir)
if err != nil {
reportPathError(ctx, "%s", err.Error())
return ret
@@ -520,14 +527,14 @@
}
p := validatePath(ctx, pathComponents...)
- path := SourcePath{basePath{p, pathConfig(ctx), ""}}
+ path := SourcePath{basePath{p, ctx.Config(), ""}}
abs, err := filepath.Abs(path.String())
if err != nil {
reportPathError(ctx, "%s", err.Error())
return OptionalPath{}
}
- buildroot, err := filepath.Abs(pathConfig(ctx).buildDir)
+ buildroot, err := filepath.Abs(ctx.Config().buildDir)
if err != nil {
reportPathError(ctx, "%s", err.Error())
return OptionalPath{}
@@ -636,7 +643,7 @@
// On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
path := validatePath(ctx, pathComponents...)
- return OutputPath{basePath{path, pathConfig(ctx), ""}}
+ return OutputPath{basePath{path, ctx.Config(), ""}}
}
func (p OutputPath) writablePath() {}
@@ -837,7 +844,7 @@
if ctx.InstallInSanitizerDir() {
partition = "data/asan/" + partition
}
- outPaths = []string{"target", "product", ctx.AConfig().DeviceName(), partition}
+ outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
switch ctx.Os() {
case Linux:
@@ -885,6 +892,13 @@
return validateSafePath(ctx, pathComponents...)
}
+func PathForPhony(ctx PathContext, phony string) WritablePath {
+ if strings.ContainsAny(phony, "$/") {
+ reportPathError(ctx, "Phony target contains invalid character ($ or /): %s", phony)
+ }
+ return OutputPath{basePath{phony, ctx.Config(), ""}}
+}
+
type testPath struct {
basePath
}
diff --git a/android/paths_test.go b/android/paths_test.go
index 82ae4dc..1e4ba53 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -194,7 +194,7 @@
return pathtools.MockFs(nil)
}
-func (m moduleInstallPathContextImpl) Config() interface{} {
+func (m moduleInstallPathContextImpl) Config() Config {
return m.androidBaseContextImpl.config
}
diff --git a/android/register.go b/android/register.go
index 81a266d..6c88af1 100644
--- a/android/register.go
+++ b/android/register.go
@@ -44,7 +44,7 @@
type ModuleFactory func() Module
-// ModuleFactoryAdaptor Wraps a ModuleFactory into a blueprint.ModuleFactory by converting an Module
+// ModuleFactoryAdaptor wraps a ModuleFactory into a blueprint.ModuleFactory by converting a Module
// into a blueprint.Module and a list of property structs
func ModuleFactoryAdaptor(factory ModuleFactory) blueprint.ModuleFactory {
return func() (blueprint.Module, []interface{}) {
@@ -53,16 +53,27 @@
}
}
+type SingletonFactory func() Singleton
+
+// SingletonFactoryAdaptor wraps a SingletonFactory into a blueprint.SingletonFactory by converting
+// a Singleton into a blueprint.Singleton
+func SingletonFactoryAdaptor(factory SingletonFactory) blueprint.SingletonFactory {
+ return func() blueprint.Singleton {
+ singleton := factory()
+ return singletonAdaptor{singleton}
+ }
+}
+
func RegisterModuleType(name string, factory ModuleFactory) {
moduleTypes = append(moduleTypes, moduleType{name, ModuleFactoryAdaptor(factory)})
}
-func RegisterSingletonType(name string, factory blueprint.SingletonFactory) {
- singletons = append(singletons, singleton{name, factory})
+func RegisterSingletonType(name string, factory SingletonFactory) {
+ singletons = append(singletons, singleton{name, SingletonFactoryAdaptor(factory)})
}
-func RegisterPreSingletonType(name string, factory blueprint.SingletonFactory) {
- preSingletons = append(preSingletons, singleton{name, factory})
+func RegisterPreSingletonType(name string, factory SingletonFactory) {
+ preSingletons = append(preSingletons, singleton{name, SingletonFactoryAdaptor(factory)})
}
type Context struct {
@@ -88,5 +99,5 @@
registerMutators(ctx.Context, preArch, preDeps, postDeps)
- ctx.RegisterSingletonType("env", EnvSingleton)
+ ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
}
diff --git a/android/singleton.go b/android/singleton.go
new file mode 100644
index 0000000..87910fd
--- /dev/null
+++ b/android/singleton.go
@@ -0,0 +1,165 @@
+// Copyright 2017 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 android
+
+import (
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
+)
+
+// SingletonContext
+type SingletonContext interface {
+ Config() Config
+
+ ModuleName(module blueprint.Module) string
+ ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
+ ModuleType(module blueprint.Module) string
+ BlueprintFile(module blueprint.Module) string
+
+ ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+ Failed() bool
+
+ Variable(pctx PackageContext, name, value string)
+ Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) blueprint.Rule
+ Build(pctx PackageContext, params BuildParams)
+ RequireNinjaVersion(major, minor, micro int)
+
+ // SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
+ // that controls where Ninja stores its build log files. This value can be
+ // set at most one time for a single build, later calls are ignored.
+ SetNinjaBuildDir(pctx PackageContext, value string)
+
+ // Eval takes a string with embedded ninja variables, and returns a string
+ // with all of the variables recursively expanded. Any variables references
+ // are expanded in the scope of the PackageContext.
+ Eval(pctx PackageContext, ninjaStr string) (string, error)
+
+ VisitAllModules(visit func(Module))
+ VisitAllModulesIf(pred func(Module) bool, visit func(Module))
+ VisitDepsDepthFirst(module Module, visit func(Module))
+ VisitDepsDepthFirstIf(module Module, pred func(Module) bool,
+ visit func(Module))
+
+ VisitAllModuleVariants(module Module, visit func(Module))
+
+ PrimaryModule(module Module) Module
+ FinalModule(module Module) Module
+
+ AddNinjaFileDeps(deps ...string)
+
+ // GlobWithDeps returns a list of files that match the specified pattern but do not match any
+ // of the patterns in excludes. It also adds efficient dependencies to rerun the primary
+ // builder whenever a file matching the pattern as added or removed, without rerunning if a
+ // file that does not match the pattern is added to a searched directory.
+ GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+ Fs() pathtools.FileSystem
+}
+
+type singletonAdaptor struct {
+ Singleton
+}
+
+func (s singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
+ s.Singleton.GenerateBuildActions(singletonContextAdaptor{ctx})
+}
+
+type Singleton interface {
+ GenerateBuildActions(SingletonContext)
+}
+
+type singletonContextAdaptor struct {
+ blueprint.SingletonContext
+}
+
+func (s singletonContextAdaptor) Config() Config {
+ return s.SingletonContext.Config().(Config)
+}
+
+func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
+ s.SingletonContext.Variable(pctx.PackageContext, name, value)
+}
+
+func (s singletonContextAdaptor) Rule(pctx PackageContext, name string, params RuleParams, argNames ...string) blueprint.Rule {
+ return s.SingletonContext.Rule(pctx.PackageContext, name, params.RuleParams, argNames...)
+}
+
+func (s singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
+ bparams := convertBuildParams(params)
+ s.SingletonContext.Build(pctx.PackageContext, bparams)
+
+}
+
+func (s singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
+ s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
+}
+
+func (s singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
+ return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
+}
+
+// visitAdaptor wraps a visit function that takes an android.Module parameter into
+// a function that takes an blueprint.Module parameter and only calls the visit function if the
+// blueprint.Module is an android.Module.
+func visitAdaptor(visit func(Module)) func(blueprint.Module) {
+ return func(module blueprint.Module) {
+ if aModule, ok := module.(Module); ok {
+ visit(aModule)
+ }
+ }
+}
+
+// predAdaptor wraps a pred function that takes an android.Module parameter
+// into a function that takes an blueprint.Module parameter and only calls the visit function if the
+// blueprint.Module is an android.Module, otherwise returns false.
+func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool {
+ return func(module blueprint.Module) bool {
+ if aModule, ok := module.(Module); ok {
+ return pred(aModule)
+ } else {
+ return false
+ }
+ }
+}
+
+func (s singletonContextAdaptor) VisitAllModules(visit func(Module)) {
+ s.SingletonContext.VisitAllModules(visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
+ s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
+ s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
+ s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
+ s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
+}
+
+func (s singletonContextAdaptor) PrimaryModule(module Module) Module {
+ return s.SingletonContext.PrimaryModule(module).(Module)
+}
+
+func (s singletonContextAdaptor) FinalModule(module Module) Module {
+ return s.SingletonContext.FinalModule(module).(Module)
+}
diff --git a/android/testing.go b/android/testing.go
index e79562d..fc58cec 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"strings"
"github.com/google/blueprint"
@@ -53,7 +54,7 @@
func (ctx *TestContext) Register() {
registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
- ctx.RegisterSingletonType("env", EnvSingleton)
+ ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
}
func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
@@ -78,6 +79,25 @@
return TestingModule{module}
}
+// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
+// filenames to contents stored as a byte slice.
+func (ctx *TestContext) MockFileSystem(files map[string][]byte) {
+ // no module list file specified; find every file named Blueprints or Android.bp
+ pathsToParse := []string{}
+ for candidate := range files {
+ base := filepath.Base(candidate)
+ if base == "Blueprints" || base == "Android.bp" {
+ pathsToParse = append(pathsToParse, candidate)
+ }
+ }
+ if len(pathsToParse) < 1 {
+ panic(fmt.Sprintf("No Blueprint or Android.bp files found in mock filesystem: %v\n", files))
+ }
+ files[blueprint.MockModuleListFile] = []byte(strings.Join(pathsToParse, "\n"))
+
+ ctx.Context.MockFileSystem(files)
+}
+
type TestingModule struct {
module Module
}
@@ -111,7 +131,7 @@
outputs = append(outputs, p.Output)
}
for _, f := range outputs {
- if f.Rel() == file {
+ if f.String() == file || f.Rel() == file {
return p
}
}
diff --git a/android/util.go b/android/util.go
index 4d30a74..29bb9b1 100644
--- a/android/util.go
+++ b/android/util.go
@@ -157,3 +157,10 @@
ok = true
return
}
+
+func GetNumericSdkVersion(v string) string {
+ if strings.Contains(v, "system_") {
+ return strings.Replace(v, "system_", "", 1)
+ }
+ return v
+}
diff --git a/android/variable.go b/android/variable.go
index 4272817..c8a672e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -189,6 +189,7 @@
Override_rs_driver *string `json:",omitempty"`
DeviceKernelHeaders []string `json:",omitempty"`
+ DistDir *string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -257,7 +258,7 @@
property := "product_variables." + proptools.PropertyNameForField(name)
// Check that the variable was set for the product
- val := reflect.ValueOf(mctx.Config().(Config).ProductVariables).FieldByName(name)
+ val := reflect.ValueOf(mctx.Config().ProductVariables).FieldByName(name)
if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
continue
}
diff --git a/androidmk/cmd/androidmk/android.go b/androidmk/cmd/androidmk/android.go
index df01cf4..18756a9 100644
--- a/androidmk/cmd/androidmk/android.go
+++ b/androidmk/cmd/androidmk/android.go
@@ -24,7 +24,8 @@
)
const (
- clear_vars = "__android_mk_clear_vars"
+ clear_vars = "__android_mk_clear_vars"
+ include_ignored = "__android_mk_include_ignored"
)
type bpVariable struct {
@@ -92,6 +93,7 @@
"LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api",
"LOCAL_NOTICE_FILE": "notice",
"LOCAL_JAVA_LANGUAGE_VERSION": "java_version",
+ "LOCAL_INSTRUMENTATION_FOR": "instrumentation_for",
})
addStandardProperties(bpparser.ListType,
map[string]string{
@@ -661,6 +663,8 @@
false: "target.not_linux_glibc"},
"(,$(TARGET_BUILD_APPS))": {
false: "product_variables.unbundled_build"},
+ "($(TARGET_BUILD_APPS),)": {
+ false: "product_variables.unbundled_build"},
"($(TARGET_BUILD_PDK),true)": {
true: "product_variables.pdk"},
"($(TARGET_BUILD_PDK), true)": {
@@ -693,6 +697,10 @@
return "**/*.java"
}
+func includeIgnored(args []string) string {
+ return include_ignored
+}
+
var moduleTypes = map[string]string{
"BUILD_SHARED_LIBRARY": "cc_library_shared",
"BUILD_STATIC_LIBRARY": "cc_library_static",
@@ -729,6 +737,10 @@
globalScope.SetFunc("all-java-files-under", allJavaFilesUnder)
globalScope.SetFunc("all-proto-files-under", allProtoFilesUnder)
globalScope.SetFunc("all-subdir-java-files", allSubdirJavaFiles)
+ globalScope.SetFunc("all-makefiles-under", includeIgnored)
+ globalScope.SetFunc("first-makefiles-under", includeIgnored)
+ globalScope.SetFunc("all-named-subdir-makefiles", includeIgnored)
+ globalScope.SetFunc("all-subdir-makefiles", includeIgnored)
for k, v := range moduleTypes {
globalScope.Set(k, v)
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 660d9a0..385690c 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -177,6 +177,9 @@
makeModule(file, val)
case val == clear_vars:
resetModule(file)
+ case val == include_ignored:
+ // subdirs are already automatically included in Soong
+ continue
default:
file.errorf(x, "unsupported include")
continue
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 0b86540..9986889 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -460,6 +460,13 @@
// endif
`,
},
+ {
+ desc: "ignore all-makefiles-under",
+ in: `
+include $(call all-makefiles-under,$(LOCAL_PATH))
+`,
+ expected: ``,
+ },
}
func reformatBlueprint(input string) string {
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 065d0aa..44e977f 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -318,7 +318,7 @@
ret.Class = "SHARED_LIBRARIES"
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- path, file := filepath.Split(c.installPath)
+ path, file := filepath.Split(c.installPath.String())
stem := strings.TrimSuffix(file, filepath.Ext(file))
fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=")
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+outputFile.Ext())
diff --git a/cc/binary.go b/cc/binary.go
index 5f81866..206237a 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -182,7 +182,7 @@
if !ctx.toolchain().Bionic() {
if ctx.Os() == android.Linux {
- if binary.Properties.Static_executable == nil && Bool(ctx.AConfig().ProductVariables.HostStaticBinaries) {
+ if binary.Properties.Static_executable == nil && Bool(ctx.Config().ProductVariables.HostStaticBinaries) {
binary.Properties.Static_executable = BoolPtr(true)
}
} else {
@@ -204,7 +204,7 @@
flags = binary.baseLinker.linkerFlags(ctx, flags)
if ctx.Host() && !binary.static() {
- if !ctx.AConfig().IsEnvTrue("DISABLE_HOST_PIE") {
+ if !ctx.Config().IsEnvTrue("DISABLE_HOST_PIE") {
flags.LdFlags = append(flags.LdFlags, "-pie")
if ctx.Windows() {
flags.LdFlags = append(flags.LdFlags, "-Wl,-e_mainCRTStartup")
diff --git a/cc/builder.go b/cc/builder.go
index a81dc89..b5f4c5c 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -196,11 +196,19 @@
_ = pctx.SourcePathVariable("sAbiDiffer", "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/header-abi-diff")
- // Abidiff check turned on in advice-only mode. Builds will not fail on abi incompatibilties / extensions.
- sAbiDiff = pctx.AndroidStaticRule("sAbiDiff",
- blueprint.RuleParams{
- Command: "$sAbiDiffer $allowFlags -lib $libName -arch $arch -check-all-apis -o ${out} -new $in -old $referenceDump",
- CommandDeps: []string{"$sAbiDiffer"},
+ sAbiDiff = pctx.AndroidRuleFunc("sAbiDiff",
+ func(config android.Config) (blueprint.RuleParams, error) {
+
+ commandStr := "($sAbiDiffer $allowFlags -lib $libName -arch $arch -check-all-apis -o ${out} -new $in -old $referenceDump)"
+ distDir := config.ProductVariables.DistDir
+ if distDir != nil && *distDir != "" {
+ distAbiDiffDir := *distDir + "/abidiffs/"
+ commandStr += " || (mkdir -p " + distAbiDiffDir + " && cp ${out} " + distAbiDiffDir + " && exit 1)"
+ }
+ return blueprint.RuleParams{
+ Command: commandStr,
+ CommandDeps: []string{"$sAbiDiffer"},
+ }, nil
},
"allowFlags", "referenceDump", "libName", "arch")
diff --git a/cc/cc.go b/cc/cc.go
index 384b240..891dccb 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -326,9 +326,12 @@
flags Flags
// When calling a linker, if module A depends on module B, then A must precede B in its command
- // line invocation. staticDepsInLinkOrder stores the proper ordering of all of the transitive
+ // line invocation. depsInLinkOrder stores the proper ordering of all of the transitive
// deps of this module
- staticDepsInLinkOrder android.Paths
+ depsInLinkOrder android.Paths
+
+ // only non-nil when this is a shared library that reuses the objects of a static library
+ staticVariant *Module
}
func (c *Module) Init() android.Module {
@@ -537,7 +540,8 @@
// orderDeps reorders dependencies into a list such that if module A depends on B, then
// A will precede B in the resultant list.
// This is convenient for passing into a linker.
-func orderDeps(directDeps []android.Path, transitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
+// Note that directSharedDeps should be the analogous static library for each shared lib dep
+func orderDeps(directStaticDeps []android.Path, directSharedDeps []android.Path, allTransitiveDeps map[android.Path][]android.Path) (orderedAllDeps []android.Path, orderedDeclaredDeps []android.Path) {
// If A depends on B, then
// Every list containing A will also contain B later in the list
// So, after concatenating all lists, the final instance of B will have come from the same
@@ -545,38 +549,46 @@
// So, the final instance of B will be later in the concatenation than the final A
// So, keeping only the final instance of A and of B ensures that A is earlier in the output
// list than B
- for _, dep := range directDeps {
+ for _, dep := range directStaticDeps {
orderedAllDeps = append(orderedAllDeps, dep)
- orderedAllDeps = append(orderedAllDeps, transitiveDeps[dep]...)
+ orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
+ }
+ for _, dep := range directSharedDeps {
+ orderedAllDeps = append(orderedAllDeps, dep)
+ orderedAllDeps = append(orderedAllDeps, allTransitiveDeps[dep]...)
}
orderedAllDeps = android.LastUniquePaths(orderedAllDeps)
- // We don't want to add any new dependencies into directDeps (to allow the caller to
+ // We don't want to add any new dependencies into directStaticDeps (to allow the caller to
// intentionally exclude or replace any unwanted transitive dependencies), so we limit the
- // resultant list to only what the caller has chosen to include in directDeps
- _, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directDeps)
+ // resultant list to only what the caller has chosen to include in directStaticDeps
+ _, orderedDeclaredDeps = android.FilterPathList(orderedAllDeps, directStaticDeps)
return orderedAllDeps, orderedDeclaredDeps
}
-func orderStaticModuleDeps(module *Module, deps []*Module) (results []android.Path) {
- // make map of transitive dependencies
- transitiveStaticDepNames := make(map[android.Path][]android.Path, len(deps))
- for _, dep := range deps {
- transitiveStaticDepNames[dep.outputFile.Path()] = dep.staticDepsInLinkOrder
+func orderStaticModuleDeps(module *Module, staticDeps []*Module, sharedDeps []*Module) (results []android.Path) {
+ // convert Module to Path
+ allTransitiveDeps := make(map[android.Path][]android.Path, len(staticDeps))
+ staticDepFiles := []android.Path{}
+ for _, dep := range staticDeps {
+ allTransitiveDeps[dep.outputFile.Path()] = dep.depsInLinkOrder
+ staticDepFiles = append(staticDepFiles, dep.outputFile.Path())
}
- // get the output file for each declared dependency
- depFiles := []android.Path{}
- for _, dep := range deps {
- depFiles = append(depFiles, dep.outputFile.Path())
+ sharedDepFiles := []android.Path{}
+ for _, sharedDep := range sharedDeps {
+ staticAnalogue := sharedDep.staticVariant
+ if staticAnalogue != nil {
+ allTransitiveDeps[staticAnalogue.outputFile.Path()] = staticAnalogue.depsInLinkOrder
+ sharedDepFiles = append(sharedDepFiles, staticAnalogue.outputFile.Path())
+ }
}
// reorder the dependencies based on transitive dependencies
- module.staticDepsInLinkOrder, results = orderDeps(depFiles, transitiveStaticDepNames)
+ module.depsInLinkOrder, results = orderDeps(staticDepFiles, sharedDepFiles, allTransitiveDeps)
return results
-
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
@@ -933,7 +945,7 @@
clang = true
}
- if ctx.Device() && ctx.AConfig().DeviceUsesClang() {
+ if ctx.Device() && ctx.Config().DeviceUsesClang() {
clang = true
}
}
@@ -1026,6 +1038,7 @@
var depPaths PathDeps
directStaticDeps := []*Module{}
+ directSharedDeps := []*Module{}
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
@@ -1092,6 +1105,7 @@
// re-exporting flags
if depTag == reuseObjTag {
if l, ok := ccDep.compiler.(libraryInterface); ok {
+ c.staticVariant = ccDep
objs, flags, deps := l.reuseObjs()
depPaths.Objs = depPaths.Objs.Append(objs)
depPaths.ReexportedFlags = append(depPaths.ReexportedFlags, flags...)
@@ -1130,6 +1144,7 @@
ptr = &depPaths.SharedLibs
depPtr = &depPaths.SharedLibsDeps
depFile = ccDep.linker.(libraryInterface).toc()
+ directSharedDeps = append(directSharedDeps, ccDep)
case lateSharedDepTag, ndkLateStubDepTag:
ptr = &depPaths.LateSharedLibs
depPtr = &depPaths.LateSharedLibsDeps
@@ -1221,7 +1236,7 @@
})
// use the ordered dependencies as this module's dependencies
- depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps)...)
+ depPaths.StaticLibs = append(depPaths.StaticLibs, orderStaticModuleDeps(c, directStaticDeps, directSharedDeps)...)
// Dedup exported flags from dependencies
depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
@@ -1426,10 +1441,10 @@
}
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
- if ctx.AConfig().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
+ if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
}
- return ctx.AConfig().PlatformSdkVersion()
+ return ctx.Config().PlatformSdkVersion()
}
var Bool = proptools.Bool
diff --git a/cc/cc_test.go b/cc/cc_test.go
index bdc8c17..148b4dd 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -289,7 +289,11 @@
var staticLinkDepOrderTestCases = []struct {
// This is a string representation of a map[moduleName][]moduleDependency .
// It models the dependencies declared in an Android.bp file.
- in string
+ inStatic string
+
+ // This is a string representation of a map[moduleName][]moduleDependency .
+ // It models the dependencies declared in an Android.bp file.
+ inShared string
// allOrdered is a string representation of a map[moduleName][]moduleDependency .
// The keys of allOrdered specify which modules we would like to check.
@@ -305,82 +309,99 @@
}{
// Simple tests
{
- in: "",
+ inStatic: "",
outOrdered: "",
},
{
- in: "a:",
+ inStatic: "a:",
outOrdered: "a:",
},
{
- in: "a:b; b:",
+ inStatic: "a:b; b:",
outOrdered: "a:b; b:",
},
// Tests of reordering
{
// diamond example
- in: "a:d,b,c; b:d; c:d; d:",
+ inStatic: "a:d,b,c; b:d; c:d; d:",
outOrdered: "a:b,c,d; b:d; c:d; d:",
},
{
// somewhat real example
- in: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
+ inStatic: "bsdiff_unittest:b,c,d,e,f,g,h,i; e:b",
outOrdered: "bsdiff_unittest:c,d,e,b,f,g,h,i; e:b",
},
{
// multiple reorderings
- in: "a:b,c,d,e; d:b; e:c",
+ inStatic: "a:b,c,d,e; d:b; e:c",
outOrdered: "a:d,b,e,c; d:b; e:c",
},
{
// should reorder without adding new transitive dependencies
- in: "bin:lib2,lib1; lib1:lib2,liboptional",
+ inStatic: "bin:lib2,lib1; lib1:lib2,liboptional",
allOrdered: "bin:lib1,lib2,liboptional; lib1:lib2,liboptional",
outOrdered: "bin:lib1,lib2; lib1:lib2,liboptional",
},
{
// multiple levels of dependencies
- in: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
+ inStatic: "a:b,c,d,e,f,g,h; f:b,c,d; b:c,d; c:d",
allOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
outOrdered: "a:e,f,b,c,d,g,h; f:b,c,d; b:c,d; c:d",
},
+ // shared dependencies
+ {
+ // Note that this test doesn't recurse, to minimize the amount of logic it tests.
+ // So, we don't actually have to check that a shared dependency of c will change the order
+ // of a library that depends statically on b and on c. We only need to check that if c has
+ // a shared dependency on b, that that shows up in allOrdered.
+ inShared: "c:b",
+ allOrdered: "c:b",
+ outOrdered: "c:",
+ },
+ {
+ // This test doesn't actually include any shared dependencies but it's a reminder of what
+ // the second phase of the above test would look like
+ inStatic: "a:b,c; c:b",
+ allOrdered: "a:c,b; c:b",
+ outOrdered: "a:c,b; c:b",
+ },
// tiebreakers for when two modules specifying different orderings and there is no dependency
// to dictate an order
{
// if the tie is between two modules at the end of a's deps, then a's order wins
- in: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
+ inStatic: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
outOrdered: "a1:b,c,d,e; a2:b,c,e,d; b:d,e; c:e,d",
},
{
// if the tie is between two modules at the start of a's deps, then c's order is used
- in: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
+ inStatic: "a1:d,e,b1,c1; b1:d,e; c1:e,d; a2:d,e,b2,c2; b2:d,e; c2:d,e",
outOrdered: "a1:b1,c1,e,d; b1:d,e; c1:e,d; a2:b2,c2,d,e; b2:d,e; c2:d,e",
},
// Tests involving duplicate dependencies
{
// simple duplicate
- in: "a:b,c,c,b",
+ inStatic: "a:b,c,c,b",
outOrdered: "a:c,b",
},
{
// duplicates with reordering
- in: "a:b,c,d,c; c:b",
+ inStatic: "a:b,c,d,c; c:b",
outOrdered: "a:d,c,b",
},
// Tests to confirm the nonexistence of infinite loops.
// These cases should never happen, so as long as the test terminates and the
// result is deterministic then that should be fine.
{
- in: "a:a",
+ inStatic: "a:a",
outOrdered: "a:a",
},
{
- in: "a:b; b:c; c:a",
+ inStatic: "a:b; b:c; c:a",
allOrdered: "a:b,c; b:c,a; c:a,b",
outOrdered: "a:b; b:c; c:a",
},
{
- in: "a:b,c; b:c,a; c:a,b",
+ inStatic: "a:b,c; b:c,a; c:a,b",
allOrdered: "a:c,a,b; b:a,b,c; c:b,c,a",
outOrdered: "a:c,b; b:a,c; c:b,a",
},
@@ -427,43 +448,47 @@
return modulesInOrder, allDeps
}
-func TestStaticLinkDependencyOrdering(t *testing.T) {
+func TestLinkReordering(t *testing.T) {
for _, testCase := range staticLinkDepOrderTestCases {
errs := []string{}
// parse testcase
- _, givenTransitiveDeps := parseModuleDeps(testCase.in)
+ _, givenTransitiveDeps := parseModuleDeps(testCase.inStatic)
expectedModuleNames, expectedTransitiveDeps := parseModuleDeps(testCase.outOrdered)
if testCase.allOrdered == "" {
// allow the test case to skip specifying allOrdered
testCase.allOrdered = testCase.outOrdered
}
_, expectedAllDeps := parseModuleDeps(testCase.allOrdered)
+ _, givenAllSharedDeps := parseModuleDeps(testCase.inShared)
// For each module whose post-reordered dependencies were specified, validate that
// reordering the inputs produces the expected outputs.
for _, moduleName := range expectedModuleNames {
moduleDeps := givenTransitiveDeps[moduleName]
- orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenTransitiveDeps)
+ givenSharedDeps := givenAllSharedDeps[moduleName]
+ orderedAllDeps, orderedDeclaredDeps := orderDeps(moduleDeps, givenSharedDeps, givenTransitiveDeps)
correctAllOrdered := expectedAllDeps[moduleName]
if !reflect.DeepEqual(orderedAllDeps, correctAllOrdered) {
errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedAllDeps."+
- "\nInput: %q"+
+ "\nin static:%q"+
+ "\nin shared:%q"+
"\nmodule: %v"+
"\nexpected: %s"+
"\nactual: %s",
- testCase.in, moduleName, correctAllOrdered, orderedAllDeps))
+ testCase.inStatic, testCase.inShared, moduleName, correctAllOrdered, orderedAllDeps))
}
correctOutputDeps := expectedTransitiveDeps[moduleName]
if !reflect.DeepEqual(correctOutputDeps, orderedDeclaredDeps) {
errs = append(errs, fmt.Sprintf("orderDeps returned incorrect orderedDeclaredDeps."+
- "\nInput: %q"+
+ "\nin static:%q"+
+ "\nin shared:%q"+
"\nmodule: %v"+
"\nexpected: %s"+
"\nactual: %s",
- testCase.in, moduleName, correctOutputDeps, orderedDeclaredDeps))
+ testCase.inStatic, testCase.inShared, moduleName, correctOutputDeps, orderedDeclaredDeps))
}
}
@@ -493,7 +518,7 @@
return paths
}
-func TestLibDeps(t *testing.T) {
+func TestStaticLibDepReordering(t *testing.T) {
ctx := testCc(t, `
cc_library {
name: "a",
@@ -514,7 +539,7 @@
variant := "android_arm64_armv8-a_core_static"
moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
- actual := moduleA.staticDepsInLinkOrder
+ actual := moduleA.depsInLinkOrder
expected := getOutputPaths(ctx, variant, []string{"c", "b", "d"})
if !reflect.DeepEqual(actual, expected) {
@@ -527,6 +552,37 @@
}
}
+func TestStaticLibDepReorderingWithShared(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "a",
+ static_libs: ["b", "c"],
+ }
+ cc_library {
+ name: "b",
+ }
+ cc_library {
+ name: "c",
+ shared_libs: ["b"],
+ }
+
+ `)
+
+ variant := "android_arm64_armv8-a_core_static"
+ moduleA := ctx.ModuleForTests("a", variant).Module().(*Module)
+ actual := moduleA.depsInLinkOrder
+ expected := getOutputPaths(ctx, variant, []string{"c", "b"})
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("staticDeps orderings did not account for shared libs"+
+ "\nactual: %v"+
+ "\nexpected: %v",
+ actual,
+ expected,
+ )
+ }
+}
+
var compilerFlagsTestCases = []struct {
in string
out bool
diff --git a/cc/cmakelists.go b/cc/cmakelists.go
index 13a2e8e..c25578e 100644
--- a/cc/cmakelists.go
+++ b/cc/cmakelists.go
@@ -23,8 +23,6 @@
"path"
"path/filepath"
"strings"
-
- "github.com/google/blueprint"
)
// This singleton generates CMakeLists.txt files. It does so for each blueprint Android.bp resulting in a cc.Module
@@ -35,7 +33,7 @@
android.RegisterSingletonType("cmakelists_generator", cMakeListsGeneratorSingleton)
}
-func cMakeListsGeneratorSingleton() blueprint.Singleton {
+func cMakeListsGeneratorSingleton() android.Singleton {
return &cmakelistsGeneratorSingleton{}
}
@@ -57,14 +55,14 @@
// This is done to ease investigating bug reports.
var outputDebugInfo = false
-func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
if getEnvVariable(envVariableGenerateCMakeLists, ctx) != envVariableTrue {
return
}
outputDebugInfo = (getEnvVariable(envVariableGenerateDebugInfo, ctx) == envVariableTrue)
- ctx.VisitAllModules(func(module blueprint.Module) {
+ ctx.VisitAllModules(func(module android.Module) {
if ccModule, ok := module.(*Module); ok {
if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok {
generateCLionProject(compiledModule, ctx, ccModule)
@@ -81,10 +79,10 @@
return
}
-func getEnvVariable(name string, ctx blueprint.SingletonContext) string {
+func getEnvVariable(name string, ctx android.SingletonContext) string {
// Using android.Config.Getenv instead of os.getEnv to guarantee soong will
// re-run in case this environment variable changes.
- return ctx.Config().(android.Config).Getenv(name)
+ return ctx.Config().Getenv(name)
}
func exists(path string) bool {
@@ -116,7 +114,7 @@
return nil
}
-func generateCLionProject(compiledModule CompiledInterface, ctx blueprint.SingletonContext, ccModule *Module) {
+func generateCLionProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module) {
srcs := compiledModule.Srcs()
if len(srcs) == 0 {
return
@@ -287,7 +285,7 @@
return flag
}
-func parseCompilerParameters(params []string, ctx blueprint.SingletonContext, f *os.File) compilerParameters {
+func parseCompilerParameters(params []string, ctx android.SingletonContext, f *os.File) compilerParameters {
var compilerParameters = makeCompilerParameters()
for i, str := range params {
@@ -388,7 +386,7 @@
c1.flags = append(c1.flags, c2.flags...)
}
-func evalVariable(ctx blueprint.SingletonContext, str string) (string, error) {
+func evalVariable(ctx android.SingletonContext, str string) (string, error) {
evaluated, err := ctx.Eval(pctx, str)
if err == nil {
return evaluated, nil
@@ -396,7 +394,7 @@
return "", err
}
-func getCMakeListsForModule(module *Module, ctx blueprint.SingletonContext) string {
+func getCMakeListsForModule(module *Module, ctx android.SingletonContext) string {
return filepath.Join(getAndroidSrcRootDirectory(ctx),
cLionOutputProjectsDirectory,
path.Dir(ctx.BlueprintFile(module)),
@@ -406,7 +404,7 @@
cMakeListsFilename)
}
-func getAndroidSrcRootDirectory(ctx blueprint.SingletonContext) string {
+func getAndroidSrcRootDirectory(ctx android.SingletonContext) string {
srcPath, _ := filepath.Abs(android.PathForSource(ctx).String())
return srcPath
}
diff --git a/cc/compiler.go b/cc/compiler.go
index ca68a00..d510aa3 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -206,6 +206,21 @@
return deps
}
+// Return true if the module is in the WarningAllowedProjects.
+func warningsAreAllowed(subdir string) bool {
+ subdir += "/"
+ for _, prefix := range config.WarningAllowedProjects {
+ if strings.HasPrefix(subdir, prefix) {
+ return true
+ }
+ }
+ return false
+}
+
+func addToModuleList(ctx ModuleContext, list string, module string) {
+ getWallWerrorMap(ctx.Config(), list).Store(module, true)
+}
+
// Create a Flags struct that collects the compile flags from global values,
// per-target values, module type values, and per-module Blueprints properties
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags {
@@ -345,7 +360,7 @@
fmt.Sprintf("${config.%sGlobalCflags}", hod))
}
- if Bool(ctx.AConfig().ProductVariables.Brillo) {
+ if Bool(ctx.Config().ProductVariables.Brillo) {
flags.GlobalFlags = append(flags.GlobalFlags, "-D__BRILLO__")
}
@@ -464,6 +479,21 @@
flags = rsFlags(ctx, flags, &compiler.Properties)
}
+ if len(compiler.Properties.Srcs) > 0 {
+ module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+ if inList("-Wno-error", flags.CFlags) || inList("-Wno-error", flags.CppFlags) {
+ addToModuleList(ctx, modulesUsingWnoError, module)
+ } else if !inList("-Werror", flags.CFlags) && !inList("-Werror", flags.CppFlags) {
+ if warningsAreAllowed(ctx.ModuleDir()) {
+ addToModuleList(ctx, modulesAddedWall, module)
+ flags.CFlags = append([]string{"-Wall"}, flags.CFlags...)
+ } else {
+ addToModuleList(ctx, modulesAddedWerror, module)
+ flags.CFlags = append([]string{"-Wall", "-Werror"}, flags.CFlags...)
+ }
+ }
+ }
+
return flags
}
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index 0f28d1e..fda4f9d 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -115,7 +115,9 @@
"-D__ARM_FEATURE_LPAE=1",
},
"kryo": []string{
- "-mcpu=cortex-a15",
+ // Use cortex-a53 because the GNU assembler doesn't recognize -mcpu=kryo
+ // even though clang does.
+ "-mcpu=cortex-a53",
"-mfpu=neon-fp-armv8",
// Fake an ARM compiler flag as these processors support LPAE which GCC/clang
// don't advertise.
@@ -158,10 +160,9 @@
android.RegisterArchVariantFeatures(android.Arm, "armv7-a-neon", "neon")
android.RegisterArchVariantFeatures(android.Arm, "armv8-a", "neon")
- // Krait and Kryo targets are not supported by GCC, but are supported by Clang,
- // so override the definitions when building modules with Clang.
+ // Krait is not supported by GCC, but is supported by Clang, so
+ // override the definitions when building modules with Clang.
replaceFirst(armClangCpuVariantCflags["krait"], "-mcpu=cortex-a15", "-mcpu=krait")
- replaceFirst(armClangCpuVariantCflags["kryo"], "-mcpu=cortex-a15", "-mcpu=krait")
// The reason we use "-march=armv8-a+crc", instead of "-march=armv8-a", for
// gcc is the latter would conflict with any specified/supported -mcpu!
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 2ef153b..302c68e 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -77,6 +77,9 @@
"-fno-inline-functions-called-once",
"-mfpmath=sse",
"-mbionic",
+
+ // windows
+ "--enable-stdcall-fixup",
})
var ClangLibToolingUnknownCflags = []string{
diff --git a/cc/config/global.go b/cc/config/global.go
index 44ad30b..fb71e6a 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -118,6 +118,43 @@
ClangDefaultBase = "prebuilts/clang/host"
ClangDefaultVersion = "clang-4393122"
ClangDefaultShortVersion = "5.0.1"
+
+ WarningAllowedProjects = []string{
+ "external/libese/third_party/NXPNFC_P61_JCOP_Kit/",
+ "external/skia/",
+ "device/",
+ "frameworks/av/media/libeffects/factory/",
+ "frameworks/av/media/libstagefright/codecs/",
+ "frameworks/base/tools/streaming_proto/",
+ "frameworks/ml/nn/",
+ "frameworks/native/libs/vr/libbufferhub/",
+ "frameworks/native/libs/vr/libbufferhubqueue/",
+ "frameworks/native/libs/vr/libdvr/tests/",
+ "frameworks/native/services/surfaceflinger/tests/",
+ "frameworks/native/services/vr/",
+ "vendor/",
+ }
+
+ // Some Android.mk files still have warnings.
+ WarningAllowedOldProjects = []string{
+ "cts/hostsidetests/security/securityPatch/",
+ "cts/tests/tests/permission/jni/",
+ "development/tutorials/ReverseDebug/",
+ "frameworks/av/drm/mediacas/plugins/",
+ "frameworks/av/services/mediaextractor/",
+ "frameworks/base/core/tests/webkit/apk_with_native_libs/jni/",
+ "frameworks/base/tests/backup/",
+ "frameworks/native/cmds/cmd/",
+ "frameworks/webview/chromium/",
+ "hardware/libhardware/modules/",
+ "hardware/libhardware/tests/",
+ "hardware/qcom/",
+ "sdk/emulator/mksdcard/",
+ "system/vold/tests/",
+ "test/vts-testcase/kernel/api/qtaguid/",
+ "test/vts-testcase/security/poc/target/",
+ "tools/adt/idea/android/ultimate/get_modification_time/jni/",
+ }
)
var pctx = android.NewPackageContext("android/soong/cc/config")
@@ -171,14 +208,14 @@
[]string{"libnativehelper/include_deprecated"})
pctx.SourcePathVariable("ClangDefaultBase", ClangDefaultBase)
- pctx.VariableFunc("ClangBase", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("LLVM_PREBUILTS_BASE"); override != "" {
+ pctx.VariableFunc("ClangBase", func(config android.Config) (string, error) {
+ if override := config.Getenv("LLVM_PREBUILTS_BASE"); override != "" {
return override, nil
}
return "${ClangDefaultBase}", nil
})
- pctx.VariableFunc("ClangVersion", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
+ pctx.VariableFunc("ClangVersion", func(config android.Config) (string, error) {
+ if override := config.Getenv("LLVM_PREBUILTS_VERSION"); override != "" {
return override, nil
}
return ClangDefaultVersion, nil
@@ -186,8 +223,8 @@
pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}")
pctx.StaticVariable("ClangBin", "${ClangPath}/bin")
- pctx.VariableFunc("ClangShortVersion", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("LLVM_RELEASE_VERSION"); override != "" {
+ pctx.VariableFunc("ClangShortVersion", func(config android.Config) (string, error) {
+ if override := config.Getenv("LLVM_RELEASE_VERSION"); override != "" {
return override, nil
}
return ClangDefaultShortVersion, nil
@@ -213,8 +250,8 @@
"frameworks/rs/script_api/include",
})
- pctx.VariableFunc("CcWrapper", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("CC_WRAPPER"); override != "" {
+ pctx.VariableFunc("CcWrapper", func(config android.Config) (string, error) {
+ if override := config.Getenv("CC_WRAPPER"); override != "" {
return override + " ", nil
}
return "", nil
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index a2fa5a2..76a5f9e 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -25,8 +25,8 @@
// Global tidy checks include only google*, performance*,
// and misc-macro-parentheses, but not google-readability*
// or google-runtime-references.
- pctx.VariableFunc("TidyDefaultGlobalChecks", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
+ pctx.VariableFunc("TidyDefaultGlobalChecks", func(config android.Config) (string, error) {
+ if override := config.Getenv("DEFAULT_GLOBAL_TIDY_CHECKS"); override != "" {
return override, nil
}
return strings.Join([]string{
@@ -41,8 +41,8 @@
// There are too many clang-tidy warnings in external and vendor projects.
// Enable only some google checks for these projects.
- pctx.VariableFunc("TidyExternalVendorChecks", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
+ pctx.VariableFunc("TidyExternalVendorChecks", func(config android.Config) (string, error) {
+ if override := config.Getenv("DEFAULT_EXTERNAL_VENDOR_TIDY_CHECKS"); override != "" {
return override, nil
}
return strings.Join([]string{
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 8d805c9..dbaa6fa 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -107,25 +107,25 @@
)
func init() {
- pctx.VariableFunc("macSdkPath", func(config interface{}) (string, error) {
- xcodeselect := config.(android.Config).HostSystemTool("xcode-select")
+ pctx.VariableFunc("macSdkPath", func(config android.Config) (string, error) {
+ xcodeselect := config.HostSystemTool("xcode-select")
bytes, err := exec.Command(xcodeselect, "--print-path").Output()
return strings.TrimSpace(string(bytes)), err
})
- pctx.VariableFunc("macSdkRoot", func(config interface{}) (string, error) {
- return xcrunSdk(config.(android.Config), "--show-sdk-path")
+ pctx.VariableFunc("macSdkRoot", func(config android.Config) (string, error) {
+ return xcrunSdk(config, "--show-sdk-path")
})
pctx.StaticVariable("macMinVersion", "10.8")
- pctx.VariableFunc("MacArPath", func(config interface{}) (string, error) {
- return xcrun(config.(android.Config), "--find", "ar")
+ pctx.VariableFunc("MacArPath", func(config android.Config) (string, error) {
+ return xcrun(config, "--find", "ar")
})
- pctx.VariableFunc("MacStripPath", func(config interface{}) (string, error) {
- return xcrun(config.(android.Config), "--find", "strip")
+ pctx.VariableFunc("MacStripPath", func(config android.Config) (string, error) {
+ return xcrun(config, "--find", "strip")
})
- pctx.VariableFunc("MacToolPath", func(config interface{}) (string, error) {
- path, err := xcrun(config.(android.Config), "--find", "ld")
+ pctx.VariableFunc("MacToolPath", func(config android.Config) (string, error) {
+ path, err := xcrun(config, "--find", "ld")
return filepath.Dir(path), err
})
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index c9bafe6..016e711 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -41,15 +41,30 @@
"--sysroot ${WindowsGccRoot}/${WindowsGccTriple}",
}
+ windowsClangCflags = append(ClangFilterUnknownCflags(windowsCflags), []string{}...)
windowsIncludeFlags = []string{
"-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include",
"-isystem ${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/include",
}
+ windowsClangCppflags = []string{
+ "-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3",
+ "-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/backward",
+ }
+
+ windowsX86ClangCppflags = []string{
+ "-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/${WindowsGccTriple}/32",
+ }
+
+ windowsX8664ClangCppflags = []string{
+ "-isystem ${WindowsGccRoot}/${WindowsGccTriple}/include/c++/4.8.3/${WindowsGccTriple}",
+ }
+
windowsLdflags = []string{
"--enable-stdcall-fixup",
}
+ windowsClangLdflags = append(ClangFilterUnknownCflags(windowsLdflags), []string{}...)
windowsX86Cflags = []string{
"-m32",
@@ -64,11 +79,21 @@
"-Wl,--large-address-aware",
"-L${WindowsGccRoot}/${WindowsGccTriple}/lib32",
}
+ windowsX86ClangLdflags = append(ClangFilterUnknownCflags(windowsX86Ldflags), []string{
+ "-B${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/32",
+ "-L${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3/32",
+ "-B${WindowsGccRoot}/${WindowsGccTriple}/lib32",
+ }...)
windowsX8664Ldflags = []string{
"-m64",
"-L${WindowsGccRoot}/${WindowsGccTriple}/lib64",
}
+ windowsX8664ClangLdflags = append(ClangFilterUnknownCflags(windowsX8664Ldflags), []string{
+ "-B${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3",
+ "-L${WindowsGccRoot}/lib/gcc/${WindowsGccTriple}/4.8.3",
+ "-B${WindowsGccRoot}/${WindowsGccTriple}/lib64",
+ }...)
windowsAvailableLibraries = addPrefix([]string{
"gdi32",
@@ -101,11 +126,24 @@
pctx.StaticVariable("WindowsCflags", strings.Join(windowsCflags, " "))
pctx.StaticVariable("WindowsLdflags", strings.Join(windowsLdflags, " "))
+ pctx.StaticVariable("WindowsClangCflags", strings.Join(windowsClangCflags, " "))
+ pctx.StaticVariable("WindowsClangLdflags", strings.Join(windowsClangLdflags, " "))
+ pctx.StaticVariable("WindowsClangCppflags", strings.Join(windowsClangCppflags, " "))
+
pctx.StaticVariable("WindowsX86Cflags", strings.Join(windowsX86Cflags, " "))
pctx.StaticVariable("WindowsX8664Cflags", strings.Join(windowsX8664Cflags, " "))
pctx.StaticVariable("WindowsX86Ldflags", strings.Join(windowsX86Ldflags, " "))
pctx.StaticVariable("WindowsX8664Ldflags", strings.Join(windowsX8664Ldflags, " "))
+ pctx.StaticVariable("WindowsX86ClangCflags",
+ strings.Join(ClangFilterUnknownCflags(windowsX86Cflags), " "))
+ pctx.StaticVariable("WindowsX8664ClangCflags",
+ strings.Join(ClangFilterUnknownCflags(windowsX8664Cflags), " "))
+ pctx.StaticVariable("WindowsX86ClangLdflags", strings.Join(windowsX86ClangLdflags, " "))
+ pctx.StaticVariable("WindowsX8664ClangLdflags", strings.Join(windowsX8664ClangLdflags, " "))
+ pctx.StaticVariable("WindowsX86ClangCppflags", strings.Join(windowsX86ClangCppflags, " "))
+ pctx.StaticVariable("WindowsX8664ClangCppflags", strings.Join(windowsX8664ClangCppflags, " "))
+
pctx.StaticVariable("WindowsIncludeFlags", strings.Join(windowsIncludeFlags, " "))
}
@@ -179,20 +217,36 @@
return false
}
-func (t *toolchainWindows) ClangTriple() string {
- panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX86) ClangTriple() string {
+ return "i686-windows-gnu"
}
-func (t *toolchainWindows) ClangCflags() string {
- panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX8664) ClangTriple() string {
+ return "x86_64-pc-windows-gnu"
}
-func (t *toolchainWindows) ClangCppflags() string {
- panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX86) ClangCflags() string {
+ return "${config.WindowsClangCflags} ${config.WindowsX86ClangCflags}"
}
-func (t *toolchainWindows) ClangLdflags() string {
- panic("Clang is not supported under mingw")
+func (t *toolchainWindowsX8664) ClangCflags() string {
+ return "${config.WindowsClangCflags} ${config.WindowsX8664ClangCflags}"
+}
+
+func (t *toolchainWindowsX86) ClangCppflags() string {
+ return "${config.WindowsClangCppflags} ${config.WindowsX86ClangCppflags}"
+}
+
+func (t *toolchainWindowsX8664) ClangCppflags() string {
+ return "${config.WindowsClangCppflags} ${config.WindowsX8664ClangCppflags}"
+}
+
+func (t *toolchainWindowsX86) ClangLdflags() string {
+ return "${config.WindowsClangLdflags} ${config.WindowsX86ClangLdflags}"
+}
+
+func (t *toolchainWindowsX8664) ClangLdflags() string {
+ return "${config.WindowsClangLdflags} ${config.WindowsX8664ClangLdflags}"
}
func (t *toolchainWindows) ShlibSuffix() string {
diff --git a/cc/library.go b/cc/library.go
index 192496a..cf10617 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -85,9 +85,6 @@
VariantIsShared bool `blueprint:"mutated"`
// This variant is static
VariantIsStatic bool `blueprint:"mutated"`
- // Location of the static library in the sysroot. Empty if the library is
- // not included in the NDK.
- NdkSysrootPath string `blueprint:"mutated"`
}
type FlagExporterProperties struct {
@@ -246,6 +243,10 @@
// Source Abi Diff
sAbiDiff android.OptionalPath
+ // Location of the static library in the sysroot. Empty if the library is
+ // not included in the NDK.
+ ndkSysrootPath android.Path
+
// Decorated interafaces
*baseCompiler
*baseLinker
@@ -742,7 +743,7 @@
Input: file,
})
- library.MutatedProperties.NdkSysrootPath = installPath.String()
+ library.ndkSysrootPath = installPath
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 7befb11..2d71db6 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -18,15 +18,51 @@
"fmt"
"sort"
"strings"
+ "sync"
"android/soong/android"
"android/soong/cc/config"
)
+const (
+ modulesAddedWall = "ModulesAddedWall"
+ modulesAddedWerror = "ModulesAddedWerror"
+ modulesUsingWnoError = "ModulesUsingWnoError"
+)
+
func init() {
android.RegisterMakeVarsProvider(pctx, makeVarsProvider)
}
+func getWallWerrorMap(config android.Config, name string) *sync.Map {
+ return config.Once(name, func() interface{} {
+ return &sync.Map{}
+ }).(*sync.Map)
+}
+
+func makeStringOfKeys(ctx android.MakeVarsContext, setName string) string {
+ set := getWallWerrorMap(ctx.Config(), setName)
+ keys := []string{}
+ set.Range(func(key interface{}, value interface{}) bool {
+ keys = append(keys, key.(string))
+ return true
+ })
+ sort.Strings(keys)
+ return strings.Join(keys, " ")
+}
+
+func makeStringOfWarningAllowedProjects() string {
+ allProjects := append([]string{}, config.WarningAllowedProjects...)
+ allProjects = append(allProjects, config.WarningAllowedOldProjects...)
+ sort.Strings(allProjects)
+ // Makefile rules use pattern "path/%" to match module paths.
+ if len(allProjects) > 0 {
+ return strings.Join(allProjects, "% ") + "%"
+ } else {
+ return ""
+ }
+}
+
func makeVarsProvider(ctx android.MakeVarsContext) {
ctx.Strict("LLVM_RELEASE_VERSION", "${config.ClangShortVersion}")
ctx.Strict("LLVM_PREBUILTS_VERSION", "${config.ClangVersion}")
@@ -64,6 +100,11 @@
ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " "))
ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " "))
+ ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects())
+ ctx.Strict("SOONG_MODULES_ADDED_WALL", makeStringOfKeys(ctx, modulesAddedWall))
+ ctx.Strict("SOONG_MODULES_ADDED_WERROR", makeStringOfKeys(ctx, modulesAddedWerror))
+ ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoError))
+
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_CFLAGS", strings.Join(asanCflags, " "))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_LDFLAGS", strings.Join(asanLdflags, " "))
ctx.Strict("ADDRESS_SANITIZER_CONFIG_EXTRA_STATIC_LIBRARIES", strings.Join(asanLibs, " "))
@@ -238,6 +279,10 @@
// This is used by external/gentoo/...
ctx.Strict("CLANG_CONFIG_"+target.Arch.ArchType.Name+"_"+typePrefix+"TRIPLE",
toolchain.ClangTriple())
+
+ ctx.Strict(makePrefix+"CLANG_SUPPORTED", "true")
+ } else {
+ ctx.Strict(makePrefix+"CLANG_SUPPORTED", "")
}
ctx.Strict(makePrefix+"CC", gccCmd(toolchain, "gcc"))
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 0458fb6..d7c2a06 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -18,6 +18,7 @@
"fmt"
"os"
"path/filepath"
+ "strings"
"github.com/google/blueprint"
@@ -73,7 +74,7 @@
properties headerProperies
- installPaths []string
+ installPaths android.Paths
licensePath android.ModuleSrcPath
}
@@ -119,6 +120,14 @@
m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
+ // When generating NDK prebuilts, skip installing MIPS headers,
+ // but keep them when doing regular platform build.
+ // Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
+ // TODO: Revert this once MIPS is supported in NDK again.
+ if Bool(ctx.AConfig().Ndk_abis) && strings.Contains(ctx.ModuleName(), "mips") {
+ return
+ }
+
srcFiles := ctx.ExpandSources(m.properties.Srcs, nil)
for _, header := range srcFiles {
installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
@@ -130,7 +139,7 @@
"expected header install path (%q) not equal to actual install path %q",
installPath, installedPath))
}
- m.installPaths = append(m.installPaths, installPath.String())
+ m.installPaths = append(m.installPaths, installPath)
}
if len(m.installPaths) == 0 {
@@ -177,7 +186,7 @@
properties preprocessedHeaderProperies
- installPaths []string
+ installPaths android.Paths
licensePath android.ModuleSrcPath
}
@@ -199,7 +208,7 @@
installDir := getHeaderInstallDir(ctx, header, String(m.properties.From), String(m.properties.To))
installPath := installDir.Join(ctx, header.Base())
installPaths = append(installPaths, installPath)
- m.installPaths = append(m.installPaths, installPath.String())
+ m.installPaths = append(m.installPaths, installPath)
}
if len(m.installPaths) == 0 {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index c517523..459d980 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -98,7 +98,7 @@
properties libraryProperties
versionScriptPath android.ModuleGenPath
- installPath string
+ installPath android.Path
}
// OMG GO
@@ -117,7 +117,7 @@
return apiLevel, nil
}
- minVersion := ctx.AConfig().MinSupportedSdkVersion()
+ minVersion := ctx.Config().MinSupportedSdkVersion()
firstArchVersions := map[android.ArchType]int{
android.Arm: minVersion,
android.Arm64: 21,
@@ -188,7 +188,7 @@
}
func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) {
- platformVersion := mctx.AConfig().PlatformSdkVersionInt()
+ platformVersion := mctx.Config().PlatformSdkVersionInt()
firstSupportedVersion, err := normalizeNdkApiLevel(mctx, String(c.properties.First_version),
mctx.Arch())
@@ -207,7 +207,7 @@
for version := firstGenVersion; version <= platformVersion; version++ {
versionStrs = append(versionStrs, strconv.Itoa(version))
}
- versionStrs = append(versionStrs, mctx.AConfig().PlatformVersionActiveCodenames()...)
+ versionStrs = append(versionStrs, mctx.Config().PlatformVersionActiveCodenames()...)
versionStrs = append(versionStrs, "current")
modules := mctx.CreateVariations(versionStrs...)
@@ -251,6 +251,8 @@
"-Wno-incompatible-library-redeclaration",
"-Wno-builtin-requires-header",
"-Wno-invalid-noreturn",
+ "-Wall",
+ "-Werror",
// These libraries aren't actually used. Don't worry about unwinding
// (avoids the need to link an unwinder into a fake library).
"-fno-unwind-tables",
@@ -342,7 +344,7 @@
installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf(
"platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir))
- stub.installPath = ctx.InstallFile(installDir, path.Base(), path).String()
+ stub.installPath = ctx.InstallFile(installDir, path.Base(), path)
}
func newStubLibrary() *Module {
diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go
index e213965..4324458 100644
--- a/cc/ndk_sysroot.go
+++ b/cc/ndk_sysroot.go
@@ -53,8 +53,6 @@
// TODO(danalbert): Write `ndk_static_library` rule.
import (
- "github.com/google/blueprint"
-
"android/soong/android"
)
@@ -76,32 +74,32 @@
return getNdkInstallBase(ctx).Join(ctx, "sysroot")
}
-func getNdkSysrootTimestampFile(ctx android.PathContext) android.Path {
+func getNdkSysrootTimestampFile(ctx android.PathContext) android.WritablePath {
return android.PathForOutput(ctx, "ndk.timestamp")
}
-func NdkSingleton() blueprint.Singleton {
+func NdkSingleton() android.Singleton {
return &ndkSingleton{}
}
type ndkSingleton struct{}
-func (n *ndkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
- installPaths := []string{}
- licensePaths := []string{}
- ctx.VisitAllModules(func(module blueprint.Module) {
+func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ var installPaths android.Paths
+ var licensePaths android.Paths
+ ctx.VisitAllModules(func(module android.Module) {
if m, ok := module.(android.Module); ok && !m.Enabled() {
return
}
if m, ok := module.(*headerModule); ok {
installPaths = append(installPaths, m.installPaths...)
- licensePaths = append(licensePaths, m.licensePath.String())
+ licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*preprocessedHeaderModule); ok {
installPaths = append(installPaths, m.installPaths...)
- licensePaths = append(licensePaths, m.licensePath.String())
+ licensePaths = append(licensePaths, m.licensePath)
}
if m, ok := module.(*Module); ok {
@@ -110,30 +108,28 @@
}
if library, ok := m.linker.(*libraryDecorator); ok {
- if library.MutatedProperties.NdkSysrootPath != "" {
- installPaths = append(installPaths, library.MutatedProperties.NdkSysrootPath)
+ if library.ndkSysrootPath != nil {
+ installPaths = append(installPaths, library.ndkSysrootPath)
}
}
}
})
combinedLicense := getNdkInstallBase(ctx).Join(ctx, "NOTICE")
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, android.BuildParams{
Rule: android.Cat,
Description: "combine licenses",
- Outputs: []string{combinedLicense.String()},
+ Output: combinedLicense,
Inputs: licensePaths,
- Optional: true,
})
- depPaths := append(installPaths, combinedLicense.String())
+ depPaths := append(installPaths, combinedLicense)
// There's a dummy "ndk" rule defined in ndk/Android.mk that depends on
// this. `m ndk` will build the sysroots.
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, android.BuildParams{
Rule: android.Touch,
- Outputs: []string{getNdkSysrootTimestampFile(ctx).String()},
+ Output: getNdkSysrootTimestampFile(ctx),
Implicits: depPaths,
- Optional: true,
})
}
diff --git a/cc/pgo.go b/cc/pgo.go
index ea23124..9fea154 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -181,7 +181,7 @@
//
// TODO Validate that each benchmark instruments at least one module
pgo.Properties.ShouldProfileModule = false
- pgoBenchmarks := ctx.AConfig().Getenv("ANDROID_PGO_INSTRUMENT")
+ pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT")
pgoBenchmarksMap := make(map[string]bool)
for _, b := range strings.Split(pgoBenchmarks, ",") {
pgoBenchmarksMap[b] = true
@@ -215,7 +215,7 @@
return props.addProfileGatherFlags(ctx, flags)
}
- if !ctx.AConfig().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
+ if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
return props.addProfileUseFlags(ctx, flags)
}
diff --git a/cc/relocation_packer.go b/cc/relocation_packer.go
index 614f15c..5006623 100644
--- a/cc/relocation_packer.go
+++ b/cc/relocation_packer.go
@@ -53,7 +53,7 @@
if ctx.Target().Os != android.Android {
enabled = false
}
- if ctx.AConfig().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
+ if ctx.Config().Getenv("DISABLE_RELOCATION_PACKER") == "true" {
enabled = false
}
if ctx.useSdk() {
@@ -68,7 +68,7 @@
}
func (p *relocationPacker) needsPacking(ctx ModuleContext) bool {
- if ctx.AConfig().EmbeddedInMake() {
+ if ctx.Config().EmbeddedInMake() {
return false
}
return p.Properties.PackingRelocations
diff --git a/cc/rs.go b/cc/rs.go
index c2335dd..68ba54b 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -86,7 +86,7 @@
case "current", "system_current", "test_current":
// Nothing
default:
- targetApi = ctx.sdkVersion()
+ targetApi = android.GetNumericSdkVersion(ctx.sdkVersion())
}
}
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 70aa412..1afec26 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -17,7 +17,9 @@
import (
"fmt"
"io"
+ "sort"
"strings"
+ "sync"
"android/soong/android"
"android/soong/cc/config"
@@ -36,9 +38,10 @@
"-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"}
cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
"-Wl,-plugin-opt,O1"}
- cfiArflags = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
- cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
- cfiExportsMap android.Path
+ cfiArflags = []string{"--plugin ${config.ClangBin}/../lib64/LLVMgold.so"}
+ cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
+ cfiExportsMap android.Path
+ cfiStaticLibsMutex sync.Mutex
intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
)
@@ -122,6 +125,10 @@
androidMkRuntimeLibrary string
}
+func init() {
+ android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
+}
+
func (sanitize *sanitize) props() []interface{} {
return []interface{}{&sanitize.Properties}
}
@@ -144,12 +151,12 @@
if ctx.clang() {
if ctx.Host() {
- globalSanitizers = ctx.AConfig().SanitizeHost()
+ globalSanitizers = ctx.Config().SanitizeHost()
} else {
- arches := ctx.AConfig().SanitizeDeviceArch()
+ arches := ctx.Config().SanitizeDeviceArch()
if len(arches) == 0 || inList(ctx.Arch().ArchType.Name, arches) {
- globalSanitizers = ctx.AConfig().SanitizeDevice()
- globalSanitizersDiag = ctx.AConfig().SanitizeDeviceDiag()
+ globalSanitizers = ctx.Config().SanitizeDevice()
+ globalSanitizersDiag = ctx.Config().SanitizeDeviceDiag()
}
}
}
@@ -187,13 +194,13 @@
}
if found, globalSanitizers = removeFromList("cfi", globalSanitizers); found && s.Cfi == nil {
- if !ctx.AConfig().CFIDisabledForPath(ctx.ModuleDir()) {
+ if !ctx.Config().CFIDisabledForPath(ctx.ModuleDir()) {
s.Cfi = boolPtr(true)
}
}
if found, globalSanitizers = removeFromList("integer_overflow", globalSanitizers); found && s.Integer_overflow == nil {
- if !ctx.AConfig().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
+ if !ctx.Config().IntegerOverflowDisabledForPath(ctx.ModuleDir()) {
s.Integer_overflow = boolPtr(true)
}
}
@@ -218,15 +225,15 @@
}
// Enable CFI for all components in the include paths
- if s.Cfi == nil && ctx.AConfig().CFIEnabledForPath(ctx.ModuleDir()) {
+ if s.Cfi == nil && ctx.Config().CFIEnabledForPath(ctx.ModuleDir()) {
s.Cfi = boolPtr(true)
- if inList("cfi", ctx.AConfig().SanitizeDeviceDiag()) {
+ if inList("cfi", ctx.Config().SanitizeDeviceDiag()) {
s.Diag.Cfi = boolPtr(true)
}
}
// CFI needs gold linker, and mips toolchain does not have one.
- if !ctx.AConfig().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
+ if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
s.Cfi = nil
s.Diag.Cfi = nil
}
@@ -243,6 +250,12 @@
s.Diag.Cfi = nil
}
+ // Also disable CFI for host builds.
+ if ctx.Host() {
+ s.Cfi = nil
+ s.Diag.Cfi = nil
+ }
+
if ctx.staticBinary() {
s.Address = nil
s.Coverage = nil
@@ -474,12 +487,11 @@
fmt.Fprintln(w, "LOCAL_SHARED_LIBRARIES += "+sanitize.androidMkRuntimeLibrary)
}
})
- if ctx.Target().Os.Class == android.Device {
- if Bool(sanitize.Properties.Sanitize.Cfi) {
- ret.SubName += ".cfi"
- } else if Bool(sanitize.Properties.Sanitize.Address) {
- ret.SubName += ".asan"
- }
+
+ // Add a suffix for CFI-enabled static libraries to allow surfacing both to make without a
+ // name conflict.
+ if ret.Class == "STATIC_LIBRARIES" && Bool(sanitize.Properties.Sanitize.Cfi) {
+ ret.SubName += ".cfi"
}
}
@@ -584,27 +596,44 @@
modules[0].(*Module).sanitize.Properties.SanitizeDep = false
modules[1].(*Module).sanitize.Properties.SanitizeDep = false
- if mctx.Device() {
- // CFI and ASAN are currently mutually exclusive so disable
- // CFI if this is an ASAN variant.
- if t == asan {
+
+ // We don't need both variants active for anything but CFI-enabled
+ // target static libraries, so suppress the appropriate variant in
+ // all other cases.
+ if t == cfi {
+ if c.static() {
+ if !mctx.Device() {
+ if isSanitizerEnabled {
+ modules[0].(*Module).Properties.PreventInstall = true
+ modules[0].(*Module).Properties.HideFromMake = true
+ } else {
+ modules[1].(*Module).Properties.PreventInstall = true
+ modules[1].(*Module).Properties.HideFromMake = true
+ }
+ } else {
+ cfiStaticLibs := cfiStaticLibs(mctx.Config())
+
+ cfiStaticLibsMutex.Lock()
+ *cfiStaticLibs = append(*cfiStaticLibs, c.Name())
+ cfiStaticLibsMutex.Unlock()
+ }
+ } else {
+ modules[0].(*Module).Properties.PreventInstall = true
+ modules[0].(*Module).Properties.HideFromMake = true
+ }
+ } else if t == asan {
+ if mctx.Device() {
+ // CFI and ASAN are currently mutually exclusive so disable
+ // CFI if this is an ASAN variant.
modules[1].(*Module).sanitize.Properties.InSanitizerDir = true
modules[1].(*Module).sanitize.SetSanitizer(cfi, false)
}
- } else {
- if mctx.AConfig().EmbeddedInMake() {
- if isSanitizerEnabled {
- modules[0].(*Module).Properties.HideFromMake = true
- } else {
- modules[1].(*Module).Properties.HideFromMake = true
- }
- }
- }
- if !mctx.AConfig().EmbeddedInMake() || !mctx.Device() {
if isSanitizerEnabled {
modules[0].(*Module).Properties.PreventInstall = true
+ modules[0].(*Module).Properties.HideFromMake = true
} else {
modules[1].(*Module).Properties.PreventInstall = true
+ modules[1].(*Module).Properties.HideFromMake = true
}
}
}
@@ -612,3 +641,15 @@
}
}
}
+
+func cfiStaticLibs(config android.Config) *[]string {
+ return config.Once("cfiStaticLibs", func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
+ cfiStaticLibs := cfiStaticLibs(ctx.Config())
+ sort.Strings(*cfiStaticLibs)
+ ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " "))
+}
diff --git a/cc/strip.go b/cc/strip.go
index 0bb29c1..a7c2d4e 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -30,7 +30,7 @@
}
func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
- return !ctx.AConfig().EmbeddedInMake() && !Bool(stripper.StripProperties.Strip.None)
+ return !ctx.Config().EmbeddedInMake() && !Bool(stripper.StripProperties.Strip.None)
}
func (stripper *stripper) strip(ctx ModuleContext, in, out android.ModuleOutPath,
diff --git a/cc/tidy.go b/cc/tidy.go
index c31f5ae..6d7c957 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -58,7 +58,7 @@
}
// If not explicitly set, check the global tidy flag
- if tidy.Properties.Tidy == nil && !ctx.AConfig().ClangTidy() {
+ if tidy.Properties.Tidy == nil && !ctx.Config().ClangTidy() {
return flags
}
@@ -82,7 +82,7 @@
flags.TidyFlags = append(flags.TidyFlags, "-extra-arg-before=-D__clang_analyzer__")
tidyChecks := "-checks="
- if checks := ctx.AConfig().TidyChecks(); len(checks) > 0 {
+ if checks := ctx.Config().TidyChecks(); len(checks) > 0 {
tidyChecks += checks
} else {
tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index 207b161..556dad0 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -54,13 +54,14 @@
}
var (
- sortEntries = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
- emulateJar = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
- stripDirs fileList
- stripFiles fileList
- zipsToNotStrip = make(zipsToNotStripSet)
- stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
- manifest = flag.String("m", "", "manifest file to insert in jar")
+ sortEntries = flag.Bool("s", false, "sort entries (defaults to the order from the input zip files)")
+ emulateJar = flag.Bool("j", false, "sort zip entries using jar ordering (META-INF first)")
+ stripDirs fileList
+ stripFiles fileList
+ zipsToNotStrip = make(zipsToNotStripSet)
+ stripDirEntries = flag.Bool("D", false, "strip directory entries from the output zip file")
+ manifest = flag.String("m", "", "manifest file to insert in jar")
+ ignoreDuplicates = flag.Bool("ignore-duplicates", false, "take each entry from the first zip it exists in and don't warn")
)
func init() {
@@ -118,7 +119,7 @@
}
// do merge
- err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries)
+ err = mergeZips(readers, writer, *manifest, *sortEntries, *emulateJar, *stripDirEntries, *ignoreDuplicates)
if err != nil {
log.Fatal(err)
}
@@ -210,7 +211,7 @@
}
func mergeZips(readers []namedZipReader, writer *zip.Writer, manifest string,
- sortEntries, emulateJar, stripDirEntries bool) error {
+ sortEntries, emulateJar, stripDirEntries, ignoreDuplicates bool) error {
sourceByDest := make(map[string]zipSource, 0)
orderedMappings := []fileMapping{}
@@ -266,6 +267,9 @@
return fmt.Errorf("Directory/file mismatch at %v from %v and %v\n",
dest, existingSource, source)
}
+ if ignoreDuplicates {
+ continue
+ }
if emulateJar &&
file.Name == jar.ManifestFile || file.Name == jar.ModuleInfoClass {
// Skip manifest and module info files that are not from the first input file
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 0619b5c..2ca7ebf 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -114,7 +114,11 @@
} else if os.Args[1] == "--dumpvars-mode" {
dumpVars(buildCtx, config, os.Args[2:])
} else {
- build.Build(buildCtx, config, build.BuildAll)
+ toBuild := build.BuildAll
+ if config.Checkbuild() {
+ toBuild |= build.RunBuildTests
+ }
+ build.Build(buildCtx, config, toBuild)
}
}
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 6420219..68d8bc7 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -15,8 +15,9 @@
blueprint_go_binary {
name: "zip2zip",
deps: [
- "android-archive-zip",
- "soong-jar",
+ "android-archive-zip",
+ "blueprint-pathtools",
+ "soong-jar",
],
srcs: [
"zip2zip.go",
diff --git a/cmd/zip2zip/zip2zip.go b/cmd/zip2zip/zip2zip.go
index f48d458..e8ea9b9 100644
--- a/cmd/zip2zip/zip2zip.go
+++ b/cmd/zip2zip/zip2zip.go
@@ -24,6 +24,8 @@
"strings"
"time"
+ "github.com/google/blueprint/pathtools"
+
"android/soong/jar"
"android/soong/third_party/zip"
)
@@ -36,8 +38,14 @@
setTime = flag.Bool("t", false, "set timestamps to 2009-01-01 00:00:00")
staticTime = time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
+
+ excludes excludeArgs
)
+func init() {
+ flag.Var(&excludes, "x", "exclude a filespec from the output")
+}
+
func main() {
flag.Usage = func() {
fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [-s|-j] [-t] [filespec]...")
@@ -45,15 +53,14 @@
fmt.Fprintln(os.Stderr, " filespec:")
fmt.Fprintln(os.Stderr, " <name>")
fmt.Fprintln(os.Stderr, " <in_name>:<out_name>")
- fmt.Fprintln(os.Stderr, " <glob>:<out_dir>/")
+ fmt.Fprintln(os.Stderr, " <glob>[:<out_dir>]")
fmt.Fprintln(os.Stderr, "")
- fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://golang.org/pkg/path/filepath/#Match")
- fmt.Fprintln(os.Stderr, "As a special exception, '**' is supported to specify all files in the input zip.")
+ fmt.Fprintln(os.Stderr, "<glob> uses the rules at https://godoc.org/github.com/google/blueprint/pathtools/#Match")
fmt.Fprintln(os.Stderr, "")
fmt.Fprintln(os.Stderr, "Files will be copied with their existing compression from the input zipfile to")
fmt.Fprintln(os.Stderr, "the output zipfile, in the order of filespec arguments.")
fmt.Fprintln(os.Stderr, "")
- fmt.Fprintln(os.Stderr, "If no filepsec is provided all files are copied (equivalent to '**').")
+ fmt.Fprintln(os.Stderr, "If no filepsec is provided all files and directories are copied.")
}
flag.Parse()
@@ -85,7 +92,9 @@
}
}()
- if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime, flag.Args()); err != nil {
+ if err := zip2zip(&reader.Reader, writer, *sortGlobs, *sortJava, *setTime,
+ flag.Args(), excludes); err != nil {
+
log.Fatal(err)
}
}
@@ -95,91 +104,126 @@
newName string
}
-func zip2zip(reader *zip.Reader, writer *zip.Writer, sortGlobs, sortJava, setTime bool, args []string) error {
- if len(args) == 0 {
- // If no filespec is provided, default to copying everything
- args = []string{"**"}
- }
- for _, arg := range args {
- var input string
- var output string
+func zip2zip(reader *zip.Reader, writer *zip.Writer, sortOutput, sortJava, setTime bool,
+ includes []string, excludes []string) error {
+ matches := []pair{}
+
+ sortMatches := func(matches []pair) {
+ if sortJava {
+ sort.SliceStable(matches, func(i, j int) bool {
+ return jar.EntryNamesLess(matches[i].newName, matches[j].newName)
+ })
+ } else if sortOutput {
+ sort.SliceStable(matches, func(i, j int) bool {
+ return matches[i].newName < matches[j].newName
+ })
+ }
+ }
+
+ for _, include := range includes {
// Reserve escaping for future implementation, so make sure no
// one is using \ and expecting a certain behavior.
- if strings.Contains(arg, "\\") {
+ if strings.Contains(include, "\\") {
return fmt.Errorf("\\ characters are not currently supported")
}
- args := strings.SplitN(arg, ":", 2)
- input = args[0]
- if len(args) == 2 {
- output = args[1]
- }
+ input, output := includeSplit(include)
- matches := []pair{}
- if strings.IndexAny(input, "*?[") >= 0 {
- matchAll := input == "**"
- if !matchAll && strings.Contains(input, "**") {
- return fmt.Errorf("** is only supported on its own, not with other characters")
- }
+ var includeMatches []pair
- for _, file := range reader.File {
- match := matchAll
-
- if !match {
- var err error
- match, err = filepath.Match(input, file.Name)
- if err != nil {
- return err
- }
- }
-
- if match {
- var newName string
- if output == "" {
- newName = file.Name
- } else {
+ for _, file := range reader.File {
+ var newName string
+ if match, err := pathtools.Match(input, file.Name); err != nil {
+ return err
+ } else if match {
+ if output == "" {
+ newName = file.Name
+ } else {
+ if pathtools.IsGlob(input) {
+ // If the input is a glob then the output is a directory.
_, name := filepath.Split(file.Name)
newName = filepath.Join(output, name)
+ } else {
+ // Otherwise it is a file.
+ newName = output
}
- matches = append(matches, pair{file, newName})
}
- }
-
- if sortJava {
- jarSort(matches)
- } else if sortGlobs {
- sort.SliceStable(matches, func(i, j int) bool {
- return matches[i].newName < matches[j].newName
- })
- }
- } else {
- if output == "" {
- output = input
- }
- for _, file := range reader.File {
- if input == file.Name {
- matches = append(matches, pair{file, output})
- break
- }
+ includeMatches = append(includeMatches, pair{file, newName})
}
}
- for _, match := range matches {
- if setTime {
- match.File.SetModTime(staticTime)
- }
- if err := writer.CopyFrom(match.File, match.newName); err != nil {
+ sortMatches(includeMatches)
+ matches = append(matches, includeMatches...)
+ }
+
+ if len(includes) == 0 {
+ // implicitly match everything
+ for _, file := range reader.File {
+ matches = append(matches, pair{file, file.Name})
+ }
+ sortMatches(matches)
+ }
+
+ var matchesAfterExcludes []pair
+ seen := make(map[string]*zip.File)
+
+ for _, match := range matches {
+ // Filter out matches whose original file name matches an exclude filter
+ excluded := false
+ for _, exclude := range excludes {
+ if excludeMatch, err := pathtools.Match(exclude, match.File.Name); err != nil {
return err
+ } else if excludeMatch {
+ excluded = true
+ break
}
}
+
+ if excluded {
+ continue
+ }
+
+ // Check for duplicate output names, ignoring ones that come from the same input zip entry.
+ if prev, exists := seen[match.newName]; exists {
+ if prev != match.File {
+ return fmt.Errorf("multiple entries for %q with different contents", match.newName)
+ }
+ continue
+ }
+ seen[match.newName] = match.File
+
+ matchesAfterExcludes = append(matchesAfterExcludes, match)
+ }
+
+ for _, match := range matchesAfterExcludes {
+ if setTime {
+ match.File.SetModTime(staticTime)
+ }
+ if err := writer.CopyFrom(match.File, match.newName); err != nil {
+ return err
+ }
}
return nil
}
-func jarSort(files []pair) {
- sort.SliceStable(files, func(i, j int) bool {
- return jar.EntryNamesLess(files[i].newName, files[j].newName)
- })
+func includeSplit(s string) (string, string) {
+ split := strings.SplitN(s, ":", 2)
+ if len(split) == 2 {
+ return split[0], split[1]
+ } else {
+ return split[0], ""
+ }
+}
+
+type excludeArgs []string
+
+func (e *excludeArgs) String() string {
+ return strings.Join(*e, " ")
+}
+
+func (e *excludeArgs) Set(s string) error {
+ *e = append(*e, s)
+ return nil
}
diff --git a/cmd/zip2zip/zip2zip_test.go b/cmd/zip2zip/zip2zip_test.go
index 53c8ce2..212ab28 100644
--- a/cmd/zip2zip/zip2zip_test.go
+++ b/cmd/zip2zip/zip2zip_test.go
@@ -30,6 +30,7 @@
sortGlobs bool
sortJava bool
args []string
+ excludes []string
outputFiles []string
err error
@@ -41,13 +42,6 @@
err: fmt.Errorf("\\ characters are not currently supported"),
},
- {
- name: "unsupported **",
-
- args: []string{"a/**:b"},
-
- err: fmt.Errorf("** is only supported on its own, not with other characters"),
- },
{ // This is modelled after the update package build rules in build/make/core/Makefile
name: "filter globs",
@@ -95,16 +89,19 @@
name: "sort all",
inputFiles: []string{
+ "RADIO/",
"RADIO/a",
+ "IMAGES/",
"IMAGES/system.img",
"IMAGES/b.txt",
"IMAGES/recovery.img",
"IMAGES/vendor.img",
+ "OTA/",
"OTA/b",
"OTA/android-info.txt",
},
sortGlobs: true,
- args: []string{"**"},
+ args: []string{"**/*"},
outputFiles: []string{
"IMAGES/b.txt",
@@ -120,11 +117,14 @@
name: "sort all implicit",
inputFiles: []string{
+ "RADIO/",
"RADIO/a",
+ "IMAGES/",
"IMAGES/system.img",
"IMAGES/b.txt",
"IMAGES/recovery.img",
"IMAGES/vendor.img",
+ "OTA/",
"OTA/b",
"OTA/android-info.txt",
},
@@ -132,12 +132,15 @@
args: nil,
outputFiles: []string{
+ "IMAGES/",
"IMAGES/b.txt",
"IMAGES/recovery.img",
"IMAGES/system.img",
"IMAGES/vendor.img",
+ "OTA/",
"OTA/android-info.txt",
"OTA/b",
+ "RADIO/",
"RADIO/a",
},
},
@@ -177,7 +180,7 @@
"b",
"a",
},
- args: []string{"a:a2", "**"},
+ args: []string{"a:a2", "**/*"},
outputFiles: []string{
"a2",
@@ -185,6 +188,69 @@
"a",
},
},
+ {
+ name: "multiple matches",
+
+ inputFiles: []string{
+ "a/a",
+ },
+ args: []string{"a/a", "a/*"},
+
+ outputFiles: []string{
+ "a/a",
+ },
+ },
+ {
+ name: "multiple conflicting matches",
+
+ inputFiles: []string{
+ "a/a",
+ "a/b",
+ },
+ args: []string{"a/b:a/a", "a/*"},
+
+ err: fmt.Errorf(`multiple entries for "a/a" with different contents`),
+ },
+ {
+ name: "excludes",
+
+ inputFiles: []string{
+ "a/a",
+ "a/b",
+ },
+ args: nil,
+ excludes: []string{"a/a"},
+
+ outputFiles: []string{
+ "a/b",
+ },
+ },
+ {
+ name: "excludes with include",
+
+ inputFiles: []string{
+ "a/a",
+ "a/b",
+ },
+ args: []string{"a/*"},
+ excludes: []string{"a/a"},
+
+ outputFiles: []string{
+ "a/b",
+ },
+ },
+ {
+ name: "excludes with glob",
+
+ inputFiles: []string{
+ "a/a",
+ "a/b",
+ },
+ args: []string{"a/*"},
+ excludes: []string{"a/*"},
+
+ outputFiles: nil,
+ },
}
func errorString(e error) string {
@@ -216,7 +282,7 @@
}
outputWriter := zip.NewWriter(outputBuf)
- err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args)
+ err = zip2zip(inputReader, outputWriter, testCase.sortGlobs, testCase.sortJava, false, testCase.args, testCase.excludes)
if errorString(testCase.err) != errorString(err) {
t.Fatalf("Unexpected error:\n got: %q\nwant: %q", errorString(err), errorString(testCase.err))
}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index c142c53..651ec15 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -134,7 +134,7 @@
if g, ok := ctx.Module().(*Module); ok {
if len(g.properties.Tools) > 0 {
ctx.AddFarVariationDependencies([]blueprint.Variation{
- {"arch", ctx.AConfig().BuildOsVariant},
+ {"arch", ctx.Config().BuildOsVariant},
}, hostToolDepTag, g.properties.Tools...)
}
}
@@ -168,7 +168,7 @@
if t, ok := module.(HostToolProvider); ok {
if !t.(android.Module).Enabled() {
- if ctx.AConfig().AllowMissingDependencies() {
+ if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{tool})
} else {
ctx.ModuleErrorf("depends on disabled module %q", tool)
diff --git a/java/aapt2.go b/java/aapt2.go
new file mode 100644
index 0000000..84e3729
--- /dev/null
+++ b/java/aapt2.go
@@ -0,0 +1,166 @@
+// Copyright 2017 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 (
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+const AAPT2_SHARD_SIZE = 100
+
+// Convert input resource file path to output file path.
+// values-[config]/<file>.xml -> values-[config]_<file>.arsc.flat;
+// For other resource file, just replace the last "/" with "_" and
+// add .flat extension.
+func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.WritablePath {
+
+ name := res.Base()
+ subDir := filepath.Dir(res.String())
+ subDir, lastDir := filepath.Split(subDir)
+ if strings.HasPrefix(lastDir, "values") {
+ name = strings.TrimSuffix(name, ".xml") + ".arsc"
+ }
+ name = lastDir + "_" + name + ".flat"
+ return android.PathForModuleOut(ctx, "aapt2", subDir, name)
+}
+
+func pathsToAapt2Paths(ctx android.ModuleContext, resPaths android.Paths) android.WritablePaths {
+ outPaths := make(android.WritablePaths, len(resPaths))
+
+ for i, res := range resPaths {
+ outPaths[i] = pathToAapt2Path(ctx, res)
+ }
+
+ return outPaths
+}
+
+var aapt2CompileRule = pctx.AndroidStaticRule("aapt2Compile",
+ blueprint.RuleParams{
+ Command: `${config.Aapt2Cmd} compile -o $outDir $cFlags --legacy $in`,
+ CommandDeps: []string{"${config.Aapt2Cmd}"},
+ },
+ "outDir", "cFlags")
+
+func aapt2Compile(ctx android.ModuleContext, dir android.Path, paths android.Paths) android.WritablePaths {
+ shards := shardPaths(paths, AAPT2_SHARD_SIZE)
+
+ ret := make(android.WritablePaths, 0, len(paths))
+
+ for i, shard := range shards {
+ outPaths := pathsToAapt2Paths(ctx, shard)
+ ret = append(ret, outPaths...)
+
+ shardDesc := ""
+ if i != 0 {
+ shardDesc = " " + strconv.Itoa(i+1)
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aapt2CompileRule,
+ Description: "aapt2 compile " + dir.String() + shardDesc,
+ Inputs: shard,
+ Outputs: outPaths,
+ Args: map[string]string{
+ "outDir": android.PathForModuleOut(ctx, "aapt2", dir.String()).String(),
+ "cFlags": "--pseudo-localize",
+ },
+ })
+ }
+
+ sort.Slice(ret, func(i, j int) bool {
+ return ret[i].String() < ret[j].String()
+ })
+ return ret
+}
+
+var aapt2LinkRule = pctx.AndroidStaticRule("aapt2Link",
+ blueprint.RuleParams{
+ Command: `${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions $inFlags && ` +
+ `${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir`,
+ CommandDeps: []string{
+ "${config.Aapt2Cmd}",
+ "${config.SoongZipCmd}",
+ },
+ Restat: true,
+ },
+ "flags", "inFlags", "proguardOptions", "genDir", "genJar")
+
+var fileListToFileRule = pctx.AndroidStaticRule("fileListToFile",
+ blueprint.RuleParams{
+ Command: `cp $out.rsp $out`,
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ })
+
+func aapt2Link(ctx android.ModuleContext,
+ packageRes, genJar, proguardOptions android.WritablePath,
+ flags []string, deps android.Paths,
+ compiledRes, compiledOverlay android.Paths) {
+
+ genDir := android.PathForModuleGen(ctx, "aapt2", "R")
+
+ var inFlags []string
+
+ if len(compiledRes) > 0 {
+ resFileList := android.PathForModuleOut(ctx, "aapt2", "res.list")
+ // Write out file lists to files
+ ctx.Build(pctx, android.BuildParams{
+ Rule: fileListToFileRule,
+ Description: "resource file list",
+ Inputs: compiledRes,
+ Output: resFileList,
+ })
+
+ deps = append(deps, compiledRes...)
+ deps = append(deps, resFileList)
+ inFlags = append(inFlags, "@"+resFileList.String())
+ }
+
+ if len(compiledOverlay) > 0 {
+ overlayFileList := android.PathForModuleOut(ctx, "aapt2", "overlay.list")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: fileListToFileRule,
+ Description: "overlay resource file list",
+ Inputs: compiledOverlay,
+ Output: overlayFileList,
+ })
+
+ deps = append(deps, compiledOverlay...)
+ deps = append(deps, overlayFileList)
+ inFlags = append(inFlags, "-R", "@"+overlayFileList.String())
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: aapt2LinkRule,
+ Description: "aapt2 link",
+ Implicits: deps,
+ Output: packageRes,
+ ImplicitOutputs: android.WritablePaths{proguardOptions, genJar},
+ Args: map[string]string{
+ "flags": strings.Join(flags, " "),
+ "inFlags": strings.Join(inFlags, " "),
+ "proguardOptions": proguardOptions.String(),
+ "genDir": genDir.String(),
+ "genJar": genJar.String(),
+ },
+ })
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 1c0526a..2e67639 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -36,12 +36,24 @@
}
if library.dexJarFile != nil {
fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", library.dexJarFile.String())
- if library.deviceProperties.Dex_preopt == nil || *library.deviceProperties.Dex_preopt == false {
+ if library.deviceProperties.Dex_preopt != nil && *library.deviceProperties.Dex_preopt == false {
fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
}
}
fmt.Fprintln(w, "LOCAL_SDK_VERSION :=", String(library.deviceProperties.Sdk_version))
fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", library.headerJarFile.String())
+
+ if library.jacocoReportClassesFile != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", library.jacocoReportClassesFile.String())
+ }
+
+ // Temporary hack: export sources used to compile framework.jar to Make
+ // to be used for droiddoc
+ // TODO(ccross): remove this once droiddoc is in soong
+ if library.Name() == "framework" {
+ fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCS :=", strings.Join(library.compiledJavaSrcs.Strings(), " "))
+ fmt.Fprintln(w, "SOONG_FRAMEWORK_SRCJARS :=", strings.Join(library.compiledSrcJars.Strings(), " "))
+ }
},
},
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
@@ -107,3 +119,40 @@
},
}
}
+
+func (app *AndroidApp) AndroidMk() android.AndroidMkData {
+ return android.AndroidMkData{
+ Class: "APPS",
+ OutputFile: android.OptionalPathForPath(app.outputFile),
+ Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk",
+ Extra: []android.AndroidMkExtraFunc{
+ func(w io.Writer, outputFile android.Path) {
+ if Bool(app.appProperties.Export_package_resources) {
+ if app.dexJarFile != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", app.dexJarFile.String())
+ }
+ fmt.Fprintln(w, "LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE :=", app.exportPackage.String())
+
+ if app.jacocoReportClassesFile != nil {
+ fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", app.jacocoReportClassesFile.String())
+ }
+
+ if app.Name() == "framework-res" {
+ fmt.Fprintln(w, "LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES)")
+ // Make base_rules.mk not put framework-res in a subdirectory called
+ // framework_res.
+ fmt.Fprintln(w, "LOCAL_NO_STANDARD_LIBRARIES := true")
+ }
+
+ if len(app.rroDirs) > 0 {
+ fmt.Fprintln(w, "LOCAL_SOONG_RRO_DIRS :=", strings.Join(app.rroDirs.Strings(), " "))
+ }
+ fmt.Fprintln(w, "LOCAL_EXPORT_PACKAGE_RESOURCES :=",
+ Bool(app.appProperties.Export_package_resources))
+ fmt.Fprintln(w, "LOCAL_FULL_MANIFEST_FILE :=", app.manifestPath.String())
+ }
+ },
+ },
+ }
+
+}
diff --git a/java/app.go b/java/app.go
index 05cc975..6866e2a 100644
--- a/java/app.go
+++ b/java/app.go
@@ -25,6 +25,11 @@
"android/soong/android"
)
+func init() {
+ android.RegisterPreSingletonType("overlay", OverlaySingletonFactory)
+ android.RegisterModuleType("android_app", AndroidAppFactory)
+}
+
// AAR prebuilts
// AndroidManifest.xml merging
// package splits
@@ -54,6 +59,8 @@
// list of directories relative to the Blueprints file containing
// Android resources
Resource_dirs []string
+
+ Instrumentation_for *string
}
type AndroidApp struct {
@@ -61,16 +68,18 @@
appProperties androidAppProperties
- aaptJavaFileList android.Path
- exportPackage android.Path
+ aaptSrcJar android.Path
+ exportPackage android.Path
+ rroDirs android.Paths
+ manifestPath android.Path
}
func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
a.Module.deps(ctx)
- if !proptools.Bool(a.properties.No_standard_libs) {
+ if !Bool(a.properties.No_framework_libs) && !Bool(a.properties.No_standard_libs) {
switch String(a.deviceProperties.Sdk_version) { // TODO: Res_sdk_version?
- case "current", "system_current", "":
+ case "current", "system_current", "test_current", "":
ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
default:
// We'll already have a dependency on an sdk prebuilt android.jar
@@ -79,38 +88,29 @@
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- aaptFlags, aaptDeps, hasResources := a.aaptFlags(ctx)
+ linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath := a.aapt2Flags(ctx)
- if hasResources {
- // First generate R.java so we can build the .class files
- aaptRJavaFlags := append([]string(nil), aaptFlags...)
+ packageRes := android.PathForModuleOut(ctx, "package-res.apk")
+ srcJar := android.PathForModuleGen(ctx, "R.jar")
+ proguardOptionsFile := android.PathForModuleGen(ctx, "proguard.options")
- publicResourcesFile, proguardOptionsFile, aaptJavaFileList :=
- CreateResourceJavaFiles(ctx, aaptRJavaFlags, aaptDeps)
- a.aaptJavaFileList = aaptJavaFileList
- // TODO(ccross): export aapt generated java files as a src jar
-
- if Bool(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)
+ var compiledRes, compiledOverlay android.Paths
+ for _, dir := range resDirs {
+ compiledRes = append(compiledRes, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
}
+ for _, dir := range overlayDirs {
+ compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files).Paths()...)
+ }
+
+ aapt2Link(ctx, packageRes, srcJar, proguardOptionsFile,
+ linkFlags, linkDeps, compiledRes, compiledOverlay)
+
+ a.exportPackage = packageRes
+ a.aaptSrcJar = srcJar
+
+ ctx.CheckbuildFile(proguardOptionsFile)
+ ctx.CheckbuildFile(a.exportPackage)
+ ctx.CheckbuildFile(a.aaptSrcJar)
// apps manifests are handled by aapt, don't let Module see them
a.properties.Manifest = nil
@@ -119,27 +119,19 @@
// a.properties.Proguard.Enabled = true
//}
- a.Module.compile(ctx)
-
- aaptPackageFlags := append([]string(nil), aaptFlags...)
- var hasProduct bool
- for _, f := range aaptPackageFlags {
- if strings.HasPrefix(f, "--product") {
- hasProduct = true
- break
- }
+ if String(a.appProperties.Instrumentation_for) == "" {
+ a.properties.Instrument = true
}
- if !hasProduct {
- aaptPackageFlags = append(aaptPackageFlags,
- "--product "+ctx.AConfig().ProductAAPTCharacteristics())
+ if ctx.ModuleName() != "framework-res" {
+ a.Module.compile(ctx, a.aaptSrcJar)
}
certificate := String(a.appProperties.Certificate)
if certificate == "" {
- certificate = ctx.AConfig().DefaultAppCertificate(ctx).String()
+ certificate = ctx.Config().DefaultAppCertificate(ctx).String()
} else if dir, _ := filepath.Split(certificate); dir == "" {
- certificate = filepath.Join(ctx.AConfig().DefaultAppCertificateDir(ctx).String(), certificate)
+ certificate = filepath.Join(ctx.Config().DefaultAppCertificateDir(ctx).String(), certificate)
} else {
certificate = filepath.Join(android.PathForSource(ctx).String(), certificate)
}
@@ -149,8 +141,20 @@
certificates = append(certificates, filepath.Join(android.PathForSource(ctx).String(), c))
}
- a.outputFile = CreateAppPackage(ctx, aaptPackageFlags, a.outputFile, certificates)
- ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+ packageFile := android.PathForModuleOut(ctx, "package.apk")
+
+ CreateAppPackage(ctx, packageFile, a.exportPackage, a.outputFile, certificates)
+
+ a.outputFile = packageFile
+ a.rroDirs = rroDirs
+ a.manifestPath = manifestPath
+
+ if ctx.ModuleName() == "framework-res" {
+ // framework-res.apk is installed as system/framework/framework-res.apk
+ ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"), ctx.ModuleName()+".apk", a.outputFile)
+ } else {
+ ctx.InstallFile(android.PathForModuleInstall(ctx, "app"), ctx.ModuleName()+".apk", a.outputFile)
+ }
}
var aaptIgnoreFilenames = []string{
@@ -165,57 +169,57 @@
"*~",
}
-func (a *AndroidApp) aaptFlags(ctx android.ModuleContext) ([]string, android.Paths, bool) {
- aaptFlags := a.appProperties.Aaptflags
+type globbedResourceDir struct {
+ dir android.Path
+ files android.Paths
+}
+
+func (a *AndroidApp) aapt2Flags(ctx android.ModuleContext) (flags []string, deps android.Paths,
+ resDirs, overlayDirs []globbedResourceDir, rroDirs android.Paths, manifestPath android.Path) {
+
hasVersionCode := false
hasVersionName := false
- for _, f := range aaptFlags {
+ hasProduct := false
+ for _, f := range a.appProperties.Aaptflags {
if strings.HasPrefix(f, "--version-code") {
hasVersionCode = true
} else if strings.HasPrefix(f, "--version-name") {
hasVersionName = true
+ } else if strings.HasPrefix(f, "--product") {
+ hasProduct = true
}
}
- if true /* is not a test */ {
- aaptFlags = append(aaptFlags, "-z")
- }
+ var linkFlags []string
+ // Flags specified in Android.bp
+ linkFlags = append(linkFlags, a.appProperties.Aaptflags...)
+
+ linkFlags = append(linkFlags, "--no-static-lib-packages")
+
+ // Find implicit or explicit asset and resource dirs
assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Asset_dirs, "assets")
resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.appProperties.Resource_dirs, "res")
- var overlayResourceDirs android.Paths
- // 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 {
- overlay := overlayDir.OverlayPath(ctx, resourceDir)
- if overlay.Valid() {
- overlayResourceDirs = append(overlayResourceDirs, overlay.Path())
- }
- }
+ var linkDeps android.Paths
+
+ // Glob directories into lists of paths
+ for _, dir := range resourceDirs {
+ resDirs = append(resDirs, globbedResourceDir{
+ dir: dir,
+ files: resourceGlob(ctx, dir),
+ })
+ resOverlayDirs, resRRODirs := overlayResourceGlob(ctx, dir)
+ overlayDirs = append(overlayDirs, resOverlayDirs...)
+ rroDirs = append(rroDirs, resRRODirs...)
}
- if len(overlayResourceDirs) > 0 {
- resourceDirs = append(overlayResourceDirs, resourceDirs...)
+ var assetFiles android.Paths
+ for _, dir := range assetDirs {
+ assetFiles = append(assetFiles, resourceGlob(ctx, dir)...)
}
- // 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 android.Paths
- var hasResources bool
- for _, d := range resourceDirs {
- newDeps := ctx.Glob(filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames)
- aaptDeps = append(aaptDeps, newDeps...)
- if len(newDeps) > 0 {
- hasResources = true
- }
- }
- for _, d := range assetDirs {
- newDeps := ctx.Glob(filepath.Join(d.String(), "**/*"), aaptIgnoreFilenames)
- aaptDeps = append(aaptDeps, newDeps...)
- }
-
+ // App manifest file
var manifestFile string
if a.properties.Manifest == nil {
manifestFile = "AndroidManifest.xml"
@@ -223,51 +227,74 @@
manifestFile = *a.properties.Manifest
}
- manifestPath := android.PathForModuleSrc(ctx, manifestFile)
- aaptDeps = append(aaptDeps, manifestPath)
+ manifestPath = android.PathForModuleSrc(ctx, manifestFile)
+ linkFlags = append(linkFlags, "--manifest "+manifestPath.String())
+ linkDeps = append(linkDeps, manifestPath)
- aaptFlags = append(aaptFlags, "-M "+manifestPath.String())
- aaptFlags = append(aaptFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
- aaptFlags = append(aaptFlags, android.JoinWithPrefix(resourceDirs.Strings(), "-S "))
+ linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirs.Strings(), "-A "))
+ linkDeps = append(linkDeps, assetFiles...)
+ // Include dirs
ctx.VisitDirectDeps(func(module android.Module) {
var depFiles android.Paths
if javaDep, ok := module.(Dependency); ok {
+ // TODO: shared android libraries
if ctx.OtherModuleName(module) == "framework-res" {
depFiles = android.Paths{javaDep.(*AndroidApp).exportPackage}
}
}
for _, dep := range depFiles {
- aaptFlags = append(aaptFlags, "-I "+dep.String())
+ linkFlags = append(linkFlags, "-I "+dep.String())
}
- aaptDeps = append(aaptDeps, depFiles...)
+ linkDeps = append(linkDeps, depFiles...)
})
+ // SDK version flags
sdkVersion := String(a.deviceProperties.Sdk_version)
- if sdkVersion == "" {
- sdkVersion = ctx.AConfig().PlatformSdkVersion()
+ switch sdkVersion {
+ case "", "current", "system_current", "test_current":
+ sdkVersion = ctx.Config().AppsDefaultVersionName()
}
- aaptFlags = append(aaptFlags, "--min-sdk-version "+sdkVersion)
- aaptFlags = append(aaptFlags, "--target-sdk-version "+sdkVersion)
+ linkFlags = append(linkFlags, "--min-sdk-version "+sdkVersion)
+ linkFlags = append(linkFlags, "--target-sdk-version "+sdkVersion)
+ // Product characteristics
+ if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
+ linkFlags = append(linkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
+ }
+
+ // Product AAPT config
+ for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
+ linkFlags = append(linkFlags, "-c", aaptConfig)
+ }
+
+ // Product AAPT preferred config
+ if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
+ linkFlags = append(linkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
+ }
+
+ // Version code
if !hasVersionCode {
- aaptFlags = append(aaptFlags, "--version-code "+ctx.AConfig().PlatformSdkVersion())
+ linkFlags = append(linkFlags, "--version-code", ctx.Config().PlatformSdkVersion())
}
if !hasVersionName {
- aaptFlags = append(aaptFlags,
- "--version-name "+ctx.AConfig().PlatformVersion()+"-"+ctx.AConfig().BuildNumber())
+ versionName := proptools.NinjaEscape([]string{ctx.Config().AppsDefaultVersionName()})[0]
+ linkFlags = append(linkFlags, "--version-name ", versionName)
+ }
+
+ if String(a.appProperties.Instrumentation_for) != "" {
+ linkFlags = append(linkFlags,
+ "--rename-instrumentation-target-package",
+ String(a.appProperties.Instrumentation_for))
}
// 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
+ return linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, manifestPath
}
func AndroidAppFactory() android.Module {
@@ -281,3 +308,114 @@
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
+
+func resourceGlob(ctx android.ModuleContext, dir android.Path) android.Paths {
+ var ret android.Paths
+ files := ctx.Glob(filepath.Join(dir.String(), "**/*"), aaptIgnoreFilenames)
+ for _, f := range files {
+ if isDir, err := ctx.Fs().IsDir(f.String()); err != nil {
+ ctx.ModuleErrorf("error in IsDir(%s): %s", f.String(), err.Error())
+ return nil
+ } else if !isDir {
+ ret = append(ret, f)
+ }
+ }
+ return ret
+}
+
+type overlayGlobResult struct {
+ dir string
+ paths android.DirectorySortedPaths
+
+ // Set to true of the product has selected that values in this overlay should not be moved to
+ // Runtime Resource Overlay (RRO) packages.
+ excludeFromRRO bool
+}
+
+const overlayDataKey = "overlayDataKey"
+
+func overlayResourceGlob(ctx android.ModuleContext, dir android.Path) (res []globbedResourceDir,
+ rroDirs android.Paths) {
+
+ overlayData := ctx.Config().Get(overlayDataKey).([]overlayGlobResult)
+
+ // Runtime resource overlays (RRO) may be turned on by the product config for some modules
+ rroEnabled := false
+ enforceRROTargets := ctx.Config().ProductVariables.EnforceRROTargets
+ if enforceRROTargets != nil {
+ if len(*enforceRROTargets) == 1 && (*enforceRROTargets)[0] == "*" {
+ rroEnabled = true
+ } else if inList(ctx.ModuleName(), *enforceRROTargets) {
+ rroEnabled = true
+ }
+ }
+
+ for _, data := range overlayData {
+ files := data.paths.PathsInDirectory(filepath.Join(data.dir, dir.String()))
+ if len(files) > 0 {
+ overlayModuleDir := android.PathForSource(ctx, data.dir, dir.String())
+ // If enforce RRO is enabled for this module and this overlay is not in the
+ // exclusion list, ignore the overlay. The list of ignored overlays will be
+ // passed to Make to be turned into an RRO package.
+ if rroEnabled && !data.excludeFromRRO {
+ rroDirs = append(rroDirs, overlayModuleDir)
+ } else {
+ res = append(res, globbedResourceDir{
+ dir: overlayModuleDir,
+ files: files,
+ })
+ }
+ }
+ }
+
+ return res, rroDirs
+}
+
+func OverlaySingletonFactory() android.Singleton {
+ return overlaySingleton{}
+}
+
+type overlaySingleton struct{}
+
+func (overlaySingleton) GenerateBuildActions(ctx android.SingletonContext) {
+
+ // Specific overlays may be excluded from Runtime Resource Overlays by the product config
+ var rroExcludedOverlays []string
+ if ctx.Config().ProductVariables.EnforceRROExcludedOverlays != nil {
+ rroExcludedOverlays = *ctx.Config().ProductVariables.EnforceRROExcludedOverlays
+ }
+
+ var overlayData []overlayGlobResult
+ for _, overlay := range ctx.Config().ResourceOverlays() {
+ var result overlayGlobResult
+ result.dir = overlay
+
+ // Mark overlays that will not have Runtime Resource Overlays enforced on them
+ for _, exclude := range rroExcludedOverlays {
+ if strings.HasPrefix(overlay, exclude) {
+ result.excludeFromRRO = true
+ }
+ }
+
+ files, err := ctx.GlobWithDeps(filepath.Join(overlay, "**/*"), aaptIgnoreFilenames)
+ if err != nil {
+ ctx.Errorf("failed to glob resource dir %q: %s", overlay, err.Error())
+ continue
+ }
+ var paths android.Paths
+ for _, f := range files {
+ if isDir, err := ctx.Fs().IsDir(f); err != nil {
+ ctx.Errorf("error in IsDir(%s): %s", f, err.Error())
+ return
+ } else if !isDir {
+ paths = append(paths, android.PathForSource(ctx, f))
+ }
+ }
+ result.paths = android.PathsToDirectorySortedPaths(paths)
+ overlayData = append(overlayData, result)
+ }
+
+ ctx.Config().Once(overlayDataKey, func() interface{} {
+ return overlayData
+ })
+}
diff --git a/java/app_builder.go b/java/app_builder.go
index ed7abce..676ed58 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -27,35 +27,11 @@
)
var (
- aaptCreateResourceJavaFile = pctx.AndroidStaticRule("aaptCreateResourceJavaFile",
- blueprint.RuleParams{
- Command: `rm -rf "$javaDir" && mkdir -p "$javaDir" && ` +
- `$aaptCmd package -m $aaptFlags -P $publicResourcesFile -G $proguardOptionsFile ` +
- `-J $javaDir || ( rm -rf "$javaDir/*"; exit 41 ) && ` +
- `find $javaDir -name "*.java" > $javaFileList`,
- CommandDeps: []string{"$aaptCmd"},
- },
- "aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
-
- aaptCreateAssetsPackage = pctx.AndroidStaticRule("aaptCreateAssetsPackage",
- blueprint.RuleParams{
- Command: `rm -f $out && $aaptCmd package $aaptFlags -F $out`,
- CommandDeps: []string{"$aaptCmd"},
- },
- "aaptFlags", "publicResourcesFile", "proguardOptionsFile", "javaDir", "javaFileList")
-
- aaptAddResources = pctx.AndroidStaticRule("aaptAddResources",
- blueprint.RuleParams{
- // TODO: add-jni-shared-libs-to-package
- Command: `cp -f $in $out.tmp && $aaptCmd package -u $aaptFlags -F $out.tmp && mv $out.tmp $out`,
- CommandDeps: []string{"$aaptCmd"},
- },
- "aaptFlags")
-
signapk = pctx.AndroidStaticRule("signapk",
blueprint.RuleParams{
- Command: `java -jar $signapkCmd $certificates $in $out`,
- CommandDeps: []string{"$signapkCmd"},
+ Command: `${config.JavaCmd} -Djava.library.path=$$(dirname $signapkJniLibrary) ` +
+ `-jar $signapkCmd $certificates $in $out`,
+ CommandDeps: []string{"$signapkCmd", "$signapkJniLibrary"},
},
"certificates")
@@ -73,79 +49,50 @@
pctx.SourcePathVariable("androidManifestMergerCmd", "prebuilts/devtools/tools/lib/manifest-merger.jar")
pctx.HostBinToolVariable("aaptCmd", "aapt")
pctx.HostJavaToolVariable("signapkCmd", "signapk.jar")
+ // TODO(ccross): this should come from the signapk dependencies, but we don't have any way
+ // to express host JNI dependencies yet.
+ pctx.HostJNIToolVariable("signapkJniLibrary", "libconscrypt_openjdk_jni")
}
-func CreateResourceJavaFiles(ctx android.ModuleContext, flags []string,
- deps android.Paths) (android.Path, android.Path, android.Path) {
- javaDir := android.PathForModuleGen(ctx, "R")
- javaFileList := android.PathForModuleOut(ctx, "R.filelist")
- publicResourcesFile := android.PathForModuleOut(ctx, "public_resources.xml")
- proguardOptionsFile := android.PathForModuleOut(ctx, "proguard.options")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: aaptCreateResourceJavaFile,
- Description: "aapt create R.java",
- Outputs: android.WritablePaths{publicResourcesFile, proguardOptionsFile, javaFileList},
- Implicits: deps,
- Args: map[string]string{
- "aaptFlags": strings.Join(flags, " "),
- "publicResourcesFile": publicResourcesFile.String(),
- "proguardOptionsFile": proguardOptionsFile.String(),
- "javaDir": javaDir.String(),
- "javaFileList": javaFileList.String(),
- },
+var combineApk = pctx.AndroidStaticRule("combineApk",
+ blueprint.RuleParams{
+ Command: `${config.MergeZipsCmd} $out $in`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
})
- return publicResourcesFile, proguardOptionsFile, javaFileList
-}
+func CreateAppPackage(ctx android.ModuleContext, outputFile android.WritablePath,
+ resJarFile, dexJarFile android.Path, certificates []string) {
-func CreateExportPackage(ctx android.ModuleContext, flags []string, deps android.Paths) android.ModuleOutPath {
- outputFile := android.PathForModuleOut(ctx, "package-export.apk")
+ // TODO(ccross): JNI libs
+
+ unsignedApk := android.PathForModuleOut(ctx, "unsigned.apk")
+
+ inputs := android.Paths{resJarFile}
+ if dexJarFile != nil {
+ inputs = append(inputs, dexJarFile)
+ }
ctx.Build(pctx, android.BuildParams{
- Rule: aaptCreateAssetsPackage,
- Description: "aapt export package",
- Output: outputFile,
- Implicits: deps,
- Args: map[string]string{
- "aaptFlags": strings.Join(flags, " "),
- },
+ Rule: combineApk,
+ Inputs: inputs,
+ Output: unsignedApk,
})
- return outputFile
-}
-
-func CreateAppPackage(ctx android.ModuleContext, flags []string, jarFile android.Path,
- certificates []string) android.Path {
-
- resourceApk := android.PathForModuleOut(ctx, "resources.apk")
-
- ctx.Build(pctx, android.BuildParams{
- Rule: aaptAddResources,
- Description: "aapt package",
- Output: resourceApk,
- Input: jarFile,
- Args: map[string]string{
- "aaptFlags": strings.Join(flags, " "),
- },
- })
-
- outputFile := android.PathForModuleOut(ctx, "package.apk")
-
var certificateArgs []string
for _, c := range certificates {
certificateArgs = append(certificateArgs, c+".x509.pem", c+".pk8")
}
+ // TODO(ccross): sometimes uncompress dex
+ // TODO(ccross): sometimes strip dex
+
ctx.Build(pctx, android.BuildParams{
Rule: signapk,
Description: "signapk",
Output: outputFile,
- Input: resourceApk,
+ Input: unsignedApk,
Args: map[string]string{
"certificates": strings.Join(certificateArgs, " "),
},
})
-
- return outputFile
}
diff --git a/java/app_test.go b/java/app_test.go
new file mode 100644
index 0000000..73ac3f7
--- /dev/null
+++ b/java/app_test.go
@@ -0,0 +1,239 @@
+// Copyright 2017 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 (
+ "android/soong/android"
+ "reflect"
+ "sort"
+ "testing"
+)
+
+var (
+ resourceFiles = []string{
+ "res/layout/layout.xml",
+ "res/values/strings.xml",
+ "res/values-en-rUS/strings.xml",
+ }
+
+ compiledResourceFiles = []string{
+ "aapt2/res/layout_layout.xml.flat",
+ "aapt2/res/values_strings.arsc.flat",
+ "aapt2/res/values-en-rUS_strings.arsc.flat",
+ }
+)
+
+func testAppContext(config android.Config, bp string, fs map[string][]byte) *android.TestContext {
+ appFS := map[string][]byte{}
+ for k, v := range fs {
+ appFS[k] = v
+ }
+
+ for _, file := range resourceFiles {
+ appFS[file] = nil
+ }
+
+ return testContext(config, bp, appFS)
+}
+
+func testApp(t *testing.T, bp string) *android.TestContext {
+ config := testConfig(nil)
+
+ ctx := testAppContext(config, bp, nil)
+
+ run(t, ctx, config)
+
+ return ctx
+}
+
+func TestApp(t *testing.T) {
+ ctx := testApp(t, `
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ }
+ `)
+
+ foo := ctx.ModuleForTests("foo", "android_common")
+
+ expectedLinkImplicits := []string{"AndroidManifest.xml"}
+
+ frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
+ expectedLinkImplicits = append(expectedLinkImplicits,
+ frameworkRes.Output("package-res.apk").Output.String())
+
+ // Test the mapping from input files to compiled output file names
+ compile := foo.Output(compiledResourceFiles[0])
+ if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
+ t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
+ resourceFiles, compile.Inputs.Strings())
+ }
+
+ compiledResourceOutputs := compile.Outputs.Strings()
+ sort.Strings(compiledResourceOutputs)
+
+ expectedLinkImplicits = append(expectedLinkImplicits, compiledResourceOutputs...)
+
+ list := foo.Output("aapt2/res.list")
+ expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
+
+ // Check that the link rule uses
+ res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
+ if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
+ t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
+ expectedLinkImplicits, res.Implicits.Strings())
+ }
+}
+
+var testEnforceRROTests = []struct {
+ name string
+ enforceRROTargets []string
+ enforceRROExcludedOverlays []string
+ fooOverlayFiles []string
+ fooRRODirs []string
+ barOverlayFiles []string
+ barRRODirs []string
+}{
+ {
+ name: "no RRO",
+ enforceRROTargets: nil,
+ enforceRROExcludedOverlays: nil,
+ fooOverlayFiles: []string{
+ "device/vendor/blah/overlay/foo/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ },
+ fooRRODirs: nil,
+ barOverlayFiles: []string{
+ "device/vendor/blah/overlay/bar/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+ },
+ barRRODirs: nil,
+ },
+ {
+ name: "enforce RRO on foo",
+ enforceRROTargets: []string{"foo"},
+ enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+ fooOverlayFiles: []string{
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ },
+ fooRRODirs: []string{
+ "device/vendor/blah/overlay/foo/res",
+ },
+ barOverlayFiles: []string{
+ "device/vendor/blah/overlay/bar/res/values/strings.xml",
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+ },
+ barRRODirs: nil,
+ },
+ {
+ name: "enforce RRO on all",
+ enforceRROTargets: []string{"*"},
+ enforceRROExcludedOverlays: []string{"device/vendor/blah/static_overlay"},
+ fooOverlayFiles: []string{
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml",
+ },
+ fooRRODirs: []string{
+ "device/vendor/blah/overlay/foo/res",
+ },
+ barOverlayFiles: []string{
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml",
+ },
+ barRRODirs: []string{
+ "device/vendor/blah/overlay/bar/res",
+ },
+ },
+}
+
+func TestEnforceRRO(t *testing.T) {
+ resourceOverlays := []string{
+ "device/vendor/blah/overlay",
+ "device/vendor/blah/overlay2",
+ "device/vendor/blah/static_overlay",
+ }
+
+ fs := map[string][]byte{
+ "foo/res/res/values/strings.xml": nil,
+ "bar/res/res/values/strings.xml": nil,
+ "device/vendor/blah/overlay/foo/res/values/strings.xml": nil,
+ "device/vendor/blah/overlay/bar/res/values/strings.xml": nil,
+ "device/vendor/blah/static_overlay/foo/res/values/strings.xml": nil,
+ "device/vendor/blah/static_overlay/bar/res/values/strings.xml": nil,
+ "device/vendor/blah/overlay2/res/values/strings.xml": nil,
+ }
+
+ bp := `
+ android_app {
+ name: "foo",
+ resource_dirs: ["foo/res"],
+ }
+
+ android_app {
+ name: "bar",
+ resource_dirs: ["bar/res"],
+ }
+ `
+
+ for _, testCase := range testEnforceRROTests {
+ t.Run(testCase.name, func(t *testing.T) {
+ config := testConfig(nil)
+ config.ProductVariables.ResourceOverlays = &resourceOverlays
+ if testCase.enforceRROTargets != nil {
+ config.ProductVariables.EnforceRROTargets = &testCase.enforceRROTargets
+ }
+ if testCase.enforceRROExcludedOverlays != nil {
+ config.ProductVariables.EnforceRROExcludedOverlays = &testCase.enforceRROExcludedOverlays
+ }
+
+ ctx := testAppContext(config, bp, fs)
+ run(t, ctx, config)
+
+ getOverlays := func(moduleName string) ([]string, []string) {
+ module := ctx.ModuleForTests(moduleName, "android_common")
+ overlayCompiledPaths := module.Output("aapt2/overlay.list").Inputs.Strings()
+
+ var overlayFiles []string
+ for _, o := range overlayCompiledPaths {
+ overlayFiles = append(overlayFiles, module.Output(o).Inputs.Strings()...)
+ }
+
+ rroDirs := module.Module().(*AndroidApp).rroDirs.Strings()
+
+ return overlayFiles, rroDirs
+ }
+
+ fooOverlayFiles, fooRRODirs := getOverlays("foo")
+ barOverlayFiles, barRRODirs := getOverlays("bar")
+
+ if !reflect.DeepEqual(fooOverlayFiles, testCase.fooOverlayFiles) {
+ t.Errorf("expected foo overlay files:\n %#v\n got:\n %#v",
+ testCase.fooOverlayFiles, fooOverlayFiles)
+ }
+ if !reflect.DeepEqual(fooRRODirs, testCase.fooRRODirs) {
+ t.Errorf("expected foo rroDirs: %#v\n got:\n %#v",
+ testCase.fooRRODirs, fooRRODirs)
+ }
+
+ if !reflect.DeepEqual(barOverlayFiles, testCase.barOverlayFiles) {
+ t.Errorf("expected bar overlay files:\n %#v\n got:\n %#v",
+ testCase.barOverlayFiles, barOverlayFiles)
+ }
+ if !reflect.DeepEqual(barRRODirs, testCase.barRRODirs) {
+ t.Errorf("expected bar rroDirs: %#v\n got:\n %#v",
+ testCase.barRRODirs, barRRODirs)
+ }
+
+ })
+ }
+}
diff --git a/java/builder.go b/java/builder.go
index 4be3b04..be40103 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -386,7 +386,7 @@
dumpDir := android.PathForModuleOut(ctx, "desugar", "classes")
javaFlags := ""
- if ctx.AConfig().UseOpenJDK9() {
+ if ctx.Config().UseOpenJDK9() {
javaFlags = "--add-opens java.base/java.lang.invoke=ALL-UNNAMED"
}
diff --git a/java/config/config.go b/java/config/config.go
index 3cd2841..603d43f 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -15,6 +15,8 @@
package config
import (
+ "path/filepath"
+ "runtime"
"strings"
_ "github.com/google/blueprint/bootstrap"
@@ -28,6 +30,16 @@
DefaultBootclasspathLibraries = []string{"core-oj", "core-libart"}
DefaultSystemModules = "core-system-modules"
DefaultLibraries = []string{"ext", "framework", "okhttp"}
+
+ DefaultJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
+
+ InstrumentFrameworkModules = []string{
+ "framework",
+ "telephony-common",
+ "services",
+ "android.car",
+ "android.car7",
+ }
)
func init() {
@@ -54,9 +66,9 @@
pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
- pctx.VariableFunc("JavaHome", func(config interface{}) (string, error) {
+ pctx.VariableFunc("JavaHome", func(config android.Config) (string, error) {
// This is set up and guaranteed by soong_ui
- return config.(android.Config).Getenv("ANDROID_JAVA_HOME"), nil
+ return config.Getenv("ANDROID_JAVA_HOME"), nil
})
pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin")
@@ -74,9 +86,10 @@
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips")
- pctx.VariableFunc("DxCmd", func(config interface{}) (string, error) {
- if config.(android.Config).IsEnvFalse("USE_D8") {
- if config.(android.Config).UnbundledBuild() || config.(android.Config).IsPdkBuild() {
+ pctx.HostBinToolVariable("Zip2ZipCmd", "zip2zip")
+ pctx.VariableFunc("DxCmd", func(config android.Config) (string, error) {
+ if config.IsEnvFalse("USE_D8") {
+ if config.UnbundledBuild() || config.IsPdkBuild() {
return "prebuilts/build-tools/common/bin/dx", nil
} else {
path, err := pctx.HostBinToolPath(config, "dx")
@@ -93,9 +106,9 @@
return path.String(), nil
}
})
- pctx.VariableFunc("TurbineJar", func(config interface{}) (string, error) {
+ pctx.VariableFunc("TurbineJar", func(config android.Config) (string, error) {
turbine := "turbine.jar"
- if config.(android.Config).UnbundledBuild() {
+ if config.UnbundledBuild() {
return "prebuilts/build-tools/common/framework/" + turbine, nil
} else {
path, err := pctx.HostJavaToolPath(config, turbine)
@@ -111,10 +124,28 @@
pctx.HostBinToolVariable("SoongJavacWrapper", "soong_javac_wrapper")
- pctx.VariableFunc("JavacWrapper", func(config interface{}) (string, error) {
- if override := config.(android.Config).Getenv("JAVAC_WRAPPER"); override != "" {
+ pctx.VariableFunc("JavacWrapper", func(config android.Config) (string, error) {
+ if override := config.Getenv("JAVAC_WRAPPER"); override != "" {
return override + " ", nil
}
return "", nil
})
+
+ pctx.HostJavaToolVariable("JacocoCLIJar", "jacoco-cli.jar")
+
+ hostBinToolVariableWithPrebuilt := func(name, prebuiltDir, tool string) {
+ pctx.VariableFunc(name, func(config android.Config) (string, error) {
+ if config.UnbundledBuild() || config.IsPdkBuild() {
+ return filepath.Join(prebuiltDir, runtime.GOOS, "bin", tool), nil
+ } else {
+ if path, err := pctx.HostBinToolPath(config, tool); err != nil {
+ return "", err
+ } else {
+ return path.String(), nil
+ }
+ }
+ })
+ }
+
+ hostBinToolVariableWithPrebuilt("Aapt2Cmd", "prebuilt/sdk/tools", "aapt2")
}
diff --git a/java/config/error_prone.go b/java/config/error_prone.go
index 31cbf2c..862217f 100644
--- a/java/config/error_prone.go
+++ b/java/config/error_prone.go
@@ -14,6 +14,8 @@
package config
+import "android/soong/android"
+
var (
// These will be filled out by external/error_prone/soong/error_prone.go if it is available
ErrorProneJavacJar string
@@ -25,7 +27,7 @@
// Wrapper that grabs value of val late so it can be initialized by a later module's init function
func errorProneVar(name string, val *string) {
- pctx.VariableFunc(name, func(config interface{}) (string, error) {
+ pctx.VariableFunc(name, func(config android.Config) (string, error) {
return *val, nil
})
}
diff --git a/java/config/makevars.go b/java/config/makevars.go
index dabf2e7..b9009f3 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -62,4 +62,7 @@
ctx.Strict("SOONG_JAVAC_WRAPPER", "${SoongJavacWrapper}")
ctx.Strict("EXTRACT_SRCJARS", "${ExtractSrcJarsCmd}")
+
+ ctx.Strict("JACOCO_CLI_JAR", "${JacocoCLIJar}")
+ ctx.Strict("DEFAULT_JACOCO_EXCLUDE_FILTER", strings.Join(DefaultJacocoExcludeFilter, ","))
}
diff --git a/java/gen.go b/java/gen.go
index b5973ec..7a0dcac 100644
--- a/java/gen.go
+++ b/java/gen.go
@@ -28,8 +28,6 @@
pctx.HostBinToolVariable("aidlCmd", "aidl")
pctx.SourcePathVariable("logtagsCmd", "build/tools/java-event-log-tags.py")
pctx.SourcePathVariable("mergeLogtagsCmd", "build/tools/merge-event-log-tags.py")
-
- pctx.IntermediatesPathVariable("allLogtagsFile", "all-event-log-tags.txt")
}
var (
@@ -117,7 +115,7 @@
return outSrcFiles
}
-func LogtagsSingleton() blueprint.Singleton {
+func LogtagsSingleton() android.Singleton {
return &logtagsSingleton{}
}
@@ -127,18 +125,18 @@
type logtagsSingleton struct{}
-func (l *logtagsSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+func (l *logtagsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var allLogtags android.Paths
- ctx.VisitAllModules(func(module blueprint.Module) {
+ ctx.VisitAllModules(func(module android.Module) {
if logtags, ok := module.(logtagsProducer); ok {
allLogtags = append(allLogtags, logtags.logtags()...)
}
})
- ctx.Build(pctx, blueprint.BuildParams{
+ ctx.Build(pctx, android.BuildParams{
Rule: mergeLogtags,
Description: "merge logtags",
- Outputs: []string{"$allLogtagsFile"},
- Inputs: allLogtags.Strings(),
+ Output: android.PathForIntermediates(ctx, "all-event-log-tags.txt"),
+ Inputs: allLogtags,
})
}
diff --git a/java/jacoco.go b/java/jacoco.go
new file mode 100644
index 0000000..b26b046
--- /dev/null
+++ b/java/jacoco.go
@@ -0,0 +1,108 @@
+// Copyright 2017 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
+
+// Rules for instrumenting classes using jacoco
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+
+ "android/soong/android"
+)
+
+var (
+ jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{
+ Command: `${config.Zip2ZipCmd} -i $in -o $strippedJar $stripSpec && ` +
+ `${config.JavaCmd} -jar ${config.JacocoCLIJar} instrument -quiet -dest $instrumentedJar $strippedJar && ` +
+ `${config.Ziptime} $instrumentedJar && ` +
+ `${config.MergeZipsCmd} --ignore-duplicates -j $out $instrumentedJar $in`,
+ CommandDeps: []string{
+ "${config.Zip2ZipCmd}",
+ "${config.JavaCmd}",
+ "${config.JacocoCLIJar}",
+ "${config.Ziptime}",
+ "${config.MergeZipsCmd}",
+ },
+ },
+ "strippedJar", "stripSpec", "instrumentedJar")
+)
+
+func jacocoInstrumentJar(ctx android.ModuleContext, outputJar, strippedJar android.WritablePath,
+ inputJar android.Path, stripSpec string) {
+ instrumentedJar := android.PathForModuleOut(ctx, "jacoco/instrumented.jar")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: jacoco,
+ Description: "jacoco",
+ Output: outputJar,
+ ImplicitOutput: strippedJar,
+ Input: inputJar,
+ Args: map[string]string{
+ "strippedJar": strippedJar.String(),
+ "stripSpec": stripSpec,
+ "instrumentedJar": instrumentedJar.String(),
+ },
+ })
+}
+
+func (j *Module) jacocoStripSpecs(ctx android.ModuleContext) string {
+ includes := jacocoFiltersToSpecs(ctx,
+ j.properties.Jacoco.Include_filter, "jacoco.include_filter")
+ excludes := jacocoFiltersToSpecs(ctx,
+ j.properties.Jacoco.Exclude_filter, "jacoco.exclude_filter")
+
+ specs := ""
+ if len(excludes) > 0 {
+ specs += android.JoinWithPrefix(excludes, "-x") + " "
+ }
+
+ if len(includes) > 0 {
+ specs += strings.Join(includes, " ")
+ } else {
+ specs += "**/*.class"
+ }
+
+ return specs
+}
+
+func jacocoFiltersToSpecs(ctx android.ModuleContext, filters []string, property string) []string {
+ specs := make([]string, len(filters))
+ for i, f := range filters {
+ specs[i] = jacocoFilterToSpec(ctx, f, property)
+ }
+ return specs
+}
+
+func jacocoFilterToSpec(ctx android.ModuleContext, filter string, property string) string {
+ wildcard := strings.HasSuffix(filter, "*")
+ filter = strings.TrimSuffix(filter, "*")
+ recursiveWildcard := wildcard && (strings.HasSuffix(filter, ".") || filter == "")
+
+ if strings.ContainsRune(filter, '*') {
+ ctx.PropertyErrorf(property, "'*' is only supported as the last character in a filter")
+ }
+
+ spec := strings.Replace(filter, ".", "/", -1)
+
+ if recursiveWildcard {
+ spec += "**/*.class"
+ } else if wildcard {
+ spec += "*.class"
+ }
+
+ return spec
+}
diff --git a/java/java.go b/java/java.go
index b2bd2b0..4355200 100644
--- a/java/java.go
+++ b/java/java.go
@@ -41,7 +41,6 @@
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)
}
@@ -51,9 +50,6 @@
// Renderscript
// Post-jar passes:
// Proguard
-// Jacoco
-// Jarjar
-// Dex
// Rmtypedefs
// DroidDoc
// Findbugs
@@ -127,6 +123,26 @@
// 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 {
@@ -177,6 +193,9 @@
// 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
@@ -184,12 +203,12 @@
logtagsSrcs android.Paths
- // jars containing source files that should be included in the javac command line,
- // for example R.java generated by aapt for android apps
- ExtraSrcJars android.Paths
-
// installed file for binary dependency
installFile android.Path
+
+ // list of .java files and srcjars that was passed to javac
+ compiledJavaSrcs android.Paths
+ compiledSrcJars android.Paths
}
type Dependency interface {
@@ -232,7 +251,7 @@
case "", "current", "system_current", "test_current":
return 10000
default:
- if i, err := strconv.Atoi(v); err != nil {
+ if i, err := strconv.Atoi(android.GetNumericSdkVersion(v)); err != nil {
ctx.PropertyErrorf("sdk_version", "invalid sdk version")
return -1
} else {
@@ -255,7 +274,13 @@
jarPath := android.ExistentPathForSource(ctx, "sdkdir", jar)
aidlPath := android.ExistentPathForSource(ctx, "sdkdir", aidl)
- if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.AConfig().AllowMissingDependencies() {
+ if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
+ if strings.Contains(v, "system_") {
+ return sdkDep{
+ invalidVersion: true,
+ module: "vsdk_v" + strings.Replace(v, "system_", "", 1),
+ }
+ }
return sdkDep{
invalidVersion: true,
module: "sdk_v" + v,
@@ -287,7 +312,7 @@
// }
//}
- if ctx.AConfig().UnbundledBuild() && v != "" {
+ if ctx.Config().UnbundledBuild() && v != "" {
return toFile(v)
}
@@ -315,14 +340,14 @@
sdkDep := decodeSdkDep(ctx, String(j.deviceProperties.Sdk_version))
if sdkDep.useDefaultLibs {
ctx.AddDependency(ctx.Module(), bootClasspathTag, config.DefaultBootclasspathLibraries...)
- if ctx.AConfig().TargetOpenJDK9() {
+ 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.AConfig().TargetOpenJDK9() {
+ if ctx.Config().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, sdkDep.systemModules)
}
ctx.AddDependency(ctx.Module(), bootClasspathTag, sdkDep.module)
@@ -330,9 +355,12 @@
} 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.AConfig().TargetOpenJDK9() {
+ } else if *j.deviceProperties.System_modules != "none" && ctx.Config().TargetOpenJDK9() {
ctx.AddDependency(ctx.Module(), systemModulesTag, *j.deviceProperties.System_modules)
}
+ if ctx.ModuleName() == "framework" {
+ ctx.AddDependency(ctx.Module(), frameworkResTag, "framework-res")
+ }
}
ctx.AddDependency(ctx.Module(), libTag, j.properties.Libs...)
@@ -467,7 +495,7 @@
if ctx.ModuleName() == "framework" {
// framework.jar has a one-off dependency on the R.java and Manifest.java files
// generated by framework-res.apk
- // TODO(ccross): aapt java files should go in a src jar
+ deps.srcJars = append(deps.srcJars, dep.(*AndroidApp).aaptSrcJar)
}
case kotlinStdlibTag:
deps.kotlinStdlib = dep.HeaderJars()
@@ -487,10 +515,10 @@
// javac flags.
javacFlags := j.properties.Javacflags
- if ctx.AConfig().TargetOpenJDK9() {
+ if ctx.Config().TargetOpenJDK9() {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
}
- if ctx.AConfig().MinimizeJavaDebugInfo() {
+ 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")
@@ -507,7 +535,7 @@
flags.javaVersion = *j.properties.Java_version
} else if ctx.Device() && sdk <= 23 {
flags.javaVersion = "1.7"
- } else if ctx.Device() && sdk <= 26 || !ctx.AConfig().TargetOpenJDK9() {
+ } 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"
@@ -535,14 +563,14 @@
return flags
}
-func (j *Module) compile(ctx android.ModuleContext) {
+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.AConfig().TargetOpenJDK9() {
+ 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)
@@ -554,7 +582,7 @@
srcJars := srcFiles.FilterByExt(".srcjar")
srcJars = append(srcJars, deps.srcJars...)
- srcJars = append(srcJars, j.ExtraSrcJars...)
+ srcJars = append(srcJars, extraSrcJars...)
var jars android.Paths
@@ -596,8 +624,12 @@
}
}
+ // Store the list of .java files that was passed to javac
+ j.compiledJavaSrcs = uniqueSrcFiles
+ j.compiledSrcJars = srcJars
+
enable_sharding := false
- if ctx.Device() && !ctx.AConfig().IsEnvFalse("TURBINE_ENABLED") {
+ 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 ||
@@ -618,7 +650,7 @@
}
if len(uniqueSrcFiles) > 0 || len(srcJars) > 0 {
var extraJarDeps android.Paths
- if ctx.AConfig().IsEnvTrue("RUN_ERROR_PRONE") {
+ 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).
@@ -718,6 +750,20 @@
}
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
@@ -766,6 +812,42 @@
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 {
@@ -780,11 +862,11 @@
dxFlags = append(dxFlags, "--no-locals")
}
- if ctx.AConfig().Getenv("NO_OPTIMIZE_DX") != "" {
+ if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" {
dxFlags = append(dxFlags, "--no-optimize")
}
- if ctx.AConfig().Getenv("GENERATE_DEX_DEBUG") != "" {
+ if ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" {
dxFlags = append(dxFlags,
"--debug",
"--verbose",
@@ -792,47 +874,29 @@
"--dump-width=1000")
}
- var minSdkVersion string
- switch String(j.deviceProperties.Sdk_version) {
- case "", "current", "test_current", "system_current":
- minSdkVersion = strconv.Itoa(ctx.AConfig().DefaultAppTargetSdkInt())
- default:
- minSdkVersion = String(j.deviceProperties.Sdk_version)
- }
-
- dxFlags = append(dxFlags, "--min-sdk-version="+minSdkVersion)
+ dxFlags = append(dxFlags, "--min-sdk-version="+j.minSdkVersionNumber(ctx))
flags.dxFlags = strings.Join(dxFlags, " ")
- desugarFlags := []string{
- "--min_sdk_version " + minSdkVersion,
- "--desugar_try_with_resources_if_needed=false",
- "--allow_empty_bootclasspath",
- }
-
- if inList("--core-library", dxFlags) {
- desugarFlags = append(desugarFlags, "--core_library")
- }
-
- flags.desugarFlags = strings.Join(desugarFlags, " ")
-
- desugarJar := android.PathForModuleOut(ctx, "desugar", jarName)
- TransformDesugar(ctx, desugarJar, classesJar, flags)
- if ctx.Failed() {
- return nil
- }
-
// Compile classes.jar into classes.dex and then javalib.jar
javalibJar := android.PathForModuleOut(ctx, "dex", jarName)
- TransformClassesJarToDexJar(ctx, javalibJar, desugarJar, flags)
- if ctx.Failed() {
- return nil
- }
+ 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 android.GetNumericSdkVersion(String(j.deviceProperties.Sdk_version))
+ }
+}
+
func (j *Module) installable() bool {
return j.properties.Installable == nil || *j.properties.Installable
}
diff --git a/java/java_test.go b/java/java_test.go
index e1c90ee..dbecc70 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -51,12 +51,14 @@
os.Exit(run())
}
-func testJava(t *testing.T, bp string) *android.TestContext {
- return testJavaWithEnv(t, bp, nil)
+
+func testConfig(env map[string]string) android.Config {
+ return android.TestArchConfig(buildDir, env)
+
}
-func testJavaWithEnv(t *testing.T, bp string, env map[string]string) *android.TestContext {
- config := android.TestArchConfig(buildDir, env)
+func testContext(config android.Config, bp string,
+ fs map[string][]byte) *android.TestContext {
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("android_app", android.ModuleFactoryAdaptor(AndroidAppFactory))
@@ -70,6 +72,7 @@
ctx.PreArchMutators(android.RegisterPrebuiltsPreArchMutators)
ctx.PreArchMutators(android.RegisterPrebuiltsPostDepsMutators)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
ctx.Register()
extraModules := []string{
@@ -95,34 +98,39 @@
`, extra)
}
- if config.TargetOpenJDK9() {
- systemModules := []string{
- "core-system-modules",
- "android_stubs_current_system_modules",
- "android_system_stubs_current_system_modules",
- "android_test_stubs_current_system_modules",
+ bp += `
+ android_app {
+ name: "framework-res",
+ no_framework_libs: true,
}
+ `
- for _, extra := range systemModules {
- bp += fmt.Sprintf(`
+ systemModules := []string{
+ "core-system-modules",
+ "android_stubs_current_system_modules",
+ "android_system_stubs_current_system_modules",
+ "android_test_stubs_current_system_modules",
+ }
+
+ for _, extra := range systemModules {
+ bp += fmt.Sprintf(`
java_system_modules {
name: "%s",
}
`, extra)
- }
}
- ctx.MockFileSystem(map[string][]byte{
- "Android.bp": []byte(bp),
- "a.java": nil,
- "b.java": nil,
- "c.java": nil,
- "b.kt": nil,
- "a.jar": nil,
- "b.jar": nil,
- "res/a": nil,
- "res/b": nil,
- "res2/a": nil,
+ mockFS := map[string][]byte{
+ "Android.bp": []byte(bp),
+ "a.java": nil,
+ "b.java": nil,
+ "c.java": nil,
+ "b.kt": nil,
+ "a.jar": nil,
+ "b.jar": nil,
+ "java-res/a": nil,
+ "java-res/b": nil,
+ "java-res2/a": nil,
"prebuilts/sdk/14/android.jar": nil,
"prebuilts/sdk/14/framework.aidl": nil,
@@ -130,14 +138,36 @@
"prebuilts/sdk/current/framework.aidl": nil,
"prebuilts/sdk/system_current/android.jar": nil,
"prebuilts/sdk/system_current/framework.aidl": nil,
+ "prebuilts/sdk/system_14/android.jar": nil,
+ "prebuilts/sdk/system_14/framework.aidl": nil,
"prebuilts/sdk/test_current/android.jar": nil,
"prebuilts/sdk/test_current/framework.aidl": nil,
- })
+ // For framework-res, which is an implicit dependency for framework
+ "AndroidManifest.xml": nil,
+ "build/target/product/security/testkey": nil,
+ }
+
+ for k, v := range fs {
+ mockFS[k] = v
+ }
+
+ ctx.MockFileSystem(mockFS)
+
+ return ctx
+}
+
+func run(t *testing.T, ctx *android.TestContext, config android.Config) {
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
fail(t, errs)
_, errs = ctx.PrepareBuildActions(config)
fail(t, errs)
+}
+
+func testJava(t *testing.T, bp string) *android.TestContext {
+ config := testConfig(nil)
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
return ctx
}
@@ -267,6 +297,14 @@
},
{
+ name: "system_14",
+ properties: `sdk_version: "system_14",`,
+ bootclasspath: []string{`""`},
+ system: "bootclasspath", // special value to tell 1.9 test to expect bootclasspath
+ classpath: []string{"prebuilts/sdk/system_14/android.jar"},
+ },
+ {
+
name: "test_current",
properties: `sdk_version: "test_current",`,
bootclasspath: []string{`""`},
@@ -394,7 +432,9 @@
// Test again with javac 1.9
t.Run("1.9", func(t *testing.T) {
- ctx := testJavaWithEnv(t, bp, map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ config := testConfig(map[string]string{"EXPERIMENTAL_USE_OPENJDK9": "true"})
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
javac := ctx.ModuleForTests("foo", variant).Rule("javac")
got := javac.Args["bootClasspath"]
@@ -497,14 +537,14 @@
{
// Test that a module with java_resource_dirs includes the files
name: "resource dirs",
- prop: `java_resource_dirs: ["res"]`,
- args: "-C res -f res/a -f res/b",
+ prop: `java_resource_dirs: ["java-res"]`,
+ args: "-C java-res -f java-res/a -f java-res/b",
},
{
// Test that a module with java_resources includes the files
name: "resource files",
- prop: `java_resources: ["res/a", "res/b"]`,
- args: "-C . -f res/a -f res/b",
+ prop: `java_resources: ["java-res/a", "java-res/b"]`,
+ args: "-C . -f java-res/a -f java-res/b",
},
{
// Test that a module with a filegroup in java_resources includes the files with the
@@ -514,10 +554,10 @@
extra: `
filegroup {
name: "foo-res",
- path: "res",
- srcs: ["res/a", "res/b"],
+ path: "java-res",
+ srcs: ["java-res/a", "java-res/b"],
}`,
- args: "-C res -f res/a -f res/b",
+ args: "-C java-res -f java-res/a -f java-res/b",
},
{
// Test that a module with "include_srcs: true" includes its source files in the resources jar
@@ -562,21 +602,21 @@
java_library {
name: "foo",
srcs: ["a.java"],
- java_resource_dirs: ["res", "res2"],
- exclude_java_resource_dirs: ["res2"],
+ java_resource_dirs: ["java-res", "java-res2"],
+ exclude_java_resource_dirs: ["java-res2"],
}
java_library {
name: "bar",
srcs: ["a.java"],
- java_resources: ["res/*"],
- exclude_java_resources: ["res/b"],
+ java_resources: ["java-res/*"],
+ exclude_java_resources: ["java-res/b"],
}
`)
fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
- expected := "-C res -f res/a -f res/b"
+ expected := "-C java-res -f java-res/a -f java-res/b"
if fooRes.Args["jarArgs"] != expected {
t.Errorf("foo resource jar args %q is not %q",
fooRes.Args["jarArgs"], expected)
@@ -585,7 +625,7 @@
barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar")
- expected = "-C . -f res/a"
+ expected = "-C . -f java-res/a"
if barRes.Args["jarArgs"] != expected {
t.Errorf("bar resource jar args %q is not %q",
barRes.Args["jarArgs"], expected)
@@ -606,7 +646,7 @@
genrule {
name: "gen",
- tool_files: ["res/a"],
+ tool_files: ["java-res/a"],
out: ["gen.java"],
}
`)
diff --git a/java/system_modules.go b/java/system_modules.go
index c3e40ca..5234d17 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -121,7 +121,7 @@
jars = append(jars, android.PathsForModuleSrc(ctx, system.properties.Jars)...)
- if ctx.AConfig().TargetOpenJDK9() {
+ if ctx.Config().TargetOpenJDK9() {
system.outputFile = TransformJarsToSystemModules(ctx, "java.base", jars)
}
}
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index d1b4943..5809894 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -36,6 +36,7 @@
"proc_sync.go",
"signal.go",
"soong.go",
+ "test_build.go",
"util.go",
],
testSrcs: [
diff --git a/ui/build/build.go b/ui/build/build.go
index 0df22b3..78eb6a3 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -68,6 +68,7 @@
BuildSoong = 1 << iota
BuildKati = 1 << iota
BuildNinja = 1 << iota
+ RunBuildTests = 1 << iota
BuildAll = BuildProductConfig | BuildSoong | BuildKati | BuildNinja
)
@@ -172,14 +173,18 @@
}
}
+ // Write combined ninja file
+ createCombinedBuildNinjaFile(ctx, config)
+
+ if what&RunBuildTests != 0 {
+ testForDanglingRules(ctx, config)
+ }
+
if what&BuildNinja != 0 {
if !config.SkipMake() {
installCleanIfNecessary(ctx, config)
}
- // Write combined ninja file
- createCombinedBuildNinjaFile(ctx, config)
-
// Run ninja
runNinja(ctx, config)
}
diff --git a/ui/build/config.go b/ui/build/config.go
index 6e5559d..df97d80 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -34,11 +34,12 @@
environ *Environment
// From the arguments
- parallel int
- keepGoing int
- verbose bool
- dist bool
- skipMake bool
+ parallel int
+ keepGoing int
+ verbose bool
+ checkbuild bool
+ dist bool
+ skipMake bool
// From the product config
katiArgs []string
@@ -206,6 +207,8 @@
} else {
if arg == "dist" {
c.dist = true
+ } else if arg == "checkbuild" {
+ c.checkbuild = true
}
c.arguments = append(c.arguments, arg)
}
@@ -313,6 +316,12 @@
panic("SetKatiSuffix has not been called")
}
+// Checkbuild returns true if "checkbuild" was one of the build goals, which means that the
+// user is interested in additional checks at the expense of build time.
+func (c *configImpl) Checkbuild() bool {
+ return c.checkbuild
+}
+
func (c *configImpl) Dist() bool {
return c.dist
}
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 05dec3a..010b325 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -43,7 +43,7 @@
RootDirs: []string{"."},
ExcludeDirs: []string{".git", ".repo"},
PruneFiles: []string{".out-dir", ".find-ignore"},
- IncludeFiles: []string{"Android.mk", "Android.bp", "Blueprints", "CleanSpec.mk"},
+ IncludeFiles: []string{"Android.mk", "Android.bp", "Blueprints", "CleanSpec.mk", "TEST_MAPPING"},
}
dumpDir := config.FileListDir()
f, err = finder.New(cacheParams, fs.OsFs, logger.New(ioutil.Discard),
@@ -74,6 +74,12 @@
ctx.Fatalf("Could not export module list: %v", err)
}
+ testMappings := f.FindNamedAt(".", "TEST_MAPPING")
+ err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
+ if err != nil {
+ ctx.Fatalf("Could not find modules: %v", err)
+ }
+
isBlueprintFile := func(dir finder.DirEntries) (dirs []string, files []string) {
files = []string{}
for _, file := range dir.FileNames {
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
new file mode 100644
index 0000000..940f0c8
--- /dev/null
+++ b/ui/build/test_build.go
@@ -0,0 +1,85 @@
+// Copyright 2017 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 build
+
+import (
+ "bufio"
+ "path/filepath"
+ "runtime"
+ "strings"
+)
+
+// Checks for files in the out directory that have a rule that depends on them but no rule to
+// create them. This catches a common set of build failures where a rule to generate a file is
+// deleted (either by deleting a module in an Android.mk file, or by modifying the build system
+// incorrectly). These failures are often not caught by a local incremental build because the
+// previously built files are still present in the output directory.
+func testForDanglingRules(ctx Context, config Config) {
+ // Many modules are disabled on mac. Checking for dangling rules would cause lots of build
+ // breakages, and presubmit wouldn't catch them, so just disable the check.
+ if runtime.GOOS != "linux" {
+ return
+ }
+
+ ctx.BeginTrace("test for dangling rules")
+ defer ctx.EndTrace()
+
+ // Get a list of leaf nodes in the dependency graph from ninja
+ executable := config.PrebuiltBuildTool("ninja")
+
+ args := []string{}
+ args = append(args, config.NinjaArgs()...)
+ args = append(args, "-f", config.CombinedNinjaFile())
+ args = append(args, "-t", "targets", "rule")
+
+ cmd := Command(ctx, config, "ninja", executable, args...)
+ stdout, err := cmd.StdoutPipe()
+ if err != nil {
+ ctx.Fatal(err)
+ }
+
+ cmd.StartOrFatal()
+
+ outDir := config.OutDir()
+ bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
+ miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
+
+ var danglingRules []string
+
+ scanner := bufio.NewScanner(stdout)
+ for scanner.Scan() {
+ line := scanner.Text()
+ if !strings.HasPrefix(line, outDir) {
+ // Leaf node is not in the out directory.
+ continue
+ }
+ if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
+ // Leaf node is in one of Soong's bootstrap directories, which do not have
+ // full build rules in the primary build.ninja file.
+ continue
+ }
+ danglingRules = append(danglingRules, line)
+ }
+
+ cmd.WaitOrFatal()
+
+ if len(danglingRules) > 0 {
+ ctx.Println("Dependencies in out found with no rule to create them:")
+ for _, dep := range danglingRules {
+ ctx.Println(dep)
+ }
+ ctx.Fatal("")
+ }
+}