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 DistFiles TaggedDistFiles 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 Entries AndroidMkEntries 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 DistFiles TaggedDistFiles 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 179// Compute the list of Make strings to declare phone goals and dist-for-goals 180// calls from the module's dist and dists properties. 181func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { 182 amod := mod.(Module).base() 183 name := amod.BaseModuleName() 184 185 var ret []string 186 187 availableTaggedDists := TaggedDistFiles{} 188 if a.DistFiles != nil { 189 availableTaggedDists = a.DistFiles 190 } else if a.OutputFile.Valid() { 191 availableTaggedDists = MakeDefaultDistFiles(a.OutputFile.Path()) 192 } 193 194 // Iterate over this module's dist structs, merged from the dist and dists properties. 195 for _, dist := range amod.Dists() { 196 // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore 197 goals := strings.Join(dist.Targets, " ") 198 199 // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map" 200 var tag string 201 if dist.Tag == nil { 202 // If the dist struct does not specify a tag, use the default output files tag. 203 tag = "" 204 } else { 205 tag = *dist.Tag 206 } 207 208 // Get the paths of the output files to be dist'd, represented by the tag. 209 // Can be an empty list. 210 tagPaths := availableTaggedDists[tag] 211 if len(tagPaths) == 0 { 212 // Nothing to dist for this tag, continue to the next dist. 213 continue 214 } 215 216 if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) { 217 errorMessage := "Cannot apply dest/suffix for more than one dist " + 218 "file for %s goals in module %s. The list of dist files, " + 219 "which should have a single element, is:\n%s" 220 panic(fmt.Errorf(errorMessage, goals, name, tagPaths)) 221 } 222 223 ret = append(ret, fmt.Sprintf(".PHONY: %s\n", goals)) 224 225 // Create dist-for-goals calls for each path in the dist'd files. 226 for _, path := range tagPaths { 227 // It's possible that the Path is nil from errant modules. Be defensive here. 228 if path == nil { 229 tagName := "default" // for error message readability 230 if dist.Tag != nil { 231 tagName = *dist.Tag 232 } 233 panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name)) 234 } 235 236 dest := filepath.Base(path.String()) 237 238 if dist.Dest != nil { 239 var err error 240 if dest, err = validateSafePath(*dist.Dest); err != nil { 241 // This was checked in ModuleBase.GenerateBuildActions 242 panic(err) 243 } 244 } 245 246 if dist.Suffix != nil { 247 ext := filepath.Ext(dest) 248 suffix := *dist.Suffix 249 dest = strings.TrimSuffix(dest, ext) + suffix + ext 250 } 251 252 if dist.Dir != nil { 253 var err error 254 if dest, err = validateSafePath(*dist.Dir, dest); err != nil { 255 // This was checked in ModuleBase.GenerateBuildActions 256 panic(err) 257 } 258 } 259 260 ret = append( 261 ret, 262 fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", goals, path.String(), dest)) 263 } 264 } 265 266 return ret 267} 268 269func (a *AndroidMkEntries) fillInEntries(config Config, bpPath string, mod blueprint.Module) { 270 a.EntryMap = make(map[string][]string) 271 amod := mod.(Module).base() 272 name := amod.BaseModuleName() 273 274 if a.Include == "" { 275 a.Include = "$(BUILD_PREBUILT)" 276 } 277 a.Required = append(a.Required, amod.commonProperties.Required...) 278 a.Host_required = append(a.Host_required, amod.commonProperties.Host_required...) 279 a.Target_required = append(a.Target_required, amod.commonProperties.Target_required...) 280 281 for _, distString := range a.GetDistForGoals(mod) { 282 fmt.Fprintf(&a.header, distString) 283 } 284 285 fmt.Fprintln(&a.header, "\ninclude $(CLEAR_VARS)") 286 287 // Collect make variable assignment entries. 288 a.SetString("LOCAL_PATH", filepath.Dir(bpPath)) 289 a.SetString("LOCAL_MODULE", name+a.SubName) 290 a.SetString("LOCAL_MODULE_CLASS", a.Class) 291 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) 292 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) 293 a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...) 294 a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...) 295 296 if am, ok := mod.(ApexModule); ok { 297 a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform()) 298 } 299 300 archStr := amod.Arch().ArchType.String() 301 host := false 302 switch amod.Os().Class { 303 case Host: 304 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. 305 if amod.Arch().ArchType != Common { 306 a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) 307 } 308 host = true 309 case HostCross: 310 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. 311 if amod.Arch().ArchType != Common { 312 a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) 313 } 314 host = true 315 case Device: 316 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. 317 if amod.Arch().ArchType != Common { 318 if amod.Target().NativeBridge { 319 hostArchStr := amod.Target().NativeBridgeHostArchName 320 if hostArchStr != "" { 321 a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr) 322 } 323 } else { 324 a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr) 325 } 326 } 327 328 a.AddStrings("LOCAL_INIT_RC", amod.commonProperties.Init_rc...) 329 a.AddStrings("LOCAL_VINTF_FRAGMENTS", amod.commonProperties.Vintf_fragments...) 330 a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(amod.commonProperties.Proprietary)) 331 if Bool(amod.commonProperties.Vendor) || Bool(amod.commonProperties.Soc_specific) { 332 a.SetString("LOCAL_VENDOR_MODULE", "true") 333 } 334 a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(amod.commonProperties.Device_specific)) 335 a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(amod.commonProperties.Product_specific)) 336 a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(amod.commonProperties.System_ext_specific)) 337 if amod.commonProperties.Owner != nil { 338 a.SetString("LOCAL_MODULE_OWNER", *amod.commonProperties.Owner) 339 } 340 } 341 342 if len(amod.noticeFiles) > 0 { 343 a.SetString("LOCAL_NOTICE_FILE", strings.Join(amod.noticeFiles.Strings(), " ")) 344 } 345 346 if host { 347 makeOs := amod.Os().String() 348 if amod.Os() == Linux || amod.Os() == LinuxBionic { 349 makeOs = "linux" 350 } 351 a.SetString("LOCAL_MODULE_HOST_OS", makeOs) 352 a.SetString("LOCAL_IS_HOST_MODULE", "true") 353 } 354 355 prefix := "" 356 if amod.ArchSpecific() { 357 switch amod.Os().Class { 358 case Host: 359 prefix = "HOST_" 360 case HostCross: 361 prefix = "HOST_CROSS_" 362 case Device: 363 prefix = "TARGET_" 364 365 } 366 367 if amod.Arch().ArchType != config.Targets[amod.Os()][0].Arch.ArchType { 368 prefix = "2ND_" + prefix 369 } 370 } 371 for _, extra := range a.ExtraEntries { 372 extra(a) 373 } 374 375 // Write to footer. 376 fmt.Fprintln(&a.footer, "include "+a.Include) 377 blueprintDir := filepath.Dir(bpPath) 378 for _, footerFunc := range a.ExtraFooters { 379 footerFunc(&a.footer, name, prefix, blueprintDir, a) 380 } 381} 382 383func (a *AndroidMkEntries) write(w io.Writer) { 384 if a.Disabled { 385 return 386 } 387 388 if !a.OutputFile.Valid() { 389 return 390 } 391 392 w.Write(a.header.Bytes()) 393 for _, name := range a.entryOrder { 394 fmt.Fprintln(w, name+" := "+strings.Join(a.EntryMap[name], " ")) 395 } 396 w.Write(a.footer.Bytes()) 397} 398 399func (a *AndroidMkEntries) FooterLinesForTests() []string { 400 return strings.Split(string(a.footer.Bytes()), "\n") 401} 402 403func AndroidMkSingleton() Singleton { 404 return &androidMkSingleton{} 405} 406 407type androidMkSingleton struct{} 408 409func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { 410 if !ctx.Config().EmbeddedInMake() { 411 return 412 } 413 414 var androidMkModulesList []blueprint.Module 415 416 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { 417 androidMkModulesList = append(androidMkModulesList, module) 418 }) 419 420 sort.SliceStable(androidMkModulesList, func(i, j int) bool { 421 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j]) 422 }) 423 424 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk") 425 if ctx.Failed() { 426 return 427 } 428 429 err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList) 430 if err != nil { 431 ctx.Errorf(err.Error()) 432 } 433 434 ctx.Build(pctx, BuildParams{ 435 Rule: blueprint.Phony, 436 Output: transMk, 437 }) 438} 439 440func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Module) error { 441 buf := &bytes.Buffer{} 442 443 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 444 445 type_stats := make(map[string]int) 446 for _, mod := range mods { 447 err := translateAndroidMkModule(ctx, buf, mod) 448 if err != nil { 449 os.Remove(mkFile) 450 return err 451 } 452 453 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod { 454 type_stats[ctx.ModuleType(amod)] += 1 455 } 456 } 457 458 keys := []string{} 459 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=") 460 for k := range type_stats { 461 keys = append(keys, k) 462 } 463 sort.Strings(keys) 464 for _, mod_type := range keys { 465 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type) 466 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, type_stats[mod_type]) 467 } 468 469 // Don't write to the file if it hasn't changed 470 if _, err := os.Stat(absolutePath(mkFile)); !os.IsNotExist(err) { 471 if data, err := ioutil.ReadFile(absolutePath(mkFile)); err == nil { 472 matches := buf.Len() == len(data) 473 474 if matches { 475 for i, value := range buf.Bytes() { 476 if value != data[i] { 477 matches = false 478 break 479 } 480 } 481 } 482 483 if matches { 484 return nil 485 } 486 } 487 } 488 489 return ioutil.WriteFile(absolutePath(mkFile), buf.Bytes(), 0666) 490} 491 492func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error { 493 defer func() { 494 if r := recover(); r != nil { 495 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s", 496 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod))) 497 } 498 }() 499 500 switch x := mod.(type) { 501 case AndroidMkDataProvider: 502 return translateAndroidModule(ctx, w, mod, x) 503 case bootstrap.GoBinaryTool: 504 return translateGoBinaryModule(ctx, w, mod, x) 505 case AndroidMkEntriesProvider: 506 return translateAndroidMkEntriesModule(ctx, w, mod, x) 507 default: 508 return nil 509 } 510} 511 512func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 513 goBinary bootstrap.GoBinaryTool) error { 514 515 name := ctx.ModuleName(mod) 516 fmt.Fprintln(w, ".PHONY:", name) 517 fmt.Fprintln(w, name+":", goBinary.InstallPath()) 518 fmt.Fprintln(w, "") 519 520 return nil 521} 522 523func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) { 524 // Get the preamble content through AndroidMkEntries logic. 525 data.Entries = AndroidMkEntries{ 526 Class: data.Class, 527 SubName: data.SubName, 528 DistFiles: data.DistFiles, 529 OutputFile: data.OutputFile, 530 Disabled: data.Disabled, 531 Include: data.Include, 532 Required: data.Required, 533 Host_required: data.Host_required, 534 Target_required: data.Target_required, 535 } 536 data.Entries.fillInEntries(config, bpPath, mod) 537 538 // copy entries back to data since it is used in Custom 539 data.Required = data.Entries.Required 540 data.Host_required = data.Entries.Host_required 541 data.Target_required = data.Entries.Target_required 542} 543 544func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 545 provider AndroidMkDataProvider) error { 546 547 amod := mod.(Module).base() 548 if shouldSkipAndroidMkProcessing(amod) { 549 return nil 550 } 551 552 data := provider.AndroidMk() 553 if data.Include == "" { 554 data.Include = "$(BUILD_PREBUILT)" 555 } 556 557 data.fillInData(ctx.Config(), ctx.BlueprintFile(mod), mod) 558 559 prefix := "" 560 if amod.ArchSpecific() { 561 switch amod.Os().Class { 562 case Host: 563 prefix = "HOST_" 564 case HostCross: 565 prefix = "HOST_CROSS_" 566 case Device: 567 prefix = "TARGET_" 568 569 } 570 571 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType { 572 prefix = "2ND_" + prefix 573 } 574 } 575 576 name := provider.BaseModuleName() 577 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod)) 578 579 if data.Custom != nil { 580 data.Custom(w, name, prefix, blueprintDir, data) 581 } else { 582 WriteAndroidMkData(w, data) 583 } 584 585 return nil 586} 587 588func WriteAndroidMkData(w io.Writer, data AndroidMkData) { 589 if data.Disabled { 590 return 591 } 592 593 if !data.OutputFile.Valid() { 594 return 595 } 596 597 // write preamble via Entries 598 data.Entries.footer = bytes.Buffer{} 599 data.Entries.write(w) 600 601 for _, extra := range data.Extra { 602 extra(w, data.OutputFile.Path()) 603 } 604 605 fmt.Fprintln(w, "include "+data.Include) 606} 607 608func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 609 provider AndroidMkEntriesProvider) error { 610 if shouldSkipAndroidMkProcessing(mod.(Module).base()) { 611 return nil 612 } 613 614 for _, entries := range provider.AndroidMkEntries() { 615 entries.fillInEntries(ctx.Config(), ctx.BlueprintFile(mod), mod) 616 entries.write(w) 617 } 618 619 return nil 620} 621 622func shouldSkipAndroidMkProcessing(module *ModuleBase) bool { 623 if !module.commonProperties.NamespaceExportedToMake { 624 // TODO(jeffrygaston) do we want to validate that there are no modules being 625 // exported to Kati that depend on this module? 626 return true 627 } 628 629 return !module.Enabled() || 630 module.commonProperties.SkipInstall || 631 // Make does not understand LinuxBionic 632 module.Os() == LinuxBionic 633} 634