• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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