blob: 39986df87986c161ccb7ac0aaf0cfd3f3f806fa2 [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
184 InstallInVendor() bool
185 InstallForceOS() (*OsType, *ArchType)
186
187 RequiredModuleNames() []string
188 HostRequiredModuleNames() []string
189 TargetRequiredModuleNames() []string
190
191 ModuleSubDir() string
192 SoongConfigTraceHash() string
193
194 Variable(pctx PackageContext, name, value string)
195 Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
196 // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
197 // and performs more verification.
198 Build(pctx PackageContext, params BuildParams)
199 // Phony creates a Make-style phony rule, a rule with no commands that can depend on other
200 // phony rules or real files. Phony can be called on the same name multiple times to add
201 // additional dependencies.
202 Phony(phony string, deps ...Path)
203
204 // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
205 // but do not exist.
206 GetMissingDependencies() []string
207
208 // LicenseMetadataFile returns the path where the license metadata for this module will be
209 // generated.
210 LicenseMetadataFile() Path
211}
212
213type moduleContext struct {
214 bp blueprint.ModuleContext
215 baseModuleContext
216 packagingSpecs []PackagingSpec
217 installFiles InstallPaths
218 checkbuildFiles Paths
219 module Module
220 phonies map[string]Paths
221
222 katiInstalls []katiInstall
223 katiSymlinks []katiInstall
224
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800225 testData []DataPath
226
Colin Cross69452e12023-11-15 11:20:53 -0800227 // For tests
228 buildParams []BuildParams
229 ruleParams map[blueprint.Rule]blueprint.RuleParams
230 variables map[string]string
231}
232
233func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
234 return pctx, BuildParams{
235 Rule: ErrorRule,
236 Description: params.Description,
237 Output: params.Output,
238 Outputs: params.Outputs,
239 ImplicitOutput: params.ImplicitOutput,
240 ImplicitOutputs: params.ImplicitOutputs,
241 Args: map[string]string{
242 "error": err.Error(),
243 },
244 }
245}
246
247func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
248 m.Build(pctx, BuildParams(params))
249}
250
251func validateBuildParams(params blueprint.BuildParams) error {
252 // Validate that the symlink outputs are declared outputs or implicit outputs
253 allOutputs := map[string]bool{}
254 for _, output := range params.Outputs {
255 allOutputs[output] = true
256 }
257 for _, output := range params.ImplicitOutputs {
258 allOutputs[output] = true
259 }
260 for _, symlinkOutput := range params.SymlinkOutputs {
261 if !allOutputs[symlinkOutput] {
262 return fmt.Errorf(
263 "Symlink output %s is not a declared output or implicit output",
264 symlinkOutput)
265 }
266 }
267 return nil
268}
269
270// Convert build parameters from their concrete Android types into their string representations,
271// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
272func convertBuildParams(params BuildParams) blueprint.BuildParams {
273 bparams := blueprint.BuildParams{
274 Rule: params.Rule,
275 Description: params.Description,
276 Deps: params.Deps,
277 Outputs: params.Outputs.Strings(),
278 ImplicitOutputs: params.ImplicitOutputs.Strings(),
279 SymlinkOutputs: params.SymlinkOutputs.Strings(),
280 Inputs: params.Inputs.Strings(),
281 Implicits: params.Implicits.Strings(),
282 OrderOnly: params.OrderOnly.Strings(),
283 Validations: params.Validations.Strings(),
284 Args: params.Args,
285 Optional: !params.Default,
286 }
287
288 if params.Depfile != nil {
289 bparams.Depfile = params.Depfile.String()
290 }
291 if params.Output != nil {
292 bparams.Outputs = append(bparams.Outputs, params.Output.String())
293 }
294 if params.SymlinkOutput != nil {
295 bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String())
296 }
297 if params.ImplicitOutput != nil {
298 bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
299 }
300 if params.Input != nil {
301 bparams.Inputs = append(bparams.Inputs, params.Input.String())
302 }
303 if params.Implicit != nil {
304 bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
305 }
306 if params.Validation != nil {
307 bparams.Validations = append(bparams.Validations, params.Validation.String())
308 }
309
310 bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
311 bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
312 bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs)
313 bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
314 bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
315 bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
316 bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
317 bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
318
319 return bparams
320}
321
322func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
323 if m.config.captureBuild {
324 m.variables[name] = value
325 }
326
327 m.bp.Variable(pctx.PackageContext, name, value)
328}
329
330func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
331 argNames ...string) blueprint.Rule {
332
333 if m.config.UseRemoteBuild() {
334 if params.Pool == nil {
335 // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
336 // jobs to the local parallelism value
337 params.Pool = localPool
338 } else if params.Pool == remotePool {
339 // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
340 // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
341 // parallelism.
342 params.Pool = nil
343 }
344 }
345
346 rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
347
348 if m.config.captureBuild {
349 m.ruleParams[rule] = params
350 }
351
352 return rule
353}
354
355func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
356 if params.Description != "" {
357 params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
358 }
359
360 if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
361 pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
362 m.ModuleName(), strings.Join(missingDeps, ", ")))
363 }
364
365 if m.config.captureBuild {
366 m.buildParams = append(m.buildParams, params)
367 }
368
369 bparams := convertBuildParams(params)
370 err := validateBuildParams(bparams)
371 if err != nil {
372 m.ModuleErrorf(
373 "%s: build parameter validation failed: %s",
374 m.ModuleName(),
375 err.Error())
376 }
377 m.bp.Build(pctx.PackageContext, bparams)
378}
379
380func (m *moduleContext) Phony(name string, deps ...Path) {
381 addPhony(m.config, name, deps...)
382}
383
384func (m *moduleContext) GetMissingDependencies() []string {
385 var missingDeps []string
386 missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
387 missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
388 missingDeps = FirstUniqueStrings(missingDeps)
389 return missingDeps
390}
391
392func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
393 module, _ := m.getDirectDepInternal(name, tag)
394 return module
395}
396
397func (m *moduleContext) ModuleSubDir() string {
398 return m.bp.ModuleSubDir()
399}
400
401func (m *moduleContext) SoongConfigTraceHash() string {
402 return m.module.base().commonProperties.SoongConfigTraceHash
403}
404
405func (m *moduleContext) InstallInData() bool {
406 return m.module.InstallInData()
407}
408
409func (m *moduleContext) InstallInTestcases() bool {
410 return m.module.InstallInTestcases()
411}
412
413func (m *moduleContext) InstallInSanitizerDir() bool {
414 return m.module.InstallInSanitizerDir()
415}
416
417func (m *moduleContext) InstallInRamdisk() bool {
418 return m.module.InstallInRamdisk()
419}
420
421func (m *moduleContext) InstallInVendorRamdisk() bool {
422 return m.module.InstallInVendorRamdisk()
423}
424
425func (m *moduleContext) InstallInDebugRamdisk() bool {
426 return m.module.InstallInDebugRamdisk()
427}
428
429func (m *moduleContext) InstallInRecovery() bool {
430 return m.module.InstallInRecovery()
431}
432
433func (m *moduleContext) InstallInRoot() bool {
434 return m.module.InstallInRoot()
435}
436
437func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
438 return m.module.InstallForceOS()
439}
440
441func (m *moduleContext) InstallInVendor() bool {
442 return m.module.InstallInVendor()
443}
444
445func (m *moduleContext) skipInstall() bool {
446 if m.module.base().commonProperties.SkipInstall {
447 return true
448 }
449
450 if m.module.base().commonProperties.HideFromMake {
451 return true
452 }
453
454 // We'll need a solution for choosing which of modules with the same name in different
455 // namespaces to install. For now, reuse the list of namespaces exported to Make as the
456 // list of namespaces to install in a Soong-only build.
457 if !m.module.base().commonProperties.NamespaceExportedToMake {
458 return true
459 }
460
461 return false
462}
463
464func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800465 deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800466 return m.installFile(installPath, name, srcPath, deps, false, true, nil)
Colin Cross69452e12023-11-15 11:20:53 -0800467}
468
469func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800470 deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800471 return m.installFile(installPath, name, srcPath, deps, true, true, nil)
Colin Cross69452e12023-11-15 11:20:53 -0800472}
473
474func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
Colin Cross09ad3a62023-11-15 12:29:33 -0800475 extraZip Path, deps ...InstallPath) InstallPath {
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800476 return m.installFile(installPath, name, srcPath, deps, false, true, &extraFilesZip{
Colin Cross69452e12023-11-15 11:20:53 -0800477 zip: extraZip,
478 dir: installPath,
479 })
480}
481
482func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
483 fullInstallPath := installPath.Join(m, name)
484 return m.packageFile(fullInstallPath, srcPath, false)
485}
486
487func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
488 licenseFiles := m.Module().EffectiveLicenseFiles()
489 spec := PackagingSpec{
490 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
491 srcPath: srcPath,
492 symlinkTarget: "",
493 executable: executable,
494 effectiveLicenseFiles: &licenseFiles,
495 partition: fullInstallPath.partition,
496 }
497 m.packagingSpecs = append(m.packagingSpecs, spec)
498 return spec
499}
500
Colin Cross09ad3a62023-11-15 12:29:33 -0800501func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800502 executable bool, hooks bool, extraZip *extraFilesZip) InstallPath {
Colin Cross69452e12023-11-15 11:20:53 -0800503
504 fullInstallPath := installPath.Join(m, name)
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800505 if hooks {
506 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
507 }
Colin Cross69452e12023-11-15 11:20:53 -0800508
509 if !m.skipInstall() {
Colin Cross09ad3a62023-11-15 12:29:33 -0800510 deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...)
Colin Cross69452e12023-11-15 11:20:53 -0800511
512 var implicitDeps, orderOnlyDeps Paths
513
514 if m.Host() {
515 // Installed host modules might be used during the build, depend directly on their
516 // dependencies so their timestamp is updated whenever their dependency is updated
Colin Cross09ad3a62023-11-15 12:29:33 -0800517 implicitDeps = InstallPaths(deps).Paths()
Colin Cross69452e12023-11-15 11:20:53 -0800518 } else {
Colin Cross09ad3a62023-11-15 12:29:33 -0800519 orderOnlyDeps = InstallPaths(deps).Paths()
Colin Cross69452e12023-11-15 11:20:53 -0800520 }
521
522 if m.Config().KatiEnabled() {
523 // When creating the install rule in Soong but embedding in Make, write the rule to a
524 // makefile instead of directly to the ninja file so that main.mk can add the
525 // dependencies from the `required` property that are hard to resolve in Soong.
526 m.katiInstalls = append(m.katiInstalls, katiInstall{
527 from: srcPath,
528 to: fullInstallPath,
529 implicitDeps: implicitDeps,
530 orderOnlyDeps: orderOnlyDeps,
531 executable: executable,
532 extraFiles: extraZip,
533 })
534 } else {
535 rule := Cp
536 if executable {
537 rule = CpExecutable
538 }
539
540 extraCmds := ""
541 if extraZip != nil {
542 extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
543 extraZip.dir.String(), extraZip.zip.String())
544 extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
545 implicitDeps = append(implicitDeps, extraZip.zip)
546 }
547
548 m.Build(pctx, BuildParams{
549 Rule: rule,
550 Description: "install " + fullInstallPath.Base(),
551 Output: fullInstallPath,
552 Input: srcPath,
553 Implicits: implicitDeps,
554 OrderOnly: orderOnlyDeps,
555 Default: !m.Config().KatiEnabled(),
556 Args: map[string]string{
557 "extraCmds": extraCmds,
558 },
559 })
560 }
561
562 m.installFiles = append(m.installFiles, fullInstallPath)
563 }
564
565 m.packageFile(fullInstallPath, srcPath, executable)
566
567 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
568
569 return fullInstallPath
570}
571
572func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
573 fullInstallPath := installPath.Join(m, name)
574 m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
575
576 relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
577 if err != nil {
578 panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
579 }
580 if !m.skipInstall() {
581
582 if m.Config().KatiEnabled() {
583 // When creating the symlink rule in Soong but embedding in Make, write the rule to a
584 // makefile instead of directly to the ninja file so that main.mk can add the
585 // dependencies from the `required` property that are hard to resolve in Soong.
586 m.katiSymlinks = append(m.katiSymlinks, katiInstall{
587 from: srcPath,
588 to: fullInstallPath,
589 })
590 } else {
591 // The symlink doesn't need updating when the target is modified, but we sometimes
592 // have a dependency on a symlink to a binary instead of to the binary directly, and
593 // the mtime of the symlink must be updated when the binary is modified, so use a
594 // normal dependency here instead of an order-only dependency.
595 m.Build(pctx, BuildParams{
596 Rule: Symlink,
597 Description: "install symlink " + fullInstallPath.Base(),
598 Output: fullInstallPath,
599 Input: srcPath,
600 Default: !m.Config().KatiEnabled(),
601 Args: map[string]string{
602 "fromPath": relPath,
603 },
604 })
605 }
606
607 m.installFiles = append(m.installFiles, fullInstallPath)
608 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
609 }
610
611 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
612 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
613 srcPath: nil,
614 symlinkTarget: relPath,
615 executable: false,
616 partition: fullInstallPath.partition,
617 })
618
619 return fullInstallPath
620}
621
622// installPath/name -> absPath where absPath might be a path that is available only at runtime
623// (e.g. /apex/...)
624func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
625 fullInstallPath := installPath.Join(m, name)
626 m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
627
628 if !m.skipInstall() {
629 if m.Config().KatiEnabled() {
630 // When creating the symlink rule in Soong but embedding in Make, write the rule to a
631 // makefile instead of directly to the ninja file so that main.mk can add the
632 // dependencies from the `required` property that are hard to resolve in Soong.
633 m.katiSymlinks = append(m.katiSymlinks, katiInstall{
634 absFrom: absPath,
635 to: fullInstallPath,
636 })
637 } else {
638 m.Build(pctx, BuildParams{
639 Rule: Symlink,
640 Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
641 Output: fullInstallPath,
642 Default: !m.Config().KatiEnabled(),
643 Args: map[string]string{
644 "fromPath": absPath,
645 },
646 })
647 }
648
649 m.installFiles = append(m.installFiles, fullInstallPath)
650 }
651
652 m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
653 relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
654 srcPath: nil,
655 symlinkTarget: absPath,
656 executable: false,
657 partition: fullInstallPath.partition,
658 })
659
660 return fullInstallPath
661}
662
Colin Cross5c1d5fb2023-11-15 12:39:40 -0800663func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath) InstallPaths {
664 m.testData = append(m.testData, data...)
665
666 ret := make(InstallPaths, 0, len(data))
667 for _, d := range data {
668 relPath := d.ToRelativeInstallPath()
669 installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, nil)
670 ret = append(ret, installed)
671 }
672
673 return ret
674}
675
Colin Cross69452e12023-11-15 11:20:53 -0800676func (m *moduleContext) CheckbuildFile(srcPath Path) {
677 m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
678}
679
680func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext {
681 return m.bp
682}
683
684func (m *moduleContext) LicenseMetadataFile() Path {
685 return m.module.base().licenseMetadataFile
686}
687
688// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must
689// be tagged with `android:"path" to support automatic source module dependency resolution.
690//
691// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
692func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
693 return PathsForModuleSrcExcludes(m, srcFiles, excludes)
694}
695
696// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must
697// be tagged with `android:"path" to support automatic source module dependency resolution.
698//
699// Deprecated: use PathForModuleSrc instead.
700func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
701 return PathForModuleSrc(m, srcFile)
702}
703
704// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
705// the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module
706// dependency resolution.
707func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
708 if srcFile != nil {
709 return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
710 }
711 return OptionalPath{}
712}
713
714func (m *moduleContext) RequiredModuleNames() []string {
715 return m.module.RequiredModuleNames()
716}
717
718func (m *moduleContext) HostRequiredModuleNames() []string {
719 return m.module.HostRequiredModuleNames()
720}
721
722func (m *moduleContext) TargetRequiredModuleNames() []string {
723 return m.module.TargetRequiredModuleNames()
724}