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 15package android 16 17import ( 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/bootstrap" 29) 30 31func init() { 32 RegisterSingletonType("androidmk", AndroidMkSingleton) 33} 34 35type AndroidMkDataProvider interface { 36 AndroidMk() AndroidMkData 37 BaseModuleName() string 38} 39 40type AndroidMkData struct { 41 Class string 42 SubName string 43 DistFile OptionalPath 44 OutputFile OptionalPath 45 Disabled bool 46 Include string 47 Required []string 48 49 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) 50 51 Extra []AndroidMkExtraFunc 52 53 preamble bytes.Buffer 54} 55 56type AndroidMkExtraFunc func(w io.Writer, outputFile Path) 57 58func AndroidMkSingleton() Singleton { 59 return &androidMkSingleton{} 60} 61 62type androidMkSingleton struct{} 63 64func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { 65 if !ctx.Config().EmbeddedInMake() { 66 return 67 } 68 69 var androidMkModulesList []blueprint.Module 70 71 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { 72 androidMkModulesList = append(androidMkModulesList, module) 73 }) 74 75 sort.SliceStable(androidMkModulesList, func(i, j int) bool { 76 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j]) 77 }) 78 79 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk") 80 if ctx.Failed() { 81 return 82 } 83 84 err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) 85 if err != nil { 86 ctx.Errorf(err.Error()) 87 } 88 89 ctx.Build(pctx, BuildParams{ 90 Rule: blueprint.Phony, 91 Output: transMk, 92 }) 93} 94 95func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error { 96 buf := &bytes.Buffer{} 97 98 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 99 100 type_stats := make(map[string]int) 101 for _, mod := range mods { 102 err := translateAndroidMkModule(ctx, buf, mod) 103 if err != nil { 104 os.Remove(mkFile) 105 return err 106 } 107 108 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod { 109 type_stats[ctx.ModuleType(amod)] += 1 110 } 111 } 112 113 keys := []string{} 114 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=") 115 for k := range type_stats { 116 keys = append(keys, k) 117 } 118 sort.Strings(keys) 119 for _, mod_type := range keys { 120 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type) 121 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type]) 122 } 123 124 // Don't write to the file if it hasn't changed 125 if _, err := os.Stat(mkFile); !os.IsNotExist(err) { 126 if data, err := ioutil.ReadFile(mkFile); err == nil { 127 matches := buf.Len() == len(data) 128 129 if matches { 130 for i, value := range buf.Bytes() { 131 if value != data[i] { 132 matches = false 133 break 134 } 135 } 136 } 137 138 if matches { 139 return nil 140 } 141 } 142 } 143 144 return ioutil.WriteFile(mkFile, buf.Bytes(), 0666) 145} 146 147func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error { 148 defer func() { 149 if r := recover(); r != nil { 150 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s", 151 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod))) 152 } 153 }() 154 155 switch x := mod.(type) { 156 case AndroidMkDataProvider: 157 return translateAndroidModule(ctx, w, mod, x) 158 case bootstrap.GoBinaryTool: 159 return translateGoBinaryModule(ctx, w, mod, x) 160 default: 161 return nil 162 } 163} 164 165func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 166 goBinary bootstrap.GoBinaryTool) error { 167 168 name := ctx.ModuleName(mod) 169 fmt.Fprintln(w, ".PHONY:", name) 170 fmt.Fprintln(w, name+":", goBinary.InstallPath()) 171 fmt.Fprintln(w, "") 172 173 return nil 174} 175 176func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 177 provider AndroidMkDataProvider) error { 178 179 name := provider.BaseModuleName() 180 amod := mod.(Module).base() 181 182 if !amod.Enabled() { 183 return nil 184 } 185 186 if amod.commonProperties.SkipInstall { 187 return nil 188 } 189 190 if !amod.commonProperties.NamespaceExportedToMake { 191 // TODO(jeffrygaston) do we want to validate that there are no modules being 192 // exported to Kati that depend on this module? 193 return nil 194 } 195 196 data := provider.AndroidMk() 197 198 if data.Include == "" { 199 data.Include = "$(BUILD_PREBUILT)" 200 } 201 202 data.Required = append(data.Required, amod.commonProperties.Required...) 203 204 // Make does not understand LinuxBionic 205 if amod.Os() == LinuxBionic { 206 return nil 207 } 208 209 prefix := "" 210 if amod.ArchSpecific() { 211 switch amod.Os().Class { 212 case Host: 213 prefix = "HOST_" 214 case HostCross: 215 prefix = "HOST_CROSS_" 216 case Device: 217 prefix = "TARGET_" 218 219 } 220 221 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType { 222 prefix = "2ND_" + prefix 223 } 224 } 225 226 if len(amod.commonProperties.Dist.Targets) > 0 { 227 distFile := data.DistFile 228 if !distFile.Valid() { 229 distFile = data.OutputFile 230 } 231 if distFile.Valid() { 232 dest := filepath.Base(distFile.String()) 233 234 if amod.commonProperties.Dist.Dest != nil { 235 var err error 236 dest, err = validateSafePath(*amod.commonProperties.Dist.Dest) 237 if err != nil { 238 // This was checked in ModuleBase.GenerateBuildActions 239 panic(err) 240 } 241 } 242 243 if amod.commonProperties.Dist.Suffix != nil { 244 ext := filepath.Ext(dest) 245 suffix := *amod.commonProperties.Dist.Suffix 246 dest = strings.TrimSuffix(dest, ext) + suffix + ext 247 } 248 249 if amod.commonProperties.Dist.Dir != nil { 250 var err error 251 dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest) 252 if err != nil { 253 // This was checked in ModuleBase.GenerateBuildActions 254 panic(err) 255 } 256 } 257 258 goals := strings.Join(amod.commonProperties.Dist.Targets, " ") 259 fmt.Fprintln(&data.preamble, ".PHONY:", goals) 260 fmt.Fprintf(&data.preamble, "$(call dist-for-goals,%s,%s:%s)\n", 261 goals, distFile.String(), dest) 262 } 263 } 264 265 fmt.Fprintln(&data.preamble, "\ninclude $(CLEAR_VARS)") 266 fmt.Fprintln(&data.preamble, "LOCAL_PATH :=", filepath.Dir(ctx.BlueprintFile(mod))) 267 fmt.Fprintln(&data.preamble, "LOCAL_MODULE :=", name+data.SubName) 268 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_CLASS :=", data.Class) 269 fmt.Fprintln(&data.preamble, "LOCAL_PREBUILT_MODULE_FILE :=", data.OutputFile.String()) 270 271 if len(data.Required) > 0 { 272 fmt.Fprintln(&data.preamble, "LOCAL_REQUIRED_MODULES := "+strings.Join(data.Required, " ")) 273 } 274 275 archStr := amod.Arch().ArchType.String() 276 host := false 277 switch amod.Os().Class { 278 case Host: 279 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. 280 if archStr != "common" { 281 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_ARCH :=", archStr) 282 } 283 host = true 284 case HostCross: 285 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. 286 if archStr != "common" { 287 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_CROSS_ARCH :=", archStr) 288 } 289 host = true 290 case Device: 291 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. 292 if archStr != "common" { 293 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_TARGET_ARCH :=", archStr) 294 } 295 296 if len(amod.commonProperties.Init_rc) > 0 { 297 fmt.Fprintln(&data.preamble, "LOCAL_INIT_RC := ", strings.Join(amod.commonProperties.Init_rc, " ")) 298 } 299 if len(amod.commonProperties.Vintf_fragments) > 0 { 300 fmt.Fprintln(&data.preamble, "LOCAL_VINTF_FRAGMENTS := ", strings.Join(amod.commonProperties.Vintf_fragments, " ")) 301 } 302 if Bool(amod.commonProperties.Proprietary) { 303 fmt.Fprintln(&data.preamble, "LOCAL_PROPRIETARY_MODULE := true") 304 } 305 if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) { 306 fmt.Fprintln(&data.preamble, "LOCAL_VENDOR_MODULE := true") 307 } 308 if Bool(amod.commonProperties.Device_specific) { 309 fmt.Fprintln(&data.preamble, "LOCAL_ODM_MODULE := true") 310 } 311 if Bool(amod.commonProperties.Product_specific) { 312 fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_MODULE := true") 313 } 314 if Bool(amod.commonProperties.Product_services_specific) { 315 fmt.Fprintln(&data.preamble, "LOCAL_PRODUCT_SERVICES_MODULE := true") 316 } 317 if amod.commonProperties.Owner != nil { 318 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_OWNER :=", *amod.commonProperties.Owner) 319 } 320 } 321 322 if amod.noticeFile.Valid() { 323 fmt.Fprintln(&data.preamble, "LOCAL_NOTICE_FILE :=", amod.noticeFile.String()) 324 } 325 326 if host { 327 makeOs := amod.Os().String() 328 if amod.Os() == Linux || amod.Os() == LinuxBionic { 329 makeOs = "linux" 330 } 331 fmt.Fprintln(&data.preamble, "LOCAL_MODULE_HOST_OS :=", makeOs) 332 fmt.Fprintln(&data.preamble, "LOCAL_IS_HOST_MODULE := true") 333 } 334 335 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod)) 336 337 if data.Custom != nil { 338 data.Custom(w, name, prefix, blueprintDir, data) 339 } else { 340 WriteAndroidMkData(w, data) 341 } 342 343 return nil 344} 345 346func WriteAndroidMkData(w io.Writer, data AndroidMkData) { 347 if data.Disabled { 348 return 349 } 350 351 if !data.OutputFile.Valid() { 352 return 353 } 354 355 w.Write(data.preamble.Bytes()) 356 357 for _, extra := range data.Extra { 358 extra(w, data.OutputFile.Path()) 359 } 360 361 fmt.Fprintln(w, "include "+data.Include) 362} 363