blob: 81692d5a2fa3e4c3943bb227bb25994a6135e5d9 [file] [log] [blame]
Colin Cross69452e12023-11-15 11:20:53 -08001// Copyright 2015 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
19 "github.com/google/blueprint"
20 "github.com/google/blueprint/proptools"
21 "path"
22 "path/filepath"
23 "strings"
24)
25
26// BuildParameters describes the set of potential parameters to build a Ninja rule.
27// In general, these correspond to a Ninja concept.
28type BuildParams struct {
29 // A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
30 // among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
31 // can contain variables that should be provided in Args.
32 Rule blueprint.Rule
33 // Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
34 // are used.
35 Deps blueprint.Deps
36 // Depfile is a writeable path that allows correct incremental builds when the inputs have not
37 // been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
38 Depfile WritablePath
39 // A description of the build action.
40 Description string
41 // Output is an output file of the action. When using this field, references to $out in the Ninja
42 // command will refer to this file.
43 Output WritablePath
44 // Outputs is a slice of output file of the action. When using this field, references to $out in
45 // the Ninja command will refer to these files.
46 Outputs WritablePaths
47 // SymlinkOutput is an output file specifically that is a symlink.
48 SymlinkOutput WritablePath
49 // SymlinkOutputs is a slice of output files specifically that is a symlink.
50 SymlinkOutputs WritablePaths
51 // ImplicitOutput is an output file generated by the action. Note: references to `$out` in the
52 // Ninja command will NOT include references to this file.
53 ImplicitOutput WritablePath
54 // ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out`
55 // in the Ninja command will NOT include references to these files.
56 ImplicitOutputs WritablePaths
57 // Input is an input file to the Ninja action. When using this field, references to $in in the
58 // Ninja command will refer to this file.
59 Input Path
60 // Inputs is a slice of input files to the Ninja action. When using this field, references to $in
61 // in the Ninja command will refer to these files.
62 Inputs Paths
63 // Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command
64 // will NOT include references to this file.
65 Implicit Path
66 // Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja
67 // command will NOT include references to these files.
68 Implicits Paths
69 // OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is
70 // not rebuilt until they are built, but changes in order-only dependencies alone do not cause the
71 // output to be rebuilt.
72 OrderOnly Paths
73 // Validation is an output path for a validation action. Validation outputs imply lower
74 // non-blocking priority to building non-validation outputs.
75 Validation Path
76 // Validations is a slice of output path for a validation action. Validation outputs imply lower
77 // non-blocking priority to building non-validation outputs.
78 Validations Paths
79 // Whether to skip outputting a default target statement which will be built by Ninja when no
80 // targets are specified on Ninja's command line.
81 Default bool
82 // Args is a key value mapping for replacements of variables within the Rule
83 Args map[string]string
84}
85
86type ModuleBuildParams BuildParams
87
88type ModuleContext interface {
89 BaseModuleContext
90
91 blueprintModuleContext() blueprint.ModuleContext
92
93 // Deprecated: use ModuleContext.Build instead.
94 ModuleBuild(pctx PackageContext, params ModuleBuildParams)
95
96 // Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
97 // be tagged with `android:"path" to support automatic source module dependency resolution.
98 //
99 // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
100 ExpandSources(srcFiles, excludes []string) Paths
101
102 // Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must
103 // be tagged with `android:"path" to support automatic source module dependency resolution.
104 //
105 // Deprecated: use PathForModuleSrc instead.
106 ExpandSource(srcFile, prop string) Path
107
108 ExpandOptionalSource(srcFile *string, prop string) OptionalPath
109
110 // InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
111 // with the given additional dependencies. The file is marked executable after copying.
112 //
113 // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
114 // installed file will be returned by PackagingSpecs() on this module or by
115 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
116 // for which IsInstallDepNeeded returns true.
Colin Cross09ad3a62023-11-15 12:29:33 -0800117 InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
Colin Cross69452e12023-11-15 11:20:53 -0800118
119 // InstallFile creates a rule to copy srcPath to name in the installPath directory,
120 // with the given additional dependencies.
121 //
122 // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
123 // installed file will be returned by PackagingSpecs() on this module or by
124 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
125 // for which IsInstallDepNeeded returns true.
Colin Cross09ad3a62023-11-15 12:29:33 -0800126 InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
Colin Cross69452e12023-11-15 11:20:53 -0800127
128 // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
129 // directory, and also unzip a zip file containing extra files to install into the same
130 // directory.
131 //
132 // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
133 // installed file will be returned by PackagingSpecs() on this module or by
134 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
135 // for which IsInstallDepNeeded returns true.
Colin Cross09ad3a62023-11-15 12:29:33 -0800136 InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath
Colin Cross69452e12023-11-15 11:20:53 -0800137
138 // InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
139 // directory.
140 //
141 // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
142 // installed file will be returned by PackagingSpecs() on this module or by
143 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
144 // for which IsInstallDepNeeded returns true.
145 InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
146
147 // InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
148 // in the installPath directory.
149 //
150 // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the
151 // installed file will be returned by PackagingSpecs() on this module or by
152 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
153 // for which IsInstallDepNeeded returns true.
154 InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
155
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800156 // InstallTestData creates rules to install test data (e.g. data files used during a test) into
157 // the installPath directory.
158 //
159 // The installed files will be returned by FilesToInstall(), and the PackagingSpec for the
160 // installed files will be returned by PackagingSpecs() on this module or by
161 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
162 // for which IsInstallDepNeeded returns true.
163 InstallTestData(installPath InstallPath, data []DataPath) InstallPaths
164
Colin Cross69452e12023-11-15 11:20:53 -0800165 // PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
166 // the rule to copy the file. This is useful to define how a module would be packaged
167 // without installing it into the global installation directories.
168 //
169 // The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by
170 // TransitivePackagingSpecs() on modules that depend on this module through dependency tags
171 // for which IsInstallDepNeeded returns true.
172 PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
173
174 CheckbuildFile(srcPath Path)
175
176 InstallInData() bool
177 InstallInTestcases() bool
178 InstallInSanitizerDir() bool
179 InstallInRamdisk() bool
180 InstallInVendorRamdisk() bool
181 InstallInDebugRamdisk() bool
182 InstallInRecovery() bool
183 InstallInRoot() bool
Colin Crossea30d852023-11-29 16:00:16 -0800184 InstallInOdm() bool
185 InstallInProduct() bool
Colin Cross69452e12023-11-15 11:20:53 -0800186 InstallInVendor() bool
187 InstallForceOS() (*OsType, *ArchType)
188
189 RequiredModuleNames() []string
190 HostRequiredModuleNames() []string
191 TargetRequiredModuleNames() []string
192
193 ModuleSubDir() string
194 SoongConfigTraceHash() string
195
196 Variable(pctx PackageContext, name, value string)
197 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
198 // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
199 // and performs more verification.
200 Build(pctx PackageContext, params BuildParams)
201 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other
202 // phony rules or real files. Phony can be called on the same name multiple times to add
203 // additional dependencies.
204 Phony(phony string, deps ...Path)
205
206 // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
207 // but do not exist.
208 GetMissingDependencies() []string
209
210 // LicenseMetadataFile returns the path where the license metadata for this module will be
211 // generated.
212 LicenseMetadataFile() Path
213}
214
215type moduleContext struct {
216 bp blueprint.ModuleContext
217 baseModuleContext
218 packagingSpecs []PackagingSpec
219 installFiles InstallPaths
220 checkbuildFiles Paths
221 module Module
222 phonies map[string]Paths
223
224 katiInstalls []katiInstall
225 katiSymlinks []katiInstall
226
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800227 testData []DataPath
228
Colin Cross69452e12023-11-15 11:20:53 -0800229 // For tests
230 buildParams []BuildParams
231 ruleParams map[blueprint.Rule]blueprint.RuleParams
232 variables map[string]string
233}
234
235func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
236 return pctx, BuildParams{
237 Rule: ErrorRule,
238 Description: params.Description,
239 Output: params.Output,
240 Outputs: params.Outputs,
241 ImplicitOutput: params.ImplicitOutput,
242 ImplicitOutputs: params.ImplicitOutputs,
243 Args: map[string]string{
244 "error": err.Error(),
245 },
246 }
247}
248
249func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
250 m.Build(pctx, BuildParams(params))
251}
252
253func validateBuildParams(params blueprint.BuildParams) error {
254 // Validate that the symlink outputs are declared outputs or implicit outputs
255 allOutputs := map[string]bool{}
256 for _, output := range params.Outputs {
257 allOutputs[output] = true
258 }
259 for _, output := range params.ImplicitOutputs {
260 allOutputs[output] = true
261 }
262 for _, symlinkOutput := range params.SymlinkOutputs {
263 if !allOutputs[symlinkOutput] {
264 return fmt.Errorf(
265 "Symlink output %s is not a declared output or implicit output",
266 symlinkOutput)
267 }
268 }
269 return nil
270}
271
272// Convert build parameters from their concrete Android types into their string representations,
273// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
274func convertBuildParams(params BuildParams) blueprint.BuildParams {
275 bparams := blueprint.BuildParams{
276 Rule: params.Rule,
277 Description: params.Description,
278 Deps: params.Deps,
279 Outputs: params.Outputs.Strings(),
280 ImplicitOutputs: params.ImplicitOutputs.Strings(),
281 SymlinkOutputs: params.SymlinkOutputs.Strings(),
282 Inputs: params.Inputs.Strings(),
283 Implicits: params.Implicits.Strings(),
284 OrderOnly: params.OrderOnly.Strings(),
285 Validations: params.Validations.Strings(),
286 Args: params.Args,
287 Optional: !params.Default,
288 }
289
290 if params.Depfile != nil {
291 bparams.Depfile = params.Depfile.String()
292 }
293 if params.Output != nil {
294 bparams.Outputs = append(bparams.Outputs, params.Output.String())
295 }
296 if params.SymlinkOutput != nil {
297 bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String())
298 }
299 if params.ImplicitOutput != nil {
300 bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
301 }
302 if params.Input != nil {
303 bparams.Inputs = append(bparams.Inputs, params.Input.String())
304 }
305 if params.Implicit != nil {
306 bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
307 }
308 if params.Validation != nil {
309 bparams.Validations = append(bparams.Validations, params.Validation.String())
310 }
311
312 bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
313 bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
314 bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs)
315 bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
316 bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
317 bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
318 bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
319 bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
320
321 return bparams
322}
323
324func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
325 if m.config.captureBuild {
326 m.variables[name] = value
327 }
328
329 m.bp.Variable(pctx.PackageContext, name, value)
330}
331
332func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
333 argNames ...string) blueprint.Rule {
334
335 if m.config.UseRemoteBuild() {
336 if params.Pool == nil {
337 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
338 // jobs to the local parallelism value
339 params.Pool = localPool
340 } else if params.Pool == remotePool {
341 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
342 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
343 // parallelism.
344 params.Pool = nil
345 }
346 }
347
348 rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
349
350 if m.config.captureBuild {
351 m.ruleParams[rule] = params
352 }
353
354 return rule
355}
356
357func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
358 if params.Description != "" {
359 params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
360 }
361
362 if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
363 pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
364 m.ModuleName(), strings.Join(missingDeps, ", ")))
365 }
366
367 if m.config.captureBuild {
368 m.buildParams = append(m.buildParams, params)
369 }
370
371 bparams := convertBuildParams(params)
372 err := validateBuildParams(bparams)
373 if err != nil {
374 m.ModuleErrorf(
375 "%s: build parameter validation failed: %s",
376 m.ModuleName(),
377 err.Error())
378 }
379 m.bp.Build(pctx.PackageContext, bparams)
380}
381
382func (m *moduleContext) Phony(name string, deps ...Path) {
383 addPhony(m.config, name, deps...)
384}
385
386func (m *moduleContext) GetMissingDependencies() []string {
387 var missingDeps []string
388 missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
389 missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
390 missingDeps = FirstUniqueStrings(missingDeps)
391 return missingDeps
392}
393
394func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
395 module, _ := m.getDirectDepInternal(name, tag)
396 return module
397}
398
399func (m *moduleContext) ModuleSubDir() string {
400 return m.bp.ModuleSubDir()
401}
402
403func (m *moduleContext) SoongConfigTraceHash() string {
404 return m.module.base().commonProperties.SoongConfigTraceHash
405}
406
407func (m *moduleContext) InstallInData() bool {
408 return m.module.InstallInData()
409}
410
411func (m *moduleContext) InstallInTestcases() bool {
412 return m.module.InstallInTestcases()
413}
414
415func (m *moduleContext) InstallInSanitizerDir() bool {
416 return m.module.InstallInSanitizerDir()
417}
418
419func (m *moduleContext) InstallInRamdisk() bool {
420 return m.module.InstallInRamdisk()
421}
422
423func (m *moduleContext) InstallInVendorRamdisk() bool {
424 return m.module.InstallInVendorRamdisk()
425}
426
427func (m *moduleContext) InstallInDebugRamdisk() bool {
428 return m.module.InstallInDebugRamdisk()
429}
430
431func (m *moduleContext) InstallInRecovery() bool {
432 return m.module.InstallInRecovery()
433}
434
435func (m *moduleContext) InstallInRoot() bool {
436 return m.module.InstallInRoot()
437}
438
439func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
440 return m.module.InstallForceOS()
441}
442
Colin Crossea30d852023-11-29 16:00:16 -0800443func (m *moduleContext) InstallInOdm() bool {
444 return m.module.InstallInOdm()
445}
446
447func (m *moduleContext) InstallInProduct() bool {
448 return m.module.InstallInProduct()
449}
450
Colin Cross69452e12023-11-15 11:20:53 -0800451func (m *moduleContext) InstallInVendor() bool {
452 return m.module.InstallInVendor()
453}
454
455func (m *moduleContext) skipInstall() bool {
456 if m.module.base().commonProperties.SkipInstall {
457 return true
458 }
459
460 if m.module.base().commonProperties.HideFromMake {
461 return true
462 }
463
464 // We'll need a solution for choosing which of modules with the same name in different
465 // namespaces to install. For now, reuse the list of namespaces exported to Make as the
466 // list of namespaces to install in a Soong-only build.
467 if !m.module.base().commonProperties.NamespaceExportedToMake {
468 return true
469 }
470
471 return false
472}
473
474func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800475 deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800476 return m.installFile(installPath, name, srcPath, deps, false, true, nil)
Colin Cross69452e12023-11-15 11:20:53 -0800477}
478
479func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800480 deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800481 return m.installFile(installPath, name, srcPath, deps, true, true, nil)
Colin Cross69452e12023-11-15 11:20:53 -0800482}
483
484func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800485 extraZip Path, deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800486 return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
Colin Cross69452e12023-11-15 11:20:53 -0800487 zip: extraZip,
488 dir: installPath,
489 })
490}
491
492func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
493 fullInstallPath := installPath.Join(m, name)
494 return m.packageFile(fullInstallPath, srcPath, false)
495}
496
497func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
498 licenseFiles := m.Module().EffectiveLicenseFiles()
499 spec := PackagingSpec{
500 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
501 srcPath: srcPath,
502 symlinkTarget: "",
503 executable: executable,
504 effectiveLicenseFiles: &licenseFiles,
505 partition: fullInstallPath.partition,
506 }
507 m.packagingSpecs = append(m.packagingSpecs, spec)
508 return spec
509}
510
Colin Cross09ad3a62023-11-15 12:29:33 -0800511func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800512 executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
Colin Cross69452e12023-11-15 11:20:53 -0800513
514 fullInstallPath := installPath.Join(m, name)
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800515 if hooks {
516 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
517 }
Colin Cross69452e12023-11-15 11:20:53 -0800518
519 if !m.skipInstall() {
Colin Cross09ad3a62023-11-15 12:29:33 -0800520 deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
Colin Cross69452e12023-11-15 11:20:53 -0800521
522 var implicitDeps, orderOnlyDeps Paths
523
524 if m.Host() {
525 // Installed host modules might be used during the build, depend directly on their
526 // dependencies so their timestamp is updated whenever their dependency is updated
Colin Cross09ad3a62023-11-15 12:29:33 -0800527 implicitDeps = InstallPaths(deps).Paths()
Colin Cross69452e12023-11-15 11:20:53 -0800528 } else {
Colin Cross09ad3a62023-11-15 12:29:33 -0800529 orderOnlyDeps = InstallPaths(deps).Paths()
Colin Cross69452e12023-11-15 11:20:53 -0800530 }
531
532 if m.Config().KatiEnabled() {
533 // When creating the install rule in Soong but embedding in Make, write the rule to a
534 // makefile instead of directly to the ninja file so that main.mk can add the
535 // dependencies from the `required` property that are hard to resolve in Soong.
536 m.katiInstalls = append(m.katiInstalls, katiInstall{
537 from: srcPath,
538 to: fullInstallPath,
539 implicitDeps: implicitDeps,
540 orderOnlyDeps: orderOnlyDeps,
541 executable: executable,
542 extraFiles: extraZip,
543 })
544 } else {
545 rule := Cp
546 if executable {
547 rule = CpExecutable
548 }
549
550 extraCmds := ""
551 if extraZip != nil {
552 extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
553 extraZip.dir.String(), extraZip.zip.String())
554 extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
555 implicitDeps = append(implicitDeps, extraZip.zip)
556 }
557
558 m.Build(pctx, BuildParams{
559 Rule: rule,
560 Description: "install " + fullInstallPath.Base(),
561 Output: fullInstallPath,
562 Input: srcPath,
563 Implicits: implicitDeps,
564 OrderOnly: orderOnlyDeps,
565 Default: !m.Config().KatiEnabled(),
566 Args: map[string]string{
567 "extraCmds": extraCmds,
568 },
569 })
570 }
571
572 m.installFiles = append(m.installFiles, fullInstallPath)
573 }
574
575 m.packageFile(fullInstallPath, srcPath, executable)
576
577 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
578
579 return fullInstallPath
580}
581
582func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
583 fullInstallPath := installPath.Join(m, name)
584 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
585
586 relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
587 if err != nil {
588 panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
589 }
590 if !m.skipInstall() {
591
592 if m.Config().KatiEnabled() {
593 // When creating the symlink rule in Soong but embedding in Make, write the rule to a
594 // makefile instead of directly to the ninja file so that main.mk can add the
595 // dependencies from the `required` property that are hard to resolve in Soong.
596 m.katiSymlinks = append(m.katiSymlinks, katiInstall{
597 from: srcPath,
598 to: fullInstallPath,
599 })
600 } else {
601 // The symlink doesn't need updating when the target is modified, but we sometimes
602 // have a dependency on a symlink to a binary instead of to the binary directly, and
603 // the mtime of the symlink must be updated when the binary is modified, so use a
604 // normal dependency here instead of an order-only dependency.
605 m.Build(pctx, BuildParams{
606 Rule: Symlink,
607 Description: "install symlink " + fullInstallPath.Base(),
608 Output: fullInstallPath,
609 Input: srcPath,
610 Default: !m.Config().KatiEnabled(),
611 Args: map[string]string{
612 "fromPath": relPath,
613 },
614 })
615 }
616
617 m.installFiles = append(m.installFiles, fullInstallPath)
618 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
619 }
620
621 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
622 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
623 srcPath: nil,
624 symlinkTarget: relPath,
625 executable: false,
626 partition: fullInstallPath.partition,
627 })
628
629 return fullInstallPath
630}
631
632// installPath/name -> absPath where absPath might be a path that is available only at runtime
633// (e.g. /apex/...)
634func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
635 fullInstallPath := installPath.Join(m, name)
636 m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
637
638 if !m.skipInstall() {
639 if m.Config().KatiEnabled() {
640 // When creating the symlink rule in Soong but embedding in Make, write the rule to a
641 // makefile instead of directly to the ninja file so that main.mk can add the
642 // dependencies from the `required` property that are hard to resolve in Soong.
643 m.katiSymlinks = append(m.katiSymlinks, katiInstall{
644 absFrom: absPath,
645 to: fullInstallPath,
646 })
647 } else {
648 m.Build(pctx, BuildParams{
649 Rule: Symlink,
650 Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
651 Output: fullInstallPath,
652 Default: !m.Config().KatiEnabled(),
653 Args: map[string]string{
654 "fromPath": absPath,
655 },
656 })
657 }
658
659 m.installFiles = append(m.installFiles, fullInstallPath)
660 }
661
662 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
663 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
664 srcPath: nil,
665 symlinkTarget: absPath,
666 executable: false,
667 partition: fullInstallPath.partition,
668 })
669
670 return fullInstallPath
671}
672
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800673func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath) InstallPaths {
674 m.testData = append(m.testData, data...)
675
676 ret := make(InstallPaths, 0, len(data))
677 for _, d := range data {
678 relPath := d.ToRelativeInstallPath()
679 installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
680 ret = append(ret, installed)
681 }
682
683 return ret
684}
685
Colin Cross69452e12023-11-15 11:20:53 -0800686func (m *moduleContext) CheckbuildFile(srcPath Path) {
687 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
688}
689
690func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
691 return m.bp
692}
693
694func (m *moduleContext) LicenseMetadataFile() Path {
695 return m.module.base().licenseMetadataFile
696}
697
698// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
699// be tagged with `android:"path" to support automatic source module dependency resolution.
700//
701// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
702func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
703 return PathsForModuleSrcExcludes(m, srcFiles, excludes)
704}
705
706// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must
707// be tagged with `android:"path" to support automatic source module dependency resolution.
708//
709// Deprecated: use PathForModuleSrc instead.
710func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
711 return PathForModuleSrc(m, srcFile)
712}
713
714// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
715// the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module
716// dependency resolution.
717func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
718 if srcFile != nil {
719 return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
720 }
721 return OptionalPath{}
722}
723
724func (m *moduleContext) RequiredModuleNames() []string {
725 return m.module.RequiredModuleNames()
726}
727
728func (m *moduleContext) HostRequiredModuleNames() []string {
729 return m.module.HostRequiredModuleNames()
730}
731
732func (m *moduleContext) TargetRequiredModuleNames() []string {
733 return m.module.TargetRequiredModuleNames()
734}