aboutsummaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2015-07-08 18:13:11 -0700
committerColin Cross <ccross@android.com>2015-12-01 15:08:01 -0800
commit218f65628efe3d15fe788eeaf2bf7a639daeb0ca (patch)
tree60d962e024387e57930b21fa0cb9ef9a9d5c61e4 /common
parent979422c6c2d85b8048b0a9a478b1ee0d6a54eeed (diff)
downloadbuild_soong-218f65628efe3d15fe788eeaf2bf7a639daeb0ca.tar.gz
build_soong-218f65628efe3d15fe788eeaf2bf7a639daeb0ca.tar.bz2
build_soong-218f65628efe3d15fe788eeaf2bf7a639daeb0ca.zip
Hybrid soong/mk build using prebuilts
Change-Id: I96daa69af27bd19c8bfbe327a1318f51c738fc03
Diffstat (limited to 'common')
-rw-r--r--common/androidmk.go268
-rw-r--r--common/arch.go10
-rw-r--r--common/config.go19
-rw-r--r--common/module.go27
4 files changed, 300 insertions, 24 deletions
diff --git a/common/androidmk.go b/common/androidmk.go
new file mode 100644
index 00000000..d3089368
--- /dev/null
+++ b/common/androidmk.go
@@ -0,0 +1,268 @@
+// Copyright 2015 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package common
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+
+ "android/soong"
+
+ "github.com/google/blueprint"
+)
+
+func init() {
+ soong.RegisterSingletonType("androidmk", AndroidMkSingleton)
+}
+
+type AndroidMkDataProvider interface {
+ AndroidMk() AndroidMkData
+}
+
+type AndroidMkData struct {
+ Class string
+ OutputFile string
+
+ Custom func(w io.Writer, name, prefix string)
+
+ Extra func(name, prefix, outputFile string, arch Arch) []string
+}
+
+func AndroidMkSingleton() blueprint.Singleton {
+ return &androidMkSingleton{}
+}
+
+type androidMkSingleton struct{}
+
+func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
+ fileModules := make(map[string][]blueprint.Module)
+ hasBPFile := make(map[string]bool)
+ bpFiles := []string{}
+
+ ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).BuildDir(), ".."))
+
+ ctx.VisitAllModules(func(module blueprint.Module) {
+ if _, ok := module.(AndroidModule); ok {
+ bpFile := ctx.BlueprintFile(module)
+
+ if !hasBPFile[bpFile] {
+ hasBPFile[bpFile] = true
+ bpFiles = append(bpFiles, bpFile)
+ }
+
+ fileModules[bpFile] = append(fileModules[bpFile], module)
+ }
+ })
+
+ // Gather list of eligible Android modules for translation
+ androidMkModules := make(map[blueprint.Module]bool)
+ var validBpFiles []string
+ srcDir := ctx.Config().(Config).SrcDir()
+ intermediatesDir := filepath.Join(ctx.Config().(Config).IntermediatesDir(), "androidmk")
+ sort.Strings(bpFiles)
+ for _, origBp := range bpFiles {
+ mkFile := filepath.Join(srcDir, filepath.Dir(origBp), "Android.mk")
+
+ files, err := Glob(ctx, intermediatesDir, mkFile, nil)
+ if err != nil {
+ ctx.Errorf("glob: %s", err.Error())
+ continue
+ }
+
+ // Existing Android.mk file, use that instead
+ if len(files) > 0 {
+ for _, file := range files {
+ ctx.AddNinjaFileDeps(file)
+ }
+ continue
+ }
+
+ validBpFiles = append(validBpFiles, origBp)
+
+ for _, mod := range fileModules[origBp] {
+ androidMkModules[mod] = true
+ }
+ }
+
+ // Validate that all modules have proper dependencies
+ androidMkModulesList := make([]AndroidModule, 0, len(androidMkModules))
+ for mod := range androidMkModules {
+ ctx.VisitDepsDepthFirstIf(mod, isAndroidModule, func(module blueprint.Module) {
+ if !androidMkModules[module] {
+ ctx.Errorf("Module %q missing dependency for Android.mk: %q", ctx.ModuleName(mod), ctx.ModuleName(module))
+ }
+ })
+ if amod, ok := mod.(AndroidModule); ok {
+ androidMkModulesList = append(androidMkModulesList, amod)
+ }
+ }
+
+ transMk := filepath.Join(ctx.Config().(Config).BuildDir(), "Android.mk")
+
+ err := translateAndroidMk(ctx, transMk, androidMkModulesList)
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+
+ ctx.Build(pctx, blueprint.BuildParams{
+ Rule: blueprint.Phony,
+ Outputs: []string{transMk},
+ Optional: true,
+ })
+}
+
+func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error {
+ buf := &bytes.Buffer{}
+
+ io.WriteString(buf, "LOCAL_PATH := $(TOP)\n")
+ io.WriteString(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))\n")
+
+ for _, mod := range mods {
+ err := translateAndroidMkModule(ctx, buf, mod)
+ if err != nil {
+ os.Remove(mkFile)
+ return err
+ }
+ }
+
+ // Don't write to the file if it hasn't changed
+ if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
+ if data, err := ioutil.ReadFile(mkFile); err == nil {
+ matches := buf.Len() == len(data)
+
+ if matches {
+ for i, value := range buf.Bytes() {
+ if value != data[i] {
+ matches = false
+ break
+ }
+ }
+ }
+
+ if matches {
+ return nil
+ }
+ }
+ }
+
+ return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
+}
+
+func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
+ if mod != ctx.PrimaryModule(mod) {
+ // These will be handled by the primary module
+ return nil
+ }
+
+ name := ctx.ModuleName(mod)
+
+ type hostClass struct {
+ host bool
+ class string
+ multilib string
+ }
+
+ type archSrc struct {
+ arch Arch
+ src string
+ extra []string
+ }
+
+ srcs := make(map[hostClass][]archSrc)
+ var modules []hostClass
+
+ ctx.VisitAllModuleVariants(mod, func(m blueprint.Module) {
+ provider, ok := m.(AndroidMkDataProvider)
+ if !ok {
+ return
+ }
+
+ amod := m.(AndroidModule).base()
+ data := provider.AndroidMk()
+
+ arch := amod.commonProperties.CompileArch
+
+ prefix := ""
+ if amod.HostOrDevice() == Host {
+ if arch.ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType {
+ prefix = "2ND_"
+ }
+ } else {
+ if arch.ArchType != ctx.Config().(Config).DeviceArches[0].ArchType {
+ prefix = "2ND_"
+ }
+ }
+
+ if data.Custom != nil {
+ data.Custom(w, name, prefix)
+ return
+ }
+
+ hC := hostClass{
+ host: amod.HostOrDevice() == Host,
+ class: data.Class,
+ multilib: amod.commonProperties.Compile_multilib,
+ }
+
+ src := archSrc{
+ arch: arch,
+ src: data.OutputFile,
+ }
+
+ if data.Extra != nil {
+ src.extra = data.Extra(name, prefix, src.src, arch)
+ }
+
+ if srcs[hC] == nil {
+ modules = append(modules, hC)
+ }
+ srcs[hC] = append(srcs[hC], src)
+ })
+
+ for _, hC := range modules {
+ archSrcs := srcs[hC]
+
+ io.WriteString(w, "\ninclude $(CLEAR_VARS)\n")
+ io.WriteString(w, "LOCAL_MODULE := "+name+"\n")
+ io.WriteString(w, "LOCAL_MODULE_CLASS := "+hC.class+"\n")
+ io.WriteString(w, "LOCAL_MULTILIB := "+hC.multilib+"\n")
+
+ printed := make(map[string]bool)
+ for _, src := range archSrcs {
+ io.WriteString(w, "LOCAL_SRC_FILES_"+src.arch.ArchType.String()+" := "+src.src+"\n")
+
+ for _, extra := range src.extra {
+ if !printed[extra] {
+ printed[extra] = true
+ io.WriteString(w, extra+"\n")
+ }
+ }
+ }
+
+ if hC.host {
+ // TODO: this isn't true for every module
+ io.WriteString(w, "LOCAL_ACP_UNAVAILABLE := true\n")
+
+ io.WriteString(w, "LOCAL_IS_HOST_MODULE := true\n")
+ }
+ io.WriteString(w, "include $(BUILD_PREBUILT)\n")
+ }
+
+ return nil
+}
diff --git a/common/arch.go b/common/arch.go
index 4cddc00e..37f7c38e 100644
--- a/common/arch.go
+++ b/common/arch.go
@@ -335,6 +335,7 @@ const (
HostSupported
DeviceSupported
HostAndDeviceSupported
+ HostAndDeviceDefault
)
type HostOrDevice int
@@ -505,16 +506,11 @@ func ArchMutator(mctx AndroidBottomUpMutatorContext) {
return
}
- hostArches, deviceArches, err := decodeArchProductVariables(mctx.Config().(Config).ProductVariables)
- if err != nil {
- mctx.ModuleErrorf("%s", err.Error())
- }
-
moduleArches := []Arch{}
multilib := module.base().commonProperties.Compile_multilib
if module.base().HostSupported() && module.base().HostOrDevice().Host() {
- hostModuleArches, err := decodeMultilib(multilib, hostArches[module.base().HostType()])
+ hostModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).HostArches[module.base().HostType()])
if err != nil {
mctx.ModuleErrorf("%s", err.Error())
}
@@ -523,7 +519,7 @@ func ArchMutator(mctx AndroidBottomUpMutatorContext) {
}
if module.base().DeviceSupported() && module.base().HostOrDevice().Device() {
- deviceModuleArches, err := decodeMultilib(multilib, deviceArches)
+ deviceModuleArches, err := decodeMultilib(multilib, mctx.Config().(Config).DeviceArches)
if err != nil {
mctx.ModuleErrorf("%s", err.Error())
}
diff --git a/common/config.go b/common/config.go
index fbd2be9e..c67023e3 100644
--- a/common/config.go
+++ b/common/config.go
@@ -38,9 +38,11 @@ func (f *FileConfigurableOptions) SetDefaultConfig() {
type Config struct {
*config
+
+ dontCreateNinjaFile bool
}
-// A config object represents the entire build configuration for Blue.
+// A config object represents the entire build configuration for Android.
type config struct {
FileConfigurableOptions
ProductVariables productVariables
@@ -48,6 +50,9 @@ type config struct {
ConfigFileName string
ProductVariablesFileName string
+ DeviceArches []Arch
+ HostArches map[HostType][]Arch
+
srcDir string // the path of the root source directory
buildDir string // the path of the build output directory
@@ -143,6 +148,14 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
return Config{}, err
}
+ hostArches, deviceArches, err := decodeArchProductVariables(config.ProductVariables)
+ if err != nil {
+ return Config{}, err
+ }
+
+ config.HostArches = hostArches
+ config.DeviceArches = deviceArches
+
return config, nil
}
@@ -158,6 +171,10 @@ func (c *config) IntermediatesDir() string {
return filepath.Join(c.BuildDir(), ".intermediates")
}
+func (c *config) RemoveAbandonedFiles() bool {
+ return false
+}
+
// PrebuiltOS returns the name of the host OS used in prebuilts directories
func (c *config) PrebuiltOS() string {
switch runtime.GOOS {
diff --git a/common/module.go b/common/module.go
index 1683671d..113768a7 100644
--- a/common/module.go
+++ b/common/module.go
@@ -105,9 +105,10 @@ type hostAndDeviceProperties struct {
type Multilib string
const (
- MultilibBoth Multilib = "both"
- MultilibFirst Multilib = "first"
- MultilibCommon Multilib = "common"
+ MultilibBoth Multilib = "both"
+ MultilibFirst Multilib = "first"
+ MultilibCommon Multilib = "common"
+ MultilibDefault Multilib = ""
)
func InitAndroidModule(m AndroidModule,
@@ -130,10 +131,13 @@ func InitAndroidArchModule(m AndroidModule, hod HostOrDeviceSupported, defaultMu
base.commonProperties.HostOrDeviceSupported = hod
base.commonProperties.Compile_multilib = string(defaultMultilib)
- if hod == HostAndDeviceSupported {
+ switch hod {
+ case HostAndDeviceSupported:
// Default to module to device supported, host not supported, can override in module
// properties
base.hostAndDeviceProperties.Device_supported = true
+ fallthrough
+ case HostAndDeviceDefault:
propertyStructs = append(propertyStructs, &base.hostAndDeviceProperties)
}
@@ -312,7 +316,7 @@ func (a *AndroidModuleBase) generateModuleTarget(ctx blueprint.ModuleContext) {
if len(deps) > 0 {
ctx.Build(pctx, blueprint.BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{ctx.ModuleName()},
+ Outputs: []string{ctx.ModuleName() + "-soong"},
Implicits: deps,
Optional: true,
})
@@ -525,15 +529,12 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx blueprint.SingletonConte
checkbuildDeps := []string{}
dirModules := make(map[string][]string)
- hasBPFile := make(map[string]bool)
- bpFiles := []string{}
ctx.VisitAllModules(func(module blueprint.Module) {
if a, ok := module.(AndroidModule); ok {
blueprintDir := a.base().blueprintDir
installTarget := a.base().installTarget
checkbuildTarget := a.base().checkbuildTarget
- bpFile := ctx.BlueprintFile(module)
if checkbuildTarget != "" {
checkbuildDeps = append(checkbuildDeps, checkbuildTarget)
@@ -543,21 +544,15 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx blueprint.SingletonConte
if installTarget != "" {
dirModules[blueprintDir] = append(dirModules[blueprintDir], installTarget)
}
-
- if !hasBPFile[bpFile] {
- hasBPFile[bpFile] = true
- bpFiles = append(bpFiles, bpFile)
- }
}
})
// Create a top-level checkbuild target that depends on all modules
ctx.Build(pctx, blueprint.BuildParams{
Rule: blueprint.Phony,
- Outputs: []string{"checkbuild"},
+ Outputs: []string{"checkbuild-soong"},
Implicits: checkbuildDeps,
- // HACK: checkbuild should be an optional build, but force it enabled for now
- //Optional: true,
+ Optional: true,
})
// Create a mm/<directory> target that depends on all modules in a directory