1// Copyright 2020 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/filepath" 20 "sort" 21 22 "github.com/google/blueprint" 23 "github.com/google/blueprint/gobtools" 24 "github.com/google/blueprint/proptools" 25 "github.com/google/blueprint/uniquelist" 26) 27 28// PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A 29// package can be the traditional <partition>.img, but isn't limited to those. Other examples could 30// be a new filesystem image that is a subset of system.img (e.g. for an Android-like mini OS 31// running on a VM), or a zip archive for some of the host tools. 32type PackagingSpec struct { 33 // Path relative to the root of the package 34 relPathInPackage string 35 36 // The path to the built artifact 37 srcPath Path 38 39 // If this is not empty, then relPathInPackage should be a symlink to this target. (Then 40 // srcPath is of course ignored.) 41 symlinkTarget string 42 43 // Whether relPathInPackage should be marked as executable or not 44 executable bool 45 46 effectiveLicenseFiles uniquelist.UniqueList[Path] 47 48 partition string 49 50 // Whether this packaging spec represents an installation of the srcPath (i.e. this struct 51 // is created via InstallFile or InstallSymlink) or a simple packaging (i.e. created via 52 // PackageFile). 53 skipInstall bool 54 55 // Paths of aconfig files for the built artifact 56 aconfigPaths uniquelist.UniqueList[Path] 57 58 // ArchType of the module which produced this packaging spec 59 archType ArchType 60 61 // List of module names that this packaging spec overrides 62 overrides uniquelist.UniqueList[string] 63 64 // Name of the module where this packaging spec is output of 65 owner string 66 67 // If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use, 68 // for the soong-only migration. 69 requiresFullInstall bool 70 71 // The path to the installed file in out/target/product. This is for legacy purposes, with 72 // tools that want to interact with these files outside of the build. You should not use it 73 // inside of the build. Will be nil if this module doesn't require a "full install". 74 fullInstallPath InstallPath 75 76 // String representation of the variation of the module where this packaging spec is output of 77 variation string 78} 79 80type packagingSpecGob struct { 81 RelPathInPackage string 82 SrcPath Path 83 SymlinkTarget string 84 Executable bool 85 EffectiveLicenseFiles Paths 86 Partition string 87 SkipInstall bool 88 AconfigPaths Paths 89 ArchType ArchType 90 Overrides []string 91 Owner string 92 RequiresFullInstall bool 93 FullInstallPath InstallPath 94 Variation string 95} 96 97func (p *PackagingSpec) Owner() string { 98 return p.owner 99} 100 101func (p *PackagingSpec) Variation() string { 102 return p.variation 103} 104 105func (p *PackagingSpec) ToGob() *packagingSpecGob { 106 return &packagingSpecGob{ 107 RelPathInPackage: p.relPathInPackage, 108 SrcPath: p.srcPath, 109 SymlinkTarget: p.symlinkTarget, 110 Executable: p.executable, 111 EffectiveLicenseFiles: p.effectiveLicenseFiles.ToSlice(), 112 Partition: p.partition, 113 SkipInstall: p.skipInstall, 114 AconfigPaths: p.aconfigPaths.ToSlice(), 115 ArchType: p.archType, 116 Overrides: p.overrides.ToSlice(), 117 Owner: p.owner, 118 RequiresFullInstall: p.requiresFullInstall, 119 FullInstallPath: p.fullInstallPath, 120 Variation: p.variation, 121 } 122} 123 124func (p *PackagingSpec) FromGob(data *packagingSpecGob) { 125 p.relPathInPackage = data.RelPathInPackage 126 p.srcPath = data.SrcPath 127 p.symlinkTarget = data.SymlinkTarget 128 p.executable = data.Executable 129 p.effectiveLicenseFiles = uniquelist.Make(data.EffectiveLicenseFiles) 130 p.partition = data.Partition 131 p.skipInstall = data.SkipInstall 132 p.aconfigPaths = uniquelist.Make(data.AconfigPaths) 133 p.archType = data.ArchType 134 p.overrides = uniquelist.Make(data.Overrides) 135 p.owner = data.Owner 136 p.requiresFullInstall = data.RequiresFullInstall 137 p.fullInstallPath = data.FullInstallPath 138 p.variation = data.Variation 139} 140 141func (p *PackagingSpec) GobEncode() ([]byte, error) { 142 return gobtools.CustomGobEncode[packagingSpecGob](p) 143} 144 145func (p *PackagingSpec) GobDecode(data []byte) error { 146 return gobtools.CustomGobDecode[packagingSpecGob](data, p) 147} 148 149func (p *PackagingSpec) Equals(other *PackagingSpec) bool { 150 if other == nil { 151 return false 152 } 153 if p.relPathInPackage != other.relPathInPackage { 154 return false 155 } 156 if p.srcPath != other.srcPath || p.symlinkTarget != other.symlinkTarget { 157 return false 158 } 159 if p.executable != other.executable { 160 return false 161 } 162 if p.partition != other.partition { 163 return false 164 } 165 return true 166} 167 168// Get file name of installed package 169func (p *PackagingSpec) FileName() string { 170 if p.relPathInPackage != "" { 171 return filepath.Base(p.relPathInPackage) 172 } 173 174 return "" 175} 176 177// Path relative to the root of the package 178func (p *PackagingSpec) RelPathInPackage() string { 179 return p.relPathInPackage 180} 181 182func (p *PackagingSpec) SetRelPathInPackage(relPathInPackage string) { 183 p.relPathInPackage = relPathInPackage 184} 185 186func (p *PackagingSpec) EffectiveLicenseFiles() Paths { 187 return p.effectiveLicenseFiles.ToSlice() 188} 189 190func (p *PackagingSpec) Partition() string { 191 return p.partition 192} 193 194func (p *PackagingSpec) SetPartition(partition string) { 195 p.partition = partition 196} 197 198func (p *PackagingSpec) SkipInstall() bool { 199 return p.skipInstall 200} 201 202// Paths of aconfig files for the built artifact 203func (p *PackagingSpec) GetAconfigPaths() Paths { 204 return p.aconfigPaths.ToSlice() 205} 206 207// The path to the installed file in out/target/product. This is for legacy purposes, with 208// tools that want to interact with these files outside of the build. You should not use it 209// inside of the build. Will be nil if this module doesn't require a "full install". 210func (p *PackagingSpec) FullInstallPath() InstallPath { 211 return p.fullInstallPath 212} 213 214// If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use, 215// for the soong-only migration. 216func (p *PackagingSpec) RequiresFullInstall() bool { 217 return p.requiresFullInstall 218} 219 220// The source file to be copied to the FullInstallPath. Do not use, for the soong-only migration. 221func (p *PackagingSpec) SrcPath() Path { 222 return p.srcPath 223} 224 225// The symlink target of the PackagingSpec. Do not use, for the soong-only migration. 226func (p *PackagingSpec) SymlinkTarget() string { 227 return p.symlinkTarget 228} 229 230type PackageModule interface { 231 Module 232 packagingBase() *PackagingBase 233 234 // AddDeps adds dependencies to the `deps` modules. This should be called in DepsMutator. 235 // When adding the dependencies, depTag is used as the tag. If `deps` modules are meant to 236 // be copied to a zip in CopyDepsToZip, `depTag` should implement PackagingItem marker interface. 237 AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) 238 239 // GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies. 240 GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec 241 GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec 242 GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec 243 244 // CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and 245 // returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions, 246 // followed by a build rule that unzips it and creates the final output (img, zip, tar.gz, 247 // etc.) from the extracted files 248 CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) []string 249} 250 251// PackagingBase provides basic functionality for packaging dependencies. A module is expected to 252// include this struct and call InitPackageModule. 253type PackagingBase struct { 254 properties PackagingProperties 255 256 // Allows this module to skip missing dependencies. In most cases, this is not required, but 257 // for rare cases like when there's a dependency to a module which exists in certain repo 258 // checkouts, this is needed. 259 IgnoreMissingDependencies bool 260 261 // If this is set to true by a module type inheriting PackagingBase, the deps property 262 // collects the first target only even with compile_multilib: true. 263 DepsCollectFirstTargetOnly bool 264 265 // If this is set to try by a module type inheriting PackagingBase, the module type is 266 // allowed to utilize High_priority_deps. 267 AllowHighPriorityDeps bool 268} 269 270type DepsProperty struct { 271 // Deps that have higher priority in packaging when there is a packaging conflict. 272 // For example, if multiple files are being installed to same filepath, the install file 273 // of the module listed in this property will have a higher priority over those in other 274 // deps properties. 275 High_priority_deps []string `android:"arch_variant"` 276 277 // Modules to include in this package 278 Deps proptools.Configurable[[]string] `android:"arch_variant"` 279} 280 281type packagingMultilibProperties struct { 282 First DepsProperty `android:"arch_variant"` 283 Common DepsProperty `android:"arch_variant"` 284 Lib32 DepsProperty `android:"arch_variant"` 285 Lib64 DepsProperty `android:"arch_variant"` 286 Both DepsProperty `android:"arch_variant"` 287 Prefer32 DepsProperty `android:"arch_variant"` 288} 289 290type packagingArchProperties struct { 291 Arm64 DepsProperty 292 Arm DepsProperty 293 X86_64 DepsProperty 294 X86 DepsProperty 295} 296 297type PackagingProperties struct { 298 DepsProperty 299 300 Multilib packagingMultilibProperties `android:"arch_variant"` 301 Arch packagingArchProperties 302} 303 304func InitPackageModule(p PackageModule) { 305 base := p.packagingBase() 306 p.AddProperties(&base.properties, &base.properties.DepsProperty) 307} 308 309func (p *PackagingBase) packagingBase() *PackagingBase { 310 return p 311} 312 313// From deps and multilib.*.deps, select the dependencies that are for the given arch deps is for 314// the current archicture when this module is not configured for multi target. When configured for 315// multi target, deps is selected for each of the targets and is NOT selected for the current 316// architecture which would be Common. 317// It returns two lists, the normal and high priority deps, respectively. 318func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([]string, []string) { 319 var normalDeps []string 320 var highPriorityDeps []string 321 322 get := func(prop DepsProperty) { 323 normalDeps = append(normalDeps, prop.Deps.GetOrDefault(ctx, nil)...) 324 highPriorityDeps = append(highPriorityDeps, prop.High_priority_deps...) 325 } 326 has := func(prop DepsProperty) bool { 327 return len(prop.Deps.GetOrDefault(ctx, nil)) > 0 || len(prop.High_priority_deps) > 0 328 } 329 330 if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 { 331 get(p.properties.DepsProperty) 332 } else if arch.Multilib == "lib32" { 333 get(p.properties.Multilib.Lib32) 334 // multilib.prefer32.deps are added for lib32 only when they support 32-bit arch 335 for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) { 336 if checkIfOtherModuleSupportsLib32(ctx, dep) { 337 normalDeps = append(normalDeps, dep) 338 } 339 } 340 for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps { 341 if checkIfOtherModuleSupportsLib32(ctx, dep) { 342 highPriorityDeps = append(highPriorityDeps, dep) 343 } 344 } 345 } else if arch.Multilib == "lib64" { 346 get(p.properties.Multilib.Lib64) 347 // multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch 348 for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) { 349 if !checkIfOtherModuleSupportsLib32(ctx, dep) { 350 normalDeps = append(normalDeps, dep) 351 } 352 } 353 for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps { 354 if !checkIfOtherModuleSupportsLib32(ctx, dep) { 355 highPriorityDeps = append(highPriorityDeps, dep) 356 } 357 } 358 } else if arch == Common { 359 get(p.properties.Multilib.Common) 360 } 361 362 if p.DepsCollectFirstTargetOnly { 363 if has(p.properties.Multilib.First) { 364 ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead") 365 } 366 for i, t := range ctx.MultiTargets() { 367 if t.Arch.ArchType == arch { 368 get(p.properties.Multilib.Both) 369 if i == 0 { 370 get(p.properties.DepsProperty) 371 } 372 } 373 } 374 } else { 375 if has(p.properties.Multilib.Both) { 376 ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead") 377 } 378 for i, t := range ctx.MultiTargets() { 379 if t.Arch.ArchType == arch { 380 get(p.properties.DepsProperty) 381 if i == 0 { 382 get(p.properties.Multilib.First) 383 } 384 } 385 } 386 } 387 388 if ctx.Arch().ArchType == Common { 389 switch arch { 390 case Arm64: 391 get(p.properties.Arch.Arm64) 392 case Arm: 393 get(p.properties.Arch.Arm) 394 case X86_64: 395 get(p.properties.Arch.X86_64) 396 case X86: 397 get(p.properties.Arch.X86) 398 } 399 } 400 401 if len(highPriorityDeps) > 0 && !p.AllowHighPriorityDeps { 402 ctx.ModuleErrorf("Usage of high_priority_deps is not allowed for %s module type", ctx.ModuleType()) 403 } 404 405 return FirstUniqueStrings(normalDeps), FirstUniqueStrings(highPriorityDeps) 406} 407 408func getSupportedTargets(ctx BaseModuleContext) []Target { 409 var ret []Target 410 // The current and the common OS targets are always supported 411 ret = append(ret, ctx.Target()) 412 if ctx.Arch().ArchType != Common { 413 ret = append(ret, Target{Os: ctx.Os(), Arch: Arch{ArchType: Common}}) 414 } 415 // If this module is configured for multi targets, those should be supported as well 416 ret = append(ret, ctx.MultiTargets()...) 417 return ret 418} 419 420// getLib32Target returns the 32-bit target from the list of targets this module supports. If this 421// module doesn't support 32-bit target, nil is returned. 422func getLib32Target(ctx BaseModuleContext) *Target { 423 for _, t := range getSupportedTargets(ctx) { 424 if t.Arch.ArchType.Multilib == "lib32" { 425 return &t 426 } 427 } 428 return nil 429} 430 431// checkIfOtherModuleSUpportsLib32 returns true if 32-bit variant of dep exists. 432func checkIfOtherModuleSupportsLib32(ctx BaseModuleContext, dep string) bool { 433 t := getLib32Target(ctx) 434 if t == nil { 435 // This packaging module doesn't support 32bit. No point of checking if dep supports 32-bit 436 // or not. 437 return false 438 } 439 return ctx.OtherModuleFarDependencyVariantExists(t.Variations(), dep) 440} 441 442// PackagingItem is a marker interface for dependency tags. 443// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip(). 444type PackagingItem interface { 445 // IsPackagingItem returns true if the dep is to be packaged 446 IsPackagingItem() bool 447} 448 449var _ PackagingItem = (*PackagingItemAlwaysDepTag)(nil) 450 451// DepTag provides default implementation of PackagingItem interface. 452// PackagingBase-derived modules can define their own dependency tag by embedding this, which 453// can be passed to AddDeps() or AddDependencies(). 454type PackagingItemAlwaysDepTag struct { 455} 456 457// IsPackagingItem returns true if the dep is to be packaged 458func (PackagingItemAlwaysDepTag) IsPackagingItem() bool { 459 return true 460} 461 462type highPriorityDepTag struct { 463 blueprint.BaseDependencyTag 464 PackagingItemAlwaysDepTag 465} 466 467// See PackageModule.AddDeps 468func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) { 469 addDep := func(t Target, dep string, highPriority bool) { 470 if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) { 471 return 472 } 473 targetVariation := t.Variations() 474 sharedVariation := blueprint.Variation{ 475 Mutator: "link", 476 Variation: "shared", 477 } 478 // If a shared variation exists, use that. Static variants do not provide any standalone files 479 // for packaging. 480 if ctx.OtherModuleFarDependencyVariantExists([]blueprint.Variation{sharedVariation}, dep) { 481 targetVariation = append(targetVariation, sharedVariation) 482 } 483 depTagToUse := depTag 484 if highPriority { 485 depTagToUse = highPriorityDepTag{} 486 } 487 488 ctx.AddFarVariationDependencies(targetVariation, depTagToUse, dep) 489 } 490 for _, t := range getSupportedTargets(ctx) { 491 normalDeps, highPriorityDeps := p.getDepsForArch(ctx, t.Arch.ArchType) 492 for _, dep := range normalDeps { 493 addDep(t, dep, false) 494 } 495 for _, dep := range highPriorityDeps { 496 addDep(t, dep, true) 497 } 498 } 499} 500 501// See PackageModule.GatherPackagingSpecs 502func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec { 503 // packaging specs gathered from the dep that are not high priorities. 504 var regularPriorities []PackagingSpec 505 506 // all packaging specs gathered from the high priority deps. 507 var highPriorities []PackagingSpec 508 509 // list of module names overridden 510 overridden := make(map[string]bool) 511 512 // all installed modules which are not overridden. 513 modulesToInstall := make(map[string]bool) 514 515 var arches []ArchType 516 for _, target := range getSupportedTargets(ctx) { 517 arches = append(arches, target.Arch.ArchType) 518 } 519 520 // filter out packaging specs for unsupported architecture 521 filterArch := func(ps PackagingSpec) bool { 522 for _, arch := range arches { 523 if arch == ps.archType { 524 return true 525 } 526 } 527 return false 528 } 529 530 // find all overridden modules and packaging specs 531 ctx.VisitDirectDepsProxy(func(child ModuleProxy) { 532 depTag := ctx.OtherModuleDependencyTag(child) 533 if pi, ok := depTag.(PackagingItem); !ok || !pi.IsPackagingItem() { 534 return 535 } 536 for _, ps := range OtherModuleProviderOrDefault( 537 ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() { 538 if !filterArch(ps) { 539 continue 540 } 541 542 if filter != nil { 543 if !filter(ps) { 544 continue 545 } 546 } 547 548 if modifier != nil { 549 modifier(&ps) 550 } 551 552 if _, ok := depTag.(highPriorityDepTag); ok { 553 highPriorities = append(highPriorities, ps) 554 } else { 555 regularPriorities = append(regularPriorities, ps) 556 } 557 558 for o := range ps.overrides.Iter() { 559 overridden[o] = true 560 } 561 } 562 }) 563 564 // gather modules to install, skipping overridden modules 565 ctx.WalkDeps(func(child, parent Module) bool { 566 owner := ctx.OtherModuleName(child) 567 if o, ok := child.(OverridableModule); ok { 568 if overriddenBy := o.GetOverriddenBy(); overriddenBy != "" { 569 owner = overriddenBy 570 } 571 } 572 if overridden[owner] { 573 return false 574 } 575 modulesToInstall[owner] = true 576 return true 577 }) 578 579 filterOverridden := func(input []PackagingSpec) []PackagingSpec { 580 // input minus packaging specs that are not installed 581 var filtered []PackagingSpec 582 for _, ps := range input { 583 if !modulesToInstall[ps.owner] { 584 continue 585 } 586 filtered = append(filtered, ps) 587 } 588 return filtered 589 } 590 591 filteredRegularPriority := filterOverridden(regularPriorities) 592 593 m := make(map[string]PackagingSpec) 594 for _, ps := range filteredRegularPriority { 595 dstPath := ps.relPathInPackage 596 if existingPs, ok := m[dstPath]; ok { 597 if !existingPs.Equals(&ps) { 598 ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps) 599 } 600 continue 601 } 602 m[dstPath] = ps 603 } 604 605 filteredHighPriority := filterOverridden(highPriorities) 606 highPriorityPs := make(map[string]PackagingSpec) 607 for _, ps := range filteredHighPriority { 608 dstPath := ps.relPathInPackage 609 if existingPs, ok := highPriorityPs[dstPath]; ok { 610 if !existingPs.Equals(&ps) { 611 ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps) 612 } 613 continue 614 } 615 highPriorityPs[dstPath] = ps 616 m[dstPath] = ps 617 } 618 619 return m 620} 621 622// See PackageModule.GatherPackagingSpecs 623func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec { 624 return p.GatherPackagingSpecsWithFilterAndModifier(ctx, filter, nil) 625} 626 627// See PackageModule.GatherPackagingSpecs 628func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec { 629 return p.GatherPackagingSpecsWithFilter(ctx, nil) 630} 631 632// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec 633// entries into the specified directory. 634func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) { 635 dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec) 636 dirsToSpecs[dir] = specs 637 return p.CopySpecsToDirs(ctx, builder, dirsToSpecs, false) 638} 639 640// CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec 641// entries into corresponding directories. 642func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec, preserveTimestamps bool) (entries []string) { 643 empty := true 644 for _, specs := range dirsToSpecs { 645 if len(specs) > 0 { 646 empty = false 647 break 648 } 649 } 650 if empty { 651 return entries 652 } 653 654 seenDir := make(map[string]bool) 655 656 dirs := make([]WritablePath, 0, len(dirsToSpecs)) 657 for dir, _ := range dirsToSpecs { 658 dirs = append(dirs, dir) 659 } 660 sort.Slice(dirs, func(i, j int) bool { 661 return dirs[i].String() < dirs[j].String() 662 }) 663 664 for _, dir := range dirs { 665 specs := dirsToSpecs[dir] 666 for _, k := range SortedKeys(specs) { 667 ps := specs[k] 668 destPath := filepath.Join(dir.String(), ps.relPathInPackage) 669 destDir := filepath.Dir(destPath) 670 entries = append(entries, ps.relPathInPackage) 671 if _, ok := seenDir[destDir]; !ok { 672 seenDir[destDir] = true 673 builder.Command().Textf("mkdir -p %s", destDir) 674 } 675 if ps.symlinkTarget == "" { 676 cmd := builder.Command().Text("cp") 677 if preserveTimestamps { 678 cmd.Flag("-p") 679 } 680 cmd.Input(ps.srcPath).Text(destPath) 681 } else { 682 builder.Command().Textf("ln -sf %s %s", ps.symlinkTarget, destPath) 683 } 684 if ps.executable { 685 builder.Command().Textf("chmod a+x %s", destPath) 686 } 687 } 688 } 689 690 return entries 691} 692 693// See PackageModule.CopyDepsToZip 694func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) (entries []string) { 695 builder := NewRuleBuilder(pctx, ctx) 696 697 dir := PathForModuleOut(ctx, ".zip") 698 builder.Command().Text("rm").Flag("-rf").Text(dir.String()) 699 builder.Command().Text("mkdir").Flag("-p").Text(dir.String()) 700 entries = p.CopySpecsToDir(ctx, builder, specs, dir) 701 702 builder.Command(). 703 BuiltTool("soong_zip"). 704 FlagWithOutput("-o ", zipOut). 705 FlagWithArg("-C ", dir.String()). 706 Flag("-L 0"). // no compression because this will be unzipped soon 707 FlagWithArg("-D ", dir.String()) 708 builder.Command().Text("rm").Flag("-rf").Text(dir.String()) 709 710 builder.Build("zip_deps", fmt.Sprintf("Zipping deps for %s", ctx.ModuleName())) 711 return entries 712} 713