• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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	"path"
20	"path/filepath"
21	"slices"
22	"strings"
23
24	"github.com/google/blueprint"
25	"github.com/google/blueprint/depset"
26	"github.com/google/blueprint/proptools"
27	"github.com/google/blueprint/uniquelist"
28)
29
30// BuildParameters describes the set of potential parameters to build a Ninja rule.
31// In general, these correspond to a Ninja concept.
32type BuildParams struct {
33	// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code
34	// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule
35	// can contain variables that should be provided in Args.
36	Rule blueprint.Rule
37	// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles
38	// are used.
39	Deps blueprint.Deps
40	// Depfile is a writeable path that allows correct incremental builds when the inputs have not
41	// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax.
42	Depfile WritablePath
43	// A description of the build action.
44	Description string
45	// Output is an output file of the action. When using this field, references to $out in the Ninja
46	// command will refer to this file.
47	Output WritablePath
48	// Outputs is a slice of output file of the action. When using this field, references to $out in
49	// the Ninja command will refer to these files.
50	Outputs 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 output 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	// PhonyOutput marks this build as `phony_output = true`
85	PhonyOutput bool
86}
87
88type ModuleBuildParams BuildParams
89
90type ModuleContext interface {
91	BaseModuleContext
92
93	// BlueprintModuleContext returns the blueprint.ModuleContext that the ModuleContext wraps.  It may only be
94	// used by the golang module types that need to call into the bootstrap module types.
95	BlueprintModuleContext() blueprint.ModuleContext
96
97	// Deprecated: use ModuleContext.Build instead.
98	ModuleBuild(pctx PackageContext, params ModuleBuildParams)
99
100	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
101	// be tagged with `android:"path" to support automatic source module dependency resolution.
102	//
103	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
104	ExpandSources(srcFiles, excludes []string) Paths
105
106	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
107	// be tagged with `android:"path" to support automatic source module dependency resolution.
108	//
109	// Deprecated: use PathForModuleSrc instead.
110	ExpandSource(srcFile, prop string) Path
111
112	ExpandOptionalSource(srcFile *string, prop string) OptionalPath
113
114	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory,
115	// with the given additional dependencies.  The file is marked executable after copying.
116	//
117	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
118	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
119	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
120	// dependency tags for which IsInstallDepNeeded returns true.
121	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
122
123	// InstallFile creates a rule to copy srcPath to name in the installPath directory,
124	// with the given additional dependencies.
125	//
126	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
127	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
128	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
129	// dependency tags for which IsInstallDepNeeded returns true.
130	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
131
132	// InstallFileWithoutCheckbuild creates a rule to copy srcPath to name in the installPath directory,
133	// with the given additional dependencies, but does not add the file to the list of files to build
134	// during `m checkbuild`.
135	//
136	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the
137	// installed file will be returned by PackagingSpecs() on this module or by
138	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags
139	// for which IsInstallDepNeeded returns true.
140	InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath
141
142	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath
143	// directory, and also unzip a zip file containing extra files to install into the same
144	// directory.
145	//
146	// The installed file can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
147	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
148	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
149	// dependency tags for which IsInstallDepNeeded returns true.
150	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath
151
152	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath
153	// directory.
154	//
155	// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
156	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
157	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
158	// dependency tags for which IsInstallDepNeeded returns true.
159	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath
160
161	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name
162	// in the installPath directory.
163	//
164	// The installed symlink can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
165	// for the installed file can be accessed by InstallFilesInfo.PackagingSpecs on this module
166	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
167	// dependency tags for which IsInstallDepNeeded returns true.
168	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath
169
170	// InstallTestData creates rules to install test data (e.g. data files used during a test) into
171	// the installPath directory.
172	//
173	// The installed files can be accessed by InstallFilesInfo.InstallFiles, and the PackagingSpec
174	// for the installed files can be accessed by InstallFilesInfo.PackagingSpecs on this module
175	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
176	// dependency tags for which IsInstallDepNeeded returns true.
177	InstallTestData(installPath InstallPath, data []DataPath) InstallPaths
178
179	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating
180	// the rule to copy the file.  This is useful to define how a module would be packaged
181	// without installing it into the global installation directories.
182	//
183	// The created PackagingSpec can be accessed by InstallFilesInfo.PackagingSpecs on this module
184	// or by InstallFilesInfo.TransitivePackagingSpecs on modules that depend on this module through
185	// dependency tags for which IsInstallDepNeeded returns true.
186	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec
187
188	CheckbuildFile(srcPaths ...Path)
189	UncheckedModule()
190
191	InstallInData() bool
192	InstallInTestcases() bool
193	InstallInSanitizerDir() bool
194	InstallInRamdisk() bool
195	InstallInVendorRamdisk() bool
196	InstallInDebugRamdisk() bool
197	InstallInRecovery() bool
198	InstallInRoot() bool
199	InstallInOdm() bool
200	InstallInProduct() bool
201	InstallInVendor() bool
202	InstallInSystemDlkm() bool
203	InstallInVendorDlkm() bool
204	InstallInOdmDlkm() bool
205	InstallForceOS() (*OsType, *ArchType)
206
207	RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string
208	HostRequiredModuleNames() []string
209	TargetRequiredModuleNames() []string
210
211	ModuleSubDir() string
212
213	Variable(pctx PackageContext, name, value string)
214	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
215	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
216	// and performs more verification.
217	Build(pctx PackageContext, params BuildParams)
218	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
219	// phony rules or real files.  Phony can be called on the same name multiple times to add
220	// additional dependencies.
221	Phony(phony string, deps ...Path)
222
223	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods,
224	// but do not exist.
225	GetMissingDependencies() []string
226
227	// LicenseMetadataFile returns the path where the license metadata for this module will be
228	// generated.
229	LicenseMetadataFile() Path
230
231	// ModuleInfoJSON returns a pointer to the ModuleInfoJSON struct that can be filled out by
232	// GenerateAndroidBuildActions.  If it is called then the struct will be written out and included in
233	// the module-info.json generated by Make, and Make will not generate its own data for this module.
234	ModuleInfoJSON() *ModuleInfoJSON
235
236	// Simiar to ModuleInfoJSON, ExtraModuleInfoJSON also returns a pointer to the ModuleInfoJSON struct.
237	// This should only be called by a module that generates multiple AndroidMkEntries struct.
238	ExtraModuleInfoJSON() *ModuleInfoJSON
239
240	// SetOutputFiles stores the outputFiles to outputFiles property, which is used
241	// to set the OutputFilesProvider later.
242	SetOutputFiles(outputFiles Paths, tag string)
243
244	GetOutputFiles() OutputFilesInfo
245
246	// SetLicenseInstallMap stores the set of dependency module:location mappings for files in an
247	// apex container for use when generation the license metadata file.
248	SetLicenseInstallMap(installMap []string)
249
250	// ComplianceMetadataInfo returns a ComplianceMetadataInfo instance for different module types to dump metadata,
251	// which usually happens in GenerateAndroidBuildActions() of a module type.
252	// See android.ModuleBase.complianceMetadataInfo
253	ComplianceMetadataInfo() *ComplianceMetadataInfo
254
255	// Get the information about the containers this module belongs to.
256	getContainersInfo() ContainersInfo
257	setContainersInfo(info ContainersInfo)
258
259	setAconfigPaths(paths Paths)
260
261	// DistForGoals creates a rule to copy one or more Paths to the artifacts
262	// directory on the build server when any of the specified goals are built.
263	DistForGoal(goal string, paths ...Path)
264
265	// DistForGoalWithFilename creates a rule to copy a Path to the artifacts
266	// directory on the build server with the given filename when the specified
267	// goal is built.
268	DistForGoalWithFilename(goal string, path Path, filename string)
269
270	// DistForGoals creates a rule to copy one or more Paths to the artifacts
271	// directory on the build server when any of the specified goals are built.
272	DistForGoals(goals []string, paths ...Path)
273
274	// DistForGoalsWithFilename creates a rule to copy a Path to the artifacts
275	// directory on the build server with the given filename when any of the
276	// specified goals are built.
277	DistForGoalsWithFilename(goals []string, path Path, filename string)
278}
279
280type moduleContext struct {
281	bp blueprint.ModuleContext
282	baseModuleContext
283	packagingSpecs   []PackagingSpec
284	installFiles     InstallPaths
285	checkbuildFiles  Paths
286	checkbuildTarget Path
287	uncheckedModule  bool
288	module           Module
289	phonies          map[string]Paths
290	// outputFiles stores the output of a module by tag and is used to set
291	// the OutputFilesProvider in GenerateBuildActions
292	outputFiles OutputFilesInfo
293
294	TransitiveInstallFiles depset.DepSet[InstallPath]
295
296	// set of dependency module:location mappings used to populate the license metadata for
297	// apex containers.
298	licenseInstallMap []string
299
300	// The path to the generated license metadata file for the module.
301	licenseMetadataFile WritablePath
302
303	katiInstalls katiInstalls
304	katiSymlinks katiInstalls
305	// katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are
306	// allowed to have duplicates across modules and variants.
307	katiInitRcInstalls           katiInstalls
308	katiVintfInstalls            katiInstalls
309	initRcPaths                  Paths
310	vintfFragmentsPaths          Paths
311	installedInitRcPaths         InstallPaths
312	installedVintfFragmentsPaths InstallPaths
313
314	testData []DataPath
315
316	// For tests
317	buildParams []BuildParams
318	ruleParams  map[blueprint.Rule]blueprint.RuleParams
319	variables   map[string]string
320
321	// moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will
322	// be included in the final module-info.json produced by Make.
323	moduleInfoJSON []*ModuleInfoJSON
324
325	// containersInfo stores the information about the containers and the information of the
326	// apexes the module belongs to.
327	containersInfo ContainersInfo
328
329	// Merged Aconfig files for all transitive deps.
330	aconfigFilePaths Paths
331
332	// complianceMetadataInfo is for different module types to dump metadata.
333	// See android.ModuleContext interface.
334	complianceMetadataInfo *ComplianceMetadataInfo
335
336	dists []dist
337}
338
339var _ ModuleContext = &moduleContext{}
340
341func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) {
342	return pctx, BuildParams{
343		Rule:            ErrorRule,
344		Description:     params.Description,
345		Output:          params.Output,
346		Outputs:         params.Outputs,
347		ImplicitOutput:  params.ImplicitOutput,
348		ImplicitOutputs: params.ImplicitOutputs,
349		Args: map[string]string{
350			"error": err.Error(),
351		},
352	}
353}
354
355func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) {
356	m.Build(pctx, BuildParams(params))
357}
358
359// Convert build parameters from their concrete Android types into their string representations,
360// and combine the singular and plural fields of the same type (e.g. Output and Outputs).
361func convertBuildParams(params BuildParams) blueprint.BuildParams {
362	bparams := blueprint.BuildParams{
363		Rule:            params.Rule,
364		Description:     params.Description,
365		Deps:            params.Deps,
366		Outputs:         params.Outputs.Strings(),
367		ImplicitOutputs: params.ImplicitOutputs.Strings(),
368		Inputs:          params.Inputs.Strings(),
369		Implicits:       params.Implicits.Strings(),
370		OrderOnly:       params.OrderOnly.Strings(),
371		Validations:     params.Validations.Strings(),
372		Args:            params.Args,
373		Default:         params.Default,
374		PhonyOutput:     params.PhonyOutput,
375	}
376
377	if params.Depfile != nil {
378		bparams.Depfile = params.Depfile.String()
379	}
380	if params.Output != nil {
381		bparams.Outputs = append(bparams.Outputs, params.Output.String())
382	}
383	if params.ImplicitOutput != nil {
384		bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String())
385	}
386	if params.Input != nil {
387		bparams.Inputs = append(bparams.Inputs, params.Input.String())
388	}
389	if params.Implicit != nil {
390		bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
391	}
392	if params.Validation != nil {
393		bparams.Validations = append(bparams.Validations, params.Validation.String())
394	}
395
396	bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
397	bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
398	bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
399	bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
400	bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
401	bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
402	bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
403
404	return bparams
405}
406
407func (m *moduleContext) Variable(pctx PackageContext, name, value string) {
408	if m.config.captureBuild {
409		m.variables[name] = value
410	}
411
412	m.bp.Variable(pctx.PackageContext, name, value)
413}
414
415func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
416	argNames ...string) blueprint.Rule {
417
418	if m.config.UseRemoteBuild() {
419		if params.Pool == nil {
420			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict
421			// jobs to the local parallelism value
422			params.Pool = localPool
423		} else if params.Pool == remotePool {
424			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's
425			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS
426			// parallelism.
427			params.Pool = nil
428		}
429	}
430
431	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...)
432
433	if m.config.captureBuild {
434		m.ruleParams[rule] = params
435	}
436
437	return rule
438}
439
440func (m *moduleContext) Build(pctx PackageContext, params BuildParams) {
441	if params.Description != "" {
442		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}"
443	}
444
445	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 {
446		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n",
447			m.ModuleName(), strings.Join(missingDeps, ", ")))
448	}
449
450	if m.config.captureBuild {
451		m.buildParams = append(m.buildParams, params)
452	}
453
454	bparams := convertBuildParams(params)
455	m.bp.Build(pctx.PackageContext, bparams)
456}
457
458func (m *moduleContext) Phony(name string, deps ...Path) {
459	for _, dep := range deps {
460		if dep == nil {
461			panic("Phony dep cannot be nil")
462		}
463	}
464	m.phonies[name] = append(m.phonies[name], deps...)
465}
466
467func (m *moduleContext) GetMissingDependencies() []string {
468	var missingDeps []string
469	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
470	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...)
471	missingDeps = FirstUniqueStrings(missingDeps)
472	return missingDeps
473}
474
475func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module {
476	deps := m.getDirectDepsInternal(name, tag)
477	if len(deps) == 1 {
478		return deps[0]
479	} else if len(deps) >= 2 {
480		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
481			name, m.ModuleName()))
482	} else {
483		return nil
484	}
485}
486
487func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy {
488	deps := m.getDirectDepsProxyInternal(name, tag)
489	if len(deps) == 1 {
490		return &deps[0]
491	} else if len(deps) >= 2 {
492		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
493			name, m.ModuleName()))
494	} else {
495		return nil
496	}
497}
498
499func (m *moduleContext) ModuleSubDir() string {
500	return m.bp.ModuleSubDir()
501}
502
503func (m *moduleContext) InstallInData() bool {
504	return m.module.InstallInData()
505}
506
507func (m *moduleContext) InstallInTestcases() bool {
508	return m.module.InstallInTestcases()
509}
510
511func (m *moduleContext) InstallInSanitizerDir() bool {
512	return m.module.InstallInSanitizerDir()
513}
514
515func (m *moduleContext) InstallInRamdisk() bool {
516	return m.module.InstallInRamdisk()
517}
518
519func (m *moduleContext) InstallInVendorRamdisk() bool {
520	return m.module.InstallInVendorRamdisk()
521}
522
523func (m *moduleContext) InstallInDebugRamdisk() bool {
524	return m.module.InstallInDebugRamdisk()
525}
526
527func (m *moduleContext) InstallInRecovery() bool {
528	return m.module.InstallInRecovery()
529}
530
531func (m *moduleContext) InstallInRoot() bool {
532	return m.module.InstallInRoot()
533}
534
535func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
536	return m.module.InstallForceOS()
537}
538
539func (m *moduleContext) InstallInOdm() bool {
540	return m.module.InstallInOdm()
541}
542
543func (m *moduleContext) InstallInProduct() bool {
544	return m.module.InstallInProduct()
545}
546
547func (m *moduleContext) InstallInVendor() bool {
548	return m.module.InstallInVendor()
549}
550
551func (m *moduleContext) InstallInSystemDlkm() bool {
552	return m.module.InstallInSystemDlkm()
553}
554
555func (m *moduleContext) InstallInVendorDlkm() bool {
556	return m.module.InstallInVendorDlkm()
557}
558
559func (m *moduleContext) InstallInOdmDlkm() bool {
560	return m.module.InstallInOdmDlkm()
561}
562
563func (m *moduleContext) skipInstall() bool {
564	if m.module.base().commonProperties.SkipInstall {
565		return true
566	}
567
568	// We'll need a solution for choosing which of modules with the same name in different
569	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the
570	// list of namespaces to install in a Soong-only build.
571	if !m.module.base().commonProperties.NamespaceExportedToMake {
572		return true
573	}
574
575	return false
576}
577
578// Tells whether this module is installed to the full install path (ex:
579// out/target/product/<name>/<partition>) or not. If this returns false, the install build rule is
580// not created and this module can only be installed to packaging modules like android_filesystem.
581func (m *moduleContext) requiresFullInstall() bool {
582	if m.skipInstall() {
583		return false
584	}
585
586	if m.module.base().commonProperties.HideFromMake {
587		return false
588	}
589
590	if proptools.Bool(m.module.base().commonProperties.No_full_install) {
591		return false
592	}
593
594	return true
595}
596
597func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path,
598	deps ...InstallPath) InstallPath {
599	return m.installFile(installPath, name, srcPath, deps, false, true, true, nil)
600}
601
602func (m *moduleContext) InstallFileWithoutCheckbuild(installPath InstallPath, name string, srcPath Path,
603	deps ...InstallPath) InstallPath {
604	return m.installFile(installPath, name, srcPath, deps, false, true, false, nil)
605}
606
607func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path,
608	deps ...InstallPath) InstallPath {
609	return m.installFile(installPath, name, srcPath, deps, true, true, true, nil)
610}
611
612func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path,
613	extraZip Path, deps ...InstallPath) InstallPath {
614	return m.installFile(installPath, name, srcPath, deps, false, true, true, &extraFilesZip{
615		zip: extraZip,
616		dir: installPath,
617	})
618}
619
620func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec {
621	fullInstallPath := installPath.Join(m, name)
622	return m.packageFile(fullInstallPath, srcPath, false, false)
623}
624
625func (m *moduleContext) getAconfigPaths() Paths {
626	return m.aconfigFilePaths
627}
628
629func (m *moduleContext) setAconfigPaths(paths Paths) {
630	m.aconfigFilePaths = paths
631}
632
633func (m *moduleContext) getOwnerAndOverrides() (string, []string) {
634	owner := m.ModuleName()
635	overrides := slices.Clone(m.Module().base().commonProperties.Overrides)
636	if b, ok := m.Module().(OverridableModule); ok {
637		if b.GetOverriddenBy() != "" {
638			// overriding variant of base module
639			overrides = append(overrides, m.ModuleName()) // com.android.foo
640			owner = m.Module().Name()                     // com.company.android.foo
641		}
642	}
643	return owner, overrides
644}
645
646func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool, requiresFullInstall bool) PackagingSpec {
647	licenseFiles := m.Module().EffectiveLicenseFiles()
648	owner, overrides := m.getOwnerAndOverrides()
649	spec := PackagingSpec{
650		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
651		srcPath:               srcPath,
652		symlinkTarget:         "",
653		executable:            executable,
654		effectiveLicenseFiles: uniquelist.Make(licenseFiles),
655		partition:             fullInstallPath.partition,
656		skipInstall:           m.skipInstall(),
657		aconfigPaths:          uniquelist.Make(m.getAconfigPaths()),
658		archType:              m.target.Arch.ArchType,
659		overrides:             uniquelist.Make(overrides),
660		owner:                 owner,
661		requiresFullInstall:   requiresFullInstall,
662		fullInstallPath:       fullInstallPath,
663		variation:             m.ModuleSubDir(),
664	}
665	m.packagingSpecs = append(m.packagingSpecs, spec)
666	return spec
667}
668
669func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath,
670	executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath {
671	if _, ok := srcPath.(InstallPath); ok {
672		m.ModuleErrorf("Src path cannot be another installed file. Please use a path from source or intermediates instead.")
673	}
674
675	fullInstallPath := installPath.Join(m, name)
676	if hooks {
677		m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
678	}
679
680	if m.requiresFullInstall() {
681		deps = append(deps, InstallPaths(m.TransitiveInstallFiles.ToList())...)
682		if m.config.KatiEnabled() {
683			deps = append(deps, m.installedInitRcPaths...)
684			deps = append(deps, m.installedVintfFragmentsPaths...)
685		}
686
687		var implicitDeps, orderOnlyDeps Paths
688
689		if m.Host() {
690			// Installed host modules might be used during the build, depend directly on their
691			// dependencies so their timestamp is updated whenever their dependency is updated
692			implicitDeps = InstallPaths(deps).Paths()
693		} else {
694			orderOnlyDeps = InstallPaths(deps).Paths()
695		}
696
697		// When creating the install rule in Soong but embedding in Make, write the rule to a
698		// makefile instead of directly to the ninja file so that main.mk can add the
699		// dependencies from the `required` property that are hard to resolve in Soong.
700		// In soong-only builds, the katiInstall will still be created for semi-legacy code paths
701		// such as module-info.json or compliance, but it will not be used for actually installing
702		// the file.
703		m.katiInstalls = append(m.katiInstalls, katiInstall{
704			from:          srcPath,
705			to:            fullInstallPath,
706			implicitDeps:  implicitDeps,
707			orderOnlyDeps: orderOnlyDeps,
708			executable:    executable,
709			extraFiles:    extraZip,
710		})
711		if !m.Config().KatiEnabled() {
712			rule := CpWithBash
713			if executable {
714				rule = CpExecutableWithBash
715			}
716
717			extraCmds := ""
718			if extraZip != nil {
719				extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )",
720					extraZip.dir.String(), extraZip.zip.String())
721				extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )"
722				implicitDeps = append(implicitDeps, extraZip.zip)
723			}
724
725			var cpFlags = "-f"
726
727			// If this is a device file, copy while preserving timestamps. This is to support
728			// adb sync in soong-only builds. Because soong-only builds have 2 different staging
729			// directories, the out/target/product one and the out/soong/.intermediates one,
730			// we need to ensure the files in them have the same timestamps so that adb sync doesn't
731			// update the files on device.
732			if strings.Contains(fullInstallPath.String(), "target/product") {
733				cpFlags += " -p"
734			}
735
736			m.Build(pctx, BuildParams{
737				Rule:        rule,
738				Description: "install " + fullInstallPath.Base(),
739				Output:      fullInstallPath,
740				Input:       srcPath,
741				Implicits:   implicitDeps,
742				OrderOnly:   orderOnlyDeps,
743				Args: map[string]string{
744					"extraCmds": extraCmds,
745					"cpFlags":   cpFlags,
746				},
747			})
748		}
749
750		m.installFiles = append(m.installFiles, fullInstallPath)
751	}
752
753	m.packageFile(fullInstallPath, srcPath, executable, m.requiresFullInstall())
754
755	if checkbuild {
756		if srcPath == nil {
757			panic("srcPath cannot be nil")
758		}
759		m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
760	}
761
762	return fullInstallPath
763}
764
765func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
766	fullInstallPath := installPath.Join(m, name)
767	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
768
769	relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String())
770	if err != nil {
771		panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err))
772	}
773	if m.requiresFullInstall() {
774
775		// When creating the symlink rule in Soong but embedding in Make, write the rule to a
776		// makefile instead of directly to the ninja file so that main.mk can add the
777		// dependencies from the `required` property that are hard to resolve in Soong.
778		// In soong-only builds, the katiInstall will still be created for semi-legacy code paths
779		// such as module-info.json or compliance, but it will not be used for actually installing
780		// the file.
781		m.katiSymlinks = append(m.katiSymlinks, katiInstall{
782			from: srcPath,
783			to:   fullInstallPath,
784		})
785		if !m.Config().KatiEnabled() {
786			// The symlink doesn't need updating when the target is modified, but we sometimes
787			// have a dependency on a symlink to a binary instead of to the binary directly, and
788			// the mtime of the symlink must be updated when the binary is modified, so use a
789			// normal dependency here instead of an order-only dependency.
790			m.Build(pctx, BuildParams{
791				Rule:        SymlinkWithBash,
792				Description: "install symlink " + fullInstallPath.Base(),
793				Output:      fullInstallPath,
794				Input:       srcPath,
795				Args: map[string]string{
796					"fromPath": relPath,
797				},
798			})
799		}
800
801		m.installFiles = append(m.installFiles, fullInstallPath)
802	}
803
804	owner, overrides := m.getOwnerAndOverrides()
805	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
806		relPathInPackage:    Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
807		srcPath:             nil,
808		symlinkTarget:       relPath,
809		executable:          false,
810		partition:           fullInstallPath.partition,
811		skipInstall:         m.skipInstall(),
812		aconfigPaths:        uniquelist.Make(m.getAconfigPaths()),
813		archType:            m.target.Arch.ArchType,
814		overrides:           uniquelist.Make(overrides),
815		owner:               owner,
816		requiresFullInstall: m.requiresFullInstall(),
817		fullInstallPath:     fullInstallPath,
818		variation:           m.ModuleSubDir(),
819	})
820
821	return fullInstallPath
822}
823
824// installPath/name -> absPath where absPath might be a path that is available only at runtime
825// (e.g. /apex/...)
826func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
827	fullInstallPath := installPath.Join(m, name)
828	m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
829
830	if m.requiresFullInstall() {
831		// When creating the symlink rule in Soong but embedding in Make, write the rule to a
832		// makefile instead of directly to the ninja file so that main.mk can add the
833		// dependencies from the `required` property that are hard to resolve in Soong.
834		// In soong-only builds, the katiInstall will still be created for semi-legacy code paths
835		// such as module-info.json or compliance, but it will not be used for actually installing
836		// the file.
837		m.katiSymlinks = append(m.katiSymlinks, katiInstall{
838			absFrom: absPath,
839			to:      fullInstallPath,
840		})
841		if !m.Config().KatiEnabled() {
842			m.Build(pctx, BuildParams{
843				Rule:        SymlinkWithBash,
844				Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath,
845				Output:      fullInstallPath,
846				Args: map[string]string{
847					"fromPath": absPath,
848				},
849			})
850		}
851
852		m.installFiles = append(m.installFiles, fullInstallPath)
853	}
854
855	owner, overrides := m.getOwnerAndOverrides()
856	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{
857		relPathInPackage:    Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()),
858		srcPath:             nil,
859		symlinkTarget:       absPath,
860		executable:          false,
861		partition:           fullInstallPath.partition,
862		skipInstall:         m.skipInstall(),
863		aconfigPaths:        uniquelist.Make(m.getAconfigPaths()),
864		archType:            m.target.Arch.ArchType,
865		overrides:           uniquelist.Make(overrides),
866		owner:               owner,
867		requiresFullInstall: m.requiresFullInstall(),
868		fullInstallPath:     fullInstallPath,
869		variation:           m.ModuleSubDir(),
870	})
871
872	return fullInstallPath
873}
874
875func (m *moduleContext) InstallTestData(installPath InstallPath, data []DataPath) InstallPaths {
876	m.testData = append(m.testData, data...)
877
878	ret := make(InstallPaths, 0, len(data))
879	for _, d := range data {
880		relPath := d.ToRelativeInstallPath()
881		installed := m.installFile(installPath, relPath, d.SrcPath, nil, false, false, true, nil)
882		ret = append(ret, installed)
883	}
884
885	return ret
886}
887
888// CheckbuildFile specifies the output files that should be built by checkbuild.
889func (m *moduleContext) CheckbuildFile(srcPaths ...Path) {
890	for _, srcPath := range srcPaths {
891		if srcPath == nil {
892			panic("CheckbuildFile() files cannot be nil")
893		}
894	}
895	m.checkbuildFiles = append(m.checkbuildFiles, srcPaths...)
896}
897
898// UncheckedModule marks the current module has having no files that should be built by checkbuild.
899func (m *moduleContext) UncheckedModule() {
900	m.uncheckedModule = true
901}
902
903func (m *moduleContext) BlueprintModuleContext() blueprint.ModuleContext {
904	return m.bp
905}
906
907func (m *moduleContext) LicenseMetadataFile() Path {
908	return m.licenseMetadataFile
909}
910
911func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON {
912	if len(m.moduleInfoJSON) == 0 {
913		moduleInfoJSON := &ModuleInfoJSON{}
914		m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON)
915	}
916	return m.moduleInfoJSON[0]
917}
918
919func (m *moduleContext) ExtraModuleInfoJSON() *ModuleInfoJSON {
920	if len(m.moduleInfoJSON) == 0 {
921		panic("call ModuleInfoJSON() instead")
922	}
923
924	moduleInfoJSON := &ModuleInfoJSON{}
925	m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON)
926	return moduleInfoJSON
927}
928
929func (m *moduleContext) SetOutputFiles(outputFiles Paths, tag string) {
930	for _, outputFile := range outputFiles {
931		if outputFile == nil {
932			panic("outputfiles cannot be nil")
933		}
934	}
935	if tag == "" {
936		if len(m.outputFiles.DefaultOutputFiles) > 0 {
937			m.ModuleErrorf("Module %s default OutputFiles cannot be overwritten", m.ModuleName())
938		}
939		m.outputFiles.DefaultOutputFiles = outputFiles
940	} else {
941		if m.outputFiles.TaggedOutputFiles == nil {
942			m.outputFiles.TaggedOutputFiles = make(map[string]Paths)
943		}
944		if _, exists := m.outputFiles.TaggedOutputFiles[tag]; exists {
945			m.ModuleErrorf("Module %s OutputFiles at tag %s cannot be overwritten", m.ModuleName(), tag)
946		} else {
947			m.outputFiles.TaggedOutputFiles[tag] = outputFiles
948		}
949	}
950}
951
952func (m *moduleContext) GetOutputFiles() OutputFilesInfo {
953	return m.outputFiles
954}
955
956func (m *moduleContext) SetLicenseInstallMap(installMap []string) {
957	m.licenseInstallMap = append(m.licenseInstallMap, installMap...)
958}
959
960func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo {
961	if m.complianceMetadataInfo == nil {
962		m.complianceMetadataInfo = NewComplianceMetadataInfo()
963	}
964	return m.complianceMetadataInfo
965}
966
967// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must
968// be tagged with `android:"path" to support automatic source module dependency resolution.
969//
970// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead.
971func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths {
972	return PathsForModuleSrcExcludes(m, srcFiles, excludes)
973}
974
975// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must
976// be tagged with `android:"path" to support automatic source module dependency resolution.
977//
978// Deprecated: use PathForModuleSrc instead.
979func (m *moduleContext) ExpandSource(srcFile, _ string) Path {
980	return PathForModuleSrc(m, srcFile)
981}
982
983// Returns an optional single path expanded from globs and modules referenced using ":module" syntax if
984// the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module
985// dependency resolution.
986func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath {
987	if srcFile != nil {
988		return OptionalPathForPath(PathForModuleSrc(m, *srcFile))
989	}
990	return OptionalPath{}
991}
992
993func (m *moduleContext) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string {
994	return m.module.RequiredModuleNames(ctx)
995}
996
997func (m *moduleContext) HostRequiredModuleNames() []string {
998	return m.module.HostRequiredModuleNames()
999}
1000
1001func (m *moduleContext) TargetRequiredModuleNames() []string {
1002	return m.module.TargetRequiredModuleNames()
1003}
1004
1005func (m *moduleContext) getContainersInfo() ContainersInfo {
1006	return m.containersInfo
1007}
1008
1009func (m *moduleContext) setContainersInfo(info ContainersInfo) {
1010	m.containersInfo = info
1011}
1012
1013func (c *moduleContext) DistForGoal(goal string, paths ...Path) {
1014	c.DistForGoals([]string{goal}, paths...)
1015}
1016
1017func (c *moduleContext) DistForGoalWithFilename(goal string, path Path, filename string) {
1018	c.DistForGoalsWithFilename([]string{goal}, path, filename)
1019}
1020
1021func (c *moduleContext) DistForGoals(goals []string, paths ...Path) {
1022	var copies distCopies
1023	for _, path := range paths {
1024		copies = append(copies, distCopy{
1025			from: path,
1026			dest: path.Base(),
1027		})
1028	}
1029	c.dists = append(c.dists, dist{
1030		goals: slices.Clone(goals),
1031		paths: copies,
1032	})
1033}
1034
1035func (c *moduleContext) DistForGoalsWithFilename(goals []string, path Path, filename string) {
1036	c.dists = append(c.dists, dist{
1037		goals: slices.Clone(goals),
1038		paths: distCopies{{from: path, dest: filename}},
1039	})
1040}
1041