Merge "Make @soong_injection usable in standalone builds."
diff --git a/android/config.go b/android/config.go
index 3db7980..79917ad 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1564,6 +1564,15 @@
return false
}
+// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
+// an empty string if not found.
+func (l *ConfiguredJarList) ApexOfJar(jar string) string {
+ if idx := IndexList(jar, l.jars); idx != -1 {
+ return l.Apex(IndexList(jar, l.jars))
+ }
+ return ""
+}
+
// IndexOfJar returns the first pair with the given jar name on the list, or -1
// if not found.
func (l *ConfiguredJarList) IndexOfJar(jar string) int {
diff --git a/android/sdk.go b/android/sdk.go
index 0adfd89..36c576d 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -284,11 +284,20 @@
// Add a property set with the specified name and return so that additional
// properties can be added.
AddPropertySet(name string) BpPropertySet
+
+ // Add comment for property (or property set).
+ AddCommentForProperty(name, text string)
}
// A .bp module definition.
type BpModule interface {
BpPropertySet
+
+ // ModuleType returns the module type of the module
+ ModuleType() string
+
+ // Name returns the name of the module or "" if no name has been specified.
+ Name() string
}
// An individual member of the SDK, includes all of the variants that the SDK
@@ -380,6 +389,10 @@
// The name of the member type property on an sdk module.
SdkPropertyName() string
+ // RequiresBpProperty returns true if this member type requires its property to be usable within
+ // an Android.bp file.
+ RequiresBpProperty() bool
+
// True if the member type supports the sdk/sdk_snapshot, false otherwise.
UsableWithSdkAndSdkSnapshot() bool
@@ -405,6 +418,10 @@
// the module is not allowed in whichever sdk property it was added.
IsInstance(module Module) bool
+ // UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a
+ // source module type.
+ UsesSourceModuleTypeInSnapshot() bool
+
// Add a prebuilt module that the sdk will populate.
//
// The sdk module code generates the snapshot as follows:
@@ -448,15 +465,29 @@
// Base type for SdkMemberType implementations.
type SdkMemberTypeBase struct {
- PropertyName string
+ PropertyName string
+
+ // When set to true BpPropertyNotRequired indicates that the member type does not require the
+ // property to be specifiable in an Android.bp file.
+ BpPropertyNotRequired bool
+
SupportsSdk bool
HostOsDependent bool
+
+ // When set to true UseSourceModuleTypeInSnapshot indicates that the member type creates a source
+ // module type in its SdkMemberType.AddPrebuiltModule() method. That prevents the sdk snapshot
+ // code from automatically adding a prefer: true flag.
+ UseSourceModuleTypeInSnapshot bool
}
func (b *SdkMemberTypeBase) SdkPropertyName() string {
return b.PropertyName
}
+func (b *SdkMemberTypeBase) RequiresBpProperty() bool {
+ return !b.BpPropertyNotRequired
+}
+
func (b *SdkMemberTypeBase) UsableWithSdkAndSdkSnapshot() bool {
return b.SupportsSdk
}
@@ -465,6 +496,10 @@
return b.HostOsDependent
}
+func (b *SdkMemberTypeBase) UsesSourceModuleTypeInSnapshot() bool {
+ return b.UseSourceModuleTypeInSnapshot
+}
+
// Encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index f0f51bf..5316d7b 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -216,6 +216,8 @@
"LOCAL_JETIFIER_ENABLED": "jetifier",
"LOCAL_IS_UNIT_TEST": "unit_test",
+
+ "LOCAL_ENFORCE_USES_LIBRARIES": "enforce_uses_libs",
})
}
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index f32ff2a..439f45d 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1446,6 +1446,23 @@
}
`,
},
+ {
+ desc: "LOCAL_ENFORCE_USES_LIBRARIES",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_ENFORCE_USES_LIBRARIES := false
+LOCAL_ENFORCE_USES_LIBRARIES := true
+include $(BUILD_PACKAGE)
+`,
+ expected: `
+android_app {
+ name: "foo",
+ enforce_uses_libs: false,
+ enforce_uses_libs: true,
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/apex/apex.go b/apex/apex.go
index 949d80e..2c0df27 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -50,10 +50,15 @@
ctx.RegisterModuleType("override_apex", overrideApexFactory)
ctx.RegisterModuleType("apex_set", apexSetFactory)
+ ctx.PreArchMutators(registerPreArchMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
}
+func registerPreArchMutators(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("prebuilt_apex_module_creator", prebuiltApexModuleCreatorMutator).Parallel()
+}
+
func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
@@ -2097,6 +2102,11 @@
}
}
+ // Add classpaths.proto config.
+ classpathProtoOutput := bootclasspathFragmentInfo.ClasspathFragmentProtoOutput
+ classpathProto := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), bootclasspathFragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
+ filesToAdd = append(filesToAdd, classpathProto)
+
return filesToAdd
}
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index e2b320c..7bb3ff6 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -279,6 +279,7 @@
).RunTest(t)
ensureExactContents(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{
+ "etc/classpaths/mybootclasspathfragment.pb",
"javalib/arm/boot.art",
"javalib/arm/boot.oat",
"javalib/arm/boot.vdex",
@@ -481,6 +482,7 @@
ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
// This does not include art, oat or vdex files as they are only included for the art boot
// image.
+ "etc/classpaths/mybootclasspathfragment.pb",
"javalib/bar.jar",
"javalib/foo.jar",
})
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 9bc5720..c7cdbfa 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -40,17 +40,29 @@
// This is intentionally not registered by name as it is not intended to be used from within an
// `Android.bp` file.
-// Properties that are specific to `deapexer` but which need to be provided on the `prebuilt_apex`
-// module.`
-type DeapexerProperties struct {
- // List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
- // APEX bundle will create an APEX variant and provide dex implementation jars for use by
- // dexpreopt and boot jars package check.
- Exported_java_libs []string
+// DeapexerExportedFile defines the properties needed to expose a file from the deapexer module.
+type DeapexerExportedFile struct {
+ // The tag parameter which must be passed to android.OutputFileProducer OutputFiles(tag) method
+ // to retrieve the path to the unpacked file.
+ Tag string
- // List of bootclasspath fragments inside this prebuiltd APEX bundle and for which this APEX
- // bundle will create an APEX variant.
- Exported_bootclasspath_fragments []string
+ // The path within the APEX that needs to be exported.
+ Path string `android:"path"`
+}
+
+// DeapexerProperties specifies the properties supported by the deapexer module.
+//
+// As these are never intended to be supplied in a .bp file they use a different naming convention
+// to make it clear that they are different.
+type DeapexerProperties struct {
+ // List of common modules that may need access to files exported by this module.
+ //
+ // A common module in this sense is one that is not arch specific but uses a common variant for
+ // all architectures, e.g. java.
+ CommonModules []string
+
+ // List of files exported from the .apex file by this module
+ ExportedFiles []DeapexerExportedFile
}
type SelectedApexProperties struct {
@@ -81,7 +93,7 @@
func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
// Add dependencies from the java modules to which this exports files from the `.apex` file onto
// this module so that they can access the `DeapexerInfo` object that this provides.
- for _, lib := range p.properties.Exported_java_libs {
+ for _, lib := range p.properties.CommonModules {
dep := prebuiltApexExportedModuleName(ctx, lib)
ctx.AddReverseDependency(ctx.Module(), android.DeapexerTag, dep)
}
@@ -96,10 +108,12 @@
exports := make(map[string]android.Path)
// Create mappings from name+tag to all the required exported paths.
- for _, l := range p.properties.Exported_java_libs {
- // Populate the exports that this makes available. The path here must match the path of the
- // file in the APEX created by apexFileForJavaModule(...).
- exports[l+"{.dexjar}"] = deapexerOutput.Join(ctx, "javalib", l+".jar")
+ for _, e := range p.properties.ExportedFiles {
+ tag := e.Tag
+ path := e.Path
+
+ // Populate the exports that this makes available.
+ exports[tag] = deapexerOutput.Join(ctx, path)
}
// If the prebuilt_apex exports any files then create a build rule that unpacks the apex using
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 8996352..9d632a9 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "path/filepath"
"strconv"
"strings"
@@ -46,11 +47,10 @@
}
type prebuiltCommon struct {
- prebuilt android.Prebuilt
- properties prebuiltCommonProperties
+ prebuilt android.Prebuilt
- deapexerProperties DeapexerProperties
- selectedApexProperties SelectedApexProperties
+ // Properties common to both prebuilt_apex and apex_set.
+ prebuiltCommonProperties prebuiltCommonProperties
}
type sanitizedPrebuilt interface {
@@ -58,7 +58,18 @@
}
type prebuiltCommonProperties struct {
+ SelectedApexProperties
+
ForceDisable bool `blueprint:"mutated"`
+
+ // List of java libraries that are embedded inside this prebuilt APEX bundle and for which this
+ // APEX bundle will create an APEX variant and provide dex implementation jars for use by
+ // dexpreopt and boot jars package check.
+ Exported_java_libs []string
+
+ // List of bootclasspath fragments inside this prebuilt APEX bundle and for which this APEX
+ // bundle will create an APEX variant.
+ Exported_bootclasspath_fragments []string
}
func (p *prebuiltCommon) Prebuilt() *android.Prebuilt {
@@ -66,7 +77,7 @@
}
func (p *prebuiltCommon) isForceDisabled() bool {
- return p.properties.ForceDisable
+ return p.prebuiltCommonProperties.ForceDisable
}
func (p *prebuiltCommon) checkForceDisable(ctx android.ModuleContext) bool {
@@ -88,25 +99,47 @@
forceDisable = forceDisable || (android.InList("hwaddress", ctx.Config().SanitizeDevice()) && !sanitized.hasSanitizedSource("hwaddress"))
if forceDisable && p.prebuilt.SourceExists() {
- p.properties.ForceDisable = true
+ p.prebuiltCommonProperties.ForceDisable = true
return true
}
return false
}
-func (p *prebuiltCommon) deapexerDeps(ctx android.BottomUpMutatorContext) {
+// prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
+// apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
+type prebuiltApexModuleCreator interface {
+ createPrebuiltApexModules(ctx android.TopDownMutatorContext)
+}
+
+// prebuiltApexModuleCreatorMutator is the mutator responsible for invoking the
+// prebuiltApexModuleCreator's createPrebuiltApexModules method.
+//
+// It is registered as a pre-arch mutator as it must run after the ComponentDepsMutator because it
+// will need to access dependencies added by that (exported modules) but must run before the
+// DepsMutator so that the deapexer module it creates can add dependencies onto itself from the
+// exported modules.
+func prebuiltApexModuleCreatorMutator(ctx android.TopDownMutatorContext) {
+ module := ctx.Module()
+ if creator, ok := module.(prebuiltApexModuleCreator); ok {
+ creator.createPrebuiltApexModules(ctx)
+ }
+}
+
+// prebuiltApexContentsDeps adds dependencies onto the prebuilt apex module's contents.
+func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorContext) {
+ module := ctx.Module()
// Add dependencies onto the java modules that represent the java libraries that are provided by
// and exported from this prebuilt apex.
- for _, exported := range p.deapexerProperties.Exported_java_libs {
- dep := prebuiltApexExportedModuleName(ctx, exported)
- ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
+ for _, exported := range p.prebuiltCommonProperties.Exported_java_libs {
+ dep := android.PrebuiltNameFromSource(exported)
+ ctx.AddDependency(module, exportedJavaLibTag, dep)
}
// Add dependencies onto the bootclasspath fragment modules that are exported from this prebuilt
// apex.
- for _, exported := range p.deapexerProperties.Exported_bootclasspath_fragments {
- dep := prebuiltApexExportedModuleName(ctx, exported)
- ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedBootclasspathFragmentTag, dep)
+ for _, exported := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments {
+ dep := android.PrebuiltNameFromSource(exported)
+ ctx.AddDependency(module, exportedBootclasspathFragmentTag, dep)
}
}
@@ -240,8 +273,7 @@
android.ModuleBase
prebuiltCommon
- properties PrebuiltProperties
- selectedApexProperties SelectedApexProperties
+ properties PrebuiltProperties
inputApex android.Path
installDir android.InstallPath
@@ -354,58 +386,16 @@
}
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
-//
-// If this needs to make files from within a `.apex` file available for use by other Soong modules,
-// e.g. make dex implementation jars available for java_import modules isted in exported_java_libs,
-// it does so as follows:
-//
-// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
-// makes them available for use by other modules, at both Soong and ninja levels.
-//
-// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
-// an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
-// dexpreopt, will work the same way from source and prebuilt.
-//
-// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
-// itself so that they can retrieve the file paths to those files.
-//
-// It also creates a child module `selector` that is responsible for selecting the appropriate
-// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
-// 1. To dedup the selection logic so it only runs in one module.
-// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
-// `apex_set`.
-//
-// prebuilt_apex
-// / | \
-// / | \
-// V | V
-// selector <--- deapexer <--- exported java lib
-//
func PrebuiltFactory() android.Module {
module := &Prebuilt{}
- module.AddProperties(&module.properties, &module.deapexerProperties, &module.selectedApexProperties)
- android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+ module.AddProperties(&module.properties, &module.prebuiltCommonProperties)
+ android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- baseModuleName := module.BaseModuleName()
-
- apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
- createApexSelectorModule(ctx, apexSelectorModuleName, &module.properties.ApexFileProperties)
-
- apexFileSource := ":" + apexSelectorModuleName
- if len(module.deapexerProperties.Exported_java_libs) != 0 {
- createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
- }
-
- // Add a source reference to retrieve the selected apex from the selector module.
- module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
- })
-
return module
}
-func createApexSelectorModule(ctx android.LoadHookContext, name string, apexFileProperties *ApexFileProperties) {
+func createApexSelectorModule(ctx android.TopDownMutatorContext, name string, apexFileProperties *ApexFileProperties) {
props := struct {
Name *string
}{
@@ -418,7 +408,54 @@
)
}
-func createDeapexerModule(ctx android.LoadHookContext, deapexerName string, apexFileSource string, deapexerProperties *DeapexerProperties) {
+// createDeapexerModuleIfNeeded will create a deapexer module if it is needed.
+//
+// A deapexer module is only needed when the prebuilt apex specifies one or more modules in either
+// the `exported_java_libs` or `exported_bootclasspath_fragments` properties as that indicates that
+// the listed modules need access to files from within the prebuilt .apex file.
+func createDeapexerModuleIfNeeded(ctx android.TopDownMutatorContext, deapexerName string, apexFileSource string, properties *prebuiltCommonProperties) {
+ // Only create the deapexer module if it is needed.
+ if len(properties.Exported_java_libs)+len(properties.Exported_bootclasspath_fragments) == 0 {
+ return
+ }
+
+ // Compute the deapexer properties from the transitive dependencies of this module.
+ javaModules := []string{}
+ exportedFiles := map[string]string{}
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ tag := ctx.OtherModuleDependencyTag(child)
+
+ name := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child))
+ if java.IsBootclasspathFragmentContentDepTag(tag) || tag == exportedJavaLibTag {
+ javaModules = append(javaModules, name)
+
+ // Add the dex implementation jar to the set of exported files. The path here must match the
+ // path of the file in the APEX created by apexFileForJavaModule(...).
+ exportedFiles[name+"{.dexjar}"] = filepath.Join("javalib", name+".jar")
+
+ } else if tag == exportedBootclasspathFragmentTag {
+ // Only visit the children of the bootclasspath_fragment for now.
+ return true
+ }
+
+ return false
+ })
+
+ // Create properties for deapexer module.
+ deapexerProperties := &DeapexerProperties{
+ // Remove any duplicates from the java modules lists as a module may be included via a direct
+ // dependency as well as transitive ones.
+ CommonModules: android.SortedUniqueStrings(javaModules),
+ }
+
+ // Populate the exported files property in a fixed order.
+ for _, tag := range android.SortedStringKeys(exportedFiles) {
+ deapexerProperties.ExportedFiles = append(deapexerProperties.ExportedFiles, DeapexerExportedFile{
+ Tag: tag,
+ Path: exportedFiles[tag],
+ })
+ }
+
props := struct {
Name *string
Selected_apex *string
@@ -479,8 +516,52 @@
exportedBootclasspathFragmentTag = exportedDependencyTag{name: "exported_bootclasspath_fragments"}
)
-func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
- p.deapexerDeps(ctx)
+var _ prebuiltApexModuleCreator = (*Prebuilt)(nil)
+
+// createPrebuiltApexModules creates modules necessary to export files from the prebuilt apex to the
+// build.
+//
+// If this needs to make files from within a `.apex` file available for use by other Soong modules,
+// e.g. make dex implementation jars available for java_import modules listed in exported_java_libs,
+// it does so as follows:
+//
+// 1. It creates a `deapexer` module that actually extracts the files from the `.apex` file and
+// makes them available for use by other modules, at both Soong and ninja levels.
+//
+// 2. It adds a dependency onto those modules and creates an apex specific variant similar to what
+// an `apex` module does. That ensures that code which looks for specific apex variant, e.g.
+// dexpreopt, will work the same way from source and prebuilt.
+//
+// 3. The `deapexer` module adds a dependency from the modules that require the exported files onto
+// itself so that they can retrieve the file paths to those files.
+//
+// It also creates a child module `selector` that is responsible for selecting the appropriate
+// input apex for both the prebuilt_apex and the deapexer. That is needed for a couple of reasons:
+// 1. To dedup the selection logic so it only runs in one module.
+// 2. To allow the deapexer to be wired up to a different source for the input apex, e.g. an
+// `apex_set`.
+//
+// prebuilt_apex
+// / | \
+// / | \
+// V V V
+// selector <--- deapexer <--- exported java lib
+//
+func (p *Prebuilt) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
+ baseModuleName := p.BaseModuleName()
+
+ apexSelectorModuleName := apexSelectorModuleName(baseModuleName)
+ createApexSelectorModule(ctx, apexSelectorModuleName, &p.properties.ApexFileProperties)
+
+ apexFileSource := ":" + apexSelectorModuleName
+ createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &p.prebuiltCommonProperties)
+
+ // Add a source reference to retrieve the selected apex from the selector module.
+ p.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+}
+
+func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+ p.prebuiltApexContentsDeps(ctx)
}
var _ ApexInfoMutator = (*Prebuilt)(nil)
@@ -491,7 +572,7 @@
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// TODO(jungjw): Check the key validity.
- p.inputApex = android.OptionalPathForModuleSrc(ctx, p.selectedApexProperties.Selected_apex).Path()
+ p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
p.installDir = android.PathForModuleInstall(ctx, "apex")
p.installFilename = p.InstallFilename()
if !strings.HasSuffix(p.installFilename, imageApexSuffix) {
@@ -693,30 +774,15 @@
// prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
func apexSetFactory() android.Module {
module := &ApexSet{}
- module.AddProperties(&module.properties, &module.selectedApexProperties, &module.deapexerProperties)
+ module.AddProperties(&module.properties, &module.prebuiltCommonProperties)
- android.InitSingleSourcePrebuiltModule(module, &module.selectedApexProperties, "Selected_apex")
+ android.InitSingleSourcePrebuiltModule(module, &module.prebuiltCommonProperties, "Selected_apex")
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- baseModuleName := module.BaseModuleName()
-
- apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
- createApexExtractorModule(ctx, apexExtractorModuleName, &module.properties.ApexExtractorProperties)
-
- apexFileSource := ":" + apexExtractorModuleName
- if len(module.deapexerProperties.Exported_java_libs) != 0 {
- createDeapexerModule(ctx, deapexerModuleName(baseModuleName), apexFileSource, &module.deapexerProperties)
- }
-
- // After passing the arch specific src properties to the creating the apex selector module
- module.selectedApexProperties.Selected_apex = proptools.StringPtr(apexFileSource)
- })
-
return module
}
-func createApexExtractorModule(ctx android.LoadHookContext, name string, apexExtractorProperties *ApexExtractorProperties) {
+func createApexExtractorModule(ctx android.TopDownMutatorContext, name string, apexExtractorProperties *ApexExtractorProperties) {
props := struct {
Name *string
}{
@@ -733,8 +799,30 @@
return baseModuleName + ".apex.extractor"
}
-func (a *ApexSet) DepsMutator(ctx android.BottomUpMutatorContext) {
- a.deapexerDeps(ctx)
+var _ prebuiltApexModuleCreator = (*ApexSet)(nil)
+
+// createPrebuiltApexModules creates modules necessary to export files from the apex set to other
+// modules.
+//
+// This effectively does for apex_set what Prebuilt.createPrebuiltApexModules does for a
+// prebuilt_apex except that instead of creating a selector module which selects one .apex file
+// from those provided this creates an extractor module which extracts the appropriate .apex file
+// from the zip file containing them.
+func (a *ApexSet) createPrebuiltApexModules(ctx android.TopDownMutatorContext) {
+ baseModuleName := a.BaseModuleName()
+
+ apexExtractorModuleName := apexExtractorModuleName(baseModuleName)
+ createApexExtractorModule(ctx, apexExtractorModuleName, &a.properties.ApexExtractorProperties)
+
+ apexFileSource := ":" + apexExtractorModuleName
+ createDeapexerModuleIfNeeded(ctx, deapexerModuleName(baseModuleName), apexFileSource, &a.prebuiltCommonProperties)
+
+ // After passing the arch specific src properties to the creating the apex selector module
+ a.prebuiltCommonProperties.Selected_apex = proptools.StringPtr(apexFileSource)
+}
+
+func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+ a.prebuiltApexContentsDeps(ctx)
}
var _ ApexInfoMutator = (*ApexSet)(nil)
@@ -749,7 +837,7 @@
ctx.ModuleErrorf("filename should end in %s for apex_set", imageApexSuffix)
}
- inputApex := android.OptionalPathForModuleSrc(ctx, a.selectedApexProperties.Selected_apex).Path()
+ inputApex := android.OptionalPathForModuleSrc(ctx, a.prebuiltCommonProperties.Selected_apex).Path()
a.outputApex = android.PathForModuleOut(ctx, a.installFilename)
ctx.Build(pctx, android.BuildParams{
Rule: android.Cp,
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 0551a18..407073a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -257,24 +257,74 @@
depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
dir: "foo/bar",
filesystem: map[string]string{
- "foo/bar/a.cpp": "",
+ "foo/bar/both.cpp": "",
+ "foo/bar/sharedonly.cpp": "",
+ "foo/bar/staticonly.cpp": "",
"foo/bar/Android.bp": `
cc_library {
name: "a",
- shared: { whole_static_libs: ["b"] },
- static: { srcs: ["a.cpp"] },
+ srcs: ["both.cpp"],
+ cflags: ["bothflag"],
+ shared_libs: ["shared_dep_for_both"],
+ static_libs: ["static_dep_for_both"],
+ whole_static_libs: ["whole_static_lib_for_both"],
+ static: {
+ srcs: ["staticonly.cpp"],
+ cflags: ["staticflag"],
+ shared_libs: ["shared_dep_for_static"],
+ static_libs: ["static_dep_for_static"],
+ whole_static_libs: ["whole_static_lib_for_static"],
+ },
+ shared: {
+ srcs: ["sharedonly.cpp"],
+ cflags: ["sharedflag"],
+ shared_libs: ["shared_dep_for_shared"],
+ static_libs: ["static_dep_for_shared"],
+ whole_static_libs: ["whole_static_lib_for_shared"],
+ },
bazel_module: { bp2build_available: true },
}
-cc_library_static { name: "b" }
+cc_library_static { name: "static_dep_for_shared" }
+
+cc_library_static { name: "static_dep_for_static" }
+
+cc_library_static { name: "static_dep_for_both" }
+
+cc_library_static { name: "whole_static_lib_for_shared" }
+
+cc_library_static { name: "whole_static_lib_for_static" }
+
+cc_library_static { name: "whole_static_lib_for_both" }
+
+cc_library { name: "shared_dep_for_shared" }
+
+cc_library { name: "shared_dep_for_static" }
+
+cc_library { name: "shared_dep_for_both" }
`,
},
bp: soongCcLibraryPreamble,
expectedBazelTargets: []string{`cc_library(
name = "a",
- copts = ["-Ifoo/bar"],
- srcs = ["a.cpp"],
- static_deps_for_shared = [":b"],
+ copts = [
+ "bothflag",
+ "-Ifoo/bar",
+ ],
+ deps = [":static_dep_for_both"],
+ dynamic_deps = [":shared_dep_for_both"],
+ dynamic_deps_for_shared = [":shared_dep_for_shared"],
+ dynamic_deps_for_static = [":shared_dep_for_static"],
+ shared_copts = ["sharedflag"],
+ shared_srcs = ["sharedonly.cpp"],
+ srcs = ["both.cpp"],
+ static_copts = ["staticflag"],
+ static_deps_for_shared = [":static_dep_for_shared"],
+ static_deps_for_static = [":static_dep_for_static"],
+ static_srcs = ["staticonly.cpp"],
+ whole_archive_deps = [":whole_static_lib_for_both"],
+ whole_archive_deps_for_shared = [":whole_static_lib_for_shared"],
+ whole_archive_deps_for_static = [":whole_static_lib_for_static"],
)`},
},
{
@@ -302,6 +352,99 @@
version_script = "v.map",
)`},
},
+ {
+ description: "cc_library shared_libs",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "mylib",
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+ name: "a",
+ shared_libs: ["mylib",],
+ bazel_module: { bp2build_available: true },
+}
+`,
+ },
+ bp: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = ["-Ifoo/bar"],
+ dynamic_deps = [":mylib"],
+)`, `cc_library(
+ name = "mylib",
+ copts = ["-Ifoo/bar"],
+)`},
+ },
+ {
+ description: "cc_library pack_relocations test",
+ moduleTypeUnderTest: "cc_library",
+ moduleTypeUnderTestFactory: cc.LibraryFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryBp2Build,
+ depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build},
+ dir: "foo/bar",
+ filesystem: map[string]string{
+ "foo/bar/Android.bp": `
+cc_library {
+ name: "a",
+ srcs: ["a.cpp"],
+ pack_relocations: false,
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+ name: "b",
+ srcs: ["b.cpp"],
+ arch: {
+ x86_64: {
+ pack_relocations: false,
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}
+
+cc_library {
+ name: "c",
+ srcs: ["c.cpp"],
+ target: {
+ darwin: {
+ pack_relocations: false,
+ },
+ },
+ bazel_module: { bp2build_available: true },
+}`,
+ },
+ bp: soongCcLibraryPreamble,
+ expectedBazelTargets: []string{`cc_library(
+ name = "a",
+ copts = ["-Ifoo/bar"],
+ linkopts = ["-Wl,--pack-dyn-relocs=none"],
+ srcs = ["a.cpp"],
+)`, `cc_library(
+ name = "b",
+ copts = ["-Ifoo/bar"],
+ linkopts = select({
+ "//build/bazel/platforms/arch:x86_64": ["-Wl,--pack-dyn-relocs=none"],
+ "//conditions:default": [],
+ }),
+ srcs = ["b.cpp"],
+)`, `cc_library(
+ name = "c",
+ copts = ["-Ifoo/bar"],
+ linkopts = select({
+ "//build/bazel/platforms/os:darwin": ["-Wl,--pack-dyn-relocs=none"],
+ "//conditions:default": [],
+ }),
+ srcs = ["c.cpp"],
+)`},
+ },
}
dir := "."
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index bff9b07..d082db1 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -189,8 +189,6 @@
":header_lib_2",
":static_lib_1",
":static_lib_2",
- ":whole_static_lib_1",
- ":whole_static_lib_2",
],
includes = [
"export_include_dir_1",
@@ -201,6 +199,10 @@
"foo_static1.cc",
"foo_static2.cc",
],
+ whole_archive_deps = [
+ ":whole_static_lib_1",
+ ":whole_static_lib_2",
+ ],
)`, `cc_library_static(
name = "static_lib_1",
copts = ["-I."],
@@ -423,13 +425,14 @@
name = "foo_static",
copts = ["-I."],
deps = select({
- "//build/bazel/platforms/arch:arm64": [
- ":static_dep",
- ":static_dep2",
- ],
+ "//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = select({
+ "//build/bazel/platforms/arch:arm64": [":static_dep2"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_static(
name = "static_dep",
copts = ["-I."],
@@ -458,13 +461,14 @@
name = "foo_static",
copts = ["-I."],
deps = select({
- "//build/bazel/platforms/os:android": [
- ":static_dep",
- ":static_dep2",
- ],
+ "//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = select({
+ "//build/bazel/platforms/os:android": [":static_dep2"],
+ "//conditions:default": [],
+ }),
)`, `cc_library_static(
name = "static_dep",
copts = ["-I."],
@@ -497,10 +501,7 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
copts = ["-I."],
- deps = [
- ":static_dep",
- ":static_dep2",
- ] + select({
+ deps = [":static_dep"] + select({
"//build/bazel/platforms/arch:arm64": [":static_dep4"],
"//conditions:default": [],
}) + select({
@@ -508,6 +509,7 @@
"//conditions:default": [],
}),
linkstatic = True,
+ whole_archive_deps = [":static_dep2"],
)`, `cc_library_static(
name = "static_dep",
copts = ["-I."],
@@ -732,8 +734,7 @@
cc_library_static { name: "static_dep" }
cc_library_static {
name: "foo_static",
- static_libs: ["static_dep"],
- whole_static_libs: ["static_dep"],
+ static_libs: ["static_dep", "static_dep"],
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 1433f6f..7d01986 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -85,7 +85,11 @@
}
type sharedAttributes struct {
- staticDeps bazel.LabelListAttribute
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ staticDeps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
}
// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
@@ -95,17 +99,35 @@
return sharedAttributes{}
}
- var staticDeps bazel.LabelListAttribute
+ copts := bazel.StringListAttribute{Value: lib.SharedProperties.Shared.Cflags}
- staticDeps.Value = android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)
+ srcs := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleSrc(ctx, lib.SharedProperties.Shared.Srcs)}
+
+ staticDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Static_libs)}
+
+ dynamicDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Shared_libs)}
+
+ wholeArchiveDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.SharedProperties.Shared.Whole_static_libs)}
return sharedAttributes{
- staticDeps: staticDeps,
+ copts: copts,
+ srcs: srcs,
+ staticDeps: staticDeps,
+ dynamicDeps: dynamicDeps,
+ wholeArchiveDeps: wholeArchiveDeps,
}
}
type staticAttributes struct {
- srcs bazel.LabelListAttribute
+ copts bazel.StringListAttribute
+ srcs bazel.LabelListAttribute
+ staticDeps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
}
// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
@@ -115,11 +137,26 @@
return staticAttributes{}
}
- var srcs bazel.LabelListAttribute
- srcs.Value = android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)
+ copts := bazel.StringListAttribute{Value: lib.StaticProperties.Static.Cflags}
+
+ srcs := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleSrc(ctx, lib.StaticProperties.Static.Srcs)}
+
+ staticDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Static_libs)}
+
+ dynamicDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Shared_libs)}
+
+ wholeArchiveDeps := bazel.LabelListAttribute{
+ Value: android.BazelLabelForModuleDeps(ctx, lib.StaticProperties.Static.Whole_static_libs)}
return staticAttributes{
- srcs: srcs,
+ copts: copts,
+ srcs: srcs,
+ staticDeps: staticDeps,
+ dynamicDeps: dynamicDeps,
+ wholeArchiveDeps: wholeArchiveDeps,
}
}
@@ -246,15 +283,28 @@
// Convenience struct to hold all attributes parsed from linker properties.
type linkerAttributes struct {
- deps bazel.LabelListAttribute
- linkopts bazel.StringListAttribute
- versionScript bazel.LabelAttribute
+ deps bazel.LabelListAttribute
+ dynamicDeps bazel.LabelListAttribute
+ wholeArchiveDeps bazel.LabelListAttribute
+ linkopts bazel.StringListAttribute
+ versionScript bazel.LabelAttribute
+}
+
+// FIXME(b/187655838): Use the existing linkerFlags() function instead of duplicating logic here
+func getBp2BuildLinkerFlags(linkerProperties *BaseLinkerProperties) []string {
+ flags := linkerProperties.Ldflags
+ if !BoolDefault(linkerProperties.Pack_relocations, true) {
+ flags = append(flags, "-Wl,--pack-dyn-relocs=none")
+ }
+ return flags
}
// bp2BuildParseLinkerProps parses the linker properties of a module, including
// configurable attribute values.
func bp2BuildParseLinkerProps(ctx android.TopDownMutatorContext, module *Module) linkerAttributes {
var deps bazel.LabelListAttribute
+ var dynamicDeps bazel.LabelListAttribute
+ var wholeArchiveDeps bazel.LabelListAttribute
var linkopts bazel.StringListAttribute
var versionScript bazel.LabelAttribute
@@ -263,14 +313,19 @@
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
deps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, libs))
- linkopts.Value = baseLinkerProps.Ldflags
+ linkopts.Value = getBp2BuildLinkerFlags(baseLinkerProps)
+ wholeArchiveDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
if baseLinkerProps.Version_script != nil {
versionScript.Value = android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script)
}
+
+ sharedLibs := baseLinkerProps.Shared_libs
+ dynamicDeps = bazel.MakeLabelListAttribute(android.BazelLabelForModuleDeps(ctx, sharedLibs))
+
break
}
}
@@ -280,14 +335,19 @@
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
deps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, libs))
- linkopts.SetValueForArch(arch.Name, baseLinkerProps.Ldflags)
+ linkopts.SetValueForArch(arch.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+ wholeArchiveDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
+
if baseLinkerProps.Version_script != nil {
versionScript.SetValueForArch(arch.Name,
android.BazelLabelForModuleSrcSingle(ctx, *baseLinkerProps.Version_script))
}
+
+ sharedLibs := baseLinkerProps.Shared_libs
+ dynamicDeps.SetValueForArch(arch.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
}
}
@@ -296,17 +356,24 @@
libs := baseLinkerProps.Header_libs
libs = append(libs, baseLinkerProps.Export_header_lib_headers...)
libs = append(libs, baseLinkerProps.Static_libs...)
- libs = append(libs, baseLinkerProps.Whole_static_libs...)
+ wholeArchiveLibs := baseLinkerProps.Whole_static_libs
libs = android.SortedUniqueStrings(libs)
+ wholeArchiveDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, wholeArchiveLibs))
deps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs))
- linkopts.SetValueForOS(os.Name, baseLinkerProps.Ldflags)
+
+ linkopts.SetValueForOS(os.Name, getBp2BuildLinkerFlags(baseLinkerProps))
+
+ sharedLibs := baseLinkerProps.Shared_libs
+ dynamicDeps.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, sharedLibs))
}
}
return linkerAttributes{
- deps: deps,
- linkopts: linkopts,
- versionScript: versionScript,
+ deps: deps,
+ dynamicDeps: dynamicDeps,
+ wholeArchiveDeps: wholeArchiveDeps,
+ linkopts: linkopts,
+ versionScript: versionScript,
}
}
diff --git a/cc/library.go b/cc/library.go
index 7b631fa..c5ff9b1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -220,15 +220,29 @@
// For bp2build conversion.
type bazelCcLibraryAttributes struct {
- Srcs bazel.LabelListAttribute
- Hdrs bazel.LabelListAttribute
- Copts bazel.StringListAttribute
- Linkopts bazel.StringListAttribute
- Deps bazel.LabelListAttribute
- User_link_flags bazel.StringListAttribute
- Includes bazel.StringListAttribute
- Static_deps_for_shared bazel.LabelListAttribute
- Version_script bazel.LabelAttribute
+ // Attributes pertaining to both static and shared variants.
+ Srcs bazel.LabelListAttribute
+ Hdrs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Includes bazel.StringListAttribute
+ Linkopts bazel.StringListAttribute
+ // Attributes pertaining to shared variant.
+ Shared_copts bazel.StringListAttribute
+ Shared_srcs bazel.LabelListAttribute
+ Static_deps_for_shared bazel.LabelListAttribute
+ Dynamic_deps_for_shared bazel.LabelListAttribute
+ Whole_archive_deps_for_shared bazel.LabelListAttribute
+ User_link_flags bazel.StringListAttribute
+ Version_script bazel.LabelAttribute
+ // Attributes pertaining to static variant.
+ Static_copts bazel.StringListAttribute
+ Static_srcs bazel.LabelListAttribute
+ Static_deps_for_static bazel.LabelListAttribute
+ Dynamic_deps_for_static bazel.LabelListAttribute
+ Whole_archive_deps_for_static bazel.LabelListAttribute
}
type bazelCcLibrary struct {
@@ -275,16 +289,26 @@
var srcs bazel.LabelListAttribute
srcs.Append(compilerAttrs.srcs)
- srcs.Append(staticAttrs.srcs)
attrs := &bazelCcLibraryAttributes{
- Srcs: srcs,
- Copts: compilerAttrs.copts,
- Linkopts: linkerAttrs.linkopts,
- Deps: linkerAttrs.deps,
- Version_script: linkerAttrs.versionScript,
- Static_deps_for_shared: sharedAttrs.staticDeps,
- Includes: exportedIncludes,
+ Srcs: srcs,
+ Deps: linkerAttrs.deps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Copts: compilerAttrs.copts,
+ Includes: exportedIncludes,
+ Linkopts: linkerAttrs.linkopts,
+ Shared_copts: sharedAttrs.copts,
+ Shared_srcs: sharedAttrs.srcs,
+ Static_deps_for_shared: sharedAttrs.staticDeps,
+ Whole_archive_deps_for_shared: sharedAttrs.wholeArchiveDeps,
+ Dynamic_deps_for_shared: sharedAttrs.dynamicDeps,
+ Version_script: linkerAttrs.versionScript,
+ Static_copts: staticAttrs.copts,
+ Static_srcs: staticAttrs.srcs,
+ Static_deps_for_static: staticAttrs.staticDeps,
+ Whole_archive_deps_for_static: staticAttrs.wholeArchiveDeps,
+ Dynamic_deps_for_static: staticAttrs.dynamicDeps,
}
props := bazel.BazelTargetModuleProperties{
@@ -2192,13 +2216,14 @@
}
type bazelCcLibraryStaticAttributes struct {
- Copts bazel.StringListAttribute
- Srcs bazel.LabelListAttribute
- Deps bazel.LabelListAttribute
- Linkopts bazel.StringListAttribute
- Linkstatic bool
- Includes bazel.StringListAttribute
- Hdrs bazel.LabelListAttribute
+ Copts bazel.StringListAttribute
+ Srcs bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Linkopts bazel.StringListAttribute
+ Linkstatic bool
+ Includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
}
type bazelCcLibraryStatic struct {
@@ -2219,9 +2244,11 @@
exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
attrs := &bazelCcLibraryStaticAttributes{
- Copts: compilerAttrs.copts,
- Srcs: compilerAttrs.srcs,
- Deps: linkerAttrs.deps,
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
+ Deps: linkerAttrs.deps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+
Linkopts: linkerAttrs.linkopts,
Linkstatic: true,
Includes: exportedIncludes,
diff --git a/cc/linker.go b/cc/linker.go
index 73fc4f0..a9930ad 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -421,9 +421,13 @@
if !BoolDefault(linker.Properties.Pack_relocations, true) {
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none")
} else if ctx.Device() {
- // The SHT_RELR relocations is only supported by API level >= 28.
- // Do not turn this on if older version NDK is used.
- if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 28) {
+ // SHT_RELR relocations are only supported at API level >= 30.
+ // ANDROID_RELR relocations were supported at API level >= 28.
+ // Relocation packer was supported at API level >= 23.
+ // Do the best we can...
+ if !ctx.useSdk() || CheckSdkVersionAtLeast(ctx, 30) {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr")
+ } else if CheckSdkVersionAtLeast(ctx, 28) {
flags.Global.LdFlags = append(flags.Global.LdFlags,
"-Wl,--pack-dyn-relocs=android+relr",
"-Wl,--use-android-relr-tags")
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index a69de6a..b7c260c 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -114,7 +114,10 @@
err = ioutil.WriteFile(filename, buf.Bytes(), 0666)
}
- // Now, produce per-package module lists with detailed information.
+ // Now, produce per-package module lists with detailed information, and a list
+ // of keywords.
+ keywordsTmpl := template.Must(template.New("file").Parse(keywordsTemplate))
+ keywordsBuf := &bytes.Buffer{}
for _, pkg := range packages {
// We need a module name getter/setter function because I couldn't
// find a way to keep it in a variable defined within the template.
@@ -141,7 +144,17 @@
if err != nil {
return err
}
+ err = keywordsTmpl.Execute(keywordsBuf, data)
+ if err != nil {
+ return err
+ }
}
+
+ // Write out list of keywords. This includes all module and property names, which is useful for
+ // building syntax highlighters.
+ keywordsFilename := filepath.Join(filepath.Dir(filename), "keywords.txt")
+ err = ioutil.WriteFile(keywordsFilename, keywordsBuf.Bytes(), 0666)
+
return err
}
@@ -413,4 +426,9 @@
</script>
{{end}}
`
+
+ keywordsTemplate = `
+{{range $moduleType := .Modules}}{{$moduleType.Name}}:{{range $property := $moduleType.Properties}}{{$property.Name}},{{end}}
+{{end}}
+`
)
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 6270b5b..bed629d 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -109,6 +109,8 @@
android.ModuleBase
android.ApexModuleBase
android.SdkBase
+ ClasspathFragmentBase
+
properties bootclasspathFragmentProperties
}
@@ -117,6 +119,7 @@
m.AddProperties(&m.properties)
android.InitApexModule(m)
android.InitSdkAwareModule(m)
+ initClasspathFragment(m, BOOTCLASSPATH)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
@@ -242,6 +245,22 @@
// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
// apex contents.
type BootclasspathFragmentApexContentInfo struct {
+ // ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
+ //
+ // The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
+ // for more details.
+ ClasspathFragmentProtoOutput android.OutputPath
+
+ // ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
+ //
+ // The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
+ // for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
+ // use android.InstallPath#Rel().
+ //
+ // This is only relevant for APEX modules as they perform their own installation; while regular
+ // system files are installed via ClasspathFragmentBase#androidMkEntries().
+ ClasspathFragmentProtoInstallDir android.InstallPath
+
// The image config, internal to this module (and the dex_bootjars singleton).
//
// Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
@@ -339,30 +358,47 @@
b.bootclasspathImageNameContentsConsistencyCheck(ctx)
}
+ // Generate classpaths.proto config
+ b.generateClasspathProtoBuildActions(ctx)
+
// Perform hidden API processing.
b.generateHiddenAPIBuildActions(ctx)
- // Nothing to do if skipping the dexpreopt of boot image jars.
- if SkipDexpreoptBootJars(ctx) {
- return
- }
-
- // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
- // GenerateSingletonBuildActions method as it cannot create it for itself.
- dexpreopt.GetGlobalSoongConfig(ctx)
-
- imageConfig := b.getImageConfig(ctx)
- if imageConfig == nil {
- return
- }
-
// Construct the boot image info from the config.
- info := BootclasspathFragmentApexContentInfo{imageConfig: imageConfig}
+ info := BootclasspathFragmentApexContentInfo{
+ ClasspathFragmentProtoInstallDir: b.classpathFragmentBase().installDirPath,
+ ClasspathFragmentProtoOutput: b.classpathFragmentBase().outputFilepath,
+ imageConfig: nil,
+ }
+
+ if !SkipDexpreoptBootJars(ctx) {
+ // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+ // GenerateSingletonBuildActions method as it cannot create it for itself.
+ dexpreopt.GetGlobalSoongConfig(ctx)
+ info.imageConfig = b.getImageConfig(ctx)
+ }
// Make it available for other modules.
ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
}
+// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
+func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
+ var classpathJars []classpathJar
+ if "art" == proptools.String(b.properties.Image_name) {
+ // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
+ classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+ } else {
+ classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
+ }
+ b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+}
+
+func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+ // TODO(satayev): populate with actual content
+ return android.EmptyConfiguredJarList()
+}
+
func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
// Get a map of the image configs that are supported.
imageConfigs := genBootImageConfigs(ctx)
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 2e05823..7422fa2 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -143,6 +143,8 @@
android.WriteFileRule(ctx, output, content.String())
}
+// Returns AndroidMkEntries objects to install generated classpath.proto.
+// Do not use this to install into APEXes as the injection of the generated files happen separately for APEXes.
func (c *ClasspathFragmentBase) androidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{{
Class: "ETC",
diff --git a/java/java.go b/java/java.go
index d74bf68..9a5fbfc 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1222,6 +1222,13 @@
return LintDepSets{}
}
+func (j *Import) getStrictUpdatabilityLinting() bool {
+ return false
+}
+
+func (j *Import) setStrictUpdatabilityLinting(bool) {
+}
+
func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...)
@@ -1545,6 +1552,13 @@
return true
}
+func (j *DexImport) getStrictUpdatabilityLinting() bool {
+ return false
+}
+
+func (j *DexImport) setStrictUpdatabilityLinting(bool) {
+}
+
func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(j.properties.Jars) != 1 {
ctx.PropertyErrorf("jars", "exactly one jar must be provided")
diff --git a/java/lint.go b/java/lint.go
index 5e39274..9f769df 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -103,6 +103,10 @@
type lintDepSetsIntf interface {
LintDepSets() LintDepSets
+
+ // Methods used to propagate strict_updatability_linting values.
+ getStrictUpdatabilityLinting() bool
+ setStrictUpdatabilityLinting(bool)
}
type LintDepSets struct {
@@ -153,6 +157,14 @@
return l.outputs.depSets
}
+func (l *linter) getStrictUpdatabilityLinting() bool {
+ return BoolDefault(l.properties.Lint.Strict_updatability_linting, false)
+}
+
+func (l *linter) setStrictUpdatabilityLinting(strictLinting bool) {
+ l.properties.Lint.Strict_updatability_linting = &strictLinting
+}
+
var _ lintDepSetsIntf = (*linter)(nil)
var _ lintOutputsIntf = (*linter)(nil)
@@ -260,7 +272,7 @@
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
- if BoolDefault(l.properties.Lint.Strict_updatability_linting, false) {
+ if l.getStrictUpdatabilityLinting() {
// Verify the module does not baseline issues that endanger safe updatability.
if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
cmd.FlagWithInput("--baseline ", baselinePath.Path())
@@ -586,6 +598,14 @@
func init() {
android.RegisterSingletonType("lint",
func() android.Singleton { return &lintSingleton{} })
+
+ registerLintBuildComponents(android.InitRegistrationContext)
+}
+
+func registerLintBuildComponents(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("enforce_strict_updatability_linting", enforceStrictUpdatabilityLintingMutator).Parallel()
+ })
}
func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
@@ -604,3 +624,15 @@
rule.Build(outputPath.Base(), outputPath.Base())
}
+
+// Enforce the strict updatability linting to all applicable transitive dependencies.
+func enforceStrictUpdatabilityLintingMutator(ctx android.TopDownMutatorContext) {
+ m := ctx.Module()
+ if d, ok := m.(lintDepSetsIntf); ok && d.getStrictUpdatabilityLinting() {
+ ctx.VisitDirectDepsWithTag(staticLibTag, func(d android.Module) {
+ if a, ok := d.(lintDepSetsIntf); ok {
+ a.setStrictUpdatabilityLinting(true)
+ }
+ })
+ }
+}
diff --git a/java/lint_test.go b/java/lint_test.go
index a253df9..6d64de7 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -181,12 +181,22 @@
srcs: [
"a.java",
],
+ static_libs: ["bar"],
min_sdk_version: "29",
sdk_version: "current",
lint: {
strict_updatability_linting: true,
},
}
+
+ java_library {
+ name: "bar",
+ srcs: [
+ "a.java",
+ ],
+ min_sdk_version: "29",
+ sdk_version: "current",
+ }
`
fs := android.MockFS{
"lint-baseline.xml": nil,
@@ -201,4 +211,11 @@
"--baseline lint-baseline.xml --disallowed_issues NewApi") {
t.Error("did not restrict baselining NewApi")
}
+
+ bar := result.ModuleForTests("bar", "android_common")
+ sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
+ if !strings.Contains(*sboxProto.Commands[0].Command,
+ "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+ t.Error("did not restrict baselining NewApi")
+ }
}
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 1caffe4..c787e47 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -203,6 +203,7 @@
func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
classpathJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+
// TODO(satayev): remove updatable boot jars once each apex has its own fragment
global := dexpreopt.GetGlobalConfig(ctx)
classpathJars = append(classpathJars, configuredJarListToClasspathJars(ctx, global.UpdatableBootJars, BOOTCLASSPATH)...)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index aff4539..800e93b 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -2195,6 +2195,20 @@
}
}
+func (module *SdkLibraryImport) getStrictUpdatabilityLinting() bool {
+ if module.implLibraryModule == nil {
+ return false
+ } else {
+ return module.implLibraryModule.getStrictUpdatabilityLinting()
+ }
+}
+
+func (module *SdkLibraryImport) setStrictUpdatabilityLinting(strictLinting bool) {
+ if module.implLibraryModule != nil {
+ module.implLibraryModule.setStrictUpdatabilityLinting(strictLinting)
+ }
+}
+
// to satisfy apex.javaDependency interface
func (module *SdkLibraryImport) Stem() string {
return module.BaseModuleName()
diff --git a/java/testing.go b/java/testing.go
index 37e63f5..387d595 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -245,6 +245,7 @@
RegisterStubsBuildComponents(ctx)
RegisterSystemModulesBuildComponents(ctx)
registerSystemserverClasspathBuildComponents(ctx)
+ registerLintBuildComponents(ctx)
}
// gatherRequiredDepsForTest gathers the module definitions used by
diff --git a/scripts/Android.bp b/scripts/Android.bp
index b0a8669..1c02bd0 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -265,22 +265,3 @@
"linker_config_proto",
],
}
-
-python_binary_host {
- name: "conv_classpaths_proto",
- srcs: [
- "conv_classpaths_proto.py",
- ],
- version: {
- py2: {
- enabled: false,
- },
- py3: {
- enabled: true,
- embedded_launcher: true,
- },
- },
- libs: [
- "classpaths_proto_python",
- ],
-}
diff --git a/scripts/conv_classpaths_proto.py b/scripts/conv_classpaths_proto.py
deleted file mode 100644
index f49fbbb..0000000
--- a/scripts/conv_classpaths_proto.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (C) 2021 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.
-
-import argparse
-
-import classpaths_pb2
-
-import google.protobuf.json_format as json_format
-import google.protobuf.text_format as text_format
-
-
-def encode(args):
- pb = classpaths_pb2.ExportedClasspathsJars()
- if args.format == 'json':
- json_format.Parse(args.input.read(), pb)
- else:
- text_format.Parse(args.input.read(), pb)
- args.output.write(pb.SerializeToString())
- args.input.close()
- args.output.close()
-
-
-def decode(args):
- pb = classpaths_pb2.ExportedClasspathsJars()
- pb.ParseFromString(args.input.read())
- if args.format == 'json':
- args.output.write(json_format.MessageToJson(pb))
- else:
- args.output.write(text_format.MessageToString(pb).encode('utf_8'))
- args.input.close()
- args.output.close()
-
-
-def main():
- parser = argparse.ArgumentParser('Convert classpaths.proto messages between binary and '
- 'human-readable formats.')
- parser.add_argument('-f', '--format', default='textproto',
- help='human-readable format, either json or text(proto), '
- 'defaults to textproto')
- parser.add_argument('-i', '--input',
- nargs='?', type=argparse.FileType('rb'), default=sys.stdin.buffer)
- parser.add_argument('-o', '--output',
- nargs='?', type=argparse.FileType('wb'),
- default=sys.stdout.buffer)
-
- subparsers = parser.add_subparsers()
-
- parser_encode = subparsers.add_parser('encode',
- help='convert classpaths protobuf message from '
- 'JSON to binary format',
- parents=[parser], add_help=False)
-
- parser_encode.set_defaults(func=encode)
-
- parser_decode = subparsers.add_parser('decode',
- help='print classpaths config in JSON format',
- parents=[parser], add_help=False)
- parser_decode.set_defaults(func=decode)
-
- args = parser.parse_args()
- args.func(args)
-
-
-if __name__ == '__main__':
- main()
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 0f2fd54..e91546e 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -95,9 +95,6 @@
prebuilt_apex {
name: "com.android.art",
src: "art.apex",
- exported_java_libs: [
- "mybootlib",
- ],
exported_bootclasspath_fragments: [
"mybootclasspathfragment",
],
diff --git a/sdk/bp.go b/sdk/bp.go
index 11ec8c6..e2dace8 100644
--- a/sdk/bp.go
+++ b/sdk/bp.go
@@ -25,6 +25,7 @@
type bpPropertySet struct {
properties map[string]interface{}
tags map[string]android.BpPropertyTag
+ comments map[string]string
order []string
}
@@ -133,10 +134,22 @@
return s.properties[name]
}
+func (s *bpPropertySet) getOptionalValue(name string) (interface{}, bool) {
+ value, ok := s.properties[name]
+ return value, ok
+}
+
func (s *bpPropertySet) getTag(name string) interface{} {
return s.tags[name]
}
+func (s *bpPropertySet) AddCommentForProperty(name, text string) {
+ if s.comments == nil {
+ s.comments = map[string]string{}
+ }
+ s.comments[name] = strings.TrimSpace(text)
+}
+
func (s *bpPropertySet) transformContents(transformer bpPropertyTransformer) {
var newOrder []string
for _, name := range s.order {
@@ -188,6 +201,12 @@
}
}
+func (s *bpPropertySet) removeProperty(name string) {
+ delete(s.properties, name)
+ delete(s.tags, name)
+ _, s.order = android.RemoveFromList(name, s.order)
+}
+
func (s *bpPropertySet) insertAfter(position string, name string, value interface{}) {
if s.properties[name] != nil {
panic("Property %q already exists in property set")
@@ -216,6 +235,19 @@
moduleType string
}
+func (m *bpModule) ModuleType() string {
+ return m.moduleType
+}
+
+func (m *bpModule) Name() string {
+ name, hasName := m.getOptionalValue("name")
+ if hasName {
+ return name.(string)
+ } else {
+ return ""
+ }
+}
+
var _ android.BpModule = (*bpModule)(nil)
type bpPropertyTransformer interface {
@@ -346,16 +378,26 @@
// is unique within this file.
func (f *bpFile) AddModule(module android.BpModule) {
m := module.(*bpModule)
- if name, ok := m.getValue("name").(string); ok {
- if f.modules[name] != nil {
- panic(fmt.Sprintf("Module %q already exists in bp file", name))
- }
-
- f.modules[name] = m
- f.order = append(f.order, m)
- } else {
- panic("Module does not have a name property, or it is not a string")
+ moduleType := module.ModuleType()
+ name := m.Name()
+ hasName := true
+ if name == "" {
+ // Use a prefixed module type as the name instead just in case this is something like a package
+ // of namespace module which does not require a name.
+ name = "#" + moduleType
+ hasName = false
}
+
+ if f.modules[name] != nil {
+ if hasName {
+ panic(fmt.Sprintf("Module %q already exists in bp file", name))
+ } else {
+ panic(fmt.Sprintf("Unnamed module type %q already exists in bp file", moduleType))
+ }
+ }
+
+ f.modules[name] = m
+ f.order = append(f.order, m)
}
func (f *bpFile) newModule(moduleType string) *bpModule {
diff --git a/sdk/sdk.go b/sdk/sdk.go
index 624c0fa..b1c8aeb 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -169,23 +169,27 @@
var fields []reflect.StructField
// Iterate over the member types creating StructField and sdkMemberListProperty objects.
- for f, memberType := range sdkMemberTypes {
+ nextFieldIndex := 0
+ for _, memberType := range sdkMemberTypes {
+
p := memberType.SdkPropertyName()
- // Create a dynamic exported field for the member type's property.
- fields = append(fields, reflect.StructField{
- Name: proptools.FieldNameForProperty(p),
- Type: reflect.TypeOf([]string{}),
- Tag: `android:"arch_variant"`,
- })
+ var getter func(properties interface{}) []string
+ var setter func(properties interface{}, list []string)
+ if memberType.RequiresBpProperty() {
+ // Create a dynamic exported field for the member type's property.
+ 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
- // cause all funcs to use the last value.
- fieldIndex := f
+ // Copy the field index for use in the getter func as using the loop variable directly will
+ // cause all funcs to use the last value.
+ fieldIndex := nextFieldIndex
+ nextFieldIndex += 1
- // Create an sdkMemberListProperty for the member type.
- memberListProperty := &sdkMemberListProperty{
- getter: func(properties interface{}) []string {
+ getter = func(properties interface{}) []string {
// The properties is expected to be of the following form (where
// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
// properties *struct {<Module_types> []string, ....}
@@ -195,9 +199,9 @@
//
list := reflect.ValueOf(properties).Elem().Field(fieldIndex).Interface().([]string)
return list
- },
+ }
- setter: func(properties interface{}, list []string) {
+ setter = func(properties interface{}, list []string) {
// The properties is expected to be of the following form (where
// <Module_types> is the name of an SdkMemberType.SdkPropertyName().
// properties *struct {<Module_types> []string, ....}
@@ -206,8 +210,13 @@
// *properties.<Module_types> = list
//
reflect.ValueOf(properties).Elem().Field(fieldIndex).Set(reflect.ValueOf(list))
- },
+ }
+ }
+ // Create an sdkMemberListProperty for the member type.
+ memberListProperty := &sdkMemberListProperty{
+ getter: getter,
+ setter: setter,
memberType: memberType,
// Dependencies added directly from member properties are always exported.
@@ -402,6 +411,9 @@
// Add dependencies from enabled and non CommonOS variants to the sdk member variants.
if s.Enabled() && !s.IsCommonOSVariant() {
for _, memberListProperty := range s.memberListProperties() {
+ if memberListProperty.getter == nil {
+ continue
+ }
names := memberListProperty.getter(s.dynamicMemberTypeListProperties)
if len(names) > 0 {
tag := memberListProperty.dependencyTag
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index e9129e0..12545d6 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -525,4 +525,43 @@
`),
)
})
+
+ t.Run("SOONG_SDK_SNAPSHOT_PREFER=true", func(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ preparer,
+ android.FixtureMergeEnv(map[string]string{
+ "SOONG_SDK_SNAPSHOT_PREFER": "true",
+ }),
+ ).RunTest(t)
+
+ checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip")
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_myjavalib@current",
+ sdk_member_name: "myjavalib",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+java_import {
+ name: "myjavalib",
+ prefer: true,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ jars: ["java/myjavalib.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ java_header_libs: ["mysdk_myjavalib@current"],
+}
+ `),
+ )
+ })
}
diff --git a/sdk/update.go b/sdk/update.go
index 457cbd9..a265676 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -29,6 +29,14 @@
"android/soong/android"
)
+// Environment variables that affect the generated snapshot
+// ========================================================
+//
+// SOONG_SDK_SNAPSHOT_PREFER
+// By default every unversioned module in the generated snapshot has prefer: false. Building it
+// with SOONG_SDK_SNAPSHOT_PREFER=true will force them to use prefer: true.
+//
+
var pctx = android.NewPackageContext("android/soong/sdk")
var (
@@ -258,8 +266,11 @@
}
s.builderForTests = builder
- // Create the prebuilt modules for each of the member modules.
+ // Group the variants for each member module together and then group the members of each member
+ // type together.
members := s.groupMemberVariantsByMemberThenType(ctx, memberVariantDeps)
+
+ // Create the prebuilt modules for each of the member modules.
for _, member := range members {
memberType := member.memberType
@@ -274,7 +285,9 @@
// Create a transformer that will transform an unversioned module by replacing any references
// to internal members with a unique module name and setting prefer: false.
- unversionedTransformer := unversionedTransformation{builder: builder}
+ unversionedTransformer := unversionedTransformation{
+ builder: builder,
+ }
for _, unversioned := range builder.prebuiltOrder {
// Prune any empty property sets.
@@ -503,15 +516,19 @@
}
combined := sdkVariantToCombinedProperties[memberVariantDep.sdkVariant]
- memberTypeProperty := s.memberListProperty(memberVariantDep.memberType)
+ memberListProperty := s.memberListProperty(memberVariantDep.memberType)
memberName := ctx.OtherModuleName(memberVariantDep.variant)
+ if memberListProperty.getter == nil {
+ continue
+ }
+
// Append the member to the appropriate list, if it is not already present in the list.
- memberList := memberTypeProperty.getter(combined.dynamicProperties)
+ memberList := memberListProperty.getter(combined.dynamicProperties)
if !android.InList(memberName, memberList) {
memberList = append(memberList, memberName)
}
- memberTypeProperty.setter(combined.dynamicProperties, memberList)
+ memberListProperty.setter(combined.dynamicProperties, memberList)
}
return list
@@ -563,6 +580,9 @@
dynamicMemberTypeListProperties := combined.dynamicProperties
for _, memberListProperty := range s.memberListProperties() {
+ if memberListProperty.getter == nil {
+ continue
+ }
names := memberListProperty.getter(dynamicMemberTypeListProperties)
if len(names) > 0 {
propertySet.AddProperty(memberListProperty.propertyName(), builder.versionedSdkMemberNames(names, false))
@@ -596,9 +616,11 @@
func (t unversionedToVersionedTransformation) transformModule(module *bpModule) *bpModule {
// Use a versioned name for the module but remember the original name for the
// snapshot.
- name := module.getValue("name").(string)
+ name := module.Name()
module.setProperty("name", t.builder.versionedSdkMemberName(name, true))
module.insertAfter("name", "sdk_member_name", name)
+ // Remove the prefer property if present as versioned modules never need marking with prefer.
+ module.removeProperty("prefer")
return module
}
@@ -618,12 +640,8 @@
func (t unversionedTransformation) transformModule(module *bpModule) *bpModule {
// If the module is an internal member then use a unique name for it.
- name := module.getValue("name").(string)
+ name := module.Name()
module.setProperty("name", t.builder.unversionedSdkMemberName(name, true))
-
- // Set prefer: false - this is not strictly required as that is the default.
- module.insertAfter("name", "prefer", false)
-
return module
}
@@ -674,12 +692,26 @@
func outputPropertySet(contents *generatedContents, set *bpPropertySet) {
contents.Indent()
+ addComment := func(name string) {
+ if text, ok := set.comments[name]; ok {
+ for _, line := range strings.Split(text, "\n") {
+ contents.Printfln("// %s", line)
+ }
+ }
+ }
+
// Output the properties first, followed by the nested sets. This ensures a
// consistent output irrespective of whether property sets are created before
// or after the properties. This simplifies the creation of the module.
for _, name := range set.order {
value := set.getValue(name)
+ // Do not write property sets in the properties phase.
+ if _, ok := value.(*bpPropertySet); ok {
+ continue
+ }
+
+ addComment(name)
switch v := value.(type) {
case []string:
length := len(v)
@@ -700,9 +732,6 @@
case bool:
contents.Printfln("%s: %t,", name, v)
- case *bpPropertySet:
- // Do not write property sets in the properties phase.
-
default:
contents.Printfln("%s: %q,", name, value)
}
@@ -714,6 +743,7 @@
// Only write property sets in the sets phase.
switch v := value.(type) {
case *bpPropertySet:
+ addComment(name)
contents.Printfln("%s: {", name)
outputPropertySet(contents, v)
contents.Printfln("},")
@@ -732,7 +762,9 @@
func (s *sdk) GetUnversionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
- return !strings.Contains(module.properties["name"].(string), "@")
+ name := module.Name()
+ // Include modules that are either unversioned or have no name.
+ return !strings.Contains(name, "@")
})
return contents.content.String()
}
@@ -740,7 +772,9 @@
func (s *sdk) GetVersionedAndroidBpContentsForTests() string {
contents := &generatedContents{}
generateFilteredBpContents(contents, s.builderForTests.bpFile, func(module *bpModule) bool {
- return strings.Contains(module.properties["name"].(string), "@")
+ name := module.Name()
+ // Include modules that are either versioned or have no name.
+ return name == "" || strings.Contains(name, "@")
})
return contents.content.String()
}
@@ -1362,6 +1396,21 @@
memberType := member.memberType
+ // Do not add the prefer property if the member snapshot module is a source module type.
+ if !memberType.UsesSourceModuleTypeInSnapshot() {
+ // Set the prefer based on the environment variable. This is a temporary work around to allow a
+ // snapshot to be created that sets prefer: true.
+ // TODO(b/174997203): Remove once the ability to select the modules to prefer can be done
+ // dynamically at build time not at snapshot generation time.
+ prefer := ctx.sdkMemberContext.Config().IsEnvTrue("SOONG_SDK_SNAPSHOT_PREFER")
+
+ // Set prefer. Setting this to false is not strictly required as that is the default but it does
+ // provide a convenient hook to post-process the generated Android.bp file, e.g. in tests to
+ // check the behavior when a prebuilt is preferred. It also makes it explicit what the default
+ // behavior is for the module.
+ bpModule.insertAfter("name", "prefer", prefer)
+ }
+
// Group the variants by os type.
variantsByOsType := make(map[android.OsType][]android.Module)
variants := member.Variants()
diff --git a/third_party/zip/android_test.go b/third_party/zip/android_test.go
index 9932c1b..46588d4 100644
--- a/third_party/zip/android_test.go
+++ b/third_party/zip/android_test.go
@@ -140,3 +140,83 @@
t.Errorf("Expected UnompressedSize64 %d, got %d", w, g)
}
}
+
+// Test for b/187485108: zip64 output can't be read by p7zip 16.02.
+func TestZip64P7ZipRecords(t *testing.T) {
+ if testing.Short() {
+ t.Skip("slow test; skipping")
+ }
+
+ const size = uint32max + 1
+ zipBytes := &bytes.Buffer{}
+ zip := NewWriter(zipBytes)
+ f, err := zip.CreateHeaderAndroid(&FileHeader{
+ Name: "large",
+ Method: Store,
+ UncompressedSize64: size,
+ CompressedSize64: size,
+ })
+ if err != nil {
+ t.Fatalf("Create: %v", err)
+ }
+ _, err = f.Write(make([]byte, size))
+ if err != nil {
+ t.Fatalf("Write: %v", err)
+ }
+ err = zip.Close()
+ if err != nil {
+ t.Fatalf("Close: %v", err)
+ }
+
+ buf := zipBytes.Bytes()
+ p := findSignatureInBlock(buf)
+ if p < 0 {
+ t.Fatalf("Missing signature")
+ }
+
+ b := readBuf(buf[p+4:]) // skip signature
+ d := &directoryEnd{
+ diskNbr: uint32(b.uint16()),
+ dirDiskNbr: uint32(b.uint16()),
+ dirRecordsThisDisk: uint64(b.uint16()),
+ directoryRecords: uint64(b.uint16()),
+ directorySize: uint64(b.uint32()),
+ directoryOffset: uint64(b.uint32()),
+ commentLen: b.uint16(),
+ }
+
+ // p7zip 16.02 wants regular end record directoryRecords to be accurate.
+ if g, w := d.directoryRecords, uint64(1); g != w {
+ t.Errorf("wanted directoryRecords %d, got %d", w, g)
+ }
+
+ if g, w := d.directorySize, uint64(uint32max); g != w {
+ t.Errorf("wanted directorySize %d, got %d", w, g)
+ }
+
+ if g, w := d.directoryOffset, uint64(uint32max); g != w {
+ t.Errorf("wanted directoryOffset %d, got %d", w, g)
+ }
+
+ r := bytes.NewReader(buf)
+
+ p64, err := findDirectory64End(r, int64(p))
+ if err != nil {
+ t.Fatalf("findDirectory64End: %v", err)
+ }
+ if p < 0 {
+ t.Fatalf("findDirectory64End: not found")
+ }
+ err = readDirectory64End(r, p64, d)
+ if err != nil {
+ t.Fatalf("readDirectory64End: %v", err)
+ }
+
+ if g, w := d.directoryRecords, uint64(1); g != w {
+ t.Errorf("wanted directoryRecords %d, got %d", w, g)
+ }
+
+ if g, w := d.directoryOffset, uint64(uint32max); g <= w {
+ t.Errorf("wanted directoryOffset > %d, got %d", w, g)
+ }
+}
diff --git a/third_party/zip/writer.go b/third_party/zip/writer.go
index 8dd986e..f526838 100644
--- a/third_party/zip/writer.go
+++ b/third_party/zip/writer.go
@@ -155,7 +155,14 @@
// store max values in the regular end record to signal that
// that the zip64 values should be used instead
- records = uint16max
+ // BEGIN ANDROID CHANGE: only store uintmax for the number of entries in the regular
+ // end record if it doesn't fit. p7zip 16.02 rejects zip files where the number of
+ // entries in the regular end record is larger than the number of entries counted
+ // in the central directory.
+ if records > uint16max {
+ records = uint16max
+ }
+ // END ANDROID CHANGE
size = uint32max
offset = uint32max
}