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