Home | History | Annotate | Download | only in common
      1 // Copyright 2015 Google Inc. All rights reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package common
     16 
     17 import (
     18 	"bytes"
     19 	"fmt"
     20 	"io"
     21 	"io/ioutil"
     22 	"os"
     23 	"path/filepath"
     24 	"sort"
     25 
     26 	"android/soong"
     27 
     28 	"github.com/google/blueprint"
     29 )
     30 
     31 func init() {
     32 	soong.RegisterSingletonType("androidmk", AndroidMkSingleton)
     33 }
     34 
     35 type AndroidMkDataProvider interface {
     36 	AndroidMk() (AndroidMkData, error)
     37 }
     38 
     39 type AndroidMkData struct {
     40 	Class      string
     41 	SubName    string
     42 	OutputFile OptionalPath
     43 	Disabled   bool
     44 
     45 	Custom func(w io.Writer, name, prefix string) error
     46 
     47 	Extra []func(w io.Writer, outputFile Path) error
     48 }
     49 
     50 func AndroidMkSingleton() blueprint.Singleton {
     51 	return &androidMkSingleton{}
     52 }
     53 
     54 type androidMkSingleton struct{}
     55 
     56 func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
     57 	if !ctx.Config().(Config).EmbeddedInMake() {
     58 		return
     59 	}
     60 
     61 	ctx.SetNinjaBuildDir(pctx, filepath.Join(ctx.Config().(Config).buildDir, ".."))
     62 
     63 	var androidMkModulesList []AndroidModule
     64 
     65 	ctx.VisitAllModules(func(module blueprint.Module) {
     66 		if amod, ok := module.(AndroidModule); ok {
     67 			androidMkModulesList = append(androidMkModulesList, amod)
     68 		}
     69 	})
     70 
     71 	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
     72 
     73 	transMk := PathForOutput(ctx, "Android.mk")
     74 	if ctx.Failed() {
     75 		return
     76 	}
     77 
     78 	err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
     79 	if err != nil {
     80 		ctx.Errorf(err.Error())
     81 	}
     82 
     83 	ctx.Build(pctx, blueprint.BuildParams{
     84 		Rule:     blueprint.Phony,
     85 		Outputs:  []string{transMk.String()},
     86 		Optional: true,
     87 	})
     88 }
     89 
     90 func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []AndroidModule) error {
     91 	buf := &bytes.Buffer{}
     92 
     93 	fmt.Fprintln(buf, "LOCAL_PATH := $(TOP)")
     94 	fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
     95 
     96 	for _, mod := range mods {
     97 		err := translateAndroidMkModule(ctx, buf, mod)
     98 		if err != nil {
     99 			os.Remove(mkFile)
    100 			return err
    101 		}
    102 	}
    103 
    104 	// Don't write to the file if it hasn't changed
    105 	if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
    106 		if data, err := ioutil.ReadFile(mkFile); err == nil {
    107 			matches := buf.Len() == len(data)
    108 
    109 			if matches {
    110 				for i, value := range buf.Bytes() {
    111 					if value != data[i] {
    112 						matches = false
    113 						break
    114 					}
    115 				}
    116 			}
    117 
    118 			if matches {
    119 				return nil
    120 			}
    121 		}
    122 	}
    123 
    124 	return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
    125 }
    126 
    127 func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
    128 	name := ctx.ModuleName(mod)
    129 
    130 	provider, ok := mod.(AndroidMkDataProvider)
    131 	if !ok {
    132 		return nil
    133 	}
    134 
    135 	amod := mod.(AndroidModule).base()
    136 	data, err := provider.AndroidMk()
    137 	if err != nil {
    138 		return err
    139 	}
    140 
    141 	if !amod.Enabled() {
    142 		return err
    143 	}
    144 
    145 	if data.SubName != "" {
    146 		name += "_" + data.SubName
    147 	}
    148 
    149 	hostCross := false
    150 	if amod.Host() && amod.HostType() != CurrentHostType() {
    151 		hostCross = true
    152 	}
    153 
    154 	if data.Custom != nil {
    155 		prefix := ""
    156 		if amod.Host() {
    157 			if hostCross {
    158 				prefix = "HOST_CROSS_"
    159 			} else {
    160 				prefix = "HOST_"
    161 			}
    162 			if amod.Arch().ArchType != ctx.Config().(Config).HostArches[amod.HostType()][0].ArchType {
    163 				prefix = "2ND_" + prefix
    164 			}
    165 		} else {
    166 			prefix = "TARGET_"
    167 			if amod.Arch().ArchType != ctx.Config().(Config).DeviceArches[0].ArchType {
    168 				prefix = "2ND_" + prefix
    169 			}
    170 		}
    171 
    172 		return data.Custom(w, name, prefix)
    173 	}
    174 
    175 	if data.Disabled {
    176 		return nil
    177 	}
    178 
    179 	if !data.OutputFile.Valid() {
    180 		return err
    181 	}
    182 
    183 	fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
    184 	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
    185 	fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", data.Class)
    186 	fmt.Fprintln(w, "LOCAL_MULTILIB :=", amod.commonProperties.Compile_multilib)
    187 	fmt.Fprintln(w, "LOCAL_SRC_FILES :=", data.OutputFile.String())
    188 
    189 	archStr := amod.Arch().ArchType.String()
    190 	if amod.Host() {
    191 		if hostCross {
    192 			fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
    193 		} else {
    194 			fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
    195 
    196 			// TODO: this isn't true for every module, only dependencies of ACP
    197 			fmt.Fprintln(w, "LOCAL_ACP_UNAVAILABLE := true")
    198 		}
    199 		fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", amod.HostType().String())
    200 		fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
    201 	} else {
    202 		fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
    203 	}
    204 
    205 	for _, extra := range data.Extra {
    206 		err = extra(w, data.OutputFile.Path())
    207 		if err != nil {
    208 			return err
    209 		}
    210 	}
    211 
    212 	fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
    213 
    214 	return err
    215 }
    216