Home | History | Annotate | Download | only in android
      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 android
     16 
     17 import (
     18 	"bytes"
     19 	"fmt"
     20 	"io"
     21 	"io/ioutil"
     22 	"os"
     23 	"path/filepath"
     24 	"sort"
     25 	"strings"
     26 
     27 	"github.com/google/blueprint"
     28 	"github.com/google/blueprint/proptools"
     29 )
     30 
     31 func init() {
     32 	RegisterSingletonType("androidmk", AndroidMkSingleton)
     33 }
     34 
     35 type AndroidMkDataProvider interface {
     36 	AndroidMk() (AndroidMkData, error)
     37 	BaseModuleName() string
     38 }
     39 
     40 type AndroidMkData struct {
     41 	Class      string
     42 	SubName    string
     43 	OutputFile OptionalPath
     44 	Disabled   bool
     45 
     46 	Custom func(w io.Writer, name, prefix, moduleDir string) error
     47 
     48 	Extra []func(w io.Writer, outputFile Path) error
     49 }
     50 
     51 func AndroidMkSingleton() blueprint.Singleton {
     52 	return &androidMkSingleton{}
     53 }
     54 
     55 type androidMkSingleton struct{}
     56 
     57 func (c *androidMkSingleton) GenerateBuildActions(ctx blueprint.SingletonContext) {
     58 	config := ctx.Config().(Config)
     59 
     60 	if !config.EmbeddedInMake() {
     61 		return
     62 	}
     63 
     64 	ctx.SetNinjaBuildDir(pctx, filepath.Join(config.buildDir, ".."))
     65 
     66 	var androidMkModulesList []Module
     67 
     68 	ctx.VisitAllModules(func(module blueprint.Module) {
     69 		if amod, ok := module.(Module); ok {
     70 			androidMkModulesList = append(androidMkModulesList, amod)
     71 		}
     72 	})
     73 
     74 	sort.Sort(AndroidModulesByName{androidMkModulesList, ctx})
     75 
     76 	transMk := PathForOutput(ctx, "Android"+proptools.String(config.ProductVariables.Make_suffix)+".mk")
     77 	if ctx.Failed() {
     78 		return
     79 	}
     80 
     81 	err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList)
     82 	if err != nil {
     83 		ctx.Errorf(err.Error())
     84 	}
     85 
     86 	ctx.Build(pctx, blueprint.BuildParams{
     87 		Rule:     blueprint.Phony,
     88 		Outputs:  []string{transMk.String()},
     89 		Optional: true,
     90 	})
     91 }
     92 
     93 func translateAndroidMk(ctx blueprint.SingletonContext, mkFile string, mods []Module) error {
     94 	buf := &bytes.Buffer{}
     95 
     96 	fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))")
     97 
     98 	type_stats := make(map[string]int)
     99 	for _, mod := range mods {
    100 		err := translateAndroidMkModule(ctx, buf, mod)
    101 		if err != nil {
    102 			os.Remove(mkFile)
    103 			return err
    104 		}
    105 
    106 		if ctx.PrimaryModule(mod) == mod {
    107 			type_stats[ctx.ModuleType(mod)] += 1
    108 		}
    109 	}
    110 
    111 	keys := []string{}
    112 	fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=")
    113 	for k := range type_stats {
    114 		keys = append(keys, k)
    115 	}
    116 	sort.Strings(keys)
    117 	for _, mod_type := range keys {
    118 		fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type)
    119 		fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type])
    120 	}
    121 
    122 	// Don't write to the file if it hasn't changed
    123 	if _, err := os.Stat(mkFile); !os.IsNotExist(err) {
    124 		if data, err := ioutil.ReadFile(mkFile); err == nil {
    125 			matches := buf.Len() == len(data)
    126 
    127 			if matches {
    128 				for i, value := range buf.Bytes() {
    129 					if value != data[i] {
    130 						matches = false
    131 						break
    132 					}
    133 				}
    134 			}
    135 
    136 			if matches {
    137 				return nil
    138 			}
    139 		}
    140 	}
    141 
    142 	return ioutil.WriteFile(mkFile, buf.Bytes(), 0666)
    143 }
    144 
    145 func translateAndroidMkModule(ctx blueprint.SingletonContext, w io.Writer, mod blueprint.Module) error {
    146 	provider, ok := mod.(AndroidMkDataProvider)
    147 	if !ok {
    148 		return nil
    149 	}
    150 
    151 	name := provider.BaseModuleName()
    152 	amod := mod.(Module).base()
    153 
    154 	if !amod.Enabled() {
    155 		return nil
    156 	}
    157 
    158 	if amod.commonProperties.SkipInstall {
    159 		return nil
    160 	}
    161 
    162 	data, err := provider.AndroidMk()
    163 	if err != nil {
    164 		return err
    165 	}
    166 
    167 	// Make does not understand LinuxBionic
    168 	if amod.Os() == LinuxBionic {
    169 		return nil
    170 	}
    171 
    172 	if data.SubName != "" {
    173 		name += data.SubName
    174 	}
    175 
    176 	if data.Custom != nil {
    177 		prefix := ""
    178 		if amod.ArchSpecific() {
    179 			switch amod.Os().Class {
    180 			case Host:
    181 				prefix = "HOST_"
    182 			case HostCross:
    183 				prefix = "HOST_CROSS_"
    184 			case Device:
    185 				prefix = "TARGET_"
    186 
    187 			}
    188 
    189 			config := ctx.Config().(Config)
    190 			if amod.Arch().ArchType != config.Targets[amod.Os().Class][0].Arch.ArchType {
    191 				prefix = "2ND_" + prefix
    192 			}
    193 		}
    194 
    195 		return data.Custom(w, name, prefix, filepath.Dir(ctx.BlueprintFile(mod)))
    196 	}
    197 
    198 	if data.Disabled {
    199 		return nil
    200 	}
    201 
    202 	if !data.OutputFile.Valid() {
    203 		return err
    204 	}
    205 
    206 	fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)")
    207 	fmt.Fprintln(w, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod)))
    208 	fmt.Fprintln(w, "LOCAL_MODULE :=", name)
    209 	fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", data.Class)
    210 	fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String())
    211 
    212 	if len(amod.commonProperties.Required) > 0 {
    213 		fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES := "+strings.Join(amod.commonProperties.Required, " "))
    214 	}
    215 
    216 	archStr := amod.Arch().ArchType.String()
    217 	host := false
    218 	switch amod.Os().Class {
    219 	case Host:
    220 		fmt.Fprintln(w, "LOCAL_MODULE_HOST_ARCH :=", archStr)
    221 		host = true
    222 	case HostCross:
    223 		fmt.Fprintln(w, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr)
    224 		host = true
    225 	case Device:
    226 		fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr)
    227 
    228 		if len(amod.commonProperties.Logtags) > 0 {
    229 			fmt.Fprintln(w, "LOCAL_LOGTAGS_FILES := ", strings.Join(amod.commonProperties.Logtags, " "))
    230 		}
    231 		if len(amod.commonProperties.Init_rc) > 0 {
    232 			fmt.Fprintln(w, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " "))
    233 		}
    234 		if amod.commonProperties.Proprietary {
    235 			fmt.Fprintln(w, "LOCAL_PROPRIETARY_MODULE := true")
    236 		}
    237 		if amod.commonProperties.Vendor {
    238 			fmt.Fprintln(w, "LOCAL_VENDOR_MODULE := true")
    239 		}
    240 		if amod.commonProperties.Owner != "" {
    241 			fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", amod.commonProperties.Owner)
    242 		}
    243 	}
    244 
    245 	if host {
    246 		fmt.Fprintln(w, "LOCAL_MODULE_HOST_OS :=", amod.Os().String())
    247 		fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true")
    248 	}
    249 
    250 	for _, extra := range data.Extra {
    251 		err = extra(w, data.OutputFile.Path())
    252 		if err != nil {
    253 			return err
    254 		}
    255 	}
    256 
    257 	fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
    258 
    259 	return err
    260 }
    261