xref: /aosp_15_r20/build/soong/android/paths.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"os"
20	"path/filepath"
21	"reflect"
22	"regexp"
23	"sort"
24	"strings"
25
26	"github.com/google/blueprint"
27	"github.com/google/blueprint/gobtools"
28	"github.com/google/blueprint/pathtools"
29)
30
31var absSrcDir string
32
33// PathContext is the subset of a (Module|Singleton)Context required by the
34// Path methods.
35type PathContext interface {
36	Config() Config
37	AddNinjaFileDeps(deps ...string)
38}
39
40type PathGlobContext interface {
41	PathContext
42	GlobWithDeps(globPattern string, excludes []string) ([]string, error)
43}
44
45var _ PathContext = SingletonContext(nil)
46var _ PathContext = ModuleContext(nil)
47
48// "Null" path context is a minimal path context for a given config.
49type NullPathContext struct {
50	config Config
51}
52
53func (NullPathContext) AddNinjaFileDeps(...string) {}
54func (ctx NullPathContext) Config() Config         { return ctx.config }
55
56// EarlyModulePathContext is a subset of EarlyModuleContext methods required by the
57// Path methods. These path methods can be called before any mutators have run.
58type EarlyModulePathContext interface {
59	PathGlobContext
60
61	ModuleDir() string
62	ModuleErrorf(fmt string, args ...interface{})
63	OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{})
64}
65
66var _ EarlyModulePathContext = ModuleContext(nil)
67
68// Glob globs files and directories matching globPattern relative to ModuleDir(),
69// paths in the excludes parameter will be omitted.
70func Glob(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
71	ret, err := ctx.GlobWithDeps(globPattern, excludes)
72	if err != nil {
73		ctx.ModuleErrorf("glob: %s", err.Error())
74	}
75	return pathsForModuleSrcFromFullPath(ctx, ret, true)
76}
77
78// GlobFiles globs *only* files (not directories) matching globPattern relative to ModuleDir().
79// Paths in the excludes parameter will be omitted.
80func GlobFiles(ctx EarlyModulePathContext, globPattern string, excludes []string) Paths {
81	ret, err := ctx.GlobWithDeps(globPattern, excludes)
82	if err != nil {
83		ctx.ModuleErrorf("glob: %s", err.Error())
84	}
85	return pathsForModuleSrcFromFullPath(ctx, ret, false)
86}
87
88// ModuleWithDepsPathContext is a subset of *ModuleContext methods required by
89// the Path methods that rely on module dependencies having been resolved.
90type ModuleWithDepsPathContext interface {
91	EarlyModulePathContext
92	OtherModuleProviderContext
93	VisitDirectDeps(visit func(Module))
94	VisitDirectDepsProxy(visit func(ModuleProxy))
95	VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(ModuleProxy))
96	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
97	HasMutatorFinished(mutatorName string) bool
98}
99
100// ModuleMissingDepsPathContext is a subset of *ModuleContext methods required by
101// the Path methods that rely on module dependencies having been resolved and ability to report
102// missing dependency errors.
103type ModuleMissingDepsPathContext interface {
104	ModuleWithDepsPathContext
105	AddMissingDependencies(missingDeps []string)
106}
107
108type ModuleInstallPathContext interface {
109	BaseModuleContext
110
111	InstallInData() bool
112	InstallInTestcases() bool
113	InstallInSanitizerDir() bool
114	InstallInRamdisk() bool
115	InstallInVendorRamdisk() bool
116	InstallInDebugRamdisk() bool
117	InstallInRecovery() bool
118	InstallInRoot() bool
119	InstallInOdm() bool
120	InstallInProduct() bool
121	InstallInVendor() bool
122	InstallInSystemDlkm() bool
123	InstallInVendorDlkm() bool
124	InstallInOdmDlkm() bool
125	InstallForceOS() (*OsType, *ArchType)
126}
127
128var _ ModuleInstallPathContext = ModuleContext(nil)
129
130type baseModuleContextToModuleInstallPathContext struct {
131	BaseModuleContext
132}
133
134func (ctx *baseModuleContextToModuleInstallPathContext) InstallInData() bool {
135	return ctx.Module().InstallInData()
136}
137
138func (ctx *baseModuleContextToModuleInstallPathContext) InstallInTestcases() bool {
139	return ctx.Module().InstallInTestcases()
140}
141
142func (ctx *baseModuleContextToModuleInstallPathContext) InstallInSanitizerDir() bool {
143	return ctx.Module().InstallInSanitizerDir()
144}
145
146func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRamdisk() bool {
147	return ctx.Module().InstallInRamdisk()
148}
149
150func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendorRamdisk() bool {
151	return ctx.Module().InstallInVendorRamdisk()
152}
153
154func (ctx *baseModuleContextToModuleInstallPathContext) InstallInDebugRamdisk() bool {
155	return ctx.Module().InstallInDebugRamdisk()
156}
157
158func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRecovery() bool {
159	return ctx.Module().InstallInRecovery()
160}
161
162func (ctx *baseModuleContextToModuleInstallPathContext) InstallInRoot() bool {
163	return ctx.Module().InstallInRoot()
164}
165
166func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdm() bool {
167	return ctx.Module().InstallInOdm()
168}
169
170func (ctx *baseModuleContextToModuleInstallPathContext) InstallInProduct() bool {
171	return ctx.Module().InstallInProduct()
172}
173
174func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendor() bool {
175	return ctx.Module().InstallInVendor()
176}
177
178func (ctx *baseModuleContextToModuleInstallPathContext) InstallInSystemDlkm() bool {
179	return ctx.Module().InstallInSystemDlkm()
180}
181
182func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendorDlkm() bool {
183	return ctx.Module().InstallInVendorDlkm()
184}
185
186func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdmDlkm() bool {
187	return ctx.Module().InstallInOdmDlkm()
188}
189
190func (ctx *baseModuleContextToModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
191	return ctx.Module().InstallForceOS()
192}
193
194var _ ModuleInstallPathContext = (*baseModuleContextToModuleInstallPathContext)(nil)
195
196// errorfContext is the interface containing the Errorf method matching the
197// Errorf method in blueprint.SingletonContext.
198type errorfContext interface {
199	Errorf(format string, args ...interface{})
200}
201
202var _ errorfContext = blueprint.SingletonContext(nil)
203
204// ModuleErrorfContext is the interface containing the ModuleErrorf method matching
205// the ModuleErrorf method in blueprint.ModuleContext.
206type ModuleErrorfContext interface {
207	ModuleErrorf(format string, args ...interface{})
208}
209
210var _ ModuleErrorfContext = blueprint.ModuleContext(nil)
211
212// reportPathError will register an error with the attached context. It
213// attempts ctx.ModuleErrorf for a better error message first, then falls
214// back to ctx.Errorf.
215func reportPathError(ctx PathContext, err error) {
216	ReportPathErrorf(ctx, "%s", err.Error())
217}
218
219// ReportPathErrorf will register an error with the attached context. It
220// attempts ctx.ModuleErrorf for a better error message first, then falls
221// back to ctx.Errorf.
222func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
223	if mctx, ok := ctx.(ModuleErrorfContext); ok {
224		mctx.ModuleErrorf(format, args...)
225	} else if ectx, ok := ctx.(errorfContext); ok {
226		ectx.Errorf(format, args...)
227	} else {
228		panic(fmt.Sprintf(format, args...))
229	}
230}
231
232func pathContextName(ctx PathContext, module blueprint.Module) string {
233	if x, ok := ctx.(interface{ ModuleName(blueprint.Module) string }); ok {
234		return x.ModuleName(module)
235	} else if x, ok := ctx.(interface{ OtherModuleName(blueprint.Module) string }); ok {
236		return x.OtherModuleName(module)
237	}
238	return "unknown"
239}
240
241type Path interface {
242	// Returns the path in string form
243	String() string
244
245	// Ext returns the extension of the last element of the path
246	Ext() string
247
248	// Base returns the last element of the path
249	Base() string
250
251	// Rel returns the portion of the path relative to the directory it was created from.  For
252	// example, Rel on a PathsForModuleSrc would return the path relative to the module source
253	// directory, and OutputPath.Join("foo").Rel() would return "foo".
254	Rel() string
255
256	// WithoutRel returns a new Path with no relative path, i.e. Rel() will return the same value as Base().
257	WithoutRel() Path
258
259	// RelativeToTop returns a new path relative to the top, it is provided solely for use in tests.
260	//
261	// It is guaranteed to always return the same type as it is called on, e.g. if called on an
262	// InstallPath then the returned value can be converted to an InstallPath.
263	//
264	// A standard build has the following structure:
265	//   ../top/
266	//          out/ - make install files go here.
267	//          out/soong - this is the outDir passed to NewTestConfig()
268	//          ... - the source files
269	//
270	// This function converts a path so that it appears relative to the ../top/ directory, i.e.
271	// * Make install paths, which have the pattern "outDir/../<path>" are converted into the top
272	//   relative path "out/<path>"
273	// * Soong install paths and other writable paths, which have the pattern "outDir/soong/<path>" are
274	//   converted into the top relative path "out/soong/<path>".
275	// * Source paths are already relative to the top.
276	// * Phony paths are not relative to anything.
277	// * toolDepPath have an absolute but known value in so don't need making relative to anything in
278	//   order to test.
279	RelativeToTop() Path
280}
281
282const (
283	testOutDir         = "out"
284	testOutSoongSubDir = "/soong"
285	TestOutSoongDir    = testOutDir + testOutSoongSubDir
286)
287
288// WritablePath is a type of path that can be used as an output for build rules.
289type WritablePath interface {
290	Path
291
292	// return the path to the build directory.
293	getSoongOutDir() string
294
295	// the writablePath method doesn't directly do anything,
296	// but it allows a struct to distinguish between whether or not it implements the WritablePath interface
297	writablePath()
298
299	ReplaceExtension(ctx PathContext, ext string) OutputPath
300}
301
302type genPathProvider interface {
303	genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath
304	genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath
305}
306type objPathProvider interface {
307	objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath
308}
309type resPathProvider interface {
310	resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath
311}
312
313// GenPathWithExt derives a new file path in ctx's generated sources directory
314// from the current path, but with the new extension.
315func GenPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleGenPath {
316	if path, ok := p.(genPathProvider); ok {
317		return path.genPathWithExt(ctx, subdir, ext)
318	}
319	ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
320	return PathForModuleGen(ctx)
321}
322
323// GenPathWithExtAndTrimExt derives a new file path in ctx's generated sources directory
324// from the current path, but with the new extension and trim the suffix.
325func GenPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir string, p Path, ext string, trimExt string) ModuleGenPath {
326	if path, ok := p.(genPathProvider); ok {
327		return path.genPathWithExtAndTrimExt(ctx, subdir, ext, trimExt)
328	}
329	ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
330	return PathForModuleGen(ctx)
331}
332
333// ObjPathWithExt derives a new file path in ctx's object directory from the
334// current path, but with the new extension.
335func ObjPathWithExt(ctx ModuleOutPathContext, subdir string, p Path, ext string) ModuleObjPath {
336	if path, ok := p.(objPathProvider); ok {
337		return path.objPathWithExt(ctx, subdir, ext)
338	}
339	ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
340	return PathForModuleObj(ctx)
341}
342
343// ResPathWithName derives a new path in ctx's output resource directory, using
344// the current path to create the directory name, and the `name` argument for
345// the filename.
346func ResPathWithName(ctx ModuleOutPathContext, p Path, name string) ModuleResPath {
347	if path, ok := p.(resPathProvider); ok {
348		return path.resPathWithName(ctx, name)
349	}
350	ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
351	return PathForModuleRes(ctx)
352}
353
354// OptionalPath is a container that may or may not contain a valid Path.
355type OptionalPath struct {
356	path          Path   // nil if invalid.
357	invalidReason string // Not applicable if path != nil. "" if the reason is unknown.
358}
359
360type optionalPathGob struct {
361	Path          Path
362	InvalidReason string
363}
364
365// OptionalPathForPath returns an OptionalPath containing the path.
366func OptionalPathForPath(path Path) OptionalPath {
367	return OptionalPath{path: path}
368}
369
370// InvalidOptionalPath returns an OptionalPath that is invalid with the given reason.
371func InvalidOptionalPath(reason string) OptionalPath {
372
373	return OptionalPath{invalidReason: reason}
374}
375
376func (p *OptionalPath) ToGob() *optionalPathGob {
377	return &optionalPathGob{
378		Path:          p.path,
379		InvalidReason: p.invalidReason,
380	}
381}
382
383func (p *OptionalPath) FromGob(data *optionalPathGob) {
384	p.path = data.Path
385	p.invalidReason = data.InvalidReason
386}
387
388func (p OptionalPath) GobEncode() ([]byte, error) {
389	return gobtools.CustomGobEncode[optionalPathGob](&p)
390}
391
392func (p *OptionalPath) GobDecode(data []byte) error {
393	return gobtools.CustomGobDecode[optionalPathGob](data, p)
394}
395
396// Valid returns whether there is a valid path
397func (p OptionalPath) Valid() bool {
398	return p.path != nil
399}
400
401// Path returns the Path embedded in this OptionalPath. You must be sure that
402// there is a valid path, since this method will panic if there is not.
403func (p OptionalPath) Path() Path {
404	if p.path == nil {
405		msg := "Requesting an invalid path"
406		if p.invalidReason != "" {
407			msg += ": " + p.invalidReason
408		}
409		panic(msg)
410	}
411	return p.path
412}
413
414// InvalidReason returns the reason that the optional path is invalid, or "" if it is valid.
415func (p OptionalPath) InvalidReason() string {
416	if p.path != nil {
417		return ""
418	}
419	if p.invalidReason == "" {
420		return "unknown"
421	}
422	return p.invalidReason
423}
424
425// AsPaths converts the OptionalPath into Paths.
426//
427// It returns nil if this is not valid, or a single length slice containing the Path embedded in
428// this OptionalPath.
429func (p OptionalPath) AsPaths() Paths {
430	if p.path == nil {
431		return nil
432	}
433	return Paths{p.path}
434}
435
436// RelativeToTop returns an OptionalPath with the path that was embedded having been replaced by the
437// result of calling Path.RelativeToTop on it.
438func (p OptionalPath) RelativeToTop() OptionalPath {
439	if p.path == nil {
440		return p
441	}
442	p.path = p.path.RelativeToTop()
443	return p
444}
445
446// String returns the string version of the Path, or "" if it isn't valid.
447func (p OptionalPath) String() string {
448	if p.path != nil {
449		return p.path.String()
450	} else {
451		return ""
452	}
453}
454
455// Paths is a slice of Path objects, with helpers to operate on the collection.
456type Paths []Path
457
458// RelativeToTop creates a new Paths containing the result of calling Path.RelativeToTop on each
459// item in this slice.
460func (p Paths) RelativeToTop() Paths {
461	ensureTestOnly()
462	if p == nil {
463		return p
464	}
465	ret := make(Paths, len(p))
466	for i, path := range p {
467		ret[i] = path.RelativeToTop()
468	}
469	return ret
470}
471
472func (paths Paths) containsPath(path Path) bool {
473	for _, p := range paths {
474		if p == path {
475			return true
476		}
477	}
478	return false
479}
480
481// PathsForSource returns Paths rooted from SrcDir, *not* rooted from the module's local source
482// directory
483func PathsForSource(ctx PathContext, paths []string) Paths {
484	ret := make(Paths, len(paths))
485	for i, path := range paths {
486		ret[i] = PathForSource(ctx, path)
487	}
488	return ret
489}
490
491// ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
492// module's local source directory, that are found in the tree. If any are not found, they are
493// omitted from the list, and dependencies are added so that we're re-run when they are added.
494func ExistentPathsForSources(ctx PathGlobContext, paths []string) Paths {
495	ret := make(Paths, 0, len(paths))
496	for _, path := range paths {
497		p := ExistentPathForSource(ctx, path)
498		if p.Valid() {
499			ret = append(ret, p.Path())
500		}
501	}
502	return ret
503}
504
505// PathsForModuleSrc returns a Paths{} containing the resolved references in paths:
506//   - filepath, relative to local module directory, resolves as a filepath relative to the local
507//     source directory
508//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
509//     source directory.
510//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
511//     or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
512//     source filepath.
513//
514// Properties passed as the paths argument must have been annotated with struct tag
515// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
516// pathdeps mutator.
517// If a requested module is not found as a dependency:
518//   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
519//     missing dependencies
520//   - otherwise, a ModuleError is thrown.
521func PathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) Paths {
522	return PathsForModuleSrcExcludes(ctx, paths, nil)
523}
524
525type SourceInput struct {
526	Context      ModuleMissingDepsPathContext
527	Paths        []string
528	ExcludePaths []string
529	IncludeDirs  bool
530}
531
532// PathsForModuleSrcExcludes returns a Paths{} containing the resolved references in paths, minus
533// those listed in excludes. Elements of paths and excludes are resolved as:
534//   - filepath, relative to local module directory, resolves as a filepath relative to the local
535//     source directory
536//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
537//     source directory. Not valid in excludes.
538//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
539//     or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
540//     source filepath.
541//
542// excluding the items (similarly resolved
543// Properties passed as the paths argument must have been annotated with struct tag
544// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
545// pathdeps mutator.
546// If a requested module is not found as a dependency:
547//   - if ctx.Config().AllowMissingDependencies() is true, this module to be marked as having
548//     missing dependencies
549//   - otherwise, a ModuleError is thrown.
550func PathsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) Paths {
551	return PathsRelativeToModuleSourceDir(SourceInput{
552		Context:      ctx,
553		Paths:        paths,
554		ExcludePaths: excludes,
555		IncludeDirs:  true,
556	})
557}
558
559func PathsRelativeToModuleSourceDir(input SourceInput) Paths {
560	ret, missingDeps := PathsAndMissingDepsRelativeToModuleSourceDir(input)
561	if input.Context.Config().AllowMissingDependencies() {
562		input.Context.AddMissingDependencies(missingDeps)
563	} else {
564		for _, m := range missingDeps {
565			input.Context.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
566		}
567	}
568	return ret
569}
570
571type directoryPath struct {
572	basePath
573}
574
575func (d *directoryPath) String() string {
576	return d.basePath.String()
577}
578
579func (d *directoryPath) base() basePath {
580	return d.basePath
581}
582
583// DirectoryPath represents a source path for directories. Incompatible with Path by design.
584type DirectoryPath interface {
585	String() string
586	base() basePath
587}
588
589var _ DirectoryPath = (*directoryPath)(nil)
590
591type DirectoryPaths []DirectoryPath
592
593// DirectoryPathsForModuleSrcExcludes returns a Paths{} containing the resolved references in
594// directory paths. Elements of paths are resolved as:
595//   - filepath, relative to local module directory, resolves as a filepath relative to the local
596//     source directory
597//   - other modules using the ":name" syntax. These modules must implement DirProvider.
598func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) DirectoryPaths {
599	var ret DirectoryPaths
600
601	for _, path := range paths {
602		if m, t := SrcIsModuleWithTag(path); m != "" {
603			module := GetModuleProxyFromPathDep(ctx, m, t)
604			if module == nil {
605				ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m)
606				continue
607			}
608			if t != "" {
609				ctx.ModuleErrorf("DirProvider dependency %q does not support the tag %q", module, t)
610				continue
611			}
612			mctx, ok := ctx.(OtherModuleProviderContext)
613			if !ok {
614				panic(fmt.Errorf("%s is not an OtherModuleProviderContext", ctx))
615			}
616			if dirProvider, ok := OtherModuleProvider(mctx, *module, DirProvider); ok {
617				ret = append(ret, dirProvider.Dirs...)
618			} else {
619				ReportPathErrorf(ctx, "module %q does not implement DirProvider", module)
620			}
621		} else {
622			p := pathForModuleSrc(ctx, path)
623			if isDir, err := ctx.Config().fs.IsDir(p.String()); err != nil {
624				ReportPathErrorf(ctx, "%s: %s", p, err.Error())
625			} else if !isDir {
626				ReportPathErrorf(ctx, "module directory path %q is not a directory", p)
627			} else {
628				ret = append(ret, &directoryPath{basePath{path: p.path, rel: p.rel}})
629			}
630		}
631	}
632
633	seen := make(map[DirectoryPath]bool, len(ret))
634	for _, path := range ret {
635		if seen[path] {
636			ReportPathErrorf(ctx, "duplicated path %q", path)
637		}
638		seen[path] = true
639	}
640	return ret
641}
642
643// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
644type OutputPaths []OutputPath
645
646// Paths returns the OutputPaths as a Paths
647func (p OutputPaths) Paths() Paths {
648	if p == nil {
649		return nil
650	}
651	ret := make(Paths, len(p))
652	for i, path := range p {
653		ret[i] = path
654	}
655	return ret
656}
657
658// Strings returns the string forms of the writable paths.
659func (p OutputPaths) Strings() []string {
660	if p == nil {
661		return nil
662	}
663	ret := make([]string, len(p))
664	for i, path := range p {
665		ret[i] = path.String()
666	}
667	return ret
668}
669
670// Expands Paths to a SourceFileProducer or OutputFileProducer module dependency referenced via ":name" or ":name{.tag}" syntax.
671// If the dependency is not found, a missingErrorDependency is returned.
672// If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned.
673func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag string) (Paths, error) {
674	module := GetModuleProxyFromPathDep(ctx, moduleName, tag)
675	if module == nil {
676		return nil, missingDependencyError{[]string{moduleName}}
677	}
678	if !OtherModuleProviderOrDefault(ctx, *module, CommonModuleInfoKey).Enabled {
679		return nil, missingDependencyError{[]string{moduleName}}
680	}
681
682	outputFiles, err := outputFilesForModule(ctx, *module, tag)
683	if outputFiles != nil && err == nil {
684		return outputFiles, nil
685	} else {
686		return nil, err
687	}
688}
689
690// GetModuleProxyFromPathDep will return the module that was added as a dependency automatically for
691// properties tagged with `android:"path"` or manually using ExtractSourceDeps or
692// ExtractSourcesDeps.
693//
694// The moduleName and tag supplied to this should be the values returned from SrcIsModuleWithTag.
695// Or, if no tag is expected then the moduleName should be the value returned by  SrcIsModule and
696// the tag must be "".
697//
698// If tag is "" then the returned module will be the dependency that was added for ":moduleName".
699// Otherwise, it is the dependency that was added for ":moduleName{tag}".
700func GetModuleProxyFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) *ModuleProxy {
701	var found *ModuleProxy
702	// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
703	// module name and the tag. Dependencies added automatically for properties tagged with
704	// `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
705	// dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
706	// it will always be the case that the dependencies will be identical, i.e. the same tag and same
707	// moduleName referring to the same dependency module.
708	//
709	// It does not matter whether the moduleName is a fully qualified name or if the module
710	// dependency is a prebuilt module. All that matters is the same information is supplied to
711	// create the tag here as was supplied to create the tag when the dependency was added so that
712	// this finds the matching dependency module.
713	expectedTag := sourceOrOutputDepTag(moduleName, tag)
714	ctx.VisitDirectDepsProxyWithTag(expectedTag, func(module ModuleProxy) {
715		found = &module
716	})
717	return found
718}
719
720// Deprecated: use GetModuleProxyFromPathDep
721func GetModuleFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) blueprint.Module {
722	var found blueprint.Module
723	// The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the
724	// module name and the tag. Dependencies added automatically for properties tagged with
725	// `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate
726	// dependencies to be added manually using ExtractSourcesDeps or ExtractSourceDeps but even then
727	// it will always be the case that the dependencies will be identical, i.e. the same tag and same
728	// moduleName referring to the same dependency module.
729	//
730	// It does not matter whether the moduleName is a fully qualified name or if the module
731	// dependency is a prebuilt module. All that matters is the same information is supplied to
732	// create the tag here as was supplied to create the tag when the dependency was added so that
733	// this finds the matching dependency module.
734	expectedTag := sourceOrOutputDepTag(moduleName, tag)
735	ctx.VisitDirectDeps(func(module Module) {
736		depTag := ctx.OtherModuleDependencyTag(module)
737		if depTag == expectedTag {
738			found = module
739		}
740	})
741	return found
742}
743
744// PathsAndMissingDepsForModuleSrcExcludes returns a Paths{} containing the resolved references in
745// paths, minus those listed in excludes. Elements of paths and excludes are resolved as:
746//   - filepath, relative to local module directory, resolves as a filepath relative to the local
747//     source directory
748//   - glob, relative to the local module directory, resolves as filepath(s), relative to the local
749//     source directory. Not valid in excludes.
750//   - other modules using the ":name{.tag}" syntax. These modules must implement SourceFileProducer
751//     or set the OutputFilesProvider. These resolve as a filepath to an output filepath or generated
752//     source filepath.
753//
754// and a list of the module names of missing module dependencies are returned as the second return.
755// Properties passed as the paths argument must have been annotated with struct tag
756// `android:"path"` so that dependencies on SourceFileProducer modules will have already been handled by the
757// pathdeps mutator.
758func PathsAndMissingDepsForModuleSrcExcludes(ctx ModuleMissingDepsPathContext, paths, excludes []string) (Paths, []string) {
759	return PathsAndMissingDepsRelativeToModuleSourceDir(SourceInput{
760		Context:      ctx,
761		Paths:        paths,
762		ExcludePaths: excludes,
763		IncludeDirs:  true,
764	})
765}
766
767func PathsAndMissingDepsRelativeToModuleSourceDir(input SourceInput) (Paths, []string) {
768	prefix := pathForModuleSrc(input.Context).String()
769
770	var expandedExcludes []string
771	if input.ExcludePaths != nil {
772		expandedExcludes = make([]string, 0, len(input.ExcludePaths))
773	}
774
775	var missingExcludeDeps []string
776	for _, e := range input.ExcludePaths {
777		if m, t := SrcIsModuleWithTag(e); m != "" {
778			modulePaths, err := getPathsFromModuleDep(input.Context, e, m, t)
779			if m, ok := err.(missingDependencyError); ok {
780				missingExcludeDeps = append(missingExcludeDeps, m.missingDeps...)
781			} else if err != nil {
782				reportPathError(input.Context, err)
783			} else {
784				expandedExcludes = append(expandedExcludes, modulePaths.Strings()...)
785			}
786		} else {
787			expandedExcludes = append(expandedExcludes, filepath.Join(prefix, e))
788		}
789	}
790
791	if input.Paths == nil {
792		return nil, missingExcludeDeps
793	}
794
795	var missingDeps []string
796
797	expandedSrcFiles := make(Paths, 0, len(input.Paths))
798	for _, s := range input.Paths {
799		srcFiles, err := expandOneSrcPath(sourcePathInput{
800			context:          input.Context,
801			path:             s,
802			expandedExcludes: expandedExcludes,
803			includeDirs:      input.IncludeDirs,
804		})
805		if depErr, ok := err.(missingDependencyError); ok {
806			missingDeps = append(missingDeps, depErr.missingDeps...)
807		} else if err != nil {
808			reportPathError(input.Context, err)
809		}
810		expandedSrcFiles = append(expandedSrcFiles, srcFiles...)
811	}
812
813	// TODO: b/334169722 - Replace with an error instead of implicitly removing duplicates.
814	return FirstUniquePaths(expandedSrcFiles), append(missingDeps, missingExcludeDeps...)
815}
816
817type missingDependencyError struct {
818	missingDeps []string
819}
820
821func (e missingDependencyError) Error() string {
822	return "missing dependencies: " + strings.Join(e.missingDeps, ", ")
823}
824
825type sourcePathInput struct {
826	context          ModuleWithDepsPathContext
827	path             string
828	expandedExcludes []string
829	includeDirs      bool
830}
831
832// Expands one path string to Paths rooted from the module's local source
833// directory, excluding those listed in the expandedExcludes.
834// Expands globs, references to SourceFileProducer or OutputFileProducer modules using the ":name" and ":name{.tag}" syntax.
835func expandOneSrcPath(input sourcePathInput) (Paths, error) {
836	excludePaths := func(paths Paths) Paths {
837		if len(input.expandedExcludes) == 0 {
838			return paths
839		}
840		remainder := make(Paths, 0, len(paths))
841		for _, p := range paths {
842			if !InList(p.String(), input.expandedExcludes) {
843				remainder = append(remainder, p)
844			}
845		}
846		return remainder
847	}
848	if m, t := SrcIsModuleWithTag(input.path); m != "" {
849		modulePaths, err := getPathsFromModuleDep(input.context, input.path, m, t)
850		if err != nil {
851			return nil, err
852		} else {
853			return excludePaths(modulePaths), nil
854		}
855	} else {
856		p := pathForModuleSrc(input.context, input.path)
857		if pathtools.IsGlob(input.path) {
858			paths := GlobFiles(input.context, p.String(), input.expandedExcludes)
859			return PathsWithModuleSrcSubDir(input.context, paths, ""), nil
860		} else {
861			if exists, _, err := input.context.Config().fs.Exists(p.String()); err != nil {
862				ReportPathErrorf(input.context, "%s: %s", p, err.Error())
863			} else if !exists && !input.context.Config().TestAllowNonExistentPaths {
864				ReportPathErrorf(input.context, "module source path %q does not exist", p)
865			} else if !input.includeDirs {
866				if isDir, err := input.context.Config().fs.IsDir(p.String()); exists && err != nil {
867					ReportPathErrorf(input.context, "%s: %s", p, err.Error())
868				} else if isDir {
869					ReportPathErrorf(input.context, "module source path %q is a directory", p)
870				}
871			}
872
873			if InList(p.String(), input.expandedExcludes) {
874				return nil, nil
875			}
876			return Paths{p}, nil
877		}
878	}
879}
880
881// pathsForModuleSrcFromFullPath returns Paths rooted from the module's local
882// source directory, but strip the local source directory from the beginning of
883// each string. If incDirs is false, strip paths with a trailing '/' from the list.
884// It intended for use in globs that only list files that exist, so it allows '$' in
885// filenames.
886func pathsForModuleSrcFromFullPath(ctx EarlyModulePathContext, paths []string, incDirs bool) Paths {
887	prefix := ctx.ModuleDir() + "/"
888	if prefix == "./" {
889		prefix = ""
890	}
891	ret := make(Paths, 0, len(paths))
892	for _, p := range paths {
893		if !incDirs && strings.HasSuffix(p, "/") {
894			continue
895		}
896		path := filepath.Clean(p)
897		if !strings.HasPrefix(path, prefix) {
898			ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
899			continue
900		}
901
902		srcPath, err := safePathForSource(ctx, ctx.ModuleDir(), path[len(prefix):])
903		if err != nil {
904			reportPathError(ctx, err)
905			continue
906		}
907
908		srcPath.basePath.rel = srcPath.path
909
910		ret = append(ret, srcPath)
911	}
912	return ret
913}
914
915// PathsWithOptionalDefaultForModuleSrc returns Paths rooted from the module's local source
916// directory. If input is nil, use the default if it exists.  If input is empty, returns nil.
917func PathsWithOptionalDefaultForModuleSrc(ctx ModuleMissingDepsPathContext, input []string, def string) Paths {
918	if input != nil {
919		return PathsForModuleSrc(ctx, input)
920	}
921	// Use Glob so that if the default doesn't exist, a dependency is added so that when it
922	// is created, we're run again.
923	path := filepath.Join(ctx.ModuleDir(), def)
924	return Glob(ctx, path, nil)
925}
926
927// Strings returns the Paths in string form
928func (p Paths) Strings() []string {
929	if p == nil {
930		return nil
931	}
932	ret := make([]string, len(p))
933	for i, path := range p {
934		ret[i] = path.String()
935	}
936	return ret
937}
938
939func CopyOfPaths(paths Paths) Paths {
940	return append(Paths(nil), paths...)
941}
942
943// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each.  It
944// modifies the Paths slice contents in place, and returns a subslice of the original slice.
945func FirstUniquePaths(list Paths) Paths {
946	// 128 was chosen based on BenchmarkFirstUniquePaths results.
947	if len(list) > 128 {
948		return firstUniquePathsMap(list)
949	}
950	return firstUniquePathsList(list)
951}
952
953// SortedUniquePaths returns all unique elements of a Paths in sorted order.  It modifies the
954// Paths slice contents in place, and returns a subslice of the original slice.
955func SortedUniquePaths(list Paths) Paths {
956	unique := FirstUniquePaths(list)
957	sort.Slice(unique, func(i, j int) bool {
958		return unique[i].String() < unique[j].String()
959	})
960	return unique
961}
962
963func firstUniquePathsList(list Paths) Paths {
964	k := 0
965outer:
966	for i := 0; i < len(list); i++ {
967		for j := 0; j < k; j++ {
968			if list[i] == list[j] {
969				continue outer
970			}
971		}
972		list[k] = list[i]
973		k++
974	}
975	return list[:k]
976}
977
978func firstUniquePathsMap(list Paths) Paths {
979	k := 0
980	seen := make(map[Path]bool, len(list))
981	for i := 0; i < len(list); i++ {
982		if seen[list[i]] {
983			continue
984		}
985		seen[list[i]] = true
986		list[k] = list[i]
987		k++
988	}
989	return list[:k]
990}
991
992// FirstUniqueInstallPaths returns all unique elements of an InstallPaths, keeping the first copy of each.  It
993// modifies the InstallPaths slice contents in place, and returns a subslice of the original slice.
994func FirstUniqueInstallPaths(list InstallPaths) InstallPaths {
995	// 128 was chosen based on BenchmarkFirstUniquePaths results.
996	if len(list) > 128 {
997		return firstUniqueInstallPathsMap(list)
998	}
999	return firstUniqueInstallPathsList(list)
1000}
1001
1002func firstUniqueInstallPathsList(list InstallPaths) InstallPaths {
1003	k := 0
1004outer:
1005	for i := 0; i < len(list); i++ {
1006		for j := 0; j < k; j++ {
1007			if list[i] == list[j] {
1008				continue outer
1009			}
1010		}
1011		list[k] = list[i]
1012		k++
1013	}
1014	return list[:k]
1015}
1016
1017func firstUniqueInstallPathsMap(list InstallPaths) InstallPaths {
1018	k := 0
1019	seen := make(map[InstallPath]bool, len(list))
1020	for i := 0; i < len(list); i++ {
1021		if seen[list[i]] {
1022			continue
1023		}
1024		seen[list[i]] = true
1025		list[k] = list[i]
1026		k++
1027	}
1028	return list[:k]
1029}
1030
1031// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each.  It
1032// modifies the Paths slice contents in place, and returns a subslice of the original slice.
1033func LastUniquePaths(list Paths) Paths {
1034	totalSkip := 0
1035	for i := len(list) - 1; i >= totalSkip; i-- {
1036		skip := 0
1037		for j := i - 1; j >= totalSkip; j-- {
1038			if list[i] == list[j] {
1039				skip++
1040			} else {
1041				list[j+skip] = list[j]
1042			}
1043		}
1044		totalSkip += skip
1045	}
1046	return list[totalSkip:]
1047}
1048
1049// ReversePaths returns a copy of a Paths in reverse order.
1050func ReversePaths(list Paths) Paths {
1051	if list == nil {
1052		return nil
1053	}
1054	ret := make(Paths, len(list))
1055	for i := range list {
1056		ret[i] = list[len(list)-1-i]
1057	}
1058	return ret
1059}
1060
1061func indexPathList(s Path, list []Path) int {
1062	for i, l := range list {
1063		if l == s {
1064			return i
1065		}
1066	}
1067
1068	return -1
1069}
1070
1071func inPathList(p Path, list []Path) bool {
1072	return indexPathList(p, list) != -1
1073}
1074
1075func FilterPathList(list []Path, filter []Path) (remainder []Path, filtered []Path) {
1076	return FilterPathListPredicate(list, func(p Path) bool { return inPathList(p, filter) })
1077}
1078
1079func FilterPathListPredicate(list []Path, predicate func(Path) bool) (remainder []Path, filtered []Path) {
1080	for _, l := range list {
1081		if predicate(l) {
1082			filtered = append(filtered, l)
1083		} else {
1084			remainder = append(remainder, l)
1085		}
1086	}
1087
1088	return
1089}
1090
1091// HasExt returns true of any of the paths have extension ext, otherwise false
1092func (p Paths) HasExt(ext string) bool {
1093	for _, path := range p {
1094		if path.Ext() == ext {
1095			return true
1096		}
1097	}
1098
1099	return false
1100}
1101
1102// FilterByExt returns the subset of the paths that have extension ext
1103func (p Paths) FilterByExt(ext string) Paths {
1104	ret := make(Paths, 0, len(p))
1105	for _, path := range p {
1106		if path.Ext() == ext {
1107			ret = append(ret, path)
1108		}
1109	}
1110	return ret
1111}
1112
1113// FilterOutByExt returns the subset of the paths that do not have extension ext
1114func (p Paths) FilterOutByExt(ext string) Paths {
1115	ret := make(Paths, 0, len(p))
1116	for _, path := range p {
1117		if path.Ext() != ext {
1118			ret = append(ret, path)
1119		}
1120	}
1121	return ret
1122}
1123
1124// DirectorySortedPaths is a slice of paths that are sorted such that all files in a directory
1125// (including subdirectories) are in a contiguous subslice of the list, and can be found in
1126// O(log(N)) time using a binary search on the directory prefix.
1127type DirectorySortedPaths Paths
1128
1129func PathsToDirectorySortedPaths(paths Paths) DirectorySortedPaths {
1130	ret := append(DirectorySortedPaths(nil), paths...)
1131	sort.Slice(ret, func(i, j int) bool {
1132		return ret[i].String() < ret[j].String()
1133	})
1134	return ret
1135}
1136
1137// PathsInDirectory returns a subslice of the DirectorySortedPaths as a Paths that contains all entries
1138// that are in the specified directory and its subdirectories.
1139func (p DirectorySortedPaths) PathsInDirectory(dir string) Paths {
1140	prefix := filepath.Clean(dir) + "/"
1141	start := sort.Search(len(p), func(i int) bool {
1142		return prefix < p[i].String()
1143	})
1144
1145	ret := p[start:]
1146
1147	end := sort.Search(len(ret), func(i int) bool {
1148		return !strings.HasPrefix(ret[i].String(), prefix)
1149	})
1150
1151	ret = ret[:end]
1152
1153	return Paths(ret)
1154}
1155
1156// WritablePaths is a slice of WritablePath, used for multiple outputs.
1157type WritablePaths []WritablePath
1158
1159// RelativeToTop creates a new WritablePaths containing the result of calling Path.RelativeToTop on
1160// each item in this slice.
1161func (p WritablePaths) RelativeToTop() WritablePaths {
1162	ensureTestOnly()
1163	if p == nil {
1164		return p
1165	}
1166	ret := make(WritablePaths, len(p))
1167	for i, path := range p {
1168		ret[i] = path.RelativeToTop().(WritablePath)
1169	}
1170	return ret
1171}
1172
1173// Strings returns the string forms of the writable paths.
1174func (p WritablePaths) Strings() []string {
1175	if p == nil {
1176		return nil
1177	}
1178	ret := make([]string, len(p))
1179	for i, path := range p {
1180		ret[i] = path.String()
1181	}
1182	return ret
1183}
1184
1185// Paths returns the WritablePaths as a Paths
1186func (p WritablePaths) Paths() Paths {
1187	if p == nil {
1188		return nil
1189	}
1190	ret := make(Paths, len(p))
1191	for i, path := range p {
1192		ret[i] = path
1193	}
1194	return ret
1195}
1196
1197type basePath struct {
1198	path string
1199	rel  string
1200}
1201
1202type basePathGob struct {
1203	Path string
1204	Rel  string
1205}
1206
1207func (p *basePath) ToGob() *basePathGob {
1208	return &basePathGob{
1209		Path: p.path,
1210		Rel:  p.rel,
1211	}
1212}
1213
1214func (p *basePath) FromGob(data *basePathGob) {
1215	p.path = data.Path
1216	p.rel = data.Rel
1217}
1218
1219func (p basePath) GobEncode() ([]byte, error) {
1220	return gobtools.CustomGobEncode[basePathGob](&p)
1221}
1222
1223func (p *basePath) GobDecode(data []byte) error {
1224	return gobtools.CustomGobDecode[basePathGob](data, p)
1225}
1226
1227func (p basePath) Ext() string {
1228	return filepath.Ext(p.path)
1229}
1230
1231func (p basePath) Base() string {
1232	return filepath.Base(p.path)
1233}
1234
1235func (p basePath) Rel() string {
1236	if p.rel != "" {
1237		return p.rel
1238	}
1239	return p.path
1240}
1241
1242func (p basePath) String() string {
1243	return p.path
1244}
1245
1246func (p basePath) withRel(rel string) basePath {
1247	p.path = filepath.Join(p.path, rel)
1248	p.rel = rel
1249	return p
1250}
1251
1252func (p basePath) withoutRel() basePath {
1253	p.rel = filepath.Base(p.path)
1254	return p
1255}
1256
1257// SourcePath is a Path representing a file path rooted from SrcDir
1258type SourcePath struct {
1259	basePath
1260}
1261
1262var _ Path = SourcePath{}
1263
1264func (p SourcePath) withRel(rel string) SourcePath {
1265	p.basePath = p.basePath.withRel(rel)
1266	return p
1267}
1268
1269func (p SourcePath) RelativeToTop() Path {
1270	ensureTestOnly()
1271	return p
1272}
1273
1274// safePathForSource is for paths that we expect are safe -- only for use by go
1275// code that is embedding ninja variables in paths
1276func safePathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
1277	p, err := validateSafePath(pathComponents...)
1278	ret := SourcePath{basePath{p, ""}}
1279	if err != nil {
1280		return ret, err
1281	}
1282
1283	// absolute path already checked by validateSafePath
1284	// special-case api surface gen files for now
1285	if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) && !strings.Contains(ret.String(), ctx.Config().soongOutDir+"/.export") {
1286		return ret, fmt.Errorf("source path %q is in output", ret.String())
1287	}
1288
1289	return ret, err
1290}
1291
1292// pathForSource creates a SourcePath from pathComponents, but does not check that it exists.
1293func pathForSource(ctx PathContext, pathComponents ...string) (SourcePath, error) {
1294	p, err := validatePath(pathComponents...)
1295	ret := SourcePath{basePath{p, ""}}
1296	if err != nil {
1297		return ret, err
1298	}
1299
1300	// absolute path already checked by validatePath
1301	// special-case for now
1302	if strings.HasPrefix(ret.String(), ctx.Config().soongOutDir) && !strings.Contains(ret.String(), ctx.Config().soongOutDir+"/.export") {
1303		return ret, fmt.Errorf("source path %q is in output", ret.String())
1304	}
1305
1306	return ret, nil
1307}
1308
1309// existsWithDependencies returns true if the path exists, and adds appropriate dependencies to rerun if the
1310// path does not exist.
1311func existsWithDependencies(ctx PathGlobContext, path SourcePath) (exists bool, err error) {
1312	var files []string
1313
1314	// Use glob to produce proper dependencies, even though we only want
1315	// a single file.
1316	files, err = ctx.GlobWithDeps(path.String(), nil)
1317
1318	if err != nil {
1319		return false, fmt.Errorf("glob: %s", err.Error())
1320	}
1321
1322	return len(files) > 0, nil
1323}
1324
1325// PathForSource joins the provided path components and validates that the result
1326// neither escapes the source dir nor is in the out dir.
1327// On error, it will return a usable, but invalid SourcePath, and report a ModuleError.
1328func PathForSource(ctx PathContext, pathComponents ...string) SourcePath {
1329	path, err := pathForSource(ctx, pathComponents...)
1330	if err != nil {
1331		reportPathError(ctx, err)
1332	}
1333
1334	if pathtools.IsGlob(path.String()) {
1335		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
1336	}
1337
1338	if modCtx, ok := ctx.(ModuleMissingDepsPathContext); ok && ctx.Config().AllowMissingDependencies() {
1339		exists, err := existsWithDependencies(modCtx, path)
1340		if err != nil {
1341			reportPathError(ctx, err)
1342		}
1343		if !exists {
1344			modCtx.AddMissingDependencies([]string{path.String()})
1345		}
1346	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
1347		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
1348	} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
1349		ReportPathErrorf(ctx, "source path %q does not exist", path)
1350	}
1351	return path
1352}
1353
1354// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
1355// the path is relative to the root of the output folder, not the out/soong folder.
1356func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
1357	path, err := validatePath(pathComponents...)
1358	if err != nil {
1359		reportPathError(ctx, err)
1360	}
1361	fullPath := filepath.Join(ctx.Config().OutDir(), path)
1362	path = fullPath[len(fullPath)-len(path):]
1363	return OutputPath{basePath{path, ""}, ctx.Config().OutDir(), fullPath}
1364}
1365
1366// MaybeExistentPathForSource joins the provided path components and validates that the result
1367// neither escapes the source dir nor is in the out dir.
1368// It does not validate whether the path exists.
1369func MaybeExistentPathForSource(ctx PathContext, pathComponents ...string) SourcePath {
1370	path, err := pathForSource(ctx, pathComponents...)
1371	if err != nil {
1372		reportPathError(ctx, err)
1373	}
1374
1375	if pathtools.IsGlob(path.String()) {
1376		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
1377	}
1378	return path
1379}
1380
1381// ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
1382// rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
1383// it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
1384// of the path changes.
1385func ExistentPathForSource(ctx PathGlobContext, pathComponents ...string) OptionalPath {
1386	path, err := pathForSource(ctx, pathComponents...)
1387	if err != nil {
1388		reportPathError(ctx, err)
1389		// No need to put the error message into the returned path since it has been reported already.
1390		return OptionalPath{}
1391	}
1392
1393	if pathtools.IsGlob(path.String()) {
1394		ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
1395		return OptionalPath{}
1396	}
1397
1398	exists, err := existsWithDependencies(ctx, path)
1399	if err != nil {
1400		reportPathError(ctx, err)
1401		return OptionalPath{}
1402	}
1403	if !exists {
1404		return InvalidOptionalPath(path.String() + " does not exist")
1405	}
1406	return OptionalPathForPath(path)
1407}
1408
1409func (p SourcePath) String() string {
1410	if p.path == "" {
1411		return "."
1412	}
1413	return p.path
1414}
1415
1416func (p SourcePath) WithoutRel() Path {
1417	p.basePath = p.basePath.withoutRel()
1418	return p
1419}
1420
1421// Join creates a new SourcePath with paths... joined with the current path. The
1422// provided paths... may not use '..' to escape from the current path.
1423func (p SourcePath) Join(ctx PathContext, paths ...string) SourcePath {
1424	path, err := validatePath(paths...)
1425	if err != nil {
1426		reportPathError(ctx, err)
1427	}
1428	return p.withRel(path)
1429}
1430
1431// join is like Join but does less path validation.
1432func (p SourcePath) join(ctx PathContext, paths ...string) SourcePath {
1433	path, err := validateSafePath(paths...)
1434	if err != nil {
1435		reportPathError(ctx, err)
1436	}
1437	return p.withRel(path)
1438}
1439
1440// OverlayPath returns the overlay for `path' if it exists. This assumes that the
1441// SourcePath is the path to a resource overlay directory.
1442func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) OptionalPath {
1443	var relDir string
1444	if srcPath, ok := path.(SourcePath); ok {
1445		relDir = srcPath.path
1446	} else {
1447		ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
1448		// No need to put the error message into the returned path since it has been reported already.
1449		return OptionalPath{}
1450	}
1451	dir := filepath.Join(p.path, relDir)
1452	// Use Glob so that we are run again if the directory is added.
1453	if pathtools.IsGlob(dir) {
1454		ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
1455	}
1456	paths, err := ctx.GlobWithDeps(dir, nil)
1457	if err != nil {
1458		ReportPathErrorf(ctx, "glob: %s", err.Error())
1459		return OptionalPath{}
1460	}
1461	if len(paths) == 0 {
1462		return InvalidOptionalPath(dir + " does not exist")
1463	}
1464	return OptionalPathForPath(PathForSource(ctx, paths[0]))
1465}
1466
1467// OutputPath is a Path representing an intermediates file path rooted from the build directory
1468type OutputPath struct {
1469	basePath
1470
1471	// The base out directory for this path, either Config.SoongOutDir() or Config.OutDir()
1472	outDir string
1473
1474	fullPath string
1475}
1476
1477type outputPathGob struct {
1478	BasePath basePath
1479	OutDir   string
1480	FullPath string
1481}
1482
1483func (p *OutputPath) ToGob() *outputPathGob {
1484	return &outputPathGob{
1485		BasePath: p.basePath,
1486		OutDir:   p.outDir,
1487		FullPath: p.fullPath,
1488	}
1489}
1490
1491func (p *OutputPath) FromGob(data *outputPathGob) {
1492	p.basePath = data.BasePath
1493	p.outDir = data.OutDir
1494	p.fullPath = data.FullPath
1495}
1496
1497func (p OutputPath) GobEncode() ([]byte, error) {
1498	return gobtools.CustomGobEncode[outputPathGob](&p)
1499}
1500
1501func (p *OutputPath) GobDecode(data []byte) error {
1502	return gobtools.CustomGobDecode[outputPathGob](data, p)
1503}
1504
1505func (p OutputPath) withRel(rel string) OutputPath {
1506	p.basePath = p.basePath.withRel(rel)
1507	p.fullPath = filepath.Join(p.fullPath, rel)
1508	return p
1509}
1510
1511func (p OutputPath) WithoutRel() Path {
1512	p.basePath = p.basePath.withoutRel()
1513	return p
1514}
1515
1516func (p OutputPath) getSoongOutDir() string {
1517	return p.outDir
1518}
1519
1520func (p OutputPath) RelativeToTop() Path {
1521	return p.outputPathRelativeToTop()
1522}
1523
1524func (p OutputPath) outputPathRelativeToTop() OutputPath {
1525	p.fullPath = StringPathRelativeToTop(p.outDir, p.fullPath)
1526	if strings.HasSuffix(p.outDir, testOutSoongSubDir) {
1527		p.outDir = TestOutSoongDir
1528	} else {
1529		// Handle the PathForArbitraryOutput case
1530		p.outDir = testOutDir
1531	}
1532	return p
1533}
1534
1535func (p OutputPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1536	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1537}
1538
1539var _ Path = OutputPath{}
1540var _ WritablePath = OutputPath{}
1541var _ objPathProvider = OutputPath{}
1542
1543// toolDepPath is a Path representing a dependency of the build tool.
1544type toolDepPath struct {
1545	basePath
1546}
1547
1548func (t toolDepPath) WithoutRel() Path {
1549	t.basePath = t.basePath.withoutRel()
1550	return t
1551}
1552
1553func (t toolDepPath) RelativeToTop() Path {
1554	ensureTestOnly()
1555	return t
1556}
1557
1558var _ Path = toolDepPath{}
1559
1560// pathForBuildToolDep returns a toolDepPath representing the given path string.
1561// There is no validation for the path, as it is "trusted": It may fail
1562// normal validation checks. For example, it may be an absolute path.
1563// Only use this function to construct paths for dependencies of the build
1564// tool invocation.
1565func pathForBuildToolDep(ctx PathContext, path string) toolDepPath {
1566	return toolDepPath{basePath{path, ""}}
1567}
1568
1569// PathForOutput joins the provided paths and returns an OutputPath that is
1570// validated to not escape the build dir.
1571// On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
1572func PathForOutput(ctx PathContext, pathComponents ...string) OutputPath {
1573	path, err := validatePath(pathComponents...)
1574	if err != nil {
1575		reportPathError(ctx, err)
1576	}
1577	fullPath := filepath.Join(ctx.Config().soongOutDir, path)
1578	path = fullPath[len(fullPath)-len(path):]
1579	return OutputPath{basePath{path, ""}, ctx.Config().soongOutDir, fullPath}
1580}
1581
1582// PathsForOutput returns Paths rooted from outDir
1583func PathsForOutput(ctx PathContext, paths []string) WritablePaths {
1584	ret := make(WritablePaths, len(paths))
1585	for i, path := range paths {
1586		ret[i] = PathForOutput(ctx, path)
1587	}
1588	return ret
1589}
1590
1591func (p OutputPath) writablePath() {}
1592
1593func (p OutputPath) String() string {
1594	return p.fullPath
1595}
1596
1597// Join creates a new OutputPath with paths... joined with the current path. The
1598// provided paths... may not use '..' to escape from the current path.
1599func (p OutputPath) Join(ctx PathContext, paths ...string) OutputPath {
1600	path, err := validatePath(paths...)
1601	if err != nil {
1602		reportPathError(ctx, err)
1603	}
1604	return p.withRel(path)
1605}
1606
1607// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
1608func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
1609	if strings.Contains(ext, "/") {
1610		ReportPathErrorf(ctx, "extension %q cannot contain /", ext)
1611	}
1612	ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
1613	ret.rel = pathtools.ReplaceExtension(p.rel, ext)
1614	return ret
1615}
1616
1617// InSameDir creates a new OutputPath from the directory of the current OutputPath joined with the elements in paths.
1618func (p OutputPath) InSameDir(ctx PathContext, paths ...string) OutputPath {
1619	path, err := validatePath(paths...)
1620	if err != nil {
1621		reportPathError(ctx, err)
1622	}
1623
1624	ret := PathForOutput(ctx, filepath.Dir(p.path), path)
1625	ret.rel = filepath.Join(filepath.Dir(p.rel), path)
1626	return ret
1627}
1628
1629// PathForIntermediates returns an OutputPath representing the top-level
1630// intermediates directory.
1631func PathForIntermediates(ctx PathContext, paths ...string) OutputPath {
1632	path, err := validatePath(paths...)
1633	if err != nil {
1634		reportPathError(ctx, err)
1635	}
1636	return PathForOutput(ctx, ".intermediates", path)
1637}
1638
1639var _ genPathProvider = SourcePath{}
1640var _ objPathProvider = SourcePath{}
1641var _ resPathProvider = SourcePath{}
1642
1643// PathForModuleSrc returns a Path representing the paths... under the
1644// module's local source directory.
1645func PathForModuleSrc(ctx ModuleMissingDepsPathContext, pathComponents ...string) Path {
1646	// Just join the components textually just to make sure that it does not corrupt a fully qualified
1647	// module reference, e.g. if the pathComponents is "://other:foo" then using filepath.Join() or
1648	// validatePath() will corrupt it, e.g. replace "//" with "/". If the path is not a module
1649	// reference then it will be validated by expandOneSrcPath anyway when it calls expandOneSrcPath.
1650	p := strings.Join(pathComponents, string(filepath.Separator))
1651	paths, err := expandOneSrcPath(sourcePathInput{context: ctx, path: p, includeDirs: true})
1652	if err != nil {
1653		if depErr, ok := err.(missingDependencyError); ok {
1654			if ctx.Config().AllowMissingDependencies() {
1655				ctx.AddMissingDependencies(depErr.missingDeps)
1656			} else {
1657				ctx.ModuleErrorf(`%s, is the property annotated with android:"path"?`, depErr.Error())
1658			}
1659		} else {
1660			reportPathError(ctx, err)
1661		}
1662		return nil
1663	} else if len(paths) == 0 {
1664		ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
1665		return nil
1666	} else if len(paths) > 1 {
1667		ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
1668	}
1669	return paths[0]
1670}
1671
1672func pathForModuleSrc(ctx EarlyModulePathContext, paths ...string) SourcePath {
1673	p, err := validatePath(paths...)
1674	if err != nil {
1675		reportPathError(ctx, err)
1676	}
1677
1678	path, err := pathForSource(ctx, ctx.ModuleDir(), p)
1679	if err != nil {
1680		reportPathError(ctx, err)
1681	}
1682
1683	path.basePath.rel = p
1684
1685	return path
1686}
1687
1688// PathsWithModuleSrcSubDir takes a list of Paths and returns a new list of Paths where Rel() on each path
1689// will return the path relative to subDir in the module's source directory.  If any input paths are not located
1690// inside subDir then a path error will be reported.
1691func PathsWithModuleSrcSubDir(ctx EarlyModulePathContext, paths Paths, subDir string) Paths {
1692	paths = append(Paths(nil), paths...)
1693	subDirFullPath := pathForModuleSrc(ctx, subDir)
1694	for i, path := range paths {
1695		rel := Rel(ctx, subDirFullPath.String(), path.String())
1696		paths[i] = subDirFullPath.join(ctx, rel)
1697	}
1698	return paths
1699}
1700
1701// PathWithModuleSrcSubDir takes a Path and returns a Path where Rel() will return the path relative to subDir in the
1702// module's source directory.  If the input path is not located inside subDir then a path error will be reported.
1703func PathWithModuleSrcSubDir(ctx EarlyModulePathContext, path Path, subDir string) Path {
1704	subDirFullPath := pathForModuleSrc(ctx, subDir)
1705	rel := Rel(ctx, subDirFullPath.String(), path.String())
1706	return subDirFullPath.Join(ctx, rel)
1707}
1708
1709// OptionalPathForModuleSrc returns an OptionalPath. The OptionalPath contains a
1710// valid path if p is non-nil.
1711func OptionalPathForModuleSrc(ctx ModuleMissingDepsPathContext, p *string) OptionalPath {
1712	if p == nil {
1713		return OptionalPath{}
1714	}
1715	return OptionalPathForPath(PathForModuleSrc(ctx, *p))
1716}
1717
1718func (p SourcePath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
1719	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1720}
1721
1722func (p SourcePath) genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath {
1723	// If Trim_extension being set, force append Output_extension without replace original extension.
1724	if trimExt != "" {
1725		if ext != "" {
1726			return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)+"."+ext)
1727		}
1728		return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt))
1729	}
1730	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1731}
1732
1733func (p SourcePath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1734	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1735}
1736
1737func (p SourcePath) resPathWithName(ctx ModuleOutPathContext, name string) ModuleResPath {
1738	// TODO: Use full directory if the new ctx is not the current ctx?
1739	return PathForModuleRes(ctx, p.path, name)
1740}
1741
1742// ModuleOutPath is a Path representing a module's output directory.
1743type ModuleOutPath struct {
1744	OutputPath
1745}
1746
1747func (p ModuleOutPath) RelativeToTop() Path {
1748	p.OutputPath = p.outputPathRelativeToTop()
1749	return p
1750}
1751
1752var _ Path = ModuleOutPath{}
1753var _ WritablePath = ModuleOutPath{}
1754
1755func (p ModuleOutPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1756	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1757}
1758
1759// ModuleOutPathContext Subset of ModuleContext functions necessary for output path methods.
1760type ModuleOutPathContext interface {
1761	PathContext
1762
1763	ModuleName() string
1764	ModuleDir() string
1765	ModuleSubDir() string
1766}
1767
1768func pathForModuleOut(ctx ModuleOutPathContext) OutputPath {
1769	return PathForOutput(ctx, ".intermediates", ctx.ModuleDir(), ctx.ModuleName(), ctx.ModuleSubDir())
1770}
1771
1772// PathForModuleOut returns a Path representing the paths... under the module's
1773// output directory.
1774func PathForModuleOut(ctx ModuleOutPathContext, paths ...string) ModuleOutPath {
1775	p, err := validatePath(paths...)
1776	if err != nil {
1777		reportPathError(ctx, err)
1778	}
1779	return ModuleOutPath{
1780		OutputPath: pathForModuleOut(ctx).withRel(p),
1781	}
1782}
1783
1784// ModuleGenPath is a Path representing the 'gen' directory in a module's output
1785// directory. Mainly used for generated sources.
1786type ModuleGenPath struct {
1787	ModuleOutPath
1788}
1789
1790func (p ModuleGenPath) RelativeToTop() Path {
1791	p.OutputPath = p.outputPathRelativeToTop()
1792	return p
1793}
1794
1795var _ Path = ModuleGenPath{}
1796var _ WritablePath = ModuleGenPath{}
1797var _ genPathProvider = ModuleGenPath{}
1798var _ objPathProvider = ModuleGenPath{}
1799
1800// PathForModuleGen returns a Path representing the paths... under the module's
1801// `gen' directory.
1802func PathForModuleGen(ctx ModuleOutPathContext, paths ...string) ModuleGenPath {
1803	p, err := validatePath(paths...)
1804	if err != nil {
1805		reportPathError(ctx, err)
1806	}
1807	return ModuleGenPath{
1808		ModuleOutPath: ModuleOutPath{
1809			OutputPath: pathForModuleOut(ctx).withRel("gen").withRel(p),
1810		},
1811	}
1812}
1813
1814func (p ModuleGenPath) genPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleGenPath {
1815	// TODO: make a different path for local vs remote generated files?
1816	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1817}
1818
1819func (p ModuleGenPath) genPathWithExtAndTrimExt(ctx ModuleOutPathContext, subdir, ext string, trimExt string) ModuleGenPath {
1820	// If Trim_extension being set, force append Output_extension without replace original extension.
1821	if trimExt != "" {
1822		if ext != "" {
1823			return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt)+"."+ext)
1824		}
1825		return PathForModuleGen(ctx, subdir, strings.TrimSuffix(p.path, trimExt))
1826	}
1827	return PathForModuleGen(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1828}
1829
1830func (p ModuleGenPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext string) ModuleObjPath {
1831	return PathForModuleObj(ctx, subdir, pathtools.ReplaceExtension(p.path, ext))
1832}
1833
1834// ModuleObjPath is a Path representing the 'obj' directory in a module's output
1835// directory. Used for compiled objects.
1836type ModuleObjPath struct {
1837	ModuleOutPath
1838}
1839
1840func (p ModuleObjPath) RelativeToTop() Path {
1841	p.OutputPath = p.outputPathRelativeToTop()
1842	return p
1843}
1844
1845var _ Path = ModuleObjPath{}
1846var _ WritablePath = ModuleObjPath{}
1847
1848// PathForModuleObj returns a Path representing the paths... under the module's
1849// 'obj' directory.
1850func PathForModuleObj(ctx ModuleOutPathContext, pathComponents ...string) ModuleObjPath {
1851	p, err := validatePath(pathComponents...)
1852	if err != nil {
1853		reportPathError(ctx, err)
1854	}
1855	return ModuleObjPath{PathForModuleOut(ctx, "obj", p)}
1856}
1857
1858// ModuleResPath is a a Path representing the 'res' directory in a module's
1859// output directory.
1860type ModuleResPath struct {
1861	ModuleOutPath
1862}
1863
1864func (p ModuleResPath) RelativeToTop() Path {
1865	p.OutputPath = p.outputPathRelativeToTop()
1866	return p
1867}
1868
1869var _ Path = ModuleResPath{}
1870var _ WritablePath = ModuleResPath{}
1871
1872// PathForModuleRes returns a Path representing the paths... under the module's
1873// 'res' directory.
1874func PathForModuleRes(ctx ModuleOutPathContext, pathComponents ...string) ModuleResPath {
1875	p, err := validatePath(pathComponents...)
1876	if err != nil {
1877		reportPathError(ctx, err)
1878	}
1879
1880	return ModuleResPath{PathForModuleOut(ctx, "res", p)}
1881}
1882
1883// InstallPath is a Path representing a installed file path rooted from the build directory
1884type InstallPath struct {
1885	basePath
1886
1887	// The soong build directory, i.e. Config.SoongOutDir()
1888	soongOutDir string
1889
1890	// partitionDir is the part of the InstallPath that is automatically determined according to the context.
1891	// For example, it is host/<os>-<arch> for host modules, and target/product/<device>/<partition> for device modules.
1892	partitionDir string
1893
1894	partition string
1895
1896	// makePath indicates whether this path is for Soong (false) or Make (true).
1897	makePath bool
1898
1899	fullPath string
1900}
1901
1902type installPathGob struct {
1903	BasePath     basePath
1904	SoongOutDir  string
1905	PartitionDir string
1906	Partition    string
1907	MakePath     bool
1908	FullPath     string
1909}
1910
1911func (p *InstallPath) ToGob() *installPathGob {
1912	return &installPathGob{
1913		BasePath:     p.basePath,
1914		SoongOutDir:  p.soongOutDir,
1915		PartitionDir: p.partitionDir,
1916		Partition:    p.partition,
1917		MakePath:     p.makePath,
1918		FullPath:     p.fullPath,
1919	}
1920}
1921
1922func (p *InstallPath) FromGob(data *installPathGob) {
1923	p.basePath = data.BasePath
1924	p.soongOutDir = data.SoongOutDir
1925	p.partitionDir = data.PartitionDir
1926	p.partition = data.Partition
1927	p.makePath = data.MakePath
1928	p.fullPath = data.FullPath
1929}
1930
1931func (p InstallPath) GobEncode() ([]byte, error) {
1932	return gobtools.CustomGobEncode[installPathGob](&p)
1933}
1934
1935func (p *InstallPath) GobDecode(data []byte) error {
1936	return gobtools.CustomGobDecode[installPathGob](data, p)
1937}
1938
1939// Will panic if called from outside a test environment.
1940func ensureTestOnly() {
1941	if PrefixInList(os.Args, "-test.") {
1942		return
1943	}
1944	panic(fmt.Errorf("Not in test. Command line:\n  %s", strings.Join(os.Args, "\n  ")))
1945}
1946
1947func (p InstallPath) RelativeToTop() Path {
1948	ensureTestOnly()
1949	if p.makePath {
1950		p.soongOutDir = testOutDir
1951	} else {
1952		p.soongOutDir = TestOutSoongDir
1953	}
1954	p.fullPath = filepath.Join(p.soongOutDir, p.path)
1955	return p
1956}
1957
1958func (p InstallPath) WithoutRel() Path {
1959	p.basePath = p.basePath.withoutRel()
1960	return p
1961}
1962
1963func (p InstallPath) getSoongOutDir() string {
1964	return p.soongOutDir
1965}
1966
1967func (p InstallPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
1968	panic("Not implemented")
1969}
1970
1971var _ Path = InstallPath{}
1972var _ WritablePath = InstallPath{}
1973
1974func (p InstallPath) writablePath() {}
1975
1976func (p InstallPath) String() string {
1977	return p.fullPath
1978}
1979
1980// PartitionDir returns the path to the partition where the install path is rooted at. It is
1981// out/soong/target/product/<device>/<partition> for device modules, and out/soong/host/<os>-<arch> for host modules.
1982// The ./soong is dropped if the install path is for Make.
1983func (p InstallPath) PartitionDir() string {
1984	if p.makePath {
1985		return filepath.Join(p.soongOutDir, "../", p.partitionDir)
1986	} else {
1987		return filepath.Join(p.soongOutDir, p.partitionDir)
1988	}
1989}
1990
1991func (p InstallPath) Partition() string {
1992	return p.partition
1993}
1994
1995// Join creates a new InstallPath with paths... joined with the current path. The
1996// provided paths... may not use '..' to escape from the current path.
1997func (p InstallPath) Join(ctx PathContext, paths ...string) InstallPath {
1998	path, err := validatePath(paths...)
1999	if err != nil {
2000		reportPathError(ctx, err)
2001	}
2002	return p.withRel(path)
2003}
2004
2005func (p InstallPath) withRel(rel string) InstallPath {
2006	p.basePath = p.basePath.withRel(rel)
2007	p.fullPath = filepath.Join(p.fullPath, rel)
2008	return p
2009}
2010
2011// Deprecated: ToMakePath is a noop, PathForModuleInstall always returns Make paths when building
2012// embedded in Make.
2013func (p InstallPath) ToMakePath() InstallPath {
2014	p.makePath = true
2015	return p
2016}
2017
2018// PathForModuleInstall returns a Path representing the install path for the
2019// module appended with paths...
2020func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
2021	os, arch := osAndArch(ctx)
2022	partition := modulePartition(ctx, os.Class == Device)
2023	return pathForInstall(ctx, os, arch, partition, pathComponents...)
2024}
2025
2026// PathForHostDexInstall returns an InstallPath representing the install path for the
2027// module appended with paths...
2028func PathForHostDexInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
2029	return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", pathComponents...)
2030}
2031
2032// PathForModuleInPartitionInstall is similar to PathForModuleInstall but partition is provided by the caller
2033func PathForModuleInPartitionInstall(ctx ModuleInstallPathContext, partition string, pathComponents ...string) InstallPath {
2034	os, arch := osAndArch(ctx)
2035	return pathForInstall(ctx, os, arch, partition, pathComponents...)
2036}
2037
2038func osAndArch(ctx ModuleInstallPathContext) (OsType, ArchType) {
2039	os := ctx.Os()
2040	arch := ctx.Arch().ArchType
2041	forceOS, forceArch := ctx.InstallForceOS()
2042	if forceOS != nil {
2043		os = *forceOS
2044	}
2045	if forceArch != nil {
2046		arch = *forceArch
2047	}
2048	return os, arch
2049}
2050
2051func pathForPartitionInstallDir(ctx PathContext, partition, partitionPath string, makePath bool) InstallPath {
2052	fullPath := ctx.Config().SoongOutDir()
2053	if makePath {
2054		// Make path starts with out/ instead of out/soong.
2055		fullPath = filepath.Join(fullPath, "../", partitionPath)
2056	} else {
2057		fullPath = filepath.Join(fullPath, partitionPath)
2058	}
2059
2060	return InstallPath{
2061		basePath:     basePath{partitionPath, ""},
2062		soongOutDir:  ctx.Config().soongOutDir,
2063		partitionDir: partitionPath,
2064		partition:    partition,
2065		makePath:     makePath,
2066		fullPath:     fullPath,
2067	}
2068}
2069
2070func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string,
2071	pathComponents ...string) InstallPath {
2072
2073	var partitionPaths []string
2074
2075	if os.Class == Device {
2076		partitionPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
2077	} else {
2078		osName := os.String()
2079		if os == Linux {
2080			// instead of linux_glibc
2081			osName = "linux"
2082		}
2083		if os == LinuxMusl && ctx.Config().UseHostMusl() {
2084			// When using musl instead of glibc, use "linux" instead of "linux_musl".  When cross
2085			// compiling we will still use "linux_musl".
2086			osName = "linux"
2087		}
2088
2089		// SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
2090		// and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
2091		// to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
2092		// Let's keep using x86 for the existing cases until we have a need to support
2093		// other architectures.
2094		archName := arch.String()
2095		if os.Class == Host && (arch == X86_64 || arch == Common) {
2096			archName = "x86"
2097		}
2098		partitionPaths = []string{"host", osName + "-" + archName, partition}
2099	}
2100
2101	partitionPath, err := validatePath(partitionPaths...)
2102	if err != nil {
2103		reportPathError(ctx, err)
2104	}
2105
2106	base := pathForPartitionInstallDir(ctx, partition, partitionPath, ctx.Config().KatiEnabled())
2107	return base.Join(ctx, pathComponents...)
2108}
2109
2110func PathForNdkInstall(ctx PathContext, paths ...string) OutputPath {
2111	return PathForOutput(ctx, append([]string{"ndk"}, paths...)...)
2112}
2113
2114func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
2115	base := pathForPartitionInstallDir(ctx, "", "mainline-sdks", false)
2116	return base.Join(ctx, paths...)
2117}
2118
2119func PathForSuiteInstall(ctx PathContext, suite string, pathComponents ...string) InstallPath {
2120	return pathForPartitionInstallDir(ctx, "test_suites", "test_suites", false).Join(ctx, suite).Join(ctx, pathComponents...)
2121}
2122
2123func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
2124	rel := Rel(ctx, strings.TrimSuffix(path.PartitionDir(), path.partition), path.String())
2125	return "/" + rel
2126}
2127
2128func modulePartition(ctx ModuleInstallPathContext, device bool) string {
2129	var partition string
2130	if ctx.InstallInTestcases() {
2131		// "testcases" install directory can be used for host or device modules.
2132		partition = "testcases"
2133	} else if device {
2134		if ctx.InstallInData() {
2135			partition = "data"
2136		} else if ctx.InstallInRamdisk() {
2137			if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
2138				partition = "recovery/root/first_stage_ramdisk"
2139			} else {
2140				partition = "ramdisk"
2141			}
2142			if !ctx.InstallInRoot() {
2143				partition += "/system"
2144			}
2145		} else if ctx.InstallInVendorRamdisk() {
2146			// The module is only available after switching root into
2147			// /first_stage_ramdisk. To expose the module before switching root
2148			// on a device without a dedicated recovery partition, install the
2149			// recovery variant.
2150			if ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() {
2151				partition = "vendor_ramdisk/first_stage_ramdisk"
2152			} else {
2153				partition = "vendor_ramdisk"
2154			}
2155			if !ctx.InstallInRoot() {
2156				partition += "/system"
2157			}
2158		} else if ctx.InstallInDebugRamdisk() {
2159			partition = "debug_ramdisk"
2160		} else if ctx.InstallInRecovery() {
2161			if ctx.InstallInRoot() {
2162				partition = "recovery/root"
2163			} else {
2164				// the layout of recovery partion is the same as that of system partition
2165				partition = "recovery/root/system"
2166			}
2167		} else if ctx.SocSpecific() || ctx.InstallInVendor() {
2168			partition = ctx.DeviceConfig().VendorPath()
2169		} else if ctx.DeviceSpecific() || ctx.InstallInOdm() {
2170			partition = ctx.DeviceConfig().OdmPath()
2171		} else if ctx.ProductSpecific() || ctx.InstallInProduct() {
2172			partition = ctx.DeviceConfig().ProductPath()
2173		} else if ctx.SystemExtSpecific() {
2174			partition = ctx.DeviceConfig().SystemExtPath()
2175		} else if ctx.InstallInRoot() {
2176			partition = "root"
2177		} else if ctx.InstallInSystemDlkm() {
2178			partition = ctx.DeviceConfig().SystemDlkmPath()
2179		} else if ctx.InstallInVendorDlkm() {
2180			partition = ctx.DeviceConfig().VendorDlkmPath()
2181		} else if ctx.InstallInOdmDlkm() {
2182			partition = ctx.DeviceConfig().OdmDlkmPath()
2183		} else {
2184			partition = "system"
2185		}
2186		if ctx.InstallInSanitizerDir() {
2187			partition = "data/asan/" + partition
2188		}
2189	}
2190	return partition
2191}
2192
2193type InstallPaths []InstallPath
2194
2195// Paths returns the InstallPaths as a Paths
2196func (p InstallPaths) Paths() Paths {
2197	if p == nil {
2198		return nil
2199	}
2200	ret := make(Paths, len(p))
2201	for i, path := range p {
2202		ret[i] = path
2203	}
2204	return ret
2205}
2206
2207// Strings returns the string forms of the install paths.
2208func (p InstallPaths) Strings() []string {
2209	if p == nil {
2210		return nil
2211	}
2212	ret := make([]string, len(p))
2213	for i, path := range p {
2214		ret[i] = path.String()
2215	}
2216	return ret
2217}
2218
2219// validatePathInternal ensures that a path does not leave its component, and
2220// optionally doesn't contain Ninja variables.
2221func validatePathInternal(allowNinjaVariables bool, pathComponents ...string) (string, error) {
2222	initialEmpty := 0
2223	finalEmpty := 0
2224	for i, path := range pathComponents {
2225		if !allowNinjaVariables && strings.Contains(path, "$") {
2226			return "", fmt.Errorf("Path contains invalid character($): %s", path)
2227		}
2228
2229		path := filepath.Clean(path)
2230		if path == ".." || strings.HasPrefix(path, "../") || strings.HasPrefix(path, "/") {
2231			return "", fmt.Errorf("Path is outside directory: %s", path)
2232		}
2233
2234		if i == initialEmpty && pathComponents[i] == "" {
2235			initialEmpty++
2236		}
2237		if i == finalEmpty && pathComponents[len(pathComponents)-1-i] == "" {
2238			finalEmpty++
2239		}
2240	}
2241	// Optimization: filepath.Join("foo", "") returns a newly allocated copy
2242	// of "foo", while filepath.Join("foo") does not.  Strip out any empty
2243	// path components.
2244	if initialEmpty == len(pathComponents) {
2245		return "", nil
2246	}
2247	nonEmptyPathComponents := pathComponents[initialEmpty : len(pathComponents)-finalEmpty]
2248	// TODO: filepath.Join isn't necessarily correct with embedded ninja
2249	// variables. '..' may remove the entire ninja variable, even if it
2250	// will be expanded to multiple nested directories.
2251	return filepath.Join(nonEmptyPathComponents...), nil
2252}
2253
2254// validateSafePath validates a path that we trust (may contain ninja
2255// variables).  Ensures that each path component does not attempt to leave its
2256// component. Returns a joined version of each path component.
2257func validateSafePath(pathComponents ...string) (string, error) {
2258	return validatePathInternal(true, pathComponents...)
2259}
2260
2261// validatePath validates that a path does not include ninja variables, and that
2262// each path component does not attempt to leave its component. Returns a joined
2263// version of each path component.
2264func validatePath(pathComponents ...string) (string, error) {
2265	return validatePathInternal(false, pathComponents...)
2266}
2267
2268func PathForPhony(ctx PathContext, phony string) WritablePath {
2269	if strings.ContainsAny(phony, "$/") {
2270		ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
2271	}
2272	return PhonyPath{basePath{phony, ""}}
2273}
2274
2275type PhonyPath struct {
2276	basePath
2277}
2278
2279func (p PhonyPath) writablePath() {}
2280
2281func (p PhonyPath) getSoongOutDir() string {
2282	// A phone path cannot contain any / so cannot be relative to the build directory.
2283	return ""
2284}
2285
2286func (p PhonyPath) RelativeToTop() Path {
2287	ensureTestOnly()
2288	// A phony path cannot contain any / so does not have a build directory so switching to a new
2289	// build directory has no effect so just return this path.
2290	return p
2291}
2292
2293func (p PhonyPath) WithoutRel() Path {
2294	p.basePath = p.basePath.withoutRel()
2295	return p
2296}
2297
2298func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
2299	panic("Not implemented")
2300}
2301
2302var _ Path = PhonyPath{}
2303var _ WritablePath = PhonyPath{}
2304
2305type testPath struct {
2306	basePath
2307}
2308
2309func (p testPath) RelativeToTop() Path {
2310	ensureTestOnly()
2311	return p
2312}
2313
2314func (p testPath) WithoutRel() Path {
2315	p.basePath = p.basePath.withoutRel()
2316	return p
2317}
2318
2319func (p testPath) String() string {
2320	return p.path
2321}
2322
2323var _ Path = testPath{}
2324
2325// PathForTesting returns a Path constructed from joining the elements of paths with '/'.  It should only be used from
2326// within tests.
2327func PathForTesting(paths ...string) Path {
2328	p, err := validateSafePath(paths...)
2329	if err != nil {
2330		panic(err)
2331	}
2332	return testPath{basePath{path: p, rel: p}}
2333}
2334
2335func PathForTestingWithRel(path, rel string) Path {
2336	p, err := validateSafePath(path, rel)
2337	if err != nil {
2338		panic(err)
2339	}
2340	r, err := validatePath(rel)
2341	if err != nil {
2342		panic(err)
2343	}
2344	return testPath{basePath{path: p, rel: r}}
2345}
2346
2347// PathsForTesting returns a Path constructed from each element in strs. It should only be used from within tests.
2348func PathsForTesting(strs ...string) Paths {
2349	p := make(Paths, len(strs))
2350	for i, s := range strs {
2351		p[i] = PathForTesting(s)
2352	}
2353
2354	return p
2355}
2356
2357type testPathContext struct {
2358	config Config
2359}
2360
2361func (x *testPathContext) Config() Config             { return x.config }
2362func (x *testPathContext) AddNinjaFileDeps(...string) {}
2363
2364// PathContextForTesting returns a PathContext that can be used in tests, for example to create an OutputPath with
2365// PathForOutput.
2366func PathContextForTesting(config Config) PathContext {
2367	return &testPathContext{
2368		config: config,
2369	}
2370}
2371
2372type testModuleInstallPathContext struct {
2373	baseModuleContext
2374
2375	inData          bool
2376	inTestcases     bool
2377	inSanitizerDir  bool
2378	inRamdisk       bool
2379	inVendorRamdisk bool
2380	inDebugRamdisk  bool
2381	inRecovery      bool
2382	inRoot          bool
2383	inOdm           bool
2384	inProduct       bool
2385	inVendor        bool
2386	inSystemDlkm    bool
2387	inVendorDlkm    bool
2388	inOdmDlkm       bool
2389	forceOS         *OsType
2390	forceArch       *ArchType
2391}
2392
2393func (m testModuleInstallPathContext) Config() Config {
2394	return m.baseModuleContext.config
2395}
2396
2397func (testModuleInstallPathContext) AddNinjaFileDeps(deps ...string) {}
2398
2399func (m testModuleInstallPathContext) InstallInData() bool {
2400	return m.inData
2401}
2402
2403func (m testModuleInstallPathContext) InstallInTestcases() bool {
2404	return m.inTestcases
2405}
2406
2407func (m testModuleInstallPathContext) InstallInSanitizerDir() bool {
2408	return m.inSanitizerDir
2409}
2410
2411func (m testModuleInstallPathContext) InstallInRamdisk() bool {
2412	return m.inRamdisk
2413}
2414
2415func (m testModuleInstallPathContext) InstallInVendorRamdisk() bool {
2416	return m.inVendorRamdisk
2417}
2418
2419func (m testModuleInstallPathContext) InstallInDebugRamdisk() bool {
2420	return m.inDebugRamdisk
2421}
2422
2423func (m testModuleInstallPathContext) InstallInRecovery() bool {
2424	return m.inRecovery
2425}
2426
2427func (m testModuleInstallPathContext) InstallInRoot() bool {
2428	return m.inRoot
2429}
2430
2431func (m testModuleInstallPathContext) InstallInOdm() bool {
2432	return m.inOdm
2433}
2434
2435func (m testModuleInstallPathContext) InstallInProduct() bool {
2436	return m.inProduct
2437}
2438
2439func (m testModuleInstallPathContext) InstallInVendor() bool {
2440	return m.inVendor
2441}
2442
2443func (m testModuleInstallPathContext) InstallInSystemDlkm() bool {
2444	return m.inSystemDlkm
2445}
2446
2447func (m testModuleInstallPathContext) InstallInVendorDlkm() bool {
2448	return m.inVendorDlkm
2449}
2450
2451func (m testModuleInstallPathContext) InstallInOdmDlkm() bool {
2452	return m.inOdmDlkm
2453}
2454
2455func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) {
2456	return m.forceOS, m.forceArch
2457}
2458
2459// Construct a minimal ModuleInstallPathContext for testing. Note that baseModuleContext is
2460// default-initialized, which leaves blueprint.baseModuleContext set to nil, so methods that are
2461// delegated to it will panic.
2462func ModuleInstallPathContextForTesting(config Config) ModuleInstallPathContext {
2463	ctx := &testModuleInstallPathContext{}
2464	ctx.config = config
2465	ctx.os = Android
2466	return ctx
2467}
2468
2469// Rel performs the same function as filepath.Rel, but reports errors to a PathContext, and reports an error if
2470// targetPath is not inside basePath.
2471func Rel(ctx PathContext, basePath string, targetPath string) string {
2472	rel, isRel := MaybeRel(ctx, basePath, targetPath)
2473	if !isRel {
2474		ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
2475		return ""
2476	}
2477	return rel
2478}
2479
2480// MaybeRel performs the same function as filepath.Rel, but reports errors to a PathContext, and returns false if
2481// targetPath is not inside basePath.
2482func MaybeRel(ctx PathContext, basePath string, targetPath string) (string, bool) {
2483	rel, isRel, err := maybeRelErr(basePath, targetPath)
2484	if err != nil {
2485		reportPathError(ctx, err)
2486	}
2487	return rel, isRel
2488}
2489
2490func maybeRelErr(basePath string, targetPath string) (string, bool, error) {
2491	// filepath.Rel returns an error if one path is absolute and the other is not, handle that case first.
2492	if filepath.IsAbs(basePath) != filepath.IsAbs(targetPath) {
2493		return "", false, nil
2494	}
2495	rel, err := filepath.Rel(basePath, targetPath)
2496	if err != nil {
2497		return "", false, err
2498	} else if rel == ".." || strings.HasPrefix(rel, "../") || strings.HasPrefix(rel, "/") {
2499		return "", false, nil
2500	}
2501	return rel, true, nil
2502}
2503
2504// Writes a file to the output directory.  Attempting to write directly to the output directory
2505// will fail due to the sandbox of the soong_build process.
2506// Only writes the file if the file doesn't exist or if it has different contents, to prevent
2507// updating the timestamp if no changes would be made. (This is better for incremental
2508// performance.)
2509func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error {
2510	absPath := absolutePath(path.String())
2511	err := os.MkdirAll(filepath.Dir(absPath), 0777)
2512	if err != nil {
2513		return err
2514	}
2515	return pathtools.WriteFileIfChanged(absPath, data, perm)
2516}
2517
2518func RemoveAllOutputDir(path WritablePath) error {
2519	return os.RemoveAll(absolutePath(path.String()))
2520}
2521
2522func CreateOutputDirIfNonexistent(path WritablePath, perm os.FileMode) error {
2523	dir := absolutePath(path.String())
2524	return createDirIfNonexistent(dir, perm)
2525}
2526
2527func createDirIfNonexistent(dir string, perm os.FileMode) error {
2528	if _, err := os.Stat(dir); os.IsNotExist(err) {
2529		return os.MkdirAll(dir, os.ModePerm)
2530	} else {
2531		return err
2532	}
2533}
2534
2535// absolutePath is deliberately private so that Soong's Go plugins can't use it to find and
2536// read arbitrary files without going through the methods in the current package that track
2537// dependencies.
2538func absolutePath(path string) string {
2539	if filepath.IsAbs(path) {
2540		return path
2541	}
2542	return filepath.Join(absSrcDir, path)
2543}
2544
2545// A DataPath represents the path of a file to be used as data, for example
2546// a test library to be installed alongside a test.
2547// The data file should be installed (copied from `<SrcPath>`) to
2548// `<install_root>/<RelativeInstallPath>/<filename>`, or
2549// `<install_root>/<filename>` if RelativeInstallPath is empty.
2550type DataPath struct {
2551	// The path of the data file that should be copied into the data directory
2552	SrcPath Path
2553	// The install path of the data file, relative to the install root.
2554	RelativeInstallPath string
2555	// If WithoutRel is true, use SrcPath.Base() instead of SrcPath.Rel() as the filename.
2556	WithoutRel bool
2557}
2558
2559func (d *DataPath) ToRelativeInstallPath() string {
2560	relPath := d.SrcPath.Rel()
2561	if d.WithoutRel {
2562		relPath = d.SrcPath.Base()
2563	}
2564	if d.RelativeInstallPath != "" {
2565		relPath = filepath.Join(d.RelativeInstallPath, relPath)
2566	}
2567	return relPath
2568}
2569
2570// PathsIfNonNil returns a Paths containing only the non-nil input arguments.
2571func PathsIfNonNil(paths ...Path) Paths {
2572	if len(paths) == 0 {
2573		// Fast path for empty argument list
2574		return nil
2575	} else if len(paths) == 1 {
2576		// Fast path for a single argument
2577		if paths[0] != nil {
2578			return paths
2579		} else {
2580			return nil
2581		}
2582	}
2583	ret := make(Paths, 0, len(paths))
2584	for _, path := range paths {
2585		if path != nil {
2586			ret = append(ret, path)
2587		}
2588	}
2589	if len(ret) == 0 {
2590		return nil
2591	}
2592	return ret
2593}
2594
2595var thirdPartyDirPrefixExceptions = []*regexp.Regexp{
2596	regexp.MustCompile("^vendor/[^/]*google[^/]*/"),
2597	regexp.MustCompile("^hardware/google/"),
2598	regexp.MustCompile("^hardware/interfaces/"),
2599	regexp.MustCompile("^hardware/libhardware[^/]*/"),
2600	regexp.MustCompile("^hardware/ril/"),
2601}
2602
2603func IsThirdPartyPath(path string) bool {
2604	thirdPartyDirPrefixes := []string{"external/", "vendor/", "hardware/"}
2605
2606	if HasAnyPrefix(path, thirdPartyDirPrefixes) {
2607		for _, prefix := range thirdPartyDirPrefixExceptions {
2608			if prefix.MatchString(path) {
2609				return false
2610			}
2611		}
2612		return true
2613	}
2614	return false
2615}
2616
2617// ToRelativeSourcePath converts absolute source path to the path relative to the source root.
2618// This throws an error if the input path is outside of the source root and cannot be converted
2619// to the relative path.
2620// This should be rarely used given that the source path is relative in Soong.
2621func ToRelativeSourcePath(ctx PathContext, path string) string {
2622	ret := path
2623	if filepath.IsAbs(path) {
2624		relPath, err := filepath.Rel(absSrcDir, path)
2625		if err != nil || strings.HasPrefix(relPath, "..") {
2626			ReportPathErrorf(ctx, "%s is outside of the source root", path)
2627		}
2628		ret = relPath
2629	}
2630	return ret
2631}
2632