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 RegisterAndroidMkBuildComponents(InitRegistrationContext) 33} 34 35func RegisterAndroidMkBuildComponents(ctx RegistrationContext) { 36 ctx.RegisterSingletonType("androidmk", AndroidMkSingleton) 37} 38 39// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to 40// use the Custom function. 41type AndroidMkDataProvider interface { 42 AndroidMk() AndroidMkData 43 BaseModuleName() string 44} 45 46type AndroidMkData struct { 47 Class string 48 SubName string 49 DistFile OptionalPath 50 OutputFile OptionalPath 51 Disabled bool 52 Include string 53 Required []string 54 Host_required []string 55 Target_required []string 56 57 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) 58 59 Extra []AndroidMkExtraFunc 60 61 preamble bytes.Buffer 62} 63 64type AndroidMkExtraFunc func(w io.Writer, outputFile Path) 65 66// Allows modules to customize their Android*.mk output. 67type AndroidMkEntriesProvider interface { 68 AndroidMkEntries() []AndroidMkEntries 69 BaseModuleName() string 70} 71 72type AndroidMkEntries struct { 73 Class string 74 SubName string 75 DistFile OptionalPath 76 OutputFile OptionalPath 77 Disabled bool 78 Include string 79 Required []string 80 Host_required []string 81 Target_required []string 82 83 header bytes.Buffer 84 footer bytes.Buffer 85 86 ExtraEntries []AndroidMkExtraEntriesFunc 87 ExtraFooters []AndroidMkExtraFootersFunc 88 89 EntryMap map[string][]string 90 entryOrder []string 91} 92 93type AndroidMkExtraEntriesFunc func(entries *AndroidMkEntries) 94type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) 95 96func (a *AndroidMkEntries) SetString(name, value string) { 97 if _, ok := a.EntryMap[name]; !ok { 98 a.entryOrder = append(a.entryOrder, name) 99 } 100 a.EntryMap[name] = []string{value} 101} 102 103func (a *AndroidMkEntries) SetPath(name string, path Path) { 104 if _, ok := a.EntryMap[name]; !ok { 105 a.entryOrder = append(a.entryOrder, name) 106 } 107 a.EntryMap[name] = []string{path.String()} 108} 109 110func (a *AndroidMkEntries) SetOptionalPath(name string, path OptionalPath) { 111 if path.Valid() { 112 a.SetPath(name, path.Path()) 113 } 114} 115 116func (a *AndroidMkEntries) AddPath(name string, path Path) { 117 if _, ok := a.EntryMap[name]; !ok { 118 a.entryOrder = append(a.entryOrder, name) 119 } 120 a.EntryMap[name] = append(a.EntryMap[name], path.String()) 121} 122 123func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) { 124 if path.Valid() { 125 a.AddPath(name, path.Path()) 126 } 127} 128 129func (a *AndroidMkEntries) SetPaths(name string, paths Paths) { 130 if _, ok := a.EntryMap[name]; !ok { 131 a.entryOrder = append(a.entryOrder, name) 132 } 133 a.EntryMap[name] = paths.Strings() 134} 135 136func (a *AndroidMkEntries) SetOptionalPaths(name string, paths Paths) { 137 if len(paths) > 0 { 138 a.SetPaths(name, paths) 139 } 140} 141 142func (a *AndroidMkEntries) AddPaths(name string, paths Paths) { 143 if _, ok := a.EntryMap[name]; !ok { 144 a.entryOrder = append(a.entryOrder, name) 145 } 146 a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...) 147} 148 149func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { 150 if flag { 151 if _, ok := a.EntryMap[name]; !ok { 152 a.entryOrder = append(a.entryOrder, name) 153 } 154 a.EntryMap[name] = []string{"true"} 155 } 156} 157 158func (a *AndroidMkEntries) SetBool(name string, flag bool) { 159 if _, ok := a.EntryMap[name]; !ok { 160 a.entryOrder = append(a.entryOrder, name) 161 } 162 if flag { 163 a.EntryMap[name] = []string{"true"} 164 } else { 165 a.EntryMap[name] = []string{"false"} 166 } 167} 168 169func (a *AndroidMkEntries) AddStrings(name string, value ...string) { 170 if len(value) == 0 { 171 return 172 } 173 if _, ok := a.EntryMap[name]; !ok { 174 a.entryOrder = append(a.entryOrder, name) 175 } 176 a.EntryMap[name] = append(a.EntryMap[name], value...) 177} 178 179func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { 180 a.EntryMap = make(map[string][]string) 181 amod := mod.(Module).base() 182 name := amod.BaseModuleName() 183 184 if a.Include == "" { 185 a.Include = "$(BUILD_PREBUILT)" 186 } 187 a.Required = append(a.Required, amod.commonProperties.Required...) 188 a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...) 189 a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...) 190 191 // Fill in the header part. 192 if len(amod.commonProperties.Dist.Targets) > 0 { 193 distFile := a.DistFile 194 if !distFile.Valid() { 195 distFile = a.OutputFile 196 } 197 if distFile.Valid() { 198 dest := filepath.Base(distFile.String()) 199 200 if amod.commonProperties.Dist.Dest != nil { 201 var err error 202 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dest); err != nil { 203 // This was checked in ModuleBase.GenerateBuildActions 204 panic(err) 205 } 206 } 207 208 if amod.commonProperties.Dist.Suffix != nil { 209 ext := filepath.Ext(dest) 210 suffix := *amod.commonProperties.Dist.Suffix 211 dest = strings.TrimSuffix(dest, ext) + suffix + ext 212 } 213 214 if amod.commonProperties.Dist.Dir != nil { 215 var err error 216 if dest, err = validateSafePath(*amod.commonProperties.Dist.Dir, dest); err != nil { 217 // This was checked in ModuleBase.GenerateBuildActions 218 panic(err) 219 } 220 } 221 222 goals := strings.Join(amod.commonProperties.Dist.Targets, " ") 223 fmt.Fprintln(&a.header, ".PHONY:", goals) 224 fmt.Fprintf(&a.header, "$(call dist-for-goals,%s,%s:%s)\n", 225 goals, distFile.String(), dest) 226 } 227 } 228 229 fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)") 230 231 // Collect make variable assignment entries. 232 a.SetString("LOCAL_PATH", filepath.Dir(bpPath)) 233 a.SetString("LOCAL_MODULE", name+a.SubName) 234 a.SetString("LOCAL_MODULE_CLASS", a.Class) 235 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) 236 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) 237 a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...) 238 a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...) 239 240 if am, ok := mod.(ApexModule); ok { 241 a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform()) 242 } 243 244 archStr := amod.Arch().ArchType.String() 245 host := false 246 switch amod.Os().Class { 247 case Host: 248 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. 249 if amod.Arch().ArchType != Common { 250 a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) 251 } 252 host = true 253 case HostCross: 254 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. 255 if amod.Arch().ArchType != Common { 256 a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) 257 } 258 host = true 259 case Device: 260 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. 261 if amod.Arch().ArchType != Common { 262 if amod.Target().NativeBridge { 263 hostArchStr := amod.Target().NativeBridgeHostArchName 264 if hostArchStr != "" { 265 a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr) 266 } 267 } else { 268 a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr) 269 } 270 } 271 272 a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...) 273 a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...) 274 a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary)) 275 if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) { 276 a.SetString("LOCAL_VENDOR_MODULE", "true") 277 } 278 a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific)) 279 a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific)) 280 a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(amod.commonProperties.System_ext_specific)) 281 if amod.commonProperties.Owner != nil { 282 a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner) 283 } 284 } 285 286 if amod.noticeFile.Valid() { 287 a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String()) 288 } 289 290 if host { 291 makeOs := amod.Os().String() 292 if amod.Os() == Linux || amod.Os() == LinuxBionic { 293 makeOs = "linux" 294 } 295 a.SetString("LOCAL_MODULE_HOST_OS", makeOs) 296 a.SetString("LOCAL_IS_HOST_MODULE", "true") 297 } 298 299 prefix := "" 300 if amod.ArchSpecific() { 301 switch amod.Os().Class { 302 case Host: 303 prefix = "HOST_" 304 case HostCross: 305 prefix = "HOST_CROSS_" 306 case Device: 307 prefix = "TARGET_" 308 309 } 310 311 if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType { 312 prefix = "2ND_" + prefix 313 } 314 } 315 for _, extra := range a.ExtraEntries { 316 extra(a) 317 } 318 319 // Write to footer. 320 fmt.Fprintln(&a.footer, "include "+a.Include) 321 blueprintDir := filepath.Dir(bpPath) 322 for _, footerFunc := range a.ExtraFooters { 323 footerFunc(&a.footer, name, prefix, blueprintDir, a) 324 } 325} 326 327func (a *AndroidMkEntries) write(w io.Writer) { 328 if a.Disabled { 329 return 330 } 331 332 if !a.OutputFile.Valid() { 333 return 334 } 335 336 w.Write(a.header.Bytes()) 337 for _, name := range a.entryOrder { 338 fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " ")) 339 } 340 w.Write(a.footer.Bytes()) 341} 342 343func (a *AndroidMkEntries) FooterLinesForTests() []string { 344 return strings.Split(string(a.footer.Bytes()), "\n") 345} 346 347func AndroidMkSingleton() Singleton { 348 return &androidMkSingleton{} 349} 350 351type androidMkSingleton struct{} 352 353func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { 354 if !ctx.Config().EmbeddedInMake() { 355 return 356 } 357 358 var androidMkModulesList []blueprint.Module 359 360 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { 361 androidMkModulesList = append(androidMkModulesList, module) 362 }) 363 364 sort.SliceStable(androidMkModulesList, func(i, j int) bool { 365 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j]) 366 }) 367 368 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk") 369 if ctx.Failed() { 370 return 371 } 372 373 err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList) 374 if err != nil { 375 ctx.Errorf(err.Error()) 376 } 377 378 ctx.Build(pctx, BuildParams{ 379 Rule: blueprint.Phony, 380 Output: transMk, 381 }) 382} 383 384func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error { 385 buf := &bytes.Buffer{} 386 387 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 388 389 type_stats := make(map[string]int) 390 for _, mod := range mods { 391 err := translateAndroidMkModule(ctx, buf, mod) 392 if err != nil { 393 os.Remove(mkFile) 394 return err 395 } 396 397 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod { 398 type_stats[ctx.ModuleType(amod)] += 1 399 } 400 } 401 402 keys := []string{} 403 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=") 404 for k := range type_stats { 405 keys = append(keys, k) 406 } 407 sort.Strings(keys) 408 for _, mod_type := range keys { 409 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type) 410 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type]) 411 } 412 413 // Don't write to the file if it hasn't changed 414 if _, err := os.Stat(absolutePath(mkFile)); !os.IsNotExist(err) { 415 if data, err := ioutil.ReadFile(absolutePath(mkFile)); err == nil { 416 matches := buf.Len() == len(data) 417 418 if matches { 419 for i, value := range buf.Bytes() { 420 if value != data[i] { 421 matches = false 422 break 423 } 424 } 425 } 426 427 if matches { 428 return nil 429 } 430 } 431 } 432 433 return ioutil.WriteFile(absolutePath(mkFile), buf.Bytes(), 0666) 434} 435 436func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error { 437 defer func() { 438 if r := recover(); r != nil { 439 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s", 440 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod))) 441 } 442 }() 443 444 switch x := mod.(type) { 445 case AndroidMkDataProvider: 446 return translateAndroidModule(ctx, w, mod, x) 447 case bootstrap.GoBinaryTool: 448 return translateGoBinaryModule(ctx, w, mod, x) 449 case AndroidMkEntriesProvider: 450 return translateAndroidMkEntriesModule(ctx, w, mod, x) 451 default: 452 return nil 453 } 454} 455 456func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 457 goBinary bootstrap.GoBinaryTool) error { 458 459 name := ctx.ModuleName(mod) 460 fmt.Fprintln(w, ".PHONY:", name) 461 fmt.Fprintln(w, name+":", goBinary.InstallPath()) 462 fmt.Fprintln(w, "") 463 464 return nil 465} 466 467func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) { 468 // Get the preamble content through AndroidMkEntries logic. 469 entries := AndroidMkEntries{ 470 Class: data.Class, 471 SubName: data.SubName, 472 DistFile: data.DistFile, 473 OutputFile: data.OutputFile, 474 Disabled: data.Disabled, 475 Include: data.Include, 476 Required: data.Required, 477 Host_required: data.Host_required, 478 Target_required: data.Target_required, 479 } 480 entries.fillInEntries(config, bpPath, mod) 481 482 // preamble doesn't need the footer content. 483 entries.footer = bytes.Buffer{} 484 entries.write(&data.preamble) 485 486 // copy entries back to data since it is used in Custom 487 data.Required = entries.Required 488 data.Host_required = entries.Host_required 489 data.Target_required = entries.Target_required 490} 491 492func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 493 provider AndroidMkDataProvider) error { 494 495 amod := mod.(Module).base() 496 if shouldSkipAndroidMkProcessing(amod) { 497 return nil 498 } 499 500 data := provider.AndroidMk() 501 if data.Include == "" { 502 data.Include = "$(BUILD_PREBUILT)" 503 } 504 505 data.fillInData(ctx.Config(), ctx.BlueprintFile(mod), mod) 506 507 prefix := "" 508 if amod.ArchSpecific() { 509 switch amod.Os().Class { 510 case Host: 511 prefix = "HOST_" 512 case HostCross: 513 prefix = "HOST_CROSS_" 514 case Device: 515 prefix = "TARGET_" 516 517 } 518 519 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType { 520 prefix = "2ND_" + prefix 521 } 522 } 523 524 name := provider.BaseModuleName() 525 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod)) 526 527 if data.Custom != nil { 528 data.Custom(w, name, prefix, blueprintDir, data) 529 } else { 530 WriteAndroidMkData(w, data) 531 } 532 533 return nil 534} 535 536func WriteAndroidMkData(w io.Writer, data AndroidMkData) { 537 if data.Disabled { 538 return 539 } 540 541 if !data.OutputFile.Valid() { 542 return 543 } 544 545 w.Write(data.preamble.Bytes()) 546 547 for _, extra := range data.Extra { 548 extra(w, data.OutputFile.Path()) 549 } 550 551 fmt.Fprintln(w, "include "+data.Include) 552} 553 554func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 555 provider AndroidMkEntriesProvider) error { 556 if shouldSkipAndroidMkProcessing(mod.(Module).base()) { 557 return nil 558 } 559 560 for _, entries := range provider.AndroidMkEntries() { 561 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod) 562 entries.write(w) 563 } 564 565 return nil 566} 567 568func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { 569 if !module.commonProperties.NamespaceExportedToMake { 570 // TODO(jeffrygaston) do we want to validate that there are no modules being 571 // exported to Kati that depend on this module? 572 return true 573 } 574 575 return !module.Enabled() || 576 module.commonProperties.SkipInstall || 577 // Make does not understand LinuxBionic 578 module.Os() == LinuxBionic 579} 580