Merge changes Ie883eb45,If46a2f74,I8f4c5395,Ic4eb169d,I2b2408ef, ... into rvc-dev

* changes:
  Replace references to droiddoc with droidstubs
  Allow walkPayloadDeps visitor to control walk flow
  Add apex_available to sysprop_library
  Improve missing apex_available message
  Split TestApexAvailable into separate tests
  Use reflect.Zero(type) to get value to clear field
  Sdk snapshot set compile_multilib per OsType
  Remove old SdkMemberType API for creating snapshot modules
  Improve consistency of handling java snapshot properties
  Make new module creation API more flexible
  Add abstraction for tracking compile multilib usages
  Add support for using cc_library in sdk/module_exports
  Extract the osTypeSpecificInfo code from module creation loop
  Extract archTypeSpecificInfo code from module creation loop
  Clean up the main module creation loop
  Add support for cc_prebuilt_library
  Refactor prebuilt to use srcs supplier function
  Output properties before sets in snapshot module
  Remove SdkMemberType.FinalizeModule
  Follow up a review comment that was missed
  Copy shared_libs and system_shared_libs to module snapshot
  Support extracting common values from embedded structures
  Refactor common value extraction
  Copy white listed apex available settings into snapshot
  Disable installation for sdk snapshot versioned prebuilts
  Remove special handling of test_ apexes
  Remove special handling of com.android.art.debug/release
  Allow sdk members to vary by os type
  Add support for multiple os types
  Copy sdk_version to cc library snapshots
  Refactor java_library/java_test snapshot processing
  Refactor snapshot module creation
  Enable androidmk processing in sdk testing
  Add a nice install paths for module SDKs and exports.
  Copy apex_available properties to snapshot modules
  Improve documentation of CompileMultiTargets and related properties
  Only check copy rules into the snapshot directory
  Simplify java library sdk member code
  Add CommonOS variant for sdk
  Fix bug in error reporting when adding duplicate properties
  Avoid invoking sdk member to add empty list of dependencies
  Add windows to the list of available OS's in sdk tests
  Add support for cc_library_headers in sdk/module_exports
  Prune any empty property sets from the modules before transforming
  Simplify cc library sdk snapshot handling of include dirs/headers
  Add support for transforming a property set after its contents
  Fix issues with bp transformation
This commit is contained in:
TreeHugger Robot 2020-04-23 15:19:26 +00:00 committed by Android (Google) Code Review
commit 4586da2aae
38 changed files with 3273 additions and 746 deletions

View file

