diff options
Diffstat (limited to 'android/module.go')
-rw-r--r-- | android/module.go | 1305 |
1 files changed, 1069 insertions, 236 deletions
diff --git a/android/module.go b/android/module.go index 880915377..ce7fd0ca0 100644 --- a/android/module.go +++ b/android/module.go @@ -15,10 +15,12 @@ package android import ( + "android/soong/bazel" "fmt" "os" "path" "path/filepath" + "regexp" "strings" "text/scanner" @@ -42,6 +44,8 @@ type BuildParams struct { Description string Output WritablePath Outputs WritablePaths + SymlinkOutput WritablePath + SymlinkOutputs WritablePaths ImplicitOutput WritablePath ImplicitOutputs WritablePaths Input Path @@ -49,6 +53,8 @@ type BuildParams struct { Implicit Path Implicits Paths OrderOnly Paths + Validation Path + Validations Paths Default bool Args map[string]string } @@ -58,18 +64,44 @@ type ModuleBuildParams BuildParams // EarlyModuleContext provides methods that can be called early, as soon as the properties have // been parsed into the module and before any mutators have run. type EarlyModuleContext interface { + // Module returns the current module as a Module. It should rarely be necessary, as the module already has a + // reference to itself. Module() Module + + // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when + // the module was created, but may have been modified by calls to BaseMutatorContext.Rename. ModuleName() string + + // ModuleDir returns the path to the directory that contains the definition of the module. ModuleDir() string + + // ModuleType returns the name of the module type that was used to create the module, as specified in + // RegisterModuleType. ModuleType() string + + // BlueprintFile returns the name of the blueprint file that contains the definition of this + // module. BlueprintsFile() string + // ContainsProperty returns true if the specified property name was set in the module definition. ContainsProperty(name string) bool + + // Errorf reports an error at the specified position of the module definition file. Errorf(pos scanner.Position, fmt string, args ...interface{}) + + // ModuleErrorf reports an error at the line number of the module type in the module definition. ModuleErrorf(fmt string, args ...interface{}) + + // PropertyErrorf reports an error at the line number of a property in the module definition. PropertyErrorf(property, fmt string, args ...interface{}) + + // Failed returns true if any errors have been reported. In most cases the module can continue with generating + // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error + // has prevented the module from creating necessary data it can return early when Failed returns true. Failed() bool + // AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest. The + // primary builder will be rerun whenever the specified files are modified. AddNinjaFileDeps(deps ...string) DeviceSpecific() bool @@ -94,6 +126,10 @@ type EarlyModuleContext interface { GlobFiles(globPattern string, excludes []string) Paths IsSymlink(path Path) bool Readlink(path Path) string + + // Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the + // default SimpleNameInterface if Context.SetNameInterface was not called. + Namespace() *Namespace } // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns @@ -103,31 +139,165 @@ type EarlyModuleContext interface { type BaseModuleContext interface { EarlyModuleContext + blueprintBaseModuleContext() blueprint.BaseModuleContext + + // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleName(m blueprint.Module) string + + // OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleDir(m blueprint.Module) string + + // OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) + + // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency + // on the module. When called inside a Visit* method with current module being visited, and there are multiple + // dependencies on the module being visited, it returns the dependency tag used for the current dependency. OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag + + // OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface + // passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. OtherModuleExists(name string) bool + + // OtherModuleDependencyVariantExists returns true if a module with the + // specified name and variant exists. The variant must match the given + // variations. It must also match all the non-local variations of the current + // module. In other words, it checks for the module that AddVariationDependencies + // would add a dependency on with the same arguments. + OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool + + // OtherModuleFarDependencyVariantExists returns true if a module with the + // specified name and variant exists. The variant must match the given + // variations, but not the non-local variations of the current module. In + // other words, it checks for the module that AddFarVariationDependencies + // would add a dependency on with the same arguments. + OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool + + // OtherModuleReverseDependencyVariantExists returns true if a module with the + // specified name exists with the same variations as the current module. In + // other words, it checks for the module that AddReverseDependency would add a + // dependency on with the same argument. + OtherModuleReverseDependencyVariantExists(name string) bool + + // OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information. + // It is intended for use inside the visit functions of Visit* and WalkDeps. OtherModuleType(m blueprint.Module) string + // OtherModuleProvider returns the value for a provider for the given module. If the value is + // not set it returns the zero value of the type of the provider, so the return value can always + // be type asserted to the type of the provider. The value returned may be a deep copy of the + // value originally passed to SetProvider. + OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} + + // OtherModuleHasProvider returns true if the provider for the given module has been set. + OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool + + // Provider returns the value for a provider for the current module. If the value is + // not set it returns the zero value of the type of the provider, so the return value can always + // be type asserted to the type of the provider. It panics if called before the appropriate + // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep + // copy of the value originally passed to SetProvider. + Provider(provider blueprint.ProviderKey) interface{} + + // HasProvider returns true if the provider for the current module has been set. + HasProvider(provider blueprint.ProviderKey) bool + + // SetProvider sets the value for a provider for the current module. It panics if not called + // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value + // is not of the appropriate type, or if the value has already been set. The value should not + // be modified after being passed to SetProvider. + SetProvider(provider blueprint.ProviderKey, value interface{}) + GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module + + // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if + // none exists. It panics if the dependency does not have the specified tag. It skips any + // dependencies that are not an android.Module. GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module + + // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified + // name, or nil if none exists. If there are multiple dependencies on the same module it returns + // the first DependencyTag. GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) + // VisitDirectDepsBlueprint calls visit for each direct dependency. If there are multiple + // direct dependencies on the same module visit will be called multiple times on that module + // and OtherModuleDependencyTag will return a different tag for each. + // + // The Module passed to the visit function should not be retained outside of the visit + // function, it may be invalidated by future mutators. VisitDirectDepsBlueprint(visit func(blueprint.Module)) + + // VisitDirectDeps calls visit for each direct dependency. If there are multiple + // direct dependencies on the same module visit will be called multiple times on that module + // and OtherModuleDependencyTag will return a different tag for each. It skips any + // dependencies that are not an android.Module. + // + // The Module passed to the visit function should not be retained outside of the visit + // function, it may be invalidated by future mutators. VisitDirectDeps(visit func(Module)) + VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) + + // VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit. If there are + // multiple direct dependencies on the same module pred and visit will be called multiple times on that module and + // OtherModuleDependencyTag will return a different tag for each. It skips any + // dependencies that are not an android.Module. + // + // The Module passed to the visit function should not be retained outside of the visit function, it may be + // invalidated by future mutators. VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module VisitDepsDepthFirst(visit func(Module)) // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) + + // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may + // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the + // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited + // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. It skips + // any dependencies that are not an android.Module. + // + // The Modules passed to the visit function should not be retained outside of the visit function, they may be + // invalidated by future mutators. WalkDeps(visit func(Module, Module) bool) + + // WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency + // tree in top down order. visit may be called multiple times for the same (child, parent) + // pair if there are multiple direct dependencies between the child and parent with different + // tags. OtherModuleDependencyTag will return the tag for the currently visited + // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down + // to child. + // + // The Modules passed to the visit function should not be retained outside of the visit function, they may be + // invalidated by future mutators. WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) + // GetWalkPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module + // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the + // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are + // only done once for all variants of a module. + PrimaryModule() Module + + // FinalModule returns the last variant of the current module. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all + // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform + // singleton actions that are only done once for all variants of a module. + FinalModule() Module + + // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always + // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read + // from all variants if the current module == FinalModule(). Otherwise, care must be taken to not access any + // data modified by the current mutator. + VisitAllModuleVariants(visit func(Module)) + // GetTagPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency tags path from a start module to current child module. // It has one less entry than GetWalkPath() as it contains the dependency tags that @@ -135,6 +305,13 @@ type BaseModuleContext interface { // GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] GetTagPath() []blueprint.DependencyTag + // GetPathString is supposed to be called in visit function passed in WalkDeps() + // and returns a multi-line string showing the modules and dependency tags + // among them along the top-down dependency path from a start module to current child module. + // skipFirst when set to true, the output doesn't include the start module, + // which is already printed when this function is used along with ModuleErrorf(). + GetPathString(skipFirst bool) string + AddMissingDependencies(missingDeps []string) Target() Target @@ -162,6 +339,8 @@ type BaseContext interface { type ModuleContext interface { BaseModuleContext + blueprintModuleContext() blueprint.ModuleContext + // Deprecated: use ModuleContext.Build instead. ModuleBuild(pctx PackageContext, params ModuleBuildParams) @@ -169,19 +348,63 @@ type ModuleContext interface { 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 ...Path) 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 ...Path) 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 InstallBypassMake() bool + InstallForceOS() (*OsType, *ArchType) RequiredModuleNames() []string HostRequiredModuleNames() []string @@ -199,12 +422,9 @@ type ModuleContext interface { // additional dependencies. Phony(phony string, deps ...Path) - PrimaryModule() Module - FinalModule() Module - VisitAllModuleVariants(visit func(Module)) - + // GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, + // but do not exist. GetMissingDependencies() []string - Namespace() blueprint.Namespace } type Module interface { @@ -215,28 +435,45 @@ type Module interface { // For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go GenerateAndroidBuildActions(ModuleContext) + // Add dependencies to the components of a module, i.e. modules that are created + // by the module and which are considered to be part of the creating module. + // + // This is called before prebuilts are renamed so as to allow a dependency to be + // added directly to a prebuilt child module instead of depending on a source module + // and relying on prebuilt processing to switch to the prebuilt module if preferred. + // + // A dependency on a prebuilt must include the "prebuilt_" prefix. + ComponentDepsMutator(ctx BottomUpMutatorContext) + DepsMutator(BottomUpMutatorContext) base() *ModuleBase Disable() Enabled() bool Target() Target + MultiTargets() []Target Owner() string InstallInData() bool InstallInTestcases() bool InstallInSanitizerDir() bool InstallInRamdisk() bool + InstallInVendorRamdisk() bool + InstallInDebugRamdisk() bool InstallInRecovery() bool InstallInRoot() bool InstallBypassMake() bool - SkipInstall() + InstallForceOS() (*OsType, *ArchType) + HideFromMake() + IsHideFromMake() bool IsSkipInstall() bool + MakeUninstallable() ReplacedByPrebuilt() IsReplacedByPrebuilt() bool ExportedToMake() bool InitRc() Paths VintfFragments() Paths - NoticeFile() OptionalPath + NoticeFiles() Paths + EffectiveLicenseFiles() Paths AddProperties(props ...interface{}) GetProperties() []interface{} @@ -257,6 +494,69 @@ type Module interface { RequiredModuleNames() []string HostRequiredModuleNames() []string TargetRequiredModuleNames() []string + + FilesToInstall() InstallPaths + PackagingSpecs() []PackagingSpec + + // TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive + // dependencies with dependency tags for which IsInstallDepNeeded() returns true. + TransitivePackagingSpecs() []PackagingSpec +} + +// BazelTargetModule is a lightweight wrapper interface around Module for +// bp2build conversion purposes. +// +// In bp2build's bootstrap.Main execution, Soong runs an alternate pipeline of +// mutators that creates BazelTargetModules from regular Module objects, +// performing the mapping from Soong properties to Bazel rule attributes in the +// process. This process may optionally create additional BazelTargetModules, +// resulting in a 1:many mapping. +// +// bp2build.Codegen is then responsible for visiting all modules in the graph, +// filtering for BazelTargetModules, and code-generating BUILD targets from +// them. +type BazelTargetModule interface { + Module + + bazelTargetModuleProperties() *bazel.BazelTargetModuleProperties + SetBazelTargetModuleProperties(props bazel.BazelTargetModuleProperties) + + RuleClass() string + BzlLoadLocation() string +} + +// InitBazelTargetModule is a wrapper function that decorates BazelTargetModule +// with property structs containing metadata for bp2build conversion. +func InitBazelTargetModule(module BazelTargetModule) { + module.AddProperties(module.bazelTargetModuleProperties()) + InitAndroidModule(module) +} + +// BazelTargetModuleBase contains the property structs with metadata for +// bp2build conversion. +type BazelTargetModuleBase struct { + ModuleBase + Properties bazel.BazelTargetModuleProperties +} + +// bazelTargetModuleProperties getter. +func (btmb *BazelTargetModuleBase) bazelTargetModuleProperties() *bazel.BazelTargetModuleProperties { + return &btmb.Properties +} + +// SetBazelTargetModuleProperties setter for BazelTargetModuleProperties +func (btmb *BazelTargetModuleBase) SetBazelTargetModuleProperties(props bazel.BazelTargetModuleProperties) { + btmb.Properties = props +} + +// RuleClass returns the rule class for this Bazel target +func (b *BazelTargetModuleBase) RuleClass() string { + return b.bazelTargetModuleProperties().Rule_class +} + +// BzlLoadLocation returns the rule class for this Bazel target +func (b *BazelTargetModuleBase) BzlLoadLocation() string { + return b.bazelTargetModuleProperties().Bzl_load_location } // Qualified id for a module @@ -302,6 +602,32 @@ func newPackageId(pkg string) qualifiedModuleName { return qualifiedModuleName{pkg: pkg, name: ""} } +type Dist struct { + // Copy the output of this module to the $DIST_DIR when `dist` is specified on the + // command line and any of these targets are also on the command line, or otherwise + // built + Targets []string `android:"arch_variant"` + + // The name of the output artifact. This defaults to the basename of the output of + // the module. + Dest *string `android:"arch_variant"` + + // The directory within the dist directory to store the artifact. Defaults to the + // top level directory (""). + Dir *string `android:"arch_variant"` + + // A suffix to add to the artifact file name (before any extension). + Suffix *string `android:"arch_variant"` + + // A string tag to select the OutputFiles associated with the tag. + // + // If no tag is specified then it will select the default dist paths provided + // by the module type. If a tag of "" is specified then it will return the + // default output files provided by the modules, i.e. the result of calling + // OutputFiles(""). + Tag *string `android:"arch_variant"` +} + type nameProperties struct { // The name of the module. Must be unique across all modules. Name *string @@ -362,13 +688,24 @@ type commonProperties struct { // more details. Visibility []string - // Names of the licenses that apply to this module. + // Describes the licenses applicable to this module. Must reference license modules. Licenses []string + // Flattened from direct license dependencies. Equal to Licenses unless particular module adds more. + Effective_licenses []string `blueprint:"mutated"` + // Override of module name when reporting licenses + Effective_package_name *string `blueprint:"mutated"` + // Notice files + Effective_license_text Paths `blueprint:"mutated"` + // License names + Effective_license_kinds []string `blueprint:"mutated"` + // License conditions + Effective_license_conditions []string `blueprint:"mutated"` + // control whether this module compiles for 32-bit, 64-bit, or both. Possible values // are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both // architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit - // platform + // platform). Compile_multilib *string `android:"arch_variant"` Target struct { @@ -423,11 +760,17 @@ type commonProperties struct { // Whether this module is installed to ramdisk Ramdisk *bool - // Whether this module is built for non-native architecures (also known as native bridge binary) + // Whether this module is installed to vendor ramdisk + Vendor_ramdisk *bool + + // Whether this module is installed to debug ramdisk + Debug_ramdisk *bool + + // Whether this module is built for non-native architectures (also known as native bridge binary) Native_bridge_supported *bool `android:"arch_variant"` // init.rc files to be installed if this module is installed - Init_rc []string `android:"path"` + Init_rc []string `android:"arch_variant,path"` // VINTF manifest fragments to be installed if this module is installed Vintf_fragments []string `android:"path"` @@ -444,24 +787,6 @@ type commonProperties struct { // relative path to a file to include in the list of notices for the device Notice *string `android:"path"` - Dist struct { - // copy the output of this module to the $DIST_DIR when `dist` is specified on the - // command line and any of these targets are also on the command line, or otherwise - // built - Targets []string `android:"arch_variant"` - - // The name of the output artifact. This defaults to the basename of the output of - // the module. - Dest *string `android:"arch_variant"` - - // The directory within the dist directory to store the artifact. Defaults to the - // top level directory (""). - Dir *string `android:"arch_variant"` - - // A suffix to add to the artifact file name (before any extension). - Suffix *string `android:"arch_variant"` - } `android:"arch_variant"` - // The OsType of artifacts that this module variant is responsible for creating. // // Set by osMutator @@ -512,6 +837,13 @@ type commonProperties struct { // Set by osMutator. CommonOSVariant bool `blueprint:"mutated"` + // When HideFromMake is set to true, no entry for this variant will be emitted in the + // generated Android.mk file. + HideFromMake bool `blueprint:"mutated"` + + // When SkipInstall is set to true, calls to ctx.InstallFile, ctx.InstallExecutable, + // ctx.InstallSymlink and ctx.InstallAbsoluteSymlink act like calls to ctx.PackageFile + // and don't create a rule to install the file. SkipInstall bool `blueprint:"mutated"` // Whether the module has been replaced by a prebuilt @@ -529,10 +861,72 @@ type commonProperties struct { DebugMutators []string `blueprint:"mutated"` DebugVariations []string `blueprint:"mutated"` - // set by ImageMutator + // ImageVariation is set by ImageMutator to specify which image this variation is for, + // for example "" for core or "recovery" for recovery. It will often be set to one of the + // constants in image.go, but can also be set to a custom value by individual module types. ImageVariation string `blueprint:"mutated"` } +type distProperties struct { + // configuration to distribute output files from this module to the distribution + // directory (default: $OUT/dist, configurable with $DIST_DIR) + Dist Dist `android:"arch_variant"` + + // a list of configurations to distribute output files from this module to the + // distribution directory (default: $OUT/dist, configurable with $DIST_DIR) + Dists []Dist `android:"arch_variant"` +} + +// The key to use in TaggedDistFiles when a Dist structure does not specify a +// tag property. This intentionally does not use "" as the default because that +// would mean that an empty tag would have a different meaning when used in a dist +// structure that when used to reference a specific set of output paths using the +// :module{tag} syntax, which passes tag to the OutputFiles(tag) method. +const DefaultDistTag = "<default-dist-tag>" + +// A map of OutputFile tag keys to Paths, for disting purposes. +type TaggedDistFiles map[string]Paths + +// addPathsForTag adds a mapping from the tag to the paths. If the map is nil +// then it will create a map, update it and then return it. If a mapping already +// exists for the tag then the paths are appended to the end of the current list +// of paths, ignoring any duplicates. +func (t TaggedDistFiles) addPathsForTag(tag string, paths ...Path) TaggedDistFiles { + if t == nil { + t = make(TaggedDistFiles) + } + + for _, distFile := range paths { + if distFile != nil && !t[tag].containsPath(distFile) { + t[tag] = append(t[tag], distFile) + } + } + + return t +} + +// merge merges the entries from the other TaggedDistFiles object into this one. +// If the TaggedDistFiles is nil then it will create a new instance, merge the +// other into it, and then return it. +func (t TaggedDistFiles) merge(other TaggedDistFiles) TaggedDistFiles { + for tag, paths := range other { + t = t.addPathsForTag(tag, paths...) + } + + return t +} + +func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles { + for _, path := range paths { + if path == nil { + panic("The path to a dist file cannot be nil.") + } + } + + // The default OutputFile tag is the empty "" string. + return TaggedDistFiles{DefaultDistTag: paths} +} + type hostAndDeviceProperties struct { // If set to true, build a variant of the module for the host. Defaults to false. Host_supported *bool @@ -554,27 +948,32 @@ const ( type HostOrDeviceSupported int const ( - _ HostOrDeviceSupported = iota + hostSupported = 1 << iota + hostCrossSupported + deviceSupported + hostDefault + deviceDefault // Host and HostCross are built by default. Device is not supported. - HostSupported + HostSupported = hostSupported | hostCrossSupported | hostDefault // Host is built by default. HostCross and Device are not supported. - HostSupportedNoCross + HostSupportedNoCross = hostSupported | hostDefault // Device is built by default. Host and HostCross are not supported. - DeviceSupported + DeviceSupported = deviceSupported | deviceDefault // Device is built by default. Host and HostCross are supported. - HostAndDeviceSupported + HostAndDeviceSupported = hostSupported | hostCrossSupported | deviceSupported | deviceDefault // Host, HostCross, and Device are built by default. - HostAndDeviceDefault + HostAndDeviceDefault = hostSupported | hostCrossSupported | hostDefault | + deviceSupported | deviceDefault // Nothing is supported. This is not exposed to the user, but used to mark a // host only module as unsupported when the module type is not supported on // the host OS. E.g. benchmarks are supported on Linux but not Darwin. - NeitherHostNorDeviceSupported + NeitherHostNorDeviceSupported = 0 ) type moduleKind int @@ -608,13 +1007,16 @@ func initAndroidModuleBase(m Module) { m.base().module = m } +// InitAndroidModule initializes the Module as an Android module that is not architecture-specific. +// It adds the common properties, for example "name" and "enabled". func InitAndroidModule(m Module) { initAndroidModuleBase(m) base := m.base() m.AddProperties( &base.nameProperties, - &base.commonProperties) + &base.commonProperties, + &base.distProperties) initProductVariableModule(m) @@ -624,8 +1026,18 @@ func InitAndroidModule(m Module) { // The default_visibility property needs to be checked and parsed by the visibility module during // its checking and parsing phases so make it the primary visibility property. setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility) + + // The default_applicable_licenses property needs to be checked and parsed by the licenses module during + // its checking and parsing phases so make it the primary licenses property. + setPrimaryLicensesProperty(m, "licenses", &base.commonProperties.Licenses) } +// InitAndroidArchModule initializes the Module as an Android module that is architecture-specific. +// It adds the common properties, for example "name" and "enabled", as well as runtime generated +// property structs for architecture-specific versions of generic properties tagged with +// `android:"arch_variant"`. +// +// InitAndroidModule should not be called if InitAndroidArchModule was called. func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { InitAndroidModule(m) @@ -635,21 +1047,37 @@ func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib base.commonProperties.ArchSpecific = true base.commonProperties.UseTargetVariants = true - switch hod { - case HostAndDeviceSupported, HostAndDeviceDefault: + if hod&hostSupported != 0 && hod&deviceSupported != 0 { m.AddProperties(&base.hostAndDeviceProperties) } - InitArchModule(m) + initArchModule(m) } +// InitAndroidMultiTargetsArchModule initializes the Module as an Android module that is +// architecture-specific, but will only have a single variant per OS that handles all the +// architectures simultaneously. The list of Targets that it must handle will be available from +// ModuleContext.MultiTargets. It adds the common properties, for example "name" and "enabled", as +// well as runtime generated property structs for architecture-specific versions of generic +// properties tagged with `android:"arch_variant"`. +// +// InitAndroidModule or InitAndroidArchModule should not be called if +// InitAndroidMultiTargetsArchModule was called. func InitAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { InitAndroidArchModule(m, hod, defaultMultilib) m.base().commonProperties.UseTargetVariants = false } -// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that -// has dependencies on all the OsType specific variants. +// InitCommonOSAndroidMultiTargetsArchModule initializes the Module as an Android module that is +// architecture-specific, but will only have a single variant per OS that handles all the +// architectures simultaneously, and will also have an additional CommonOS variant that has +// dependencies on all the OS-specific variants. The list of Targets that it must handle will be +// available from ModuleContext.MultiTargets. It adds the common properties, for example "name" and +// "enabled", as well as runtime generated property structs for architecture-specific versions of +// generic properties tagged with `android:"arch_variant"`. +// +// InitAndroidModule, InitAndroidArchModule or InitAndroidMultiTargetsArchModule should not be +// called if InitCommonOSAndroidMultiTargetsArchModule was called. func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { InitAndroidArchModule(m, hod, defaultMultilib) m.base().commonProperties.UseTargetVariants = false @@ -705,11 +1133,22 @@ type ModuleBase struct { nameProperties nameProperties commonProperties commonProperties + distProperties distProperties variableProperties interface{} hostAndDeviceProperties hostAndDeviceProperties generalProperties []interface{} - archProperties [][]interface{} - customizableProperties []interface{} + + // Arch specific versions of structs in generalProperties. The outer index + // has the same order as generalProperties as initialized in + // InitAndroidArchModule, and the inner index chooses the props specific to + // the architecture. The interface{} value is an archPropRoot that is + // filled with arch specific values by the arch mutator. + archProperties [][]interface{} + + customizableProperties []interface{} + + // Properties specific to the Blueprint to BUILD migration. + bazelTargetModuleProperties bazel.BazelTargetModuleProperties // Information about all the properties on the module that contains visibility rules that need // checking. @@ -718,11 +1157,20 @@ type ModuleBase struct { // The primary visibility property, may be nil, that controls access to the module. primaryVisibilityProperty visibilityProperty - noAddressSanitizer bool - installFiles Paths - checkbuildFiles Paths - noticeFile OptionalPath - phonies map[string]Paths + // The primary licenses property, may be nil, records license metadata for the module. + primaryLicensesProperty applicableLicensesProperty + + noAddressSanitizer bool + installFiles InstallPaths + installFilesDepSet *installPathsDepSet + checkbuildFiles Paths + packagingSpecs []PackagingSpec + packagingSpecsDepSet *packagingSpecsDepSet + noticeFiles Paths + phonies map[string]Paths + + // The files to copy to the dist as explicitly specified in the .bp file. + distFiles TaggedDistFiles // Used by buildTargetSingleton to create checkbuild and per-directory build targets // Only set on the final variant of each module @@ -741,10 +1189,10 @@ type ModuleBase struct { initRcPaths Paths vintfFragmentsPaths Paths - - prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool } +func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {} + func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {} func (m *ModuleBase) AddProperties(props ...interface{}) { @@ -767,10 +1215,6 @@ func (m *ModuleBase) VariablesForTests() map[string]string { return m.variables } -func (m *ModuleBase) Prefer32(prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool) { - m.prefer32 = prefer32 -} - // Name returns the name of the module. It may be overridden by individual module types, for // example prebuilts will prepend prebuilt_ to the name. func (m *ModuleBase) Name() string { @@ -811,6 +1255,48 @@ func (m *ModuleBase) visibilityProperties() []visibilityProperty { return m.visibilityPropertyInfo } +func (m *ModuleBase) Dists() []Dist { + if len(m.distProperties.Dist.Targets) > 0 { + // Make a copy of the underlying Dists slice to protect against + // backing array modifications with repeated calls to this method. + distsCopy := append([]Dist(nil), m.distProperties.Dists...) + return append(distsCopy, m.distProperties.Dist) + } else { + return m.distProperties.Dists + } +} + +func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles { + var distFiles TaggedDistFiles + for _, dist := range m.Dists() { + // If no tag is specified then it means to use the default dist paths so use + // the special tag name which represents that. + tag := proptools.StringDefault(dist.Tag, DefaultDistTag) + + if outputFileProducer, ok := m.module.(OutputFileProducer); ok { + // Call the OutputFiles(tag) method to get the paths associated with the tag. + distFilesForTag, err := outputFileProducer.OutputFiles(tag) + + // If the tag was not supported and is not DefaultDistTag then it is an error. + // Failing to find paths for DefaultDistTag is not an error. It just means + // that the module type requires the legacy behavior. + if err != nil && tag != DefaultDistTag { + ctx.PropertyErrorf("dist.tag", "%s", err.Error()) + } + + distFiles = distFiles.addPathsForTag(tag, distFilesForTag...) + } else if tag != DefaultDistTag { + // If the tag was specified then it is an error if the module does not + // implement OutputFileProducer because there is no other way of accessing + // the paths for the specified tag. + ctx.PropertyErrorf("dist.tag", + "tag %s not supported because the module does not implement OutputFileProducer", tag) + } + } + + return distFiles +} + func (m *ModuleBase) Target() Target { return m.commonProperties.CompileTarget } @@ -828,7 +1314,7 @@ func (m *ModuleBase) Os() OsType { } func (m *ModuleBase) Host() bool { - return m.Os().Class == Host || m.Os().Class == HostCross + return m.Os().Class == Host } func (m *ModuleBase) Device() bool { @@ -848,43 +1334,54 @@ func (m *ModuleBase) IsCommonOSVariant() bool { return m.commonProperties.CommonOSVariant } -func (m *ModuleBase) OsClassSupported() []OsClass { - switch m.commonProperties.HostOrDeviceSupported { - case HostSupported: - return []OsClass{Host, HostCross} - case HostSupportedNoCross: - return []OsClass{Host} - case DeviceSupported: - return []OsClass{Device} - case HostAndDeviceSupported, HostAndDeviceDefault: - var supported []OsClass - if Bool(m.hostAndDeviceProperties.Host_supported) || - (m.commonProperties.HostOrDeviceSupported == HostAndDeviceDefault && - m.hostAndDeviceProperties.Host_supported == nil) { - supported = append(supported, Host, HostCross) - } - if m.hostAndDeviceProperties.Device_supported == nil || - *m.hostAndDeviceProperties.Device_supported { - supported = append(supported, Device) +// supportsTarget returns true if the given Target is supported by the current module. +func (m *ModuleBase) supportsTarget(target Target) bool { + switch target.Os.Class { + case Host: + if target.HostCross { + return m.HostCrossSupported() + } else { + return m.HostSupported() } - return supported + case Device: + return m.DeviceSupported() default: - return nil + return false } } +// DeviceSupported returns true if the current module is supported and enabled for device targets, +// i.e. the factory method set the HostOrDeviceSupported value to include device support and +// the device support is enabled by default or enabled by the device_supported property. func (m *ModuleBase) DeviceSupported() bool { - return m.commonProperties.HostOrDeviceSupported == DeviceSupported || - m.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported && - (m.hostAndDeviceProperties.Device_supported == nil || - *m.hostAndDeviceProperties.Device_supported) + hod := m.commonProperties.HostOrDeviceSupported + // deviceEnabled is true if the device_supported property is true or the HostOrDeviceSupported + // value has the deviceDefault bit set. + deviceEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Device_supported, hod&deviceDefault != 0) + return hod&deviceSupported != 0 && deviceEnabled } +// HostSupported returns true if the current module is supported and enabled for host targets, +// i.e. the factory method set the HostOrDeviceSupported value to include host support and +// the host support is enabled by default or enabled by the host_supported property. func (m *ModuleBase) HostSupported() bool { - return m.commonProperties.HostOrDeviceSupported == HostSupported || - m.commonProperties.HostOrDeviceSupported == HostAndDeviceSupported && - (m.hostAndDeviceProperties.Host_supported != nil && - *m.hostAndDeviceProperties.Host_supported) + hod := m.commonProperties.HostOrDeviceSupported + // hostEnabled is true if the host_supported property is true or the HostOrDeviceSupported + // value has the hostDefault bit set. + hostEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Host_supported, hod&hostDefault != 0) + return hod&hostSupported != 0 && hostEnabled +} + +// HostCrossSupported returns true if the current module is supported and enabled for host cross +// targets, i.e. the factory method set the HostOrDeviceSupported value to include host cross +// support and the host cross support is enabled by default or enabled by the +// host_supported property. +func (m *ModuleBase) HostCrossSupported() bool { + hod := m.commonProperties.HostOrDeviceSupported + // hostEnabled is true if the host_supported property is true or the HostOrDeviceSupported + // value has the hostDefault bit set. + hostEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Host_supported, hod&hostDefault != 0) + return hod&hostCrossSupported != 0 && hostEnabled } func (m *ModuleBase) Platform() bool { @@ -962,17 +1459,39 @@ func (m *ModuleBase) Disable() { m.commonProperties.ForcedDisabled = true } +// HideFromMake marks this variant so that it is not emitted in the generated Android.mk file. +func (m *ModuleBase) HideFromMake() { + m.commonProperties.HideFromMake = true +} + +// IsHideFromMake returns true if HideFromMake was previously called. +func (m *ModuleBase) IsHideFromMake() bool { + return m.commonProperties.HideFromMake == true +} + +// SkipInstall marks this variant to not create install rules when ctx.Install* are called. func (m *ModuleBase) SkipInstall() { m.commonProperties.SkipInstall = true } +// IsSkipInstall returns true if this variant is marked to not create install +// rules when ctx.Install* are called. func (m *ModuleBase) IsSkipInstall() bool { - return m.commonProperties.SkipInstall == true + return m.commonProperties.SkipInstall +} + +// Similar to HideFromMake, but if the AndroidMk entry would set +// LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry +// rather than leaving it out altogether. That happens in cases where it would +// have other side effects, in particular when it adds a NOTICE file target, +// which other install targets might depend on. +func (m *ModuleBase) MakeUninstallable() { + m.HideFromMake() } func (m *ModuleBase) ReplacedByPrebuilt() { m.commonProperties.ReplacedByPrebuilt = true - m.SkipInstall() + m.HideFromMake() } func (m *ModuleBase) IsReplacedByPrebuilt() bool { @@ -983,25 +1502,37 @@ func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } -func (m *ModuleBase) computeInstallDeps( - ctx blueprint.ModuleContext) Paths { +func (m *ModuleBase) EffectiveLicenseFiles() Paths { + return m.commonProperties.Effective_license_text +} - result := Paths{} - // TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation - ctx.VisitDepsDepthFirstIf(isFileInstaller, - func(m blueprint.Module) { - fileInstaller := m.(fileInstaller) - files := fileInstaller.filesToInstall() - result = append(result, files...) - }) +// computeInstallDeps finds the installed paths of all dependencies that have a dependency +// tag that is annotated as needing installation via the IsInstallDepNeeded method. +func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*installPathsDepSet, []*packagingSpecsDepSet) { + var installDeps []*installPathsDepSet + var packagingSpecs []*packagingSpecsDepSet + ctx.VisitDirectDeps(func(dep Module) { + if IsInstallDepNeeded(ctx.OtherModuleDependencyTag(dep)) && !dep.IsHideFromMake() { + installDeps = append(installDeps, dep.base().installFilesDepSet) + packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet) + } + }) - return result + return installDeps, packagingSpecs } -func (m *ModuleBase) filesToInstall() Paths { +func (m *ModuleBase) FilesToInstall() InstallPaths { return m.installFiles } +func (m *ModuleBase) PackagingSpecs() []PackagingSpec { + return m.packagingSpecs +} + +func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec { + return m.packagingSpecsDepSet.ToList() +} + func (m *ModuleBase) NoAddressSanitizer() bool { return m.noAddressSanitizer } @@ -1022,6 +1553,14 @@ func (m *ModuleBase) InstallInRamdisk() bool { return Bool(m.commonProperties.Ramdisk) } +func (m *ModuleBase) InstallInVendorRamdisk() bool { + return Bool(m.commonProperties.Vendor_ramdisk) +} + +func (m *ModuleBase) InstallInDebugRamdisk() bool { + return Bool(m.commonProperties.Debug_ramdisk) +} + func (m *ModuleBase) InstallInRecovery() bool { return Bool(m.commonProperties.Recovery) } @@ -1034,12 +1573,16 @@ func (m *ModuleBase) InstallBypassMake() bool { return false } +func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) { + return nil, nil +} + func (m *ModuleBase) Owner() string { return String(m.commonProperties.Owner) } -func (m *ModuleBase) NoticeFile() OptionalPath { - return m.noticeFile +func (m *ModuleBase) NoticeFiles() Paths { + return m.noticeFiles } func (m *ModuleBase) setImageVariation(variant string) { @@ -1067,6 +1610,14 @@ func (m *ModuleBase) InRamdisk() bool { return m.base().commonProperties.ImageVariation == RamdiskVariation } +func (m *ModuleBase) InVendorRamdisk() bool { + return m.base().commonProperties.ImageVariation == VendorRamdiskVariation +} + +func (m *ModuleBase) InDebugRamdisk() bool { + return m.base().commonProperties.ImageVariation == DebugRamdiskVariation +} + func (m *ModuleBase) InRecovery() bool { return m.base().commonProperties.ImageVariation == RecoveryVariation } @@ -1092,8 +1643,8 @@ func (m *ModuleBase) VintfFragments() Paths { } func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { - allInstalledFiles := Paths{} - allCheckbuildFiles := Paths{} + var allInstalledFiles InstallPaths + var allCheckbuildFiles Paths ctx.VisitAllModuleVariants(func(module Module) { a := module.base() allInstalledFiles = append(allInstalledFiles, a.installFiles...) @@ -1102,14 +1653,14 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { var deps Paths - namespacePrefix := ctx.Namespace().(*Namespace).id + namespacePrefix := ctx.Namespace().id if namespacePrefix != "" { namespacePrefix = namespacePrefix + "-" } if len(allInstalledFiles) > 0 { name := namespacePrefix + ctx.ModuleName() + "-install" - ctx.Phony(name, allInstalledFiles...) + ctx.Phony(name, allInstalledFiles.Paths()...) m.installTarget = PathForPhony(ctx, name) deps = append(deps, m.installTarget) } @@ -1123,7 +1674,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { if len(deps) > 0 { suffix := "" - if ctx.Config().EmbeddedInMake() { + if ctx.Config().KatiEnabled() { suffix = "-soong" } @@ -1216,11 +1767,15 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) module: m.module, bp: blueprintCtx, baseModuleContext: m.baseModuleContextFactory(blueprintCtx), - installDeps: m.computeInstallDeps(blueprintCtx), - installFiles: m.installFiles, variables: make(map[string]string), } + dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx) + // set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies + // of installed files of this module. It will be replaced by a depset including the installed + // files of this module at the end for use by modules that depend on this one. + m.installFilesDepSet = newInstallPathsDepSet(nil, dependencyInstallFiles) + // Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never // reporting missing dependency errors in Blueprint when AllowMissingDependencies == true. // TODO: This will be removed once defaults modules handle missing dependency errors @@ -1245,8 +1800,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) if !ctx.PrimaryArch() { suffix = append(suffix, ctx.Arch().ArchType.String()) } - if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() { - suffix = append(suffix, apex.ApexName()) + if apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo); !apexInfo.IsForPlatform() { + suffix = append(suffix, apexInfo.ApexVariationName) } ctx.Variable(pctx, "moduleDesc", desc) @@ -1258,38 +1813,43 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) ctx.Variable(pctx, "moduleDescSuffix", s) // Some common property checks for properties that will be used later in androidmk.go - if m.commonProperties.Dist.Dest != nil { - _, err := validateSafePath(*m.commonProperties.Dist.Dest) - if err != nil { - ctx.PropertyErrorf("dist.dest", "%s", err.Error()) - } - } - if m.commonProperties.Dist.Dir != nil { - _, err := validateSafePath(*m.commonProperties.Dist.Dir) - if err != nil { - ctx.PropertyErrorf("dist.dir", "%s", err.Error()) - } - } - if m.commonProperties.Dist.Suffix != nil { - if strings.Contains(*m.commonProperties.Dist.Suffix, "/") { - ctx.PropertyErrorf("dist.suffix", "Suffix may not contain a '/' character.") - } + checkDistProperties(ctx, "dist", &m.distProperties.Dist) + for i, _ := range m.distProperties.Dists { + checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i]) } if m.Enabled() { // ensure all direct android.Module deps are enabled ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) { - if _, ok := bm.(Module); ok { - ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps) + if m, ok := bm.(Module); ok { + ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps) } }) - notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE") + m.noticeFiles = make([]Path, 0) + optPath := OptionalPath{} + notice := proptools.StringDefault(m.commonProperties.Notice, "") if module := SrcIsModule(notice); module != "" { - m.noticeFile = ctx.ExpandOptionalSource(¬ice, "notice") - } else { + optPath = ctx.ExpandOptionalSource(¬ice, "notice") + } else if notice != "" { noticePath := filepath.Join(ctx.ModuleDir(), notice) - m.noticeFile = ExistentPathForSource(ctx, noticePath) + optPath = ExistentPathForSource(ctx, noticePath) + } + if optPath.Valid() { + m.noticeFiles = append(m.noticeFiles, optPath.Path()) + } else { + for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} { + noticePath := filepath.Join(ctx.ModuleDir(), notice) + optPath = ExistentPathForSource(ctx, noticePath) + if optPath.Valid() { + m.noticeFiles = append(m.noticeFiles, optPath.Path()) + } + } + } + + licensesPropertyFlattener(ctx) + if ctx.Failed() { + return } m.module.GenerateAndroidBuildActions(ctx) @@ -1297,10 +1857,30 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) return } - m.installFiles = append(m.installFiles, ctx.installFiles...) - m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...) m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc) + rcDir := PathForModuleInstall(ctx, "etc", "init") + for _, src := range m.initRcPaths { + ctx.PackageFile(rcDir, filepath.Base(src.String()), src) + } + m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments) + vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest") + for _, src := range m.vintfFragmentsPaths { + ctx.PackageFile(vintfDir, filepath.Base(src.String()), src) + } + + // Create the set of tagged dist files after calling GenerateAndroidBuildActions + // as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the + // output paths being set which must be done before or during + // GenerateAndroidBuildActions. + m.distFiles = m.GenerateTaggedDistFiles(ctx) + if ctx.Failed() { + return + } + + m.installFiles = append(m.installFiles, ctx.installFiles...) + m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...) + m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...) for k, v := range ctx.phonies { m.phonies[k] = append(m.phonies[k], v...) } @@ -1319,11 +1899,40 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) } } + m.installFilesDepSet = newInstallPathsDepSet(m.installFiles, dependencyInstallFiles) + m.packagingSpecsDepSet = newPackagingSpecsDepSet(m.packagingSpecs, dependencyPackagingSpecs) + m.buildParams = ctx.buildParams m.ruleParams = ctx.ruleParams m.variables = ctx.variables } +// Check the supplied dist structure to make sure that it is valid. +// +// property - the base property, e.g. dist or dists[1], which is combined with the +// name of the nested property to produce the full property, e.g. dist.dest or +// dists[1].dir. +func checkDistProperties(ctx *moduleContext, property string, dist *Dist) { + if dist.Dest != nil { + _, err := validateSafePath(*dist.Dest) + if err != nil { + ctx.PropertyErrorf(property+".dest", "%s", err.Error()) + } + } + if dist.Dir != nil { + _, err := validateSafePath(*dist.Dir) + if err != nil { + ctx.PropertyErrorf(property+".dir", "%s", err.Error()) + } + } + if dist.Suffix != nil { + if strings.Contains(*dist.Suffix, "/") { + ctx.PropertyErrorf(property+".suffix", "Suffix may not contain a '/' character.") + } + } + +} + type earlyModuleContext struct { blueprint.EarlyModuleContext @@ -1332,19 +1941,11 @@ type earlyModuleContext struct { } func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths { - ret, err := e.GlobWithDeps(globPattern, excludes) - if err != nil { - e.ModuleErrorf("glob: %s", err.Error()) - } - return pathsForModuleSrcFromFullPath(e, ret, true) + return Glob(e, globPattern, excludes) } func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths { - ret, err := e.GlobWithDeps(globPattern, excludes) - if err != nil { - e.ModuleErrorf("glob: %s", err.Error()) - } - return pathsForModuleSrcFromFullPath(e, ret, false) + return GlobFiles(e, globPattern, excludes) } func (b *earlyModuleContext) IsSymlink(path Path) bool { @@ -1400,6 +2001,10 @@ func (e *earlyModuleContext) SystemExtSpecific() bool { return e.kind == systemExtSpecificModule } +func (e *earlyModuleContext) Namespace() *Namespace { + return e.EarlyModuleContext.Namespace().(*Namespace) +} + type baseModuleContext struct { bp blueprint.BaseModuleContext earlyModuleContext @@ -1426,19 +2031,47 @@ func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) bluepri return b.bp.OtherModuleDependencyTag(m) } func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) } +func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool { + return b.bp.OtherModuleDependencyVariantExists(variations, name) +} +func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool { + return b.bp.OtherModuleFarDependencyVariantExists(variations, name) +} +func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { + return b.bp.OtherModuleReverseDependencyVariantExists(name) +} func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) } +func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} { + return b.bp.OtherModuleProvider(m, provider) +} +func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool { + return b.bp.OtherModuleHasProvider(m, provider) +} +func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} { + return b.bp.Provider(provider) +} +func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool { + return b.bp.HasProvider(provider) +} +func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) { + b.bp.SetProvider(provider, value) +} func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { return b.bp.GetDirectDepWithTag(name, tag) } +func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext { + return b.bp +} + type moduleContext struct { bp blueprint.ModuleContext baseModuleContext - installDeps Paths - installFiles Paths + packagingSpecs []PackagingSpec + installFiles InstallPaths checkbuildFiles Paths module Module phonies map[string]Paths @@ -1467,6 +2100,27 @@ func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParam 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, @@ -1474,9 +2128,11 @@ func convertBuildParams(params BuildParams) blueprint.BuildParams { 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, } @@ -1487,6 +2143,9 @@ func convertBuildParams(params BuildParams) blueprint.BuildParams { 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()) } @@ -1496,13 +2155,18 @@ func convertBuildParams(params BuildParams) blueprint.BuildParams { 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.Depfile = proptools.NinjaEscapeList([]string{bparams.Depfile})[0] + bparams.Validations = proptools.NinjaEscapeList(bparams.Validations) + bparams.Depfile = proptools.NinjaEscape(bparams.Depfile) return bparams } @@ -1554,7 +2218,15 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.buildParams = append(m.buildParams, params) } - m.bp.Build(pctx.PackageContext, convertBuildParams(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) { @@ -1577,7 +2249,12 @@ func (b *baseModuleContext) AddMissingDependencies(deps []string) { } } -func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module { +type AllowDisabledModuleDependency interface { + blueprint.DependencyTag + AllowDisabledModuleDependency(target Module) bool +} + +func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module { aModule, _ := module.(Module) if !strict { @@ -1590,30 +2267,45 @@ func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, stric } if !aModule.Enabled() { - if b.Config().AllowMissingDependencies() { - b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) - } else { - b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) + if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) { + if b.Config().AllowMissingDependencies() { + b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) + } else { + b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) + } } return nil } return aModule } -func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { - type dep struct { - mod blueprint.Module - tag blueprint.DependencyTag - } +type dep struct { + mod blueprint.Module + tag blueprint.DependencyTag +} + +func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep { var deps []dep b.VisitDirectDepsBlueprint(func(module blueprint.Module) { - if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name { - returnedTag := b.bp.OtherModuleDependencyTag(aModule) + if aModule, _ := module.(Module); aModule != nil { + if aModule.base().BaseModuleName() == name { + returnedTag := b.bp.OtherModuleDependencyTag(aModule) + if tag == nil || returnedTag == tag { + deps = append(deps, dep{aModule, returnedTag}) + } + } + } else if b.bp.OtherModuleName(module) == name { + returnedTag := b.bp.OtherModuleDependencyTag(module) if tag == nil || returnedTag == tag { - deps = append(deps, dep{aModule, returnedTag}) + deps = append(deps, dep{module, returnedTag}) } } }) + return deps +} + +func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { + deps := b.getDirectDepsInternal(name, tag) if len(deps) == 1 { return deps[0].mod, deps[0].tag } else if len(deps) >= 2 { @@ -1624,6 +2316,25 @@ func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.Depe } } +func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) { + foundDeps := b.getDirectDepsInternal(name, nil) + deps := map[blueprint.Module]bool{} + for _, dep := range foundDeps { + deps[dep.mod] = true + } + if len(deps) == 1 { + return foundDeps[0].mod, foundDeps[0].tag + } else if len(deps) >= 2 { + // this could happen if two dependencies have the same name in different namespaces + // TODO(b/186554727): this should not occur if namespaces are handled within + // getDirectDepsInternal. + panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", + name, b.ModuleName())) + } else { + return nil, nil + } +} + func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { var deps []Module b.VisitDirectDepsBlueprint(func(module blueprint.Module) { @@ -1641,8 +2352,11 @@ func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.Dependenc return module } +// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified +// name, or nil if none exists. If there are multiple dependencies on the same module it returns the +// first DependencyTag. func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { - return b.getDirectDepInternal(name, nil) + return b.getDirectDepFirstTag(name) } func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { @@ -1651,7 +2365,7 @@ func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { b.bp.VisitDirectDeps(func(module blueprint.Module) { - if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { visit(aModule) } }) @@ -1659,7 +2373,7 @@ func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { b.bp.VisitDirectDeps(func(module blueprint.Module) { - if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { if b.bp.OtherModuleDependencyTag(aModule) == tag { visit(aModule) } @@ -1671,7 +2385,7 @@ func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func b.bp.VisitDirectDepsIf( // pred func(module blueprint.Module) bool { - if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { return pred(aModule) } else { return false @@ -1685,7 +2399,7 @@ func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { b.bp.VisitDepsDepthFirst(func(module blueprint.Module) { - if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { visit(aModule) } }) @@ -1695,7 +2409,7 @@ func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit b.bp.VisitDepsDepthFirstIf( // pred func(module blueprint.Module) bool { - if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { + if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { return pred(aModule) } else { return false @@ -1740,18 +2454,63 @@ func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { return b.tagPath } -func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) { - m.bp.VisitAllModuleVariants(func(module blueprint.Module) { +func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { + b.bp.VisitAllModuleVariants(func(module blueprint.Module) { visit(module.(Module)) }) } -func (m *moduleContext) PrimaryModule() Module { - return m.bp.PrimaryModule().(Module) +func (b *baseModuleContext) PrimaryModule() Module { + return b.bp.PrimaryModule().(Module) +} + +func (b *baseModuleContext) FinalModule() Module { + return b.bp.FinalModule().(Module) +} + +// IsMetaDependencyTag returns true for cross-cutting metadata dependencies. +func IsMetaDependencyTag(tag blueprint.DependencyTag) bool { + if tag == licenseKindTag { + return true + } else if tag == licensesTag { + return true + } + return false } -func (m *moduleContext) FinalModule() Module { - return m.bp.FinalModule().(Module) +// A regexp for removing boilerplate from BaseDependencyTag from the string representation of +// a dependency tag. +var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) + +// PrettyPrintTag returns string representation of the tag, but prefers +// custom String() method if available. +func PrettyPrintTag(tag blueprint.DependencyTag) string { + // Use tag's custom String() method if available. + if stringer, ok := tag.(fmt.Stringer); ok { + return stringer.String() + } + + // Otherwise, get a default string representation of the tag's struct. + tagString := fmt.Sprintf("%T: %+v", tag, tag) + + // Remove the boilerplate from BaseDependencyTag as it adds no value. + tagString = tagCleaner.ReplaceAllString(tagString, "") + return tagString +} + +func (b *baseModuleContext) GetPathString(skipFirst bool) string { + sb := strings.Builder{} + tagPath := b.GetTagPath() + walkPath := b.GetWalkPath() + if !skipFirst { + sb.WriteString(walkPath[0].String()) + } + for i, m := range walkPath[1:] { + sb.WriteString("\n") + sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i]))) + sb.WriteString(fmt.Sprintf(" -> %s", m.String())) + } + return sb.String() } func (m *moduleContext) ModuleSubDir() string { @@ -1779,7 +2538,7 @@ func (b *baseModuleContext) Os() OsType { } func (b *baseModuleContext) Host() bool { - return b.os.Class == Host || b.os.Class == HostCross + return b.os.Class == Host } func (b *baseModuleContext) Device() bool { @@ -1819,10 +2578,6 @@ func (m *ModuleBase) MakeAsPlatform() { m.commonProperties.System_ext_specific = boolPtr(false) } -func (m *ModuleBase) EnableNativeBridgeSupportByDefault() { - m.commonProperties.Native_bridge_supported = boolPtr(true) -} - func (m *ModuleBase) MakeAsSystemExt() { m.commonProperties.Vendor = boolPtr(false) m.commonProperties.Proprietary = boolPtr(false) @@ -1852,6 +2607,14 @@ 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() } @@ -1864,11 +2627,19 @@ func (m *moduleContext) InstallBypassMake() bool { return m.module.InstallBypassMake() } -func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool { +func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { + return m.module.InstallForceOS() +} + +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. @@ -1877,11 +2648,7 @@ func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool { } if m.Device() { - if m.Config().EmbeddedInMake() && !m.InstallBypassMake() { - return true - } - - if m.Config().SkipMegaDeviceInstall(fullInstallPath.String()) { + if m.Config().KatiEnabled() && !m.InstallBypassMake() { return true } } @@ -1891,23 +2658,37 @@ func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool { func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath { - return m.installFile(installPath, name, srcPath, Cp, deps) + return m.installFile(installPath, name, srcPath, deps, false) } func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath { - return m.installFile(installPath, name, srcPath, CpExecutable, deps) + return m.installFile(installPath, name, srcPath, deps, true) } -func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, - rule blueprint.Rule, deps []Path) InstallPath { - +func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec { fullInstallPath := installPath.Join(m, name) - m.module.base().hooks.runInstallHooks(m, fullInstallPath, false) + return m.packageFile(fullInstallPath, srcPath, false) +} - if !m.skipInstall(fullInstallPath) { +func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec { + spec := PackagingSpec{ + relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), + srcPath: srcPath, + symlinkTarget: "", + executable: executable, + } + m.packagingSpecs = append(m.packagingSpecs, spec) + return spec +} - deps = append(deps, m.installDeps...) +func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, executable bool) InstallPath { + + fullInstallPath := installPath.Join(m, name) + m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) + + if !m.skipInstall() { + deps = append(deps, m.module.base().installFilesDepSet.ToList().Paths()...) var implicitDeps, orderOnlyDeps Paths @@ -1919,6 +2700,11 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat orderOnlyDeps = deps } + rule := Cp + if executable { + rule = CpExecutable + } + m.Build(pctx, BuildParams{ Rule: rule, Description: "install " + fullInstallPath.Base(), @@ -1926,31 +2712,35 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat Input: srcPath, Implicits: implicitDeps, OrderOnly: orderOnlyDeps, - Default: !m.Config().EmbeddedInMake(), + Default: !m.Config().KatiEnabled(), }) 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, fullInstallPath, true) + m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true) - if !m.skipInstall(fullInstallPath) { + 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() { - 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)) - } m.Build(pctx, BuildParams{ Rule: Symlink, Description: "install symlink " + fullInstallPath.Base(), Output: fullInstallPath, Input: srcPath, - Default: !m.Config().EmbeddedInMake(), + Default: !m.Config().KatiEnabled(), Args: map[string]string{ "fromPath": relPath, }, @@ -1959,6 +2749,14 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src 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, + }) + return fullInstallPath } @@ -1966,14 +2764,14 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src // (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, fullInstallPath, true) + m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) - if !m.skipInstall(fullInstallPath) { + if !m.skipInstall() { m.Build(pctx, BuildParams{ Rule: Symlink, Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath, Output: fullInstallPath, - Default: !m.Config().EmbeddedInMake(), + Default: !m.Config().KatiEnabled(), Args: map[string]string{ "fromPath": absPath, }, @@ -1981,6 +2779,14 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str 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, + }) + return fullInstallPath } @@ -1988,27 +2794,8 @@ func (m *moduleContext) CheckbuildFile(srcPath Path) { m.checkbuildFiles = append(m.checkbuildFiles, srcPath) } -type fileInstaller interface { - filesToInstall() Paths -} - -func isFileInstaller(m blueprint.Module) bool { - _, ok := m.(fileInstaller) - return ok -} - -func isAndroidModule(m blueprint.Module) bool { - _, ok := m.(Module) - return ok -} - -func findStringInSlice(str string, slice []string) int { - for i, s := range slice { - if s == str { - return i - } - } - return -1 +func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { + return m.bp } // SrcIsModule decodes module references in the format ":name" into the module name, or empty string if the input @@ -2112,7 +2899,7 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P return nil } if len(paths) > 1 { - reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", + ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", pathContextName(ctx, module)) return nil } @@ -2130,12 +2917,26 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) } return paths, nil + } else if sourceFileProducer, ok := module.(SourceFileProducer); ok { + if tag != "" { + return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) + } + paths := sourceFileProducer.Srcs() + if len(paths) == 0 { + return nil, fmt.Errorf("failed to get output files from module %q", pathContextName(ctx, module)) + } + return paths, nil } else { return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module)) } } +// Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to +// specify that they can be used as a tool by a genrule module. type HostToolProvider interface { + Module + // HostToolPath returns the path to the host tool for the module if it is one, or an invalid + // OptionalPath. HostToolPath() OptionalPath } @@ -2217,7 +3018,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { }) suffix := "" - if ctx.Config().EmbeddedInMake() { + if ctx.Config().KatiEnabled() { suffix = "-soong" } @@ -2225,7 +3026,7 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { ctx.Phony("checkbuild"+suffix, checkbuildDeps...) // Make will generate the MODULES-IN-* targets - if ctx.Config().EmbeddedInMake() { + if ctx.Config().KatiEnabled() { return } @@ -2258,30 +3059,36 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { } // Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild. - osDeps := map[OsType]Paths{} + type osAndCross struct { + os OsType + hostCross bool + } + osDeps := map[osAndCross]Paths{} ctx.VisitAllModules(func(module Module) { if module.Enabled() { - os := module.Target().Os - osDeps[os] = append(osDeps[os], module.base().checkbuildFiles...) + key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} + osDeps[key] = append(osDeps[key], module.base().checkbuildFiles...) } }) osClass := make(map[string]Paths) - for os, deps := range osDeps { + for key, deps := range osDeps { var className string - switch os.Class { + switch key.os.Class { case Host: - className = "host" - case HostCross: - className = "host-cross" + if key.hostCross { + className = "host-cross" + } else { + className = "host" + } case Device: className = "target" default: continue } - name := className + "-" + os.Name + name := className + "-" + key.os.Name osClass[className] = append(osClass[className], PathForPhony(ctx, name)) ctx.Phony(name, deps...) @@ -2316,4 +3123,30 @@ type IdeInfo struct { Classes []string `json:"class,omitempty"` Installed_paths []string `json:"installed,omitempty"` SrcJars []string `json:"srcjars,omitempty"` + Paths []string `json:"path,omitempty"` +} + +func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error { + bpctx := ctx.blueprintBaseModuleContext() + return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents) +} + +// installPathsDepSet is a thin type-safe wrapper around the generic depSet. It always uses +// topological order. +type installPathsDepSet struct { + depSet +} + +// newInstallPathsDepSet returns an immutable packagingSpecsDepSet with the given direct and +// transitive contents. +func newInstallPathsDepSet(direct InstallPaths, transitive []*installPathsDepSet) *installPathsDepSet { + return &installPathsDepSet{*newDepSet(TOPOLOGICAL, direct, transitive)} +} + +// ToList returns the installPathsDepSet flattened to a list in topological order. +func (d *installPathsDepSet) ToList() InstallPaths { + if d == nil { + return nil + } + return d.depSet.ToList().(InstallPaths) } |