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 "fmt" 19 "path" 20 "path/filepath" 21 "slices" 22 "strings" 23 24 "github.com/google/blueprint" 25 "github.com/google/blueprint/depset" 26 "github.com/google/blueprint/proptools" 27 "github.com/google/blueprint/uniquelist" 28) 29 30// BuildParameters describes the set of potential parameters to build a Ninja rule. 31// In general, these correspond to a Ninja concept. 32type BuildParams struct { 33 // A Ninja Rule that will be written to the Ninja file. This allows factoring out common code 34 // among multiple modules to reduce repetition in the Ninja file of action requirements. A rule 35 // can contain variables that should be provided in Args. 36 Rule blueprint.Rule 37 // Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles 38 // are used. 39 Deps blueprint.Deps 40 // Depfile is a writeable path that allows correct incremental builds when the inputs have not 41 // been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax. 42 Depfile WritablePath 43 // A description of the build action. 44 Description string 45 // Output is an output file of the action. When using this field, references to $out in the Ninja 46 // command will refer to this file. 47 Output WritablePath 48 // Outputs is a slice of output file of the action. When using this field, references to $out in 49 // the Ninja command will refer to these files. 50 Outputs WritablePaths 51 // ImplicitOutput is an output file generated by the action. Note: references to `$out` in the 52 // Ninja command will NOT include references to this file. 53 ImplicitOutput WritablePath 54 // ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out` 55 // in the Ninja command will NOT include references to these files. 56 ImplicitOutputs WritablePaths 57 // Input is an input file to the Ninja action. When using this field, references to $in in the 58 // Ninja command will refer to this file. 59 Input Path 60 // Inputs is a slice of input files to the Ninja action. When using this field, references to $in 61 // in the Ninja command will refer to these files. 62 Inputs Paths 63 // Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command 64 // will NOT include references to this file. 65 Implicit Path 66 // Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja 67 // command will NOT include references to these files. 68 Implicits Paths 69 // OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is 70 // not rebuilt until they are built, but changes in order-only dependencies alone do not cause the 71 // output to be rebuilt. 72 OrderOnly Paths 73 // Validation is an output path for a validation action. Validation outputs imply lower 74 // non-blocking priority to building non-validation outputs. 75 Validation Path 76 // Validations is a slice of output path for a validation action. Validation outputs imply lower 77 // non-blocking priority to building non-validation outputs. 78 Validations Paths 79 // Whether to output a default target statement which will be built by Ninja when no 80 // targets are specified on Ninja's command line. 81 Default bool 82 // Args is a key value mapping for replacements of variables within the Rule 83 Args map[string]string 84 // PhonyOutput marks this build as `phony_output = true` 85 PhonyOutput bool 86} 87 88type ModuleBuildParams BuildParams 89 90type ModuleContext interface { 91 BaseModuleContext 92 93 // BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps. It may only be 94 // used by the golang module types that need to call into the bootstrap module types. 95 BlueprintModuleContext() blueprint.ModuleContext 96 97 // Deprecated: use ModuleContext.Build instead. 98 ModuleBuild(pctx PackageContext, params ModuleBuildParams) 99 100 // Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must 101 // be tagged with `android:"path" to support automatic source module dependency resolution. 102 // 103 // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. 104 ExpandSources(srcFiles, excludes []string) Paths 105 106 // Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must 107 // be tagged with `android:"path" to support automatic source module dependency resolution. 108 // 109 // Deprecated: use PathForModuleSrc instead. 110 ExpandSource(srcFile, prop string) Path 111 112 ExpandOptionalSource(srcFile *string, prop string) OptionalPath 113 114 // InstallExecutable creates a rule to copy srcPath to name in the installPath directory, 115 // with the given additional dependencies. The file is marked executable after copying. 116 // 117 // The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 118 // for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module 119 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 120 // dependency tags for which IsInstallDepNeeded returns true. 121 InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath 122 123 // InstallFile creates a rule to copy srcPath to name in the installPath directory, 124 // with the given additional dependencies. 125 // 126 // The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 127 // for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module 128 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 129 // dependency tags for which IsInstallDepNeeded returns true. 130 InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath 131 132 // InstallFileWithoutCheckbuild creates a rule to copy srcPath to name in the installPath directory, 133 // with the given additional dependencies, but does not add the file to the list of files to build 134 // during `m checkbuild`. 135 // 136 // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the 137 // installed file will be returned by PackagingSpecs() on this module or by 138 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags 139 // for which IsInstallDepNeeded returns true. 140 InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath 141 142 // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath 143 // directory, and also unzip a zip file containing extra files to install into the same 144 // directory. 145 // 146 // The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 147 // for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module 148 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 149 // dependency tags for which IsInstallDepNeeded returns true. 150 InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath 151 152 // InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath 153 // directory. 154 // 155 // The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 156 // for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module 157 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 158 // dependency tags for which IsInstallDepNeeded returns true. 159 InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath 160 161 // InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name 162 // in the installPath directory. 163 // 164 // The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 165 // for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module 166 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 167 // dependency tags for which IsInstallDepNeeded returns true. 168 InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath 169 170 // InstallTestData creates rules to install test data (e.g. data files used during a test) into 171 // the installPath directory. 172 // 173 // The installed files can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec 174 // for the installed files can be accessed by InstallFilesInfo.PackagingSpecs on this module 175 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 176 // dependency tags for which IsInstallDepNeeded returns true. 177 InstallTestData(installPath InstallPath, data []DataPath) InstallPaths 178 179 // PackageFile creates a PackagingSpec as if InstallFile was called, but without creating 180 // the rule to copy the file. This is useful to define how a module would be packaged 181 // without installing it into the global installation directories. 182 // 183 // The created PackagingSpec can be accessed by InstallFilesInfo.PackagingSpecs on this module 184 // or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through 185 // dependency tags for which IsInstallDepNeeded returns true. 186 PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec 187 188 CheckbuildFile(srcPaths ...Path) 189 UncheckedModule() 190 191 InstallInData() bool 192 InstallInTestcases() bool 193 InstallInSanitizerDir() bool 194 InstallInRamdisk() bool 195 InstallInVendorRamdisk() bool 196 InstallInDebugRamdisk() bool 197 InstallInRecovery() bool 198 InstallInRoot() bool 199 InstallInOdm() bool 200 InstallInProduct() bool 201 InstallInVendor() bool 202 InstallInSystemDlkm() bool 203 InstallInVendorDlkm() bool 204 InstallInOdmDlkm() bool 205 InstallForceOS() (*OsType, *ArchType) 206 207 RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string 208 HostRequiredModuleNames() []string 209 TargetRequiredModuleNames() []string 210 211 ModuleSubDir() string 212 213 Variable(pctx PackageContext, name, value string) 214 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule 215 // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string, 216 // and performs more verification. 217 Build(pctx PackageContext, params BuildParams) 218 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other 219 // phony rules or real files. Phony can be called on the same name multiple times to add 220 // additional dependencies. 221 Phony(phony string, deps ...Path) 222 223 // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, 224 // but do not exist. 225 GetMissingDependencies() []string 226 227 // LicenseMetadataFile returns the path where the license metadata for this module will be 228 // generated. 229 LicenseMetadataFile() Path 230 231 // ModuleInfoJSON returns a pointer to the ModuleInfoJSON struct that can be filled out by 232 // GenerateAndroidBuildActions. If it is called then the struct will be written out and included in 233 // the module-info.json generated by Make, and Make will not generate its own data for this module. 234 ModuleInfoJSON() *ModuleInfoJSON 235 236 // Simiar to ModuleInfoJSON, ExtraModuleInfoJSON also returns a pointer to the ModuleInfoJSON struct. 237 // This should only be called by a module that generates multiple AndroidMkEntries struct. 238 ExtraModuleInfoJSON() *ModuleInfoJSON 239 240 // SetOutputFiles stores the outputFiles to outputFiles property, which is used 241 // to set the OutputFilesProvider later. 242 SetOutputFiles(outputFiles Paths, tag string) 243 244 GetOutputFiles() OutputFilesInfo 245 246 // SetLicenseInstallMap stores the set of dependency module:location mappings for files in an 247 // apex container for use when generation the license metadata file. 248 SetLicenseInstallMap(installMap []string) 249 250 // ComplianceMetadataInfo returns a ComplianceMetadataInfo instance for different module types to dump metadata, 251 // which usually happens in GenerateAndroidBuildActions() of a module type. 252 // See android.ModuleBase.complianceMetadataInfo 253 ComplianceMetadataInfo() *ComplianceMetadataInfo 254 255 // Get the information about the containers this module belongs to. 256 getContainersInfo() ContainersInfo 257 setContainersInfo(info ContainersInfo) 258 259 setAconfigPaths(paths Paths) 260 261 // DistForGoals creates a rule to copy one or more Paths to the artifacts 262 // directory on the build server when any of the specified goals are built. 263 DistForGoal(goal string, paths ...Path) 264 265 // DistForGoalWithFilename creates a rule to copy a Path to the artifacts 266 // directory on the build server with the given filename when the specified 267 // goal is built. 268 DistForGoalWithFilename(goal string, path Path, filename string) 269 270 // DistForGoals creates a rule to copy one or more Paths to the artifacts 271 // directory on the build server when any of the specified goals are built. 272 DistForGoals(goals []string, paths ...Path) 273 274 // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts 275 // directory on the build server with the given filename when any of the 276 // specified goals are built. 277 DistForGoalsWithFilename(goals []string, path Path, filename string) 278} 279 280type moduleContext struct { 281 bp blueprint.ModuleContext 282 baseModuleContext 283 packagingSpecs []PackagingSpec 284 installFiles InstallPaths 285 checkbuildFiles Paths 286 checkbuildTarget Path 287 uncheckedModule bool 288 module Module 289 phonies map[string]Paths 290 // outputFiles stores the output of a module by tag and is used to set 291 // the OutputFilesProvider in GenerateBuildActions 292 outputFiles OutputFilesInfo 293 294 TransitiveInstallFiles depset.DepSet[InstallPath] 295 296 // set of dependency module:location mappings used to populate the license metadata for 297 // apex containers. 298 licenseInstallMap []string 299 300 // The path to the generated license metadata file for the module. 301 licenseMetadataFile WritablePath 302 303 katiInstalls katiInstalls 304 katiSymlinks katiInstalls 305 // katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are 306 // allowed to have duplicates across modules and variants. 307 katiInitRcInstalls katiInstalls 308 katiVintfInstalls katiInstalls 309 initRcPaths Paths 310 vintfFragmentsPaths Paths 311 installedInitRcPaths InstallPaths 312 installedVintfFragmentsPaths InstallPaths 313 314 testData []DataPath 315 316 // For tests 317 buildParams []BuildParams 318 ruleParams map[blueprint.Rule]blueprint.RuleParams 319 variables map[string]string 320 321 // moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will 322 // be included in the final module-info.json produced by Make. 323 moduleInfoJSON []*ModuleInfoJSON 324 325 // containersInfo stores the information about the containers and the information of the 326 // apexes the module belongs to. 327 containersInfo ContainersInfo 328 329 // Merged Aconfig files for all transitive deps. 330 aconfigFilePaths Paths 331 332 // complianceMetadataInfo is for different module types to dump metadata. 333 // See android.ModuleContext interface. 334 complianceMetadataInfo *ComplianceMetadataInfo 335 336 dists []dist 337} 338 339var _ ModuleContext = &moduleContext{} 340 341func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) { 342 return pctx, BuildParams{ 343 Rule: ErrorRule, 344 Description: params.Description, 345 Output: params.Output, 346 Outputs: params.Outputs, 347 ImplicitOutput: params.ImplicitOutput, 348 ImplicitOutputs: params.ImplicitOutputs, 349 Args: map[string]string{ 350 "error": err.Error(), 351 }, 352 } 353} 354 355func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) { 356 m.Build(pctx, BuildParams(params)) 357} 358 359// Convert build parameters from their concrete Android types into their string representations, 360// and combine the singular and plural fields of the same type (e.g. Output and Outputs). 361func convertBuildParams(params BuildParams) blueprint.BuildParams { 362 bparams := blueprint.BuildParams{ 363 Rule: params.Rule, 364 Description: params.Description, 365 Deps: params.Deps, 366 Outputs: params.Outputs.Strings(), 367 ImplicitOutputs: params.ImplicitOutputs.Strings(), 368 Inputs: params.Inputs.Strings(), 369 Implicits: params.Implicits.Strings(), 370 OrderOnly: params.OrderOnly.Strings(), 371 Validations: params.Validations.Strings(), 372 Args: params.Args, 373 Default: params.Default, 374 PhonyOutput: params.PhonyOutput, 375 } 376 377 if params.Depfile != nil { 378 bparams.Depfile = params.Depfile.String() 379 } 380 if params.Output != nil { 381 bparams.Outputs = append(bparams.Outputs, params.Output.String()) 382 } 383 if params.ImplicitOutput != nil { 384 bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String()) 385 } 386 if params.Input != nil { 387 bparams.Inputs = append(bparams.Inputs, params.Input.String()) 388 } 389 if params.Implicit != nil { 390 bparams.Implicits = append(bparams.Implicits, params.Implicit.String()) 391 } 392 if params.Validation != nil { 393 bparams.Validations = append(bparams.Validations, params.Validation.String()) 394 } 395 396 bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs) 397 bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs) 398 bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs) 399 bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits) 400 bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly) 401 bparams.Validations = proptools.NinjaEscapeList(bparams.Validations) 402 bparams.Depfile = proptools.NinjaEscape(bparams.Depfile) 403 404 return bparams 405} 406 407func (m *moduleContext) Variable(pctx PackageContext, name, value string) { 408 if m.config.captureBuild { 409 m.variables[name] = value 410 } 411 412 m.bp.Variable(pctx.PackageContext, name, value) 413} 414 415func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, 416 argNames ...string) blueprint.Rule { 417 418 if m.config.UseRemoteBuild() { 419 if params.Pool == nil { 420 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict 421 // jobs to the local parallelism value 422 params.Pool = localPool 423 } else if params.Pool == remotePool { 424 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's 425 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS 426 // parallelism. 427 params.Pool = nil 428 } 429 } 430 431 rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) 432 433 if m.config.captureBuild { 434 m.ruleParams[rule] = params 435 } 436 437 return rule 438} 439 440func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { 441 if params.Description != "" { 442 params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" 443 } 444 445 if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { 446 pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n", 447 m.ModuleName(), strings.Join(missingDeps, ", "))) 448 } 449 450 if m.config.captureBuild { 451 m.buildParams = append(m.buildParams, params) 452 } 453 454 bparams := convertBuildParams(params) 455 m.bp.Build(pctx.PackageContext, bparams) 456} 457 458func (m *moduleContext) Phony(name string, deps ...Path) { 459 for _, dep := range deps { 460 if dep == nil { 461 panic("Phony dep cannot be nil") 462 } 463 } 464 m.phonies[name] = append(m.phonies[name], deps...) 465} 466 467func (m *moduleContext) GetMissingDependencies() []string { 468 var missingDeps []string 469 missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) 470 missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...) 471 missingDeps = FirstUniqueStrings(missingDeps) 472 return missingDeps 473} 474 475func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module { 476 deps := m.getDirectDepsInternal(name, tag) 477 if len(deps) == 1 { 478 return deps[0] 479 } else if len(deps) >= 2 { 480 panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", 481 name, m.ModuleName())) 482 } else { 483 return nil 484 } 485} 486 487func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy { 488 deps := m.getDirectDepsProxyInternal(name, tag) 489 if len(deps) == 1 { 490 return &deps[0] 491 } else if len(deps) >= 2 { 492 panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", 493 name, m.ModuleName())) 494 } else { 495 return nil 496 } 497} 498 499func (m *moduleContext) ModuleSubDir() string { 500 return m.bp.ModuleSubDir() 501} 502 503func (m *moduleContext) InstallInData() bool { 504 return m.module.InstallInData() 505} 506 507func (m *moduleContext) InstallInTestcases() bool { 508 return m.module.InstallInTestcases() 509} 510 511func (m *moduleContext) InstallInSanitizerDir() bool { 512 return m.module.InstallInSanitizerDir() 513} 514 515func (m *moduleContext) InstallInRamdisk() bool { 516 return m.module.InstallInRamdisk() 517} 518 519func (m *moduleContext) InstallInVendorRamdisk() bool { 520 return m.module.InstallInVendorRamdisk() 521} 522 523func (m *moduleContext) InstallInDebugRamdisk() bool { 524 return m.module.InstallInDebugRamdisk() 525} 526 527func (m *moduleContext) InstallInRecovery() bool { 528 return m.module.InstallInRecovery() 529} 530 531func (m *moduleContext) InstallInRoot() bool { 532 return m.module.InstallInRoot() 533} 534 535func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { 536 return m.module.InstallForceOS() 537} 538 539func (m *moduleContext) InstallInOdm() bool { 540 return m.module.InstallInOdm() 541} 542 543func (m *moduleContext) InstallInProduct() bool { 544 return m.module.InstallInProduct() 545} 546 547func (m *moduleContext) InstallInVendor() bool { 548 return m.module.InstallInVendor() 549} 550 551func (m *moduleContext) InstallInSystemDlkm() bool { 552 return m.module.InstallInSystemDlkm() 553} 554 555func (m *moduleContext) InstallInVendorDlkm() bool { 556 return m.module.InstallInVendorDlkm() 557} 558 559func (m *moduleContext) InstallInOdmDlkm() bool { 560 return m.module.InstallInOdmDlkm() 561} 562 563func (m *moduleContext) skipInstall() bool { 564 if m.module.base().commonProperties.SkipInstall { 565 return true 566 } 567 568 // We'll need a solution for choosing which of modules with the same name in different 569 // namespaces to install. For now, reuse the list of namespaces exported to Make as the 570 // list of namespaces to install in a Soong-only build. 571 if !m.module.base().commonProperties.NamespaceExportedToMake { 572 return true 573 } 574 575 return false 576} 577 578// Tells whether this module is installed to the full install path (ex: 579// out/target/product/<name>/<partition>) or not. If this returns false, the install build rule is 580// not created and this module can only be installed to packaging modules like android_filesystem. 581func (m *moduleContext) requiresFullInstall() bool { 582 if m.skipInstall() { 583 return false 584 } 585 586 if m.module.base().commonProperties.HideFromMake { 587 return false 588 } 589 590 if proptools.Bool(m.module.base().commonProperties.No_full_install) { 591 return false 592 } 593 594 return true 595} 596 597func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, 598 deps ...InstallPath) InstallPath { 599 return m.installFile(installPath, name, srcPath, deps, false, true, true, nil) 600} 601 602func (m *moduleContext) InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, 603 deps ...InstallPath) InstallPath { 604 return m.installFile(installPath, name, srcPath, deps, false, true, false, nil) 605} 606 607func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path, 608 deps ...InstallPath) InstallPath { 609 return m.installFile(installPath, name, srcPath, deps, true, true, true, nil) 610} 611 612func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, 613 extraZip Path, deps ...InstallPath) InstallPath { 614 return m.installFile(installPath, name, srcPath, deps, false, true, true, &extraFilesZip{ 615 zip: extraZip, 616 dir: installPath, 617 }) 618} 619 620func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec { 621 fullInstallPath := installPath.Join(m, name) 622 return m.packageFile(fullInstallPath, srcPath, false, false) 623} 624 625func (m *moduleContext) getAconfigPaths() Paths { 626 return m.aconfigFilePaths 627} 628 629func (m *moduleContext) setAconfigPaths(paths Paths) { 630 m.aconfigFilePaths = paths 631} 632 633func (m *moduleContext) getOwnerAndOverrides() (string, []string) { 634 owner := m.ModuleName() 635 overrides := slices.Clone(m.Module().base().commonProperties.Overrides) 636 if b, ok := m.Module().(OverridableModule); ok { 637 if b.GetOverriddenBy() != "" { 638 // overriding variant of base module 639 overrides = append(overrides, m.ModuleName()) // com.android.foo 640 owner = m.Module().Name() // com.company.android.foo 641 } 642 } 643 return owner, overrides 644} 645 646func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool, requiresFullInstall bool) PackagingSpec { 647 licenseFiles := m.Module().EffectiveLicenseFiles() 648 owner, overrides := m.getOwnerAndOverrides() 649 spec := PackagingSpec{ 650 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), 651 srcPath: srcPath, 652 symlinkTarget: "", 653 executable: executable, 654 effectiveLicenseFiles: uniquelist.Make(licenseFiles), 655 partition: fullInstallPath.partition, 656 skipInstall: m.skipInstall(), 657 aconfigPaths: uniquelist.Make(m.getAconfigPaths()), 658 archType: m.target.Arch.ArchType, 659 overrides: uniquelist.Make(overrides), 660 owner: owner, 661 requiresFullInstall: requiresFullInstall, 662 fullInstallPath: fullInstallPath, 663 variation: m.ModuleSubDir(), 664 } 665 m.packagingSpecs = append(m.packagingSpecs, spec) 666 return spec 667} 668 669func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath, 670 executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath { 671 if _, ok := srcPath.(InstallPath); ok { 672 m.ModuleErrorf("Src path cannot be another installed file. Please use a path from source or intermediates instead.") 673 } 674 675 fullInstallPath := installPath.Join(m, name) 676 if hooks { 677 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) 678 } 679 680 if m.requiresFullInstall() { 681 deps = append(deps, InstallPaths(m.TransitiveInstallFiles.ToList())...) 682 if m.config.KatiEnabled() { 683 deps = append(deps, m.installedInitRcPaths...) 684 deps = append(deps, m.installedVintfFragmentsPaths...) 685 } 686 687 var implicitDeps, orderOnlyDeps Paths 688 689 if m.Host() { 690 // Installed host modules might be used during the build, depend directly on their 691 // dependencies so their timestamp is updated whenever their dependency is updated 692 implicitDeps = InstallPaths(deps).Paths() 693 } else { 694 orderOnlyDeps = InstallPaths(deps).Paths() 695 } 696 697 // When creating the install rule in Soong but embedding in Make, write the rule to a 698 // makefile instead of directly to the ninja file so that main.mk can add the 699 // dependencies from the `required` property that are hard to resolve in Soong. 700 // In soong-only builds, the katiInstall will still be created for semi-legacy code paths 701 // such as module-info.json or compliance, but it will not be used for actually installing 702 // the file. 703 m.katiInstalls = append(m.katiInstalls, katiInstall{ 704 from: srcPath, 705 to: fullInstallPath, 706 implicitDeps: implicitDeps, 707 orderOnlyDeps: orderOnlyDeps, 708 executable: executable, 709 extraFiles: extraZip, 710 }) 711 if !m.Config().KatiEnabled() { 712 rule := CpWithBash 713 if executable { 714 rule = CpExecutableWithBash 715 } 716 717 extraCmds := "" 718 if extraZip != nil { 719 extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )", 720 extraZip.dir.String(), extraZip.zip.String()) 721 extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )" 722 implicitDeps = append(implicitDeps, extraZip.zip) 723 } 724 725 var cpFlags = "-f" 726 727 // If this is a device file, copy while preserving timestamps. This is to support 728 // adb sync in soong-only builds. Because soong-only builds have 2 different staging 729 // directories, the out/target/product one and the out/soong/.intermediates one, 730 // we need to ensure the files in them have the same timestamps so that adb sync doesn't 731 // update the files on device. 732 if strings.Contains(fullInstallPath.String(), "target/product") { 733 cpFlags += " -p" 734 } 735 736 m.Build(pctx, BuildParams{ 737 Rule: rule, 738 Description: "install " + fullInstallPath.Base(), 739 Output: fullInstallPath, 740 Input: srcPath, 741 Implicits: implicitDeps, 742 OrderOnly: orderOnlyDeps, 743 Args: map[string]string{ 744 "extraCmds": extraCmds, 745 "cpFlags": cpFlags, 746 }, 747 }) 748 } 749 750 m.installFiles = append(m.installFiles, fullInstallPath) 751 } 752 753 m.packageFile(fullInstallPath, srcPath, executable, m.requiresFullInstall()) 754 755 if checkbuild { 756 if srcPath == nil { 757 panic("srcPath cannot be nil") 758 } 759 m.checkbuildFiles = append(m.checkbuildFiles, srcPath) 760 } 761 762 return fullInstallPath 763} 764 765func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath { 766 fullInstallPath := installPath.Join(m, name) 767 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true) 768 769 relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String()) 770 if err != nil { 771 panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err)) 772 } 773 if m.requiresFullInstall() { 774 775 // When creating the symlink rule in Soong but embedding in Make, write the rule to a 776 // makefile instead of directly to the ninja file so that main.mk can add the 777 // dependencies from the `required` property that are hard to resolve in Soong. 778 // In soong-only builds, the katiInstall will still be created for semi-legacy code paths 779 // such as module-info.json or compliance, but it will not be used for actually installing 780 // the file. 781 m.katiSymlinks = append(m.katiSymlinks, katiInstall{ 782 from: srcPath, 783 to: fullInstallPath, 784 }) 785 if !m.Config().KatiEnabled() { 786 // The symlink doesn't need updating when the target is modified, but we sometimes 787 // have a dependency on a symlink to a binary instead of to the binary directly, and 788 // the mtime of the symlink must be updated when the binary is modified, so use a 789 // normal dependency here instead of an order-only dependency. 790 m.Build(pctx, BuildParams{ 791 Rule: SymlinkWithBash, 792 Description: "install symlink " + fullInstallPath.Base(), 793 Output: fullInstallPath, 794 Input: srcPath, 795 Args: map[string]string{ 796 "fromPath": relPath, 797 }, 798 }) 799 } 800 801 m.installFiles = append(m.installFiles, fullInstallPath) 802 } 803 804 owner, overrides := m.getOwnerAndOverrides() 805 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ 806 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), 807 srcPath: nil, 808 symlinkTarget: relPath, 809 executable: false, 810 partition: fullInstallPath.partition, 811 skipInstall: m.skipInstall(), 812 aconfigPaths: uniquelist.Make(m.getAconfigPaths()), 813 archType: m.target.Arch.ArchType, 814 overrides: uniquelist.Make(overrides), 815 owner: owner, 816 requiresFullInstall: m.requiresFullInstall(), 817 fullInstallPath: fullInstallPath, 818 variation: m.ModuleSubDir(), 819 }) 820 821 return fullInstallPath 822} 823 824// installPath/name -> absPath where absPath might be a path that is available only at runtime 825// (e.g. /apex/...) 826func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath { 827 fullInstallPath := installPath.Join(m, name) 828 m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) 829 830 if m.requiresFullInstall() { 831 // When creating the symlink rule in Soong but embedding in Make, write the rule to a 832 // makefile instead of directly to the ninja file so that main.mk can add the 833 // dependencies from the `required` property that are hard to resolve in Soong. 834 // In soong-only builds, the katiInstall will still be created for semi-legacy code paths 835 // such as module-info.json or compliance, but it will not be used for actually installing 836 // the file. 837 m.katiSymlinks = append(m.katiSymlinks, katiInstall{ 838 absFrom: absPath, 839 to: fullInstallPath, 840 }) 841 if !m.Config().KatiEnabled() { 842 m.Build(pctx, BuildParams{ 843 Rule: SymlinkWithBash, 844 Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath, 845 Output: fullInstallPath, 846 Args: map[string]string{ 847 "fromPath": absPath, 848 }, 849 }) 850 } 851 852 m.installFiles = append(m.installFiles, fullInstallPath) 853 } 854 855 owner, overrides := m.getOwnerAndOverrides() 856 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ 857 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), 858 srcPath: nil, 859 symlinkTarget: absPath, 860 executable: false, 861 partition: fullInstallPath.partition, 862 skipInstall: m.skipInstall(), 863 aconfigPaths: uniquelist.Make(m.getAconfigPaths()), 864 archType: m.target.Arch.ArchType, 865 overrides: uniquelist.Make(overrides), 866 owner: owner, 867 requiresFullInstall: m.requiresFullInstall(), 868 fullInstallPath: fullInstallPath, 869 variation: m.ModuleSubDir(), 870 }) 871 872 return fullInstallPath 873} 874 875func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath) InstallPaths { 876 m.testData = append(m.testData, data...) 877 878 ret := make(InstallPaths, 0, len(data)) 879 for _, d := range data { 880 relPath := d.ToRelativeInstallPath() 881 installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, true, nil) 882 ret = append(ret, installed) 883 } 884 885 return ret 886} 887 888// CheckbuildFile specifies the output files that should be built by checkbuild. 889func (m *moduleContext) CheckbuildFile(srcPaths ...Path) { 890 for _, srcPath := range srcPaths { 891 if srcPath == nil { 892 panic("CheckbuildFile() files cannot be nil") 893 } 894 } 895 m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...) 896} 897 898// UncheckedModule marks the current module has having no files that should be built by checkbuild. 899func (m *moduleContext) UncheckedModule() { 900 m.uncheckedModule = true 901} 902 903func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext { 904 return m.bp 905} 906 907func (m *moduleContext) LicenseMetadataFile() Path { 908 return m.licenseMetadataFile 909} 910 911func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON { 912 if len(m.moduleInfoJSON) == 0 { 913 moduleInfoJSON := &ModuleInfoJSON{} 914 m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON) 915 } 916 return m.moduleInfoJSON[0] 917} 918 919func (m *moduleContext) ExtraModuleInfoJSON() *ModuleInfoJSON { 920 if len(m.moduleInfoJSON) == 0 { 921 panic("call ModuleInfoJSON() instead") 922 } 923 924 moduleInfoJSON := &ModuleInfoJSON{} 925 m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON) 926 return moduleInfoJSON 927} 928 929func (m *moduleContext) SetOutputFiles(outputFiles Paths, tag string) { 930 for _, outputFile := range outputFiles { 931 if outputFile == nil { 932 panic("outputfiles cannot be nil") 933 } 934 } 935 if tag == "" { 936 if len(m.outputFiles.DefaultOutputFiles) > 0 { 937 m.ModuleErrorf("Module %s default OutputFiles cannot be overwritten", m.ModuleName()) 938 } 939 m.outputFiles.DefaultOutputFiles = outputFiles 940 } else { 941 if m.outputFiles.TaggedOutputFiles == nil { 942 m.outputFiles.TaggedOutputFiles = make(map[string]Paths) 943 } 944 if _, exists := m.outputFiles.TaggedOutputFiles[tag]; exists { 945 m.ModuleErrorf("Module %s OutputFiles at tag %s cannot be overwritten", m.ModuleName(), tag) 946 } else { 947 m.outputFiles.TaggedOutputFiles[tag] = outputFiles 948 } 949 } 950} 951 952func (m *moduleContext) GetOutputFiles() OutputFilesInfo { 953 return m.outputFiles 954} 955 956func (m *moduleContext) SetLicenseInstallMap(installMap []string) { 957 m.licenseInstallMap = append(m.licenseInstallMap, installMap...) 958} 959 960func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo { 961 if m.complianceMetadataInfo == nil { 962 m.complianceMetadataInfo = NewComplianceMetadataInfo() 963 } 964 return m.complianceMetadataInfo 965} 966 967// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must 968// be tagged with `android:"path" to support automatic source module dependency resolution. 969// 970// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. 971func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths { 972 return PathsForModuleSrcExcludes(m, srcFiles, excludes) 973} 974 975// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must 976// be tagged with `android:"path" to support automatic source module dependency resolution. 977// 978// Deprecated: use PathForModuleSrc instead. 979func (m *moduleContext) ExpandSource(srcFile, _ string) Path { 980 return PathForModuleSrc(m, srcFile) 981} 982 983// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if 984// the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module 985// dependency resolution. 986func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath { 987 if srcFile != nil { 988 return OptionalPathForPath(PathForModuleSrc(m, *srcFile)) 989 } 990 return OptionalPath{} 991} 992 993func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string { 994 return m.module.RequiredModuleNames(ctx) 995} 996 997func (m *moduleContext) HostRequiredModuleNames() []string { 998 return m.module.HostRequiredModuleNames() 999} 1000 1001func (m *moduleContext) TargetRequiredModuleNames() []string { 1002 return m.module.TargetRequiredModuleNames() 1003} 1004 1005func (m *moduleContext) getContainersInfo() ContainersInfo { 1006 return m.containersInfo 1007} 1008 1009func (m *moduleContext) setContainersInfo(info ContainersInfo) { 1010 m.containersInfo = info 1011} 1012 1013func (c *moduleContext) DistForGoal(goal string, paths ...Path) { 1014 c.DistForGoals([]string{goal}, paths...) 1015} 1016 1017func (c *moduleContext) DistForGoalWithFilename(goal string, path Path, filename string) { 1018 c.DistForGoalsWithFilename([]string{goal}, path, filename) 1019} 1020 1021func (c *moduleContext) DistForGoals(goals []string, paths ...Path) { 1022 var copies distCopies 1023 for _, path := range paths { 1024 copies = append(copies, distCopy{ 1025 from: path, 1026 dest: path.Base(), 1027 }) 1028 } 1029 c.dists = append(c.dists, dist{ 1030 goals: slices.Clone(goals), 1031 paths: copies, 1032 }) 1033} 1034 1035func (c *moduleContext) DistForGoalsWithFilename(goals []string, path Path, filename string) { 1036 c.dists = append(c.dists, dist{ 1037 goals: slices.Clone(goals), 1038 paths: distCopies{{from: path, dest: filename}}, 1039 }) 1040} 1041