@ -536,6 +536,7 @@ bootstrap_go_package {
"sdk/update.go",
],
testSrcs: [
"sdk/bp_test.go",
"sdk/cc_sdk_test.go",
"sdk/exports_test.go",
"sdk/java_sdk_test.go",

View file

@ -29,7 +29,11 @@ import (
)
func init() {
RegisterSingletonType("androidmk", AndroidMkSingleton)
RegisterAndroidMkBuildComponents(InitRegistrationContext)
}
func RegisterAndroidMkBuildComponents(ctx RegistrationContext) {
ctx.RegisterSingletonType("androidmk", AndroidMkSingleton)
}
// Deprecated: consider using AndroidMkEntriesProvider instead, especially if you're not going to

View file

@ -126,6 +126,10 @@ func (m *ApexModuleBase) apexModuleBase() *ApexModuleBase {
return m
}
func (m *ApexModuleBase) ApexAvailable() []string {
return m.ApexProperties.Apex_available
}
func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock()
@ -163,7 +167,7 @@ func (m *ApexModuleBase) IsInstallableToApex() bool {
const (
AvailableToPlatform = "//apex_available:platform"
availableToAnyApex = "//apex_available:anyapex"
AvailableToAnyApex = "//apex_available:anyapex"
)
func CheckAvailableForApex(what string, apex_available []string) bool {
@ -173,7 +177,7 @@ func CheckAvailableForApex(what string, apex_available []string) bool {
return what == AvailableToPlatform
}
return InList(what, apex_available) ||
(what != AvailableToPlatform && InList(availableToAnyApex, apex_available))
(what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
}
func (m *ApexModuleBase) AvailableFor(what string) bool {
@ -199,7 +203,7 @@ func (m *ApexModuleBase) ChooseSdkVersion(versionList []string, maxSdkVersion in
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
if n == AvailableToPlatform || n == availableToAnyApex {
if n == AvailableToPlatform || n == AvailableToAnyApex {
continue
}
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {

View file

@ -596,7 +596,7 @@ var BuildOs = func() OsType {
}()
var (
osTypeList []OsType
OsTypeList []OsType
commonTargetMap = make(map[string]Target)
NoOsType OsType
@ -607,6 +607,10 @@ var (
Android = NewOsType("android", Device, false)
Fuchsia = NewOsType("fuchsia", Device, false)
// A pseudo OSType for a common os variant, which is OSType agnostic and which
// has dependencies on all the OS variants.
CommonOS = NewOsType("common_os", Generic, false)
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
LinuxBionic: []ArchType{X86_64},
@ -668,7 +672,7 @@ func NewOsType(name string, class OsClass, defDisabled bool) OsType {
DefaultDisabled: defDisabled,
}
osTypeList = append(osTypeList, os)
OsTypeList = append(OsTypeList, os)
if _, found := commonTargetMap[name]; found {
panic(fmt.Errorf("Found Os type duplicate during OsType registration: %q", name))
@ -680,7 +684,7 @@ func NewOsType(name string, class OsClass, defDisabled bool) OsType {
}
func osByName(name string) OsType {
for _, os := range osTypeList {
for _, os := range OsTypeList {
if os.Name == name {
return os
}
@ -746,7 +750,7 @@ func osMutator(mctx BottomUpMutatorContext) {
var moduleOSList []OsType
for _, os := range osTypeList {
for _, os := range OsTypeList {
supportedClass := false
for _, osClass := range osClasses {
if os.Class == osClass {
@ -775,12 +779,64 @@ func osMutator(mctx BottomUpMutatorContext) {
osNames[i] = os.String()
}
modules := mctx.CreateVariations(osNames...)
for i, m := range modules {
m.(Module).base().commonProperties.CompileOS = moduleOSList[i]
m.(Module).base().setOSProperties(mctx)
createCommonOSVariant := base.commonProperties.CreateCommonOSVariant
if createCommonOSVariant {
// A CommonOS variant was requested so add it to the list of OS's variants to
// create. It needs to be added to the end because it needs to depend on the
// the other variants in the list returned by CreateVariations(...) and inter
// variant dependencies can only be created from a later variant in that list to
// an earlier one. That is because variants are always processed in the order in
// which they are returned from CreateVariations(...).
osNames = append(osNames, CommonOS.Name)
moduleOSList = append(moduleOSList, CommonOS)
}
modules := mctx.CreateVariations(osNames...)
for i, m := range modules {
m.base().commonProperties.CompileOS = moduleOSList[i]
m.base().setOSProperties(mctx)
}
if createCommonOSVariant {
// A CommonOS variant was requested so add dependencies from it (the last one in
// the list) to the OS type specific variants.
last := len(modules) - 1
commonOSVariant := modules[last]
commonOSVariant.base().commonProperties.CommonOSVariant = true
for _, module := range modules[0:last] {
// Ignore modules that are enabled. Note, this will only avoid adding
// dependencies on OsType variants that are explicitly disabled in their
// properties. The CommonOS variant will still depend on disabled variants
// if they are disabled afterwards, e.g. in archMutator if
if module.Enabled() {
mctx.AddInterVariantDependency(commonOsToOsSpecificVariantTag, commonOSVariant, module)
}
}
}
}
// Identifies the dependency from CommonOS variant to the os specific variants.
type commonOSTag struct{ blueprint.BaseDependencyTag }
var commonOsToOsSpecificVariantTag = commonOSTag{}
// Get the OsType specific variants for the current CommonOS variant.
//
// The returned list will only contain enabled OsType specific variants of the
// module referenced in the supplied context. An empty list is returned if there
// are no enabled variants or the supplied context is not for an CommonOS
// variant.
func GetOsSpecificVariantsOfCommonOSVariant(mctx BaseModuleContext) []Module {
var variants []Module
mctx.VisitDirectDeps(func(m Module) {
if mctx.OtherModuleDependencyTag(m) == commonOsToOsSpecificVariantTag {
if m.Enabled() {
variants = append(variants, m)
}
}
})
return variants
}
// archMutator splits a module into a variant for each Target requested by the module. Target selection
@ -821,6 +877,15 @@ func archMutator(mctx BottomUpMutatorContext) {
}
os := base.commonProperties.CompileOS
if os == CommonOS {
// Make sure that the target related properties are initialized for the
// CommonOS variant.
addTargetProperties(module, commonTargetMap[os.Name], nil, true)
// Do not create arch specific variants for the CommonOS variant.
return
}
osTargets := mctx.Config().Targets[os]
image := base.commonProperties.ImageVariation
// Filter NativeBridge targets unless they are explicitly supported
@ -881,15 +946,17 @@ func archMutator(mctx BottomUpMutatorContext) {
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
m.(Module).base().commonProperties.CompileTarget = targets[i]
m.(Module).base().commonProperties.CompileMultiTargets = multiTargets
if i == 0 {
m.(Module).base().commonProperties.CompilePrimary = true
}
addTargetProperties(m, targets[i], multiTargets, i == 0)
m.(Module).base().setArchProperties(mctx)
}
}
func addTargetProperties(m Module, target Target, multiTargets []Target, primaryTarget bool) {
m.base().commonProperties.CompileTarget = target
m.base().commonProperties.CompileMultiTargets = multiTargets
m.base().commonProperties.CompilePrimary = primaryTarget
}
func decodeMultilib(base *ModuleBase, class OsClass) (multilib, extraMultilib string) {
switch class {
case Device:
@ -1004,7 +1071,7 @@ func createArchPropTypeDesc(props reflect.Type) []archPropTypeDesc {
"Arm_on_x86",
"Arm_on_x86_64",
}
for _, os := range osTypeList {
for _, os := range OsTypeList {
targets = append(targets, os.Field)
for _, archType := range osArchTypeMap[os] {
@ -1711,6 +1778,8 @@ func filterMultilibTargets(targets []Target, multilib string) []Target {
return ret
}
// Return the set of Os specific common architecture targets for each Os in a list of
// targets.
func getCommonTargets(targets []Target) []Target {
var ret []Target
set := make(map[string]bool)

View file

@ -359,6 +359,9 @@ func NewConfig(srcDir, buildDir string) (Config, error) {
return Config{}, err
}
// Make the CommonOS OsType available for all products.
targets[CommonOS] = []Target{commonTargetMap[CommonOS.Name]}
var archConfig []archConfig
if Bool(config.Mega_device) {
archConfig = getMegaDeviceConfig()

View file

@ -132,6 +132,9 @@ type BaseModuleContext interface {
Target() Target
TargetPrimary() bool
// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
// responsible for creating.
MultiTargets() []Target
Arch() Arch
Os() OsType
@ -361,6 +364,10 @@ type commonProperties struct {
}
}
// If set to true then the archMutator will create variants for each arch specific target
// (e.g. 32/64) that the module is required to produce. If set to false then it will only
// create a variant for the architecture and will list the additional arch specific targets
// that the variant needs to produce in the CompileMultiTargets property.
UseTargetVariants bool `blueprint:"mutated"`
Default_multilib string `blueprint:"mutated"`
@ -439,16 +446,56 @@ type commonProperties struct {
Suffix *string `android:"arch_variant"`
} `android:"arch_variant"`
// Set by TargetMutator
CompileOS OsType `blueprint:"mutated"`
CompileTarget Target `blueprint:"mutated"`
// The OsType of artifacts that this module variant is responsible for creating.
//
// Set by osMutator
CompileOS OsType `blueprint:"mutated"`
// The Target of artifacts that this module variant is responsible for creating.
//
// Set by archMutator
CompileTarget Target `blueprint:"mutated"`
// The additional arch specific targets (e.g. 32/64 bit) that this module variant is
// responsible for creating.
//
// By default this is nil as, where necessary, separate variants are created for the
// different multilib types supported and that information is encapsulated in the
// CompileTarget so the module variant simply needs to create artifacts for that.
//
// However, if UseTargetVariants is set to false (e.g. by
// InitAndroidMultiTargetsArchModule) then no separate variants are created for the
// multilib targets. Instead a single variant is created for the architecture and
// this contains the multilib specific targets that this variant should create.
//
// Set by archMutator
CompileMultiTargets []Target `blueprint:"mutated"`
CompilePrimary bool `blueprint:"mutated"`
// True if the module variant's CompileTarget is the primary target
//
// Set by archMutator
CompilePrimary bool `blueprint:"mutated"`
// Set by InitAndroidModule
HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"`
ArchSpecific bool `blueprint:"mutated"`
// If set to true then a CommonOS variant will be created which will have dependencies
// on all its OsType specific variants. Used by sdk/module_exports to create a snapshot
// that covers all os and architecture variants.
//
// The OsType specific variants can be retrieved by calling
// GetOsSpecificVariantsOfCommonOSVariant
//
// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule
CreateCommonOSVariant bool `blueprint:"mutated"`
// If set to true then this variant is the CommonOS variant that has dependencies on its
// OsType specific variants.
//
// Set by osMutator.
CommonOSVariant bool `blueprint:"mutated"`
SkipInstall bool `blueprint:"mutated"`
NamespaceExportedToMake bool `blueprint:"mutated"`
@ -581,6 +628,14 @@ func InitAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defa
m.base().commonProperties.UseTargetVariants = false
}
// As InitAndroidMultiTargetsArchModule except it creates an additional CommonOS variant that
// has dependencies on all the OsType specific variants.
func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) {
InitAndroidArchModule(m, hod, defaultMultilib)
m.base().commonProperties.UseTargetVariants = false
m.base().commonProperties.CreateCommonOSVariant = true
}
// A ModuleBase object contains the properties that are common to all Android
// modules. It should be included as an anonymous field in every module
// struct definition. InitAndroidModule should then be called from the module's
@ -772,6 +827,11 @@ func (m *ModuleBase) ArchSpecific() bool {
return m.commonProperties.ArchSpecific
}
// True if the current variant is a CommonOS variant, false otherwise.
func (m *ModuleBase) IsCommonOSVariant() bool {
return m.commonProperties.CommonOSVariant
}
func (m *ModuleBase) OsClassSupported() []OsClass {
switch m.commonProperties.HostOrDeviceSupported {
case HostSupported:
@ -958,6 +1018,16 @@ func (m *ModuleBase) ImageVariation() blueprint.Variation {
}
}
func (m *ModuleBase) getVariationByMutatorName(mutator string) string {
for i, v := range m.commonProperties.DebugMutators {
if v == mutator {
return m.commonProperties.DebugVariations[i]
}
}
return ""
}
func (m *ModuleBase) InRamdisk() bool {
return m.base().commonProperties.ImageVariation == RamdiskVariation
}
@ -1136,8 +1206,11 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext)
blueprintCtx.GetMissingDependencies()
// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and
// are enabled.
ctx.baseModuleContext.strictVisitDeps = true
// are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants
// (because the dependencies are added before the modules are disabled). The
// GetOsSpecificVariantsOfCommonOSVariant(...) method will ensure that the disabled variants are
// ignored.
ctx.baseModuleContext.strictVisitDeps = !m.IsCommonOSVariant()
if ctx.config.captureBuild {
ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)

View file

@ -1238,8 +1238,8 @@ func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string
return ret
}
func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
paths = append([]string{"ndk"}, paths...)
func pathForNdkOrSdkInstall(ctx PathContext, prefix string, paths []string) InstallPath {
paths = append([]string{prefix}, paths...)
path, err := validatePath(paths...)
if err != nil {
reportPathError(ctx, err)
@ -1247,6 +1247,14 @@ func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
return InstallPath{basePath{path, ctx.Config(), ""}, ""}
}
func PathForNdkInstall(ctx PathContext, paths ...string) InstallPath {
return pathForNdkOrSdkInstall(ctx, "ndk", paths)
}
func PathForMainlineSdksInstall(ctx PathContext, paths ...string) InstallPath {
return pathForNdkOrSdkInstall(ctx, "mainline-sdks", paths)
}
func InstallPathToOnDevicePath(ctx PathContext, path InstallPath) string {
rel := Rel(ctx, PathForOutput(ctx, "target", "product", ctx.Config().DeviceName()).String(), path.String())

View file

@ -50,12 +50,9 @@ type PrebuiltProperties struct {
type Prebuilt struct {
properties PrebuiltProperties
module Module
srcs *[]string
// Metadata for single source Prebuilt modules.
srcProps reflect.Value
srcField reflect.StructField
srcsSupplier PrebuiltSrcsSupplier
srcsPropertyName string
}
func (p *Prebuilt) Name(name string) string {
@ -72,31 +69,26 @@ func (p *Prebuilt) ForcePrefer() {
// preference configs. We'll want to add native support for dynamic source cases if we end up having
// more modules like this.
func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
if p.srcs != nil {
if len(*p.srcs) == 0 {
ctx.PropertyErrorf("srcs", "missing prebuilt source file")
if p.srcsSupplier != nil {
srcs := p.srcsSupplier()
if len(srcs) == 0 {
ctx.PropertyErrorf(p.srcsPropertyName, "missing prebuilt source file")
return nil
}
if len(*p.srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
if len(srcs) > 1 {
ctx.PropertyErrorf(p.srcsPropertyName, "multiple prebuilt source files")
return nil
}
// Return the singleton source after expanding any filegroup in the
// sources.
return PathForModuleSrc(ctx, (*p.srcs)[0])
} else {
if !p.srcProps.IsValid() {
ctx.ModuleErrorf("prebuilt source was not set")
}
src := p.getSingleSourceFieldValue()
if src == "" {
ctx.PropertyErrorf(proptools.FieldNameForProperty(p.srcField.Name),
"missing prebuilt source file")
return nil
}
src := srcs[0]
return PathForModuleSrc(ctx, src)
} else {
ctx.ModuleErrorf("prebuilt source was not set")
return nil
}
}
@ -104,18 +96,80 @@ func (p *Prebuilt) UsePrebuilt() bool {
return p.properties.UsePrebuilt
}
func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
// Called to provide the srcs value for the prebuilt module.
//
// Return the src value or nil if it is not available.
type PrebuiltSrcsSupplier func() []string
// Initialize the module as a prebuilt module that uses the provided supplier to access the
// prebuilt sources of the module.
//
// The supplier will be called multiple times and must return the same values each time it
// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
// as a replacement for a source module with the same name even if prefer = true.
//
// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
// containing exactly one source file.
//
// The provided property name is used to provide helpful error messages in the event that
// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
p := module.Prebuilt()
module.AddProperties(&p.properties)
p.srcs = srcs
if srcsSupplier == nil {
panic(fmt.Errorf("srcsSupplier must not be nil"))
}
if srcsPropertyName == "" {
panic(fmt.Errorf("srcsPropertyName must not be empty"))
}
p.srcsSupplier = srcsSupplier
p.srcsPropertyName = srcsPropertyName
}
func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
if srcs == nil {
panic(fmt.Errorf("srcs must not be nil"))
}
srcsSupplier := func() []string {
return *srcs
}
InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
}
func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
p := module.Prebuilt()
module.AddProperties(&p.properties)
p.srcProps = reflect.ValueOf(srcProps).Elem()
p.srcField, _ = p.srcProps.Type().FieldByName(srcField)
p.checkSingleSourceProperties()
srcPropsValue := reflect.ValueOf(srcProps).Elem()
srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
if !srcPropsValue.IsValid() || srcStructField.Name == "" {
panic(fmt.Errorf("invalid single source prebuilt %+v", module))
}
if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
}
srcFieldIndex := srcStructField.Index
srcPropertyName := proptools.PropertyNameForField(srcField)
srcsSupplier := func() []string {
value := srcPropsValue.FieldByIndex(srcFieldIndex)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
if value.Kind() != reflect.String {
panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
}
src := value.String()
if src == "" {
return nil
}
return []string{src}
}
InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
}
type PrebuiltInterface interface {
@ -152,7 +206,7 @@ func PrebuiltMutator(ctx BottomUpMutatorContext) {
func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
p := m.Prebuilt()
if p.srcs == nil && !p.srcProps.IsValid() {
if p.srcsSupplier == nil {
panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
}
if !p.properties.SourceExists {
@ -191,11 +245,7 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
// usePrebuilt returns true if a prebuilt should be used instead of the source module. The prebuilt
// will be used if it is marked "prefer" or if the source module is disabled.
func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
if p.srcs != nil && len(*p.srcs) == 0 {
return false
}
if p.srcProps.IsValid() && p.getSingleSourceFieldValue() == "" {
if p.srcsSupplier != nil && len(p.srcsSupplier()) == 0 {
return false
}
@ -210,24 +260,3 @@ func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module) bool {
func (p *Prebuilt) SourceExists() bool {
return p.properties.SourceExists
}
func (p *Prebuilt) checkSingleSourceProperties() {
if !p.srcProps.IsValid() || p.srcField.Name == "" {
panic(fmt.Errorf("invalid single source prebuilt %+v", p))
}
if p.srcProps.Kind() != reflect.Struct && p.srcProps.Kind() != reflect.Interface {
panic(fmt.Errorf("invalid single source prebuilt %+v", p.srcProps))
}
}
func (p *Prebuilt) getSingleSourceFieldValue() string {
value := p.srcProps.FieldByIndex(p.srcField.Index)
if value.Kind() == reflect.Ptr {
value = value.Elem()
}
if value.Kind() != reflect.String {
panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one", p.srcField.Name))
}
return value.String()
}

View file

@ -145,10 +145,6 @@ func (s *SdkBase) RequiredSdks() SdkRefs {
return s.properties.RequiredSdks
}
func (s *SdkBase) BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder) {
sdkModuleContext.ModuleErrorf("module type " + sdkModuleContext.OtherModuleType(s.module) + " cannot be used in an sdk")
}
// InitSdkAwareModule initializes the SdkBase struct. This must be called by all modules including
// SdkBase.
func InitSdkAwareModule(m SdkAware) {
@ -186,9 +182,33 @@ type SnapshotBuilder interface {
// is correctly output for both versioned and unversioned prebuilts in the
// snapshot.
//
// "required: true" means that the property must only contain references
// to other members of the sdk. Passing a reference to a module that is not a
// member of the sdk will result in a build error.
//
// "required: false" means that the property can contain references to modules
// that are either members or not members of the sdk. If a reference is to a
// module that is a non member then the reference is left unchanged, i.e. it
// is not transformed as references to members are.
//
// The handling of the member names is dependent on whether it is an internal or
// exported member. An exported member is one whose name is specified in one of
// the member type specific properties. An internal member is one that is added
// due to being a part of an exported (or other internal) member and is not itself
// an exported member.
//
// Member names are handled as follows:
// * When creating the unversioned form of the module the name is left unchecked
// unless the member is internal in which case it is transformed into an sdk
// specific name, i.e. by prefixing with the sdk name.
//
// * When creating the versioned form of the module the name is transformed into
// a versioned sdk specific name, i.e. by prefixing with the sdk name and
// suffixing with the version.
//
// e.g.
// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag())
SdkMemberReferencePropertyTag() BpPropertyTag
// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
type BpPropertyTag interface{}
@ -295,14 +315,36 @@ type SdkMemberType interface {
// the module is not allowed in whichever sdk property it was added.
IsInstance(module Module) bool
// Build the snapshot for the SDK member
// Add a prebuilt module that the sdk will populate.
//
// The ModuleContext provided is for the SDK module, so information for
// variants in the supplied member can be accessed using the Other... methods.
// Returning nil from this will cause the sdk module type to use the deprecated BuildSnapshot
// method to build the snapshot. That method is deprecated because it requires the SdkMemberType
// implementation to do all the word.
//
// The SdkMember is guaranteed to contain variants for which the
// IsInstance(Module) method returned true.
BuildSnapshot(sdkModuleContext ModuleContext, builder SnapshotBuilder, member SdkMember)
// Otherwise, returning a non-nil value from this will cause the sdk module type to do the
// majority of the work to generate the snapshot. The sdk module code generates the snapshot
// as follows:
//
// * A properties struct of type SdkMemberProperties is created for each variant and
// populated with information from the variant by calling PopulateFromVariant(SdkAware)
// on the struct.
//
// * An additional properties struct is created into which the common properties will be
// added.
//
// * The variant property structs are analysed to find exported (capitalized) fields which
// have common values. Those fields are cleared and the common value added to the common
// properties. A field annotated with a tag of `sdk:"keep"` will be treated as if it
// was not capitalized, i.e. not optimized for common values.
//
// * The sdk module type populates the BpModule structure, creating the arch specific
// structure and calls AddToPropertySet(...) on the properties struct to add the member
// specific properties in the correct place in the structure.
//
AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
// Create a structure into which variant specific properties can be added.
CreateVariantPropertiesStruct() SdkMemberProperties
}
// Base type for SdkMemberType implementations.
@ -389,3 +431,84 @@ func RegisterSdkMemberType(memberType SdkMemberType) {
SdkMemberTypes = SdkMemberTypes.copyAndAppend(memberType)
}
}
// Base structure for all implementations of SdkMemberProperties.
//
// Contains common properties that apply across many different member types. These
// are not affected by the optimization to extract common values.
type SdkMemberPropertiesBase struct {
// The number of unique os types supported by the member variants.
//
// If a member has a variant with more than one os type then it will need to differentiate
// the locations of any of their prebuilt files in the snapshot by os type to prevent them
// from colliding. See OsPrefix().
//
// This property is the same for all variants of a member and so would be optimized away
// if it was not explicitly kept.
Os_count int `sdk:"keep"`
// The os type for which these properties refer.
//
// Provided to allow a member to differentiate between os types in the locations of their
// prebuilt files when it supports more than one os type.
//
// This property is the same for all os type specific variants of a member and so would be
// optimized away if it was not explicitly kept.
Os OsType `sdk:"keep"`
// The setting to use for the compile_multilib property.
//
// This property is set after optimization so there is no point in trying to optimize it.
Compile_multilib string `sdk:"keep"`
}
// The os prefix to use for any file paths in the sdk.
//
// Is an empty string if the member only provides variants for a single os type, otherwise
// is the OsType.Name.
func (b *SdkMemberPropertiesBase) OsPrefix() string {
if b.Os_count == 1 {
return ""
} else {
return b.Os.Name
}
}
func (b *SdkMemberPropertiesBase) Base() *SdkMemberPropertiesBase {
return b
}
// Interface to be implemented on top of a structure that contains variant specific
// information.
//
// Struct fields that are capitalized are examined for common values to extract. Fields
// that are not capitalized are assumed to be arch specific.
type SdkMemberProperties interface {
// Access the base structure.
Base() *SdkMemberPropertiesBase
// Populate this structure with information from the variant.
PopulateFromVariant(ctx SdkMemberContext, variant Module)
// Add the information from this structure to the property set.
AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
}
// Provides access to information common to a specific member.
type SdkMemberContext interface {
// The module context of the sdk common os variant which is creating the snapshot.
SdkModuleContext() ModuleContext
// The builder of the snapshot.
SnapshotBuilder() SnapshotBuilder
// The type of the member.
MemberType() SdkMemberType
// The name of the member.
//
// Provided for use by sdk members to create a member specific location within the snapshot
// into which to copy the prebuilt files.
Name() string
}

View file

@ -410,6 +410,10 @@ func CheckErrorsAgainstExpectations(t *testing.T, errs []error, expectedErrorPat
}
func SetInMakeForTests(config Config) {
config.inMake = true
}
func AndroidMkEntriesForTest(t *testing.T, config Config, bpPath string, mod blueprint.Module) []AndroidMkEntries {
var p AndroidMkEntriesProvider
var ok bool

View file

@ -61,8 +61,26 @@ var (
usesTag = dependencyTag{name: "uses"}
androidAppTag = dependencyTag{name: "androidApp", payload: true}
apexAvailWl = makeApexAvailableWhitelist()
inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
)
// Transform the map of apex -> modules to module -> apexes.
func invertApexWhiteList(m map[string][]string) map[string][]string {
r := make(map[string][]string)
for apex, modules := range m {
for _, module := range modules {
r[module] = append(r[module], apex)
}
}
return r
}
// Retrieve the while list of apexes to which the supplied module belongs.
func WhitelistedApexAvailable(moduleName string) []string {
return inverseApexAvailWl[normalizeModuleName(moduleName)]
}
// This is a map from apex to modules, which overrides the
// apex_available setting for that particular module to make
// it available for the apex regardless of its setting.
@ -91,7 +109,7 @@ func makeApexAvailableWhitelist() map[string][]string {
//
// Module separator
//
m["com.android.art"] = []string{
artApexContents := []string{
"art_cmdlineparser_headers",
"art_disassembler_headers",
"art_libartbase_headers",
@ -152,6 +170,8 @@ func makeApexAvailableWhitelist() map[string][]string {
"libziparchive",
"perfetto_trace_protos",
}
m["com.android.art.debug"] = artApexContents
m["com.android.art.release"] = artApexContents
//
// Module separator
//
@ -773,7 +793,7 @@ func makeApexAvailableWhitelist() map[string][]string {
//
// Module separator
//
m["//any"] = []string{
m[android.AvailableToAnyApex] = []string{
"libatomic",
"libclang_rt",
"libgcc_stripped",
@ -1749,10 +1769,14 @@ func (c *flattenedApexContext) InstallBypassMake() bool {
return true
}
// Function called while walking an APEX's payload dependencies.
//
// Return true if the `to` module should be visited, false otherwise.
type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
// Visit dependencies that contributes to the payload of this APEX
func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
return false
@ -1761,22 +1785,18 @@ func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext,
// Check for the direct dependencies that contribute to the payload
if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
if dt.payload {
do(ctx, parent, am, false /* externalDep */)
return true
return do(ctx, parent, am, false /* externalDep */)
}
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
// Check for the indirect dependencies if it is considered as part of the APEX
if am.ApexName() != "" {
do(ctx, parent, am, false /* externalDep */)
return true
return do(ctx, parent, am, false /* externalDep */)
}
do(ctx, parent, am, true /* externalDep */)
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
return do(ctx, parent, am, true /* externalDep */)
})
}
@ -1803,24 +1823,36 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) {
return
}
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
apexName := ctx.ModuleName()
fromName := ctx.OtherModuleName(from)
toName := ctx.OtherModuleName(to)
if externalDep || to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
return
if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
return true
}
ctx.ModuleErrorf("%q requires %q that is not available for the APEX.", fromName, toName)
message := ""
for _, m := range ctx.GetWalkPath()[1:] {
message = fmt.Sprintf("%s\n -> %s", message, m.String())
}
ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
// Visit this module's dependencies to check and report any issues with their availability.
return true
})
}
// Collects the list of module names that directly or indirectly contributes to the payload of this APEX
func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
a.depInfos = make(map[string]depInfo)
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
return
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return !externalDep
}
if info, exists := a.depInfos[to.Name()]; exists {
@ -1836,6 +1868,9 @@ func (a *apexBundle) collectDepsInfo(ctx android.ModuleContext) {
isExternal: externalDep,
}
}
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return !externalDep
})
}
@ -2182,10 +2217,21 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
func whitelistedApexAvailable(apex, moduleName string) bool {
key := apex
key = strings.Replace(key, "test_", "", 1)
key = strings.Replace(key, "com.android.art.debug", "com.android.art", 1)
key = strings.Replace(key, "com.android.art.release", "com.android.art", 1)
moduleName = normalizeModuleName(moduleName)
if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
return true
}
key = android.AvailableToAnyApex
if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
return true
}
return false
}
func normalizeModuleName(moduleName string) string {
// Prebuilt modules (e.g. java_import, etc.) have "prebuilt_" prefix added by the build
// system. Trim the prefix for the check since they are confusing
moduleName = strings.TrimPrefix(moduleName, "prebuilt_")
@ -2194,17 +2240,7 @@ func whitelistedApexAvailable(apex, moduleName string) bool {
// We don't want to list them all
moduleName = "libclang_rt"
}
if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
return true
}
key = "//any"
if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
return true
}
return false
return moduleName
}
func newApexBundle() *apexBundle {

View file

@ -3478,7 +3478,7 @@ func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
}`)
}
func TestApexAvailable(t *testing.T) {
func TestApexAvailable_DirectDep(t *testing.T) {
// libfoo is not available to myapex, but only to otherapex
testApexError(t, "requires \"libfoo\" that is not available for the APEX", `
apex {
@ -3511,9 +3511,17 @@ func TestApexAvailable(t *testing.T) {
system_shared_libs: [],
apex_available: ["otherapex"],
}`)
}
func TestApexAvailable_IndirectDep(t *testing.T) {
// libbbaz is an indirect dep
testApexError(t, "requires \"libbaz\" that is not available for the APEX", `
testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
.*-> libfoo.*link:shared.*
.*-> libfoo.*link:static.*
.*-> libbar.*link:shared.*
.*-> libbar.*link:static.*
.*-> libbaz.*link:shared.*
.*-> libbaz.*link:static.*`, `
apex {
name: "myapex",
key: "myapex.key",
@ -3547,7 +3555,9 @@ func TestApexAvailable(t *testing.T) {
stl: "none",
system_shared_libs: [],
}`)
}
func TestApexAvailable_InvalidApexName(t *testing.T) {
testApexError(t, "\"otherapex\" is not a valid module name", `
apex {
name: "myapex",
@ -3568,7 +3578,7 @@ func TestApexAvailable(t *testing.T) {
apex_available: ["otherapex"],
}`)
ctx, _ := testApex(t, `
testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@ -3604,7 +3614,9 @@ func TestApexAvailable(t *testing.T) {
versions: ["10", "20", "30"],
},
}`)
}
func TestApexAvailable_CreatedForPlatform(t *testing.T) {
// check that libfoo and libbar are created only for myapex, but not for the platform
// TODO(jiyong) the checks for the platform variant are removed because we now create
// the platform variant regardless of the apex_availability. Instead, we will make sure that
@ -3616,7 +3628,7 @@ func TestApexAvailable(t *testing.T) {
// ensureListContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared_myapex")
// ensureListNotContains(t, ctx.ModuleVariantsForTests("libbar"), "android_arm64_armv8-a_shared")
ctx, _ = testApex(t, `
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
@ -3638,8 +3650,10 @@ func TestApexAvailable(t *testing.T) {
// check that libfoo is created only for the platform
ensureListNotContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared_myapex")
ensureListContains(t, ctx.ModuleVariantsForTests("libfoo"), "android_arm64_armv8-a_shared")
}
ctx, _ = testApex(t, `
func TestApexAvailable_CreatedForApex(t *testing.T) {
testApex(t, `
apex {
name: "myapex",
key: "myapex.key",

View file

@ -219,14 +219,18 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs,
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
var noticeFiles android.Paths
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
return
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
notice := to.NoticeFile()
if notice.Valid() {
noticeFiles = append(noticeFiles, notice.Path())
}
return true
})
if len(noticeFiles) == 0 {

View file

@ -16,7 +16,6 @@ package cc
import (
"path/filepath"
"strings"
"android/soong/android"
"github.com/google/blueprint"
@ -64,65 +63,12 @@ func (mt *binarySdkMemberType) IsInstance(module android.Module) bool {
return false
}
func (mt *binarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
info := mt.organizeVariants(member)
buildSharedNativeBinarySnapshot(info, builder, member)
func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
}
// Organize the variants by architecture.
func (mt *binarySdkMemberType) organizeVariants(member android.SdkMember) *nativeBinaryInfo {
memberName := member.Name()
info := &nativeBinaryInfo{
name: memberName,
memberType: mt,
}
for _, variant := range member.Variants() {
ccModule := variant.(*Module)
info.archVariantProperties = append(info.archVariantProperties, nativeBinaryInfoProperties{
name: memberName,
archType: ccModule.Target().Arch.ArchType.String(),
outputFile: ccModule.OutputFile().Path(),
})
}
// Initialize the unexported properties that will not be set during the
// extraction process.
info.commonProperties.name = memberName
// Extract common properties from the arch specific properties.
extractCommonProperties(&info.commonProperties, info.archVariantProperties)
return info
}
func buildSharedNativeBinarySnapshot(info *nativeBinaryInfo, builder android.SnapshotBuilder, member android.SdkMember) {
pbm := builder.AddPrebuiltModule(member, "cc_prebuilt_binary")
archVariantCount := len(info.archVariantProperties)
// Choose setting for compile_multilib that is appropriate for the arch variants supplied.
var multilib string
if archVariantCount == 2 {
multilib = "both"
} else if archVariantCount == 1 {
if strings.HasSuffix(info.archVariantProperties[0].archType, "64") {
multilib = "64"
} else {
multilib = "32"
}
}
if multilib != "" {
pbm.AddProperty("compile_multilib", multilib)
}
archProperties := pbm.AddPropertySet("arch")
for _, av := range info.archVariantProperties {
archTypeProperties := archProperties.AddPropertySet(av.archType)
archTypeProperties.AddProperty("srcs", []string{nativeBinaryPathFor(av)})
builder.CopyToSnapshot(av.outputFile, nativeBinaryPathFor(av))
}
func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &nativeBinaryInfoProperties{}
}
const (
@ -131,7 +77,7 @@ const (
// path to the native binary. Relative to <sdk_root>/<api_dir>
func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
return filepath.Join(lib.archType,
return filepath.Join(lib.OsPrefix(), lib.archType,
nativeBinaryDir, lib.outputFile.Base())
}
@ -140,8 +86,7 @@ func nativeBinaryPathFor(lib nativeBinaryInfoProperties) string {
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeBinaryInfoProperties struct {
// The name of the library, is not exported as this must not be changed during optimization.
name string
android.SdkMemberPropertiesBase
// archType is not exported as if set (to a non default value) it is always arch specific.
// This is "" for common properties.
@ -149,12 +94,50 @@ type nativeBinaryInfoProperties struct {
// outputFile is not exported as it is always arch specific.
outputFile android.Path
// The set of shared libraries
//
// This field is exported as its contents may not be arch specific.
SharedLibs []string
// The set of system shared libraries
//
// This field is exported as its contents may not be arch specific.
SystemSharedLibs []string
}
// nativeBinaryInfo represents a collection of arch-specific modules having the same name
type nativeBinaryInfo struct {
name string
memberType *binarySdkMemberType
archVariantProperties []nativeBinaryInfoProperties
commonProperties nativeBinaryInfoProperties
func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
ccModule := variant.(*Module)
p.archType = ccModule.Target().Arch.ArchType.String()
p.outputFile = ccModule.OutputFile().Path()
if ccModule.linker != nil {
specifiedDeps := specifiedDeps{}
specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
p.SharedLibs = specifiedDeps.sharedLibs
p.SystemSharedLibs = specifiedDeps.systemSharedLibs
}
}
func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
if p.Compile_multilib != "" {
propertySet.AddProperty("compile_multilib", p.Compile_multilib)
}
builder := ctx.SnapshotBuilder()
if p.outputFile != nil {
propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
builder.CopyToSnapshot(p.outputFile, nativeBinaryPathFor(*p))
}
if len(p.SharedLibs) > 0 {
propertySet.AddPropertyWithTag("shared_libs", p.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
if len(p.SystemSharedLibs) > 0 {
propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
}

View file

@ -250,6 +250,8 @@ type BaseProperties struct {
// Used by vendor snapshot to record dependencies from snapshot modules.
SnapshotSharedLibs []string `blueprint:"mutated"`
SnapshotRuntimeLibs []string `blueprint:"mutated"`
Installable *bool
}
type VendorProperties struct {
@ -368,11 +370,21 @@ type linker interface {
nativeCoverage() bool
coverageOutputFilePath() android.OptionalPath
// Get the deps that have been explicitly specified in the properties.
// Only updates the
linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps
}
type specifiedDeps struct {
sharedLibs []string
systemSharedLibs []string
}
type installer interface {
installerProps() []interface{}
install(ctx ModuleContext, path android.Path)
everInstallable() bool
inData() bool
inSanitizerDir() bool
hostToolPath() android.OptionalPath
@ -1513,6 +1525,13 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
if ctx.Failed() {
return
}
} else if !proptools.BoolDefault(c.Properties.Installable, true) {
// If the module has been specifically configure to not be installed then
// skip the installation as otherwise it will break when running inside make
// as the output path to install will not be specified. Not all uninstallable
// modules can skip installation as some are needed for resolving make side
// dependencies.
c.SkipInstall()
}
}
@ -2705,8 +2724,18 @@ func (c *Module) AvailableFor(what string) bool {
}
}
// Return true if the module is ever installable.
func (c *Module) EverInstallable() bool {
return c.installer != nil &&
// Check to see whether the module is actually ever installable.
c.installer.everInstallable()
}
func (c *Module) installable() bool {
ret := c.installer != nil && !c.Properties.PreventInstall && c.outputFile.Valid()
ret := c.EverInstallable() &&
// Check to see whether the module has been configured to not be installed.
proptools.BoolDefault(c.Properties.Installable, true) &&
!c.Properties.PreventInstall && c.outputFile.Valid()
// The platform variant doesn't need further condition. Apex variants however might not
// be installable because it will likely to be included in the APEX and won't appear

View file

@ -86,6 +86,11 @@ func (installer *baseInstaller) install(ctx ModuleContext, file android.Path) {
installer.path = ctx.InstallFile(installer.installDir(ctx), file.Base(), file)
}
func (installer *baseInstaller) everInstallable() bool {
// Most cc modules are installable.
return true
}
func (installer *baseInstaller) inData() bool {
return installer.location == InstallInData
}

View file

@ -195,6 +195,7 @@ func LibraryFactory() android.Module {
module.sdkMemberTypes = []android.SdkMemberType{
sharedLibrarySdkMemberType,
staticLibrarySdkMemberType,
staticAndSharedLibrarySdkMemberType,
}
return module.Init()
}
@ -817,6 +818,23 @@ func (library *libraryDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps {
return deps
}
func (library *libraryDecorator) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
specifiedDeps = library.baseLinker.linkerSpecifiedDeps(specifiedDeps)
var properties StaticOrSharedProperties
if library.static() {
properties = library.StaticProperties.Static
} else if library.shared() {
properties = library.SharedProperties.Shared
}
specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, properties.Shared_libs...)
specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, properties.System_shared_libs...)
specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs)
specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs)
return specifiedDeps
}
func (library *libraryDecorator) linkStatic(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
@ -1221,6 +1239,12 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
}
}
func (library *libraryDecorator) everInstallable() bool {
// Only shared and static libraries are installed. Header libraries (which are
// neither static or shared) are not installed.
return library.shared() || library.static()
}
func (library *libraryDecorator) static() bool {
return library.MutatedProperties.VariantIsStatic
}

View file

@ -18,6 +18,18 @@ import "android/soong/android"
func init() {
RegisterLibraryHeadersBuildComponents(android.InitRegistrationContext)
// Register sdk member types.
android.RegisterSdkMemberType(headersLibrarySdkMemberType)
}
var headersLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_header_libs",
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_library_headers",
linkTypes: nil,
}
func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
@ -32,6 +44,7 @@ func RegisterLibraryHeadersBuildComponents(ctx android.RegistrationContext) {
func LibraryHeaderFactory() android.Module {
module, library := NewLibrary(android.HostAndDeviceSupported)
library.HeaderOnly()
module.sdkMemberTypes = []android.SdkMemberType{headersLibrarySdkMemberType}
return module.Init()
}

View file

@ -16,10 +16,10 @@ package cc
import (
"path/filepath"
"reflect"
"android/soong/android"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
// This file contains support for using cc library modules within an sdk.
@ -42,10 +42,20 @@ var staticLibrarySdkMemberType = &librarySdkMemberType{
linkTypes: []string{"static"},
}
var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
PropertyName: "native_libs",
SupportsSdk: true,
},
prebuiltModuleType: "cc_prebuilt_library",
linkTypes: []string{"static", "shared"},
}
func init() {
// Register sdk member types.
android.RegisterSdkMemberType(sharedLibrarySdkMemberType)
android.RegisterSdkMemberType(staticLibrarySdkMemberType)
android.RegisterSdkMemberType(staticAndSharedLibrarySdkMemberType)
}
type librarySdkMemberType struct {
@ -65,12 +75,19 @@ func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorCont
if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name)
}
for _, linkType := range mt.linkTypes {
if mt.linkTypes == nil {
mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: android.CoreVariation},
{Mutator: "link", Variation: linkType},
{Mutator: "version", Variation: version},
}...), dependencyTag, name)
} else {
for _, linkType := range mt.linkTypes {
mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
{Mutator: "image", Variation: android.CoreVariation},
{Mutator: "link", Variation: linkType},
{Mutator: "version", Variation: version},
}...), dependencyTag, name)
}
}
}
}
@ -89,48 +106,25 @@ func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
return false
}
// copy exported header files and stub *.so files
func (mt *librarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
info := mt.organizeVariants(member)
buildSharedNativeLibSnapshot(sdkModuleContext, info, builder, member)
func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType)
ccModule := member.Variants()[0].(*Module)
sdkVersion := ccModule.SdkVersion()
if sdkVersion != "" {
pbm.AddProperty("sdk_version", sdkVersion)
}
stl := ccModule.stl.Properties.Stl
if stl != nil {
pbm.AddProperty("stl", proptools.String(stl))
}
return pbm
}
// Organize the variants by architecture.
func (mt *librarySdkMemberType) organizeVariants(member android.SdkMember) *nativeLibInfo {
memberName := member.Name()
info := &nativeLibInfo{
name: memberName,
memberType: mt,
}
for _, variant := range member.Variants() {
ccModule := variant.(*Module)
// Separate out the generated include dirs (which are arch specific) from the
// include dirs (which may not be).
exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
info.archVariantProperties = append(info.archVariantProperties, nativeLibInfoProperties{
name: memberName,
archType: ccModule.Target().Arch.ArchType.String(),
ExportedIncludeDirs: exportedIncludeDirs,
exportedGeneratedIncludeDirs: exportedGeneratedIncludeDirs,
ExportedSystemIncludeDirs: ccModule.ExportedSystemIncludeDirs(),
ExportedFlags: ccModule.ExportedFlags(),
exportedGeneratedHeaders: ccModule.ExportedGeneratedHeaders(),
outputFile: ccModule.OutputFile().Path(),
})
}
// Initialize the unexported properties that will not be set during the
// extraction process.
info.commonProperties.name = memberName
// Extract common properties from the arch specific properties.
extractCommonProperties(&info.commonProperties, info.archVariantProperties)
return info
func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &nativeLibInfoProperties{memberType: mt}
}
func isGeneratedHeaderDirectory(p android.Path) bool {
@ -138,144 +132,137 @@ func isGeneratedHeaderDirectory(p android.Path) bool {
return gen
}
// Extract common properties from a slice of property structures of the same type.
//
// All the property structures must be of the same type.
// commonProperties - must be a pointer to the structure into which common properties will be added.
// inputPropertiesSlice - must be a slice of input properties structures.
//
// Iterates over each exported field (capitalized name) and checks to see whether they
// have the same value (using DeepEquals) across all the input properties. If it does not then no
// change is made. Otherwise, the common value is stored in the field in the commonProperties
// and the field in each of the input properties structure is set to its default value.
func extractCommonProperties(commonProperties interface{}, inputPropertiesSlice interface{}) {
commonStructValue := reflect.ValueOf(commonProperties).Elem()
propertiesStructType := commonStructValue.Type()
type includeDirsProperty struct {
// Accessor to retrieve the paths
pathsGetter func(libInfo *nativeLibInfoProperties) android.Paths
// Create an empty structure from which default values for the field can be copied.
emptyStructValue := reflect.New(propertiesStructType).Elem()
// The name of the property in the prebuilt library, "" means there is no property.
propertyName string
for f := 0; f < propertiesStructType.NumField(); f++ {
// Check to see if all the structures have the same value for the field. The commonValue
// is nil on entry to the loop and if it is nil on exit then there is no common value,
// otherwise it points to the common value.
var commonValue *reflect.Value
sliceValue := reflect.ValueOf(inputPropertiesSlice)
// The directory within the snapshot directory into which items should be copied.
snapshotDir string
for i := 0; i < sliceValue.Len(); i++ {
structValue := sliceValue.Index(i)
fieldValue := structValue.Field(f)
if !fieldValue.CanInterface() {
// The field is not exported so ignore it.
continue
}
// True if the items on the path should be copied.
copy bool
if commonValue == nil {
// Use the first value as the commonProperties value.
commonValue = &fieldValue
} else {
// If the value does not match the current common value then there is
// no value in common so break out.
if !reflect.DeepEqual(fieldValue.Interface(), commonValue.Interface()) {
commonValue = nil
break
}
}
}
// If the fields all have a common value then store it in the common struct field
// and set the input struct's field to the empty value.
if commonValue != nil {
emptyValue := emptyStructValue.Field(f)
commonStructValue.Field(f).Set(*commonValue)
for i := 0; i < sliceValue.Len(); i++ {
structValue := sliceValue.Index(i)
fieldValue := structValue.Field(f)
fieldValue.Set(emptyValue)
}
}
}
// True if the paths represent directories, files if they represent files.
dirs bool
}
func buildSharedNativeLibSnapshot(sdkModuleContext android.ModuleContext, info *nativeLibInfo, builder android.SnapshotBuilder, member android.SdkMember) {
// a function for emitting include dirs
addExportedDirCopyCommandsForNativeLibs := func(lib nativeLibInfoProperties) {
// Do not include exportedGeneratedIncludeDirs in the list of directories whose
// contents are copied as they are copied from exportedGeneratedHeaders below.
includeDirs := lib.ExportedIncludeDirs
includeDirs = append(includeDirs, lib.ExportedSystemIncludeDirs...)
for _, dir := range includeDirs {
// lib.ArchType is "" for common properties.
targetDir := filepath.Join(lib.archType, nativeIncludeDir)
// TODO(jiyong) copy headers having other suffixes
headers, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.h", nil)
for _, file := range headers {
src := android.PathForSource(sdkModuleContext, file)
dest := filepath.Join(targetDir, file)
builder.CopyToSnapshot(src, dest)
}
}
genHeaders := lib.exportedGeneratedHeaders
for _, file := range genHeaders {
// lib.ArchType is "" for common properties.
targetDir := filepath.Join(lib.archType, nativeGeneratedIncludeDir)
dest := filepath.Join(targetDir, lib.name, file.Rel())
builder.CopyToSnapshot(file, dest)
}
}
addExportedDirCopyCommandsForNativeLibs(info.commonProperties)
// for each architecture
for _, av := range info.archVariantProperties {
builder.CopyToSnapshot(av.outputFile, nativeLibraryPathFor(av))
addExportedDirCopyCommandsForNativeLibs(av)
}
info.generatePrebuiltLibrary(sdkModuleContext, builder, member)
}
func (info *nativeLibInfo) generatePrebuiltLibrary(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
pbm := builder.AddPrebuiltModule(member, info.memberType.prebuiltModuleType)
addPossiblyArchSpecificProperties(info.commonProperties, pbm)
archProperties := pbm.AddPropertySet("arch")
for _, av := range info.archVariantProperties {
archTypeProperties := archProperties.AddPropertySet(av.archType)
// Add any arch specific properties inside the appropriate arch: {<arch>: {...}} block
archTypeProperties.AddProperty("srcs", []string{nativeLibraryPathFor(av)})
addPossiblyArchSpecificProperties(av, archTypeProperties)
}
pbm.AddProperty("stl", "none")
pbm.AddProperty("system_shared_libs", []string{})
var includeDirProperties = []includeDirsProperty{
{
// ExportedIncludeDirs lists directories that contains some header files to be
// copied into a directory in the snapshot. The snapshot directories must be added to
// the export_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
dirs: true,
},
{
// ExportedSystemIncludeDirs lists directories that contains some system header files to
// be copied into a directory in the snapshot. The snapshot directories must be added to
// the export_system_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.ExportedSystemIncludeDirs },
propertyName: "export_system_include_dirs",
snapshotDir: nativeIncludeDir,
copy: true,
dirs: true,
},
{
// exportedGeneratedIncludeDirs lists directories that contains some header files
// that are explicitly listed in the exportedGeneratedHeaders property. So, the contents
// of these directories do not need to be copied, but these directories do need adding to
// the export_include_dirs property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedIncludeDirs },
propertyName: "export_include_dirs",
snapshotDir: nativeGeneratedIncludeDir,
copy: false,
dirs: true,
},
{
// exportedGeneratedHeaders lists header files that are in one of the directories
// specified in exportedGeneratedIncludeDirs must be copied into the snapshot.
// As they are in a directory in exportedGeneratedIncludeDirs they do not need adding to a
// property in the prebuilt module in the snapshot.
pathsGetter: func(libInfo *nativeLibInfoProperties) android.Paths { return libInfo.exportedGeneratedHeaders },
propertyName: "",
snapshotDir: nativeGeneratedIncludeDir,
copy: true,
dirs: false,
},
}
// Add properties that may, or may not, be arch specific.
func addPossiblyArchSpecificProperties(libInfo nativeLibInfoProperties, outputProperties android.BpPropertySet) {
addExportedDirsForNativeLibs(libInfo, outputProperties, false /*systemInclude*/)
addExportedDirsForNativeLibs(libInfo, outputProperties, true /*systemInclude*/)
}
func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
// a function for emitting include dirs
func addExportedDirsForNativeLibs(lib nativeLibInfoProperties, properties android.BpPropertySet, systemInclude bool) {
includeDirs := nativeIncludeDirPathsFor(lib, systemInclude)
if len(includeDirs) == 0 {
return
// Copy the generated library to the snapshot and add a reference to it in the .bp module.
if libInfo.outputFile != nil {
nativeLibraryPath := nativeLibraryPathFor(libInfo)
builder.CopyToSnapshot(libInfo.outputFile, nativeLibraryPath)
outputProperties.AddProperty("srcs", []string{nativeLibraryPath})
}
var propertyName string
if !systemInclude {
propertyName = "export_include_dirs"
} else {
propertyName = "export_system_include_dirs"
if len(libInfo.SharedLibs) > 0 {
outputProperties.AddPropertyWithTag("shared_libs", libInfo.SharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
if len(libInfo.SystemSharedLibs) > 0 {
outputProperties.AddPropertyWithTag("system_shared_libs", libInfo.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
// Map from property name to the include dirs to add to the prebuilt module in the snapshot.
includeDirs := make(map[string][]string)
// Iterate over each include directory property, copying files and collating property
// values where necessary.
for _, propertyInfo := range includeDirProperties {
// Calculate the base directory in the snapshot into which the files will be copied.
// lib.ArchType is "" for common properties.
targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
propertyName := propertyInfo.propertyName
// Iterate over each path in one of the include directory properties.
for _, path := range propertyInfo.pathsGetter(libInfo) {
// Copy the files/directories when necessary.
if propertyInfo.copy {
if propertyInfo.dirs {
// When copying a directory glob and copy all the headers within it.
// TODO(jiyong) copy headers having other suffixes
headers, _ := sdkModuleContext.GlobWithDeps(path.String()+"/**/*.h", nil)
for _, file := range headers {
src := android.PathForSource(sdkModuleContext, file)
dest := filepath.Join(targetDir, file)
builder.CopyToSnapshot(src, dest)
}
} else {
// Otherwise, just copy the files.
dest := filepath.Join(targetDir, libInfo.name, path.Rel())
builder.CopyToSnapshot(path, dest)
}
}
// Only directories are added to a property.
if propertyInfo.dirs {
var snapshotPath string
if isGeneratedHeaderDirectory(path) {
snapshotPath = filepath.Join(targetDir, libInfo.name)
} else {
snapshotPath = filepath.Join(targetDir, path.String())
}
includeDirs[propertyName] = append(includeDirs[propertyName], snapshotPath)
}
}
}
// Add the collated include dir properties to the output.
for property, dirs := range includeDirs {
outputProperties.AddProperty(property, dirs)
}
properties.AddProperty(propertyName, includeDirs)
}
const (
@ -285,41 +272,20 @@ const (
)
// path to the native library. Relative to <sdk_root>/<api_dir>
func nativeLibraryPathFor(lib nativeLibInfoProperties) string {
return filepath.Join(lib.archType,
func nativeLibraryPathFor(lib *nativeLibInfoProperties) string {
return filepath.Join(lib.OsPrefix(), lib.archType,
nativeStubDir, lib.outputFile.Base())
}
// paths to the include dirs of a native shared library. Relative to <sdk_root>/<api_dir>
func nativeIncludeDirPathsFor(lib nativeLibInfoProperties, systemInclude bool) []string {
var result []string
var includeDirs []android.Path
if !systemInclude {
// Include the generated include dirs in the exported include dirs.
includeDirs = append(lib.ExportedIncludeDirs, lib.exportedGeneratedIncludeDirs...)
} else {
includeDirs = lib.ExportedSystemIncludeDirs
}
for _, dir := range includeDirs {
var path string
if isGeneratedHeaderDirectory(dir) {
path = filepath.Join(nativeGeneratedIncludeDir, lib.name)
} else {
path = filepath.Join(nativeIncludeDir, dir.String())
}
// lib.ArchType is "" for common properties.
path = filepath.Join(lib.archType, path)
result = append(result, path)
}
return result
}
// nativeLibInfoProperties represents properties of a native lib
//
// The exported (capitalized) fields will be examined and may be changed during common value extraction.
// The unexported fields will be left untouched.
type nativeLibInfoProperties struct {
android.SdkMemberPropertiesBase
memberType *librarySdkMemberType
// The name of the library, is not exported as this must not be changed during optimization.
name string
@ -352,14 +318,53 @@ type nativeLibInfoProperties struct {
// This field is exported as its contents may not be arch specific.
ExportedFlags []string
// The set of shared libraries
//
// This field is exported as its contents may not be arch specific.
SharedLibs []string
// The set of system shared libraries
//
// This field is exported as its contents may not be arch specific.
SystemSharedLibs []string
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
// nativeLibInfo represents a collection of arch-specific modules having the same name
type nativeLibInfo struct {
name string
memberType *librarySdkMemberType
archVariantProperties []nativeLibInfoProperties
commonProperties nativeLibInfoProperties
func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
ccModule := variant.(*Module)
// If the library has some link types then it produces an output binary file, otherwise it
// is header only.
if p.memberType.linkTypes != nil {
p.outputFile = ccModule.OutputFile().Path()
}
// Separate out the generated include dirs (which are arch specific) from the
// include dirs (which may not be).
exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate(
ccModule.ExportedIncludeDirs(), isGeneratedHeaderDirectory)
p.name = variant.Name()
p.archType = ccModule.Target().Arch.ArchType.String()
// Make sure that the include directories are unique.
p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
p.ExportedFlags = ccModule.ExportedFlags()
if ccModule.linker != nil {
specifiedDeps := specifiedDeps{}
specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
p.SharedLibs = specifiedDeps.sharedLibs
p.SystemSharedLibs = specifiedDeps.systemSharedLibs
}
p.exportedGeneratedHeaders = ccModule.ExportedGeneratedHeaders()
}
func (p *nativeLibInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
addPossiblyArchSpecificProperties(ctx.SdkModuleContext(), ctx.SnapshotBuilder(), p, propertySet)
}

View file

@ -490,6 +490,12 @@ func (linker *baseLinker) link(ctx ModuleContext,
panic(fmt.Errorf("baseLinker doesn't know how to link"))
}
func (linker *baseLinker) linkerSpecifiedDeps(specifiedDeps specifiedDeps) specifiedDeps {
specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, linker.Properties.Shared_libs...)
specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, linker.Properties.System_shared_libs...)
return specifiedDeps
}
// Injecting version symbols
// Some host modules want a version number, but we don't want to rebuild it every time. Optionally add a step
// after linking that injects a constant placeholder with the current version number.

View file

@ -23,6 +23,7 @@ func init() {
}
func RegisterPrebuiltBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
@ -96,10 +97,16 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
p.libraryDecorator.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
// TODO(ccross): verify shared library dependencies
if len(p.properties.Srcs) > 0 {
srcs := p.prebuiltSrcs()
if len(srcs) > 0 {
builderFlags := flagsToBuilderFlags(flags)
in := p.Prebuilt.SingleSourcePath(ctx)
if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
return nil
}
in := android.PathForModuleSrc(ctx, srcs[0])
if p.shared() {
p.unstrippedOutputFile = in
@ -123,6 +130,18 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
return nil
}
func (p *prebuiltLibraryLinker) prebuiltSrcs() []string {
srcs := p.properties.Srcs
if p.static() {
srcs = append(srcs, p.libraryDecorator.StaticProperties.Static.Srcs...)
}
if p.shared() {
srcs = append(srcs, p.libraryDecorator.SharedProperties.Shared.Srcs...)
}
return srcs
}
func (p *prebuiltLibraryLinker) shared() bool {
return p.libraryDecorator.shared()
}
@ -151,13 +170,28 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDec
module.AddProperties(&prebuilt.properties)
android.InitPrebuiltModule(module, &prebuilt.properties.Srcs)
srcsSupplier := func() []string {
return prebuilt.prebuiltSrcs()
}
android.InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
// Prebuilt libraries can be used in SDKs.
android.InitSdkAwareModule(module)
return module, library
}
// cc_prebuilt_library installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltLibraryFactory() android.Module {
module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
// Prebuilt shared libraries can be included in APEXes
android.InitApexModule(module)
return module.Init()
}
// cc_prebuilt_library_shared installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltSharedLibraryFactory() android.Module {

View file

@ -59,36 +59,38 @@ func TestPrebuilt(t *testing.T) {
name: "libe",
srcs: ["libe.a"],
}
cc_library {
name: "libf",
}
cc_prebuilt_library {
name: "libf",
static: {
srcs: ["libf.a"],
},
shared: {
srcs: ["libf.so"],
},
}
`
fs := map[string][]byte{
"liba.so": nil,
"libb.a": nil,
"libd.so": nil,
"libe.a": nil,
}
config := TestConfig(buildDir, android.Android, nil, bp, fs)
ctx := CreateTestContext()
ctx.Register(config)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
ctx := testPrebuilt(t, bp)
// Verify that all the modules exist and that their dependencies were connected correctly
liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module()
libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module()
libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module()
libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module()
libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module()
prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module()
prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module()
prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module()
prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module()
prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module()
prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module()
hasDep := func(m android.Module, wantDep android.Module) bool {
t.Helper()
@ -116,4 +118,89 @@ func TestPrebuilt(t *testing.T) {
if !hasDep(libe, prebuiltLibe) {
t.Errorf("libe missing dependency on prebuilt_libe")
}
if !hasDep(libfStatic, prebuiltLibfStatic) {
t.Errorf("libf static missing dependency on prebuilt_libf")
}
if !hasDep(libfShared, prebuiltLibfShared) {
t.Errorf("libf shared missing dependency on prebuilt_libf")
}
}
func testPrebuilt(t *testing.T, bp string) *android.TestContext {
fs := map[string][]byte{
"liba.so": nil,
"libb.a": nil,
"libd.so": nil,
"libe.a": nil,
"libf.a": nil,
"libf.so": nil,
}
config := TestConfig(buildDir, android.Android, nil, bp, fs)
ctx := CreateTestContext()
// Enable androidmk support.
// * Register the singleton
// * Configure that we are inside make
// * Add CommonOS to ensure that androidmk processing works.
android.RegisterAndroidMkBuildComponents(ctx)
android.SetInMakeForTests(config)
ctx.Register(config)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
android.FailIfErrored(t, errs)
return ctx
}
func TestPrebuiltLibraryShared(t *testing.T) {
ctx := testPrebuilt(t, `
cc_prebuilt_library_shared {
name: "libtest",
srcs: ["libf.so"],
strip: {
none: true,
},
}
`)
shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
assertString(t, shared.OutputFile().String(), "libf.so")
}
func TestPrebuiltLibraryStatic(t *testing.T) {
ctx := testPrebuilt(t, `
cc_prebuilt_library_static {
name: "libtest",
srcs: ["libf.a"],
}
`)
static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
assertString(t, static.OutputFile().String(), "libf.a")
}
func TestPrebuiltLibrary(t *testing.T) {
ctx := testPrebuilt(t, `
cc_prebuilt_library {
name: "libtest",
static: {
srcs: ["libf.a"],
},
shared: {
srcs: ["libf.so"],
},
strip: {
none: true,
},
}
`)
shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
assertString(t, shared.OutputFile().String(), "libf.so")
static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
assertString(t, static.OutputFile().String(), "libf.a")
}

View file

@ -34,7 +34,7 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
}
func GatherRequiredDepsForTest(os android.OsType) string {
func GatherRequiredDepsForTest(oses ...android.OsType) string {
ret := `
toolchain_library {
name: "libatomic",
@ -380,8 +380,9 @@ func GatherRequiredDepsForTest(os android.OsType) string {
}
`
if os == android.Fuchsia {
ret += `
for _, os := range oses {
if os == android.Fuchsia {
ret += `
cc_library {
name: "libbioniccompat",
stl: "none",
@ -391,6 +392,22 @@ func GatherRequiredDepsForTest(os android.OsType) string {
stl: "none",
}
`
}
if os == android.Windows {
ret += `
toolchain_library {
name: "libwinpthread",
host_supported: true,
enabled: false,
target: {
windows: {
enabled: true,
},
},
src: "",
}
`
}
}
return ret
}

View file

@ -1927,18 +1927,33 @@ func (mt *droidStubsSdkMemberType) IsInstance(module android.Module) bool {
return ok
}
func (mt *droidStubsSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
variants := member.Variants()
if len(variants) != 1 {
sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
}
variant := variants[0]
d, _ := variant.(*Droidstubs)
stubsSrcJar := d.stubsSrcJar
snapshotRelativeDir := filepath.Join("java", d.Name()+"_stubs_sources")
builder.UnzipToSnapshot(stubsSrcJar, snapshotRelativeDir)
pbm := builder.AddPrebuiltModule(member, "prebuilt_stubs_sources")
pbm.AddProperty("srcs", []string{snapshotRelativeDir})
func (mt *droidStubsSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_stubs_sources")
}
func (mt *droidStubsSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &droidStubsInfoProperties{}
}
type droidStubsInfoProperties struct {
android.SdkMemberPropertiesBase
StubsSrcJar android.Path
}
func (p *droidStubsInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
droidstubs := variant.(*Droidstubs)
p.StubsSrcJar = droidstubs.stubsSrcJar
}
func (p *droidStubsInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
if p.StubsSrcJar != nil {
builder := ctx.SnapshotBuilder()
snapshotRelativeDir := filepath.Join("java", ctx.Name()+"_stubs_sources")
builder.UnzipToSnapshot(p.StubsSrcJar, snapshotRelativeDir)
propertySet.AddProperty("srcs", []string{snapshotRelativeDir})
}
}

View file

@ -39,11 +39,17 @@ func init() {
// Register sdk member types.
android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
android.RegisterSdkMemberType(&implLibrarySdkMemberType{
librarySdkMemberType{
android.SdkMemberTypeBase{
PropertyName: "java_libs",
},
android.RegisterSdkMemberType(&librarySdkMemberType{
android.SdkMemberTypeBase{
PropertyName: "java_libs",
},
func(j *Library) android.Path {
implementationJars := j.ImplementationJars()
if len(implementationJars) != 1 {
panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
}
return implementationJars[0]
},
})
@ -1860,16 +1866,20 @@ const (
)
// path to the jar file of a java library. Relative to <sdk_root>/<api_dir>
func sdkSnapshotFilePathForJar(member android.SdkMember) string {
return sdkSnapshotFilePathForMember(member, jarFileSuffix)
func sdkSnapshotFilePathForJar(osPrefix, name string) string {
return sdkSnapshotFilePathForMember(osPrefix, name, jarFileSuffix)
}
func sdkSnapshotFilePathForMember(member android.SdkMember, suffix string) string {
return filepath.Join(javaDir, member.Name()+suffix)
func sdkSnapshotFilePathForMember(osPrefix, name string, suffix string) string {
return filepath.Join(javaDir, osPrefix, name+suffix)
}
type librarySdkMemberType struct {
android.SdkMemberTypeBase
// Function to retrieve the appropriate output jar (implementation or header) from
// the library.
jarToExportGetter func(j *Library) android.Path
}
func (mt *librarySdkMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
@ -1881,75 +1891,67 @@ func (mt *librarySdkMemberType) IsInstance(module android.Module) bool {
return ok
}
func (mt *librarySdkMemberType) buildSnapshot(
sdkModuleContext android.ModuleContext,
builder android.SnapshotBuilder,
member android.SdkMember,
jarToExportGetter func(j *Library) android.Path) {
func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_import")
}
variants := member.Variants()
if len(variants) != 1 {
sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
for _, variant := range variants {
sdkModuleContext.ModuleErrorf(" %q", variant)
}
}
variant := variants[0]
func (mt *librarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &librarySdkMemberProperties{}
}
type librarySdkMemberProperties struct {
android.SdkMemberPropertiesBase
JarToExport android.Path
AidlIncludeDirs android.Paths
}
func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
j := variant.(*Library)
exportedJar := jarToExportGetter(j)
snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(j)
p.AidlIncludeDirs = j.AidlIncludeDirs()
}
for _, dir := range j.AidlIncludeDirs() {
// TODO(jiyong): copy parcelable declarations only
aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
for _, file := range aidlFiles {
builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
}
func (p *librarySdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
builder := ctx.SnapshotBuilder()
exportedJar := p.JarToExport
if exportedJar != nil {
snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
module := builder.AddPrebuiltModule(member, "java_import")
module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
aidlIncludeDirs := p.AidlIncludeDirs
if len(aidlIncludeDirs) != 0 {
sdkModuleContext := ctx.SdkModuleContext()
for _, dir := range aidlIncludeDirs {
// TODO(jiyong): copy parcelable declarations only
aidlFiles, _ := sdkModuleContext.GlobWithDeps(dir.String()+"/**/*.aidl", nil)
for _, file := range aidlFiles {
builder.CopyToSnapshot(android.PathForSource(sdkModuleContext, file), filepath.Join(aidlIncludeDir, file))
}
}
// TODO(b/151933053) - add aidl include dirs property
}
}
var javaHeaderLibsSdkMemberType android.SdkMemberType = &headerLibrarySdkMemberType{
librarySdkMemberType{
android.SdkMemberTypeBase{
PropertyName: "java_header_libs",
SupportsSdk: true,
},
var javaHeaderLibsSdkMemberType android.SdkMemberType = &librarySdkMemberType{
android.SdkMemberTypeBase{
PropertyName: "java_header_libs",
SupportsSdk: true,
},
}
type headerLibrarySdkMemberType struct {
librarySdkMemberType
}
func (mt *headerLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
func(j *Library) android.Path {
headerJars := j.HeaderJars()
if len(headerJars) != 1 {
panic(fmt.Errorf("there must be only one header jar from %q", j.Name()))
}
return headerJars[0]
})
}
type implLibrarySdkMemberType struct {
librarySdkMemberType
}
func (mt *implLibrarySdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
mt.librarySdkMemberType.buildSnapshot(sdkModuleContext, builder, member, func(j *Library) android.Path {
implementationJars := j.ImplementationJars()
if len(implementationJars) != 1 {
panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
}
return implementationJars[0]
})
},
}
// java_library builds and links sources into a `.jar` file for the device, and possibly for the host as well.
@ -2100,31 +2102,50 @@ func (mt *testSdkMemberType) IsInstance(module android.Module) bool {
return ok
}
func (mt *testSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
variants := member.Variants()
if len(variants) != 1 {
sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
for _, variant := range variants {
sdkModuleContext.ModuleErrorf(" %q", variant)
}
}
variant := variants[0]
j := variant.(*Test)
func (mt *testSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_test_import")
}
implementationJars := j.ImplementationJars()
func (mt *testSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &testSdkMemberProperties{}
}
type testSdkMemberProperties struct {
android.SdkMemberPropertiesBase
JarToExport android.Path
TestConfig android.Path
}
func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
test := variant.(*Test)
implementationJars := test.ImplementationJars()
if len(implementationJars) != 1 {
panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name()))
}
snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(member)
builder.CopyToSnapshot(implementationJars[0], snapshotRelativeJavaLibPath)
p.JarToExport = implementationJars[0]
p.TestConfig = test.testConfig
}
snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(member, testConfigSuffix)
builder.CopyToSnapshot(j.testConfig, snapshotRelativeTestConfigPath)
func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
builder := ctx.SnapshotBuilder()
module := builder.AddPrebuiltModule(member, "java_test_import")
module.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
module.AddProperty("test_config", snapshotRelativeTestConfigPath)
exportedJar := p.JarToExport
if exportedJar != nil {
snapshotRelativeJavaLibPath := sdkSnapshotFilePathForJar(p.OsPrefix(), ctx.Name())
builder.CopyToSnapshot(exportedJar, snapshotRelativeJavaLibPath)
propertySet.AddProperty("jars", []string{snapshotRelativeJavaLibPath})
}
testConfig := p.TestConfig
if testConfig != nil {
snapshotRelativeTestConfigPath := sdkSnapshotFilePathForMember(p.OsPrefix(), ctx.Name(), testConfigSuffix)
builder.CopyToSnapshot(testConfig, snapshotRelativeTestConfigPath)
propertySet.AddProperty("test_config", snapshotRelativeTestConfigPath)
}
}
// java_test builds a and links sources into a `.jar` file for the device, and possibly for the host as well, and
@ -2327,7 +2348,7 @@ func BinaryHostFactory() android.Module {
//
type ImportProperties struct {
Jars []string `android:"path"`
Jars []string `android:"path,arch_variant"`
Sdk_version *string

View file

@ -451,7 +451,7 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc
mctx.CreateModule(LibraryFactory, &props)
}
// Creates a droiddoc module that creates stubs source files from the given full source
// Creates a droidstubs module that creates stubs source files from the given full source
// files
func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiScope *apiScope) {
props := struct {
@ -506,15 +506,15 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc
props.Merge_annotations_dirs = module.sdkLibraryProperties.Merge_annotations_dirs
props.Merge_inclusion_annotations_dirs = module.sdkLibraryProperties.Merge_inclusion_annotations_dirs
droiddocArgs := []string{}
droidstubsArgs := []string{}
if len(module.sdkLibraryProperties.Api_packages) != 0 {
droiddocArgs = append(droiddocArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
droidstubsArgs = append(droidstubsArgs, "--stub-packages "+strings.Join(module.sdkLibraryProperties.Api_packages, ":"))
}
if len(module.sdkLibraryProperties.Hidden_api_packages) != 0 {
droiddocArgs = append(droiddocArgs,
droidstubsArgs = append(droidstubsArgs,
android.JoinWithPrefix(module.sdkLibraryProperties.Hidden_api_packages, " --hide-package "))
}
droiddocArgs = append(droiddocArgs, module.sdkLibraryProperties.Droiddoc_options...)
droidstubsArgs = append(droidstubsArgs, module.sdkLibraryProperties.Droiddoc_options...)
disabledWarnings := []string{
"MissingPermission",
"BroadcastBehavior",
@ -526,16 +526,16 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc
"Todo",
"Typo",
}
droiddocArgs = append(droiddocArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
switch apiScope {
case apiScopeSystem:
droiddocArgs = append(droiddocArgs, "-showAnnotation android.annotation.SystemApi")
droidstubsArgs = append(droidstubsArgs, "-showAnnotation android.annotation.SystemApi")
case apiScopeTest:
droiddocArgs = append(droiddocArgs, " -showAnnotation android.annotation.TestApi")
droidstubsArgs = append(droidstubsArgs, " -showAnnotation android.annotation.TestApi")
}
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
props.Args = proptools.StringPtr(strings.Join(droiddocArgs, " "))
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
// List of APIs identified from the provided source files are created. They are later
// compared against to the not-yet-released (a.k.a current) list of APIs and to the

View file

@ -242,18 +242,28 @@ func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool {
return false
}
func (mt *systemModulesSdkMemberType) BuildSnapshot(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, member android.SdkMember) {
variants := member.Variants()
if len(variants) != 1 {
sdkModuleContext.ModuleErrorf("sdk contains %d variants of member %q but only one is allowed", len(variants), member.Name())
for _, variant := range variants {
sdkModuleContext.ModuleErrorf(" %q", variant)
}
}
variant := variants[0]
systemModule := variant.(*SystemModules)
pbm := builder.AddPrebuiltModule(member, "java_system_modules_import")
// Add the references to the libraries that form the system module.
pbm.AddPropertyWithTag("libs", systemModule.properties.Libs, builder.SdkMemberReferencePropertyTag())
func (mt *systemModulesSdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
return ctx.SnapshotBuilder().AddPrebuiltModule(member, "java_system_modules_import")
}
type systemModulesInfoProperties struct {
android.SdkMemberPropertiesBase
Libs []string
}
func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
return &systemModulesInfoProperties{}
}
func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
systemModule := variant.(*SystemModules)
p.Libs = systemModule.properties.Libs
}
func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
if len(p.Libs) > 0 {
// Add the references to the libraries that form the system module.
propertySet.AddPropertyWithTag("libs", p.Libs, ctx.SnapshotBuilder().SdkMemberReferencePropertyTag(true))
}
}

View file

@ -35,7 +35,7 @@ func (s *bpPropertySet) init() {
func (s *bpPropertySet) AddProperty(name string, value interface{}) {
if s.properties[name] != nil {
panic("Property %q already exists in property set")
panic(fmt.Sprintf("Property %q already exists in property set", name))
}
s.properties[name] = value
@ -48,8 +48,7 @@ func (s *bpPropertySet) AddPropertyWithTag(name string, value interface{}, tag a
}
func (s *bpPropertySet) AddPropertySet(name string) android.BpPropertySet {
set := &bpPropertySet{}
set.init()
set := newPropertySet()
s.AddProperty(name, set)
return set
}
@ -62,7 +61,7 @@ func (s *bpPropertySet) getTag(name string) interface{} {
return s.tags[name]
}
func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
var newOrder []string
for _, name := range s.order {
value := s.properties[name]
@ -70,7 +69,13 @@ func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
var newValue interface{}
var newTag android.BpPropertyTag
if propertySet, ok := value.(*bpPropertySet); ok {
newValue, newTag = transformer.transformPropertySet(name, propertySet, tag)
var newPropertySet *bpPropertySet
newPropertySet, newTag = transformPropertySet(transformer, name, propertySet, tag)
if newPropertySet == nil {
newValue = nil
} else {
newValue = newPropertySet
}
} else {
newValue, newTag = transformer.transformProperty(name, value, tag)
}
@ -88,6 +93,16 @@ func (s *bpPropertySet) transform(transformer bpPropertyTransformer) {
s.order = newOrder
}
func transformPropertySet(transformer bpPropertyTransformer, name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
newPropertySet, newTag := transformer.transformPropertySetBeforeContents(name, propertySet, tag)
if newPropertySet != nil {
newPropertySet.transformContents(transformer)
newPropertySet, newTag = transformer.transformPropertySetAfterContents(name, newPropertySet, newTag)
}
return newPropertySet, newTag
}
func (s *bpPropertySet) setProperty(name string, value interface{}) {
if s.properties[name] == nil {
s.AddProperty(name, value)
@ -136,7 +151,17 @@ type bpPropertyTransformer interface {
// The name will be "" for the top level property set.
//
// Returning (nil, ...) will cause the property set to be removed.
transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
// Transform the property set, returning the new property set/tag to insert back into the
// parent property set (or module if this is the top level property set).
//
// This will be called after transforming the properties in the supplied set.
//
// The name will be "" for the top level property set.
//
// Returning (nil, ...) will cause the property set to be removed.
transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag)
// Transform a property, return the new value/tag to insert back into the property set.
//
@ -165,7 +190,11 @@ func (t identityTransformation) transformModule(module *bpModule) *bpModule {
return module
}
func (t identityTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
func (t identityTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
return propertySet, tag
}
func (t identityTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
return propertySet, tag
}
@ -180,12 +209,13 @@ func (m *bpModule) deepCopy() *bpModule {
func (m *bpModule) transform(transformer bpTransformer) *bpModule {
transformedModule := transformer.transformModule(m)
// Copy the contents of the returned property set into the module and then transform that.
transformedModule.bpPropertySet, _ = transformer.transformPropertySet("", transformedModule.bpPropertySet, nil)
transformedModule.bpPropertySet.transform(transformer)
transformedModule.bpPropertySet, _ = transformPropertySet(transformer, "", transformedModule.bpPropertySet, nil)
return transformedModule
}
type deepCopyTransformation struct{}
type deepCopyTransformation struct {
identityTransformation
}
func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
// Take a shallow copy of the module. Any mutable property values will be copied by the
@ -194,7 +224,7 @@ func (t deepCopyTransformation) transformModule(module *bpModule) *bpModule {
return &moduleCopy
}
func (t deepCopyTransformation) transformPropertySet(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
func (t deepCopyTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
// Create a shallow copy of the properties map. Any mutable property values will be copied by the
// transformer.
propertiesCopy := make(map[string]interface{})
@ -253,10 +283,19 @@ func (f *bpFile) AddModule(module android.BpModule) {
}
func (f *bpFile) newModule(moduleType string) *bpModule {
return newModule(moduleType)
}
func newModule(moduleType string) *bpModule {
module := &bpModule{
moduleType: moduleType,
bpPropertySet: &bpPropertySet{},
bpPropertySet: newPropertySet(),
}
module.bpPropertySet.init()
return module
}
func newPropertySet() *bpPropertySet {
set := &bpPropertySet{}
set.init()
return set
}

76
sdk/bp_test.go Normal file
View file

@ -0,0 +1,76 @@
// Copyright (C) 2020 The Android Open Source Project
//
// 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 sdk
import (
"testing"
"android/soong/android"
)
type removeFredTransformation struct {
identityTransformation
}
func (t removeFredTransformation) transformProperty(name string, value interface{}, tag android.BpPropertyTag) (interface{}, android.BpPropertyTag) {
if name == "fred" {
return nil, nil
}
return value, tag
}
func (t removeFredTransformation) transformPropertySetBeforeContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
if name == "fred" {
return nil, nil
}
return propertySet, tag
}
func (t removeFredTransformation) transformPropertySetAfterContents(name string, propertySet *bpPropertySet, tag android.BpPropertyTag) (*bpPropertySet, android.BpPropertyTag) {
if len(propertySet.properties) == 0 {
return nil, nil
}
return propertySet, tag
}
func TestTransformRemoveProperty(t *testing.T) {
helper := &TestHelper{t}
set := newPropertySet()
set.AddProperty("name", "name")
set.AddProperty("fred", "12")
set.transformContents(removeFredTransformation{})
contents := &generatedContents{}
outputPropertySet(contents, set)
helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\\n", contents.content.String())
}
func TestTransformRemovePropertySet(t *testing.T) {
helper := &TestHelper{t}
set := newPropertySet()
set.AddProperty("name", "name")
set.AddPropertySet("fred")
set.transformContents(removeFredTransformation{})
contents := &generatedContents{}
outputPropertySet(contents, set)
helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\\n", contents.content.String())
}

File diff suppressed because it is too large Load diff

View file

@ -42,7 +42,7 @@ func TestModuleExportsSnapshot(t *testing.T) {
"package/Android.bp": []byte(packageBp),
})
result.CheckSnapshot("myexports", "android_common", "package",
result.CheckSnapshot("myexports", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.

View file

@ -141,7 +141,7 @@ func TestSnapshotWithJavaHeaderLibrary(t *testing.T) {
}
`)
result.CheckSnapshot("mysdk", "android_common", "",
result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -196,7 +196,7 @@ func TestHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
}
`)
result.CheckSnapshot("mysdk", "linux_glibc_common", "",
result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -230,6 +230,72 @@ aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
)
}
func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
result := testSdkWithJava(t, `
sdk {
name: "mysdk",
host_supported: true,
java_header_libs: ["myjavalib"],
}
java_library {
name: "myjavalib",
host_supported: true,
srcs: ["Test.java"],
system_modules: "none",
sdk_version: "none",
compile_dex: true,
}
`)
result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
java_import {
name: "mysdk_myjavalib@current",
sdk_member_name: "myjavalib",
host_supported: true,
target: {
android: {
jars: ["java/android/myjavalib.jar"],
},
linux_glibc: {
jars: ["java/linux_glibc/myjavalib.jar"],
},
},
}
java_import {
name: "myjavalib",
prefer: false,
host_supported: true,
target: {
android: {
jars: ["java/android/myjavalib.jar"],
},
linux_glibc: {
jars: ["java/linux_glibc/myjavalib.jar"],
},
},
}
sdk_snapshot {
name: "mysdk@current",
host_supported: true,
java_header_libs: ["mysdk_myjavalib@current"],
}
`),
checkAllCopyRules(`
.intermediates/myjavalib/android_common/turbine-combined/myjavalib.jar -> java/android/myjavalib.jar
.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
`),
)
}
func TestSnapshotWithJavaImplLibrary(t *testing.T) {
result := testSdkWithJava(t, `
module_exports {
@ -250,7 +316,7 @@ func TestSnapshotWithJavaImplLibrary(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "android_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -305,7 +371,7 @@ func TestHostSnapshotWithJavaImplLibrary(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "linux_glibc_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -356,7 +422,7 @@ func TestSnapshotWithJavaTest(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "android_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -409,7 +475,7 @@ func TestHostSnapshotWithJavaTest(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "linux_glibc_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -503,7 +569,7 @@ func TestSnapshotWithDroidstubs(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "android_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -526,7 +592,7 @@ module_exports_snapshot {
`),
checkAllCopyRules(""),
checkMergeZip(".intermediates/myexports/android_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@ -552,7 +618,7 @@ func TestHostSnapshotWithDroidstubs(t *testing.T) {
}
`)
result.CheckSnapshot("myexports", "linux_glibc_common", "",
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -580,7 +646,7 @@ module_exports_snapshot {
}
`),
checkAllCopyRules(""),
checkMergeZip(".intermediates/myexports/linux_glibc_common/tmp/java/myjavaapistubs_stubs_sources.zip"),
checkMergeZip(".intermediates/myexports/common_os/tmp/java/myjavaapistubs_stubs_sources.zip"),
)
}
@ -612,7 +678,7 @@ func TestSnapshotWithJavaSystemModules(t *testing.T) {
}
`)
result.CheckSnapshot("mysdk", "android_common", "",
result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -702,7 +768,7 @@ func TestHostSnapshotWithJavaSystemModules(t *testing.T) {
}
`)
result.CheckSnapshot("mysdk", "linux_glibc_common", "",
result.CheckSnapshot("mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -750,3 +816,126 @@ sdk_snapshot {
checkAllCopyRules(".intermediates/system-module/linux_glibc_common/javac/system-module.jar -> java/system-module.jar"),
)
}
func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
// b/145598135 - Generating host snapshots for anything other than linux is not supported.
SkipIfNotLinux(t)
result := testSdkWithJava(t, `
module_exports {
name: "myexports",
host_supported: true,
java_libs: ["myjavalib"],
target: {
android: {
java_header_libs: ["androidjavalib"],
},
host: {
java_header_libs: ["hostjavalib"],
},
},
}
java_library {
name: "myjavalib",
host_supported: true,
srcs: ["Test.java"],
system_modules: "none",
sdk_version: "none",
}
java_library {
name: "androidjavalib",
srcs: ["Test.java"],
system_modules: "none",
sdk_version: "none",
}
java_library_host {
name: "hostjavalib",
srcs: ["Test.java"],
}
`)
result.CheckSnapshot("myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
java_import {
name: "myexports_hostjavalib@current",
sdk_member_name: "hostjavalib",
device_supported: false,
host_supported: true,
jars: ["java/hostjavalib.jar"],
}
java_import {
name: "hostjavalib",
prefer: false,
device_supported: false,
host_supported: true,
jars: ["java/hostjavalib.jar"],
}
java_import {
name: "myexports_androidjavalib@current",
sdk_member_name: "androidjavalib",
jars: ["java/androidjavalib.jar"],
}
java_import {
name: "androidjavalib",
prefer: false,
jars: ["java/androidjavalib.jar"],
}
java_import {
name: "myexports_myjavalib@current",
sdk_member_name: "myjavalib",
host_supported: true,
target: {
android: {
jars: ["java/android/myjavalib.jar"],
},
linux_glibc: {
jars: ["java/linux_glibc/myjavalib.jar"],
},
},
}
java_import {
name: "myjavalib",
prefer: false,
host_supported: true,
target: {
android: {
jars: ["java/android/myjavalib.jar"],
},
linux_glibc: {
jars: ["java/linux_glibc/myjavalib.jar"],
},
},
}
module_exports_snapshot {
name: "myexports@current",
host_supported: true,
java_libs: ["myexports_myjavalib@current"],
target: {
android: {
java_header_libs: ["myexports_androidjavalib@current"],
},
linux_glibc: {
java_header_libs: ["myexports_hostjavalib@current"],
},
},
}
`),
checkAllCopyRules(`
.intermediates/hostjavalib/linux_glibc_common/javac/hostjavalib.jar -> java/hostjavalib.jar
.intermediates/androidjavalib/android_common/turbine-combined/androidjavalib.jar -> java/androidjavalib.jar
.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/android/myjavalib.jar
.intermediates/myjavalib/linux_glibc_common/javac/myjavalib.jar -> java/linux_glibc/myjavalib.jar
`),
)
}

View file

@ -50,8 +50,17 @@ type sdk struct {
// list properties, e.g. java_libs.
dynamicMemberTypeListProperties interface{}
// The set of exported members.
exportedMembers map[string]struct{}
// Information about the OsType specific member variants associated with this variant.
//
// Set by OsType specific variants in the collectMembers() method and used by the
// CommonOS variant when building the snapshot. That work is all done on separate
// calls to the sdk.GenerateAndroidBuildActions method which is guaranteed to be
// called for the OsType specific variants before the CommonOS variant (because
// the latter depends on the former).
memberRefs []sdkMemberRef
// The multilib variants that are used by this sdk variant.
multilibUsages multilibUsage
properties sdkProperties
@ -143,6 +152,7 @@ func createDynamicSdkMemberTypes(sdkMemberTypes []android.SdkMemberType) *dynami
fields = append(fields, reflect.StructField{
Name: proptools.FieldNameForProperty(p),
Type: reflect.TypeOf([]string{}),
Tag: `android:"arch_variant"`,
})
// Copy the field index for use in the getter func as using the loop variable directly will
@ -201,7 +211,7 @@ func newSdkModule(moduleExports bool) *sdk {
// properties for the member type specific list properties.
s.dynamicMemberTypeListProperties = s.dynamicSdkMemberTypes.createMemberListProperties()
s.AddProperties(&s.properties, s.dynamicMemberTypeListProperties)
android.InitAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitCommonOSAndroidMultiTargetsArchModule(s, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(s)
android.AddLoadHook(s, func(ctx android.LoadHookContext) {
type props struct {
@ -225,26 +235,19 @@ func (s *sdk) memberListProperties() []*sdkMemberListProperty {
}
func (s *sdk) getExportedMembers() map[string]struct{} {
if s.exportedMembers == nil {
// Collect all the exported members.
s.exportedMembers = make(map[string]struct{})
// Collect all the exported members.
exportedMembers := make(map[string]struct{})
for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
// Every member specified explicitly in the properties is exported by the sdk.
for _, name := range names {
s.exportedMembers[name] = struct{}{}
}
// Every member specified explicitly in the properties is exported by the sdk.
for _, name := range names {
exportedMembers[name] = struct{}{}
}
}
return s.exportedMembers
}
func (s *sdk) isInternalMember(memberName string) bool {
_, ok := s.getExportedMembers()[memberName]
return !ok
return exportedMembers
}
func (s *sdk) snapshot() bool {
@ -252,10 +255,31 @@ func (s *sdk) snapshot() bool {
}
func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if !s.snapshot() {
if s.snapshot() {
// We don't need to create a snapshot out of sdk_snapshot.
// That doesn't make sense. We need a snapshot to create sdk_snapshot.
s.snapshotFile = android.OptionalPathForPath(s.buildSnapshot(ctx))
return
}
// This method is guaranteed to be called on OsType specific variants before it is called
// on their corresponding CommonOS variant.
if !s.IsCommonOSVariant() {
// Update the OsType specific sdk variant with information about its members.
s.collectMembers(ctx)
} else {
// Get the OsType specific variants on which the CommonOS depends.
osSpecificVariants := android.GetOsSpecificVariantsOfCommonOSVariant(ctx)
var sdkVariants []*sdk
for _, m := range osSpecificVariants {
if sdkVariant, ok := m.(*sdk); ok {
sdkVariants = append(sdkVariants, sdkVariant)
}
}
// Generate the snapshot from the member info.
p := s.buildSnapshot(ctx, sdkVariants)
s.snapshotFile = android.OptionalPathForPath(p)
ctx.InstallFile(android.PathForMainlineSdksInstall(ctx), s.Name()+"-current.zip", p)
}
}
@ -320,11 +344,14 @@ func (t sdkMemberVersionedDepTag) ExcludeFromVisibilityEnforcement() {}
// Step 1: create dependencies from an SDK module to its members.
func memberMutator(mctx android.BottomUpMutatorContext) {
if s, ok := mctx.Module().(*sdk); ok {
if s.Enabled() {
// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
if s.Enabled() && !s.IsCommonOSVariant() {
for _, memberListProperty := range s.memberListProperties() {
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
tag := memberListProperty.dependencyTag
memberListProperty.memberType.AddDependencies(mctx, tag, names)
if len(names) > 0 {
tag := memberListProperty.dependencyTag
memberListProperty.memberType.AddDependencies(mctx, tag, names)
}
}
}
}

View file

@ -16,6 +16,8 @@ package sdk
import (
"testing"
"github.com/google/blueprint/proptools"
)
// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
@ -146,7 +148,7 @@ func TestSnapshotVisibility(t *testing.T) {
"package/Android.bp": []byte(packageBp),
})
result.CheckSnapshot("mysdk", "android_common", "package",
result.CheckSnapshot("mysdk", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@ -206,3 +208,122 @@ sdk_snapshot {
}
`))
}
func TestSDkInstall(t *testing.T) {
sdk := `
sdk {
name: "mysdk",
}
`
result := testSdkWithFs(t, ``,
map[string][]byte{
"Android.bp": []byte(sdk),
})
result.CheckSnapshot("mysdk", "",
checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
)
}
type EmbeddedPropertiesStruct struct {
S_Embedded_Common string
S_Embedded_Different string
}
type testPropertiesStruct struct {
private string
Public_Kept string `sdk:"keep"`
S_Common string
S_Different string
A_Common []string
A_Different []string
F_Common *bool
F_Different *bool
EmbeddedPropertiesStruct
}
func TestCommonValueOptimization(t *testing.T) {
common := &testPropertiesStruct{}
structs := []*testPropertiesStruct{
&testPropertiesStruct{
private: "common",
Public_Kept: "common",
S_Common: "common",
S_Different: "upper",
A_Common: []string{"first", "second"},
A_Different: []string{"alpha", "beta"},
F_Common: proptools.BoolPtr(false),
F_Different: proptools.BoolPtr(false),
EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
S_Embedded_Common: "embedded_common",
S_Embedded_Different: "embedded_upper",
},
},
&testPropertiesStruct{
private: "common",
Public_Kept: "common",
S_Common: "common",
S_Different: "lower",
A_Common: []string{"first", "second"},
A_Different: []string{"alpha", "delta"},
F_Common: proptools.BoolPtr(false),
F_Different: proptools.BoolPtr(true),
EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
S_Embedded_Common: "embedded_common",
S_Embedded_Different: "embedded_lower",
},
},
}
extractor := newCommonValueExtractor(common)
extractor.extractCommonProperties(common, structs)
h := TestHelper{t}
h.AssertDeepEquals("common properties not correct", common,
&testPropertiesStruct{
private: "",
Public_Kept: "",
S_Common: "common",
S_Different: "",
A_Common: []string{"first", "second"},
A_Different: []string(nil),
F_Common: proptools.BoolPtr(false),
F_Different: nil,
EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
S_Embedded_Common: "embedded_common",
S_Embedded_Different: "",
},
})
h.AssertDeepEquals("updated properties[0] not correct", structs[0],
&testPropertiesStruct{
private: "common",
Public_Kept: "common",
S_Common: "",
S_Different: "upper",
A_Common: nil,
A_Different: []string{"alpha", "beta"},
F_Common: nil,
F_Different: proptools.BoolPtr(false),
EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
S_Embedded_Common: "",
S_Embedded_Different: "embedded_upper",
},
})
h.AssertDeepEquals("updated properties[1] not correct", structs[1],
&testPropertiesStruct{
private: "common",
Public_Kept: "common",
S_Common: "",
S_Different: "lower",
A_Common: nil,
A_Different: []string{"alpha", "delta"},
F_Common: nil,
F_Different: proptools.BoolPtr(true),
EmbeddedPropertiesStruct: EmbeddedPropertiesStruct{
S_Embedded_Common: "",
S_Embedded_Different: "embedded_lower",
},
})
}

View file

@ -19,6 +19,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strings"
"testing"
@ -40,7 +41,7 @@ func testSdkContext(bp string, fs map[string][]byte) (*android.TestContext, andr
name: "myapex.cert",
certificate: "myapex",
}
` + cc.GatherRequiredDepsForTest(android.Android)
` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
mockFS := map[string][]byte{
"build/make/target/product/security": nil,
@ -61,8 +62,24 @@ func testSdkContext(bp string, fs map[string][]byte) (*android.TestContext, andr
config := android.TestArchConfig(buildDir, nil, bp, mockFS)
// Add windows as a default disable OS to test behavior when some OS variants
// are disabled.
config.Targets[android.Windows] = []android.Target{
{android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
}
ctx := android.NewTestArchContext()
// Enable androidmk support.
// * Register the singleton
// * Configure that we are inside make
// * Add CommonOS to ensure that androidmk processing works.
android.RegisterAndroidMkBuildComponents(ctx)
android.SetInMakeForTests(config)
config.Targets[android.CommonOS] = []android.Target{
{android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", ""},
}
// from android package
android.RegisterPackageBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
@ -160,6 +177,13 @@ func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string,
h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
}
func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
h.t.Helper()
if !reflect.DeepEqual(actual, expected) {
h.t.Errorf("%s: expected %#v, actual %#v", message, expected, actual)
}
}
// Encapsulates result of processing an SDK definition. Provides support for
// checking the state of the build structures.
type testSdkResult struct {
@ -182,15 +206,23 @@ func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo {
buildParams := sdk.BuildParamsForTests()
copyRules := &strings.Builder{}
otherCopyRules := &strings.Builder{}
snapshotDirPrefix := sdk.builderForTests.snapshotDir.String() + "/"
for _, bp := range buildParams {
switch bp.Rule.String() {
case android.Cp.String():
// Get source relative to build directory.
src := android.NormalizePathForTesting(bp.Input)
output := bp.Output
// Get destination relative to the snapshot root
dest := bp.Output.Rel()
_, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
info.snapshotContents = append(info.snapshotContents, dest)
dest := output.Rel()
src := android.NormalizePathForTesting(bp.Input)
// We differentiate between copy rules for the snapshot, and copy rules for the install file.
if strings.HasPrefix(output.String(), snapshotDirPrefix) {
// Get source relative to build directory.
_, _ = fmt.Fprintf(copyRules, "%s -> %s\n", src, dest)
info.snapshotContents = append(info.snapshotContents, dest)
} else {
_, _ = fmt.Fprintf(otherCopyRules, "%s -> %s\n", src, dest)
}
case repackageZip.String():
// Add the destdir to the snapshot contents as that is effectively where
@ -223,6 +255,7 @@ func (r *testSdkResult) getSdkSnapshotBuildInfo(sdk *sdk) *snapshotBuildInfo {
}
info.copyRules = copyRules.String()
info.otherCopyRules = otherCopyRules.String()
return info
}
@ -240,9 +273,12 @@ func (r *testSdkResult) ModuleForTests(name string, variant string) android.Test
// Takes a list of functions which check different facets of the snapshot build rules.
// Allows each test to customize what is checked without duplicating lots of code
// or proliferating check methods of different flavors.
func (r *testSdkResult) CheckSnapshot(name string, variant string, dir string, checkers ...snapshotBuildInfoChecker) {
func (r *testSdkResult) CheckSnapshot(name string, dir string, checkers ...snapshotBuildInfoChecker) {
r.t.Helper()
// The sdk CommonOS variant is always responsible for generating the snapshot.
variant := android.CommonOS.Name
sdk := r.Module(name, variant).(*sdk)
snapshotBuildInfo := r.getSdkSnapshotBuildInfo(sdk)
@ -295,6 +331,13 @@ func checkAllCopyRules(expected string) snapshotBuildInfoChecker {
}
}
func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
info.r.t.Helper()
info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
}
}
// Check that the specified path is in the list of zips to merge with the intermediate zip.
func checkMergeZip(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
@ -321,10 +364,14 @@ type snapshotBuildInfo struct {
// snapshot.
snapshotContents []string
// A formatted representation of the src/dest pairs, one pair per line, of the format
// src -> dest
// A formatted representation of the src/dest pairs for a snapshot, one pair per line,
// of the format src -> dest
copyRules string
// A formatted representation of the src/dest pairs for files not in a snapshot, one pair
// per line, of the format src -> dest
otherCopyRules string
// The path to the intermediate zip, which is a zip created from the source files copied
// into the snapshot directory and which will be merged with other zips to form the final output.
// Is am empty string if there is no intermediate zip because there are no zips to merge in.

File diff suppressed because it is too large Load diff

View file

@ -115,6 +115,7 @@ func syspropJavaGenFactory() android.Module {
type syspropLibrary struct {
android.ModuleBase
android.ApexModuleBase
properties syspropLibraryProperties
@ -296,6 +297,7 @@ func syspropLibraryFactory() android.Module {
&m.properties,
)
android.InitAndroidModule(m)
android.InitApexModule(m)
android.AddLoadHook(m, func(ctx android.LoadHookContext) { syspropLibraryHook(ctx, m) })
return m
}
@ -323,6 +325,7 @@ type ccLibraryProperties struct {
Recovery_available *bool
Vendor_available *bool
Host_supported *bool
Apex_available []string
}
type javaLibraryProperties struct {
@ -411,6 +414,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) {
ccProps.Recovery_available = m.properties.Recovery_available
ccProps.Vendor_available = m.properties.Vendor_available
ccProps.Host_supported = m.properties.Host_supported
ccProps.Apex_available = m.ApexProperties.Apex_available
ctx.CreateModule(cc.LibraryFactory, &ccProps)
scope := "internal"

View file

@ -15,6 +15,8 @@
package sysprop
import (
"reflect"
"android/soong/android"
"android/soong/cc"
"android/soong/java"
@ -157,6 +159,7 @@ func TestSyspropLibrary(t *testing.T) {
ctx := test(t, `
sysprop_library {
name: "sysprop-platform",
apex_available: ["//apex_available:platform"],
srcs: ["android/sysprop/PlatformProperties.sysprop"],
api_packages: ["android.sysprop"],
property_owner: "Platform",
@ -305,7 +308,12 @@ func TestSyspropLibrary(t *testing.T) {
"android_arm64_armv8-a_shared",
"android_arm64_armv8-a_static",
} {
ctx.ModuleForTests("libsysprop-platform", variant)
library := ctx.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module)
expectedApexAvailableOnLibrary := []string{"//apex_available:platform"}
if !reflect.DeepEqual(library.ApexProperties.Apex_available, expectedApexAvailableOnLibrary) {
t.Errorf("apex available property on libsysprop-platform must be %#v, but was %#v.",
expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available)
}
// core variant of vendor-owned sysprop_library is for product
ctx.ModuleForTests("libsysprop-vendor", variant)