Initial prebuilt support am: ce75d2c6a2

am: 2d9267aa6c

Change-Id: Ibbd81201441f7ada699ec3522d7020b95bf49a3e
This commit is contained in:
Colin Cross 2016-10-13 23:33:17 +00:00 committed by android-build-merger
commit 6e240412aa
11 changed files with 469 additions and 21 deletions

View File

@ -72,6 +72,7 @@ bootstrap_go_package {
"android/onceper.go",
"android/package_ctx.go",
"android/paths.go",
"android/prebuilt.go",
"android/register.go",
"android/util.go",
"android/variable.go",
@ -81,6 +82,7 @@ bootstrap_go_package {
],
testSrcs: [
"android/paths_test.go",
"android/prebuilt_test.go",
],
}
@ -126,6 +128,7 @@ bootstrap_go_package {
"cc/check.go",
"cc/gen.go",
"cc/makevars.go",
"cc/prebuilt.go",
"cc/relocation_packer.go",
"cc/sanitize.go",
"cc/stl.go",

View File

@ -34,6 +34,7 @@ func init() {
type AndroidMkDataProvider interface {
AndroidMk() (AndroidMkData, error)
BaseModuleName() string
}
type AndroidMkData struct {
@ -142,13 +143,12 @@ func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []Mo
}
func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
name := ctx.ModuleName(mod)
provider, ok := mod.(AndroidMkDataProvider)
if !ok {
return nil
}
name := provider.BaseModuleName()
amod := mod.(Module).base()
data, err := provider.AndroidMk()
if err != nil {
@ -156,7 +156,11 @@ func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod b
}
if !amod.Enabled() {
return err
return nil
}
if amod.commonProperties.SkipInstall {
return nil
}
if data.SubName != "" {

View File

@ -151,6 +151,11 @@ func saveToConfigFile(config jsonConfigurable, filename string) error {
return nil
}
// TestConfig returns a Config object suitable for using for tests
func TestConfig() Config {
return Config{&config{}}
}
// New creates a new Config object. The srcDir argument specifies the path to
// the root source directory. It also loads the config file, if found.
func NewConfig(srcDir, buildDir string) (Config, error) {

View File

@ -147,6 +147,8 @@ type commonProperties struct {
// Set by InitAndroidModule
HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
ArchSpecific bool `blueprint:"mutated"`
SkipInstall bool `blueprint:"mutated"`
}
type hostAndDeviceProperties struct {
@ -277,10 +279,17 @@ type ModuleBase struct {
hooks hooks
}
// Name returns the name of the module. It may be overridden by individual module types, for
// example prebuilts will prepend prebuilt_ to the name.
func (a *ModuleBase) Name() string {
return a.nameProperties.Name
}
// BaseModuleName returns the name of the module as specified in the blueprints file.
func (a *ModuleBase) BaseModuleName() string {
return a.nameProperties.Name
}
func (a *ModuleBase) base() *ModuleBase {
return a
}
@ -348,6 +357,10 @@ func (a *ModuleBase) Enabled() bool {
return *a.commonProperties.Enabled
}
func (a *ModuleBase) SkipInstall() {
a.commonProperties.SkipInstall = true
}
func (a *ModuleBase) computeInstallDeps(
ctx blueprint.ModuleContext) Paths {
@ -600,7 +613,9 @@ func (a *androidModuleContext) InstallFileName(installPath OutputPath, name stri
fullInstallPath := installPath.Join(a, name)
a.module.base().hooks.runInstallHooks(a, fullInstallPath, false)
if a.Host() || !a.AConfig().SkipDeviceInstall() {
if !a.module.base().commonProperties.SkipInstall &&
(a.Host() || !a.AConfig().SkipDeviceInstall()) {
deps = append(deps, a.installDeps...)
var implicitDeps, orderOnlyDeps Paths
@ -636,7 +651,9 @@ func (a *androidModuleContext) InstallSymlink(installPath OutputPath, name strin
fullInstallPath := installPath.Join(a, name)
a.module.base().hooks.runInstallHooks(a, fullInstallPath, true)
if a.Host() || !a.AConfig().SkipDeviceInstall() {
if !a.module.base().commonProperties.SkipInstall &&
(a.Host() || !a.AConfig().SkipDeviceInstall()) {
a.ModuleBuild(pctx, ModuleBuildParams{
Rule: Symlink,
Output: fullInstallPath,

View File

@ -33,6 +33,7 @@ func registerMutators() {
}
ctx.TopDown("load_hooks", loadHookMutator).Parallel()
ctx.BottomUp("prebuilts", prebuiltMutator).Parallel()
ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
ctx.TopDown("defaults", defaultsMutator).Parallel()
@ -45,6 +46,9 @@ func registerMutators() {
ctx.BottomUp("deps", depsMutator).Parallel()
ctx.BottomUp("prebuilt_replace", PrebuiltReplaceMutator).Parallel()
ctx.TopDown("prebuilt_disable", PrebuiltDisableMutator).Parallel()
register(postDeps)
}

121
android/prebuilt.go Normal file
View File

@ -0,0 +1,121 @@
// Copyright 2016 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"
// This file implements common functionality for handling modules that may exist as prebuilts,
// source, or both.
var prebuiltDependencyTag blueprint.BaseDependencyTag
func SourceModuleHasPrebuilt(ctx ModuleContext) OptionalPath {
var path Path
ctx.VisitDirectDeps(func(m blueprint.Module) {
if ctx.OtherModuleDependencyTag(m) == prebuiltDependencyTag {
p := m.(PrebuiltInterface).Prebuilt()
if p.usePrebuilt(ctx) {
path = p.Path(ctx)
}
}
})
return OptionalPathForPath(path)
}
type Prebuilt struct {
Properties struct {
Srcs []string `android:"arch_variant"`
// When prefer is set to true the prebuilt will be used instead of any source module with
// a matching name.
Prefer bool `android:"arch_variant"`
SourceExists bool `blueprint:"mutated"`
}
module Module
}
func (p *Prebuilt) Name(name string) string {
return "prebuilt_" + name
}
func (p *Prebuilt) Path(ctx ModuleContext) Path {
if len(p.Properties.Srcs) == 0 {
ctx.PropertyErrorf("srcs", "missing prebuilt source file")
return nil
}
if len(p.Properties.Srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
return nil
}
return PathForModuleSrc(ctx, p.Properties.Srcs[0])
}
type PrebuiltInterface interface {
Module
Prebuilt() *Prebuilt
}
type PrebuiltSourceInterface interface {
SkipInstall()
}
// prebuiltMutator ensures that there is always a module with an undecorated name, and marks
// prebuilt modules that have both a prebuilt and a source module.
func prebuiltMutator(ctx BottomUpMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt()
name := m.base().BaseModuleName()
if ctx.OtherModuleExists(name) {
ctx.AddReverseDependency(ctx.Module(), prebuiltDependencyTag, name)
p.Properties.SourceExists = true
} else {
ctx.Rename(name)
}
}
}
// PrebuiltReplaceMutator replaces dependencies on the source module with dependencies on the prebuilt
// when both modules exist and the prebuilt should be used.
func PrebuiltReplaceMutator(ctx BottomUpMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt()
name := m.base().BaseModuleName()
if p.Properties.SourceExists && p.usePrebuilt(ctx) {
ctx.ReplaceDependencies(name)
}
}
}
// PrebuiltDisableMutator disables source modules that have prebuilts that should be used instead.
func PrebuiltDisableMutator(ctx TopDownMutatorContext) {
if s, ok := ctx.Module().(PrebuiltSourceInterface); ok {
ctx.VisitDirectDeps(func(m blueprint.Module) {
if ctx.OtherModuleDependencyTag(m) == prebuiltDependencyTag {
p := m.(PrebuiltInterface).Prebuilt()
if p.usePrebuilt(ctx) {
s.SkipInstall()
}
}
})
}
}
func (p *Prebuilt) usePrebuilt(ctx BaseContext) bool {
// TODO: use p.Properties.Name and ctx.ModuleDir to override prefer
return p.Properties.Prefer && len(p.Properties.Srcs) > 0
}

206
android/prebuilt_test.go Normal file
View File

@ -0,0 +1,206 @@
// Copyright 2016 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 (
"testing"
"github.com/google/blueprint"
)
var prebuiltsTests = []struct {
name string
modules string
prebuilt bool
}{
{
name: "no prebuilt",
modules: `
source {
name: "bar",
}`,
prebuilt: false,
},
{
name: "no source prebuilt not preferred",
modules: `
prebuilt {
name: "bar",
prefer: false,
srcs: ["prebuilt"],
}`,
prebuilt: true,
},
{
name: "no source prebuilt preferred",
modules: `
prebuilt {
name: "bar",
prefer: true,
srcs: ["prebuilt"],
}`,
prebuilt: true,
},
{
name: "prebuilt not preferred",
modules: `
source {
name: "bar",
}
prebuilt {
name: "bar",
prefer: false,
srcs: ["prebuilt"],
}`,
prebuilt: false,
},
{
name: "prebuilt preferred",
modules: `
source {
name: "bar",
}
prebuilt {
name: "bar",
prefer: true,
srcs: ["prebuilt"],
}`,
prebuilt: true,
},
}
func TestPrebuilts(t *testing.T) {
for _, test := range prebuiltsTests {
t.Run(test.name, func(t *testing.T) {
ctx := NewContext()
ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
ctx.RegisterModuleType("source", newSourceModule)
ctx.MockFileSystem(map[string][]byte{
"Blueprints": []byte(`
source {
name: "foo",
deps: ["bar"],
}
` + test.modules),
})
config := TestConfig()
_, errs := ctx.ParseBlueprintsFiles("Blueprints")
fail(t, errs)
_, errs = ctx.PrepareBuildActions(config)
fail(t, errs)
foo := findModule(ctx, "foo")
if foo == nil {
t.Fatalf("failed to find module foo")
}
if test.prebuilt {
if !foo.(*sourceModule).dependsOnPrebuiltModule {
t.Errorf("doesn't depend on prebuilt module")
}
if foo.(*sourceModule).dependsOnSourceModule {
t.Errorf("depends on source module")
}
} else {
if foo.(*sourceModule).dependsOnPrebuiltModule {
t.Errorf("depends on prebuilt module")
}
if !foo.(*sourceModule).dependsOnSourceModule {
t.Errorf("doens't depend on source module")
}
}
})
}
}
type prebuiltModule struct {
ModuleBase
prebuilt Prebuilt
}
func newPrebuiltModule() (blueprint.Module, []interface{}) {
m := &prebuiltModule{}
return InitAndroidModule(m, &m.prebuilt.Properties)
}
func (p *prebuiltModule) Name() string {
return p.prebuilt.Name(p.ModuleBase.Name())
}
func (p *prebuiltModule) DepsMutator(ctx BottomUpMutatorContext) {
}
func (p *prebuiltModule) GenerateAndroidBuildActions(ModuleContext) {
}
func (p *prebuiltModule) Prebuilt() *Prebuilt {
return &p.prebuilt
}
type sourceModule struct {
ModuleBase
properties struct {
Deps []string
}
dependsOnSourceModule, dependsOnPrebuiltModule bool
}
func newSourceModule() (blueprint.Module, []interface{}) {
m := &sourceModule{}
return InitAndroidModule(m, &m.properties)
}
func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) {
for _, d := range s.properties.Deps {
ctx.AddDependency(ctx.Module(), nil, d)
}
}
func (s *sourceModule) GenerateAndroidBuildActions(ctx ModuleContext) {
ctx.VisitDirectDeps(func(m blueprint.Module) {
if _, ok := m.(*sourceModule); ok {
s.dependsOnSourceModule = true
}
if _, ok := m.(*prebuiltModule); ok {
s.dependsOnPrebuiltModule = true
}
})
}
func findModule(ctx *blueprint.Context, name string) blueprint.Module {
var ret blueprint.Module
ctx.VisitAllModules(func(m blueprint.Module) {
if ctx.ModuleName(m) == name {
ret = m
}
})
return ret
}
func fail(t *testing.T, errs []error) {
if len(errs) > 0 {
for _, err := range errs {
t.Error(err)
}
t.FailNow()
}
}

View File

@ -81,7 +81,7 @@ func (binary *binaryDecorator) linkerProps() []interface{} {
}
func (binary *binaryDecorator) getStem(ctx BaseModuleContext) string {
stem := ctx.ModuleName()
stem := ctx.baseModuleName()
if binary.Properties.Stem != "" {
stem = binary.Properties.Stem
}
@ -171,7 +171,7 @@ func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) {
}
if ctx.TargetPrimary() {
binary.baseInstaller.Properties.Symlinks = append(binary.baseInstaller.Properties.Symlinks,
ctx.ModuleName())
ctx.baseModuleName())
}
}
}

View File

@ -19,7 +19,6 @@ package cc
// is handled in builder.go
import (
"fmt"
"strconv"
"strings"
@ -146,6 +145,7 @@ type ModuleContextIntf interface {
sdk() bool
sdkVersion() string
selectedStl() string
baseModuleName() string
}
type ModuleContext interface {
@ -354,6 +354,10 @@ func (ctx *moduleContextImpl) selectedStl() string {
return ""
}
func (ctx *moduleContextImpl) baseModuleName() string {
return ctx.mod.ModuleBase.BaseModuleName()
}
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@ -368,6 +372,21 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo
return module
}
func (c *Module) Prebuilt() *android.Prebuilt {
if p, ok := c.linker.(prebuiltLinkerInterface); ok {
return p.prebuilt()
}
return nil
}
func (c *Module) Name() string {
name := c.ModuleBase.Name()
if p, ok := c.linker.(prebuiltLinkerInterface); ok {
name = p.Name(name)
}
return name
}
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
ModuleContext: actx,
@ -434,12 +453,12 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
return
}
c.outputFile = android.OptionalPathForPath(outputFile)
}
if c.installer != nil && !c.Properties.PreventInstall {
c.installer.install(ctx, outputFile)
if ctx.Failed() {
return
}
if c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid() {
c.installer.install(ctx, c.outputFile.Path())
if ctx.Failed() {
return
}
}
}
@ -792,11 +811,6 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return
}
if !cc.outputFile.Valid() {
ctx.ModuleErrorf("module %q missing output file", name)
return
}
if tag == reuseObjTag {
depPaths.ObjFiles = append(depPaths.ObjFiles,
cc.compiler.(libraryInterface).reuseObjs()...)
@ -861,11 +875,13 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
depPaths.CrtBegin = linkFile
case crtEndDepTag:
depPaths.CrtEnd = linkFile
default:
panic(fmt.Errorf("unknown dependency tag: %s", tag))
}
if ptr != nil {
if !linkFile.Valid() {
ctx.ModuleErrorf("module %q missing output file", name)
return
}
*ptr = append(*ptr, linkFile.Path())
}

View File

@ -284,7 +284,7 @@ type libraryInterface interface {
func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
name := library.libName
if name == "" {
name = ctx.ModuleName()
name = ctx.baseModuleName()
}
if ctx.Host() && Bool(library.Properties.Unique_host_soname) {

72
cc/prebuilt.go Normal file
View File

@ -0,0 +1,72 @@
// Copyright 2016 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 cc
import (
"android/soong/android"
"github.com/google/blueprint"
)
func init() {
android.RegisterModuleType("cc_prebuilt_shared_library", prebuiltSharedLibraryFactory)
}
type prebuiltLinkerInterface interface {
Name(string) string
prebuilt() *android.Prebuilt
}
type prebuiltLibraryLinker struct {
*libraryDecorator
android.Prebuilt
}
var _ prebuiltLinkerInterface = (*prebuiltLibraryLinker)(nil)
func (p *prebuiltLibraryLinker) prebuilt() *android.Prebuilt {
return &p.Prebuilt
}
func (p *prebuiltLibraryLinker) linkerProps() []interface{} {
props := p.libraryDecorator.linkerProps()
return append(props, &p.Prebuilt.Properties)
}
func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objFiles android.Paths) android.Path {
// TODO(ccross): verify shared library dependencies
if len(p.Prebuilt.Properties.Srcs) > 0 {
p.libraryDecorator.exportIncludes(ctx, "-I")
p.libraryDecorator.reexportFlags(deps.ReexportedFlags)
p.libraryDecorator.reexportDeps(deps.ReexportedFlagsDeps)
// TODO(ccross): .toc optimization, stripping, packing
return p.Prebuilt.Path(ctx)
}
return nil
}
func prebuiltSharedLibraryFactory() (blueprint.Module, []interface{}) {
module, library := NewLibrary(android.HostAndDeviceSupported, true, false)
module.compiler = nil
prebuilt := &prebuiltLibraryLinker{
libraryDecorator: library,
}
module.linker = prebuilt
return module.Init()
}