|  | // Copyright 2015 Google Inc. All rights reserved. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | package android | 
|  |  | 
|  | import ( | 
|  | "fmt" | 
|  | "github.com/google/blueprint" | 
|  | "github.com/google/blueprint/proptools" | 
|  | "path" | 
|  | "path/filepath" | 
|  | "strings" | 
|  | ) | 
|  |  | 
|  | // BuildParameters describes the set of potential parameters to build a Ninja rule. | 
|  | // In general, these correspond to a Ninja concept. | 
|  | type BuildParams struct { | 
|  | // A Ninja Rule that will be written to the Ninja file. This allows factoring out common code | 
|  | // among multiple modules to reduce repetition in the Ninja file of action requirements. A rule | 
|  | // can contain variables that should be provided in Args. | 
|  | Rule blueprint.Rule | 
|  | // Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles | 
|  | // are used. | 
|  | Deps blueprint.Deps | 
|  | // Depfile is a writeable path that allows correct incremental builds when the inputs have not | 
|  | // been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax. | 
|  | Depfile WritablePath | 
|  | // A description of the build action. | 
|  | Description string | 
|  | // Output is an output file of the action. When using this field, references to $out in the Ninja | 
|  | // command will refer to this file. | 
|  | Output WritablePath | 
|  | // Outputs is a slice of output file of the action. When using this field, references to $out in | 
|  | // the Ninja command will refer to these files. | 
|  | Outputs WritablePaths | 
|  | // SymlinkOutput is an output file specifically that is a symlink. | 
|  | SymlinkOutput WritablePath | 
|  | // SymlinkOutputs is a slice of output files specifically that is a symlink. | 
|  | SymlinkOutputs WritablePaths | 
|  | // ImplicitOutput is an output file generated by the action. Note: references to `$out` in the | 
|  | // Ninja command will NOT include references to this file. | 
|  | ImplicitOutput WritablePath | 
|  | // ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out` | 
|  | // in the Ninja command will NOT include references to these files. | 
|  | ImplicitOutputs WritablePaths | 
|  | // Input is an input file to the Ninja action. When using this field, references to $in in the | 
|  | // Ninja command will refer to this file. | 
|  | Input Path | 
|  | // Inputs is a slice of input files to the Ninja action. When using this field, references to $in | 
|  | // in the Ninja command will refer to these files. | 
|  | Inputs Paths | 
|  | // Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command | 
|  | // will NOT include references to this file. | 
|  | Implicit Path | 
|  | // Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja | 
|  | // command will NOT include references to these files. | 
|  | Implicits Paths | 
|  | // OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is | 
|  | // not rebuilt until they are built, but changes in order-only dependencies alone do not cause the | 
|  | // output to be rebuilt. | 
|  | OrderOnly Paths | 
|  | // Validation is an output path for a validation action. Validation outputs imply lower | 
|  | // non-blocking priority to building non-validation outputs. | 
|  | Validation Path | 
|  | // Validations is a slice of output path for a validation action. Validation outputs imply lower | 
|  | // non-blocking priority to building non-validation outputs. | 
|  | Validations Paths | 
|  | // Whether to skip outputting a default target statement which will be built by Ninja when no | 
|  | // targets are specified on Ninja's command line. | 
|  | Default bool | 
|  | // Args is a key value mapping for replacements of variables within the Rule | 
|  | Args map[string]string | 
|  | } | 
|  |  | 
|  | type ModuleBuildParams BuildParams | 
|  |  | 
|  | type ModuleContext interface { | 
|  | BaseModuleContext | 
|  |  | 
|  | blueprintModuleContext() blueprint.ModuleContext | 
|  |  | 
|  | // Deprecated: use ModuleContext.Build instead. | 
|  | ModuleBuild(pctx PackageContext, params ModuleBuildParams) | 
|  |  | 
|  | // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must | 
|  | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
|  | // | 
|  | // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. | 
|  | ExpandSources(srcFiles, excludes []string) Paths | 
|  |  | 
|  | // Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must | 
|  | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
|  | // | 
|  | // Deprecated: use PathForModuleSrc instead. | 
|  | ExpandSource(srcFile, prop string) Path | 
|  |  | 
|  | ExpandOptionalSource(srcFile *string, prop string) OptionalPath | 
|  |  | 
|  | // InstallExecutable creates a rule to copy srcPath to name in the installPath directory, | 
|  | // with the given additional dependencies.  The file is marked executable after copying. | 
|  | // | 
|  | // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
|  | // installed file will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath | 
|  |  | 
|  | // InstallFile creates a rule to copy srcPath to name in the installPath directory, | 
|  | // with the given additional dependencies. | 
|  | // | 
|  | // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
|  | // installed file will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | InstallFile(installPath InstallPath, name string, srcPath Path, deps ...InstallPath) InstallPath | 
|  |  | 
|  | // InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath | 
|  | // directory, and also unzip a zip file containing extra files to install into the same | 
|  | // directory. | 
|  | // | 
|  | // The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
|  | // installed file will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...InstallPath) InstallPath | 
|  |  | 
|  | // InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath | 
|  | // directory. | 
|  | // | 
|  | // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the | 
|  | // installed file will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath | 
|  |  | 
|  | // InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name | 
|  | // in the installPath directory. | 
|  | // | 
|  | // The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the | 
|  | // installed file will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath | 
|  |  | 
|  | // PackageFile creates a PackagingSpec as if InstallFile was called, but without creating | 
|  | // the rule to copy the file.  This is useful to define how a module would be packaged | 
|  | // without installing it into the global installation directories. | 
|  | // | 
|  | // The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by | 
|  | // TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
|  | // for which IsInstallDepNeeded returns true. | 
|  | PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec | 
|  |  | 
|  | CheckbuildFile(srcPath Path) | 
|  |  | 
|  | InstallInData() bool | 
|  | InstallInTestcases() bool | 
|  | InstallInSanitizerDir() bool | 
|  | InstallInRamdisk() bool | 
|  | InstallInVendorRamdisk() bool | 
|  | InstallInDebugRamdisk() bool | 
|  | InstallInRecovery() bool | 
|  | InstallInRoot() bool | 
|  | InstallInVendor() bool | 
|  | InstallForceOS() (*OsType, *ArchType) | 
|  |  | 
|  | RequiredModuleNames() []string | 
|  | HostRequiredModuleNames() []string | 
|  | TargetRequiredModuleNames() []string | 
|  |  | 
|  | ModuleSubDir() string | 
|  | SoongConfigTraceHash() string | 
|  |  | 
|  | Variable(pctx PackageContext, name, value string) | 
|  | Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule | 
|  | // Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string, | 
|  | // and performs more verification. | 
|  | Build(pctx PackageContext, params BuildParams) | 
|  | // Phony creates a Make-style phony rule, a rule with no commands that can depend on other | 
|  | // phony rules or real files.  Phony can be called on the same name multiple times to add | 
|  | // additional dependencies. | 
|  | Phony(phony string, deps ...Path) | 
|  |  | 
|  | // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, | 
|  | // but do not exist. | 
|  | GetMissingDependencies() []string | 
|  |  | 
|  | // LicenseMetadataFile returns the path where the license metadata for this module will be | 
|  | // generated. | 
|  | LicenseMetadataFile() Path | 
|  | } | 
|  |  | 
|  | type moduleContext struct { | 
|  | bp blueprint.ModuleContext | 
|  | baseModuleContext | 
|  | packagingSpecs  []PackagingSpec | 
|  | installFiles    InstallPaths | 
|  | checkbuildFiles Paths | 
|  | module          Module | 
|  | phonies         map[string]Paths | 
|  |  | 
|  | katiInstalls []katiInstall | 
|  | katiSymlinks []katiInstall | 
|  |  | 
|  | // For tests | 
|  | buildParams []BuildParams | 
|  | ruleParams  map[blueprint.Rule]blueprint.RuleParams | 
|  | variables   map[string]string | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) { | 
|  | return pctx, BuildParams{ | 
|  | Rule:            ErrorRule, | 
|  | Description:     params.Description, | 
|  | Output:          params.Output, | 
|  | Outputs:         params.Outputs, | 
|  | ImplicitOutput:  params.ImplicitOutput, | 
|  | ImplicitOutputs: params.ImplicitOutputs, | 
|  | Args: map[string]string{ | 
|  | "error": err.Error(), | 
|  | }, | 
|  | } | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) { | 
|  | m.Build(pctx, BuildParams(params)) | 
|  | } | 
|  |  | 
|  | func validateBuildParams(params blueprint.BuildParams) error { | 
|  | // Validate that the symlink outputs are declared outputs or implicit outputs | 
|  | allOutputs := map[string]bool{} | 
|  | for _, output := range params.Outputs { | 
|  | allOutputs[output] = true | 
|  | } | 
|  | for _, output := range params.ImplicitOutputs { | 
|  | allOutputs[output] = true | 
|  | } | 
|  | for _, symlinkOutput := range params.SymlinkOutputs { | 
|  | if !allOutputs[symlinkOutput] { | 
|  | return fmt.Errorf( | 
|  | "Symlink output %s is not a declared output or implicit output", | 
|  | symlinkOutput) | 
|  | } | 
|  | } | 
|  | return nil | 
|  | } | 
|  |  | 
|  | // Convert build parameters from their concrete Android types into their string representations, | 
|  | // and combine the singular and plural fields of the same type (e.g. Output and Outputs). | 
|  | func convertBuildParams(params BuildParams) blueprint.BuildParams { | 
|  | bparams := blueprint.BuildParams{ | 
|  | Rule:            params.Rule, | 
|  | Description:     params.Description, | 
|  | Deps:            params.Deps, | 
|  | Outputs:         params.Outputs.Strings(), | 
|  | ImplicitOutputs: params.ImplicitOutputs.Strings(), | 
|  | SymlinkOutputs:  params.SymlinkOutputs.Strings(), | 
|  | Inputs:          params.Inputs.Strings(), | 
|  | Implicits:       params.Implicits.Strings(), | 
|  | OrderOnly:       params.OrderOnly.Strings(), | 
|  | Validations:     params.Validations.Strings(), | 
|  | Args:            params.Args, | 
|  | Optional:        !params.Default, | 
|  | } | 
|  |  | 
|  | if params.Depfile != nil { | 
|  | bparams.Depfile = params.Depfile.String() | 
|  | } | 
|  | if params.Output != nil { | 
|  | bparams.Outputs = append(bparams.Outputs, params.Output.String()) | 
|  | } | 
|  | if params.SymlinkOutput != nil { | 
|  | bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String()) | 
|  | } | 
|  | if params.ImplicitOutput != nil { | 
|  | bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String()) | 
|  | } | 
|  | if params.Input != nil { | 
|  | bparams.Inputs = append(bparams.Inputs, params.Input.String()) | 
|  | } | 
|  | if params.Implicit != nil { | 
|  | bparams.Implicits = append(bparams.Implicits, params.Implicit.String()) | 
|  | } | 
|  | if params.Validation != nil { | 
|  | bparams.Validations = append(bparams.Validations, params.Validation.String()) | 
|  | } | 
|  |  | 
|  | bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs) | 
|  | bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs) | 
|  | bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs) | 
|  | bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs) | 
|  | bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits) | 
|  | bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly) | 
|  | bparams.Validations = proptools.NinjaEscapeList(bparams.Validations) | 
|  | bparams.Depfile = proptools.NinjaEscape(bparams.Depfile) | 
|  |  | 
|  | return bparams | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) Variable(pctx PackageContext, name, value string) { | 
|  | if m.config.captureBuild { | 
|  | m.variables[name] = value | 
|  | } | 
|  |  | 
|  | m.bp.Variable(pctx.PackageContext, name, value) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, | 
|  | argNames ...string) blueprint.Rule { | 
|  |  | 
|  | if m.config.UseRemoteBuild() { | 
|  | if params.Pool == nil { | 
|  | // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict | 
|  | // jobs to the local parallelism value | 
|  | params.Pool = localPool | 
|  | } else if params.Pool == remotePool { | 
|  | // remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's | 
|  | // pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS | 
|  | // parallelism. | 
|  | params.Pool = nil | 
|  | } | 
|  | } | 
|  |  | 
|  | rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) | 
|  |  | 
|  | if m.config.captureBuild { | 
|  | m.ruleParams[rule] = params | 
|  | } | 
|  |  | 
|  | return rule | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { | 
|  | if params.Description != "" { | 
|  | params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" | 
|  | } | 
|  |  | 
|  | if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { | 
|  | pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n", | 
|  | m.ModuleName(), strings.Join(missingDeps, ", "))) | 
|  | } | 
|  |  | 
|  | if m.config.captureBuild { | 
|  | m.buildParams = append(m.buildParams, params) | 
|  | } | 
|  |  | 
|  | bparams := convertBuildParams(params) | 
|  | err := validateBuildParams(bparams) | 
|  | if err != nil { | 
|  | m.ModuleErrorf( | 
|  | "%s: build parameter validation failed: %s", | 
|  | m.ModuleName(), | 
|  | err.Error()) | 
|  | } | 
|  | m.bp.Build(pctx.PackageContext, bparams) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) Phony(name string, deps ...Path) { | 
|  | addPhony(m.config, name, deps...) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) GetMissingDependencies() []string { | 
|  | var missingDeps []string | 
|  | missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) | 
|  | missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...) | 
|  | missingDeps = FirstUniqueStrings(missingDeps) | 
|  | return missingDeps | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { | 
|  | module, _ := m.getDirectDepInternal(name, tag) | 
|  | return module | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) ModuleSubDir() string { | 
|  | return m.bp.ModuleSubDir() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) SoongConfigTraceHash() string { | 
|  | return m.module.base().commonProperties.SoongConfigTraceHash | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInData() bool { | 
|  | return m.module.InstallInData() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInTestcases() bool { | 
|  | return m.module.InstallInTestcases() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInSanitizerDir() bool { | 
|  | return m.module.InstallInSanitizerDir() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInRamdisk() bool { | 
|  | return m.module.InstallInRamdisk() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInVendorRamdisk() bool { | 
|  | return m.module.InstallInVendorRamdisk() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInDebugRamdisk() bool { | 
|  | return m.module.InstallInDebugRamdisk() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInRecovery() bool { | 
|  | return m.module.InstallInRecovery() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInRoot() bool { | 
|  | return m.module.InstallInRoot() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { | 
|  | return m.module.InstallForceOS() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallInVendor() bool { | 
|  | return m.module.InstallInVendor() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) skipInstall() bool { | 
|  | if m.module.base().commonProperties.SkipInstall { | 
|  | return true | 
|  | } | 
|  |  | 
|  | if m.module.base().commonProperties.HideFromMake { | 
|  | return true | 
|  | } | 
|  |  | 
|  | // We'll need a solution for choosing which of modules with the same name in different | 
|  | // namespaces to install.  For now, reuse the list of namespaces exported to Make as the | 
|  | // list of namespaces to install in a Soong-only build. | 
|  | if !m.module.base().commonProperties.NamespaceExportedToMake { | 
|  | return true | 
|  | } | 
|  |  | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, | 
|  | deps ...InstallPath) InstallPath { | 
|  | return m.installFile(installPath, name, srcPath, deps, false, nil) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path, | 
|  | deps ...InstallPath) InstallPath { | 
|  | return m.installFile(installPath, name, srcPath, deps, true, nil) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, | 
|  | extraZip Path, deps ...InstallPath) InstallPath { | 
|  | return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{ | 
|  | zip: extraZip, | 
|  | dir: installPath, | 
|  | }) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec { | 
|  | fullInstallPath := installPath.Join(m, name) | 
|  | return m.packageFile(fullInstallPath, srcPath, false) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec { | 
|  | licenseFiles := m.Module().EffectiveLicenseFiles() | 
|  | spec := PackagingSpec{ | 
|  | relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
|  | srcPath:               srcPath, | 
|  | symlinkTarget:         "", | 
|  | executable:            executable, | 
|  | effectiveLicenseFiles: &licenseFiles, | 
|  | partition:             fullInstallPath.partition, | 
|  | } | 
|  | m.packagingSpecs = append(m.packagingSpecs, spec) | 
|  | return spec | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath, | 
|  | executable bool, extraZip *extraFilesZip) InstallPath { | 
|  |  | 
|  | fullInstallPath := installPath.Join(m, name) | 
|  | m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) | 
|  |  | 
|  | if !m.skipInstall() { | 
|  | deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList())...) | 
|  |  | 
|  | var implicitDeps, orderOnlyDeps Paths | 
|  |  | 
|  | if m.Host() { | 
|  | // Installed host modules might be used during the build, depend directly on their | 
|  | // dependencies so their timestamp is updated whenever their dependency is updated | 
|  | implicitDeps = InstallPaths(deps).Paths() | 
|  | } else { | 
|  | orderOnlyDeps = InstallPaths(deps).Paths() | 
|  | } | 
|  |  | 
|  | if m.Config().KatiEnabled() { | 
|  | // When creating the install rule in Soong but embedding in Make, write the rule to a | 
|  | // makefile instead of directly to the ninja file so that main.mk can add the | 
|  | // dependencies from the `required` property that are hard to resolve in Soong. | 
|  | m.katiInstalls = append(m.katiInstalls, katiInstall{ | 
|  | from:          srcPath, | 
|  | to:            fullInstallPath, | 
|  | implicitDeps:  implicitDeps, | 
|  | orderOnlyDeps: orderOnlyDeps, | 
|  | executable:    executable, | 
|  | extraFiles:    extraZip, | 
|  | }) | 
|  | } else { | 
|  | rule := Cp | 
|  | if executable { | 
|  | rule = CpExecutable | 
|  | } | 
|  |  | 
|  | extraCmds := "" | 
|  | if extraZip != nil { | 
|  | extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )", | 
|  | extraZip.dir.String(), extraZip.zip.String()) | 
|  | extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )" | 
|  | implicitDeps = append(implicitDeps, extraZip.zip) | 
|  | } | 
|  |  | 
|  | m.Build(pctx, BuildParams{ | 
|  | Rule:        rule, | 
|  | Description: "install " + fullInstallPath.Base(), | 
|  | Output:      fullInstallPath, | 
|  | Input:       srcPath, | 
|  | Implicits:   implicitDeps, | 
|  | OrderOnly:   orderOnlyDeps, | 
|  | Default:     !m.Config().KatiEnabled(), | 
|  | Args: map[string]string{ | 
|  | "extraCmds": extraCmds, | 
|  | }, | 
|  | }) | 
|  | } | 
|  |  | 
|  | m.installFiles = append(m.installFiles, fullInstallPath) | 
|  | } | 
|  |  | 
|  | m.packageFile(fullInstallPath, srcPath, executable) | 
|  |  | 
|  | m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
|  |  | 
|  | return fullInstallPath | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath { | 
|  | fullInstallPath := installPath.Join(m, name) | 
|  | m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true) | 
|  |  | 
|  | relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String()) | 
|  | if err != nil { | 
|  | panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err)) | 
|  | } | 
|  | if !m.skipInstall() { | 
|  |  | 
|  | if m.Config().KatiEnabled() { | 
|  | // When creating the symlink rule in Soong but embedding in Make, write the rule to a | 
|  | // makefile instead of directly to the ninja file so that main.mk can add the | 
|  | // dependencies from the `required` property that are hard to resolve in Soong. | 
|  | m.katiSymlinks = append(m.katiSymlinks, katiInstall{ | 
|  | from: srcPath, | 
|  | to:   fullInstallPath, | 
|  | }) | 
|  | } else { | 
|  | // The symlink doesn't need updating when the target is modified, but we sometimes | 
|  | // have a dependency on a symlink to a binary instead of to the binary directly, and | 
|  | // the mtime of the symlink must be updated when the binary is modified, so use a | 
|  | // normal dependency here instead of an order-only dependency. | 
|  | m.Build(pctx, BuildParams{ | 
|  | Rule:        Symlink, | 
|  | Description: "install symlink " + fullInstallPath.Base(), | 
|  | Output:      fullInstallPath, | 
|  | Input:       srcPath, | 
|  | Default:     !m.Config().KatiEnabled(), | 
|  | Args: map[string]string{ | 
|  | "fromPath": relPath, | 
|  | }, | 
|  | }) | 
|  | } | 
|  |  | 
|  | m.installFiles = append(m.installFiles, fullInstallPath) | 
|  | m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
|  | } | 
|  |  | 
|  | m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ | 
|  | relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
|  | srcPath:          nil, | 
|  | symlinkTarget:    relPath, | 
|  | executable:       false, | 
|  | partition:        fullInstallPath.partition, | 
|  | }) | 
|  |  | 
|  | return fullInstallPath | 
|  | } | 
|  |  | 
|  | // installPath/name -> absPath where absPath might be a path that is available only at runtime | 
|  | // (e.g. /apex/...) | 
|  | func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath { | 
|  | fullInstallPath := installPath.Join(m, name) | 
|  | m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) | 
|  |  | 
|  | if !m.skipInstall() { | 
|  | if m.Config().KatiEnabled() { | 
|  | // When creating the symlink rule in Soong but embedding in Make, write the rule to a | 
|  | // makefile instead of directly to the ninja file so that main.mk can add the | 
|  | // dependencies from the `required` property that are hard to resolve in Soong. | 
|  | m.katiSymlinks = append(m.katiSymlinks, katiInstall{ | 
|  | absFrom: absPath, | 
|  | to:      fullInstallPath, | 
|  | }) | 
|  | } else { | 
|  | m.Build(pctx, BuildParams{ | 
|  | Rule:        Symlink, | 
|  | Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath, | 
|  | Output:      fullInstallPath, | 
|  | Default:     !m.Config().KatiEnabled(), | 
|  | Args: map[string]string{ | 
|  | "fromPath": absPath, | 
|  | }, | 
|  | }) | 
|  | } | 
|  |  | 
|  | m.installFiles = append(m.installFiles, fullInstallPath) | 
|  | } | 
|  |  | 
|  | m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ | 
|  | relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
|  | srcPath:          nil, | 
|  | symlinkTarget:    absPath, | 
|  | executable:       false, | 
|  | partition:        fullInstallPath.partition, | 
|  | }) | 
|  |  | 
|  | return fullInstallPath | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) CheckbuildFile(srcPath Path) { | 
|  | m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { | 
|  | return m.bp | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) LicenseMetadataFile() Path { | 
|  | return m.module.base().licenseMetadataFile | 
|  | } | 
|  |  | 
|  | // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must | 
|  | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
|  | // | 
|  | // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. | 
|  | func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths { | 
|  | return PathsForModuleSrcExcludes(m, srcFiles, excludes) | 
|  | } | 
|  |  | 
|  | // Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must | 
|  | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
|  | // | 
|  | // Deprecated: use PathForModuleSrc instead. | 
|  | func (m *moduleContext) ExpandSource(srcFile, _ string) Path { | 
|  | return PathForModuleSrc(m, srcFile) | 
|  | } | 
|  |  | 
|  | // Returns an optional single path expanded from globs and modules referenced using ":module" syntax if | 
|  | // the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module | 
|  | // dependency resolution. | 
|  | func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath { | 
|  | if srcFile != nil { | 
|  | return OptionalPathForPath(PathForModuleSrc(m, *srcFile)) | 
|  | } | 
|  | return OptionalPath{} | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) RequiredModuleNames() []string { | 
|  | return m.module.RequiredModuleNames() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) HostRequiredModuleNames() []string { | 
|  | return m.module.HostRequiredModuleNames() | 
|  | } | 
|  |  | 
|  | func (m *moduleContext) TargetRequiredModuleNames() []string { | 
|  | return m.module.TargetRequiredModuleNames() | 
|  | } |