blob: a8fb28d302fd6a159143749f0389e8f0e094fba7 [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"
Jeongik Cha76e677f2023-12-21 16:39:15 +090020 "strings"
Jiyong Parkdda8f692020-11-09 18:38:48 +090021
22 "github.com/google/blueprint"
23)
24
Jiyong Parkcc1157c2020-11-25 11:31:13 +090025// PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A
26// package can be the traditional <partition>.img, but isn't limited to those. Other examples could
27// be a new filesystem image that is a subset of system.img (e.g. for an Android-like mini OS
28// running on a VM), or a zip archive for some of the host tools.
Jiyong Park073ea552020-11-09 14:08:34 +090029type PackagingSpec struct {
30 // Path relative to the root of the package
31 relPathInPackage string
32
33 // The path to the built artifact
34 srcPath Path
35
36 // If this is not empty, then relPathInPackage should be a symlink to this target. (Then
37 // srcPath is of course ignored.)
38 symlinkTarget string
39
40 // Whether relPathInPackage should be marked as executable or not
41 executable bool
Dan Willemsen9fe14102021-07-13 21:52:04 -070042
43 effectiveLicenseFiles *Paths
Jooyung Han99c5fe62022-03-21 15:13:38 +090044
45 partition string
Jiyong Park073ea552020-11-09 14:08:34 +090046}
Jiyong Parkdda8f692020-11-09 18:38:48 +090047
Kiyoung Kim24dfc1f2020-11-16 10:48:44 +090048// Get file name of installed package
49func (p *PackagingSpec) FileName() string {
50 if p.relPathInPackage != "" {
51 return filepath.Base(p.relPathInPackage)
52 }
53
54 return ""
55}
56
Jiyong Park6446b622021-02-01 20:08:28 +090057// Path relative to the root of the package
58func (p *PackagingSpec) RelPathInPackage() string {
59 return p.relPathInPackage
60}
61
Dan Willemsen9fe14102021-07-13 21:52:04 -070062func (p *PackagingSpec) SetRelPathInPackage(relPathInPackage string) {
63 p.relPathInPackage = relPathInPackage
64}
65
66func (p *PackagingSpec) EffectiveLicenseFiles() Paths {
67 if p.effectiveLicenseFiles == nil {
68 return Paths{}
69 }
70 return *p.effectiveLicenseFiles
71}
72
Jooyung Han99c5fe62022-03-21 15:13:38 +090073func (p *PackagingSpec) Partition() string {
74 return p.partition
75}
76
Jiyong Parkdda8f692020-11-09 18:38:48 +090077type PackageModule interface {
78 Module
79 packagingBase() *PackagingBase
80
81 // AddDeps adds dependencies to the `deps` modules. This should be called in DepsMutator.
Jooyung Han092ef812021-03-10 15:40:34 +090082 // When adding the dependencies, depTag is used as the tag. If `deps` modules are meant to
83 // be copied to a zip in CopyDepsToZip, `depTag` should implement PackagingItem marker interface.
Jiyong Park65b62242020-11-25 12:44:59 +090084 AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag)
Jiyong Parkdda8f692020-11-09 18:38:48 +090085
Jooyung Hana8834282022-03-25 11:40:12 +090086 // GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
87 GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
Jeongik Cha54bf8752024-02-08 10:44:37 +090088 GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
Jooyung Hana8834282022-03-25 11:40:12 +090089
Jiyong Parkdda8f692020-11-09 18:38:48 +090090 // CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
Jiyong Parkcc1157c2020-11-25 11:31:13 +090091 // returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
Jiyong Parkdda8f692020-11-09 18:38:48 +090092 // followed by a build rule that unzips it and creates the final output (img, zip, tar.gz,
93 // etc.) from the extracted files
Jooyung Hana8834282022-03-25 11:40:12 +090094 CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) []string
Jiyong Parkdda8f692020-11-09 18:38:48 +090095}
96
97// PackagingBase provides basic functionality for packaging dependencies. A module is expected to
98// include this struct and call InitPackageModule.
99type PackagingBase struct {
100 properties PackagingProperties
101
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900102 // Allows this module to skip missing dependencies. In most cases, this is not required, but
103 // for rare cases like when there's a dependency to a module which exists in certain repo
104 // checkouts, this is needed.
Jiyong Parkdda8f692020-11-09 18:38:48 +0900105 IgnoreMissingDependencies bool
106}
107
108type depsProperty struct {
109 // Modules to include in this package
110 Deps []string `android:"arch_variant"`
111}
112
113type packagingMultilibProperties struct {
114 First depsProperty `android:"arch_variant"`
115 Common depsProperty `android:"arch_variant"`
116 Lib32 depsProperty `android:"arch_variant"`
117 Lib64 depsProperty `android:"arch_variant"`
118}
119
Jiyong Park2136d152021-02-01 23:24:56 +0900120type packagingArchProperties struct {
121 Arm64 depsProperty
122 Arm depsProperty
123 X86_64 depsProperty
124 X86 depsProperty
125}
126
Jiyong Parkdda8f692020-11-09 18:38:48 +0900127type PackagingProperties struct {
128 Deps []string `android:"arch_variant"`
129 Multilib packagingMultilibProperties `android:"arch_variant"`
Jiyong Park2136d152021-02-01 23:24:56 +0900130 Arch packagingArchProperties
Jiyong Parkdda8f692020-11-09 18:38:48 +0900131}
132
Jiyong Parkdda8f692020-11-09 18:38:48 +0900133func InitPackageModule(p PackageModule) {
134 base := p.packagingBase()
135 p.AddProperties(&base.properties)
136}
137
138func (p *PackagingBase) packagingBase() *PackagingBase {
139 return p
140}
141
Jiyong Parkcc1157c2020-11-25 11:31:13 +0900142// From deps and multilib.*.deps, select the dependencies that are for the given arch deps is for
143// the current archicture when this module is not configured for multi target. When configured for
144// multi target, deps is selected for each of the targets and is NOT selected for the current
145// architecture which would be Common.
Jiyong Parkdda8f692020-11-09 18:38:48 +0900146func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []string {
147 var ret []string
148 if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
149 ret = append(ret, p.properties.Deps...)
150 } else if arch.Multilib == "lib32" {
151 ret = append(ret, p.properties.Multilib.Lib32.Deps...)
152 } else if arch.Multilib == "lib64" {
153 ret = append(ret, p.properties.Multilib.Lib64.Deps...)
154 } else if arch == Common {
155 ret = append(ret, p.properties.Multilib.Common.Deps...)
156 }
Jiyong Park2136d152021-02-01 23:24:56 +0900157
Jiyong Parkdda8f692020-11-09 18:38:48 +0900158 for i, t := range ctx.MultiTargets() {
159 if t.Arch.ArchType == arch {
160 ret = append(ret, p.properties.Deps...)
161 if i == 0 {
162 ret = append(ret, p.properties.Multilib.First.Deps...)
163 }
164 }
165 }
Jiyong Park2136d152021-02-01 23:24:56 +0900166
167 if ctx.Arch().ArchType == Common {
168 switch arch {
169 case Arm64:
170 ret = append(ret, p.properties.Arch.Arm64.Deps...)
171 case Arm:
172 ret = append(ret, p.properties.Arch.Arm.Deps...)
173 case X86_64:
174 ret = append(ret, p.properties.Arch.X86_64.Deps...)
175 case X86:
176 ret = append(ret, p.properties.Arch.X86.Deps...)
177 }
178 }
179
Jiyong Parkdda8f692020-11-09 18:38:48 +0900180 return FirstUniqueStrings(ret)
181}
182
183func (p *PackagingBase) getSupportedTargets(ctx BaseModuleContext) []Target {
184 var ret []Target
185 // The current and the common OS targets are always supported
186 ret = append(ret, ctx.Target())
187 if ctx.Arch().ArchType != Common {
188 ret = append(ret, Target{Os: ctx.Os(), Arch: Arch{ArchType: Common}})
189 }
190 // If this module is configured for multi targets, those should be supported as well
191 ret = append(ret, ctx.MultiTargets()...)
192 return ret
193}
194
Jooyung Han092ef812021-03-10 15:40:34 +0900195// PackagingItem is a marker interface for dependency tags.
196// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip().
197type PackagingItem interface {
198 // IsPackagingItem returns true if the dep is to be packaged
199 IsPackagingItem() bool
200}
201
202// DepTag provides default implementation of PackagingItem interface.
203// PackagingBase-derived modules can define their own dependency tag by embedding this, which
204// can be passed to AddDeps() or AddDependencies().
205type PackagingItemAlwaysDepTag struct {
206}
207
208// IsPackagingItem returns true if the dep is to be packaged
209func (PackagingItemAlwaysDepTag) IsPackagingItem() bool {
210 return true
211}
212
Jiyong Parkdda8f692020-11-09 18:38:48 +0900213// See PackageModule.AddDeps
Jiyong Park65b62242020-11-25 12:44:59 +0900214func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
Jiyong Parkdda8f692020-11-09 18:38:48 +0900215 for _, t := range p.getSupportedTargets(ctx) {
216 for _, dep := range p.getDepsForArch(ctx, t.Arch.ArchType) {
217 if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
218 continue
219 }
220 ctx.AddFarVariationDependencies(t.Variations(), depTag, dep)
221 }
222 }
223}
224
Jeongik Cha54bf8752024-02-08 10:44:37 +0900225func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
Jiyong Parkdda8f692020-11-09 18:38:48 +0900226 m := make(map[string]PackagingSpec)
Jooyung Han092ef812021-03-10 15:40:34 +0900227 ctx.VisitDirectDeps(func(child Module) {
228 if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
229 return
Jiyong Parkdda8f692020-11-09 18:38:48 +0900230 }
Jooyung Han092ef812021-03-10 15:40:34 +0900231 for _, ps := range child.TransitivePackagingSpecs() {
Jeongik Cha54bf8752024-02-08 10:44:37 +0900232 if filter != nil {
233 if !filter(ps) {
234 continue
235 }
236 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900237 if _, ok := m[ps.relPathInPackage]; !ok {
238 m[ps.relPathInPackage] = ps
239 }
240 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900241 })
Jooyung Handf09d172021-05-11 11:13:30 +0900242 return m
243}
Jiyong Parkdda8f692020-11-09 18:38:48 +0900244
Jeongik Cha54bf8752024-02-08 10:44:37 +0900245// See PackageModule.GatherPackagingSpecs
246func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
247 return p.GatherPackagingSpecsWithFilter(ctx, nil)
248}
249
Dan Willemsen9fe14102021-07-13 21:52:04 -0700250// CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
251// entries into the specified directory.
Peter Collingbourneff56c012023-03-15 22:24:03 -0700252func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
Cole Faust3b3a0112024-01-03 15:16:55 -0800253 if len(specs) == 0 {
254 return entries
255 }
Jiyong Parkdda8f692020-11-09 18:38:48 +0900256 seenDir := make(map[string]bool)
Jeongik Cha76e677f2023-12-21 16:39:15 +0900257 preparerPath := PathForModuleOut(ctx, "preparer.sh")
258 cmd := builder.Command().Tool(preparerPath)
259 var sb strings.Builder
Cole Faust3b3a0112024-01-03 15:16:55 -0800260 sb.WriteString("set -e\n")
Cole Faust18994c72023-02-28 16:02:16 -0800261 for _, k := range SortedKeys(specs) {
Jooyung Hana8834282022-03-25 11:40:12 +0900262 ps := specs[k]
Peter Collingbourneff56c012023-03-15 22:24:03 -0700263 destPath := filepath.Join(dir.String(), ps.relPathInPackage)
Jiyong Parkdda8f692020-11-09 18:38:48 +0900264 destDir := filepath.Dir(destPath)
265 entries = append(entries, ps.relPathInPackage)
266 if _, ok := seenDir[destDir]; !ok {
267 seenDir[destDir] = true
Jeongik Cha76e677f2023-12-21 16:39:15 +0900268 sb.WriteString(fmt.Sprintf("mkdir -p %s\n", destDir))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900269 }
270 if ps.symlinkTarget == "" {
Jeongik Cha76e677f2023-12-21 16:39:15 +0900271 cmd.Implicit(ps.srcPath)
272 sb.WriteString(fmt.Sprintf("cp %s %s\n", ps.srcPath, destPath))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900273 } else {
Jeongik Cha76e677f2023-12-21 16:39:15 +0900274 sb.WriteString(fmt.Sprintf("ln -sf %s %s\n", ps.symlinkTarget, destPath))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900275 }
276 if ps.executable {
Jeongik Cha76e677f2023-12-21 16:39:15 +0900277 sb.WriteString(fmt.Sprintf("chmod a+x %s\n", destPath))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900278 }
279 }
280
Jeongik Cha76e677f2023-12-21 16:39:15 +0900281 WriteExecutableFileRuleVerbatim(ctx, preparerPath, sb.String())
282
Dan Willemsen9fe14102021-07-13 21:52:04 -0700283 return entries
284}
285
286// See PackageModule.CopyDepsToZip
Jooyung Hana8834282022-03-25 11:40:12 +0900287func (p *PackagingBase) CopyDepsToZip(ctx ModuleContext, specs map[string]PackagingSpec, zipOut WritablePath) (entries []string) {
Dan Willemsen9fe14102021-07-13 21:52:04 -0700288 builder := NewRuleBuilder(pctx, ctx)
289
290 dir := PathForModuleOut(ctx, ".zip")
291 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
292 builder.Command().Text("mkdir").Flag("-p").Text(dir.String())
Jooyung Hana8834282022-03-25 11:40:12 +0900293 entries = p.CopySpecsToDir(ctx, builder, specs, dir)
Dan Willemsen9fe14102021-07-13 21:52:04 -0700294
Jiyong Parkdda8f692020-11-09 18:38:48 +0900295 builder.Command().
Colin Crossf1a035e2020-11-16 17:32:30 -0800296 BuiltTool("soong_zip").
Jiyong Parkdda8f692020-11-09 18:38:48 +0900297 FlagWithOutput("-o ", zipOut).
298 FlagWithArg("-C ", dir.String()).
299 Flag("-L 0"). // no compression because this will be unzipped soon
300 FlagWithArg("-D ", dir.String())
301 builder.Command().Text("rm").Flag("-rf").Text(dir.String())
302
Colin Crossf1a035e2020-11-16 17:32:30 -0800303 builder.Build("zip_deps", fmt.Sprintf("Zipping deps for %s", ctx.ModuleName()))
Jiyong Parkdda8f692020-11-09 18:38:48 +0900304 return entries
305}