blob: 738f215e9b5c27f47e6febfa199a13ed46ff825f [file] [log] [blame]
Jiyong Park073ea552020-11-09 14:08:34 +09001// 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
Jiyong Parkdda8f692020-11-09 18:38:48 +090017import (
18 "fmt"
19 "path/filepath"
Inseob Kim33f95a92024-07-11 15:44:49 +090020 "sort"
Jiyong Parkdda8f692020-11-09 18:38:48 +090021
22 "github.com/google/blueprint"
Yu Liu3cadf7d2024-10-24 18:47:06 +000023 "github.com/google/blueprint/gobtools"
Jiyong Park105e11c2024-05-17 14:58:24 +090024 "github.com/google/blueprint/proptools"
Colin Crossf0c1ede2025-01-23 13:30:36 -080025 "github.com/google/blueprint/uniquelist"
Jiyong Parkdda8f692020-11-09 18:38:48 +090026)
27
Jiyong Parkcc1157c2020-11-25 11:31:13 +090028// 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.
Jiyong Park073ea552020-11-09 14:08:34 +090032type 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
Dan Willemsen9fe14102021-07-13 21:52:04 -070045
Colin Crossf0c1ede2025-01-23 13:30:36 -080046 effectiveLicenseFiles uniquelist.UniqueList[Path]
Jooyung Han99c5fe62022-03-21 15:13:38 +090047
48 partition string
Jiyong Park4152b192024-04-30 21:24:21 +090049
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
Justin Yun74f3f302024-05-07 14:32:14 +090054
55 // Paths of aconfig files for the built artifact
Colin Crossf0c1ede2025-01-23 13:30:36 -080056 aconfigPaths uniquelist.UniqueList[Path]
Jiyong Parkc6a773d2024-05-14 21:49:11 +090057
58 // ArchType of the module which produced this packaging spec
59 archType ArchType
Jiyong Parka574d532024-08-28 18:06:43 +090060
61 // List of module names that this packaging spec overrides
Colin Crossf0c1ede2025-01-23 13:30:36 -080062 overrides uniquelist.UniqueList[string]
Jiyong Parka574d532024-08-28 18:06:43 +090063
64 // Name of the module where this packaging spec is output of
65 owner string
Jiyong Park073ea552020-11-09 14:08:34 +090066}
Jiyong Parkdda8f692020-11-09 18:38:48 +090067
Yu Liu467d7c52024-09-18 21:54:44 +000068type packagingSpecGob struct {
Yu Liu5246a7e2024-10-09 20:04:52 +000069 RelPathInPackage string
70 SrcPath Path
71 SymlinkTarget string
72 Executable bool
Colin Crossf0c1ede2025-01-23 13:30:36 -080073 EffectiveLicenseFiles Paths
Yu Liu5246a7e2024-10-09 20:04:52 +000074 Partition string
75 SkipInstall bool
Colin Crossf0c1ede2025-01-23 13:30:36 -080076 AconfigPaths Paths
Yu Liu5246a7e2024-10-09 20:04:52 +000077 ArchType ArchType
Colin Crossf0c1ede2025-01-23 13:30:36 -080078 Overrides []string
Yu Liu5246a7e2024-10-09 20:04:52 +000079 Owner string
Yu Liu467d7c52024-09-18 21:54:44 +000080}
Yu Liu26a716d2024-08-30 23:40:32 +000081
Yu Liu467d7c52024-09-18 21:54:44 +000082func (p *PackagingSpec) ToGob() *packagingSpecGob {
83 return &packagingSpecGob{
Yu Liu5246a7e2024-10-09 20:04:52 +000084 RelPathInPackage: p.relPathInPackage,
85 SrcPath: p.srcPath,
86 SymlinkTarget: p.symlinkTarget,
87 Executable: p.executable,
Colin Crossf0c1ede2025-01-23 13:30:36 -080088 EffectiveLicenseFiles: p.effectiveLicenseFiles.ToSlice(),
Yu Liu5246a7e2024-10-09 20:04:52 +000089 Partition: p.partition,
90 SkipInstall: p.skipInstall,
Colin Crossf0c1ede2025-01-23 13:30:36 -080091 AconfigPaths: p.aconfigPaths.ToSlice(),
Yu Liu5246a7e2024-10-09 20:04:52 +000092 ArchType: p.archType,
Colin Crossf0c1ede2025-01-23 13:30:36 -080093 Overrides: p.overrides.ToSlice(),
Yu Liu5246a7e2024-10-09 20:04:52 +000094 Owner: p.owner,
Yu Liu467d7c52024-09-18 21:54:44 +000095 }
96}
97
98func (p *PackagingSpec) FromGob(data *packagingSpecGob) {
99 p.relPathInPackage = data.RelPathInPackage
100 p.srcPath = data.SrcPath
101 p.symlinkTarget = data.SymlinkTarget
102 p.executable = data.Executable
Colin Crossf0c1ede2025-01-23 13:30:36 -0800103 p.effectiveLicenseFiles = uniquelist.Make(data.EffectiveLicenseFiles)
Yu Liu467d7c52024-09-18 21:54:44 +0000104 p.partition = data.Partition
105 p.skipInstall = data.SkipInstall
Colin Crossf0c1ede2025-01-23 13:30:36 -0800106 p.aconfigPaths = uniquelist.Make(data.AconfigPaths)
Yu Liu467d7c52024-09-18 21:54:44 +0000107 p.archType = data.ArchType
Colin Crossf0c1ede2025-01-23 13:30:36 -0800108 p.overrides = uniquelist.Make(data.Overrides)
Yu Liu467d7c52024-09-18 21:54:44 +0000109 p.owner = data.Owner
110}
111
112func (p *PackagingSpec) GobEncode() ([]byte, error) {
Yu Liu3cadf7d2024-10-24 18:47:06 +0000113 return gobtools.CustomGobEncode[packagingSpecGob](p)
Yu Liu26a716d2024-08-30 23:40:32 +0000114}
115
116func (p *PackagingSpec) GobDecode(data []byte) error {
Yu Liu3cadf7d2024-10-24 18:47:06 +0000117 return gobtools.CustomGobDecode[packagingSpecGob](data, p)
Yu Liu26a716d2024-08-30 23:40:32 +0000118}
119
Jiyong Park16ef7ac2024-05-01 12:36:10 +0000120func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
121 if other == nil {
122 return false
123 }
124 if p.relPathInPackage != other.relPathInPackage {
125 return false
126 }
127 if p.srcPath != other.srcPath || p.symlinkTarget != other.symlinkTarget {
128 return false
129 }
130 if p.executable != other.executable {
131 return false
132 }
133 if p.partition != other.partition {
134 return false
135 }
136 return true
137}
138
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +0900139// Get file name of installed package
140func (p *PackagingSpec) FileName() string {
141 if p.relPathInPackage != "" {
142 return filepath.Base(p.relPathInPackage)
143 }
144
145 return ""
146}
147
Jiyong Park6446b622021-02-01 20:08:28 +0900148// Path relative to the root of the package
149func (p *PackagingSpec) RelPathInPackage() string {
150 return p.relPathInPackage
151}
152
Dan Willemsen9fe14102021-07-13 21:52:04 -0700153func (p *PackagingSpec) SetRelPathInPackage(relPathInPackage string) {
154 p.relPathInPackage = relPathInPackage
155}
156
157func (p *PackagingSpec) EffectiveLicenseFiles() Paths {
Colin Crossf0c1ede2025-01-23 13:30:36 -0800158 return p.effectiveLicenseFiles.ToSlice()
Dan Willemsen9fe14102021-07-13 21:52:04 -0700159}
160
Jooyung Han99c5fe62022-03-21 15:13:38 +0900161func (p *PackagingSpec) Partition() string {
162 return p.partition
163}
164
Inseob Kim3c0a0422024-11-05 17:21:37 +0900165func (p *PackagingSpec) SetPartition(partition string) {
166 p.partition = partition
167}
168
Jiyong Park4152b192024-04-30 21:24:21 +0900169func (p *PackagingSpec) SkipInstall() bool {
170 return p.skipInstall
171}
172
Justin Yun74f3f302024-05-07 14:32:14 +0900173// Paths of aconfig files for the built artifact
174func (p *PackagingSpec) GetAconfigPaths() Paths {
Colin Crossf0c1ede2025-01-23 13:30:36 -0800175 return p.aconfigPaths.ToSlice()
Justin Yun74f3f302024-05-07 14:32:14 +0900176}
177
Jiyong Parkdda8f692020-11-09 18:38:48 +0900178type PackageModule interface {
179 Module
180 packagingBase() *PackagingBase
181
182 // AddDeps adds dependencies to the `deps` modules. This should be called in DepsMutator.
Jooyung Han092ef812021-03-10 15:40:34 +0900183 // When adding the dependencies, depTag is used as the tag. If `deps` modules are meant to
184 // be copied to a zip in CopyDepsToZip, `depTag` should implement PackagingItem marker interface.
Jiyong Park65b62242020-11-25 12:44:59 +0900185 AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900186
Jooyung Hana8834282022-03-25 11:40:12 +0900187 // GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
188 GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
Jeongik Cha54bf8752024-02-08 10:44:37 +0900189 GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
Inseob Kim3c0a0422024-11-05 17:21:37 +0900190 GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec
Jooyung Hana8834282022-03-25 11:40:12 +0900191
Jiyong Parkdda8f692020-11-09 18:38:48 +0900192 // CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900193 // returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
Jiyong Parkdda8f692020-11-09 18:38:48 +0900194 // followed by a build rule that unzips it and creates the final output (img, zip, tar.gz,
195 // etc.) from the extracted files
Jooyung Hana8834282022-03-25 11:40:12 +0900196 CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) []string
Jiyong Parkdda8f692020-11-09 18:38:48 +0900197}
198
199// PackagingBase provides basic functionality for packaging dependencies. A module is expected to
200// include this struct and call InitPackageModule.
201type PackagingBase struct {
202 properties PackagingProperties
203
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900204 // Allows this module to skip missing dependencies. In most cases, this is not required, but
205 // for rare cases like when there's a dependency to a module which exists in certain repo
206 // checkouts, this is needed.
Jiyong Parkdda8f692020-11-09 18:38:48 +0900207 IgnoreMissingDependencies bool
Jiyong Park3ea9b652024-05-15 23:01:54 +0900208
209 // If this is set to true by a module type inheriting PackagingBase, the deps property
210 // collects the first target only even with compile_multilib: true.
211 DepsCollectFirstTargetOnly bool
Jihoon Kang79196c52024-10-30 18:49:47 +0000212
213 // If this is set to try by a module type inheriting PackagingBase, the module type is
214 // allowed to utilize High_priority_deps.
215 AllowHighPriorityDeps bool
Jiyong Parkdda8f692020-11-09 18:38:48 +0900216}
217
Jihoon Kang79196c52024-10-30 18:49:47 +0000218type DepsProperty struct {
219 // Deps that have higher priority in packaging when there is a packaging conflict.
220 // For example, if multiple files are being installed to same filepath, the install file
221 // of the module listed in this property will have a higher priority over those in other
222 // deps properties.
223 High_priority_deps []string `android:"arch_variant"`
224
Jiyong Parkdda8f692020-11-09 18:38:48 +0900225 // Modules to include in this package
Jiyong Park105e11c2024-05-17 14:58:24 +0900226 Deps proptools.Configurable[[]string] `android:"arch_variant"`
Jiyong Parkdda8f692020-11-09 18:38:48 +0900227}
228
229type packagingMultilibProperties struct {
Jihoon Kang79196c52024-10-30 18:49:47 +0000230 First DepsProperty `android:"arch_variant"`
231 Common DepsProperty `android:"arch_variant"`
232 Lib32 DepsProperty `android:"arch_variant"`
233 Lib64 DepsProperty `android:"arch_variant"`
234 Both DepsProperty `android:"arch_variant"`
235 Prefer32 DepsProperty `android:"arch_variant"`
Jiyong Parkdda8f692020-11-09 18:38:48 +0900236}
237
Jiyong Park2136d152021-02-01 23:24:56 +0900238type packagingArchProperties struct {
Jihoon Kang79196c52024-10-30 18:49:47 +0000239 Arm64 DepsProperty
240 Arm DepsProperty
241 X86_64 DepsProperty
242 X86 DepsProperty
Jiyong Park2136d152021-02-01 23:24:56 +0900243}
244
Jiyong Parkdda8f692020-11-09 18:38:48 +0900245type PackagingProperties struct {
Jihoon Kang79196c52024-10-30 18:49:47 +0000246 DepsProperty
247
248 Multilib packagingMultilibProperties `android:"arch_variant"`
Jiyong Park2136d152021-02-01 23:24:56 +0900249 Arch packagingArchProperties
Jiyong Parkdda8f692020-11-09 18:38:48 +0900250}
251
Jiyong Parkdda8f692020-11-09 18:38:48 +0900252func InitPackageModule(p PackageModule) {
253 base := p.packagingBase()
Jihoon Kang79196c52024-10-30 18:49:47 +0000254 p.AddProperties(&base.properties, &base.properties.DepsProperty)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900255}
256
257func (p *PackagingBase) packagingBase() *PackagingBase {
258 return p
259}
260
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900261// From deps and multilib.*.deps, select the dependencies that are for the given arch deps is for
262// the current archicture when this module is not configured for multi target. When configured for
263// multi target, deps is selected for each of the targets and is NOT selected for the current
264// architecture which would be Common.
Cole Faust0c5eaed2024-11-01 11:05:00 -0700265// It returns two lists, the normal and high priority deps, respectively.
266func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([]string, []string) {
267 var normalDeps []string
268 var highPriorityDeps []string
269
270 get := func(prop DepsProperty) {
271 normalDeps = append(normalDeps, prop.Deps.GetOrDefault(ctx, nil)...)
272 highPriorityDeps = append(highPriorityDeps, prop.High_priority_deps...)
273 }
274 has := func(prop DepsProperty) bool {
275 return len(prop.Deps.GetOrDefault(ctx, nil)) > 0 || len(prop.High_priority_deps) > 0
Jihoon Kang79196c52024-10-30 18:49:47 +0000276 }
277
Jiyong Parkdda8f692020-11-09 18:38:48 +0900278 if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700279 get(p.properties.DepsProperty)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900280 } else if arch.Multilib == "lib32" {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700281 get(p.properties.Multilib.Lib32)
Jiyong Parke6043782024-05-20 16:17:39 +0900282 // multilib.prefer32.deps are added for lib32 only when they support 32-bit arch
Cole Faust0c5eaed2024-11-01 11:05:00 -0700283 for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) {
Jiyong Parke6043782024-05-20 16:17:39 +0900284 if checkIfOtherModuleSupportsLib32(ctx, dep) {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700285 normalDeps = append(normalDeps, dep)
286 }
287 }
288 for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps {
289 if checkIfOtherModuleSupportsLib32(ctx, dep) {
290 highPriorityDeps = append(highPriorityDeps, dep)
Jiyong Parke6043782024-05-20 16:17:39 +0900291 }
292 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900293 } else if arch.Multilib == "lib64" {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700294 get(p.properties.Multilib.Lib64)
Jiyong Parke6043782024-05-20 16:17:39 +0900295 // multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch
Cole Faust0c5eaed2024-11-01 11:05:00 -0700296 for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) {
Jiyong Parke6043782024-05-20 16:17:39 +0900297 if !checkIfOtherModuleSupportsLib32(ctx, dep) {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700298 normalDeps = append(normalDeps, dep)
299 }
300 }
301 for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps {
302 if !checkIfOtherModuleSupportsLib32(ctx, dep) {
303 highPriorityDeps = append(highPriorityDeps, dep)
Jiyong Parke6043782024-05-20 16:17:39 +0900304 }
305 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900306 } else if arch == Common {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700307 get(p.properties.Multilib.Common)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900308 }
Jiyong Park2136d152021-02-01 23:24:56 +0900309
Jiyong Park3ea9b652024-05-15 23:01:54 +0900310 if p.DepsCollectFirstTargetOnly {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700311 if has(p.properties.Multilib.First) {
Jiyong Park3ea9b652024-05-15 23:01:54 +0900312 ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead")
313 }
314 for i, t := range ctx.MultiTargets() {
315 if t.Arch.ArchType == arch {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700316 get(p.properties.Multilib.Both)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900317 if i == 0 {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700318 get(p.properties.DepsProperty)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900319 }
320 }
321 }
322 } else {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700323 if has(p.properties.Multilib.Both) {
Jiyong Park3ea9b652024-05-15 23:01:54 +0900324 ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead")
325 }
326 for i, t := range ctx.MultiTargets() {
327 if t.Arch.ArchType == arch {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700328 get(p.properties.DepsProperty)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900329 if i == 0 {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700330 get(p.properties.Multilib.First)
Jiyong Park3ea9b652024-05-15 23:01:54 +0900331 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900332 }
333 }
334 }
Jiyong Park2136d152021-02-01 23:24:56 +0900335
336 if ctx.Arch().ArchType == Common {
337 switch arch {
338 case Arm64:
Cole Faust0c5eaed2024-11-01 11:05:00 -0700339 get(p.properties.Arch.Arm64)
Jiyong Park2136d152021-02-01 23:24:56 +0900340 case Arm:
Cole Faust0c5eaed2024-11-01 11:05:00 -0700341 get(p.properties.Arch.Arm)
Jiyong Park2136d152021-02-01 23:24:56 +0900342 case X86_64:
Cole Faust0c5eaed2024-11-01 11:05:00 -0700343 get(p.properties.Arch.X86_64)
Jiyong Park2136d152021-02-01 23:24:56 +0900344 case X86:
Cole Faust0c5eaed2024-11-01 11:05:00 -0700345 get(p.properties.Arch.X86)
Jiyong Park2136d152021-02-01 23:24:56 +0900346 }
347 }
348
Cole Faust0c5eaed2024-11-01 11:05:00 -0700349 if len(highPriorityDeps) > 0 && !p.AllowHighPriorityDeps {
350 ctx.ModuleErrorf("Usage of high_priority_deps is not allowed for %s module type", ctx.ModuleType())
351 }
352
353 return FirstUniqueStrings(normalDeps), FirstUniqueStrings(highPriorityDeps)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900354}
355
Jiyong Parke6043782024-05-20 16:17:39 +0900356func getSupportedTargets(ctx BaseModuleContext) []Target {
Jiyong Parkdda8f692020-11-09 18:38:48 +0900357 var ret []Target
358 // The current and the common OS targets are always supported
359 ret = append(ret, ctx.Target())
360 if ctx.Arch().ArchType != Common {
361 ret = append(ret, Target{Os: ctx.Os(), Arch: Arch{ArchType: Common}})
362 }
363 // If this module is configured for multi targets, those should be supported as well
364 ret = append(ret, ctx.MultiTargets()...)
365 return ret
366}
367
Jiyong Parke6043782024-05-20 16:17:39 +0900368// getLib32Target returns the 32-bit target from the list of targets this module supports. If this
369// module doesn't support 32-bit target, nil is returned.
370func getLib32Target(ctx BaseModuleContext) *Target {
371 for _, t := range getSupportedTargets(ctx) {
372 if t.Arch.ArchType.Multilib == "lib32" {
373 return &t
374 }
375 }
376 return nil
377}
378
379// checkIfOtherModuleSUpportsLib32 returns true if 32-bit variant of dep exists.
380func checkIfOtherModuleSupportsLib32(ctx BaseModuleContext, dep string) bool {
381 t := getLib32Target(ctx)
382 if t == nil {
383 // This packaging module doesn't support 32bit. No point of checking if dep supports 32-bit
384 // or not.
385 return false
386 }
387 return ctx.OtherModuleFarDependencyVariantExists(t.Variations(), dep)
388}
389
Jooyung Han092ef812021-03-10 15:40:34 +0900390// PackagingItem is a marker interface for dependency tags.
391// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip().
392type PackagingItem interface {
393 // IsPackagingItem returns true if the dep is to be packaged
394 IsPackagingItem() bool
395}
396
Jihoon Kang79196c52024-10-30 18:49:47 +0000397var _ PackagingItem = (*PackagingItemAlwaysDepTag)(nil)
398
Jooyung Han092ef812021-03-10 15:40:34 +0900399// DepTag provides default implementation of PackagingItem interface.
400// PackagingBase-derived modules can define their own dependency tag by embedding this, which
401// can be passed to AddDeps() or AddDependencies().
402type PackagingItemAlwaysDepTag struct {
403}
404
405// IsPackagingItem returns true if the dep is to be packaged
406func (PackagingItemAlwaysDepTag) IsPackagingItem() bool {
407 return true
408}
409
Jihoon Kang79196c52024-10-30 18:49:47 +0000410type highPriorityDepTag struct {
Jihoon Kangade584c2024-11-14 19:45:47 +0000411 blueprint.BaseDependencyTag
412 PackagingItemAlwaysDepTag
Jihoon Kang79196c52024-10-30 18:49:47 +0000413}
414
Jiyong Parkdda8f692020-11-09 18:38:48 +0900415// See PackageModule.AddDeps
Jiyong Park65b62242020-11-25 12:44:59 +0900416func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
Cole Faust0c5eaed2024-11-01 11:05:00 -0700417 addDep := func(t Target, dep string, highPriority bool) {
418 if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
419 return
420 }
421 targetVariation := t.Variations()
422 sharedVariation := blueprint.Variation{
423 Mutator: "link",
424 Variation: "shared",
425 }
426 // If a shared variation exists, use that. Static variants do not provide any standalone files
427 // for packaging.
428 if ctx.OtherModuleFarDependencyVariantExists([]blueprint.Variation{sharedVariation}, dep) {
429 targetVariation = append(targetVariation, sharedVariation)
430 }
431 depTagToUse := depTag
432 if highPriority {
Jihoon Kangade584c2024-11-14 19:45:47 +0000433 depTagToUse = highPriorityDepTag{}
Cole Faust0c5eaed2024-11-01 11:05:00 -0700434 }
Jihoon Kang79196c52024-10-30 18:49:47 +0000435
Cole Faust0c5eaed2024-11-01 11:05:00 -0700436 ctx.AddFarVariationDependencies(targetVariation, depTagToUse, dep)
437 }
438 for _, t := range getSupportedTargets(ctx) {
439 normalDeps, highPriorityDeps := p.getDepsForArch(ctx, t.Arch.ArchType)
440 for _, dep := range normalDeps {
441 addDep(t, dep, false)
442 }
443 for _, dep := range highPriorityDeps {
444 addDep(t, dep, true)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900445 }
446 }
447}
448
Inseob Kim3c0a0422024-11-05 17:21:37 +0900449// See PackageModule.GatherPackagingSpecs
450func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleContext, filter func(PackagingSpec) bool, modifier func(*PackagingSpec)) map[string]PackagingSpec {
Jihoon Kang79196c52024-10-30 18:49:47 +0000451 // packaging specs gathered from the dep that are not high priorities.
452 var regularPriorities []PackagingSpec
453
454 // all packaging specs gathered from the high priority deps.
455 var highPriorities []PackagingSpec
456
Spandan Das6c2b01d2024-10-22 22:16:04 +0000457 // Name of the dependency which requested the packaging spec.
458 // If this dep is overridden, the packaging spec will not be installed via this dependency chain.
459 // (the packaging spec might still be installed if there are some other deps which depend on it).
460 var depNames []string
461
Jiyong Parka574d532024-08-28 18:06:43 +0900462 // list of module names overridden
463 var overridden []string
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900464
465 var arches []ArchType
Jiyong Parke6043782024-05-20 16:17:39 +0900466 for _, target := range getSupportedTargets(ctx) {
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900467 arches = append(arches, target.Arch.ArchType)
468 }
469
470 // filter out packaging specs for unsupported architecture
471 filterArch := func(ps PackagingSpec) bool {
472 for _, arch := range arches {
473 if arch == ps.archType {
474 return true
475 }
476 }
477 return false
478 }
479
Yu Liuac483e02024-11-11 22:29:30 +0000480 ctx.VisitDirectDepsProxy(func(child ModuleProxy) {
Jihoon Kang79196c52024-10-30 18:49:47 +0000481 depTag := ctx.OtherModuleDependencyTag(child)
482 if pi, ok := depTag.(PackagingItem); !ok || !pi.IsPackagingItem() {
Jooyung Han092ef812021-03-10 15:40:34 +0900483 return
Jiyong Parkdda8f692020-11-09 18:38:48 +0900484 }
Yu Liubad1eef2024-08-21 22:37:35 +0000485 for _, ps := range OtherModuleProviderOrDefault(
486 ctx, child, InstallFilesProvider).TransitivePackagingSpecs.ToList() {
Jiyong Parkc6a773d2024-05-14 21:49:11 +0900487 if !filterArch(ps) {
488 continue
489 }
490
Jeongik Cha54bf8752024-02-08 10:44:37 +0900491 if filter != nil {
492 if !filter(ps) {
493 continue
494 }
495 }
Jihoon Kang79196c52024-10-30 18:49:47 +0000496
Inseob Kim3c0a0422024-11-05 17:21:37 +0900497 if modifier != nil {
498 modifier(&ps)
499 }
500
Jihoon Kang79196c52024-10-30 18:49:47 +0000501 if _, ok := depTag.(highPriorityDepTag); ok {
502 highPriorities = append(highPriorities, ps)
503 } else {
504 regularPriorities = append(regularPriorities, ps)
505 }
506
Spandan Das6c2b01d2024-10-22 22:16:04 +0000507 depNames = append(depNames, child.Name())
Colin Crossf0c1ede2025-01-23 13:30:36 -0800508 overridden = append(overridden, ps.overrides.ToSlice()...)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900509 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900510 })
Jiyong Parka574d532024-08-28 18:06:43 +0900511
Jihoon Kang79196c52024-10-30 18:49:47 +0000512 filterOverridden := func(input []PackagingSpec) []PackagingSpec {
513 // input minus packaging specs that are overridden
514 var filtered []PackagingSpec
515 for index, ps := range input {
516 if ps.owner != "" && InList(ps.owner, overridden) {
517 continue
518 }
519 // The dependency which requested this packaging spec has been overridden.
520 if InList(depNames[index], overridden) {
521 continue
522 }
523 filtered = append(filtered, ps)
Jiyong Parka574d532024-08-28 18:06:43 +0900524 }
Jihoon Kang79196c52024-10-30 18:49:47 +0000525 return filtered
Jiyong Parka574d532024-08-28 18:06:43 +0900526 }
527
Jihoon Kang79196c52024-10-30 18:49:47 +0000528 filteredRegularPriority := filterOverridden(regularPriorities)
529
Jiyong Parka574d532024-08-28 18:06:43 +0900530 m := make(map[string]PackagingSpec)
Jihoon Kang79196c52024-10-30 18:49:47 +0000531 for _, ps := range filteredRegularPriority {
Jiyong Parka574d532024-08-28 18:06:43 +0900532 dstPath := ps.relPathInPackage
533 if existingPs, ok := m[dstPath]; ok {
534 if !existingPs.Equals(&ps) {
535 ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
536 }
537 continue
538 }
539 m[dstPath] = ps
540 }
Jihoon Kang79196c52024-10-30 18:49:47 +0000541
542 filteredHighPriority := filterOverridden(highPriorities)
543 highPriorityPs := make(map[string]PackagingSpec)
544 for _, ps := range filteredHighPriority {
545 dstPath := ps.relPathInPackage
546 if existingPs, ok := highPriorityPs[dstPath]; ok {
547 if !existingPs.Equals(&ps) {
548 ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps)
549 }
550 continue
551 }
552 highPriorityPs[dstPath] = ps
553 m[dstPath] = ps
554 }
555
Jooyung Handf09d172021-05-11 11:13:30 +0900556 return m
557}
Jiyong Parkdda8f692020-11-09 18:38:48 +0900558
Jeongik Cha54bf8752024-02-08 10:44:37 +0900559// See PackageModule.GatherPackagingSpecs
Inseob Kim3c0a0422024-11-05 17:21:37 +0900560func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
561 return p.GatherPackagingSpecsWithFilterAndModifier(ctx, filter, nil)
562}
563
564// See PackageModule.GatherPackagingSpecs
Jeongik Cha54bf8752024-02-08 10:44:37 +0900565func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
566 return p.GatherPackagingSpecsWithFilter(ctx, nil)
567}
568
Dan Willemsen9fe14102021-07-13 21:52:04 -0700569// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
570// entries into the specified directory.
Peter Collingbourneff56c012023-03-15 22:24:03 -0700571func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
Inseob Kim33f95a92024-07-11 15:44:49 +0900572 dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec)
573 dirsToSpecs[dir] = specs
574 return p.CopySpecsToDirs(ctx, builder, dirsToSpecs)
575}
576
577// CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec
578// entries into corresponding directories.
579func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec) (entries []string) {
580 empty := true
581 for _, specs := range dirsToSpecs {
582 if len(specs) > 0 {
583 empty = false
584 break
585 }
586 }
587 if empty {
Cole Faust3b3a0112024-01-03 15:16:55 -0800588 return entries
589 }
Inseob Kim33f95a92024-07-11 15:44:49 +0900590
Jiyong Parkdda8f692020-11-09 18:38:48 +0900591 seenDir := make(map[string]bool)
Inseob Kim33f95a92024-07-11 15:44:49 +0900592
593 dirs := make([]WritablePath, 0, len(dirsToSpecs))
594 for dir, _ := range dirsToSpecs {
595 dirs = append(dirs, dir)
596 }
597 sort.Slice(dirs, func(i, j int) bool {
598 return dirs[i].String() < dirs[j].String()
599 })
600
601 for _, dir := range dirs {
602 specs := dirsToSpecs[dir]
603 for _, k := range SortedKeys(specs) {
604 ps := specs[k]
605 destPath := filepath.Join(dir.String(), ps.relPathInPackage)
606 destDir := filepath.Dir(destPath)
607 entries = append(entries, ps.relPathInPackage)
608 if _, ok := seenDir[destDir]; !ok {
609 seenDir[destDir] = true
Cole Faustd7556eb2024-12-02 13:18:58 -0800610 builder.Command().Textf("mkdir -p %s", destDir)
Inseob Kim33f95a92024-07-11 15:44:49 +0900611 }
612 if ps.symlinkTarget == "" {
Cole Faustd7556eb2024-12-02 13:18:58 -0800613 builder.Command().Text("cp").Input(ps.srcPath).Text(destPath)
Inseob Kim33f95a92024-07-11 15:44:49 +0900614 } else {
Cole Faustd7556eb2024-12-02 13:18:58 -0800615 builder.Command().Textf("ln -sf %s %s", ps.symlinkTarget, destPath)
Inseob Kim33f95a92024-07-11 15:44:49 +0900616 }
617 if ps.executable {
Cole Faustd7556eb2024-12-02 13:18:58 -0800618 builder.Command().Textf("chmod a+x %s", destPath)
Inseob Kim33f95a92024-07-11 15:44:49 +0900619 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900620 }
621 }
622
Dan Willemsen9fe14102021-07-13 21:52:04 -0700623 return entries
624}
625
626// See PackageModule.CopyDepsToZip
Jooyung Hana8834282022-03-25 11:40:12 +0900627func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) (entries []string) {
Dan Willemsen9fe14102021-07-13 21:52:04 -0700628 builder := NewRuleBuilder(pctx, ctx)
629
630 dir := PathForModuleOut(ctx, ".zip")
631 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
632 builder.Command().Text("mkdir").Flag("-p").Text(dir.String())
Jooyung Hana8834282022-03-25 11:40:12 +0900633 entries = p.CopySpecsToDir(ctx, builder, specs, dir)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700634
Jiyong Parkdda8f692020-11-09 18:38:48 +0900635 builder.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800636 BuiltTool("soong_zip").
Jiyong Parkdda8f692020-11-09 18:38:48 +0900637 FlagWithOutput("-o ", zipOut).
638 FlagWithArg("-C ", dir.String()).
639 Flag("-L 0"). // no compression because this will be unzipped soon
640 FlagWithArg("-D ", dir.String())
641 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
642
Colin Crossf1a035e2020-11-16 17:32:30 -0800643 builder.Build("zip_deps", fmt.Sprintf("Zipping deps for %s", ctx.ModuleName()))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900644 return entries
645}