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// This file offers AndroidMkEntriesProvider, which individual modules implement to output 16// Android.mk entries that contain information about the modules built through Soong. Kati reads 17// and combines them with the legacy Make-based module definitions to produce the complete view of 18// the source tree, which makes this a critical point of Make-Soong interoperability. 19// 20// Naturally, Soong-only builds do not rely on this mechanism. 21 22package android 23 24import ( 25 "bytes" 26 "fmt" 27 "io" 28 "os" 29 "path/filepath" 30 "reflect" 31 "runtime" 32 "sort" 33 "strconv" 34 "strings" 35 36 "github.com/google/blueprint" 37 "github.com/google/blueprint/bootstrap" 38 "github.com/google/blueprint/pathtools" 39 "github.com/google/blueprint/proptools" 40) 41 42func init() { 43 RegisterAndroidMkBuildComponents(InitRegistrationContext) 44} 45 46func RegisterAndroidMkBuildComponents(ctx RegistrationContext) { 47 ctx.RegisterParallelSingletonType("androidmk", AndroidMkSingleton) 48} 49 50// Enable androidmk support. 51// * Register the singleton 52// * Configure that we are inside make 53var PrepareForTestWithAndroidMk = GroupFixturePreparers( 54 FixtureRegisterWithContext(RegisterAndroidMkBuildComponents), 55 FixtureModifyConfig(SetKatiEnabledForTests), 56) 57 58// Deprecated: Use AndroidMkEntriesProvider instead, especially if you're not going to use the 59// Custom function. It's easier to use and test. 60type AndroidMkDataProvider interface { 61 AndroidMk() AndroidMkData 62 BaseModuleName() string 63} 64 65type AndroidMkData struct { 66 Class string 67 SubName string 68 DistFiles TaggedDistFiles 69 OutputFile OptionalPath 70 Disabled bool 71 Include string 72 Required []string 73 Host_required []string 74 Target_required []string 75 76 Custom func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) 77 78 Extra []AndroidMkExtraFunc 79 80 Entries AndroidMkEntries 81} 82 83type AndroidMkExtraFunc func(w io.Writer, outputFile Path) 84 85// Interface for modules to declare their Android.mk outputs. Note that every module needs to 86// implement this in order to be included in the final Android-<product_name>.mk output, even if 87// they only need to output the common set of entries without any customizations. 88type AndroidMkEntriesProvider interface { 89 // Returns AndroidMkEntries objects that contain all basic info plus extra customization data 90 // if needed. This is the core func to implement. 91 // Note that one can return multiple objects. For example, java_library may return an additional 92 // AndroidMkEntries object for its hostdex sub-module. 93 AndroidMkEntries() []AndroidMkEntries 94 // Modules don't need to implement this as it's already implemented by ModuleBase. 95 // AndroidMkEntries uses BaseModuleName() instead of ModuleName() because certain modules 96 // e.g. Prebuilts, override the Name() func and return modified names. 97 // If a different name is preferred, use SubName or OverrideName in AndroidMkEntries. 98 BaseModuleName() string 99} 100 101// The core data struct that modules use to provide their Android.mk data. 102type AndroidMkEntries struct { 103 // Android.mk class string, e.g EXECUTABLES, JAVA_LIBRARIES, ETC 104 Class string 105 // Optional suffix to append to the module name. Useful when a module wants to return multiple 106 // AndroidMkEntries objects. For example, when a java_library returns an additional entry for 107 // its hostdex sub-module, this SubName field is set to "-hostdex" so that it can have a 108 // different name than the parent's. 109 SubName string 110 // If set, this value overrides the base module name. SubName is still appended. 111 OverrideName string 112 // Dist files to output 113 DistFiles TaggedDistFiles 114 // The output file for Kati to process and/or install. If absent, the module is skipped. 115 OutputFile OptionalPath 116 // If true, the module is skipped and does not appear on the final Android-<product name>.mk 117 // file. Useful when a module needs to be skipped conditionally. 118 Disabled bool 119 // The postprocessing mk file to include, e.g. $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk 120 // If not set, $(BUILD_SYSTEM)/prebuilt.mk is used. 121 Include string 122 // Required modules that need to be built and included in the final build output when building 123 // this module. 124 Required []string 125 // Required host modules that need to be built and included in the final build output when 126 // building this module. 127 Host_required []string 128 // Required device modules that need to be built and included in the final build output when 129 // building this module. 130 Target_required []string 131 132 header bytes.Buffer 133 footer bytes.Buffer 134 135 // Funcs to append additional Android.mk entries or modify the common ones. Multiple funcs are 136 // accepted so that common logic can be factored out as a shared func. 137 ExtraEntries []AndroidMkExtraEntriesFunc 138 // Funcs to add extra lines to the module's Android.mk output. Unlike AndroidMkExtraEntriesFunc, 139 // which simply sets Make variable values, this can be used for anything since it can write any 140 // Make statements directly to the final Android-*.mk file. 141 // Primarily used to call macros or declare/update Make targets. 142 ExtraFooters []AndroidMkExtraFootersFunc 143 144 // A map that holds the up-to-date Make variable values. Can be accessed from tests. 145 EntryMap map[string][]string 146 // A list of EntryMap keys in insertion order. This serves a few purposes: 147 // 1. Prevents churns. Golang map doesn't provide consistent iteration order, so without this, 148 // the outputted Android-*.mk file may change even though there have been no content changes. 149 // 2. Allows modules to refer to other variables, like LOCAL_BAR_VAR := $(LOCAL_FOO_VAR), 150 // without worrying about the variables being mixed up in the actual mk file. 151 // 3. Makes troubleshooting and spotting errors easier. 152 entryOrder []string 153 154 // Provides data typically stored by Context objects that are commonly needed by 155 //AndroidMkEntries objects. 156 entryContext AndroidMkEntriesContext 157} 158 159type AndroidMkEntriesContext interface { 160 Config() Config 161} 162 163type AndroidMkExtraEntriesContext interface { 164 Provider(provider blueprint.AnyProviderKey) (any, bool) 165} 166 167type androidMkExtraEntriesContext struct { 168 ctx fillInEntriesContext 169 mod blueprint.Module 170} 171 172func (a *androidMkExtraEntriesContext) Provider(provider blueprint.AnyProviderKey) (any, bool) { 173 return a.ctx.moduleProvider(a.mod, provider) 174} 175 176type AndroidMkExtraEntriesFunc func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) 177type AndroidMkExtraFootersFunc func(w io.Writer, name, prefix, moduleDir string) 178 179// Utility funcs to manipulate Android.mk variable entries. 180 181// SetString sets a Make variable with the given name to the given value. 182func (a *AndroidMkEntries) SetString(name, value string) { 183 if _, ok := a.EntryMap[name]; !ok { 184 a.entryOrder = append(a.entryOrder, name) 185 } 186 a.EntryMap[name] = []string{value} 187} 188 189// SetPath sets a Make variable with the given name to the given path string. 190func (a *AndroidMkEntries) SetPath(name string, path Path) { 191 if _, ok := a.EntryMap[name]; !ok { 192 a.entryOrder = append(a.entryOrder, name) 193 } 194 a.EntryMap[name] = []string{path.String()} 195} 196 197// SetOptionalPath sets a Make variable with the given name to the given path string if it is valid. 198// It is a no-op if the given path is invalid. 199func (a *AndroidMkEntries) SetOptionalPath(name string, path OptionalPath) { 200 if path.Valid() { 201 a.SetPath(name, path.Path()) 202 } 203} 204 205// AddPath appends the given path string to a Make variable with the given name. 206func (a *AndroidMkEntries) AddPath(name string, path Path) { 207 if _, ok := a.EntryMap[name]; !ok { 208 a.entryOrder = append(a.entryOrder, name) 209 } 210 a.EntryMap[name] = append(a.EntryMap[name], path.String()) 211} 212 213// AddOptionalPath appends the given path string to a Make variable with the given name if it is 214// valid. It is a no-op if the given path is invalid. 215func (a *AndroidMkEntries) AddOptionalPath(name string, path OptionalPath) { 216 if path.Valid() { 217 a.AddPath(name, path.Path()) 218 } 219} 220 221// SetPaths sets a Make variable with the given name to a slice of the given path strings. 222func (a *AndroidMkEntries) SetPaths(name string, paths Paths) { 223 if _, ok := a.EntryMap[name]; !ok { 224 a.entryOrder = append(a.entryOrder, name) 225 } 226 a.EntryMap[name] = paths.Strings() 227} 228 229// SetOptionalPaths sets a Make variable with the given name to a slice of the given path strings 230// only if there are a non-zero amount of paths. 231func (a *AndroidMkEntries) SetOptionalPaths(name string, paths Paths) { 232 if len(paths) > 0 { 233 a.SetPaths(name, paths) 234 } 235} 236 237// AddPaths appends the given path strings to a Make variable with the given name. 238func (a *AndroidMkEntries) AddPaths(name string, paths Paths) { 239 if _, ok := a.EntryMap[name]; !ok { 240 a.entryOrder = append(a.entryOrder, name) 241 } 242 a.EntryMap[name] = append(a.EntryMap[name], paths.Strings()...) 243} 244 245// SetBoolIfTrue sets a Make variable with the given name to true if the given flag is true. 246// It is a no-op if the given flag is false. 247func (a *AndroidMkEntries) SetBoolIfTrue(name string, flag bool) { 248 if flag { 249 if _, ok := a.EntryMap[name]; !ok { 250 a.entryOrder = append(a.entryOrder, name) 251 } 252 a.EntryMap[name] = []string{"true"} 253 } 254} 255 256// SetBool sets a Make variable with the given name to if the given bool flag value. 257func (a *AndroidMkEntries) SetBool(name string, flag bool) { 258 if _, ok := a.EntryMap[name]; !ok { 259 a.entryOrder = append(a.entryOrder, name) 260 } 261 if flag { 262 a.EntryMap[name] = []string{"true"} 263 } else { 264 a.EntryMap[name] = []string{"false"} 265 } 266} 267 268// AddStrings appends the given strings to a Make variable with the given name. 269func (a *AndroidMkEntries) AddStrings(name string, value ...string) { 270 if len(value) == 0 { 271 return 272 } 273 if _, ok := a.EntryMap[name]; !ok { 274 a.entryOrder = append(a.entryOrder, name) 275 } 276 a.EntryMap[name] = append(a.EntryMap[name], value...) 277} 278 279// AddCompatibilityTestSuites adds the supplied test suites to the EntryMap, with special handling 280// for partial MTS and MCTS test suites. 281func (a *AndroidMkEntries) AddCompatibilityTestSuites(suites ...string) { 282 // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}. 283 // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite, 284 // we add the full test suite to our list. 285 if PrefixInList(suites, "mts-") && !InList("mts", suites) { 286 suites = append(suites, "mts") 287 } 288 if PrefixInList(suites, "mcts-") && !InList("mcts", suites) { 289 suites = append(suites, "mcts") 290 } 291 a.AddStrings("LOCAL_COMPATIBILITY_SUITE", suites...) 292} 293 294// The contributions to the dist. 295type distContributions struct { 296 // Path to license metadata file. 297 licenseMetadataFile Path 298 // List of goals and the dist copy instructions. 299 copiesForGoals []*copiesForGoals 300} 301 302// getCopiesForGoals returns a copiesForGoals into which copy instructions that 303// must be processed when building one or more of those goals can be added. 304func (d *distContributions) getCopiesForGoals(goals string) *copiesForGoals { 305 copiesForGoals := &copiesForGoals{goals: goals} 306 d.copiesForGoals = append(d.copiesForGoals, copiesForGoals) 307 return copiesForGoals 308} 309 310// Associates a list of dist copy instructions with a set of goals for which they 311// should be run. 312type copiesForGoals struct { 313 // goals are a space separated list of build targets that will trigger the 314 // copy instructions. 315 goals string 316 317 // A list of instructions to copy a module's output files to somewhere in the 318 // dist directory. 319 copies []distCopy 320} 321 322// Adds a copy instruction. 323func (d *copiesForGoals) addCopyInstruction(from Path, dest string) { 324 d.copies = append(d.copies, distCopy{from, dest}) 325} 326 327// Instruction on a path that must be copied into the dist. 328type distCopy struct { 329 // The path to copy from. 330 from Path 331 332 // The destination within the dist directory to copy to. 333 dest string 334} 335 336// Compute the contributions that the module makes to the dist. 337func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContributions { 338 amod := mod.(Module).base() 339 name := amod.BaseModuleName() 340 341 // Collate the set of associated tag/paths available for copying to the dist. 342 // Start with an empty (nil) set. 343 var availableTaggedDists TaggedDistFiles 344 345 // Then merge in any that are provided explicitly by the module. 346 if a.DistFiles != nil { 347 // Merge the DistFiles into the set. 348 availableTaggedDists = availableTaggedDists.merge(a.DistFiles) 349 } 350 351 // If no paths have been provided for the DefaultDistTag and the output file is 352 // valid then add that as the default dist path. 353 if _, ok := availableTaggedDists[DefaultDistTag]; !ok && a.OutputFile.Valid() { 354 availableTaggedDists = availableTaggedDists.addPathsForTag(DefaultDistTag, a.OutputFile.Path()) 355 } 356 357 // If the distFiles created by GenerateTaggedDistFiles contains paths for the 358 // DefaultDistTag then that takes priority so delete any existing paths. 359 if _, ok := amod.distFiles[DefaultDistTag]; ok { 360 delete(availableTaggedDists, DefaultDistTag) 361 } 362 363 // Finally, merge the distFiles created by GenerateTaggedDistFiles. 364 availableTaggedDists = availableTaggedDists.merge(amod.distFiles) 365 366 if len(availableTaggedDists) == 0 { 367 // Nothing dist-able for this module. 368 return nil 369 } 370 371 // Collate the contributions this module makes to the dist. 372 distContributions := &distContributions{} 373 374 if !exemptFromRequiredApplicableLicensesProperty(mod.(Module)) { 375 distContributions.licenseMetadataFile = amod.licenseMetadataFile 376 } 377 378 // Iterate over this module's dist structs, merged from the dist and dists properties. 379 for _, dist := range amod.Dists() { 380 // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore 381 goals := strings.Join(dist.Targets, " ") 382 383 // Get the tag representing the output files to be dist'd. e.g. ".jar", ".proguard_map" 384 var tag string 385 if dist.Tag == nil { 386 // If the dist struct does not specify a tag, use the default output files tag. 387 tag = DefaultDistTag 388 } else { 389 tag = *dist.Tag 390 } 391 392 // Get the paths of the output files to be dist'd, represented by the tag. 393 // Can be an empty list. 394 tagPaths := availableTaggedDists[tag] 395 if len(tagPaths) == 0 { 396 // Nothing to dist for this tag, continue to the next dist. 397 continue 398 } 399 400 if len(tagPaths) > 1 && (dist.Dest != nil || dist.Suffix != nil) { 401 errorMessage := "%s: Cannot apply dest/suffix for more than one dist " + 402 "file for %q goals tag %q in module %s. The list of dist files, " + 403 "which should have a single element, is:\n%s" 404 panic(fmt.Errorf(errorMessage, mod, goals, tag, name, tagPaths)) 405 } 406 407 copiesForGoals := distContributions.getCopiesForGoals(goals) 408 409 // Iterate over each path adding a copy instruction to copiesForGoals 410 for _, path := range tagPaths { 411 // It's possible that the Path is nil from errant modules. Be defensive here. 412 if path == nil { 413 tagName := "default" // for error message readability 414 if dist.Tag != nil { 415 tagName = *dist.Tag 416 } 417 panic(fmt.Errorf("Dist file should not be nil for the %s tag in %s", tagName, name)) 418 } 419 420 dest := filepath.Base(path.String()) 421 422 if dist.Dest != nil { 423 var err error 424 if dest, err = validateSafePath(*dist.Dest); err != nil { 425 // This was checked in ModuleBase.GenerateBuildActions 426 panic(err) 427 } 428 } 429 430 ext := filepath.Ext(dest) 431 suffix := "" 432 if dist.Suffix != nil { 433 suffix = *dist.Suffix 434 } 435 436 productString := "" 437 if dist.Append_artifact_with_product != nil && *dist.Append_artifact_with_product { 438 productString = fmt.Sprintf("_%s", a.entryContext.Config().DeviceProduct()) 439 } 440 441 if suffix != "" || productString != "" { 442 dest = strings.TrimSuffix(dest, ext) + suffix + productString + ext 443 } 444 445 if dist.Dir != nil { 446 var err error 447 if dest, err = validateSafePath(*dist.Dir, dest); err != nil { 448 // This was checked in ModuleBase.GenerateBuildActions 449 panic(err) 450 } 451 } 452 453 copiesForGoals.addCopyInstruction(path, dest) 454 } 455 } 456 457 return distContributions 458} 459 460// generateDistContributionsForMake generates make rules that will generate the 461// dist according to the instructions in the supplied distContribution. 462func generateDistContributionsForMake(distContributions *distContributions) []string { 463 var ret []string 464 for _, d := range distContributions.copiesForGoals { 465 ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals)) 466 // Create dist-for-goals calls for each of the copy instructions. 467 for _, c := range d.copies { 468 if distContributions.licenseMetadataFile != nil { 469 ret = append( 470 ret, 471 fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n", 472 c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String())) 473 } 474 ret = append( 475 ret, 476 fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest)) 477 } 478 } 479 480 return ret 481} 482 483// Compute the list of Make strings to declare phony goals and dist-for-goals 484// calls from the module's dist and dists properties. 485func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { 486 distContributions := a.getDistContributions(mod) 487 if distContributions == nil { 488 return nil 489 } 490 491 return generateDistContributionsForMake(distContributions) 492} 493 494// fillInEntries goes through the common variable processing and calls the extra data funcs to 495// generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file. 496type fillInEntriesContext interface { 497 ModuleDir(module blueprint.Module) string 498 ModuleSubDir(module blueprint.Module) string 499 Config() Config 500 moduleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) 501 ModuleType(module blueprint.Module) string 502} 503 504func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint.Module) { 505 a.entryContext = ctx 506 a.EntryMap = make(map[string][]string) 507 amod := mod.(Module) 508 base := amod.base() 509 name := base.BaseModuleName() 510 if a.OverrideName != "" { 511 name = a.OverrideName 512 } 513 514 if a.Include == "" { 515 a.Include = "$(BUILD_PREBUILT)" 516 } 517 a.Required = append(a.Required, amod.RequiredModuleNames()...) 518 a.Host_required = append(a.Host_required, amod.HostRequiredModuleNames()...) 519 a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...) 520 521 for _, distString := range a.GetDistForGoals(mod) { 522 fmt.Fprintf(&a.header, distString) 523 } 524 525 fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)) 526 527 // Collect make variable assignment entries. 528 a.SetString("LOCAL_PATH", ctx.ModuleDir(mod)) 529 a.SetString("LOCAL_MODULE", name+a.SubName) 530 a.SetString("LOCAL_MODULE_CLASS", a.Class) 531 a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) 532 a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) 533 a.AddStrings("LOCAL_HOST_REQUIRED_MODULES", a.Host_required...) 534 a.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", a.Target_required...) 535 a.AddStrings("LOCAL_SOONG_MODULE_TYPE", ctx.ModuleType(amod)) 536 537 // If the install rule was generated by Soong tell Make about it. 538 if len(base.katiInstalls) > 0 { 539 // Assume the primary install file is last since it probably needs to depend on any other 540 // installed files. If that is not the case we can add a method to specify the primary 541 // installed file. 542 a.SetPath("LOCAL_SOONG_INSTALLED_MODULE", base.katiInstalls[len(base.katiInstalls)-1].to) 543 a.SetString("LOCAL_SOONG_INSTALL_PAIRS", base.katiInstalls.BuiltInstalled()) 544 a.SetPaths("LOCAL_SOONG_INSTALL_SYMLINKS", base.katiSymlinks.InstallPaths().Paths()) 545 } else { 546 // Soong may not have generated the install rule also when `no_full_install: true`. 547 // Mark this module as uninstallable in order to prevent Make from creating an 548 // install rule there. 549 a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install)) 550 } 551 552 if len(base.testData) > 0 { 553 a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(base.testData)...) 554 } 555 556 if am, ok := mod.(ApexModule); ok { 557 a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform()) 558 } 559 560 archStr := base.Arch().ArchType.String() 561 host := false 562 switch base.Os().Class { 563 case Host: 564 if base.Target().HostCross { 565 // Make cannot identify LOCAL_MODULE_HOST_CROSS_ARCH:= common. 566 if base.Arch().ArchType != Common { 567 a.SetString("LOCAL_MODULE_HOST_CROSS_ARCH", archStr) 568 } 569 } else { 570 // Make cannot identify LOCAL_MODULE_HOST_ARCH:= common. 571 if base.Arch().ArchType != Common { 572 a.SetString("LOCAL_MODULE_HOST_ARCH", archStr) 573 } 574 } 575 host = true 576 case Device: 577 // Make cannot identify LOCAL_MODULE_TARGET_ARCH:= common. 578 if base.Arch().ArchType != Common { 579 if base.Target().NativeBridge { 580 hostArchStr := base.Target().NativeBridgeHostArchName 581 if hostArchStr != "" { 582 a.SetString("LOCAL_MODULE_TARGET_ARCH", hostArchStr) 583 } 584 } else { 585 a.SetString("LOCAL_MODULE_TARGET_ARCH", archStr) 586 } 587 } 588 589 if !base.InVendorRamdisk() { 590 a.AddPaths("LOCAL_FULL_INIT_RC", base.initRcPaths) 591 } 592 if len(base.vintfFragmentsPaths) > 0 { 593 a.AddPaths("LOCAL_FULL_VINTF_FRAGMENTS", base.vintfFragmentsPaths) 594 } 595 a.SetBoolIfTrue("LOCAL_PROPRIETARY_MODULE", Bool(base.commonProperties.Proprietary)) 596 if Bool(base.commonProperties.Vendor) || Bool(base.commonProperties.Soc_specific) { 597 a.SetString("LOCAL_VENDOR_MODULE", "true") 598 } 599 a.SetBoolIfTrue("LOCAL_ODM_MODULE", Bool(base.commonProperties.Device_specific)) 600 a.SetBoolIfTrue("LOCAL_PRODUCT_MODULE", Bool(base.commonProperties.Product_specific)) 601 a.SetBoolIfTrue("LOCAL_SYSTEM_EXT_MODULE", Bool(base.commonProperties.System_ext_specific)) 602 if base.commonProperties.Owner != nil { 603 a.SetString("LOCAL_MODULE_OWNER", *base.commonProperties.Owner) 604 } 605 } 606 607 if host { 608 makeOs := base.Os().String() 609 if base.Os() == Linux || base.Os() == LinuxBionic || base.Os() == LinuxMusl { 610 makeOs = "linux" 611 } 612 a.SetString("LOCAL_MODULE_HOST_OS", makeOs) 613 a.SetString("LOCAL_IS_HOST_MODULE", "true") 614 } 615 616 prefix := "" 617 if base.ArchSpecific() { 618 switch base.Os().Class { 619 case Host: 620 if base.Target().HostCross { 621 prefix = "HOST_CROSS_" 622 } else { 623 prefix = "HOST_" 624 } 625 case Device: 626 prefix = "TARGET_" 627 628 } 629 630 if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType { 631 prefix = "2ND_" + prefix 632 } 633 } 634 635 if licenseMetadata, ok := SingletonModuleProvider(ctx, mod, LicenseMetadataProvider); ok { 636 a.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath) 637 } 638 639 if _, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { 640 a.SetBool("LOCAL_SOONG_MODULE_INFO_JSON", true) 641 } 642 643 extraCtx := &androidMkExtraEntriesContext{ 644 ctx: ctx, 645 mod: mod, 646 } 647 648 for _, extra := range a.ExtraEntries { 649 extra(extraCtx, a) 650 } 651 652 // Write to footer. 653 fmt.Fprintln(&a.footer, "include "+a.Include) 654 blueprintDir := ctx.ModuleDir(mod) 655 for _, footerFunc := range a.ExtraFooters { 656 footerFunc(&a.footer, name, prefix, blueprintDir) 657 } 658} 659 660func (a *AndroidMkEntries) disabled() bool { 661 return a.Disabled || !a.OutputFile.Valid() 662} 663 664// write flushes the AndroidMkEntries's in-struct data populated by AndroidMkEntries into the 665// given Writer object. 666func (a *AndroidMkEntries) write(w io.Writer) { 667 if a.disabled() { 668 return 669 } 670 671 w.Write(a.header.Bytes()) 672 for _, name := range a.entryOrder { 673 AndroidMkEmitAssignList(w, name, a.EntryMap[name]) 674 } 675 w.Write(a.footer.Bytes()) 676} 677 678func (a *AndroidMkEntries) FooterLinesForTests() []string { 679 return strings.Split(string(a.footer.Bytes()), "\n") 680} 681 682// AndroidMkSingleton is a singleton to collect Android.mk data from all modules and dump them into 683// the final Android-<product_name>.mk file output. 684func AndroidMkSingleton() Singleton { 685 return &androidMkSingleton{} 686} 687 688type androidMkSingleton struct{} 689 690func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { 691 // Skip if Soong wasn't invoked from Make. 692 if !ctx.Config().KatiEnabled() { 693 return 694 } 695 696 var androidMkModulesList []blueprint.Module 697 698 ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { 699 androidMkModulesList = append(androidMkModulesList, module) 700 }) 701 702 // Sort the module list by the module names to eliminate random churns, which may erroneously 703 // invoke additional build processes. 704 sort.SliceStable(androidMkModulesList, func(i, j int) bool { 705 return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j]) 706 }) 707 708 transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk") 709 if ctx.Failed() { 710 return 711 } 712 713 moduleInfoJSON := PathForOutput(ctx, "module-info"+String(ctx.Config().productVariables.Make_suffix)+".json") 714 715 err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, androidMkModulesList) 716 if err != nil { 717 ctx.Errorf(err.Error()) 718 } 719 720 ctx.Build(pctx, BuildParams{ 721 Rule: blueprint.Phony, 722 Output: transMk, 723 }) 724} 725 726func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []blueprint.Module) error { 727 buf := &bytes.Buffer{} 728 729 var moduleInfoJSONs []*ModuleInfoJSON 730 731 fmt.Fprintln(buf, "LOCAL_MODULE_MAKEFILE := $(lastword $(MAKEFILE_LIST))") 732 733 typeStats := make(map[string]int) 734 for _, mod := range mods { 735 err := translateAndroidMkModule(ctx, buf, &moduleInfoJSONs, mod) 736 if err != nil { 737 os.Remove(absMkFile) 738 return err 739 } 740 741 if amod, ok := mod.(Module); ok && ctx.PrimaryModule(amod) == amod { 742 typeStats[ctx.ModuleType(amod)] += 1 743 } 744 } 745 746 keys := []string{} 747 fmt.Fprintln(buf, "\nSTATS.SOONG_MODULE_TYPE :=") 748 for k := range typeStats { 749 keys = append(keys, k) 750 } 751 sort.Strings(keys) 752 for _, mod_type := range keys { 753 fmt.Fprintln(buf, "STATS.SOONG_MODULE_TYPE +=", mod_type) 754 fmt.Fprintf(buf, "STATS.SOONG_MODULE_TYPE.%s := %d\n", mod_type, typeStats[mod_type]) 755 } 756 757 err := pathtools.WriteFileIfChanged(absMkFile, buf.Bytes(), 0666) 758 if err != nil { 759 return err 760 } 761 762 return writeModuleInfoJSON(ctx, moduleInfoJSONs, moduleInfoJSONPath) 763} 764 765func writeModuleInfoJSON(ctx SingletonContext, moduleInfoJSONs []*ModuleInfoJSON, moduleInfoJSONPath WritablePath) error { 766 moduleInfoJSONBuf := &strings.Builder{} 767 moduleInfoJSONBuf.WriteString("[") 768 for i, moduleInfoJSON := range moduleInfoJSONs { 769 if i != 0 { 770 moduleInfoJSONBuf.WriteString(",\n") 771 } 772 moduleInfoJSONBuf.WriteString("{") 773 moduleInfoJSONBuf.WriteString(strconv.Quote(moduleInfoJSON.core.RegisterName)) 774 moduleInfoJSONBuf.WriteString(":") 775 err := encodeModuleInfoJSON(moduleInfoJSONBuf, moduleInfoJSON) 776 moduleInfoJSONBuf.WriteString("}") 777 if err != nil { 778 return err 779 } 780 } 781 moduleInfoJSONBuf.WriteString("]") 782 WriteFileRule(ctx, moduleInfoJSONPath, moduleInfoJSONBuf.String()) 783 return nil 784} 785 786func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod blueprint.Module) error { 787 defer func() { 788 if r := recover(); r != nil { 789 panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s", 790 r, ctx.ModuleName(mod), ctx.ModuleSubDir(mod))) 791 } 792 }() 793 794 // Additional cases here require review for correct license propagation to make. 795 var err error 796 switch x := mod.(type) { 797 case AndroidMkDataProvider: 798 err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x) 799 case bootstrap.GoBinaryTool: 800 err = translateGoBinaryModule(ctx, w, mod, x) 801 case AndroidMkEntriesProvider: 802 err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x) 803 default: 804 // Not exported to make so no make variables to set. 805 } 806 807 if err != nil { 808 return err 809 } 810 811 return err 812} 813 814// A simple, special Android.mk entry output func to make it possible to build blueprint tools using 815// m by making them phony targets. 816func translateGoBinaryModule(ctx SingletonContext, w io.Writer, mod blueprint.Module, 817 goBinary bootstrap.GoBinaryTool) error { 818 819 name := ctx.ModuleName(mod) 820 fmt.Fprintln(w, ".PHONY:", name) 821 fmt.Fprintln(w, name+":", goBinary.InstallPath()) 822 fmt.Fprintln(w, "") 823 // Assuming no rules in make include go binaries in distributables. 824 // If the assumption is wrong, make will fail to build without the necessary .meta_lic and .meta_module files. 825 // In that case, add the targets and rules here to build a .meta_lic file for `name` and a .meta_module for 826 // `goBinary.InstallPath()` pointing to the `name`.meta_lic file. 827 828 return nil 829} 830 831func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Module) { 832 // Get the preamble content through AndroidMkEntries logic. 833 data.Entries = AndroidMkEntries{ 834 Class: data.Class, 835 SubName: data.SubName, 836 DistFiles: data.DistFiles, 837 OutputFile: data.OutputFile, 838 Disabled: data.Disabled, 839 Include: data.Include, 840 Required: data.Required, 841 Host_required: data.Host_required, 842 Target_required: data.Target_required, 843 } 844 data.Entries.fillInEntries(ctx, mod) 845 846 // copy entries back to data since it is used in Custom 847 data.Required = data.Entries.Required 848 data.Host_required = data.Entries.Host_required 849 data.Target_required = data.Entries.Target_required 850} 851 852// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider 853// instead. 854func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, 855 mod blueprint.Module, provider AndroidMkDataProvider) error { 856 857 amod := mod.(Module).base() 858 if shouldSkipAndroidMkProcessing(ctx, amod) { 859 return nil 860 } 861 862 data := provider.AndroidMk() 863 if data.Include == "" { 864 data.Include = "$(BUILD_PREBUILT)" 865 } 866 867 data.fillInData(ctx, mod) 868 aconfigUpdateAndroidMkData(ctx, mod.(Module), &data) 869 870 prefix := "" 871 if amod.ArchSpecific() { 872 switch amod.Os().Class { 873 case Host: 874 if amod.Target().HostCross { 875 prefix = "HOST_CROSS_" 876 } else { 877 prefix = "HOST_" 878 } 879 case Device: 880 prefix = "TARGET_" 881 882 } 883 884 if amod.Arch().ArchType != ctx.Config().Targets[amod.Os()][0].Arch.ArchType { 885 prefix = "2ND_" + prefix 886 } 887 } 888 889 name := provider.BaseModuleName() 890 blueprintDir := filepath.Dir(ctx.BlueprintFile(mod)) 891 892 if data.Custom != nil { 893 // List of module types allowed to use .Custom(...) 894 // Additions to the list require careful review for proper license handling. 895 switch reflect.TypeOf(mod).String() { // ctx.ModuleType(mod) doesn't work: aidl_interface creates phony without type 896 case "*aidl.aidlApi": // writes non-custom before adding .phony 897 case "*aidl.aidlMapping": // writes non-custom before adding .phony 898 case "*android.customModule": // appears in tests only 899 case "*android_sdk.sdkRepoHost": // doesn't go through base_rules 900 case "*apex.apexBundle": // license properties written 901 case "*bpf.bpf": // license properties written (both for module and objs) 902 case "*genrule.Module": // writes non-custom before adding .phony 903 case "*java.SystemModules": // doesn't go through base_rules 904 case "*java.systemModulesImport": // doesn't go through base_rules 905 case "*phony.phony": // license properties written 906 case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY` 907 case "*selinux.selinuxContextsModule": // license properties written 908 case "*sysprop.syspropLibrary": // license properties written 909 default: 910 if !ctx.Config().IsEnvFalse("ANDROID_REQUIRE_LICENSES") { 911 return fmt.Errorf("custom make rules not allowed for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), ctx.ModuleName(mod)) 912 } 913 } 914 data.Custom(w, name, prefix, blueprintDir, data) 915 } else { 916 WriteAndroidMkData(w, data) 917 } 918 919 if !data.Entries.disabled() { 920 if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { 921 *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) 922 } 923 } 924 925 return nil 926} 927 928// A support func for the deprecated AndroidMkDataProvider interface. Use AndroidMkEntryProvider 929// instead. 930func WriteAndroidMkData(w io.Writer, data AndroidMkData) { 931 if data.Entries.disabled() { 932 return 933 } 934 935 // write preamble via Entries 936 data.Entries.footer = bytes.Buffer{} 937 data.Entries.write(w) 938 939 for _, extra := range data.Extra { 940 extra(w, data.OutputFile.Path()) 941 } 942 943 fmt.Fprintln(w, "include "+data.Include) 944} 945 946func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, 947 mod blueprint.Module, provider AndroidMkEntriesProvider) error { 948 if shouldSkipAndroidMkProcessing(ctx, mod.(Module).base()) { 949 return nil 950 } 951 952 entriesList := provider.AndroidMkEntries() 953 aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList) 954 955 // Any new or special cases here need review to verify correct propagation of license information. 956 for _, entries := range entriesList { 957 entries.fillInEntries(ctx, mod) 958 entries.write(w) 959 } 960 961 if len(entriesList) > 0 && !entriesList[0].disabled() { 962 if moduleInfoJSON, ok := SingletonModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { 963 *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) 964 } 965 } 966 967 return nil 968} 969 970func ShouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module Module) bool { 971 return shouldSkipAndroidMkProcessing(ctx, module.base()) 972} 973 974func shouldSkipAndroidMkProcessing(ctx ConfigAndErrorContext, module *ModuleBase) bool { 975 if !module.commonProperties.NamespaceExportedToMake { 976 // TODO(jeffrygaston) do we want to validate that there are no modules being 977 // exported to Kati that depend on this module? 978 return true 979 } 980 981 // On Mac, only expose host darwin modules to Make, as that's all we claim to support. 982 // In reality, some of them depend on device-built (Java) modules, so we can't disable all 983 // device modules in Soong, but we can hide them from Make (and thus the build user interface) 984 if runtime.GOOS == "darwin" && module.Os() != Darwin { 985 return true 986 } 987 988 // Only expose the primary Darwin target, as Make does not understand Darwin+Arm64 989 if module.Os() == Darwin && module.Target().HostCross { 990 return true 991 } 992 993 return !module.Enabled(ctx) || 994 module.commonProperties.HideFromMake || 995 // Make does not understand LinuxBionic 996 module.Os() == LinuxBionic || 997 // Make does not understand LinuxMusl, except when we are building with USE_HOST_MUSL=true 998 // and all host binaries are LinuxMusl 999 (module.Os() == LinuxMusl && module.Target().HostCross) 1000} 1001 1002// A utility func to format LOCAL_TEST_DATA outputs. See the comments on DataPath to understand how 1003// to use this func. 1004func androidMkDataPaths(data []DataPath) []string { 1005 var testFiles []string 1006 for _, d := range data { 1007 rel := d.SrcPath.Rel() 1008 if d.WithoutRel { 1009 rel = d.SrcPath.Base() 1010 } 1011 path := d.SrcPath.String() 1012 // LOCAL_TEST_DATA requires the rel portion of the path to be removed from the path. 1013 if !strings.HasSuffix(path, rel) { 1014 panic(fmt.Errorf("path %q does not end with %q", path, rel)) 1015 } 1016 path = strings.TrimSuffix(path, rel) 1017 testFileString := path + ":" + rel 1018 if len(d.RelativeInstallPath) > 0 { 1019 testFileString += ":" + d.RelativeInstallPath 1020 } 1021 testFiles = append(testFiles, testFileString) 1022 } 1023 return testFiles 1024} 1025 1026// AndroidMkEmitAssignList emits the line 1027// 1028// VAR := ITEM ... 1029// 1030// Items are the elements to the given set of lists 1031// If all the passed lists are empty, no line will be emitted 1032func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) { 1033 doPrint := false 1034 for _, l := range lists { 1035 if doPrint = len(l) > 0; doPrint { 1036 break 1037 } 1038 } 1039 if !doPrint { 1040 return 1041 } 1042 fmt.Fprint(w, varName, " :=") 1043 for _, l := range lists { 1044 for _, item := range l { 1045 fmt.Fprint(w, " ", item) 1046 } 1047 } 1048 fmt.Fprintln(w) 1049} 1050