Merge "Add --release and --lib-variant to the instructions to update ABI dumps" into main
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index 7317587..ee9891d 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -130,6 +130,7 @@
AconfigFiles: mergedAconfigFiles,
ModeInfos: mergedModeInfos,
})
+ ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
}
}
diff --git a/android/apex.go b/android/apex.go
index dc0aeed..fcbd13e 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -37,11 +37,7 @@
// Accessible via `ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)`
type ApexInfo struct {
// Name of the apex variation that this module (i.e. the apex variant of the module) is
- // mutated into, or "" for a platform (i.e. non-APEX) variant. Note that this name and the
- // Soong module name of the APEX can be different. That happens when there is
- // `override_apex` that overrides `apex`. In that case, both Soong modules have the same
- // apex variation name which usually is `com.android.foo`. This name is also the `name`
- // in the path `/apex/<name>` where this apex is activated on at runtime.
+ // mutated into, or "" for a platform (i.e. non-APEX) variant.
//
// Also note that a module can be included in multiple APEXes, in which case, the module is
// mutated into one or more variants, each of which is for an APEX. The variants then can
diff --git a/android/deptag.go b/android/deptag.go
index 77b9d61..c7ba4d3 100644
--- a/android/deptag.go
+++ b/android/deptag.go
@@ -44,21 +44,6 @@
return false
}
-// Dependency tags can implement this interface and return true from SkipToTransitiveDeps to
-// annotate that this dependency isn't installed, but its transitive dependencies are. This is
-// useful when a module is built into another module (ex: static linking) but the module still has
-// runtime dependencies.
-type SkipToTransitiveDepsTag interface {
- SkipToTransitiveDeps() bool
-}
-
-func IsSkipToTransitiveDepsTag(tag blueprint.DependencyTag) bool {
- if i, ok := tag.(SkipToTransitiveDepsTag); ok {
- return i.SkipToTransitiveDeps()
- }
- return false
-}
-
type PropagateAconfigValidationDependencyTag interface {
PropagateAconfigValidation() bool
}
diff --git a/android/makevars.go b/android/makevars.go
index b6bc14e..f92f458 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -507,12 +507,13 @@
if extraFiles := install.extraFiles; extraFiles != nil {
fmt.Fprintf(buf, "\t( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} ) || \\\n", extraFiles.dir.String(), extraFiles.zip.String())
fmt.Fprintf(buf, "\t ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )\n")
- fmt.Fprintf(buf, "EXTRA_INSTALL_ZIPS += %s:%s\n", extraFiles.dir.String(), extraFiles.zip.String())
+ fmt.Fprintf(buf, "EXTRA_INSTALL_ZIPS += %s:%s:%s\n", install.to.String(), extraFiles.dir.String(), extraFiles.zip.String())
}
fmt.Fprintln(buf)
}
fmt.Fprintf(buf, ".KATI_READONLY := EXTRA_INSTALL_ZIPS\n")
+ fmt.Fprintf(buf, "$(KATI_visibility_prefix EXTRA_INSTALL_ZIPS,build/make/core/Makefile)\n")
for _, symlink := range symlinks {
fmt.Fprintf(buf, "%s:", symlink.to.String())
diff --git a/android/module.go b/android/module.go
index d7f0537..4dc1688 100644
--- a/android/module.go
+++ b/android/module.go
@@ -902,6 +902,9 @@
installedInitRcPaths InstallPaths
installedVintfFragmentsPaths InstallPaths
+ // Merged Aconfig files for all transitive deps.
+ aconfigFilePaths Paths
+
// set of dependency module:location mappings used to populate the license metadata for
// apex containers.
licenseInstallMap []string
@@ -1066,7 +1069,8 @@
// TODO(jiyong): the Make-side does this only when the required module is a shared
// library or a native test.
bothInAndroid := ctx.Device() && target.Os.Class == Device
- nativeArch := InList(ctx.Arch().ArchType.Multilib, []string{"lib32", "lib64"})
+ nativeArch := InList(ctx.Arch().ArchType.Multilib, []string{"lib32", "lib64"}) &&
+ InList(target.Arch.ArchType.Multilib, []string{"lib32", "lib64"})
sameBitness := ctx.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib
if bothInAndroid && nativeArch && !sameBitness {
return
@@ -1470,27 +1474,15 @@
var installDeps []*DepSet[InstallPath]
var packagingSpecs []*DepSet[PackagingSpec]
ctx.VisitDirectDeps(func(dep Module) {
- depTag := ctx.OtherModuleDependencyTag(dep)
- // If this is true, the direct outputs from the module is not gathered, but its
- // transitive deps are still gathered.
- skipToTransitive := IsSkipToTransitiveDepsTag(depTag)
- if isInstallDepNeeded(dep, depTag) || skipToTransitive {
+ if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
// Installation is still handled by Make, so anything hidden from Make is not
// installable.
if !dep.IsHideFromMake() && !dep.IsSkipInstall() {
- if skipToTransitive {
- installDeps = append(installDeps, dep.base().installFilesDepSet.transitive...)
- } else {
- installDeps = append(installDeps, dep.base().installFilesDepSet)
- }
+ installDeps = append(installDeps, dep.base().installFilesDepSet)
}
// Add packaging deps even when the dependency is not installed so that uninstallable
// modules can still be packaged. Often the package will be installed instead.
- if skipToTransitive {
- packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet.transitive...)
- } else {
- packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
- }
+ packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet)
}
})
@@ -1990,6 +1982,7 @@
TargetDependencies: targetRequired,
HostDependencies: hostRequired,
Data: data,
+ Required: m.RequiredModuleNames(),
}
SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON)
}
@@ -2169,9 +2162,19 @@
}
return proptools.ConfigurableValueUndefined()
case "product_variable":
- // TODO(b/323382414): Might add these on a case-by-case basis
- ctx.OtherModulePropertyErrorf(m, property, "TODO(b/323382414): Product variables are not yet supported in selects")
- return proptools.ConfigurableValueUndefined()
+ if condition.NumArgs() != 1 {
+ ctx.OtherModulePropertyErrorf(m, property, "product_variable requires 1 argument, found %d", condition.NumArgs())
+ return proptools.ConfigurableValueUndefined()
+ }
+ variable := condition.Arg(0)
+ switch variable {
+ case "debuggable":
+ return proptools.ConfigurableValueBool(ctx.Config().Debuggable())
+ default:
+ // TODO(b/323382414): Might add these on a case-by-case basis
+ ctx.OtherModulePropertyErrorf(m, property, fmt.Sprintf("TODO(b/323382414): Product variable %q is not yet supported in selects", variable))
+ return proptools.ConfigurableValueUndefined()
+ }
case "soong_config_variable":
if condition.NumArgs() != 2 {
ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", condition.NumArgs())
diff --git a/android/module_context.go b/android/module_context.go
index 605d3ba..18adb30 100644
--- a/android/module_context.go
+++ b/android/module_context.go
@@ -482,6 +482,10 @@
return m.packageFile(fullInstallPath, srcPath, false)
}
+func (m *moduleContext) getAconfigPaths() *Paths {
+ return &m.module.base().aconfigFilePaths
+}
+
func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec {
licenseFiles := m.Module().EffectiveLicenseFiles()
spec := PackagingSpec{
@@ -492,6 +496,8 @@
effectiveLicenseFiles: &licenseFiles,
partition: fullInstallPath.partition,
skipInstall: m.skipInstall(),
+ aconfigPaths: m.getAconfigPaths(),
+ archType: m.target.Arch.ArchType,
}
m.packagingSpecs = append(m.packagingSpecs, spec)
return spec
@@ -616,6 +622,8 @@
executable: false,
partition: fullInstallPath.partition,
skipInstall: m.skipInstall(),
+ aconfigPaths: m.getAconfigPaths(),
+ archType: m.target.Arch.ArchType,
})
return fullInstallPath
@@ -658,6 +666,8 @@
executable: false,
partition: fullInstallPath.partition,
skipInstall: m.skipInstall(),
+ aconfigPaths: m.getAconfigPaths(),
+ archType: m.target.Arch.ArchType,
})
return fullInstallPath
diff --git a/android/module_info_json.go b/android/module_info_json.go
index 1c0a38e..ee552dc 100644
--- a/android/module_info_json.go
+++ b/android/module_info_json.go
@@ -17,6 +17,7 @@
HostDependencies []string `json:"host_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).HOST_REQUIRED_FROM_TARGET))
TargetDependencies []string `json:"target_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).TARGET_REQUIRED_FROM_HOST))
Data []string `json:"data,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_DATA))
+ Required []string `json:"required,omitempty"` // $(sort $(ALL_MODULES.$(m).REQUIRED_FROM_TARGET))
}
type ModuleInfoJSON struct {
@@ -77,6 +78,7 @@
sortAndUnique(&moduleInfoJSONCopy.core.HostDependencies)
sortAndUnique(&moduleInfoJSONCopy.core.TargetDependencies)
sortAndUnique(&moduleInfoJSONCopy.core.Data)
+ sortAndUnique(&moduleInfoJSONCopy.core.Required)
sortAndUnique(&moduleInfoJSONCopy.Class)
sortAndUnique(&moduleInfoJSONCopy.Tags)
diff --git a/android/override_module.go b/android/override_module.go
index 21cf381..55f384f 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -28,6 +28,7 @@
// module based on it.
import (
+ "fmt"
"sort"
"sync"
@@ -120,7 +121,7 @@
addOverride(o OverrideModule)
getOverrides() []OverrideModule
- override(ctx BaseModuleContext, m Module, o OverrideModule)
+ override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule)
GetOverriddenBy() string
GetOverriddenByModuleDir() string
@@ -191,15 +192,14 @@
}
// Overrides a base module with the given OverrideModule.
-func (b *OverridableModuleBase) override(ctx BaseModuleContext, m Module, o OverrideModule) {
-
+func (b *OverridableModuleBase) override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule) {
for _, p := range b.overridableProperties {
for _, op := range o.getOverridingProperties() {
if proptools.TypeEqual(p, op) {
err := proptools.ExtendProperties(p, op, nil, proptools.OrderReplace)
if err != nil {
if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ ctx.OtherModulePropertyErrorf(bm, propertyErr.Property, "%s", propertyErr.Err.Error())
} else {
panic(err)
}
@@ -210,7 +210,7 @@
// Adds the base module to the overrides property, if exists, of the overriding module. See the
// comment on OverridableModuleBase.overridesProperty for details.
if b.overridesProperty != nil {
- *b.overridesProperty = append(*b.overridesProperty, ctx.ModuleName())
+ *b.overridesProperty = append(*b.overridesProperty, ctx.OtherModuleName(bm))
}
b.overridableModuleProperties.OverriddenBy = o.Name()
b.overridableModuleProperties.OverriddenByModuleDir = o.ModuleDir()
@@ -235,7 +235,7 @@
// to keep them in this order and not put any order mutators between them.
func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) {
ctx.BottomUp("override_deps", overrideModuleDepsMutator).Parallel()
- ctx.BottomUp("perform_override", performOverrideMutator).Parallel()
+ ctx.Transition("override", &overrideTransitionMutator{})
// overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can
// add deps from overridable properties.
ctx.BottomUp("overridable_deps", overridableModuleDepsMutator).Parallel()
@@ -262,18 +262,6 @@
ctx.PropertyErrorf("base", "%q is not a valid module name", base)
return
}
- // See if there's a prebuilt module that overrides this override module with prefer flag,
- // in which case we call HideFromMake on the corresponding variant later.
- ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
- prebuilt := GetEmbeddedPrebuilt(dep)
- if prebuilt == nil {
- panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
- }
- if prebuilt.UsePrebuilt() {
- module.setOverriddenByPrebuilt(dep)
- return
- }
- })
baseModule := ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)[0]
if o, ok := baseModule.(OverridableModule); ok {
overrideModule := ctx.Module().(OverrideModule)
@@ -285,11 +273,13 @@
// Now, goes through all overridable modules, finds all modules overriding them, creates a local
// variant for each of them, and performs the actual overriding operation by calling override().
-func performOverrideMutator(ctx BottomUpMutatorContext) {
+type overrideTransitionMutator struct{}
+
+func (overrideTransitionMutator) Split(ctx BaseModuleContext) []string {
if b, ok := ctx.Module().(OverridableModule); ok {
overrides := b.getOverrides()
if len(overrides) == 0 {
- return
+ return []string{""}
}
variants := make([]string, len(overrides)+1)
// The first variant is for the original, non-overridden, base module.
@@ -297,27 +287,69 @@
for i, o := range overrides {
variants[i+1] = o.(Module).Name()
}
- mods := ctx.CreateLocalVariations(variants...)
- // Make the original variation the default one to depend on if no other override module variant
- // is specified.
- ctx.AliasVariation(variants[0])
- for i, o := range overrides {
- mods[i+1].(OverridableModule).override(ctx, mods[i+1], o)
- if prebuilt := o.getOverriddenByPrebuilt(); prebuilt != nil {
- // The overriding module itself, too, is overridden by a prebuilt.
- // Perform the same check for replacement
- checkInvariantsForSourceAndPrebuilt(ctx, mods[i+1], prebuilt)
- // Copy the flag and hide it in make
- mods[i+1].ReplacedByPrebuilt()
- }
- }
+ return variants
} else if o, ok := ctx.Module().(OverrideModule); ok {
// Create a variant of the overriding module with its own name. This matches the above local
// variant name rule for overridden modules, and thus allows ReplaceDependencies to match the
// two.
- ctx.CreateLocalVariations(o.Name())
- // To allow dependencies to be added without having to know the above variation.
- ctx.AliasVariation(o.Name())
+ return []string{o.Name()}
+ }
+
+ return []string{""}
+}
+
+func (overrideTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
+ if o, ok := ctx.Module().(OverrideModule); ok {
+ if ctx.DepTag() == overrideBaseDepTag {
+ return o.Name()
+ }
+ }
+
+ // Variations are always local and shouldn't affect the variant used for dependencies
+ return ""
+}
+
+func (overrideTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
+ if _, ok := ctx.Module().(OverridableModule); ok {
+ return incomingVariation
+ } else if o, ok := ctx.Module().(OverrideModule); ok {
+ // To allow dependencies to be added without having to know the variation.
+ return o.Name()
+ }
+
+ return ""
+}
+
+func (overrideTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
+ if o, ok := ctx.Module().(OverrideModule); ok {
+ overridableDeps := ctx.GetDirectDepsWithTag(overrideBaseDepTag)
+ if len(overridableDeps) > 1 {
+ panic(fmt.Errorf("expected a single dependency with overrideBaseDepTag, found %q", overridableDeps))
+ } else if len(overridableDeps) == 1 {
+ b := overridableDeps[0].(OverridableModule)
+ b.override(ctx, b, o)
+
+ checkPrebuiltReplacesOverride(ctx, b)
+ }
+ }
+}
+
+func checkPrebuiltReplacesOverride(ctx BottomUpMutatorContext, b OverridableModule) {
+ // See if there's a prebuilt module that overrides this override module with prefer flag,
+ // in which case we call HideFromMake on the corresponding variant later.
+ prebuiltDeps := ctx.GetDirectDepsWithTag(PrebuiltDepTag)
+ for _, prebuiltDep := range prebuiltDeps {
+ prebuilt := GetEmbeddedPrebuilt(prebuiltDep)
+ if prebuilt == nil {
+ panic("PrebuiltDepTag leads to a non-prebuilt module " + prebuiltDep.Name())
+ }
+ if prebuilt.UsePrebuilt() {
+ // The overriding module itself, too, is overridden by a prebuilt.
+ // Perform the same check for replacement
+ checkInvariantsForSourceAndPrebuilt(ctx, b, prebuiltDep)
+ // Copy the flag and hide it in make
+ b.ReplacedByPrebuilt()
+ }
}
}
diff --git a/android/packaging.go b/android/packaging.go
index fe61da1..ae412e1 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -20,6 +20,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
// PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A
@@ -48,6 +49,12 @@
// is created via InstallFile or InstallSymlink) or a simple packaging (i.e. created via
// PackageFile).
skipInstall bool
+
+ // Paths of aconfig files for the built artifact
+ aconfigPaths *Paths
+
+ // ArchType of the module which produced this packaging spec
+ archType ArchType
}
func (p *PackagingSpec) Equals(other *PackagingSpec) bool {
@@ -102,6 +109,11 @@
return p.skipInstall
}
+// Paths of aconfig files for the built artifact
+func (p *PackagingSpec) GetAconfigPaths() Paths {
+ return *p.aconfigPaths
+}
+
type PackageModule interface {
Module
packagingBase() *PackagingBase
@@ -131,18 +143,24 @@
// for rare cases like when there's a dependency to a module which exists in certain repo
// checkouts, this is needed.
IgnoreMissingDependencies bool
+
+ // If this is set to true by a module type inheriting PackagingBase, the deps property
+ // collects the first target only even with compile_multilib: true.
+ DepsCollectFirstTargetOnly bool
}
type depsProperty struct {
// Modules to include in this package
- Deps []string `android:"arch_variant"`
+ Deps proptools.Configurable[[]string] `android:"arch_variant"`
}
type packagingMultilibProperties struct {
- First depsProperty `android:"arch_variant"`
- Common depsProperty `android:"arch_variant"`
- Lib32 depsProperty `android:"arch_variant"`
- Lib64 depsProperty `android:"arch_variant"`
+ First depsProperty `android:"arch_variant"`
+ Common depsProperty `android:"arch_variant"`
+ Lib32 depsProperty `android:"arch_variant"`
+ Lib64 depsProperty `android:"arch_variant"`
+ Both depsProperty `android:"arch_variant"`
+ Prefer32 depsProperty `android:"arch_variant"`
}
type packagingArchProperties struct {
@@ -153,8 +171,8 @@
}
type PackagingProperties struct {
- Deps []string `android:"arch_variant"`
- Multilib packagingMultilibProperties `android:"arch_variant"`
+ Deps proptools.Configurable[[]string] `android:"arch_variant"`
+ Multilib packagingMultilibProperties `android:"arch_variant"`
Arch packagingArchProperties
}
@@ -172,22 +190,55 @@
// multi target, deps is selected for each of the targets and is NOT selected for the current
// architecture which would be Common.
func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []string {
- var ret []string
- if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
- ret = append(ret, p.properties.Deps...)
- } else if arch.Multilib == "lib32" {
- ret = append(ret, p.properties.Multilib.Lib32.Deps...)
- } else if arch.Multilib == "lib64" {
- ret = append(ret, p.properties.Multilib.Lib64.Deps...)
- } else if arch == Common {
- ret = append(ret, p.properties.Multilib.Common.Deps...)
+ get := func(prop proptools.Configurable[[]string]) []string {
+ return prop.GetOrDefault(ctx, nil)
}
- for i, t := range ctx.MultiTargets() {
- if t.Arch.ArchType == arch {
- ret = append(ret, p.properties.Deps...)
- if i == 0 {
- ret = append(ret, p.properties.Multilib.First.Deps...)
+ var ret []string
+ if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 {
+ ret = append(ret, get(p.properties.Deps)...)
+ } else if arch.Multilib == "lib32" {
+ ret = append(ret, get(p.properties.Multilib.Lib32.Deps)...)
+ // multilib.prefer32.deps are added for lib32 only when they support 32-bit arch
+ for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
+ if checkIfOtherModuleSupportsLib32(ctx, dep) {
+ ret = append(ret, dep)
+ }
+ }
+ } else if arch.Multilib == "lib64" {
+ ret = append(ret, get(p.properties.Multilib.Lib64.Deps)...)
+ // multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch
+ for _, dep := range get(p.properties.Multilib.Prefer32.Deps) {
+ if !checkIfOtherModuleSupportsLib32(ctx, dep) {
+ ret = append(ret, dep)
+ }
+ }
+ } else if arch == Common {
+ ret = append(ret, get(p.properties.Multilib.Common.Deps)...)
+ }
+
+ if p.DepsCollectFirstTargetOnly {
+ if len(get(p.properties.Multilib.First.Deps)) > 0 {
+ ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead")
+ }
+ for i, t := range ctx.MultiTargets() {
+ if t.Arch.ArchType == arch {
+ ret = append(ret, get(p.properties.Multilib.Both.Deps)...)
+ if i == 0 {
+ ret = append(ret, get(p.properties.Deps)...)
+ }
+ }
+ }
+ } else {
+ if len(get(p.properties.Multilib.Both.Deps)) > 0 {
+ ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead")
+ }
+ for i, t := range ctx.MultiTargets() {
+ if t.Arch.ArchType == arch {
+ ret = append(ret, get(p.properties.Deps)...)
+ if i == 0 {
+ ret = append(ret, get(p.properties.Multilib.First.Deps)...)
+ }
}
}
}
@@ -195,20 +246,20 @@
if ctx.Arch().ArchType == Common {
switch arch {
case Arm64:
- ret = append(ret, p.properties.Arch.Arm64.Deps...)
+ ret = append(ret, get(p.properties.Arch.Arm64.Deps)...)
case Arm:
- ret = append(ret, p.properties.Arch.Arm.Deps...)
+ ret = append(ret, get(p.properties.Arch.Arm.Deps)...)
case X86_64:
- ret = append(ret, p.properties.Arch.X86_64.Deps...)
+ ret = append(ret, get(p.properties.Arch.X86_64.Deps)...)
case X86:
- ret = append(ret, p.properties.Arch.X86.Deps...)
+ ret = append(ret, get(p.properties.Arch.X86.Deps)...)
}
}
return FirstUniqueStrings(ret)
}
-func (p *PackagingBase) getSupportedTargets(ctx BaseModuleContext) []Target {
+func getSupportedTargets(ctx BaseModuleContext) []Target {
var ret []Target
// The current and the common OS targets are always supported
ret = append(ret, ctx.Target())
@@ -220,6 +271,28 @@
return ret
}
+// getLib32Target returns the 32-bit target from the list of targets this module supports. If this
+// module doesn't support 32-bit target, nil is returned.
+func getLib32Target(ctx BaseModuleContext) *Target {
+ for _, t := range getSupportedTargets(ctx) {
+ if t.Arch.ArchType.Multilib == "lib32" {
+ return &t
+ }
+ }
+ return nil
+}
+
+// checkIfOtherModuleSUpportsLib32 returns true if 32-bit variant of dep exists.
+func checkIfOtherModuleSupportsLib32(ctx BaseModuleContext, dep string) bool {
+ t := getLib32Target(ctx)
+ if t == nil {
+ // This packaging module doesn't support 32bit. No point of checking if dep supports 32-bit
+ // or not.
+ return false
+ }
+ return ctx.OtherModuleFarDependencyVariantExists(t.Variations(), dep)
+}
+
// PackagingItem is a marker interface for dependency tags.
// Direct dependencies with a tag implementing PackagingItem are packaged in CopyDepsToZip().
type PackagingItem interface {
@@ -240,7 +313,7 @@
// See PackageModule.AddDeps
func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) {
- for _, t := range p.getSupportedTargets(ctx) {
+ for _, t := range getSupportedTargets(ctx) {
for _, dep := range p.getDepsForArch(ctx, t.Arch.ArchType) {
if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) {
continue
@@ -252,11 +325,31 @@
func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
m := make(map[string]PackagingSpec)
+
+ var arches []ArchType
+ for _, target := range getSupportedTargets(ctx) {
+ arches = append(arches, target.Arch.ArchType)
+ }
+
+ // filter out packaging specs for unsupported architecture
+ filterArch := func(ps PackagingSpec) bool {
+ for _, arch := range arches {
+ if arch == ps.archType {
+ return true
+ }
+ }
+ return false
+ }
+
ctx.VisitDirectDeps(func(child Module) {
if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
return
}
for _, ps := range child.TransitivePackagingSpecs() {
+ if !filterArch(ps) {
+ continue
+ }
+
if filter != nil {
if !filter(ps) {
continue
diff --git a/android/packaging_test.go b/android/packaging_test.go
index 4b72c24..89df8ef 100644
--- a/android/packaging_test.go
+++ b/android/packaging_test.go
@@ -15,6 +15,8 @@
package android
import (
+ "fmt"
+ "strings"
"testing"
"github.com/google/blueprint"
@@ -25,9 +27,8 @@
type componentTestModule struct {
ModuleBase
props struct {
- Deps []string
- Build_only_deps []string
- Skip_install *bool
+ Deps []string
+ Skip_install *bool
}
}
@@ -37,18 +38,6 @@
InstallAlwaysNeededDependencyTag
}
-// dep tag for build_only_deps
-type buildOnlyDepTag struct {
- blueprint.BaseDependencyTag
- InstallAlwaysNeededDependencyTag
-}
-
-var _ SkipToTransitiveDepsTag = (*buildOnlyDepTag)(nil)
-
-func (tag buildOnlyDepTag) SkipToTransitiveDeps() bool {
- return true
-}
-
func componentTestModuleFactory() Module {
m := &componentTestModule{}
m.AddProperties(&m.props)
@@ -58,7 +47,6 @@
func (m *componentTestModule) DepsMutator(ctx BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), installDepTag{}, m.props.Deps...)
- ctx.AddDependency(ctx.Module(), buildOnlyDepTag{}, m.props.Build_only_deps...)
}
func (m *componentTestModule) GenerateAndroidBuildActions(ctx ModuleContext) {
@@ -81,18 +69,15 @@
entries []string
}
-func packageMultiTargetTestModuleFactory() Module {
+func packageTestModuleFactory(multiTarget bool, depsCollectFirstTargetOnly bool) Module {
module := &packageTestModule{}
InitPackageModule(module)
- InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon)
- module.AddProperties(&module.properties)
- return module
-}
-
-func packageTestModuleFactory() Module {
- module := &packageTestModule{}
- InitPackageModule(module)
- InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
+ module.DepsCollectFirstTargetOnly = depsCollectFirstTargetOnly
+ if multiTarget {
+ InitAndroidMultiTargetsArchModule(module, DeviceSupported, MultilibCommon)
+ } else {
+ InitAndroidArchModule(module, DeviceSupported, MultilibBoth)
+ }
module.AddProperties(&module.properties)
return module
}
@@ -112,17 +97,24 @@
m.entries = m.CopyDepsToZip(ctx, m.GatherPackagingSpecs(ctx), zipFile)
}
-func runPackagingTest(t *testing.T, multitarget bool, bp string, expected []string) {
+type testConfig struct {
+ multiTarget bool
+ depsCollectFirstTargetOnly bool
+ debuggable bool
+}
+
+func runPackagingTest(t *testing.T, config testConfig, bp string, expected []string) {
t.Helper()
var archVariant string
- var moduleFactory ModuleFactory
- if multitarget {
+ if config.multiTarget {
archVariant = "android_common"
- moduleFactory = packageMultiTargetTestModuleFactory
} else {
archVariant = "android_arm64_armv8-a"
- moduleFactory = packageTestModuleFactory
+ }
+
+ moduleFactory := func() Module {
+ return packageTestModuleFactory(config.multiTarget, config.depsCollectFirstTargetOnly)
}
result := GroupFixturePreparers(
@@ -131,6 +123,9 @@
ctx.RegisterModuleType("component", componentTestModuleFactory)
ctx.RegisterModuleType("package_module", moduleFactory)
}),
+ FixtureModifyProductVariables(func(variables FixtureProductVariables) {
+ variables.Debuggable = proptools.BoolPtr(config.debuggable)
+ }),
FixtureWithRootAndroidBp(bp),
).RunTest(t)
@@ -142,8 +137,11 @@
}
func TestPackagingBaseMultiTarget(t *testing.T) {
- multiTarget := true
- runPackagingTest(t, multiTarget,
+ config := testConfig{
+ multiTarget: true,
+ depsCollectFirstTargetOnly: false,
+ }
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -155,7 +153,7 @@
}
`, []string{"lib64/foo"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -172,7 +170,7 @@
}
`, []string{"lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -190,7 +188,7 @@
}
`, []string{"lib32/foo", "lib32/bar", "lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -213,7 +211,7 @@
}
`, []string{"lib32/foo", "lib32/bar", "lib64/foo"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -235,7 +233,7 @@
}
`, []string{"lib32/foo", "lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -266,8 +264,11 @@
}
func TestPackagingBaseSingleTarget(t *testing.T) {
- multiTarget := false
- runPackagingTest(t, multiTarget,
+ config := testConfig{
+ multiTarget: false,
+ depsCollectFirstTargetOnly: false,
+ }
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -279,7 +280,7 @@
}
`, []string{"lib64/foo"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -296,7 +297,7 @@
}
`, []string{"lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -318,7 +319,7 @@
}
`, []string{"lib64/foo"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -339,7 +340,7 @@
}
`, []string{"lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -367,7 +368,7 @@
}
`, []string{"lib64/foo", "lib64/bar"})
- runPackagingTest(t, multiTarget,
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -388,8 +389,11 @@
func TestPackagingWithSkipInstallDeps(t *testing.T) {
// package -[dep]-> foo -[dep]-> bar -[dep]-> baz
// Packaging should continue transitively through modules that are not installed.
- multiTarget := false
- runPackagingTest(t, multiTarget,
+ config := testConfig{
+ multiTarget: false,
+ depsCollectFirstTargetOnly: false,
+ }
+ runPackagingTest(t, config,
`
component {
name: "foo",
@@ -413,15 +417,137 @@
`, []string{"lib64/foo", "lib64/bar", "lib64/baz"})
}
-func TestPackagingWithSkipToTransitvDeps(t *testing.T) {
- // packag -[deps]-> foo -[build_only_deps]-> bar -[deps]-> baz
- // bar isn't installed, but it brings baz to its parent.
- multiTarget := false
- runPackagingTest(t, multiTarget,
+func TestPackagingWithDepsCollectFirstTargetOnly(t *testing.T) {
+ config := testConfig{
+ multiTarget: true,
+ depsCollectFirstTargetOnly: true,
+ }
+ runPackagingTest(t, config,
`
component {
name: "foo",
- build_only_deps: ["bar"],
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ }
+ `, []string{"lib64/foo"})
+
+ runPackagingTest(t, config,
+ `
+ component {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ component {
+ name: "bar",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ }
+ `, []string{"lib64/foo", "lib64/bar"})
+
+ runPackagingTest(t, config,
+ `
+ component {
+ name: "foo",
+ deps: ["bar"],
+ }
+
+ component {
+ name: "bar",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ compile_multilib: "both",
+ }
+ `, []string{"lib64/foo", "lib64/bar"})
+
+ runPackagingTest(t, config,
+ `
+ component {
+ name: "foo",
+ }
+
+ component {
+ name: "bar",
+ compile_multilib: "32",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ multilib: {
+ lib32: {
+ deps: ["bar"],
+ },
+ },
+ compile_multilib: "both",
+ }
+ `, []string{"lib32/bar", "lib64/foo"})
+
+ runPackagingTest(t, config,
+ `
+ component {
+ name: "foo",
+ }
+
+ component {
+ name: "bar",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ multilib: {
+ both: {
+ deps: ["bar"],
+ },
+ },
+ compile_multilib: "both",
+ }
+ `, []string{"lib64/foo", "lib32/bar", "lib64/bar"})
+
+ runPackagingTest(t, config,
+ `
+ component {
+ name: "foo",
+ }
+
+ component {
+ name: "bar",
+ }
+
+ component {
+ name: "baz",
+ }
+
+ package_module {
+ name: "package",
+ deps: ["foo"],
+ arch: {
+ arm64: {
+ deps: ["bar"],
+ },
+ x86_64: {
+ deps: ["baz"],
+ },
+ },
+ compile_multilib: "both",
+ }
+ `, []string{"lib64/foo", "lib64/bar"})
+}
+
+func TestDebuggableDeps(t *testing.T) {
+ bp := `
+ component {
+ name: "foo",
}
component {
@@ -435,7 +561,94 @@
package_module {
name: "package",
- deps: ["foo"],
+ deps: ["foo"] + select(product_variable("debuggable"), {
+ true: ["bar"],
+ default: [],
+ }),
+ }`
+ testcases := []struct {
+ debuggable bool
+ expected []string
+ }{
+ {
+ debuggable: true,
+ expected: []string{"lib64/foo", "lib64/bar", "lib64/baz"},
+ },
+ {
+ debuggable: false,
+ expected: []string{"lib64/foo"},
+ },
+ }
+ for _, tc := range testcases {
+ config := testConfig{
+ debuggable: tc.debuggable,
}
- `, []string{"lib64/foo", "lib64/baz"})
+ runPackagingTest(t, config, bp, tc.expected)
+ }
+}
+
+func TestPrefer32Deps(t *testing.T) {
+ bpTemplate := `
+ component {
+ name: "foo",
+ compile_multilib: "both", // not needed but for clarity
+ }
+
+ component {
+ name: "foo_32only",
+ compile_multilib: "prefer32",
+ }
+
+ component {
+ name: "foo_64only",
+ compile_multilib: "64",
+ }
+
+ package_module {
+ name: "package",
+ compile_multilib: "%COMPILE_MULTILIB%",
+ multilib: {
+ prefer32: {
+ deps: %DEPS%,
+ },
+ },
+ }
+ `
+
+ testcases := []struct {
+ compileMultilib string
+ deps []string
+ expected []string
+ }{
+ {
+ compileMultilib: "first",
+ deps: []string{"foo", "foo_64only"},
+ expected: []string{"lib64/foo", "lib64/foo_64only"},
+ },
+ {
+ compileMultilib: "64",
+ deps: []string{"foo", "foo_64only"},
+ expected: []string{"lib64/foo", "lib64/foo_64only"},
+ },
+ {
+ compileMultilib: "32",
+ deps: []string{"foo", "foo_32only"},
+ expected: []string{"lib32/foo", "lib32/foo_32only"},
+ },
+ {
+ compileMultilib: "both",
+ deps: []string{"foo", "foo_32only", "foo_64only"},
+ expected: []string{"lib32/foo", "lib32/foo_32only", "lib64/foo_64only"},
+ },
+ }
+ for _, tc := range testcases {
+ config := testConfig{
+ multiTarget: true,
+ depsCollectFirstTargetOnly: true,
+ }
+ bp := strings.Replace(bpTemplate, "%COMPILE_MULTILIB%", tc.compileMultilib, -1)
+ bp = strings.Replace(bp, "%DEPS%", `["`+strings.Join(tc.deps, `", "`)+`"]`, -1)
+ fmt.Printf("bp = %s\n", bp)
+ runPackagingTest(t, config, bp, tc.expected)
+ }
}
diff --git a/android/util.go b/android/util.go
index 698a856..de4ca4d 100644
--- a/android/util.go
+++ b/android/util.go
@@ -302,6 +302,24 @@
return removed, result
}
+// FirstUniqueFunc returns all unique elements of a slice, keeping the first copy of
+// each. It does not modify the input slice. The eq function should return true
+// if two elements can be considered equal.
+func FirstUniqueFunc[SortableList ~[]Sortable, Sortable any](list SortableList, eq func(a, b Sortable) bool) SortableList {
+ k := 0
+outer:
+ for i := 0; i < len(list); i++ {
+ for j := 0; j < k; j++ {
+ if eq(list[i], list[j]) {
+ continue outer
+ }
+ }
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
+}
+
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It does not modify the input slice.
func FirstUniqueStrings(list []string) []string {
diff --git a/apex/apex.go b/apex/apex.go
index 9a80ec6..1dec61b 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -137,10 +137,6 @@
// Rust binaries with prefer_rlib:true add unnecessary dependencies.
Unwanted_transitive_deps []string
- // The minimum SDK version that this APEX must support at minimum. This is usually set to
- // the SDK version that the APEX was first introduced.
- Min_sdk_version *string
-
// Whether this APEX is considered updatable or not. When set to true, this will enforce
// additional rules for making sure that the APEX is truly updatable. To be updatable,
// min_sdk_version should be set as well. This will also disable the size optimizations like
@@ -388,6 +384,10 @@
// Trim against a specific Dynamic Common Lib APEX
Trim_against *string
+
+ // The minimum SDK version that this APEX must support at minimum. This is usually set to
+ // the SDK version that the APEX was first introduced.
+ Min_sdk_version *string
}
type apexBundle struct {
@@ -699,7 +699,12 @@
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ApexNativeDependencies, target android.Target, imageVariation string) {
binVariations := target.Variations()
libVariations := append(target.Variations(), blueprint.Variation{Mutator: "link", Variation: "shared"})
- rustLibVariations := append(target.Variations(), blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"})
+ rustLibVariations := append(
+ target.Variations(), []blueprint.Variation{
+ {Mutator: "rust_libraries", Variation: "dylib"},
+ {Mutator: "link", Variation: ""},
+ }...,
+ )
// Append "image" variation
binVariations = append(binVariations, blueprint.Variation{Mutator: "image", Variation: imageVariation})
@@ -1030,6 +1035,11 @@
// be built for this apexBundle.
apexVariationName := mctx.ModuleName() // could be com.android.foo
+ if overridable, ok := mctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" {
+ // use the overridden name com.mycompany.android.foo
+ apexVariationName = overridable.GetOverriddenBy()
+ }
+
a.properties.ApexVariationName = apexVariationName
testApexes := []string{}
if a.testApex {
@@ -1094,7 +1104,7 @@
if !mctx.Module().Enabled(mctx) {
return
}
- if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting() {
+ if apex, ok := mctx.Module().(*apexBundle); ok && apex.checkStrictUpdatabilityLinting(mctx) {
mctx.WalkDeps(func(child, parent android.Module) bool {
// b/208656169 Do not propagate strict updatability linting to libcore/
// These libs are available on the classpath during compilation
@@ -1188,8 +1198,9 @@
}
)
-func (a *apexBundle) checkStrictUpdatabilityLinting() bool {
- return a.Updatable() && !android.InList(a.ApexVariationName(), skipStrictUpdatabilityLintAllowlist)
+func (a *apexBundle) checkStrictUpdatabilityLinting(mctx android.TopDownMutatorContext) bool {
+ // The allowlist contains the base apex name, so use that instead of the ApexVariationName
+ return a.Updatable() && !android.InList(mctx.ModuleName(), skipStrictUpdatabilityLintAllowlist)
}
// apexUniqueVariationsMutator checks if any dependencies use unique apex variations. If so, use
@@ -1290,13 +1301,12 @@
func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []string {
// apexBundle itself is mutated so that it and its dependencies have the same apex variant.
if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) {
- return []string{ai.ApexVariationName()}
- } else if o, ok := ctx.Module().(*OverrideApex); ok {
- apexBundleName := o.GetOverriddenModuleName()
- if apexBundleName == "" {
- ctx.ModuleErrorf("base property is not set")
+ if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" {
+ return []string{overridable.GetOverriddenBy()}
}
- return []string{apexBundleName}
+ return []string{ai.ApexVariationName()}
+ } else if _, ok := ctx.Module().(*OverrideApex); ok {
+ return []string{ctx.ModuleName()}
}
return []string{""}
}
@@ -1309,9 +1319,12 @@
if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
return android.IncomingApexTransition(ctx, incomingVariation)
} else if ai, ok := ctx.Module().(ApexInfoMutator); ok {
+ if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" {
+ return overridable.GetOverriddenBy()
+ }
return ai.ApexVariationName()
- } else if o, ok := ctx.Module().(*OverrideApex); ok {
- return o.GetOverriddenModuleName()
+ } else if _, ok := ctx.Module().(*OverrideApex); ok {
+ return ctx.Module().Name()
}
return ""
@@ -1636,7 +1649,8 @@
func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, outputFile android.Path) apexFile {
dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
- return newApexFile(ctx, outputFile, outputFile.Base(), dirInApex, etc, prebuilt)
+ makeModuleName := strings.ReplaceAll(filepath.Join(dirInApex, outputFile.Base()), "/", "_")
+ return newApexFile(ctx, outputFile, makeModuleName, dirInApex, etc, prebuilt)
}
func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.PlatformCompatConfigIntf, depName string) apexFile {
@@ -2646,7 +2660,7 @@
// Only override the minSdkVersion value on Apexes which already specify
// a min_sdk_version (it's optional for non-updatable apexes), and that its
// min_sdk_version value is lower than the one to override with.
- minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.properties.Min_sdk_version))
+ minApiLevel := android.MinSdkVersionFromValue(ctx, proptools.String(a.overridableProperties.Min_sdk_version))
if minApiLevel.IsNone() {
return ""
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 9a5c2b4..965b4be 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5049,6 +5049,20 @@
// Make sure that the frameworks/base/Android.bp file exists as otherwise hidden API encoding
// is disabled.
android.FixtureAddTextFile("frameworks/base/Android.bp", ""),
+
+ // Make sure that we have atleast one platform library so that we can check the monolithic hiddenapi
+ // file creation.
+ java.FixtureConfigureBootJars("platform:foo"),
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["platform/Android.bp"] = []byte(`
+ java_library {
+ name: "foo",
+ srcs: ["Test.java"],
+ compile_dex: true,
+ }
+ `)
+ fs["platform/Test.java"] = nil
+ }),
)
checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) {
@@ -5143,7 +5157,7 @@
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
- checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
+ checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
my-bootclasspath-fragment/index.csv
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
@@ -5221,7 +5235,7 @@
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
- checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
+ checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
my-bootclasspath-fragment/index.csv
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
@@ -5410,7 +5424,7 @@
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
- checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
+ checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
my-bootclasspath-fragment/index.csv
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
@@ -5507,7 +5521,7 @@
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/hiddenapi-modular/encoded/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
- checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
+ checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
out/soong/.intermediates/my-bootclasspath-fragment/android_common_myapex/modular-hiddenapi/index.csv
@@ -5620,7 +5634,7 @@
checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/prebuilt_myapex.deapexer/android_common/deapexer/javalib/libbar.jar")
// Verify the correct module jars contribute to the hiddenapi index file.
- checkHiddenAPIIndexFromClassesInputs(t, ctx, ``)
+ checkHiddenAPIIndexFromClassesInputs(t, ctx, `out/soong/.intermediates/platform/foo/android_common/javac/foo.jar`)
checkHiddenAPIIndexFromFlagsInputs(t, ctx, `
my-bootclasspath-fragment/index.csv
out/soong/.intermediates/frameworks/base/boot/platform-bootclasspath/android_common/hiddenapi-monolithic/index-from-classes.csv
@@ -5908,6 +5922,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "current",
system_modules: "none",
+ use_embedded_native_libs: true,
jni_libs: ["libjni"],
stl: "none",
apex_available: [ "myapex" ],
@@ -6462,7 +6477,7 @@
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
}
- overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_bar").Rule("apexManifestRule")
+ overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_myoverrideapex").Rule("apexManifestRule")
overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"]
if overrideBarActualDefaultVersion != barExpectedDefaultVersion {
t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion)
@@ -6842,7 +6857,7 @@
`, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"}))
originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule)
- overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Module().(android.OverridableModule)
+ overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Module().(android.OverridableModule)
if originalVariant.GetOverriddenBy() != "" {
t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy())
}
@@ -6850,7 +6865,7 @@
t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy())
}
- module := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex")
+ module := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex")
apexRule := module.Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
@@ -8942,7 +8957,7 @@
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
}
- rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_myapex").Rule("diffApexContentRule")
+ rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Rule("diffApexContentRule")
if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual {
t.Errorf("allowed_files_file: expected %q but got %q", expected, actual)
}
@@ -11238,6 +11253,20 @@
android.FixtureMergeMockFs(map[string][]byte{
"system/sepolicy/apex/com.android.foo-file_contexts": nil,
}),
+ // Make sure that we have atleast one platform library so that we can check the monolithic hiddenapi
+ // file creation.
+ java.FixtureConfigureBootJars("platform:foo"),
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["platform/Android.bp"] = []byte(`
+ java_library {
+ name: "foo",
+ srcs: ["Test.java"],
+ compile_dex: true,
+ }
+ `)
+ fs["platform/Test.java"] = nil
+ }),
+
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.BuildFlags = map[string]string{
"RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": tc.selectedApexContributions,
@@ -11266,7 +11295,7 @@
variation := func(moduleName string) string {
ret := "android_common_com.android.foo"
if moduleName == "com.google.android.foo" {
- ret = "android_common_com.google.android.foo_com.android.foo"
+ ret = "android_common_com.google.android.foo_com.google.android.foo"
}
return ret
}
@@ -11531,3 +11560,118 @@
"depend on java_aconfig_library not passed as an input",
aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "quux"))
}
+
+func TestMultiplePrebuiltsWithSameBase(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ prebuilts: ["myetc", "myetc2"],
+ min_sdk_version: "29",
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ prebuilt_etc {
+ name: "myetc",
+ src: "myprebuilt",
+ filename: "myfilename",
+ }
+ prebuilt_etc {
+ name: "myetc2",
+ sub_dir: "mysubdir",
+ src: "myprebuilt",
+ filename: "myfilename",
+ }
+ `, withFiles(android.MockFS{
+ "packages/modules/common/build/allowed_deps.txt": nil,
+ }))
+
+ ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, ctx, ab)
+ var builder strings.Builder
+ data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
+ androidMk := builder.String()
+
+ android.AssertStringDoesContain(t, "not found", androidMk, "LOCAL_MODULE := etc_myfilename.myapex")
+ android.AssertStringDoesContain(t, "not found", androidMk, "LOCAL_MODULE := etc_mysubdir_myfilename.myapex")
+}
+
+func TestApexMinSdkVersionOverride(t *testing.T) {
+ checkMinSdkVersion := func(t *testing.T, module android.TestingModule, expectedMinSdkVersion string) {
+ args := module.Rule("apexRule").Args
+ optFlags := args["opt_flags"]
+ if !strings.Contains(optFlags, "--min_sdk_version "+expectedMinSdkVersion) {
+ t.Errorf("%s: Expected min_sdk_version=%s, got: %s", module.Module(), expectedMinSdkVersion, optFlags)
+ }
+ }
+
+ checkHasDep := func(t *testing.T, ctx *android.TestContext, m android.Module, wantDep android.Module) {
+ t.Helper()
+ found := false
+ ctx.VisitDirectDeps(m, func(dep blueprint.Module) {
+ if dep == wantDep {
+ found = true
+ }
+ })
+ if !found {
+ t.Errorf("Could not find a dependency from %v to %v\n", m, wantDep)
+ }
+ }
+
+ ctx := testApex(t, `
+ apex {
+ name: "com.android.apex30",
+ min_sdk_version: "30",
+ key: "apex30.key",
+ java_libs: ["javalib"],
+ }
+
+ java_library {
+ name: "javalib",
+ srcs: ["A.java"],
+ apex_available: ["com.android.apex30"],
+ min_sdk_version: "30",
+ sdk_version: "current",
+ }
+
+ override_apex {
+ name: "com.mycompany.android.apex30",
+ base: "com.android.apex30",
+ }
+
+ override_apex {
+ name: "com.mycompany.android.apex31",
+ base: "com.android.apex30",
+ min_sdk_version: "31",
+ }
+
+ apex_key {
+ name: "apex30.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ `, android.FixtureMergeMockFs(android.MockFS{
+ "system/sepolicy/apex/com.android.apex30-file_contexts": nil,
+ }),
+ )
+
+ baseModule := ctx.ModuleForTests("com.android.apex30", "android_common_com.android.apex30")
+ checkMinSdkVersion(t, baseModule, "30")
+
+ // Override module, but uses same min_sdk_version
+ overridingModuleSameMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex30_com.mycompany.android.apex30")
+ javalibApex30Variant := ctx.ModuleForTests("javalib", "android_common_apex30")
+ checkMinSdkVersion(t, overridingModuleSameMinSdkVersion, "30")
+ checkHasDep(t, ctx, overridingModuleSameMinSdkVersion.Module(), javalibApex30Variant.Module())
+
+ // Override module, uses different min_sdk_version
+ overridingModuleDifferentMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex31_com.mycompany.android.apex31")
+ javalibApex31Variant := ctx.ModuleForTests("javalib", "android_common_apex31")
+ checkMinSdkVersion(t, overridingModuleDifferentMinSdkVersion, "31")
+ checkHasDep(t, ctx, overridingModuleDifferentMinSdkVersion.Module(), javalibApex31Variant.Module())
+}
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 2be9c10..9f1e1e1 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -795,3 +795,127 @@
}
`)
}
+
+// Source and prebuilt apex provide different set of boot jars
+func TestNonBootJarMissingInPrebuiltFragment(t *testing.T) {
+ bp := `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ bootclasspath_fragments: ["apex-fragment"],
+ updatable: false,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ java_library {
+ name: "foo",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ apex_available: ["myapex"],
+ permitted_packages: ["bar"],
+ }
+
+ bootclasspath_fragment {
+ name: "apex-fragment",
+ contents: ["foo", "bar"],
+ apex_available:[ "myapex" ],
+ hidden_api: {
+ split_packages: ["*"],
+ },
+ }
+
+ prebuilt_apex {
+ name: "com.google.android.myapex", // mainline prebuilt selection logic in soong relies on the naming convention com.google.android
+ apex_name: "myapex",
+ source_apex_name: "myapex",
+ src: "myapex.apex",
+ exported_bootclasspath_fragments: ["apex-fragment"],
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["foo.jar"],
+ apex_available: ["myapex"],
+ permitted_packages: ["foo"],
+ }
+
+ prebuilt_bootclasspath_fragment {
+ name: "apex-fragment",
+ contents: ["foo"], // Unlike the source fragment, this is missing bar
+ apex_available:[ "myapex" ],
+ hidden_api: {
+ annotation_flags: "my-bootclasspath-fragment/annotation-flags.csv",
+ metadata: "my-bootclasspath-fragment/metadata.csv",
+ index: "my-bootclasspath-fragment/index.csv",
+ stub_flags: "my-bootclasspath-fragment/stub-flags.csv",
+ all_flags: "my-bootclasspath-fragment/all-flags.csv",
+ },
+ }
+
+ apex_contributions {
+ name: "my_apex_contributions",
+ api_domain: "myapex",
+ contents: [%v],
+ }
+ `
+ testCases := []struct {
+ desc string
+ configuredBootJars []string
+ apexContributionContents string
+ errorExpected bool
+ }{
+ {
+ desc: "Source apex is selected, and APEX_BOOT_JARS is correctly configured for source apex builds",
+ configuredBootJars: []string{"myapex:foo", "myapex:bar"},
+ },
+ {
+ desc: "Source apex is selected, and APEX_BOOT_JARS is missing bar",
+ configuredBootJars: []string{"myapex:foo"},
+ errorExpected: true,
+ },
+ {
+ desc: "Prebuilt apex is selected, and APEX_BOOT_JARS is correctly configured for prebuilt apex build",
+ configuredBootJars: []string{"myapex:foo"},
+ apexContributionContents: `"prebuilt_com.google.android.myapex"`,
+ },
+ {
+ desc: "Prebuilt apex is selected, and APEX_BOOT_JARS is missing foo",
+ configuredBootJars: []string{"myapex:bar"},
+ apexContributionContents: `"prebuilt_com.google.android.myapex"`,
+ errorExpected: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ fixture := android.GroupFixturePreparers(
+ prepareForTestWithPlatformBootclasspath,
+ PrepareForTestWithApexBuildComponents,
+ prepareForTestWithMyapex,
+ java.FixtureConfigureApexBootJars(tc.configuredBootJars...),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BuildFlags = map[string]string{
+ "RELEASE_APEX_CONTRIBUTIONS_ART": "my_apex_contributions",
+ }
+ }),
+ )
+ if tc.errorExpected {
+ fixture = fixture.ExtendWithErrorHandler(
+ android.FixtureExpectsAtLeastOneErrorMatchingPattern(`in contents.*must also be declared in PRODUCT_APEX_BOOT_JARS`),
+ )
+ }
+ fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.apexContributionContents))
+ }
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 72a9e52..b2afa39 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -835,7 +835,21 @@
android.SetProvider(ctx, android.PrebuiltInfoProvider, info)
}
+// Uses an object provided by its deps to validate that the contents of bcpf have been added to the global
+// PRODUCT_APEX_BOOT_JARS
+// This validation will only run on the apex which is active for this product/release_config
+func validateApexClasspathFragments(ctx android.ModuleContext) {
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if info, exists := android.OtherModuleProvider(ctx, m, java.ClasspathFragmentValidationInfoProvider); exists {
+ ctx.ModuleErrorf("%s in contents of %s must also be declared in PRODUCT_APEX_BOOT_JARS", info.UnknownJars, info.ClasspathFragmentModuleName)
+ }
+ })
+}
+
func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Validate contents of classpath fragments
+ validateApexClasspathFragments(ctx)
+
p.apexKeysPath = writeApexKeys(ctx, p)
// TODO(jungjw): Check the key validity.
p.inputApex = android.OptionalPathForModuleSrc(ctx, p.prebuiltCommonProperties.Selected_apex).Path()
@@ -1059,6 +1073,9 @@
}
func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // Validate contents of classpath fragments
+ validateApexClasspathFragments(ctx)
+
a.apexKeysPath = writeApexKeys(ctx, a)
a.installFilename = a.InstallFilename()
if !strings.HasSuffix(a.installFilename, imageApexSuffix) && !strings.HasSuffix(a.installFilename, imageCapexSuffix) {
diff --git a/bin/aninja b/bin/aninja
new file mode 100755
index 0000000..cceb794
--- /dev/null
+++ b/bin/aninja
@@ -0,0 +1,25 @@
+#!/bin/bash -e
+
+# Copyright (C) 2022 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+require_lunch
+
+cd $(gettop)
+prebuilts/build-tools/linux-x86/bin/ninja -f out/combined-${TARGET_PRODUCT}.ninja "$@"
+
diff --git a/bin/cgrep b/bin/cgrep
new file mode 100755
index 0000000..6c9130c
--- /dev/null
+++ b/bin/cgrep
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.c' \
+ -o -name '*.cc' \
+ -o -name '*.cpp' \
+ -o -name '*.h' \
+ -o -name '*.hpp' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/ggrep b/bin/ggrep
new file mode 100755
index 0000000..fce8c84
--- /dev/null
+++ b/bin/ggrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.gradle' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/gogrep b/bin/gogrep
new file mode 100755
index 0000000..0265ccf
--- /dev/null
+++ b/bin/gogrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.go' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/hmm b/bin/hmm
new file mode 100755
index 0000000..c3d60fa
--- /dev/null
+++ b/bin/hmm
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+cat <<EOF
+
+Run "m help" for help with the build system itself.
+
+Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment:
+- lunch: lunch <product_name>-<release_type>-<build_variant>
+ Selects <product_name> as the product to build, and <build_variant> as the variant to
+ build, and stores those selections in the environment to be read by subsequent
+ invocations of 'm' etc.
+- tapas: tapas [<App1> <App2> ...] [arm|x86|arm64|x86_64] [eng|userdebug|user]
+ Sets up the build environment for building unbundled apps (APKs).
+- banchan: banchan <module1> [<module2> ...] \\
+ [arm|x86|arm64|riscv64|x86_64|arm64_only|x86_64only] [eng|userdebug|user]
+ Sets up the build environment for building unbundled modules (APEXes).
+- croot: Changes directory to the top of the tree, or a subdirectory thereof.
+- m: Makes from the top of the tree.
+- mm: Builds and installs all of the modules in the current directory, and their
+ dependencies.
+- mmm: Builds and installs all of the modules in the supplied directories, and their
+ dependencies.
+ To limit the modules being built use the syntax: mmm dir/:target1,target2.
+- mma: Same as 'mm'
+- mmma: Same as 'mmm'
+- provision: Flash device with all required partitions. Options will be passed on to fastboot.
+- cgrep: Greps on all local C/C++ files.
+- ggrep: Greps on all local Gradle files.
+- gogrep: Greps on all local Go files.
+- jgrep: Greps on all local Java files.
+- jsongrep: Greps on all local Json files.
+- ktgrep: Greps on all local Kotlin files.
+- resgrep: Greps on all local res/*.xml files.
+- mangrep: Greps on all local AndroidManifest.xml files.
+- mgrep: Greps on all local Makefiles and *.bp files.
+- owngrep: Greps on all local OWNERS files.
+- rsgrep: Greps on all local Rust files.
+- sepgrep: Greps on all local sepolicy files.
+- sgrep: Greps on all local source files.
+- tomlgrep: Greps on all local Toml files.
+- pygrep: Greps on all local Python files.
+- godir: Go to the directory containing a file.
+- allmod: List all modules.
+- gomod: Go to the directory containing a module.
+- bmod: Get the Bazel label of a Soong module if it is converted with bp2build.
+- pathmod: Get the directory containing a module.
+- outmod: Gets the location of a module's installed outputs with a certain extension.
+- dirmods: Gets the modules defined in a given directory.
+- installmod: Adb installs a module's built APK.
+- refreshmod: Refresh list of modules for allmod/gomod/pathmod/outmod/installmod.
+- syswrite: Remount partitions (e.g. system.img) as writable, rebooting if necessary.
+
+Environment options:
+- SANITIZE_HOST: Set to 'address' to use ASAN for all host modules.
+- ANDROID_QUIET_BUILD: set to 'true' to display only the essential messages.
+
+Look at build/make/envsetup for more functions:
+EOF
+ local T=$(gettop)
+ local A=""
+ local i
+ for i in `(cat $T/build/envsetup.sh | sed -n "/^[[:blank:]]*function /s/function \([a-z]*\).*/\1/p" | sort | uniq`; do
+ A="$A $i"
+ done
+ echo $A
diff --git a/bin/jgrep b/bin/jgrep
new file mode 100755
index 0000000..afe70db
--- /dev/null
+++ b/bin/jgrep
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.java' \
+ -o -name '*.kt' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/jsongrep b/bin/jsongrep
new file mode 100755
index 0000000..6e14d0c
--- /dev/null
+++ b/bin/jsongrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.json' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/ktgrep b/bin/ktgrep
new file mode 120000
index 0000000..9b51491
--- /dev/null
+++ b/bin/ktgrep
@@ -0,0 +1 @@
+jgrep
\ No newline at end of file
diff --git a/bin/m b/bin/m
new file mode 100755
index 0000000..edcfce5
--- /dev/null
+++ b/bin/m
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --all-modules --dir="$(pwd)" "$@"
+
+exit $?
diff --git a/bin/mangrep b/bin/mangrep
new file mode 100755
index 0000000..a343000
--- /dev/null
+++ b/bin/mangrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name 'AndroidManifest.xml' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/mgrep b/bin/mgrep
new file mode 100755
index 0000000..793730d
--- /dev/null
+++ b/bin/mgrep
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name 'Makefile' \
+ -o -name 'Makefile.*' \
+ -o -name '*.make' \
+ -o -name '*.mak' \
+ -o -name '*.mk' \
+ -o -name '*.bp' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/mm b/bin/mm
new file mode 100755
index 0000000..6461b1e
--- /dev/null
+++ b/bin/mm
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir-no-deps --dir="$(pwd)" "$@"
+
+exit $?
diff --git a/bin/mma b/bin/mma
new file mode 100755
index 0000000..6f1c934
--- /dev/null
+++ b/bin/mma
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir --dir="$(pwd)" "$@"
+
+exit $?
diff --git a/bin/mmm b/bin/mmm
new file mode 100755
index 0000000..ab3a632
--- /dev/null
+++ b/bin/mmm
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs-no-deps --dir="$(pwd)" "$@"
+
+exit $?
diff --git a/bin/mmma b/bin/mmma
new file mode 100755
index 0000000..d9190e5
--- /dev/null
+++ b/bin/mmma
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs --dir="$(pwd)" "$@"
+
+exit $?
diff --git a/bin/overrideflags b/bin/overrideflags
new file mode 100755
index 0000000..e16537b
--- /dev/null
+++ b/bin/overrideflags
@@ -0,0 +1,100 @@
+#!/bin/bash -e
+# Copyright (C) 2023 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.
+
+
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+function print_help() {
+ echo -e "overrideflags is used to set default value for local build."
+ echo -e "\nOptions:"
+ echo -e "\t--release-config \tPath to release configuration directory. Required"
+ echo -e "\t--no-edit \tIf present, skip editing flag value file."
+ echo -e "\t-h/--help \tShow this help."
+}
+
+function main() {
+ while (($# > 0)); do
+ case $1 in
+ --release-config)
+ if [[ $# -le 1 ]]; then
+ echo "--release-config requires a path"
+ return 1
+ fi
+ local release_config_dir="$2"
+ shift 2
+ ;;
+ --no-edit)
+ local no_edit="true"
+ shift 1
+ ;;
+ -h|--help)
+ print_help
+ return
+ ;;
+ *)
+ echo "$1 is unrecognized"
+ print_help
+ return 1
+ ;;
+ esac
+ done
+
+
+
+ case $(uname -s) in
+ Darwin)
+ local host_arch=darwin-x86
+ ;;
+ Linux)
+ local host_arch=linux-x86
+ ;;
+ *)
+ >&2 echo Unknown host $(uname -s)
+ return
+ ;;
+ esac
+
+ if [[ -z "${release_config_dir}" ]]; then
+ echo "Please provide release configuration path by --release-config"
+ exit 1
+ elif [ ! -d "${release_config_dir}" ]; then
+ echo "${release_config_dir} is an invalid directory"
+ exit 1
+ fi
+ local T="$(gettop)"
+ local aconfig_dir="${T}"/build/make/tools/aconfig/
+ local overrideflag_py="${aconfig_dir}"/overrideflags/overrideflags.py
+ local overridefile="${release_config_dir}/aconfig/override_values.textproto"
+
+ # Edit override file
+ if [[ -z "${no_edit}" ]]; then
+ editor="${EDITOR:-$(which vim)}"
+
+ eval "${editor} ${overridefile}"
+ if [ $? -ne 0 ]; then
+ echo "Fail to set override values"
+ return 1
+ fi
+ fi
+
+ ${T}/prebuilts/build-tools/${host_arch}/bin/py3-cmd -u "${overrideflag_py}" \
+ --overrides "${overridefile}" \
+ --out "${release_config_dir}/aconfig"
+}
+
+
+main "$@"
diff --git a/bin/owngrep b/bin/owngrep
new file mode 100755
index 0000000..26ce6e8
--- /dev/null
+++ b/bin/owngrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name 'OWNERS' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/pygrep b/bin/pygrep
new file mode 100755
index 0000000..e072289
--- /dev/null
+++ b/bin/pygrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.py' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/rcgrep b/bin/rcgrep
new file mode 100755
index 0000000..ff93e51
--- /dev/null
+++ b/bin/rcgrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.rc' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/refreshmod b/bin/refreshmod
new file mode 100755
index 0000000..f511846
--- /dev/null
+++ b/bin/refreshmod
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# Update module-info.json in out.
+
+# Common script utilities
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh
+
+require_top
+
+if [ ! "$ANDROID_PRODUCT_OUT" ]; then
+ echo "No ANDROID_PRODUCT_OUT. Try running 'lunch' first." >&2
+ return 1
+fi
+
+echo "Refreshing modules (building module-info.json)" >&2
+
+_wrap_build $TOP/build/soong/soong_ui.bash --build-mode --all-modules --dir="$(pwd)" module-info
diff --git a/bin/resgrep b/bin/resgrep
new file mode 100755
index 0000000..600091f
--- /dev/null
+++ b/bin/resgrep
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+for dir in `find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -name res -type d`; do
+ find $dir -type f -name '*\.xml' -exec grep --color -n "$@" {} +
+done
diff --git a/bin/rsgrep b/bin/rsgrep
new file mode 100755
index 0000000..8c24151
--- /dev/null
+++ b/bin/rsgrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.rs' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/sepgrep b/bin/sepgrep
new file mode 100755
index 0000000..0e0d1ba
--- /dev/null
+++ b/bin/sepgrep
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -path ./out -prune -o -name sepolicy -type d \
+ -exec grep --color -n -r --exclude-dir=\.git "$@" {} +
+exit $?
diff --git a/bin/sgrep b/bin/sgrep
new file mode 100755
index 0000000..f186553
--- /dev/null
+++ b/bin/sgrep
@@ -0,0 +1,36 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.c' \
+ -o -name '*.cc' \
+ -o -name '*.cpp' \
+ -o -name '*.h' \
+ -o -name '*.hpp' \
+ -o -name '*.S' \
+ -o -name '*.java' \
+ -o -name '*.kt' \
+ -o -name '*.xml' \
+ -o -name '*.sh' \
+ -o -name '*.mk' \
+ -o -name '*.bp' \
+ -o -name '*.aidl' \
+ -o -name '*.vts' \
+ -o -name '*.proto' \
+ -o -name '*.rs' \
+ -o -name '*.go' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/syswrite b/bin/syswrite
new file mode 100755
index 0000000..46201e3
--- /dev/null
+++ b/bin/syswrite
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Copyright (C) 2024 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.
+
+# syswrite - disable verity, reboot if needed, and remount image
+# Easy way to make system.img/etc writable
+
+adb wait-for-device && adb root && adb wait-for-device || exit 1
+if [[ $(adb disable-verity | grep -i "reboot") ]]; then
+ echo "rebooting"
+ adb reboot && adb wait-for-device && adb root && adb wait-for-device || exit 1
+fi
+adb remount || exit 1
diff --git a/bin/tomlgrep b/bin/tomlgrep
new file mode 100755
index 0000000..636ef22
--- /dev/null
+++ b/bin/tomlgrep
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.toml' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/bin/treegrep b/bin/treegrep
new file mode 100755
index 0000000..b83d419
--- /dev/null
+++ b/bin/treegrep
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2022 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.
+
+find . -name .repo -prune -o -name .git -prune -o -name out -prune -o -type f \( \
+ -name '*.c' \
+ -o -name '*.cc' \
+ -o -name '*.cpp' \
+ -o -name '*.h' \
+ -o -name '*.hpp' \
+ -o -name '*.S' \
+ -o -name '*.java' \
+ -o -name '*.kt' \
+ -o -name '*.xml' \
+ \) -exec grep --color -n "$@" {} +
+exit $?
diff --git a/cc/binary.go b/cc/binary.go
index 7aa8e20..3ff35de 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -18,6 +18,7 @@
"path/filepath"
"android/soong/android"
+
"github.com/google/blueprint"
)
@@ -425,6 +426,10 @@
validations = append(validations, objs.tidyDepFiles...)
linkerDeps = append(linkerDeps, flags.LdFlagsDeps...)
+ if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
+ deps.StaticLibs = append(deps.StaticLibs, generatedLib)
+ }
+
// Register link action.
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs,
deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, deps.CrtEnd, true,
diff --git a/cc/builder.go b/cc/builder.go
index e255cbe..42aa4b6 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -19,6 +19,7 @@
// functions.
import (
+ "fmt"
"path/filepath"
"runtime"
"strconv"
@@ -330,6 +331,15 @@
CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
+
+ // Function pointer for producting staticlibs from rlibs. Corresponds to
+ // rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init())
+ //
+ // This is required since soong-rust depends on soong-cc, so soong-cc cannot depend on soong-rust
+ // without resulting in a circular dependency. Setting this function pointer in soong-rust allows
+ // soong-cc to call into this particular function.
+ TransformRlibstoStaticlib (func(ctx android.ModuleContext, mainSrc android.Path, deps []RustRlibDep,
+ outputFile android.WritablePath) android.Path) = nil
)
func PwdPrefix() string {
@@ -778,6 +788,47 @@
}
}
+// Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty.
+func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path {
+ if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 {
+ // This should only be reachable if a module defines static_rlibs and
+ // soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests).
+ panic(fmt.Errorf("TransformRlibstoStaticlib is not set and static_rlibs is defined in %s", ctx.ModuleName()))
+ } else if len(rlibDeps) == 0 {
+ return nil
+ }
+
+ output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a")
+ stemFile := output.ReplaceExtension(ctx, "rs")
+ crateNames := []string{}
+
+ // Collect crate names
+ for _, lib := range rlibDeps {
+ // Exclude libstd so this can support no_std builds.
+ if lib.CrateName != "libstd" {
+ crateNames = append(crateNames, lib.CrateName)
+ }
+ }
+
+ // Deduplicate any crateNames just to be safe
+ crateNames = android.FirstUniqueStrings(crateNames)
+
+ // Write the source file
+ android.WriteFileRule(ctx, stemFile, genRustStaticlibSrcFile(crateNames))
+
+ return TransformRlibstoStaticlib(ctx, stemFile, rlibDeps, output)
+}
+
+func genRustStaticlibSrcFile(crateNames []string) string {
+ lines := []string{
+ "// @Soong generated Source",
+ }
+ for _, crate := range crateNames {
+ lines = append(lines, fmt.Sprintf("extern crate %s;", crate))
+ }
+ return strings.Join(lines, "\n")
+}
+
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
// and shared libraries, to a shared library (.so) or dynamic executable
func transformObjToDynamicBinary(ctx android.ModuleContext,
diff --git a/cc/cc.go b/cc/cc.go
index eb6e974..89cf093 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -100,6 +100,7 @@
StaticLibs, LateStaticLibs, WholeStaticLibs []string
HeaderLibs []string
RuntimeLibs []string
+ Rlibs []string
// UnexportedStaticLibs are static libraries that are also passed to -Wl,--exclude-libs= to
// prevent automatically exporting symbols.
@@ -145,6 +146,17 @@
LlndkHeaderLibs []string
}
+// A struct which to collect flags for rlib dependencies
+type RustRlibDep struct {
+ LibPath android.Path // path to the rlib
+ LinkDirs []string // flags required for dependency (e.g. -L flags)
+ CrateName string // crateNames associated with rlibDeps
+}
+
+func EqRustRlibDeps(a RustRlibDep, b RustRlibDep) bool {
+ return a.LibPath == b.LibPath
+}
+
// PathDeps is a struct containing file paths to dependencies of a module.
// It's constructed in depsToPath() by traversing the direct dependencies of the current module.
// It's used to construct flags for various build statements (such as for compiling and linking).
@@ -157,6 +169,8 @@
SharedLibsDeps, EarlySharedLibsDeps, LateSharedLibsDeps android.Paths
// Paths to .a files
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
+ // Paths and crateNames for RustStaticLib dependencies
+ RustRlibDeps []RustRlibDep
// Transitive static library dependencies of static libraries for use in ordering.
TranstiveStaticLibrariesForOrdering *android.DepSet[android.Path]
@@ -185,6 +199,7 @@
ReexportedFlags []string
ReexportedGeneratedHeaders android.Paths
ReexportedDeps android.Paths
+ ReexportedRustRlibDeps []RustRlibDep
// Paths to crt*.o files
CrtBegin, CrtEnd android.Paths
@@ -298,6 +313,7 @@
AndroidMkSharedLibs []string `blueprint:"mutated"`
AndroidMkStaticLibs []string `blueprint:"mutated"`
+ AndroidMkRlibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
AndroidMkHeaderLibs []string `blueprint:"mutated"`
@@ -660,6 +676,7 @@
headerLibraryDependency = iota
sharedLibraryDependency
staticLibraryDependency
+ rlibLibraryDependency
)
func (k libraryDependencyKind) String() string {
@@ -670,6 +687,8 @@
return "sharedLibraryDependency"
case staticLibraryDependency:
return "staticLibraryDependency"
+ case rlibLibraryDependency:
+ return "rlibLibraryDependency"
default:
panic(fmt.Errorf("unknown libraryDependencyKind %d", k))
}
@@ -747,6 +766,11 @@
return d.Kind == staticLibraryDependency
}
+// rlib returns true if the libraryDependencyTag is tagging an rlib dependency.
+func (d libraryDependencyTag) rlib() bool {
+ return d.Kind == rlibLibraryDependency
+}
+
func (d libraryDependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
if d.shared() {
return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency}
@@ -1114,6 +1138,14 @@
return false
}
+func (c *Module) CrateName() string {
+ panic(fmt.Errorf("CrateName called on non-Rust module: %q", c.BaseModuleName()))
+}
+
+func (c *Module) ExportedCrateLinkDirs() []string {
+ panic(fmt.Errorf("ExportedCrateLinkDirs called on non-Rust module: %q", c.BaseModuleName()))
+}
+
func (c *Module) IsFuzzModule() bool {
if _, ok := c.compiler.(*fuzzBinary); ok {
return true
@@ -2309,6 +2341,7 @@
deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
+ deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
deps.LateStaticLibs = android.LastUniqueStrings(deps.LateStaticLibs)
deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
deps.LateSharedLibs = android.LastUniqueStrings(deps.LateSharedLibs)
@@ -2616,6 +2649,15 @@
}, depTag, lib)
}
+ for _, lib := range deps.Rlibs {
+ depTag := libraryDependencyTag{Kind: rlibLibraryDependency}
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: ""},
+ {Mutator: "rust_libraries", Variation: "rlib"},
+ {Mutator: "rust_stdlinkage", Variation: "rlib-std"},
+ }, depTag, lib)
+ }
+
// staticUnwinderDep is treated as staticDep for Q apexes
// so that native libraries/binaries are linked with static unwinder
// because Q libc doesn't have unwinder APIs
@@ -3225,6 +3267,14 @@
default:
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
+
+ case libDepTag.rlib():
+ rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()}
+ depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, rlibDep)
+ depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep)
+ depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...)
+ depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, depExporterInfo.IncludeDirs...)
+
case libDepTag.static():
staticLibraryInfo, isStaticLib := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider)
if !isStaticLib {
@@ -3277,6 +3327,12 @@
panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
+
+ // We re-export the Rust static_rlibs so rlib dependencies don't need to be redeclared by cc_library_static dependents.
+ // E.g. libfoo (cc_library_static) depends on libfoo.ffi (a rust_ffi rlib), libbar depending on libfoo shouldn't have to also add libfoo.ffi to static_rlibs.
+ depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
+ depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
+
if libDepTag.unexportedSymbols {
depPaths.LdFlags = append(depPaths.LdFlags,
"-Wl,--exclude-libs="+staticLibraryInfo.StaticLibrary.Base())
@@ -3329,6 +3385,12 @@
depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, depExporterInfo.SystemIncludeDirs...)
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, depExporterInfo.Deps...)
depPaths.Flags = append(depPaths.Flags, depExporterInfo.Flags...)
+ depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, depExporterInfo.RustRlibDeps...)
+
+ // Only re-export RustRlibDeps for cc static libs
+ if c.static() {
+ depPaths.ReexportedRustRlibDeps = append(depPaths.ReexportedRustRlibDeps, depExporterInfo.RustRlibDeps...)
+ }
if libDepTag.reexportFlags {
reexportExporter(depExporterInfo)
@@ -3401,11 +3463,14 @@
depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
+ depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps)
+
depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags)
depPaths.ReexportedDeps = android.FirstUniquePaths(depPaths.ReexportedDeps)
depPaths.ReexportedGeneratedHeaders = android.FirstUniquePaths(depPaths.ReexportedGeneratedHeaders)
+ depPaths.ReexportedRustRlibDeps = android.FirstUniqueFunc(depPaths.ReexportedRustRlibDeps, EqRustRlibDeps)
if c.sabi != nil {
c.sabi.Properties.ReexportedIncludes = android.FirstUniqueStrings(c.sabi.Properties.ReexportedIncludes)
diff --git a/cc/cmake_ext_add_aidl_library.txt b/cc/cmake_ext_add_aidl_library.txt
index dcf805a..af5bdf6 100644
--- a/cc/cmake_ext_add_aidl_library.txt
+++ b/cc/cmake_ext_add_aidl_library.txt
@@ -1,35 +1,51 @@
-function(add_aidl_library NAME LANG SOURCES AIDLFLAGS)
+function(add_aidl_library NAME LANG AIDLROOT SOURCES AIDLFLAGS)
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20")
cmake_policy(SET CMP0116 NEW)
endif()
+ # Strip trailing slash
+ get_filename_component(AIDLROOT_TRAILING "${AIDLROOT}" NAME)
+ if ("${AIDLROOT_TRAILING}" STREQUAL "")
+ get_filename_component(AIDLROOT "${AIDLROOT}foo" DIRECTORY)
+ endif()
+
set(GEN_DIR "${CMAKE_CURRENT_BINARY_DIR}/.intermediates/${NAME}-source")
set(GEN_SOURCES)
- foreach(SOURCE ${SOURCES})
- get_filename_component(SOURCE_WE ${SOURCE} NAME_WE)
- get_filename_component(SOURCE_ABSOLUTE ${SOURCE} ABSOLUTE)
- get_filename_component(SOURCE_DIR ${SOURCE_ABSOLUTE} DIRECTORY)
- set(GEN_SOURCE "${GEN_DIR}/${SOURCE_WE}.cpp")
+ foreach (SOURCE ${SOURCES})
+ set(SOURCE_FULL ${AIDLROOT}/${SOURCE})
+ get_filename_component(SOURCE_WLE ${SOURCE} NAME_WLE)
+ get_filename_component(SOURCE_SUBDIR ${SOURCE} DIRECTORY)
+ set(GEN_SOURCE "${GEN_DIR}/${SOURCE_SUBDIR}/${SOURCE_WLE}.cpp")
+
+ file(READ "${SOURCE}" SOURCE_CONTENTS)
+ string(FIND "${SOURCE_CONTENTS}" "@VintfStability" VINTF_MATCH)
+ set(STABILITY_FLAG)
+ if (${VINTF_MATCH} GREATER_EQUAL 0)
+ set(STABILITY_FLAG --stability vintf)
+ endif()
+
set(DEPFILE_ARG)
if (NOT ${CMAKE_GENERATOR} MATCHES "Unix Makefiles")
set(DEPFILE_ARG DEPFILE "${GEN_SOURCE}.d")
endif()
+
add_custom_command(
OUTPUT "${GEN_SOURCE}"
- MAIN_DEPENDENCY "${SOURCE_ABSOLUTE}"
+ MAIN_DEPENDENCY "${SOURCE_FULL}"
${DEPFILE_ARG}
COMMAND "${AIDL_BIN}"
ARGS
--lang=${LANG}
- --include="${SOURCE_DIR}"
+ --include="${AIDLROOT}"
--dep="${GEN_SOURCE}.d"
--out="${GEN_DIR}"
--header_out="${GEN_DIR}/include"
--ninja
--structured
--min_sdk_version=current
+ ${STABILITY_FLAG}
${AIDLFLAGS}
- "${SOURCE_ABSOLUTE}"
+ "${SOURCE_FULL}"
)
list(APPEND GEN_SOURCES "${GEN_SOURCE}")
endforeach()
@@ -39,9 +55,14 @@
target_include_directories(${NAME}
PUBLIC
"${GEN_DIR}/include"
- "${ANDROID_BUILD_TOP}/frameworks/native/libs/binder/ndk/include_${LANG}"
)
+
+ if (${LANG} MATCHES "ndk")
+ set(BINDER_LIB_NAME "libbinder_ndk_sdk")
+ else()
+ set(BINDER_LIB_NAME "libbinder_sdk")
+ endif()
target_link_libraries(${NAME}
- libbinder_sdk
+ ${BINDER_LIB_NAME}
)
endfunction()
diff --git a/cc/cmake_module_aidl.txt b/cc/cmake_module_aidl.txt
index 4509a88..84755a3 100644
--- a/cc/cmake_module_aidl.txt
+++ b/cc/cmake_module_aidl.txt
@@ -1,8 +1,11 @@
# <<.M.Name>>
-<<setList .M.Name "_SRCS" "${ANDROID_BUILD_TOP}/" (getCompilerProperties .M).AidlInterface.Sources>>
+<<setList .M.Name "_SRCS" "" (getAidlSources .M)>>
<<setList .M.Name "_AIDLFLAGS" "" (getCompilerProperties .M).AidlInterface.Flags>>
-add_aidl_library(<<.M.Name>> <<(getCompilerProperties .M).AidlInterface.Lang>> "${<<.M.Name>>_SRCS}" "${<<.M.Name>>_AIDLFLAGS}")
+add_aidl_library(<<.M.Name>> <<(getCompilerProperties .M).AidlInterface.Lang>>
+ "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getCompilerProperties .M).AidlInterface.AidlRoot>>"
+ "${<<.M.Name>>_SRCS}"
+ "${<<.M.Name>>_AIDLFLAGS}")
add_library(android::<<.M.Name>> ALIAS <<.M.Name>>)
diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt
index 571f27c..488e5e1 100644
--- a/cc/cmake_module_cc.txt
+++ b/cc/cmake_module_cc.txt
@@ -1,7 +1,7 @@
<<$srcs := getSources .M>>
<<$includeDirs := getIncludeDirs .Ctx .M>>
<<$cflags := (getCompilerProperties .M).Cflags>>
-<<$deps := mapLibraries (concat5
+<<$deps := mapLibraries .Ctx .M (concat5
(getLinkerProperties .M).Whole_static_libs
(getLinkerProperties .M).Static_libs
(getLinkerProperties .M).Shared_libs
diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go
index 0635a29..c21a46f 100644
--- a/cc/cmake_snapshot.go
+++ b/cc/cmake_snapshot.go
@@ -192,13 +192,16 @@
},
"getExtraLibs": getExtraLibs,
"getIncludeDirs": getIncludeDirs,
- "mapLibraries": func(libs []string, mapping map[string]LibraryMappingProperty) []string {
+ "mapLibraries": func(ctx android.ModuleContext, m *Module, libs []string, mapping map[string]LibraryMappingProperty) []string {
var mappedLibs []string
for _, lib := range libs {
mappedLib, exists := mapping[lib]
if exists {
lib = mappedLib.Mapped_name
} else {
+ if !ctx.OtherModuleExists(lib) {
+ ctx.OtherModuleErrorf(m, "Dependency %s doesn't exist", lib)
+ }
lib = "android::" + lib
}
if lib == "" {
@@ -210,6 +213,21 @@
mappedLibs = slices.Compact(mappedLibs)
return mappedLibs
},
+ "getAidlSources": func(m *Module) []string {
+ aidlInterface := m.compiler.baseCompilerProps().AidlInterface
+ aidlRoot := aidlInterface.AidlRoot + string(filepath.Separator)
+ if aidlInterface.AidlRoot == "" {
+ aidlRoot = ""
+ }
+ var sources []string
+ for _, src := range aidlInterface.Sources {
+ if !strings.HasPrefix(src, aidlRoot) {
+ panic(fmt.Sprintf("Aidl source '%v' doesn't start with '%v'", src, aidlRoot))
+ }
+ sources = append(sources, src[len(aidlRoot):])
+ }
+ return sources
+ },
}
return template.Must(template.New("").Delims("<<", ">>").Funcs(funcMap).Parse(templateContents))
@@ -282,14 +300,14 @@
var pregeneratedModules []*Module
ctx.WalkDeps(func(dep_a android.Module, parent android.Module) bool {
moduleName := ctx.OtherModuleName(dep_a)
- dep, ok := dep_a.(*Module)
- if !ok {
- return false // not a cc module
- }
if visited := visitedModules[moduleName]; visited {
return false // visit only once
}
visitedModules[moduleName] = true
+ dep, ok := dep_a.(*Module)
+ if !ok {
+ return false // not a cc module
+ }
if mapping, ok := pprop.LibraryMapping[moduleName]; ok {
if mapping.Package_pregenerated != "" {
pregeneratedModules = append(pregeneratedModules, dep)
diff --git a/cc/compiler.go b/cc/compiler.go
index aee584d..21b8f2e 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -147,6 +147,9 @@
// list of aidl_interface sources
Sources []string `blueprint:"mutated"`
+ // root directory of AIDL sources
+ AidlRoot string `blueprint:"mutated"`
+
// AIDL backend language (e.g. "cpp", "ndk")
Lang string `blueprint:"mutated"`
@@ -789,6 +792,9 @@
// be added to the include path using -I
Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+ // list of Rust static libraries.
+ Static_rlibs []string `android:"arch_variant,variant_prepend"`
+
// list of static libraries that provide headers for this binding.
Static_libs []string `android:"arch_variant,variant_prepend"`
diff --git a/cc/config/global.go b/cc/config/global.go
index 16b5e09..290a27d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -136,6 +136,11 @@
// displaying logs in web browsers.
"-fmessage-length=0",
+ // Disable C++17 "relaxed template template argument matching" as a workaround for
+ // our out-dated libcxx.
+ // http://b/341084395
+ "-fno-relaxed-template-template-args",
+
// Using simple template names reduces the size of debug builds.
"-gsimple-template-names",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index b3e6639..164ec99 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -597,7 +597,7 @@
ctx.WalkDeps(func(child, parent android.Module) bool {
// If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive
- // shared dependencies (even for rust_ffi_static)
+ // shared dependencies (even for rust_ffi_rlib or rust_ffi_static)
if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() {
if recursed[ctx.OtherModuleName(child)] {
return false
diff --git a/cc/library.go b/cc/library.go
index 03feff2..b9018a7 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -274,11 +274,12 @@
type flagExporter struct {
Properties FlagExporterProperties
- dirs android.Paths // Include directories to be included with -I
- systemDirs android.Paths // System include directories to be included with -isystem
- flags []string // Exported raw flags.
- deps android.Paths
- headers android.Paths
+ dirs android.Paths // Include directories to be included with -I
+ systemDirs android.Paths // System include directories to be included with -isystem
+ flags []string // Exported raw flags.
+ deps android.Paths
+ headers android.Paths
+ rustRlibDeps []RustRlibDep
}
// exportedIncludes returns the effective include paths for this module and
@@ -339,6 +340,10 @@
f.deps = append(f.deps, deps...)
}
+func (f *flagExporter) reexportRustStaticDeps(deps ...RustRlibDep) {
+ f.rustRlibDeps = append(f.rustRlibDeps, deps...)
+}
+
// addExportedGeneratedHeaders does nothing but collects generated header files.
// This can be differ to exportedDeps which may contain phony files to minimize ninja.
func (f *flagExporter) addExportedGeneratedHeaders(headers ...android.Path) {
@@ -356,6 +361,8 @@
// Used sparingly, for extra files that need to be explicitly exported to dependers,
// or for phony files to minimize ninja.
Deps: f.deps,
+ // Used for exporting rlib deps of static libraries to dependents.
+ RustRlibDeps: f.rustRlibDeps,
// For exported generated headers, such as exported aidl headers, proto headers, or
// sysprop headers.
GeneratedHeaders: f.headers,
@@ -1132,9 +1139,14 @@
linkerDeps = append(linkerDeps, deps.EarlySharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.SharedLibsDeps...)
linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...)
+
+ if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil {
+ deps.StaticLibs = append(deps.StaticLibs, generatedLib)
+ }
+
transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs,
- deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs,
- linkerDeps, deps.CrtBegin, deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles)
+ deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin,
+ deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles)
objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...)
objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...)
@@ -1619,6 +1631,10 @@
library.reexportDeps(deps.ReexportedDeps...)
library.addExportedGeneratedHeaders(deps.ReexportedGeneratedHeaders...)
+ if library.static() && len(deps.ReexportedRustRlibDeps) > 0 {
+ library.reexportRustStaticDeps(deps.ReexportedRustRlibDeps...)
+ }
+
// Optionally export aidl headers.
if Bool(library.Properties.Aidl.Export_aidl_headers) {
if library.baseCompiler.hasAidl(deps) {
@@ -2146,14 +2162,12 @@
// Header only
}
- } else if library, ok := mctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() {
-
+ } else if library, ok := mctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) {
// Non-cc.Modules may need an empty variant for their mutators.
variations := []string{}
if library.NonCcVariants() {
variations = append(variations, "")
}
-
isLLNDK := false
if m, ok := mctx.Module().(*Module); ok {
isLLNDK = m.IsLlndk()
diff --git a/cc/linkable.go b/cc/linkable.go
index 10cc38f..5579aae 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -73,6 +73,12 @@
// RustLibraryInterface returns true if this is a Rust library module
RustLibraryInterface() bool
+ // CrateName returns the crateName for a Rust library, panics if not a Rust library.
+ CrateName() string
+
+ // DepFlags returns a slice of Rustc string flags, panics if not a Rust library
+ ExportedCrateLinkDirs() []string
+
// BaseModuleName returns the android.ModuleBase.BaseModuleName() value for this module.
BaseModuleName() string
@@ -380,6 +386,7 @@
SystemIncludeDirs android.Paths // System include directories to be included with -isystem
Flags []string // Exported raw flags.
Deps android.Paths
+ RustRlibDeps []RustRlibDep
GeneratedHeaders android.Paths
}
diff --git a/cc/linker.go b/cc/linker.go
index 1d0f205..f325c12 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -39,6 +39,9 @@
// the dependency's .a file will be linked into this module using -Wl,--whole-archive.
Whole_static_libs []string `android:"arch_variant,variant_prepend"`
+ // list of Rust libs that should be statically linked into this module.
+ Static_rlibs []string `android:"arch_variant"`
+
// list of modules that should be statically linked into this module.
Static_libs []string `android:"arch_variant,variant_prepend"`
@@ -116,10 +119,14 @@
// product variant of the C/C++ module.
Static_libs []string
- // list of ehader libs that only should be used to build vendor or product
+ // list of header libs that only should be used to build vendor or product
// variant of the C/C++ module.
Header_libs []string
+ // list of Rust libs that should be statically linked to build vendor or product
+ // variant.
+ Static_rlibs []string
+
// list of shared libs that should not be used to build vendor or
// product variant of the C/C++ module.
Exclude_shared_libs []string
@@ -148,6 +155,10 @@
// variant of the C/C++ module.
Static_libs []string
+ // list of Rust libs that should be statically linked to build the recovery
+ // variant.
+ Static_rlibs []string
+
// list of shared libs that should not be used to build
// the recovery variant of the C/C++ module.
Exclude_shared_libs []string
@@ -165,10 +176,14 @@
Exclude_runtime_libs []string
}
Ramdisk struct {
- // list of static libs that only should be used to build the recovery
+ // list of static libs that only should be used to build the ramdisk
// variant of the C/C++ module.
Static_libs []string
+ // list of Rust libs that should be statically linked to build the ramdisk
+ // variant.
+ Static_rlibs []string
+
// list of shared libs that should not be used to build
// the ramdisk variant of the C/C++ module.
Exclude_shared_libs []string
@@ -183,9 +198,13 @@
}
Vendor_ramdisk struct {
// list of shared libs that should not be used to build
- // the recovery variant of the C/C++ module.
+ // the vendor ramdisk variant of the C/C++ module.
Exclude_shared_libs []string
+ // list of Rust libs that should be statically linked to build the vendor ramdisk
+ // variant.
+ Static_rlibs []string
+
// list of static libs that should not be used to build
// the vendor ramdisk variant of the C/C++ module.
Exclude_static_libs []string
@@ -201,6 +220,10 @@
// variants.
Shared_libs []string
+ // list of Rust libs that should be statically linked to build the vendor ramdisk
+ // variant.
+ Static_rlibs []string
+
// list of ehader libs that only should be used to build platform variant of
// the C/C++ module.
Header_libs []string
@@ -295,6 +318,7 @@
deps.WholeStaticLibs = append(deps.WholeStaticLibs, linker.Properties.Whole_static_libs...)
deps.HeaderLibs = append(deps.HeaderLibs, linker.Properties.Header_libs...)
deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Static_libs...)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Static_rlibs...)
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs...)
deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...)
@@ -338,6 +362,7 @@
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor.Exclude_runtime_libs)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor.Static_rlibs...)
}
if ctx.inProduct() {
@@ -351,6 +376,7 @@
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Product.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Product.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Product.Exclude_runtime_libs)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Product.Static_rlibs...)
}
if ctx.inRecovery() {
@@ -364,6 +390,7 @@
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Recovery.Exclude_runtime_libs)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Recovery.Static_rlibs...)
}
if ctx.inRamdisk() {
@@ -374,6 +401,7 @@
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Ramdisk.Exclude_runtime_libs)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Ramdisk.Static_rlibs...)
}
if ctx.inVendorRamdisk() {
@@ -383,6 +411,7 @@
deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
deps.RuntimeLibs = removeListFromList(deps.RuntimeLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_runtime_libs)
+ deps.Rlibs = append(deps.Rlibs, linker.Properties.Target.Vendor_ramdisk.Static_rlibs...)
}
if !ctx.useSdk() {
diff --git a/cc/test.go b/cc/test.go
index 3a1a3af..a96af31 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -359,6 +359,12 @@
func (test *testBinary) linkerFlags(ctx ModuleContext, flags Flags) Flags {
flags = test.binaryDecorator.linkerFlags(ctx, flags)
flags = test.testDecorator.linkerFlags(ctx, flags)
+
+ // Add a default rpath to allow tests to dlopen libraries specified in data_libs.
+ // Host modules already get an rpath specified in linker.go.
+ if !ctx.Host() {
+ flags.Global.LdFlags = append(flags.Global.LdFlags, `-Wl,-rpath,\$$ORIGIN`)
+ }
return flags
}
diff --git a/cc/testing.go b/cc/testing.go
index c3a33cb..989be02 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -300,6 +300,7 @@
system_shared_libs: [],
stl: "none",
vendor_available: true,
+ vendor_ramdisk_available: true,
product_available: true,
recovery_available: true,
host_supported: true,
diff --git a/cmd/release_config/crunch_flags/main.go b/cmd/release_config/crunch_flags/main.go
index cd39ffd..8a80a02 100644
--- a/cmd/release_config/crunch_flags/main.go
+++ b/cmd/release_config/crunch_flags/main.go
@@ -16,8 +16,8 @@
)
var (
- // When a flag declaration has an initial value that is a string, the default workflow is PREBUILT.
- // If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is MANUAL.
+ // When a flag declaration has an initial value that is a string, the default workflow is WorkflowPrebuilt.
+ // If the flag name starts with any of prefixes in manualFlagNamePrefixes, it is WorkflowManual.
manualFlagNamePrefixes []string = []string{
"RELEASE_ACONFIG_",
"RELEASE_PLATFORM_",
@@ -133,8 +133,8 @@
Containers: containers,
}
description = ""
- // Most build flags are `workflow: PREBUILT`.
- workflow := rc_proto.Workflow(rc_proto.Workflow_PREBUILT)
+ // Most build flags are `workflow: WorkflowPrebuilt`.
+ workflow := rc_proto.Workflow(rc_proto.Workflow_WorkflowPrebuilt)
switch {
case declName == "RELEASE_ACONFIG_VALUE_SETS":
if strings.HasPrefix(declValue, "\"") {
@@ -142,21 +142,21 @@
}
continue
case strings.HasPrefix(declValue, "\""):
- // String values mean that the flag workflow is (most likely) either MANUAL or PREBUILT.
+ // String values mean that the flag workflow is (most likely) either WorkflowManual or WorkflowPrebuilt.
declValue = declValue[1 : len(declValue)-1]
flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{declValue}}
for _, prefix := range manualFlagNamePrefixes {
if strings.HasPrefix(declName, prefix) {
- workflow = rc_proto.Workflow(rc_proto.Workflow_MANUAL)
+ workflow = rc_proto.Workflow(rc_proto.Workflow_WorkflowManual)
break
}
}
case declValue == "False" || declValue == "True":
- // Boolean values are LAUNCH flags.
+ // Boolean values are WorkflowLaunch flags.
flagDeclaration.Value = &rc_proto.Value{Val: &rc_proto.Value_BoolValue{declValue == "True"}}
- workflow = rc_proto.Workflow(rc_proto.Workflow_LAUNCH)
+ workflow = rc_proto.Workflow(rc_proto.Workflow_WorkflowLaunch)
case declValue == "None":
- // Use PREBUILT workflow with no initial value.
+ // Use WorkflowPrebuilt workflow with no initial value.
default:
fmt.Printf("%s: Unexpected value %s=%s\n", path, declName, declValue)
}
diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go
index 5432806..0617838 100644
--- a/cmd/release_config/release_config/main.go
+++ b/cmd/release_config/release_config/main.go
@@ -51,7 +51,7 @@
flag.BoolVar(&textproto, "textproto", true, "write artifacts as text protobuf")
flag.BoolVar(&json, "json", true, "write artifacts as json")
flag.BoolVar(&pb, "pb", true, "write artifacts as binary protobuf")
- flag.BoolVar(&allMake, "all_make", true, "write makefiles for all release configs")
+ flag.BoolVar(&allMake, "all_make", false, "write makefiles for all release configs")
flag.BoolVar(&useBuildVar, "use_get_build_var", false, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS")
flag.BoolVar(&guard, "guard", true, "whether to guard with RELEASE_BUILD_FLAGS_IN_PROTOBUF")
@@ -77,7 +77,7 @@
panic(err)
}
- makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, targetRelease))
+ makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.varmk", product, targetRelease))
useProto, ok := config.FlagArtifacts["RELEASE_BUILD_FLAGS_IN_PROTOBUF"]
if guard && (!ok || rc_lib.MarshalValue(useProto.Value) == "") {
// We were told to guard operation and either we have no build flag, or it is False.
@@ -92,10 +92,10 @@
}
if allMake {
// Write one makefile per release config, using the canonical release name.
- for k, _ := range configs.ReleaseConfigs {
- if k != targetRelease {
- makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.mk", product, k))
- err = configs.WriteMakefile(makefilePath, k)
+ for _, c := range configs.GetSortedReleaseConfigs() {
+ if c.Name != targetRelease {
+ makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.varmk", product, c.Name))
+ err = configs.WriteMakefile(makefilePath, c.Name)
if err != nil {
panic(err)
}
diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go
index 8204822..82adc34 100644
--- a/cmd/release_config/release_config_lib/release_config.go
+++ b/cmd/release_config/release_config_lib/release_config.go
@@ -69,6 +69,9 @@
// Unmarshalled flag artifacts
FlagArtifacts FlagArtifacts
+ // The files used by this release config
+ FilesUsedMap map[string]bool
+
// Generated release config
ReleaseConfigArtifact *rc_proto.ReleaseConfigArtifact
@@ -80,10 +83,17 @@
}
func ReleaseConfigFactory(name string, index int) (c *ReleaseConfig) {
- return &ReleaseConfig{Name: name, DeclarationIndex: index}
+ return &ReleaseConfig{
+ Name: name,
+ DeclarationIndex: index,
+ FilesUsedMap: make(map[string]bool),
+ }
}
func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error {
+ for f := range iConfig.FilesUsedMap {
+ config.FilesUsedMap[f] = true
+ }
for _, fa := range iConfig.FlagArtifacts {
name := *fa.FlagDeclaration.Name
myFa, ok := config.FlagArtifacts[name]
@@ -91,7 +101,8 @@
return fmt.Errorf("Could not inherit flag %s from %s", name, iConfig.Name)
}
if name == "RELEASE_ACONFIG_VALUE_SETS" {
- if len(fa.Traces) > 0 {
+ // If there is a value assigned, add the trace.
+ if len(fa.Value.GetStringValue()) > 0 {
myFa.Traces = append(myFa.Traces, fa.Traces...)
myFa.Value = &rc_proto.Value{Val: &rc_proto.Value_StringValue{
myFa.Value.GetStringValue() + " " + fa.Value.GetStringValue()}}
@@ -105,6 +116,17 @@
return nil
}
+func (config *ReleaseConfig) GetSortedFileList() []string {
+ ret := []string{}
+ for k := range config.FilesUsedMap {
+ ret = append(ret, k)
+ }
+ slices.SortFunc(ret, func(a, b string) int {
+ return cmp.Compare(a, b)
+ })
+ return ret
+}
+
func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) error {
if config.ReleaseConfigArtifact != nil {
return nil
@@ -144,9 +166,18 @@
return err
}
}
+
+ // If we inherited nothing, then we need to mark the global files as used for this
+ // config. If we inherited, then we already marked them as part of inheritance.
+ if len(config.InheritNames) == 0 {
+ for f := range configs.FilesUsedMap {
+ config.FilesUsedMap[f] = true
+ }
+ }
+
contributionsToApply = append(contributionsToApply, config.Contributions...)
- workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL)
+ workflowManual := rc_proto.Workflow(rc_proto.Workflow_WorkflowManual)
myDirsMap := make(map[int]bool)
for _, contrib := range contributionsToApply {
contribAconfigValueSets := []string{}
@@ -180,8 +211,8 @@
return fmt.Errorf("Setting value for flag %s not allowed in %s\n", name, value.path)
}
if isRoot && *fa.FlagDeclaration.Workflow != workflowManual {
- // The "root" release config can only contain workflow: MANUAL flags.
- return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", name, value.path)
+ // The "root" release config can only contain workflow: WorkflowManual flags.
+ return fmt.Errorf("Setting value for non-WorkflowManual flag %s is not allowed in %s", name, value.path)
}
if err := fa.UpdateValue(*value); err != nil {
return err
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index 2487f2e..65e6d90 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -67,6 +67,9 @@
// Map of directory to *ReleaseConfigMap
releaseConfigMapsMap map[string]*ReleaseConfigMap
+ // The files used by all release configs
+ FilesUsedMap map[string]bool
+
// The list of config directories used.
configDirs []string
@@ -102,8 +105,9 @@
releaseConfigMapsMap: make(map[string]*ReleaseConfigMap),
configDirs: []string{},
configDirIndexes: make(ReleaseConfigDirMap),
+ FilesUsedMap: make(map[string]bool),
}
- workflowManual := rc_proto.Workflow(rc_proto.Workflow_MANUAL)
+ workflowManual := rc_proto.Workflow(rc_proto.Workflow_WorkflowManual)
releaseAconfigValueSets := FlagArtifact{
FlagDeclaration: &rc_proto.FlagDeclaration{
Name: proto.String("RELEASE_ACONFIG_VALUE_SETS"),
@@ -120,6 +124,16 @@
return &configs
}
+func (configs *ReleaseConfigs) GetSortedReleaseConfigs() (ret []*ReleaseConfig) {
+ for _, config := range configs.ReleaseConfigs {
+ ret = append(ret, config)
+ }
+ slices.SortFunc(ret, func(a, b *ReleaseConfig) int {
+ return cmp.Compare(a.Name, b.Name)
+ })
+ return ret
+}
+
func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) {
m = &ReleaseConfigMap{
path: protoPath,
@@ -170,6 +184,7 @@
return fmt.Errorf("Release config map %s has invalid container %s", path, container)
}
}
+ configs.FilesUsedMap[path] = true
dir := filepath.Dir(path)
// Record any aliases, checking for duplicates.
for _, alias := range m.proto.Aliases {
@@ -216,6 +231,7 @@
return fmt.Errorf("Duplicate definition of %s", *flagDeclaration.Name)
}
// Set the initial value in the flag artifact.
+ configs.FilesUsedMap[path] = true
configs.FlagArtifacts[name].UpdateValue(
FlagValue{path: path, proto: rc_proto.FlagValue{
Name: proto.String(name), Value: flagDeclaration.Value}})
@@ -239,6 +255,7 @@
configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex)
}
config := configs.ReleaseConfigs[name]
+ config.FilesUsedMap[path] = true
config.InheritNames = append(config.InheritNames, releaseConfigContribution.proto.Inherits...)
// Only walk flag_values/{RELEASE} for defined releases.
@@ -250,6 +267,7 @@
if *flagValue.proto.Name == "RELEASE_ACONFIG_VALUE_SETS" {
return fmt.Errorf("%s: %s is a reserved build flag", path, *flagValue.proto.Name)
}
+ config.FilesUsedMap[path] = true
releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue)
return nil
})
@@ -283,9 +301,7 @@
return nil, fmt.Errorf("Missing config %s. Trace=%v", name, trace)
}
-// Write the makefile for this targetRelease.
-func (configs *ReleaseConfigs) WriteMakefile(outFile, targetRelease string) error {
- makeVars := make(map[string]string)
+func (configs *ReleaseConfigs) GetAllReleaseNames() []string {
var allReleaseNames []string
for _, v := range configs.ReleaseConfigs {
allReleaseNames = append(allReleaseNames, v.Name)
@@ -294,6 +310,12 @@
slices.SortFunc(allReleaseNames, func(a, b string) int {
return cmp.Compare(a, b)
})
+ return allReleaseNames
+}
+
+// Write the makefile for this targetRelease.
+func (configs *ReleaseConfigs) WriteMakefile(outFile, targetRelease string) error {
+ makeVars := make(map[string]string)
config, err := configs.GetReleaseConfig(targetRelease)
if err != nil {
return err
@@ -356,7 +378,8 @@
data += fmt.Sprintf("# User specified TARGET_RELEASE=%s\n", targetRelease)
}
// The variable _all_release_configs will get deleted during processing, so do not mark it read-only.
- data += fmt.Sprintf("_all_release_configs := %s\n", strings.Join(allReleaseNames, " "))
+ data += fmt.Sprintf("_all_release_configs := %s\n", strings.Join(configs.GetAllReleaseNames(), " "))
+ data += fmt.Sprintf("_used_files := %s\n", strings.Join(config.GetSortedFileList(), " "))
data += fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " "))
for _, pName := range pNames {
data += fmt.Sprintf("_ALL_RELEASE_FLAGS.PARTITIONS.%s :=$= %s\n", pName, strings.Join(partitions[pName], " "))
@@ -388,8 +411,9 @@
configs.ReleaseConfigs[name].OtherNames = aliases
}
- for _, config := range configs.ReleaseConfigs {
- err := config.GenerateReleaseConfig(configs)
+ sortedReleaseConfigs := configs.GetSortedReleaseConfigs()
+ for _, c := range sortedReleaseConfigs {
+ err := c.GenerateReleaseConfig(configs)
if err != nil {
return err
}
@@ -399,17 +423,16 @@
if err != nil {
return err
}
+ orc := []*rc_proto.ReleaseConfigArtifact{}
+ for _, c := range sortedReleaseConfigs {
+ if c.Name != releaseConfig.Name {
+ orc = append(orc, c.ReleaseConfigArtifact)
+ }
+ }
+
configs.Artifact = rc_proto.ReleaseConfigsArtifact{
- ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
- OtherReleaseConfigs: func() []*rc_proto.ReleaseConfigArtifact {
- orc := []*rc_proto.ReleaseConfigArtifact{}
- for name, config := range configs.ReleaseConfigs {
- if name != releaseConfig.Name {
- orc = append(orc, config.ReleaseConfigArtifact)
- }
- }
- return orc
- }(),
+ ReleaseConfig: releaseConfig.ReleaseConfigArtifact,
+ OtherReleaseConfigs: orc,
ReleaseConfigMapsMap: func() map[string]*rc_proto.ReleaseConfigMap {
ret := make(map[string]*rc_proto.ReleaseConfigMap)
for k, v := range configs.releaseConfigMapsMap {
@@ -439,7 +462,8 @@
configs := ReleaseConfigsFactory()
mapsRead := make(map[string]bool)
- for idx, releaseConfigMapPath := range releaseConfigMapPaths {
+ var idx int
+ for _, releaseConfigMapPath := range releaseConfigMapPaths {
// Maintain an ordered list of release config directories.
configDir := filepath.Dir(releaseConfigMapPath)
if mapsRead[configDir] {
@@ -454,6 +478,7 @@
if err != nil {
return nil, err
}
+ idx += 1
}
// Now that we have all of the release config maps, can meld them and generate the artifacts.
diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go
index 483cffa..8fa75aa 100644
--- a/cmd/release_config/release_config_proto/build_flags_out.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go
@@ -11,7 +11,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.30.0
+// protoc-gen-go v1.33.0
// protoc v3.21.12
// source: build_flags_out.proto
diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go
index dded975..c52a238 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.pb.go
+++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go
@@ -11,7 +11,7 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
-// protoc-gen-go v1.30.0
+// protoc-gen-go v1.33.0
// protoc v3.21.12
// source: build_flags_src.proto
@@ -34,30 +34,30 @@
type Workflow int32
const (
- Workflow_UNSPECIFIED_workflow Workflow = 0
+ Workflow_WorkflowUnspecified Workflow = 0
// Boolean value flags that progress from false to true.
- Workflow_LAUNCH Workflow = 1
+ Workflow_WorkflowLaunch Workflow = 1
// String value flags that get updated with new version strings to control
// prebuilt inclusion.
- Workflow_PREBUILT Workflow = 2
+ Workflow_WorkflowPrebuilt Workflow = 2
// Manually managed outside flags. These are likely to be found in a
// different directory than flags with other workflows.
- Workflow_MANUAL Workflow = 3
+ Workflow_WorkflowManual Workflow = 3
)
// Enum value maps for Workflow.
var (
Workflow_name = map[int32]string{
- 0: "UNSPECIFIED_workflow",
- 1: "LAUNCH",
- 2: "PREBUILT",
- 3: "MANUAL",
+ 0: "WorkflowUnspecified",
+ 1: "WorkflowLaunch",
+ 2: "WorkflowPrebuilt",
+ 3: "WorkflowManual",
}
Workflow_value = map[string]int32{
- "UNSPECIFIED_workflow": 0,
- "LAUNCH": 1,
- "PREBUILT": 2,
- "MANUAL": 3,
+ "WorkflowUnspecified": 0,
+ "WorkflowLaunch": 1,
+ "WorkflowPrebuilt": 2,
+ "WorkflowManual": 3,
}
)
@@ -295,7 +295,7 @@
if x != nil && x.Workflow != nil {
return *x.Workflow
}
- return Workflow_UNSPECIFIED_workflow
+ return Workflow_WorkflowUnspecified
}
func (x *FlagDeclaration) GetContainers() []string {
@@ -642,15 +642,17 @@
0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2d, 0x0a,
0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e,
0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, 0x66, 0x61, 0x75,
- 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a, 0x4a, 0x0a, 0x08,
- 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x55, 0x4e, 0x53, 0x50,
- 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x5f, 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77,
- 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c,
- 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06,
- 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72,
- 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73,
- 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
- 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
+ 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a, 0x61, 0x0a, 0x08,
+ 0x77, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x17, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b,
+ 0x66, 0x6c, 0x6f, 0x77, 0x55, 0x6e, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10,
+ 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4c, 0x61, 0x75,
+ 0x6e, 0x63, 0x68, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f,
+ 0x77, 0x50, 0x72, 0x65, 0x62, 0x75, 0x69, 0x6c, 0x74, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x57,
+ 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x10, 0x03, 0x42,
+ 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f,
}
var (
diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto
index 0ef1a5f..81c6ae3 100644
--- a/cmd/release_config/release_config_proto/build_flags_src.proto
+++ b/cmd/release_config/release_config_proto/build_flags_src.proto
@@ -39,18 +39,18 @@
// com.android.1mypackage are invalid
enum workflow {
- UNSPECIFIED_workflow = 0;
+ WorkflowUnspecified = 0;
// Boolean value flags that progress from false to true.
- LAUNCH = 1;
+ WorkflowLaunch = 1;
// String value flags that get updated with new version strings to control
// prebuilt inclusion.
- PREBUILT = 2;
+ WorkflowPrebuilt = 2;
// Manually managed outside flags. These are likely to be found in a
// different directory than flags with other workflows.
- MANUAL = 3;
+ WorkflowManual = 3;
}
message value {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index d64010e..4490dd2 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -108,7 +108,7 @@
case "always":
return true
case "depend":
- if _, err := os.Stat(filepath.Join(ctx.Config().OutDir(), ".ninja_log")); errors.Is(err, os.ErrNotExist) {
+ if _, err := os.Stat(filepath.Join(topDir, ctx.Config().OutDir(), ".ninja_log")); errors.Is(err, os.ErrNotExist) {
return true
}
}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 6ab3b88..e168edc 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -59,6 +59,7 @@
ctx.RegisterModuleType("prebuilt_usr_keychars", PrebuiltUserKeyCharsFactory)
ctx.RegisterModuleType("prebuilt_usr_idc", PrebuiltUserIdcFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
+ ctx.RegisterModuleType("prebuilt_overlay", PrebuiltOverlayFactory)
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory)
@@ -650,6 +651,15 @@
return module
}
+// prebuilt_overlay is for a prebuilt artifact in <partition>/overlay directory.
+func PrebuiltOverlayFactory() android.Module {
+ module := &PrebuiltEtc{}
+ InitPrebuiltEtcModule(module, "overlay")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
+
// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system
// image.
// If soc_specific property is set to true, the firmware file is installed to the
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 3ee2340..c44574a 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -342,6 +342,19 @@
android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
}
+func TestPrebuiltOverlayInstallDirPath(t *testing.T) {
+ result := prepareForPrebuiltEtcTest.RunTestWithBp(t, `
+ prebuilt_overlay {
+ name: "foo.conf",
+ src: "foo.conf",
+ }
+ `)
+
+ p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
+ expected := "out/soong/target/product/test_device/system/overlay"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
+}
+
func TestPrebuiltFirmwareDirPath(t *testing.T) {
targetPath := "out/soong/target/product/test_device"
tests := []struct {
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 854a366..a08f7cf 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -15,6 +15,7 @@
"soong-phony", // for testing
],
srcs: [
+ "aconfig_files.go",
"avb_add_hash_footer.go",
"avb_gen_vbmeta_image.go",
"bootimg.go",
diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go
new file mode 100644
index 0000000..8daee85
--- /dev/null
+++ b/filesystem/aconfig_files.go
@@ -0,0 +1,82 @@
+// Copyright (C) 2024 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 filesystem
+
+import (
+ "android/soong/android"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func (f *filesystem) buildAconfigFlagsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, dir android.OutputPath) {
+ if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) {
+ return
+ }
+
+ aconfigFlagsBuilderPath := android.PathForModuleOut(ctx, "aconfig_flags_builder.sh")
+ aconfigToolPath := ctx.Config().HostToolPath(ctx, "aconfig")
+ cmd := builder.Command().Tool(aconfigFlagsBuilderPath).Implicit(aconfigToolPath)
+
+ var caches []string
+ for _, ps := range specs {
+ cmd.Implicits(ps.GetAconfigPaths())
+ caches = append(caches, ps.GetAconfigPaths().Strings()...)
+ }
+ caches = android.SortedUniqueStrings(caches)
+
+ var sbCaches strings.Builder
+ for _, cache := range caches {
+ sbCaches.WriteString(" --cache ")
+ sbCaches.WriteString(cache)
+ sbCaches.WriteString(" \\\n")
+ }
+ sbCaches.WriteRune('\n')
+
+ var sb strings.Builder
+ sb.WriteString("set -e\n")
+
+ installAconfigFlagsPath := dir.Join(ctx, "etc", "aconfig_flags.pb")
+ sb.WriteString(aconfigToolPath.String())
+ sb.WriteString(" dump-cache --dedup --format protobuf --out ")
+ sb.WriteString(installAconfigFlagsPath.String())
+ sb.WriteString(" \\\n")
+ sb.WriteString(sbCaches.String())
+ cmd.ImplicitOutput(installAconfigFlagsPath)
+
+ installAconfigStorageDir := dir.Join(ctx, "etc", "aconfig")
+ sb.WriteString("mkdir -p ")
+ sb.WriteString(installAconfigStorageDir.String())
+ sb.WriteRune('\n')
+
+ generatePartitionAconfigStorageFile := func(fileType, fileName string) {
+ sb.WriteString(aconfigToolPath.String())
+ sb.WriteString(" create-storage --container ")
+ sb.WriteString(f.PartitionType())
+ sb.WriteString(" --file ")
+ sb.WriteString(fileType)
+ sb.WriteString(" --out ")
+ sb.WriteString(filepath.Join(installAconfigStorageDir.String(), fileName))
+ sb.WriteString(" \\\n")
+ sb.WriteString(sbCaches.String())
+ cmd.ImplicitOutput(installAconfigStorageDir.Join(ctx, fileName))
+ }
+ generatePartitionAconfigStorageFile("package_map", "package.map")
+ generatePartitionAconfigStorageFile("flag_map", "flag.map")
+ generatePartitionAconfigStorageFile("flag_val", "flag.val")
+
+ android.WriteExecutableFileRuleVerbatim(ctx, aconfigFlagsBuilderPath, sb.String())
+}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index b342ae9..8b71e85 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -131,6 +131,9 @@
// Default is false
Build_logtags *bool
+ // Install aconfig_flags.pb file for the modules installed in this partition.
+ Gen_aconfig_flags_pb *bool
+
Fsverity fsverityProperties
}
@@ -149,6 +152,7 @@
func initFilesystemModule(module *filesystem) {
module.AddProperties(&module.properties)
android.InitPackageModule(module)
+ module.PackagingBase.DepsCollectFirstTargetOnly = true
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
}
@@ -300,6 +304,7 @@
f.addMakeBuiltFiles(ctx, builder, rootDir)
f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
f.buildEventLogtagsFile(ctx, builder, rebasedDir)
+ f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
// run host_init_verifier
// Ideally we should have a concept of pluggable linters that verify the generated image.
@@ -441,6 +446,7 @@
f.buildNonDepsFiles(ctx, builder, rootDir)
f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir)
f.buildEventLogtagsFile(ctx, builder, rebasedDir)
+ f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir)
output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
cmd := builder.Command().
diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go
index acd4813..2dc8c21 100644
--- a/filesystem/filesystem_test.go
+++ b/filesystem/filesystem_test.go
@@ -465,3 +465,98 @@
}
`)
}
+
+func TestTrackPhonyAsRequiredDep(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "fs",
+ deps: ["foo"],
+ }
+
+ cc_binary {
+ name: "foo",
+ required: ["phony"],
+ }
+
+ phony {
+ name: "phony",
+ required: ["libbar"],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+ `)
+
+ fs := result.ModuleForTests("fs", "android_common").Module().(*filesystem)
+ expected := []string{
+ "bin/foo",
+ "lib64/libbar.so",
+ }
+ for _, e := range expected {
+ android.AssertStringListContains(t, "missing entry", fs.entries, e)
+ }
+}
+
+func TestFilterOutUnsupportedArches(t *testing.T) {
+ result := fixture.RunTestWithBp(t, `
+ android_filesystem {
+ name: "fs_64_only",
+ deps: ["foo"],
+ }
+
+ android_filesystem {
+ name: "fs_64_32",
+ compile_multilib: "both",
+ deps: ["foo"],
+ }
+
+ cc_binary {
+ name: "foo",
+ required: ["phony"],
+ }
+
+ phony {
+ name: "phony",
+ required: [
+ "libbar",
+ "app",
+ ],
+ }
+
+ cc_library {
+ name: "libbar",
+ }
+
+ android_app {
+ name: "app",
+ srcs: ["a.java"],
+ platform_apis: true,
+ }
+ `)
+ testcases := []struct {
+ fsName string
+ expected []string
+ unexpected []string
+ }{
+ {
+ fsName: "fs_64_only",
+ expected: []string{"app/app/app.apk", "bin/foo", "lib64/libbar.so"},
+ unexpected: []string{"lib/libbar.so"},
+ },
+ {
+ fsName: "fs_64_32",
+ expected: []string{"app/app/app.apk", "bin/foo", "lib64/libbar.so", "lib/libbar.so"},
+ unexpected: []string{},
+ },
+ }
+ for _, c := range testcases {
+ fs := result.ModuleForTests(c.fsName, "android_common").Module().(*filesystem)
+ for _, e := range c.expected {
+ android.AssertStringListContains(t, "missing entry", fs.entries, e)
+ }
+ for _, e := range c.unexpected {
+ android.AssertStringListDoesNotContain(t, "unexpected entry", fs.entries, e)
+ }
+ }
+}
diff --git a/java/androidmk.go b/java/androidmk.go
index 4316074..a1bc904 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -412,6 +412,12 @@
if app.embeddedJniLibs {
jniSymbols := app.JNISymbolsInstalls(app.installPathForJNISymbols.String())
entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", jniSymbols.String())
+ } else {
+ var names []string
+ for _, jniLib := range app.jniLibs {
+ names = append(names, jniLib.name)
+ }
+ entries.AddStrings("LOCAL_REQUIRED_MODULES", names...)
}
if len(app.jniCoverageOutputs) > 0 {
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 875e06f..243a279 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -19,6 +19,7 @@
"testing"
"android/soong/android"
+ "android/soong/cc"
)
func TestRequired(t *testing.T) {
@@ -252,3 +253,51 @@
android.AssertDeepEquals(t, "overrides property", expected.overrides, actual)
}
}
+
+func TestJniAsRequiredDeps(t *testing.T) {
+ ctx := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ cc.PrepareForTestWithCcDefaultModules,
+ android.PrepareForTestWithAndroidMk,
+ ).RunTestWithBp(t, `
+ android_app {
+ name: "app",
+ jni_libs: ["libjni"],
+ platform_apis: true,
+ }
+
+ android_app {
+ name: "app_embedded",
+ jni_libs: ["libjni"],
+ platform_apis: true,
+ use_embedded_native_libs: true,
+ }
+
+ cc_library {
+ name: "libjni",
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ testcases := []struct {
+ name string
+ expected []string
+ }{
+ {
+ name: "app",
+ expected: []string{"libjni"},
+ },
+ {
+ name: "app_embedded",
+ expected: nil,
+ },
+ }
+
+ for _, tc := range testcases {
+ mod := ctx.ModuleForTests(tc.name, "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod)[0]
+ required := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+ android.AssertDeepEquals(t, "unexpected required deps", tc.expected, required)
+ }
+}
diff --git a/java/app.go b/java/app.go
index 254fbf4..ea72157 100644
--- a/java/app.go
+++ b/java/app.go
@@ -90,17 +90,20 @@
Stl *string `android:"arch_variant"`
// Store native libraries uncompressed in the APK and set the android:extractNativeLibs="false" manifest
- // flag so that they are used from inside the APK at runtime. This property is respected only for
- // APKs built using android_test or android_test_helper_app. For other APKs, this property is ignored
- // and native libraries are always embedded compressed.
+ // flag so that they are used from inside the APK at runtime. Defaults to true for android_test modules unless
+ // sdk_version or min_sdk_version is set to a version that doesn't support it (<23), defaults to true for
+ // android_app modules that are embedded to APEXes, defaults to false for other module types where the native
+ // libraries are generally preinstalled outside the APK.
Use_embedded_native_libs *bool
// Store dex files uncompressed in the APK and set the android:useEmbeddedDex="true" manifest attribute so that
// they are used from inside the APK at runtime.
Use_embedded_dex *bool
- // Allows compressing of embedded native libs. Only for android_test and android_test_helper_app.
- AllowCompressingNativeLibs bool `blueprint:"mutated"`
+ // Forces native libraries to always be packaged into the APK,
+ // Use_embedded_native_libs still selects whether they are stored uncompressed and aligned or compressed.
+ // True for android_test* modules.
+ AlwaysPackageNativeLibs bool `blueprint:"mutated"`
// If set, find and merge all NOTICE files that this module and its dependencies have and store
// it in the APK as an asset.
@@ -271,16 +274,37 @@
variation := append(jniTarget.Variations(),
blueprint.Variation{Mutator: "link", Variation: "shared"})
- // If the app builds against an Android SDK use the SDK variant of JNI dependencies
- // unless jni_uses_platform_apis is set.
- // Don't require the SDK variant for apps that are shipped on vendor, etc., as they already
- // have stable APIs through the VNDK.
- if (usesSDK && !a.RequiresStableAPIs(ctx) &&
- !Bool(a.appProperties.Jni_uses_platform_apis)) ||
- Bool(a.appProperties.Jni_uses_sdk_apis) {
+ // Test whether to use the SDK variant or the non-SDK variant of JNI dependencies.
+ // Many factors are considered here.
+ // 1. Basically, the selection follows whether the app has sdk_version set or not.
+ jniUsesSdkVariant := usesSDK
+ // 2. However, jni_uses_platform_apis and jni_uses_sdk_apis can override it
+ if Bool(a.appProperties.Jni_uses_sdk_apis) {
+ jniUsesSdkVariant = true
+ }
+ if Bool(a.appProperties.Jni_uses_platform_apis) {
+ jniUsesSdkVariant = false
+ }
+ // 3. Then the use of SDK variant is again prohibited for the following cases:
+ // 3.1. the app is shipped on unbundled partitions like vendor. Since the entire
+ // partition (not only the app) is considered unbudled, there's no need to use the
+ // SDK variant.
+ // 3.2. the app doesn't support embedding the JNI libs
+ if a.RequiresStableAPIs(ctx) || !a.shouldEmbedJnis(ctx) {
+ jniUsesSdkVariant = false
+ }
+ if jniUsesSdkVariant {
variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
}
- ctx.AddFarVariationDependencies(variation, jniLibTag, a.appProperties.Jni_libs...)
+
+ // Use the installable dep tag when the JNIs are not embedded
+ var tag dependencyTag
+ if a.shouldEmbedJnis(ctx) {
+ tag = jniLibTag
+ } else {
+ tag = jniInstallTag
+ }
+ ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
}
for _, aconfig_declaration := range a.aaptProperties.Flags_packages {
ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
@@ -331,27 +355,17 @@
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.checkAppSdkVersions(ctx)
+ a.checkEmbedJnis(ctx)
a.generateAndroidBuildActions(ctx)
a.generateJavaUsedByApex(ctx)
}
-func (a *AndroidApp) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
- defaultMinSdkVersion := a.Module.MinSdkVersion(ctx)
- if proptools.Bool(a.appProperties.Updatable) {
- overrideApiLevel := android.MinSdkVersionFromValue(ctx, ctx.DeviceConfig().ApexGlobalMinSdkVersionOverride())
- if !overrideApiLevel.IsNone() && overrideApiLevel.CompareTo(defaultMinSdkVersion) > 0 {
- return overrideApiLevel
- }
- }
- return defaultMinSdkVersion
-}
-
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
if a.Updatable() {
if !a.SdkVersion(ctx).Stable() {
ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion(ctx))
}
- if String(a.deviceProperties.Min_sdk_version) == "" {
+ if String(a.overridableProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
@@ -375,6 +389,17 @@
a.checkSdkVersions(ctx)
}
+// Ensures that use_embedded_native_libs are set for apk-in-apex
+func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) {
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ apkInApex := !apexInfo.IsForPlatform()
+ hasJnis := len(a.appProperties.Jni_libs) > 0
+
+ if apkInApex && hasJnis && !Bool(a.appProperties.Use_embedded_native_libs) {
+ ctx.ModuleErrorf("APK in APEX should have use_embedded_native_libs: true")
+ }
+}
+
// If an updatable APK sets min_sdk_version, min_sdk_vesion of JNI libs should match with it.
// This check is enforced for "updatable" APKs (including APK-in-APEX).
func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) {
@@ -400,20 +425,14 @@
// Returns true if the native libraries should be stored in the APK uncompressed and the
// extractNativeLibs application flag should be set to false in the manifest.
func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool {
- var useEmbedded bool
- if a.appProperties.AllowCompressingNativeLibs {
- useEmbedded = BoolDefault(a.appProperties.Use_embedded_native_libs, true)
- } else {
- useEmbedded = true // always uncompress for non-test apps
- }
-
minSdkVersion, err := a.MinSdkVersion(ctx).EffectiveVersion(ctx)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(ctx), err)
}
- supported := minSdkVersion.FinalOrFutureInt() >= 23
- return useEmbedded && supported
+ apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ return (minSdkVersion.FinalOrFutureInt() >= 23 && Bool(a.appProperties.Use_embedded_native_libs)) ||
+ !apexInfo.IsForPlatform()
}
// Returns whether this module should have the dex file stored uncompressed in the APK.
@@ -436,23 +455,9 @@
}
func (a *AndroidApp) shouldEmbedJnis(ctx android.BaseModuleContext) bool {
- // Always!
- return true
-}
-
-func (a *AndroidApp) shouldCollectRecursiveNativeDeps(ctx android.ModuleContext) bool {
- // JNI libs are always embedded, but whether to embed their transitive dependencies as well
- // or not is determined here. For most of the apps built here (using the platform build
- // system), we don't need to collect the transitive deps because they will anyway be
- // available in the partition image where the app will be installed to.
- //
- // Collecting transitive dependencies is required only for unbundled apps.
- apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
- apkInApex := !apexInfo.IsForPlatform()
- testApp := a.appProperties.AllowCompressingNativeLibs
- unbundledApp := ctx.Config().UnbundledBuild() || apkInApex || testApp
-
- return a.shouldEmbedJnis(ctx) && unbundledApp
+ return ctx.Config().UnbundledBuild() || Bool(a.appProperties.Use_embedded_native_libs) ||
+ Bool(a.appProperties.Updatable) ||
+ a.appProperties.AlwaysPackageNativeLibs
}
func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string {
@@ -538,7 +543,7 @@
}
// Use non final ids if we are doing optimized shrinking and are using R8.
- nonFinalIds := Bool(a.dexProperties.Optimize.Optimized_shrink_resources) && a.dexer.effectiveOptimizeEnabled()
+ nonFinalIds := a.dexProperties.optimizedResourceShrinkingEnabled(ctx) && a.dexer.effectiveOptimizeEnabled()
a.aapt.buildActions(ctx,
aaptBuildActionOptions{
sdkContext: android.SdkContext(a),
@@ -569,7 +574,7 @@
staticLibProguardFlagFiles = android.FirstUniquePaths(staticLibProguardFlagFiles)
a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, staticLibProguardFlagFiles...)
- if !Bool(a.dexProperties.Optimize.Optimized_shrink_resources) {
+ if !(a.dexProperties.optimizedResourceShrinkingEnabled(ctx)) {
// When using the optimized shrinking the R8 enqueuer will traverse the xml files that become
// live for code references and (transitively) mark these as live.
// In this case we explicitly don't wan't the aapt2 generated keep files (which would keep the now
@@ -608,7 +613,7 @@
var packageResources = a.exportPackage
if ctx.ModuleName() != "framework-res" {
- if a.dexProperties.resourceShrinkingEnabled() {
+ if a.dexProperties.resourceShrinkingEnabled(ctx) {
protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk")
aapt2Convert(ctx, protoFile, packageResources, "proto")
a.dexer.resourcesInput = android.OptionalPathForPath(protoFile)
@@ -631,7 +636,7 @@
}
a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars)
- if a.dexProperties.resourceShrinkingEnabled() {
+ if a.dexProperties.resourceShrinkingEnabled(ctx) {
binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk")
aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary")
packageResources = binaryResources
@@ -846,7 +851,9 @@
dexJarFile, packageResources := a.dexBuildActions(ctx)
- jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldCollectRecursiveNativeDeps(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
+ // No need to check the SDK version of the JNI deps unless we embed them
+ checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis)
+ jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), checkNativeSdkVersion)
jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx)
if ctx.Failed() {
@@ -928,6 +935,22 @@
installed := ctx.InstallFile(a.installDir, extra.Base(), extra)
extraInstalledPaths = append(extraInstalledPaths, installed)
}
+ // If we don't embed jni libs, make sure that those are installed along with the
+ // app, and also place symlinks to the installed paths under the lib/<arch>
+ // directory of the app installation directory. ex:
+ // /system/app/MyApp/lib/arm64/libfoo.so -> /system/lib64/libfoo.so
+ if !a.embeddedJniLibs {
+ for _, jniLib := range jniLibs {
+ archStr := jniLib.target.Arch.ArchType.String()
+ symlinkDir := a.installDir.Join(ctx, "lib", archStr)
+ for _, installedLib := range jniLib.installPaths {
+ // install the symlink itself
+ symlinkName := installedLib.Base()
+ symlinkTarget := android.InstallPathToOnDevicePath(ctx, installedLib)
+ ctx.InstallAbsoluteSymlink(symlinkDir, symlinkName, symlinkTarget)
+ }
+ }
+ }
ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...)
}
@@ -1015,6 +1038,7 @@
coverageFile: dep.CoverageOutputFile(),
unstrippedFile: dep.UnstrippedOutputFile(),
partition: dep.Partition(),
+ installPaths: dep.FilesToInstall(),
})
} else if ctx.Config().AllowMissingDependencies() {
ctx.AddMissingDependencies([]string{otherName})
@@ -1417,7 +1441,8 @@
module.Module.properties.Instrument = true
module.Module.properties.Supports_static_instrumentation = true
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.AllowCompressingNativeLibs = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
+ module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
@@ -1472,7 +1497,8 @@
module.Module.dexProperties.Optimize.EnabledByDefault = true
module.Module.properties.Installable = proptools.BoolPtr(true)
- module.appProperties.AllowCompressingNativeLibs = true
+ module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
+ module.appProperties.AlwaysPackageNativeLibs = true
module.Module.dexpreopter.isTest = true
module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
diff --git a/java/app_test.go b/java/app_test.go
index d6ba0f1..8049494 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -2013,8 +2013,8 @@
packaged bool
compressed bool
}{
- {"app", true, false},
- {"app_noembed", true, false},
+ {"app", false, false},
+ {"app_noembed", false, false},
{"app_embed", true, false},
{"test", true, false},
{"test_noembed", true, true},
@@ -2043,44 +2043,6 @@
}
}
-func TestJNITranstiveDepsInstallation(t *testing.T) {
- ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
- android_app {
- name: "app",
- jni_libs: ["libjni"],
- platform_apis: true,
- }
-
- cc_library {
- name: "libjni",
- shared_libs: ["libplatform"],
- system_shared_libs: [],
- stl: "none",
- required: ["librequired"],
- }
-
- cc_library {
- name: "libplatform",
- system_shared_libs: [],
- stl: "none",
- }
-
- cc_library {
- name: "librequired",
- system_shared_libs: [],
- stl: "none",
- }
-
- `)
-
- app := ctx.ModuleForTests("app", "android_common")
- jniLibZip := app.Output("jnilibs.zip")
- android.AssertPathsEndWith(t, "embedd jni lib mismatch", []string{"libjni.so"}, jniLibZip.Implicits)
-
- install := app.Rule("Cp")
- android.AssertPathsEndWith(t, "install dep mismatch", []string{"libplatform.so", "librequired.so"}, install.OrderOnly)
-}
-
func TestJNISDK(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
@@ -3357,7 +3319,8 @@
// These also include explicit `uses_libs`/`optional_uses_libs` entries, as they may be
// propagated from dependencies.
actualManifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- expectManifestFixerArgs := `--uses-library foo ` +
+ expectManifestFixerArgs := `--extract-native-libs=true ` +
+ `--uses-library foo ` +
`--uses-library com.non.sdk.lib ` +
`--uses-library qux ` +
`--uses-library quuz ` +
@@ -4147,7 +4110,7 @@
},
{
name: "aary-no-use-embedded",
- hasPackage: true,
+ hasPackage: false,
},
}
@@ -4359,52 +4322,6 @@
)
}
-func TestApexGlobalMinSdkVersionOverride(t *testing.T) {
- result := android.GroupFixturePreparers(
- PrepareForTestWithJavaDefaultModules,
- android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
- variables.ApexGlobalMinSdkVersionOverride = proptools.StringPtr("Tiramisu")
- }),
- ).RunTestWithBp(t, `
- android_app {
- name: "com.android.bar",
- srcs: ["a.java"],
- sdk_version: "current",
- }
- android_app {
- name: "com.android.foo",
- srcs: ["a.java"],
- sdk_version: "current",
- min_sdk_version: "S",
- updatable: true,
- }
- override_android_app {
- name: "com.android.go.foo",
- base: "com.android.foo",
- }
- `)
- foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer")
- fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer")
- bar := result.ModuleForTests("com.android.bar", "android_common").Rule("manifestFixer")
-
- android.AssertStringDoesContain(t,
- "expected manifest fixer to set com.android.bar minSdkVersion to S",
- bar.BuildParams.Args["args"],
- "--minSdkVersion S",
- )
- android.AssertStringDoesContain(t,
- "com.android.foo: expected manifest fixer to set minSdkVersion to T",
- foo.BuildParams.Args["args"],
- "--minSdkVersion T",
- )
- android.AssertStringDoesContain(t,
- "com.android.go.foo: expected manifest fixer to set minSdkVersion to T",
- fooOverride.BuildParams.Args["args"],
- "--minSdkVersion T",
- )
-
-}
-
func TestAppFlagsPackages(t *testing.T) {
ctx := testApp(t, `
android_app {
@@ -4529,3 +4446,36 @@
t.Errorf("Module output does not contain expected apk %s", "foo-new.apk")
}
}
+
+func TestAppMinSdkVersionOverride(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ ).RunTestWithBp(t, `
+ android_app {
+ name: "com.android.foo",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ min_sdk_version: "31",
+ updatable: true,
+ }
+ override_android_app {
+ name: "com.android.go.foo",
+ base: "com.android.foo",
+ min_sdk_version: "33",
+ }
+ `)
+ foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer")
+ fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer")
+
+ android.AssertStringDoesContain(t,
+ "com.android.foo: expected manifest fixer to set minSdkVersion to T",
+ foo.BuildParams.Args["args"],
+ "--minSdkVersion 31",
+ )
+ android.AssertStringDoesContain(t,
+ "com.android.go.foo: expected manifest fixer to set minSdkVersion to T",
+ fooOverride.BuildParams.Args["args"],
+ "--minSdkVersion 33",
+ )
+
+}
diff --git a/java/base.go b/java/base.go
index 0c28671..e97d28d 100644
--- a/java/base.go
+++ b/java/base.go
@@ -229,10 +229,6 @@
// If the SDK kind is empty, it will be set to public.
Sdk_version *string
- // if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
- // Defaults to sdk_version if not set. See sdk_version for possible values.
- Min_sdk_version *string
-
// if not blank, set the maximum version of the sdk that the compiled artifacts will run against.
// Defaults to empty string "". See sdk_version for possible values.
Max_sdk_version *string
@@ -312,6 +308,10 @@
// Otherwise, both the overridden and the overriding modules will have the same output name, which
// can cause the duplicate output error.
Stem *string
+
+ // if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
+ // Defaults to sdk_version if not set. See sdk_version for possible values.
+ Min_sdk_version *string
}
// Functionality common to Module and Import
@@ -738,8 +738,8 @@
}
func (j *Module) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
- if j.deviceProperties.Min_sdk_version != nil {
- return android.ApiLevelFrom(ctx, *j.deviceProperties.Min_sdk_version)
+ if j.overridableProperties.Min_sdk_version != nil {
+ return android.ApiLevelFrom(ctx, *j.overridableProperties.Min_sdk_version)
}
return j.SdkVersion(ctx).ApiLevel
}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 82a34ca..4d3d794 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -590,13 +590,36 @@
// So ignore it even if it is not in PRODUCT_APEX_BOOT_JARS.
// TODO(b/202896428): Add better way to handle this.
_, unknown = android.RemoveFromList("android.car-module", unknown)
- if isActiveModule(ctx, ctx.Module()) && len(unknown) > 0 {
- ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ if isApexVariant(ctx) && len(unknown) > 0 {
+ if android.IsModulePrebuilt(ctx.Module()) {
+ // prebuilt bcpf. the validation of this will be done at the top-level apex
+ providerClasspathFragmentValidationInfoProvider(ctx, unknown)
+ } else if !disableSourceApexVariant(ctx) {
+ // source bcpf, and prebuilt apex are not selected.
+ ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown)
+ }
}
}
return jars
}
+var ClasspathFragmentValidationInfoProvider = blueprint.NewProvider[ClasspathFragmentValidationInfo]()
+
+type ClasspathFragmentValidationInfo struct {
+ ClasspathFragmentModuleName string
+ UnknownJars []string
+}
+
+// Set a provider with the list of jars that have not been added to PRODUCT_APEX_BOOT_JARS
+// The validation will be done in the ctx of the top-level _selected_ apex
+func providerClasspathFragmentValidationInfoProvider(ctx android.ModuleContext, unknown []string) {
+ info := ClasspathFragmentValidationInfo{
+ ClasspathFragmentModuleName: ctx.ModuleName(),
+ UnknownJars: unknown,
+ }
+ android.SetProvider(ctx, ClasspathFragmentValidationInfoProvider, info)
+}
+
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput {
diff --git a/java/dex.go b/java/dex.go
index 6caaa7f..8cfffaf 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -111,8 +111,12 @@
return BoolDefault(d.dexProperties.Optimize.Enabled, d.dexProperties.Optimize.EnabledByDefault)
}
-func (d *DexProperties) resourceShrinkingEnabled() bool {
- return BoolDefault(d.Optimize.Optimized_shrink_resources, Bool(d.Optimize.Shrink_resources))
+func (d *DexProperties) resourceShrinkingEnabled(ctx android.ModuleContext) bool {
+ return !ctx.Config().Eng() && BoolDefault(d.Optimize.Optimized_shrink_resources, Bool(d.Optimize.Shrink_resources))
+}
+
+func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleContext) bool {
+ return d.resourceShrinkingEnabled(ctx) && Bool(d.Optimize.Optimized_shrink_resources)
}
var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8",
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 1acac1b..4d6dbff 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -262,6 +262,20 @@
if !isApexSystemServerJar {
return true
}
+ ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider)
+ allApexInfos := []android.ApexInfo{}
+ if allApexInfosProvider, ok := android.ModuleProvider(ctx, android.AllApexInfoProvider); ok {
+ allApexInfos = allApexInfosProvider.ApexInfos
+ }
+ if len(allApexInfos) > 0 && !ai.MinSdkVersion.EqualTo(allApexInfos[0].MinSdkVersion) {
+ // Apex system server jars are dexpreopted and installed on to the system image.
+ // Since we can have BigAndroid and Go variants of system server jar providing apexes,
+ // and these two variants can have different min_sdk_versions, hide one of the apex variants
+ // from make to prevent collisions.
+ //
+ // Unlike cc, min_sdk_version does not have an effect on the build actions of java libraries.
+ ctx.Module().MakeUninstallable()
+ }
} else {
// Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
if isApexSystemServerJar {
@@ -502,7 +516,7 @@
// Prebuilts are active, do not copy the dexpreopt'd source javalib to out/soong/system_server_dexjars
// The javalib from the deapexed prebuilt will be copied to this location.
// TODO (b/331665856): Implement a principled solution for this.
- copyApexSystemServerJarDex := !disableSourceApexVariant(ctx)
+ copyApexSystemServerJarDex := !disableSourceApexVariant(ctx) && !ctx.Module().IsHideFromMake()
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(
ctx, globalSoong, global, dexpreoptConfig, appProductPackages, copyApexSystemServerJarDex)
if err != nil {
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 330013e..6229797 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -198,13 +198,22 @@
hiddenApiFixtureFactory,
tc.preparer,
prepareForTestWithDefaultPlatformBootclasspath,
+ // Make sure that we have atleast one platform library so that we can check the monolithic hiddenapi
+ // file creation.
+ FixtureConfigureBootJars("platform:foo"),
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild)
variables.BuildFlags = map[string]string{
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
}
}),
- ).RunTest(t)
+ ).RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+ `)
hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common")
hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags")
diff --git a/java/java.go b/java/java.go
index fc7e5c5..e3f4824 100644
--- a/java/java.go
+++ b/java/java.go
@@ -366,25 +366,14 @@
toolchain bool
static bool
+
+ installable bool
}
-var _ android.SkipToTransitiveDepsTag = (*dependencyTag)(nil)
+var _ android.InstallNeededDependencyTag = (*dependencyTag)(nil)
-func (depTag dependencyTag) SkipToTransitiveDeps() bool {
- // jni_libs are not installed because they are always embedded into the app. However,
- // transitive deps of jni_libs themselves should be installed along with the app.
- if IsJniDepTag(depTag) {
- return true
- }
- return false
-}
-
-// installDependencyTag is a dependency tag that is annotated to cause the installed files of the
-// dependency to be installed when the parent module is installed.
-type installDependencyTag struct {
- blueprint.BaseDependencyTag
- android.InstallAlwaysNeededDependencyTag
- name string
+func (d dependencyTag) InstallDepNeeded() bool {
+ return d.installable
}
func (d dependencyTag) LicenseAnnotations() []android.LicenseAnnotation {
@@ -416,7 +405,7 @@
}
func IsJniDepTag(depTag blueprint.DependencyTag) bool {
- return depTag == jniLibTag
+ return depTag == jniLibTag || depTag == jniInstallTag
}
var (
@@ -445,8 +434,8 @@
javaApiContributionTag = dependencyTag{name: "java-api-contribution"}
depApiSrcsTag = dependencyTag{name: "dep-api-srcs"}
aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"}
- jniInstallTag = installDependencyTag{name: "jni install"}
- binaryInstallTag = installDependencyTag{name: "binary install"}
+ jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true}
+ binaryInstallTag = dependencyTag{name: "binary install", runtimeLinked: true, installable: true}
usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false)
usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true)
usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true)
@@ -502,6 +491,7 @@
coverageFile android.OptionalPath
unstrippedFile android.Path
partition string
+ installPaths android.InstallPaths
}
func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, d dexer) {
@@ -919,7 +909,7 @@
// Check min_sdk_version of the transitive dependencies if this module is created from
// java_sdk_library.
- if j.deviceProperties.Min_sdk_version != nil && j.SdkLibraryName() != nil {
+ if j.overridableProperties.Min_sdk_version != nil && j.SdkLibraryName() != nil {
j.CheckDepsMinSdkVersion(ctx)
}
@@ -1107,7 +1097,7 @@
// If the min_sdk_version was set then add the canonical representation of the API level to the
// snapshot.
- if j.deviceProperties.Min_sdk_version != nil {
+ if j.overridableProperties.Min_sdk_version != nil {
canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String())
if err != nil {
ctx.ModuleErrorf("%s", err)
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index b3c9ce5..8d4cf68 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -294,6 +294,15 @@
// generateHiddenAPIBuildActions generates all the hidden API related build rules.
func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule {
+ createEmptyHiddenApiFiles := func() {
+ paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
+ for _, path := range paths {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Touch,
+ Output: path,
+ })
+ }
+ }
// Save the paths to the monolithic files for retrieval via OutputFiles().
b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags
@@ -306,13 +315,7 @@
// optimization that can be used to reduce the incremental build time but as its name suggests it
// can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath.
if ctx.Config().DisableHiddenApiChecks() {
- paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV}
- for _, path := range paths {
- ctx.Build(pctx, android.BuildParams{
- Rule: android.Touch,
- Output: path,
- })
- }
+ createEmptyHiddenApiFiles()
return bootDexJarByModule
}
@@ -325,6 +328,13 @@
// the fragments will have already provided the flags that are needed.
classesJars := monolithicInfo.ClassesJars
+ if len(classesJars) == 0 {
+ // This product does not include any monolithic jars. Monolithic hiddenapi flag generation is not required.
+ // However, generate an empty file so that the dist tags in f/b/boot/Android.bp can be resolved, and `m dist` works.
+ createEmptyHiddenApiFiles()
+ return bootDexJarByModule
+ }
+
// Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile
input := newHiddenAPIFlagInput()
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 677b32a..645f513 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1650,6 +1650,14 @@
module.dexpreopter.configPath = module.implLibraryModule.dexpreopter.configPath
module.dexpreopter.outputProfilePathOnHost = module.implLibraryModule.dexpreopter.outputProfilePathOnHost
+ // Properties required for Library.AndroidMkEntries
+ module.logtagsSrcs = module.implLibraryModule.logtagsSrcs
+ module.dexpreopter.builtInstalled = module.implLibraryModule.dexpreopter.builtInstalled
+ module.jacocoReportClassesFile = module.implLibraryModule.jacocoReportClassesFile
+ module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary
+ module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip
+ module.linter.reports = module.implLibraryModule.linter.reports
+
if !module.Host() {
module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile
}
@@ -1814,7 +1822,6 @@
props := struct {
Name *string
Visibility []string
- Instrument bool
Libs []string
Static_libs []string
Apex_available []string
@@ -1822,8 +1829,6 @@
}{
Name: proptools.StringPtr(module.implLibraryModuleName()),
Visibility: visibility,
- // Set the instrument property to ensure it is instrumented when instrumentation is required.
- Instrument: true,
Libs: append(module.properties.Libs, module.sdkLibraryProperties.Impl_only_libs...),
@@ -1842,6 +1847,7 @@
&module.dexProperties,
&module.dexpreoptProperties,
&module.linter.properties,
+ &module.overridableProperties,
&props,
module.sdkComponentPropertiesForChildLibrary(),
}
diff --git a/rust/builder.go b/rust/builder.go
index 4f45e33..1ce92f4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,6 +21,7 @@
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/cc"
"android/soong/rust/config"
)
@@ -118,42 +119,129 @@
func init() {
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
+ cc.TransformRlibstoStaticlib = TransformRlibstoStaticlib
+}
+
+type transformProperties struct {
+ crateName string
+ targetTriple string
+ is64Bit bool
+ bootstrap bool
+ inRecovery bool
+ inRamdisk bool
+ inVendorRamdisk bool
+ cargoOutDir android.OptionalPath
+ synthetic bool
+ crateType string
+}
+
+// Populates a standard transformProperties struct for Rust modules
+func getTransformProperties(ctx ModuleContext, crateType string) transformProperties {
+ module := ctx.RustModule()
+ return transformProperties{
+ crateName: module.CrateName(),
+ is64Bit: ctx.toolchain().Is64Bit(),
+ targetTriple: ctx.toolchain().RustTriple(),
+ bootstrap: module.Bootstrap(),
+ inRecovery: module.InRecovery(),
+ inRamdisk: module.InRamdisk(),
+ inVendorRamdisk: module.InVendorRamdisk(),
+ cargoOutDir: module.compiler.cargoOutDir(),
+
+ // crateType indicates what type of crate to build
+ crateType: crateType,
+
+ // synthetic indicates whether this is an actual Rust module or not
+ synthetic: false,
+ }
}
func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ if ctx.RustModule().compiler.Thinlto() {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ }
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin")
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "bin"))
}
func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib")
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib"))
+}
+
+func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep,
+ outputFile android.WritablePath) android.Path {
+
+ var rustPathDeps PathDeps
+ var rustFlags Flags
+
+ for _, rlibDep := range deps {
+ rustPathDeps.RLibs = append(rustPathDeps.RLibs, RustLibrary{Path: rlibDep.LibPath, CrateName: rlibDep.CrateName})
+ rustPathDeps.linkDirs = append(rustPathDeps.linkDirs, rlibDep.LinkDirs...)
+ }
+
+ ccModule := ctx.(cc.ModuleContext).Module().(*cc.Module)
+ toolchain := config.FindToolchain(ctx.Os(), ctx.Arch())
+ t := transformProperties{
+ // Crate name can be a predefined value as this is a staticlib and
+ // it does not need to be unique. The crate name is used for name
+ // mangling, but it is mixed with the metadata for that purpose, which we
+ // already set to the module name.
+ crateName: "generated_rust_staticlib",
+ is64Bit: toolchain.Is64Bit(),
+ targetTriple: toolchain.RustTriple(),
+ bootstrap: ccModule.Bootstrap(),
+ inRecovery: ccModule.InRecovery(),
+ inRamdisk: ccModule.InRamdisk(),
+ inVendorRamdisk: ccModule.InVendorRamdisk(),
+
+ // crateType indicates what type of crate to build
+ crateType: "staticlib",
+
+ // synthetic indicates whether this is an actual Rust module or not
+ synthetic: true,
+ }
+
+ rustFlags = CommonDefaultFlags(ctx, toolchain, rustFlags)
+ rustFlags = CommonLibraryCompilerFlags(ctx, rustFlags)
+ rustFlags.GlobalRustFlags = append(rustFlags.GlobalRustFlags, "-C lto=thin")
+
+ rustFlags.EmitXrefs = false
+
+ return transformSrctoCrate(ctx, mainSrc, rustPathDeps, rustFlags, outputFile, t).outputFile
}
func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ if ctx.RustModule().compiler.Thinlto() {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ }
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib")
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "dylib"))
}
func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib")
+ if ctx.RustModule().compiler.Thinlto() {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ }
+
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "staticlib"))
}
func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
outputFile android.WritablePath) buildOutput {
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib")
+ if ctx.RustModule().compiler.Thinlto() {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, "-C lto=thin")
+ }
+
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "cdylib"))
}
func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
flags Flags, outputFile android.WritablePath) buildOutput {
- return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro")
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "proc-macro"))
}
func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -185,18 +273,18 @@
return libFlags
}
-func rustEnvVars(ctx ModuleContext, deps PathDeps) []string {
+func rustEnvVars(ctx android.ModuleContext, deps PathDeps, crateName string, cargoOutDir android.OptionalPath) []string {
var envVars []string
// libstd requires a specific environment variable to be set. This is
// not officially documented and may be removed in the future. See
// https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866.
- if ctx.RustModule().CrateName() == "std" {
- envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.RustModule().Arch().ArchType])
+ if crateName == "std" {
+ envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.Arch().ArchType])
}
- if len(deps.SrcDeps) > 0 {
- moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
+ if len(deps.SrcDeps) > 0 && cargoOutDir.Valid() {
+ moduleGenDir := cargoOutDir
// We must calculate an absolute path for OUT_DIR since Rust's include! macro (which normally consumes this)
// assumes that paths are relative to the source file.
var outDirPrefix string
@@ -215,13 +303,15 @@
envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx))
- if ctx.RustModule().compiler.cargoEnvCompat() {
- if bin, ok := ctx.RustModule().compiler.(*binaryDecorator); ok {
+ if rustMod, ok := ctx.Module().(*Module); ok && rustMod.compiler.cargoEnvCompat() {
+ // We only emulate cargo environment variables for 3p code, which is only ever built
+ // by defining a Rust module, so we only need to set these for true Rust modules.
+ if bin, ok := rustMod.compiler.(*binaryDecorator); ok {
envVars = append(envVars, "CARGO_BIN_NAME="+bin.getStem(ctx))
}
- envVars = append(envVars, "CARGO_CRATE_NAME="+ctx.RustModule().CrateName())
- envVars = append(envVars, "CARGO_PKG_NAME="+ctx.RustModule().CrateName())
- pkgVersion := ctx.RustModule().compiler.cargoPkgVersion()
+ envVars = append(envVars, "CARGO_CRATE_NAME="+crateName)
+ envVars = append(envVars, "CARGO_PKG_NAME="+crateName)
+ pkgVersion := rustMod.compiler.cargoPkgVersion()
if pkgVersion != "" {
envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion)
@@ -245,8 +335,8 @@
return envVars
}
-func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crateType string) buildOutput {
+func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, t transformProperties) buildOutput {
var inputs android.Paths
var implicits android.Paths
@@ -256,23 +346,21 @@
var earlyLinkFlags string
output.outputFile = outputFile
- crateName := ctx.RustModule().CrateName()
- targetTriple := ctx.toolchain().RustTriple()
- envVars := rustEnvVars(ctx, deps)
+ envVars := rustEnvVars(ctx, deps, t.crateName, t.cargoOutDir)
inputs = append(inputs, main)
// Collect rustc flags
rustcFlags = append(rustcFlags, flags.GlobalRustFlags...)
rustcFlags = append(rustcFlags, flags.RustFlags...)
- rustcFlags = append(rustcFlags, "--crate-type="+crateType)
- if crateName != "" {
- rustcFlags = append(rustcFlags, "--crate-name="+crateName)
+ rustcFlags = append(rustcFlags, "--crate-type="+t.crateType)
+ if t.crateName != "" {
+ rustcFlags = append(rustcFlags, "--crate-name="+t.crateName)
}
- if targetTriple != "" {
- rustcFlags = append(rustcFlags, "--target="+targetTriple)
- linkFlags = append(linkFlags, "-target "+targetTriple)
+ if t.targetTriple != "" {
+ rustcFlags = append(rustcFlags, "--target="+t.targetTriple)
+ linkFlags = append(linkFlags, "-target "+t.targetTriple)
}
// Suppress an implicit sysroot
@@ -302,9 +390,9 @@
linkFlags = append(linkFlags, flags.LinkFlags...)
// Check if this module needs to use the bootstrap linker
- if ctx.RustModule().Bootstrap() && !ctx.RustModule().InRecovery() && !ctx.RustModule().InRamdisk() && !ctx.RustModule().InVendorRamdisk() {
+ if t.bootstrap && !t.inRecovery && !t.inRamdisk && !t.inVendorRamdisk {
dynamicLinker := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker"
- if ctx.toolchain().Is64Bit() {
+ if t.is64Bit {
dynamicLinker += "64"
}
linkFlags = append(linkFlags, dynamicLinker)
@@ -326,49 +414,56 @@
orderOnly = append(orderOnly, deps.SharedLibs...)
- if len(deps.SrcDeps) > 0 {
- moduleGenDir := ctx.RustModule().compiler.cargoOutDir()
- var outputs android.WritablePaths
+ if !t.synthetic {
+ // Only worry about OUT_DIR for actual Rust modules.
+ // Libraries built from cc use generated source, and do not utilize OUT_DIR.
+ if len(deps.SrcDeps) > 0 {
+ var outputs android.WritablePaths
- for _, genSrc := range deps.SrcDeps {
- if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) {
- ctx.PropertyErrorf("srcs",
- "multiple source providers generate the same filename output: "+genSrc.Base())
+ for _, genSrc := range deps.SrcDeps {
+ if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) {
+ ctx.PropertyErrorf("srcs",
+ "multiple source providers generate the same filename output: "+genSrc.Base())
+ }
+ outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base()))
}
- outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base()))
- }
- ctx.Build(pctx, android.BuildParams{
- Rule: cp,
- Description: "cp " + moduleGenDir.Path().Rel(),
- Outputs: outputs,
- Inputs: deps.SrcDeps,
- Args: map[string]string{
- "outDir": moduleGenDir.String(),
- },
- })
- implicits = append(implicits, outputs.Paths()...)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: cp,
+ Description: "cp " + t.cargoOutDir.Path().Rel(),
+ Outputs: outputs,
+ Inputs: deps.SrcDeps,
+ Args: map[string]string{
+ "outDir": t.cargoOutDir.String(),
+ },
+ })
+ implicits = append(implicits, outputs.Paths()...)
+ }
}
- if flags.Clippy {
- clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
- ctx.Build(pctx, android.BuildParams{
- Rule: clippyDriver,
- Description: "clippy " + main.Rel(),
- Output: clippyFile,
- ImplicitOutputs: nil,
- Inputs: inputs,
- Implicits: implicits,
- OrderOnly: orderOnly,
- Args: map[string]string{
- "rustcFlags": strings.Join(rustcFlags, " "),
- "libFlags": strings.Join(libFlags, " "),
- "clippyFlags": strings.Join(flags.ClippyFlags, " "),
- "envVars": strings.Join(envVars, " "),
- },
- })
- // Declare the clippy build as an implicit dependency of the original crate.
- implicits = append(implicits, clippyFile)
+ if !t.synthetic {
+ // Only worry about clippy for actual Rust modules.
+ // Libraries built from cc use generated source, and don't need to run clippy.
+ if flags.Clippy {
+ clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: clippyDriver,
+ Description: "clippy " + main.Rel(),
+ Output: clippyFile,
+ ImplicitOutputs: nil,
+ Inputs: inputs,
+ Implicits: implicits,
+ OrderOnly: orderOnly,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "clippyFlags": strings.Join(flags.ClippyFlags, " "),
+ "envVars": strings.Join(envVars, " "),
+ },
+ })
+ // Declare the clippy build as an implicit dependency of the original crate.
+ implicits = append(implicits, clippyFile)
+ }
}
ctx.Build(pctx, android.BuildParams{
@@ -389,25 +484,28 @@
},
})
- if flags.EmitXrefs {
- kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
- ctx.Build(pctx, android.BuildParams{
- Rule: kytheExtract,
- Description: "Xref Rust extractor " + main.Rel(),
- Output: kytheFile,
- Inputs: inputs,
- Implicits: implicits,
- OrderOnly: orderOnly,
- Args: map[string]string{
- "rustcFlags": strings.Join(rustcFlags, " "),
- "linkFlags": strings.Join(linkFlags, " "),
- "libFlags": strings.Join(libFlags, " "),
- "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
- "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
- "envVars": strings.Join(envVars, " "),
- },
- })
- output.kytheFile = kytheFile
+ if !t.synthetic {
+ // Only emit xrefs for true Rust modules.
+ if flags.EmitXrefs {
+ kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: kytheExtract,
+ Description: "Xref Rust extractor " + main.Rel(),
+ Output: kytheFile,
+ Inputs: inputs,
+ Implicits: implicits,
+ OrderOnly: orderOnly,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "linkFlags": strings.Join(linkFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "),
+ "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "),
+ "envVars": strings.Join(envVars, " "),
+ },
+ })
+ output.kytheFile = kytheFile
+ }
}
return output
}
@@ -457,7 +555,7 @@
Args: map[string]string{
"rustdocFlags": strings.Join(rustdocFlags, " "),
"outDir": docDir.String(),
- "envVars": strings.Join(rustEnvVars(ctx, deps), " "),
+ "envVars": strings.Join(rustEnvVars(ctx, deps, crateName, ctx.RustModule().compiler.cargoOutDir()), " "),
},
})
diff --git a/rust/builder_test.go b/rust/builder_test.go
index 639f6d4..c093ac4 100644
--- a/rust/builder_test.go
+++ b/rust/builder_test.go
@@ -46,6 +46,9 @@
}
func TestCompilationOutputFiles(t *testing.T) {
+
+ // Note: Rustdoc output is produced for the PrimaryModule, so if the variant
+ // order changes, then it may be produced for a different variant.
ctx := testRust(t, `
rust_library {
name: "libfizz_buzz",
@@ -126,6 +129,16 @@
},
},
{
+ testName: "rust_ffi rlib",
+ moduleName: "librust_ffi",
+ variant: "android_arm64_armv8-a_rlib_rlib-std",
+ expectedFiles: []string{
+ "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/librust_ffi.rlib",
+ "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/librust_ffi.rlib.clippy",
+ "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_rlib_rlib-std/meta_lic",
+ },
+ },
+ {
testName: "rust_ffi shared",
moduleName: "librust_ffi",
variant: "android_arm64_armv8-a_shared",
diff --git a/rust/compiler.go b/rust/compiler.go
index 03fdf2b..efc3dee 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -47,6 +47,7 @@
edition() string
features() []string
rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
+ Thinlto() bool
// Output directory in which source-generated code from dependencies is
// copied. This is equivalent to Cargo's OUT_DIR variable.
@@ -231,6 +232,15 @@
// If cargo_env_compat is true, sets the CARGO_PKG_VERSION env var to this value.
Cargo_pkg_version *string
+
+ // Control whether LTO is used for the final (Rust) linkage. This does not impact
+ // cross-language LTO.
+ Lto struct {
+ // Whether thin LTO should be enabled. By default this is true.
+ // LTO provides such a large code size benefit for Rust, this should always
+ // be enabled for production builds unless there's a clear need to disable it.
+ Thin *bool `android:"arch_variant"`
+ } `android:"arch_variant"`
}
type baseCompiler struct {
@@ -273,6 +283,11 @@
return false
}
+// Thin LTO is enabled by default.
+func (compiler *baseCompiler) Thinlto() bool {
+ return BoolDefault(compiler.Properties.Lto.Thin, true)
+}
+
func (compiler *baseCompiler) SetDisabled() {
panic("baseCompiler does not implement SetDisabled()")
}
@@ -322,9 +337,9 @@
return []interface{}{&compiler.Properties}
}
-func (compiler *baseCompiler) cfgsToFlags() []string {
+func cfgsToFlags(cfgs []string) []string {
flags := []string{}
- for _, cfg := range compiler.Properties.Cfgs {
+ for _, cfg := range cfgs {
flags = append(flags, "--cfg '"+cfg+"'")
}
@@ -351,23 +366,61 @@
return flags
}
-func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
- if ctx.RustModule().InVendorOrProduct() {
- compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vndk")
- if ctx.RustModule().InVendor() {
- compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_vendor")
- } else if ctx.RustModule().InProduct() {
- compiler.Properties.Cfgs = append(compiler.Properties.Cfgs, "android_product")
+func CommonDefaultCfgFlags(flags Flags, vendor bool, product bool) Flags {
+ var cfgs []string
+ if vendor || product {
+ cfgs = append(cfgs, "android_vndk")
+ if vendor {
+ cfgs = append(cfgs, "android_vendor")
+ } else if product {
+ cfgs = append(cfgs, "android_product")
}
}
- flags.RustFlags = append(flags.RustFlags, compiler.cfgsToFlags()...)
- flags.RustdocFlags = append(flags.RustdocFlags, compiler.cfgsToFlags()...)
+ flags.RustFlags = append(flags.RustFlags, cfgsToFlags(cfgs)...)
+ flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(cfgs)...)
+ return flags
+}
+
+func (compiler *baseCompiler) cfgFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = CommonDefaultCfgFlags(flags, ctx.RustModule().InVendor(), ctx.RustModule().InProduct())
+
+ flags.RustFlags = append(flags.RustFlags, cfgsToFlags(compiler.Properties.Cfgs)...)
+ flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(compiler.Properties.Cfgs)...)
+
+ return flags
+}
+
+func CommonDefaultFlags(ctx android.ModuleContext, toolchain config.Toolchain, flags Flags) Flags {
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
+ flags.GlobalRustFlags = append(flags.GlobalRustFlags, toolchain.ToolchainRustFlags())
+ flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, toolchain.ToolchainLinkFlags())
+ flags.EmitXrefs = ctx.Config().EmitXrefRules()
+
+ if ctx.Host() && !ctx.Windows() {
+ flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
+ }
+
+ if ctx.Os() == android.Linux {
+ // Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
+ // the default behavior of device builds.
+ flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
+ } else if ctx.Os() == android.Darwin {
+ // Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
+ // behavior of device builds.
+ flags.LinkFlags = append(flags.LinkFlags,
+ "-lc",
+ "-ldl",
+ "-lpthread",
+ "-lm",
+ )
+ }
return flags
}
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
+ flags = CommonDefaultFlags(ctx, ctx.toolchain(), flags)
lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints)
if err != nil {
ctx.PropertyErrorf("lints", err.Error())
@@ -396,29 +449,7 @@
flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.RustdocFlags = append(flags.RustdocFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
- flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
- flags.GlobalLinkFlags = append(flags.GlobalLinkFlags, ctx.toolchain().ToolchainLinkFlags())
- flags.EmitXrefs = ctx.Config().EmitXrefRules()
- if ctx.Host() && !ctx.Windows() {
- flags.LinkFlags = append(flags.LinkFlags, cc.RpathFlags(ctx)...)
- }
-
- if ctx.Os() == android.Linux {
- // Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match
- // the default behavior of device builds.
- flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...)
- } else if ctx.Os() == android.Darwin {
- // Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default
- // behavior of device builds.
- flags.LinkFlags = append(flags.LinkFlags,
- "-lc",
- "-ldl",
- "-lpthread",
- "-lm",
- )
- }
return flags
}
@@ -568,11 +599,11 @@
compiler.installDeps = append(compiler.installDeps, installedData...)
}
-func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
+func (compiler *baseCompiler) getStem(ctx android.ModuleContext) string {
return compiler.getStemWithoutSuffix(ctx) + String(compiler.Properties.Suffix)
}
-func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
+func (compiler *baseCompiler) getStemWithoutSuffix(ctx android.BaseModuleContext) string {
stem := ctx.ModuleName()
if String(compiler.Properties.Stem) != "" {
stem = String(compiler.Properties.Stem)
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 89f4d1a..4caa12b 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -63,6 +63,35 @@
}
}
+func TestLtoFlag(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ lto: {
+ thin: false,
+ }
+ }
+
+ rust_library_host {
+ name: "libfoo_lto",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ `)
+
+ libfoo := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
+ libfooLto := ctx.ModuleForTests("libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc")
+
+ if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") {
+ t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"])
+ }
+ if !strings.Contains(libfooLto.Args["rustcFlags"], "-C lto=thin") {
+ t.Fatalf("libfoo expected to enable lto by default -- rustcFlags: %#v", libfooLto.Args["rustcFlags"])
+ }
+}
+
// Test that we reject multiple source files.
func TestEnforceSingleSourceFile(t *testing.T) {
diff --git a/rust/coverage.go b/rust/coverage.go
index 91a7806..e0e919c 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -47,7 +47,7 @@
// no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency.
if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() {
- ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}, rlibDepTag, ProfilerBuiltins)
+ ctx.AddVariationDependencies([]blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}, rlibDepTag, ProfilerBuiltins)
}
}
diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go
index ee28c6d..0d4622a 100644
--- a/rust/fuzz_test.go
+++ b/rust/fuzz_test.go
@@ -120,13 +120,17 @@
}
cc_fuzz {
name: "fuzz_static_libtest",
+ static_rlibs: ["libtest_fuzzing"],
+ }
+ cc_fuzz {
+ name: "fuzz_staticffi_libtest",
static_libs: ["libtest_fuzzing"],
}
-
`)
fuzz_shared_libtest := ctx.ModuleForTests("fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
fuzz_static_libtest := ctx.ModuleForTests("fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
+ fuzz_staticffi_libtest := ctx.ModuleForTests("fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface)
if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String())
@@ -134,4 +138,7 @@
if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String())
}
+ if !strings.Contains(fuzz_staticffi_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") {
+ t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_rlib ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String())
+ }
}
diff --git a/rust/image_test.go b/rust/image_test.go
index ba94906..71e271c 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -22,33 +22,45 @@
"android/soong/cc"
)
-// Test that cc modules can link against vendor_available rust_ffi_static libraries.
+// Test that cc modules can link against vendor_available rust_ffi_rlib/rust_ffi_static libraries.
func TestVendorLinkage(t *testing.T) {
ctx := testRust(t, `
cc_binary {
- name: "fizz_vendor",
- static_libs: ["libfoo_vendor"],
+ name: "fizz_vendor_available",
+ static_libs: ["libfoo_vendor_static"],
+ static_rlibs: ["libfoo_vendor"],
+ vendor_available: true,
+ }
+ cc_binary {
+ name: "fizz_soc_specific",
+ static_rlibs: ["libfoo_vendor"],
soc_specific: true,
}
- rust_ffi_static {
+ rust_ffi_rlib {
name: "libfoo_vendor",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_available: true,
}
+ rust_ffi_static {
+ name: "libfoo_vendor_static",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor_available: true,
+ }
`)
- vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
+ vendorBinary := ctx.ModuleForTests("fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module)
- if !android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
- t.Errorf("vendorBinary should have a dependency on libfoo_vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
+ if !android.InList("libfoo_vendor_static.vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("vendorBinary should have a dependency on libfoo_vendor_static.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs)
}
}
// Test that variants which use the vndk emit the appropriate cfg flag.
func TestImageCfgFlag(t *testing.T) {
ctx := testRust(t, `
- rust_ffi_static {
+ rust_ffi_shared {
name: "libfoo",
crate_name: "foo",
srcs: ["foo.rs"],
@@ -57,7 +69,7 @@
}
`)
- vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_static").Rule("rustc")
+ vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Rule("rustc")
if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
@@ -69,7 +81,7 @@
t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
}
- product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_static").Rule("rustc")
+ product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_shared").Rule("rustc")
if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
}
@@ -80,7 +92,7 @@
t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"])
}
- system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Rule("rustc")
+ system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("rustc")
if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") {
t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"])
}
@@ -93,27 +105,34 @@
}
-// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
+// Test that cc modules can link against vendor_ramdisk_available rust_ffi_rlib and rust_ffi_static libraries.
func TestVendorRamdiskLinkage(t *testing.T) {
ctx := testRust(t, `
- cc_library_static {
+ cc_library_shared {
name: "libcc_vendor_ramdisk",
- static_libs: ["libfoo_vendor_ramdisk"],
+ static_rlibs: ["libfoo_vendor_ramdisk"],
+ static_libs: ["libfoo_static_vendor_ramdisk"],
system_shared_libs: [],
vendor_ramdisk_available: true,
}
- rust_ffi_static {
+ rust_ffi_rlib {
name: "libfoo_vendor_ramdisk",
crate_name: "foo",
srcs: ["foo.rs"],
vendor_ramdisk_available: true,
}
+ rust_ffi_static {
+ name: "libfoo_static_vendor_ramdisk",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ vendor_ramdisk_available: true,
+ }
`)
- vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_static").Module().(*cc.Module)
+ vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module)
- if !android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
- t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_vendor_ramdisk")
+ if !android.InList("libfoo_static_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
+ t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_static_vendor_ramdisk")
}
}
diff --git a/rust/library.go b/rust/library.go
index f58a54f..1eb0c5e 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -37,10 +37,15 @@
android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
android.RegisterModuleType("rust_ffi", RustFFIFactory)
android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
- android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
- android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
+ android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
+
+ // TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib
+ // Alias rust_ffi_static to the combined rust_ffi_rlib factory
+ android.RegisterModuleType("rust_ffi_static", RustFFIStaticRlibFactory)
+ android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticRlibHostFactory)
}
type VariantLibraryProperties struct {
@@ -104,6 +109,8 @@
includeDirs android.Paths
sourceProvider SourceProvider
+ isFFI bool
+
// table-of-contents file for cdylib crates to optimize out relinking when possible
tocFile android.OptionalPath
}
@@ -143,6 +150,8 @@
BuildOnlyShared()
toc() android.OptionalPath
+
+ isFFILibrary() bool
}
func (library *libraryDecorator) nativeCoverage() bool {
@@ -250,7 +259,7 @@
}
func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage {
- if library.static() || library.MutatedProperties.VariantIsStaticStd {
+ if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) {
return RlibLinkage
} else if library.baseCompiler.preferRlib() {
return RlibLinkage
@@ -270,8 +279,8 @@
return module.Init()
}
-// rust_ffi produces all FFI variants (rust_ffi_shared and
-// rust_ffi_static).
+// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and
+// rust_ffi_rlib).
func RustFFIFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyFFI()
@@ -300,14 +309,6 @@
return module.Init()
}
-// rust_ffi_static produces a static library (Rust crate type
-// "staticlib").
-func RustFFIStaticFactory() android.Module {
- module, library := NewRustLibrary(android.HostAndDeviceSupported)
- library.BuildOnlyStatic()
- return module.Init()
-}
-
// rust_library_host produces all Rust variants for the host
// (rust_library_dylib_host and rust_library_rlib_host).
func RustLibraryHostFactory() android.Module {
@@ -317,7 +318,7 @@
}
// rust_ffi_host produces all FFI variants for the host
-// (rust_ffi_static_host and rust_ffi_shared_host).
+// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host).
func RustFFIHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyFFI()
@@ -340,14 +341,6 @@
return module.Init()
}
-// rust_ffi_static_host produces a static library for the host (Rust
-// crate type "staticlib").
-func RustFFIStaticHostFactory() android.Module {
- module, library := NewRustLibrary(android.HostSupported)
- library.BuildOnlyStatic()
- return module.Init()
-}
-
// rust_ffi_shared_host produces an shared library for the host (Rust
// crate type "cdylib").
func RustFFISharedHostFactory() android.Module {
@@ -356,11 +349,51 @@
return module.Init()
}
+// rust_ffi_rlib_host produces an rlib for the host (Rust crate
+// type "rlib").
+func RustFFIRlibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRlibStatic()
+
+ library.isFFI = true
+ return module.Init()
+}
+
+// rust_ffi_rlib produces an rlib (Rust crate type "rlib").
+func RustFFIRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlib()
+
+ library.isFFI = true
+ return module.Init()
+}
+
+// rust_ffi_static produces a staticlib and an rlib variant
+func RustFFIStaticRlibFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRlibStatic()
+
+ library.isFFI = true
+ return module.Init()
+}
+
+// rust_ffi_static_host produces a staticlib and an rlib variant for the host
+func RustFFIStaticRlibHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRlibStatic()
+
+ library.isFFI = true
+ return module.Init()
+}
+
func (library *libraryDecorator) BuildOnlyFFI() {
library.MutatedProperties.BuildDylib = false
- library.MutatedProperties.BuildRlib = false
+ // we build rlibs for later static ffi linkage.
+ library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = true
library.MutatedProperties.BuildStatic = true
+
+ library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyRust() {
@@ -384,11 +417,21 @@
library.MutatedProperties.BuildStatic = false
}
+func (library *libraryDecorator) BuildOnlyRlibStatic() {
+ library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildRlib = true
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = true
+ library.isFFI = true
+}
+
func (library *libraryDecorator) BuildOnlyStatic() {
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = true
+
+ library.isFFI = true
}
func (library *libraryDecorator) BuildOnlyShared() {
@@ -396,6 +439,12 @@
library.MutatedProperties.BuildDylib = false
library.MutatedProperties.BuildStatic = false
library.MutatedProperties.BuildShared = true
+
+ library.isFFI = true
+}
+
+func (library *libraryDecorator) isFFILibrary() bool {
+ return library.isFFI
}
func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
@@ -446,8 +495,15 @@
return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
}
+// Library cfg flags common to all variants
+func CommonLibraryCfgFlags(ctx android.ModuleContext, flags Flags) Flags {
+ return flags
+}
+
func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags {
flags = library.baseCompiler.cfgFlags(ctx, flags)
+ flags = CommonLibraryCfgFlags(ctx, flags)
+
if library.dylib() {
// We need to add a dependency on std in order to link crates as dylibs.
// The hack to add this dependency is guarded by the following cfg so
@@ -455,8 +511,15 @@
library.baseCompiler.Properties.Cfgs = append(library.baseCompiler.Properties.Cfgs, "android_dylib")
}
- flags.RustFlags = append(flags.RustFlags, library.baseCompiler.cfgsToFlags()...)
- flags.RustdocFlags = append(flags.RustdocFlags, library.baseCompiler.cfgsToFlags()...)
+ flags.RustFlags = append(flags.RustFlags, cfgsToFlags(library.baseCompiler.Properties.Cfgs)...)
+ flags.RustdocFlags = append(flags.RustdocFlags, cfgsToFlags(library.baseCompiler.Properties.Cfgs)...)
+
+ return flags
+}
+
+// Common flags applied to all libraries irrespective of properties or variant should be included here
+func CommonLibraryCompilerFlags(ctx android.ModuleContext, flags Flags) Flags {
+ flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
return flags
}
@@ -464,11 +527,13 @@
func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = library.baseCompiler.compilerFlags(ctx, flags)
- flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
- if library.shared() || library.static() {
+ flags = CommonLibraryCompilerFlags(ctx, flags)
+
+ if library.isFFI {
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...)
}
+
if library.shared() {
if ctx.Darwin() {
flags.LinkFlags = append(
@@ -494,6 +559,9 @@
deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...)
}
+ // Ensure link dirs are not duplicated
+ deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs)
+
// Calculate output filename
if library.rlib() {
fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
@@ -549,9 +617,10 @@
library.flagExporter.exportLinkObjects(deps.linkObjects...)
}
- if library.static() || library.shared() {
+ // Since we have FFI rlibs, we need to collect their includes as well
+ if library.static() || library.shared() || library.rlib() {
android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{
- IncludeDirs: library.includeDirs,
+ IncludeDirs: android.FirstUniquePaths(library.includeDirs),
})
}
@@ -666,6 +735,11 @@
return
}
+ // Don't produce rlib/dylib/source variants for shared or static variants
+ if library.shared() || library.static() {
+ return
+ }
+
var variants []string
// The source variant is used for SourceProvider modules. The other variants (i.e. rlib and dylib)
// depend on this variant. It must be the first variant to be declared.
@@ -705,6 +779,9 @@
// The source variant does not produce any library.
// Disable the compilation steps.
v.(*Module).compiler.SetDisabled()
+ case "":
+ // if there's an empty variant, alias it so it is the default variant
+ mctx.AliasVariation("")
}
}
@@ -729,20 +806,29 @@
case libraryInterface:
// Only create a variant if a library is actually being built.
if library.rlib() && !library.sysroot() {
- variants := []string{"rlib-std", "dylib-std"}
- modules := mctx.CreateLocalVariations(variants...)
+ // If this is a rust_ffi variant it only needs rlib-std
+ if library.isFFILibrary() {
+ variants := []string{"rlib-std"}
+ modules := mctx.CreateLocalVariations(variants...)
+ rlib := modules[0].(*Module)
+ rlib.compiler.(libraryInterface).setRlibStd()
+ rlib.Properties.RustSubName += RlibStdlibSuffix
+ } else {
+ variants := []string{"rlib-std", "dylib-std"}
+ modules := mctx.CreateLocalVariations(variants...)
- rlib := modules[0].(*Module)
- dylib := modules[1].(*Module)
- rlib.compiler.(libraryInterface).setRlibStd()
- dylib.compiler.(libraryInterface).setDylibStd()
- if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
- // TODO(b/165791368)
- // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
- // variants are properly supported.
- dylib.Disable()
+ rlib := modules[0].(*Module)
+ dylib := modules[1].(*Module)
+ rlib.compiler.(libraryInterface).setRlibStd()
+ dylib.compiler.(libraryInterface).setDylibStd()
+ if dylib.ModuleBase.ImageVariation().Variation == android.VendorRamdiskVariation {
+ // TODO(b/165791368)
+ // Disable rlibs that link against dylib-std on vendor ramdisk variations until those dylib
+ // variants are properly supported.
+ dylib.Disable()
+ }
+ rlib.Properties.RustSubName += RlibStdlibSuffix
}
- rlib.Properties.RustSubName += RlibStdlibSuffix
}
}
}
diff --git a/rust/library_test.go b/rust/library_test.go
index 7275b66..1133c28 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,9 +37,10 @@
}`)
// Test all variants are being built.
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc")
- libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Rule("rustc")
+ libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc")
rlibCrateType := "rlib"
@@ -62,6 +63,11 @@
t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", staticCrateType, libfooStatic.Args["rustcFlags"])
}
+ // Test crate type for FFI rlibs is correct
+ if !strings.Contains(libfooFFIRlib.Args["rustcFlags"], "crate-type="+rlibCrateType) {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", rlibCrateType, libfooFFIRlib.Args["rustcFlags"])
+ }
+
// Test crate type for C shared libraries is correct.
if !strings.Contains(libfooShared.Args["rustcFlags"], "crate-type="+sharedCrateType) {
t.Errorf("missing crate-type for shared variant, expecting %#v, got rustcFlags: %#v", sharedCrateType, libfooShared.Args["rustcFlags"])
@@ -182,15 +188,20 @@
func TestStaticLibraryLinkage(t *testing.T) {
ctx := testRust(t, `
- rust_ffi_static {
+ rust_ffi {
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
}`)
- libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std")
+ libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("Static libstd rlib expected to be a dependency of Rust rlib libraries. Rlib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+ }
+ if !android.InList("libstd", libfooStatic.Module().(*Module).Properties.AndroidMkRlibs) {
t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
libfoo.Module().(*Module).Properties.AndroidMkDylibs)
}
@@ -198,6 +209,12 @@
func TestNativeDependencyOfRlib(t *testing.T) {
ctx := testRust(t, `
+ rust_ffi_rlib {
+ name: "libffi_rlib",
+ crate_name: "ffi_rlib",
+ rlibs: ["librust_rlib"],
+ srcs: ["foo.rs"],
+ }
rust_ffi_static {
name: "libffi_static",
crate_name: "ffi_static",
@@ -224,10 +241,12 @@
rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std")
rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std")
ffiStatic := ctx.ModuleForTests("libffi_static", "android_arm64_armv8-a_static")
+ ffiRlib := ctx.ModuleForTests("libffi_rlib", "android_arm64_armv8-a_rlib_rlib-std")
modules := []android.TestingModule{
rustRlibRlibStd,
rustRlibDylibStd,
+ ffiRlib,
ffiStatic,
}
@@ -290,27 +309,28 @@
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
+ libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std")
libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
- for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
+ for _, static := range []android.TestingModule{libfooRlib, libfooStatic, libfooFFIRlib} {
if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("libbar not present as rlib dependency in static lib")
+ t.Errorf("libbar not present as rlib dependency in static lib: %s", static.Module().Name())
}
if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
- t.Errorf("libbar present as dynamic dependency in static lib")
+ t.Errorf("libbar present as dynamic dependency in static lib: %s", static.Module().Name())
}
}
for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
- t.Errorf("libbar not present as dynamic dependency in dynamic lib")
+ t.Errorf("libbar not present as dynamic dependency in dynamic lib: %s", dyn.Module().Name())
}
if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("libbar present as rlib dependency in dynamic lib")
+ t.Errorf("libbar present as rlib dependency in dynamic lib: %s", dyn.Module().Name())
}
if !android.InList("librlib_only", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
- t.Errorf("librlib_only should be selected by rustlibs as an rlib.")
+ t.Errorf("librlib_only should be selected by rustlibs as an rlib: %s.", dyn.Module().Name())
}
}
}
@@ -375,6 +395,7 @@
libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module)
libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module)
+ libbarFFIRlib := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module)
// prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here.
libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module)
@@ -398,6 +419,12 @@
if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) {
t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant")
}
+ if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_ffi_rlib does not link libstd as an rlib")
+ }
+ if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) {
+ t.Errorf("Device rust_ffi_rlib does not link dependent rustlib rlib-std variant")
+ }
if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) {
t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib")
}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index b491449..1ff6637 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -76,6 +76,7 @@
srcPath := crateRootPath(ctx, procMacro)
ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile)
procMacro.baseCompiler.unstrippedOutputFile = outputFile
+
return ret
}
diff --git a/rust/rust.go b/rust/rust.go
index e4bb99c..93853e5 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -158,6 +158,8 @@
sourceProvider SourceProvider
subAndroidMkOnce map[SubAndroidMkProvider]bool
+ exportedLinkDirs []string
+
// Output file to be installed, may be stripped or unstripped.
outputFile android.OptionalPath
@@ -231,8 +233,8 @@
func (mod *Module) NonCcVariants() bool {
if mod.compiler != nil {
- if _, ok := mod.compiler.(libraryInterface); ok {
- return false
+ if library, ok := mod.compiler.(libraryInterface); ok {
+ return library.buildRlib() || library.buildDylib()
}
}
panic(fmt.Errorf("NonCcVariants called on non-library module: %q", mod.BaseModuleName()))
@@ -462,6 +464,11 @@
linkDirs []string
linkObjects []string
+ // exportedLinkDirs are exported linkDirs for direct rlib dependencies to
+ // cc_library_static dependants of rlibs.
+ // Track them separately from linkDirs so superfluous -L flags don't get emitted.
+ exportedLinkDirs []string
+
// Used by bindgen modules which call clang
depClangFlags []string
depIncludePaths android.Paths
@@ -474,6 +481,9 @@
// Paths to generated source files
SrcDeps android.Paths
srcProviderFiles android.Paths
+
+ // Used by Generated Libraries
+ depExportedRlibs []cc.RustRlibDep
}
type RustLibraries []RustLibrary
@@ -540,6 +550,10 @@
return mod.Properties.VndkVersion
}
+func (mod *Module) ExportedCrateLinkDirs() []string {
+ return mod.exportedLinkDirs
+}
+
func (mod *Module) PreventInstall() bool {
return mod.Properties.PreventInstall
}
@@ -654,15 +668,6 @@
return nil
}
-func (mod *Module) IncludeDirs() android.Paths {
- if mod.compiler != nil {
- if library, ok := mod.compiler.(*libraryDecorator); ok {
- return library.includeDirs
- }
- }
- panic(fmt.Errorf("IncludeDirs called on non-library module: %q", mod.BaseModuleName()))
-}
-
func (mod *Module) SetStatic() {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
@@ -911,6 +916,10 @@
}
deps := mod.depsToPaths(ctx)
+ // Export linkDirs for CC rust generatedlibs
+ mod.exportedLinkDirs = append(mod.exportedLinkDirs, deps.exportedLinkDirs...)
+ mod.exportedLinkDirs = append(mod.exportedLinkDirs, deps.linkDirs...)
+
flags := Flags{
Toolchain: toolchain,
}
@@ -988,6 +997,9 @@
if ctx.Failed() {
return
}
+ // Export your own directory as a linkDir
+ mod.exportedLinkDirs = append(mod.exportedLinkDirs, linkPathFromFilePath(mod.OutputFile().Path()))
+
}
ctx.Phony("rust", ctx.RustModule().OutputFile().Path())
@@ -1218,7 +1230,7 @@
return
}
- if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
+ if rustDep, ok := dep.(*Module); ok && !rustDep.Static() && !rustDep.Shared() {
//Handle Rust Modules
makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName)
@@ -1244,9 +1256,16 @@
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName)
mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName))
+ // rust_ffi rlibs may export include dirs, so collect those here.
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider)
+ depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
+ depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
+
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName)
+ // proc_macro link dirs need to be exported, so collect those here.
+ depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path()))
case sourceDepTag:
if _, ok := mod.sourceProvider.(*protobufDecorator); ok {
@@ -1276,12 +1295,12 @@
directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep)
}
+ exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
//Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
if depTag != procMacroDepTag {
- exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider)
- depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...)
depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...)
+ depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...)
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -1291,6 +1310,7 @@
lib.exportLinkDirs(linkDir)
}
}
+
if depTag == sourceDepTag {
if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() {
if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok {
@@ -1555,6 +1575,7 @@
}
rlibDepVariations := commonDepVariations
+ rlibDepVariations = append(rlibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() {
rlibDepVariations = append(rlibDepVariations,
@@ -1570,6 +1591,8 @@
// dylibs
dylibDepVariations := append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: dylibVariation})
+ dylibDepVariations = append(dylibDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
+
for _, lib := range deps.Dylibs {
actx.AddVariationDependencies(dylibDepVariations, dylibDepTag, lib)
}
@@ -1589,7 +1612,7 @@
// otherwise select the rlib variant.
autoDepVariations := append(commonDepVariations,
blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation})
-
+ autoDepVariations = append(autoDepVariations, blueprint.Variation{Mutator: "link", Variation: ""})
if actx.OtherModuleDependencyVariantExists(autoDepVariations, lib) {
actx.AddVariationDependencies(autoDepVariations, autoDep.depTag, lib)
@@ -1604,7 +1627,11 @@
for _, lib := range deps.Rustlibs {
srcProviderVariations := append(commonDepVariations,
blueprint.Variation{Mutator: "rust_libraries", Variation: "source"})
+ srcProviderVariations = append(srcProviderVariations, blueprint.Variation{Mutator: "link", Variation: ""})
+ // Only add rustlib dependencies if they're source providers themselves.
+ // This is used to track which crate names need to be added to the source generated
+ // in the rust_protobuf mod.rs.
if actx.OtherModuleDependencyVariantExists(srcProviderVariations, lib) {
actx.AddVariationDependencies(srcProviderVariations, sourceDepTag, lib)
}
@@ -1616,7 +1643,7 @@
if deps.Stdlibs != nil {
if mod.compiler.stdLinkage(ctx) == RlibLinkage {
for _, lib := range deps.Stdlibs {
- actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...),
+ actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}, {Mutator: "link", Variation: ""}}...),
rlibDepTag, lib)
}
} else {
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 6d083f6..8b96df8 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -150,15 +150,11 @@
host_supported: true,
name: "cc_stubs_dep",
}
- rust_ffi_host_static {
+ cc_library_host_static {
name: "libstatic",
- srcs: ["foo.rs"],
- crate_name: "static",
}
- rust_ffi_host_static {
+ cc_library_host_static {
name: "libwholestatic",
- srcs: ["foo.rs"],
- crate_name: "wholestatic",
}
rust_ffi_host_shared {
name: "libshared",
@@ -435,6 +431,105 @@
}
}
+func TestRustRlibs(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_rlib {
+ name: "libbar",
+ crate_name: "bar",
+ srcs: ["src/lib.rs"],
+ export_include_dirs: ["bar_includes"]
+ }
+
+ rust_ffi_rlib {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["src/lib.rs"],
+ export_include_dirs: ["foo_includes"]
+ }
+
+ cc_library_shared {
+ name: "libcc_shared",
+ srcs:["foo.c"],
+ static_rlibs: ["libbar"],
+ }
+
+ cc_library_static {
+ name: "libcc_static",
+ srcs:["foo.c"],
+ static_rlibs: ["libfoo"],
+ }
+
+ cc_binary {
+ name: "ccBin",
+ srcs:["foo.c"],
+ static_rlibs: ["libbar"],
+ static_libs: ["libcc_static"],
+ }
+ `)
+
+ libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc")
+ libcc_shared_rustc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc")
+ libcc_shared_ld := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("ld")
+ libcc_shared_cc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("cc")
+ ccbin_rustc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("rustc")
+ ccbin_ld := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("ld")
+ ccbin_cc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("cc")
+
+ if !strings.Contains(libbar.Args["rustcFlags"], "crate-type=rlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "rlib", libbar.Args["rustcFlags"])
+ }
+
+ // Make sure there's a rustc command, and it's producing a staticlib
+ if !strings.Contains(libcc_shared_rustc.Args["rustcFlags"], "crate-type=staticlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v",
+ "staticlib", libcc_shared_rustc.Args["rustcFlags"])
+ }
+
+ // Make sure the static lib is included in the ld command
+ if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/liblibcc_shared_rust_staticlib.a") {
+ t.Errorf("missing generated static library in linker step libFlags %#v, libFlags: %#v",
+ "libcc_shared.generated_rust_staticlib.a", libcc_shared_ld.Args["libFlags"])
+ }
+
+ // Make sure the static lib includes are in the cc command
+ if !strings.Contains(libcc_shared_cc.Args["cFlags"], "-Ibar_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ibar_includes", libcc_shared_cc.Args["cFlags"])
+ }
+
+ // Make sure there's a rustc command, and it's producing a staticlib
+ if !strings.Contains(ccbin_rustc.Args["rustcFlags"], "crate-type=staticlib") {
+ t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "staticlib", ccbin_rustc.Args["rustcFlags"])
+ }
+
+ // Make sure the static lib is included in the cc command
+ if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/libccBin_rust_staticlib.a") {
+ t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v",
+ "ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"])
+ }
+
+ // Make sure the static lib includes are in the ld command
+ if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ibar_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ibar_includes", ccbin_cc.Args)
+ }
+
+ // Make sure that direct dependencies and indirect dependencies are
+ // propagating correctly to the generated rlib.
+ if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern foo=") {
+ t.Errorf("Missing indirect dependency libfoo when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
+ }
+ if !strings.Contains(ccbin_rustc.Args["libFlags"], "--extern bar=") {
+ t.Errorf("Missing direct dependency libbar when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"])
+ }
+
+ // Test indirect includes propagation
+ if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ifoo_includes") {
+ t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v",
+ "-Ifoo_includes", ccbin_cc.Args)
+ }
+}
+
func assertString(t *testing.T, got, expected string) {
t.Helper()
if got != expected {
diff --git a/rust/testing.go b/rust/testing.go
index 5837dcc..f31c591 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -49,16 +49,28 @@
func GatherRequiredDepsForTest() string {
bp := `
rust_prebuilt_library {
- name: "libstd",
- crate_name: "std",
- rlib: {
- srcs: ["libstd.rlib"],
- },
- dylib: {
- srcs: ["libstd.so"],
- },
- host_supported: true,
- sysroot: true,
+ name: "libstd",
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd/libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd/libstd.so"],
+ },
+ host_supported: true,
+ sysroot: true,
+ }
+ rust_prebuilt_library {
+ name: "libcore.sysroot",
+ crate_name: "core",
+ rlib: {
+ srcs: ["libcore/libcore.rlib"],
+ },
+ dylib: {
+ srcs: ["libcore/libcore.so"],
+ },
+ host_supported: true,
+ sysroot: true,
}
//////////////////////////////
// Device module requirements
@@ -176,10 +188,12 @@
ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory)
ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
- ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ ctx.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory)
+ ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticRlibFactory)
ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
- ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticRlibHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
diff --git a/scripts/extra_install_zips_file_list.py b/scripts/extra_install_zips_file_list.py
index 8ea2a4b..148d6cc 100755
--- a/scripts/extra_install_zips_file_list.py
+++ b/scripts/extra_install_zips_file_list.py
@@ -18,13 +18,16 @@
parser.add_argument('staging_dir',
help='Path to the partition staging directory')
parser.add_argument('extra_install_zips', nargs='*',
- help='The value of EXTRA_INSTALL_ZIPS from make. It should be a list of extraction_dir:zip_file pairs.')
+ help='The value of EXTRA_INSTALL_ZIPS from make. '
+ 'It should be a list of primary_file:extraction_dir:zip_file trios. '
+ 'The primary file will be ignored by this script, you should ensure that '
+ 'the list of trios given to this script is already filtered by relevant primary files.')
args = parser.parse_args()
staging_dir = args.staging_dir.removesuffix('/') + '/'
- for zip_pair in args.extra_install_zips:
- d, z = zip_pair.split(':')
+ for zip_trio in args.extra_install_zips:
+ _, d, z = zip_trio.split(':')
d = d.removesuffix('/') + '/'
if d.startswith(staging_dir):
diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py
index 35d2a1c..58079aa 100755
--- a/scripts/manifest_fixer.py
+++ b/scripts/manifest_fixer.py
@@ -62,8 +62,8 @@
'in the manifest.'))
parser.add_argument('--extract-native-libs', dest='extract_native_libs',
default=None, type=lambda x: (str(x).lower() == 'true'),
- help=('specify if the app wants to use embedded native libraries. Must not '
- 'be true if manifest says false.'))
+ help=('specify if the app wants to use embedded native libraries. Must not conflict '
+ 'if already declared in the manifest.'))
parser.add_argument('--has-no-code', dest='has_no_code', action='store_true',
help=('adds hasCode="false" attribute to application. Ignored if application elem '
'already has a hasCode attribute.'))
@@ -299,16 +299,7 @@
attr = doc.createAttributeNS(android_ns, 'android:extractNativeLibs')
attr.value = value
application.setAttributeNode(attr)
- elif attr.value == "false" and value == "true":
- # Note that we don't disallow the case of extractNativeLibs="true" in manifest and
- # --extract-native-libs="false". This is fine because --extract-native-libs="false" means that
- # the build system didn't compress the JNI libs, which is a fine choice for built-in apps. At
- # runtime the JNI libs will be extracted to outside of the APK, but everything will still work
- # okay.
- #
- # The opposite (extractNativeLibs="false" && --extract-native-libs="true") should however be
- # disallowed because otherwise that would make an ill-formed APK; JNI libs are stored compressed
- # but they won't be extracted. There's no way to execute the JNI libs.
+ elif attr.value != value:
raise RuntimeError('existing attribute extractNativeLibs="%s" conflicts with --extract-native-libs="%s"' %
(attr.value, value))
diff --git a/scripts/manifest_fixer_test.py b/scripts/manifest_fixer_test.py
index 9fce6b9..0a62b10 100755
--- a/scripts/manifest_fixer_test.py
+++ b/scripts/manifest_fixer_test.py
@@ -479,8 +479,8 @@
self.assert_xml_equal(output, expected)
def test_conflict(self):
- manifest_input = self.manifest_tmpl % self.extract_native_libs('false')
- self.assertRaises(RuntimeError, self.run_test, manifest_input, True)
+ manifest_input = self.manifest_tmpl % self.extract_native_libs('true')
+ self.assertRaises(RuntimeError, self.run_test, manifest_input, False)
class AddNoCodeApplicationTest(unittest.TestCase):
diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go
index 6e25122..7048a15 100644
--- a/sdk/bootclasspath_fragment_sdk_test.go
+++ b/sdk/bootclasspath_fragment_sdk_test.go
@@ -281,6 +281,19 @@
"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
}
}),
+ // Make sure that we have atleast one platform library so that we can check the monolithic hiddenapi
+ // file creation.
+ java.FixtureConfigureBootJars("platform:foo"),
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ fs["platform/Android.bp"] = []byte(`
+ java_library {
+ name: "foo",
+ srcs: ["Test.java"],
+ compile_dex: true,
+ }
+ `)
+ fs["platform/Test.java"] = nil
+ }),
android.FixtureWithRootAndroidBp(sdk+`
apex {