// 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" "fmt" "io" "io/ioutil" "os" "path/filepath" "sort" "android/soong" "github.com/google/blueprint" ) func init() { soong.RegisterSingletonType("androidmk", AndroidMkSingleton) } type AndroidMkDataProvider interface { AndroidMk() (AndroidMkData, error) } type AndroidMkData struct { Class string SubName string OutputFile OptionalPath Disabled bool Custom func(w io.Writer, name, prefix string) error Extra []func(w io.Writer, outputFile Path) error } func AndroidMkSingleton() blueprint.Singleton { return &androidMkSingleton{} } type androidMkSingleton struct{} func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) { if !ctx.Config().(Config).EmbeddedInMake() { return } ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, "..")) var androidMkModulesList []AndroidModule ctx.VisitAllModules(func(module blueprint.Module) { if amod, ok := module.(AndroidModule); ok { androidMkModulesList = append(androidMkModulesList, amod) } }) sort.Sort(AndroidModulesByName{androidMkModulesList, ctx}) transMk := PathForOutput(ctx, "Android.mk") if ctx.Failed() { return } err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) if err != nil { ctx.Errorf(err.Error()) } ctx.Build(pctx, blueprint.BuildParams{ Rule: blueprint.Phony, Outputs: []string{transMk.String()}, Optional: true, }) } func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error { buf := &bytes.Buffer{} fmt.Fprintln(buf, "LOCAL_PATH := $(TOP)") fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 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 { name := ctx.ModuleName(mod) provider, ok := mod.(AndroidMkDataProvider) if !ok { return nil } amod := mod.(AndroidModule).base() data, err := provider.AndroidMk() if err != nil { return err } if !amod.Enabled() { return err } if data.SubName != "" { name += "_" + data.SubName } hostCross := false if amod.Host() && amod.HostType() != CurrentHostType() { hostCross = true } if data.Custom != nil { prefix := "" if amod.Host() { if hostCross { prefix = "HOST_CROSS_" } else { prefix = "HOST_" } if amod.Arch().ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType { prefix = "2ND_" + prefix } } else { prefix = "TARGET_" if amod.Arch().ArchType != ctx.Config().(Config).DeviceArches[0].ArchType { prefix = "2ND_" + prefix } } return data.Custom(w, name, prefix) } if data.Disabled { return nil } if !data.OutputFile.Valid() { return err } fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)") fmt.Fprintln(w, "LOCAL_MODULE :=", name) fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", data.Class) fmt.Fprintln(w, "LOCAL_MULTILIB :=", amod.commonProperties.Compile_multilib) fmt.Fprintln(w, "LOCAL_SRC_FILES :=", data.OutputFile.String()) archStr := amod.Arch().ArchType.String() if amod.Host() { if hostCross { fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) } else { fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr) } fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", amod.HostType().String()) fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") } else { fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) } for _, extra := range data.Extra { err = extra(w, data.OutputFile.Path()) if err != nil { return err } } fmt.Fprintln(w, "include $(BUILD_PREBUILT)") return err }