Merge "Add test to TestJavaStableSdkVersion for legacy core platform"
diff --git a/android/bazel.go b/android/bazel.go
index facd116..8341e57 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -212,6 +212,13 @@
"libc_ndk", // http://b/187013218, cc_library_static, depends on //bionic/libm:libm (http://b/183064661)
"libc_malloc_hooks", // http://b/187016307, cc_library, ld.lld: error: undefined symbol: __malloc_hook
+ // There are unexported symbols that don't surface on a shared library build,
+ // from the source static archive
+ // e.g. _Unwind_{GetRegionStart,GetLanguageSpecificData,GetIP,Set{IP,GR},Resume,{Raise,Delete}Exception}, pthread_atfork
+ // ... from: cxa_{personality,exception}.o, system_error.o, wrappers_c_bionic.o
+ // cf. http://b/198403271
+ "libc++",
+
// http://b/186823769: Needs C++ STL support, includes from unconverted standard libraries in //external/libcxx
// c++_static
"libbase_ndk", // http://b/186826477, cc_library, no such target '//build/bazel/platforms/os:darwin' when --platforms //build/bazel/platforms:android_x86 is added
@@ -223,6 +230,8 @@
"libbase", // Requires liblog. http://b/186826479, cc_library, fatal error: 'memory' file not found, from libcxx.
// Also depends on fmtlib.
+ "libfdtrack", // depends on STL
+
"libseccomp_policy", // depends on libbase
"gwp_asan_crash_handler", // cc_library, ld.lld: error: undefined symbol: memset
diff --git a/android/config.go b/android/config.go
index 3e41fbb..993aaa7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1659,6 +1659,20 @@
return ConfiguredJarList{apexes, jars}
}
+// Append a list of (apex, jar) pairs to the list.
+func (l *ConfiguredJarList) AppendList(other ConfiguredJarList) ConfiguredJarList {
+ apexes := make([]string, 0, l.Len()+other.Len())
+ jars := make([]string, 0, l.Len()+other.Len())
+
+ apexes = append(apexes, l.apexes...)
+ jars = append(jars, l.jars...)
+
+ apexes = append(apexes, other.apexes...)
+ jars = append(jars, other.jars...)
+
+ return ConfiguredJarList{apexes, jars}
+}
+
// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len())
diff --git a/android/deapexer.go b/android/deapexer.go
index de3f635..9290481 100644
--- a/android/deapexer.go
+++ b/android/deapexer.go
@@ -73,7 +73,7 @@
// exported file name is the apex relative path, e.g. javalib/core-libart.jar.
//
// See Prebuilt.ApexInfoMutator for more information.
- exports map[string]Path
+ exports map[string]WritablePath
}
// PrebuiltExportPath provides the path, or nil if not available, of a file exported from the
@@ -82,7 +82,7 @@
// The exported file is identified by the apex relative path, e.g. "javalib/core-libart.jar".
//
// See apex/deapexer.go for more information.
-func (i DeapexerInfo) PrebuiltExportPath(apexRelativePath string) Path {
+func (i DeapexerInfo) PrebuiltExportPath(apexRelativePath string) WritablePath {
path := i.exports[apexRelativePath]
return path
}
@@ -95,7 +95,7 @@
// for use with a prebuilt_apex module.
//
// See apex/deapexer.go for more information.
-func NewDeapexerInfo(exports map[string]Path) DeapexerInfo {
+func NewDeapexerInfo(exports map[string]WritablePath) DeapexerInfo {
return DeapexerInfo{
exports: exports,
}
diff --git a/android/mutator.go b/android/mutator.go
index c6b6676..b361c51 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -16,9 +16,7 @@
import (
"android/soong/bazel"
- "fmt"
"reflect"
- "strings"
"sync"
"github.com/google/blueprint"
@@ -519,12 +517,6 @@
name string,
bazelProps bazel.BazelTargetModuleProperties,
attrs interface{}) {
- if strings.HasPrefix(name, bazel.BazelTargetModuleNamePrefix) {
- panic(fmt.Errorf(
- "The %s name prefix is added automatically, do not set it manually: %s",
- bazel.BazelTargetModuleNamePrefix,
- name))
- }
info := bp2buildInfo{
Name: name,
diff --git a/android/paths.go b/android/paths.go
index 763cd7c..2e378ba 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -263,38 +263,56 @@
// OptionalPath is a container that may or may not contain a valid Path.
type OptionalPath struct {
- valid bool
- path Path
+ path Path // nil if invalid.
+ invalidReason string // Not applicable if path != nil. "" if the reason is unknown.
}
// OptionalPathForPath returns an OptionalPath containing the path.
func OptionalPathForPath(path Path) OptionalPath {
- if path == nil {
- return OptionalPath{}
- }
- return OptionalPath{valid: true, path: path}
+ return OptionalPath{path: path}
+}
+
+// InvalidOptionalPath returns an OptionalPath that is invalid with the given reason.
+func InvalidOptionalPath(reason string) OptionalPath {
+
+ return OptionalPath{invalidReason: reason}
}
// Valid returns whether there is a valid path
func (p OptionalPath) Valid() bool {
- return p.valid
+ return p.path != nil
}
// Path returns the Path embedded in this OptionalPath. You must be sure that
// there is a valid path, since this method will panic if there is not.
func (p OptionalPath) Path() Path {
- if !p.valid {
- panic("Requesting an invalid path")
+ if p.path == nil {
+ msg := "Requesting an invalid path"
+ if p.invalidReason != "" {
+ msg += ": " + p.invalidReason
+ }
+ panic(msg)
}
return p.path
}
+// InvalidReason returns the reason that the optional path is invalid, or "" if it is valid.
+func (p OptionalPath) InvalidReason() string {
+ if p.path != nil {
+ return ""
+ }
+ if p.invalidReason == "" {
+ return "unknown"
+ }
+ return p.invalidReason
+}
+
// AsPaths converts the OptionalPath into Paths.
//
// It returns nil if this is not valid, or a single length slice containing the Path embedded in
// this OptionalPath.
func (p OptionalPath) AsPaths() Paths {
- if !p.valid {
+ if p.path == nil {
return nil
}
return Paths{p.path}
@@ -303,7 +321,7 @@
// RelativeToTop returns an OptionalPath with the path that was embedded having been replaced by the
// result of calling Path.RelativeToTop on it.
func (p OptionalPath) RelativeToTop() OptionalPath {
- if !p.valid {
+ if p.path == nil {
return p
}
p.path = p.path.RelativeToTop()
@@ -312,7 +330,7 @@
// String returns the string version of the Path, or "" if it isn't valid.
func (p OptionalPath) String() string {
- if p.valid {
+ if p.path != nil {
return p.path.String()
} else {
return ""
@@ -1077,6 +1095,7 @@
path, err := pathForSource(ctx, pathComponents...)
if err != nil {
reportPathError(ctx, err)
+ // No need to put the error message into the returned path since it has been reported already.
return OptionalPath{}
}
@@ -1091,7 +1110,7 @@
return OptionalPath{}
}
if !exists {
- return OptionalPath{}
+ return InvalidOptionalPath(path.String() + " does not exist")
}
return OptionalPathForPath(path)
}
@@ -1127,6 +1146,7 @@
relDir = srcPath.path
} else {
ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
+ // No need to put the error message into the returned path since it has been reported already.
return OptionalPath{}
}
dir := filepath.Join(p.srcDir, p.path, relDir)
@@ -1140,7 +1160,7 @@
return OptionalPath{}
}
if len(paths) == 0 {
- return OptionalPath{}
+ return InvalidOptionalPath(dir + " does not exist")
}
relPath := Rel(ctx, p.srcDir, paths[0])
return OptionalPathForPath(PathForSource(ctx, relPath))
diff --git a/android/paths_test.go b/android/paths_test.go
index f4e4ce1..3f4625d 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -137,26 +137,35 @@
func TestOptionalPath(t *testing.T) {
var path OptionalPath
- checkInvalidOptionalPath(t, path)
+ checkInvalidOptionalPath(t, path, "unknown")
path = OptionalPathForPath(nil)
- checkInvalidOptionalPath(t, path)
+ checkInvalidOptionalPath(t, path, "unknown")
+
+ path = InvalidOptionalPath("foo")
+ checkInvalidOptionalPath(t, path, "foo")
+
+ path = InvalidOptionalPath("")
+ checkInvalidOptionalPath(t, path, "unknown")
path = OptionalPathForPath(PathForTesting("path"))
checkValidOptionalPath(t, path, "path")
}
-func checkInvalidOptionalPath(t *testing.T, path OptionalPath) {
+func checkInvalidOptionalPath(t *testing.T, path OptionalPath, expectedInvalidReason string) {
t.Helper()
if path.Valid() {
- t.Errorf("Uninitialized OptionalPath should not be valid")
+ t.Errorf("Invalid OptionalPath should not be valid")
+ }
+ if path.InvalidReason() != expectedInvalidReason {
+ t.Errorf("Wrong invalid reason: expected %q, got %q", expectedInvalidReason, path.InvalidReason())
}
if path.String() != "" {
- t.Errorf("Uninitialized OptionalPath String() should return \"\", not %q", path.String())
+ t.Errorf("Invalid OptionalPath String() should return \"\", not %q", path.String())
}
paths := path.AsPaths()
if len(paths) != 0 {
- t.Errorf("Uninitialized OptionalPath AsPaths() should return empty Paths, not %q", paths)
+ t.Errorf("Invalid OptionalPath AsPaths() should return empty Paths, not %q", paths)
}
defer func() {
if r := recover(); r == nil {
@@ -171,6 +180,9 @@
if !path.Valid() {
t.Errorf("Initialized OptionalPath should not be invalid")
}
+ if path.InvalidReason() != "" {
+ t.Errorf("Initialized OptionalPath should not have an invalid reason, got: %q", path.InvalidReason())
+ }
if path.String() != expectedString {
t.Errorf("Initialized OptionalPath String() should return %q, not %q", expectedString, path.String())
}
diff --git a/android/sdk.go b/android/sdk.go
index 7c26fbf..100f63b 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -22,6 +22,8 @@
"github.com/google/blueprint/proptools"
)
+// RequiredSdks provides access to the set of SDKs required by an APEX and its contents.
+//
// Extracted from SdkAware to make it easier to define custom subsets of the
// SdkAware interface and improve code navigation within the IDE.
//
@@ -30,11 +32,11 @@
// is expected to implement RequiredSdks() by reading its own properties like
// `uses_sdks`.
type RequiredSdks interface {
- // The set of SDKs required by an APEX and its contents.
+ // RequiredSdks returns the set of SDKs required by an APEX and its contents.
RequiredSdks() SdkRefs
}
-// Provided to improve code navigation with the IDE.
+// sdkAwareWithoutModule is provided simply to improve code navigation with the IDE.
type sdkAwareWithoutModule interface {
RequiredSdks
@@ -233,75 +235,85 @@
return false
}
-// Provide support for generating the build rules which will build the snapshot.
+// SnapshotBuilder provides support for generating the build rules which will build the snapshot.
type SnapshotBuilder interface {
- // Copy src to the dest (which is a snapshot relative path) and add the dest
- // to the zip
+ // CopyToSnapshot generates a rule that will copy the src to the dest (which is a snapshot
+ // relative path) and add the dest to the zip.
CopyToSnapshot(src Path, dest string)
- // Return the path to an empty file.
+ // EmptyFile returns the path to an empty file.
//
// This can be used by sdk member types that need to create an empty file in the snapshot, simply
// pass the value returned from this to the CopyToSnapshot() method.
EmptyFile() Path
- // Unzip the supplied zip into the snapshot relative directory destDir.
+ // UnzipToSnapshot generates a rule that will unzip the supplied zip into the snapshot relative
+ // directory destDir.
UnzipToSnapshot(zipPath Path, destDir string)
- // Add a new prebuilt module to the snapshot. The returned module
- // must be populated with the module type specific properties. The following
- // properties will be automatically populated.
+ // AddPrebuiltModule adds a new prebuilt module to the snapshot.
+ //
+ // It is intended to be called from SdkMemberType.AddPrebuiltModule which can add module type
+ // specific properties that are not variant specific. The following properties will be
+ // automatically populated before returning.
//
// * name
// * sdk_member_name
// * prefer
//
- // This will result in two Soong modules being generated in the Android. One
- // that is versioned, coupled to the snapshot version and marked as
- // prefer=true. And one that is not versioned, not marked as prefer=true and
- // will only be used if the equivalently named non-prebuilt module is not
- // present.
+ // Properties that are variant specific will be handled by SdkMemberProperties structure.
+ //
+ // Each module created by this method can be output to the generated Android.bp file in two
+ // different forms, depending on the setting of the SOONG_SDK_SNAPSHOT_VERSION build property.
+ // The two forms are:
+ // 1. A versioned Soong module that is referenced from a corresponding similarly versioned
+ // snapshot module.
+ // 2. An unversioned Soong module that.
+ //
+ // See sdk/update.go for more information.
AddPrebuiltModule(member SdkMember, moduleType string) BpModule
- // The property tag to use when adding a property to a BpModule that contains
- // references to other sdk members. Using this will ensure that the reference
- // is correctly output for both versioned and unversioned prebuilts in the
- // snapshot.
+ // SdkMemberReferencePropertyTag returns a property tag to use when adding a property to a
+ // BpModule that contains references to other sdk members.
//
- // "required: true" means that the property must only contain references
- // to other members of the sdk. Passing a reference to a module that is not a
- // member of the sdk will result in a build error.
+ // Using this will ensure that the reference is correctly output for both versioned and
+ // unversioned prebuilts in the snapshot.
//
- // "required: false" means that the property can contain references to modules
- // that are either members or not members of the sdk. If a reference is to a
- // module that is a non member then the reference is left unchanged, i.e. it
- // is not transformed as references to members are.
+ // "required: true" means that the property must only contain references to other members of the
+ // sdk. Passing a reference to a module that is not a member of the sdk will result in a build
+ // error.
//
- // The handling of the member names is dependent on whether it is an internal or
- // exported member. An exported member is one whose name is specified in one of
- // the member type specific properties. An internal member is one that is added
- // due to being a part of an exported (or other internal) member and is not itself
- // an exported member.
+ // "required: false" means that the property can contain references to modules that are either
+ // members or not members of the sdk. If a reference is to a module that is a non member then the
+ // reference is left unchanged, i.e. it is not transformed as references to members are.
+ //
+ // The handling of the member names is dependent on whether it is an internal or exported member.
+ // An exported member is one whose name is specified in one of the member type specific
+ // properties. An internal member is one that is added due to being a part of an exported (or
+ // other internal) member and is not itself an exported member.
//
// Member names are handled as follows:
- // * When creating the unversioned form of the module the name is left unchecked
- // unless the member is internal in which case it is transformed into an sdk
- // specific name, i.e. by prefixing with the sdk name.
+ // * When creating the unversioned form of the module the name is left unchecked unless the member
+ // is internal in which case it is transformed into an sdk specific name, i.e. by prefixing with
+ // the sdk name.
//
- // * When creating the versioned form of the module the name is transformed into
- // a versioned sdk specific name, i.e. by prefixing with the sdk name and
- // suffixing with the version.
+ // * When creating the versioned form of the module the name is transformed into a versioned sdk
+ // specific name, i.e. by prefixing with the sdk name and suffixing with the version.
//
// e.g.
// bpPropertySet.AddPropertyWithTag("libs", []string{"member1", "member2"}, builder.SdkMemberReferencePropertyTag(true))
SdkMemberReferencePropertyTag(required bool) BpPropertyTag
}
+// BpPropertyTag is a marker interface that can be associated with properties in a BpPropertySet to
+// provide additional information which can be used to customize their behavior.
type BpPropertyTag interface{}
-// A set of properties for use in a .bp file.
+// BpPropertySet is a set of properties for use in a .bp file.
type BpPropertySet interface {
- // Add a property, the value can be one of the following types:
+ // AddProperty adds a property.
+ //
+ // The value can be one of the following types:
// * string
// * array of the above
// * bool
@@ -326,18 +338,18 @@
// * Otherwise, if a property exists with the name then it is an error.
AddProperty(name string, value interface{})
- // Add a property with an associated tag
+ // AddPropertyWithTag adds a property with an associated property tag.
AddPropertyWithTag(name string, value interface{}, tag BpPropertyTag)
- // Add a property set with the specified name and return so that additional
- // properties can be added.
+ // AddPropertySet adds a property set with the specified name and returns it so that additional
+ // properties can be added to it.
AddPropertySet(name string) BpPropertySet
- // Add comment for property (or property set).
+ // AddCommentForProperty adds a comment for the named property (or property set).
AddCommentForProperty(name, text string)
}
-// A .bp module definition.
+// BpModule represents a module definition in a .bp file.
type BpModule interface {
BpPropertySet
@@ -364,13 +376,14 @@
var _ BpPrintable = BpPrintableBase{}
-// An individual member of the SDK, includes all of the variants that the SDK
-// requires.
+// SdkMember is an individual member of the SDK.
+//
+// It includes all of the variants that the SDK depends upon.
type SdkMember interface {
- // The name of the member.
+ // Name returns the name of the member.
Name() string
- // All the variants required by the SDK.
+ // Variants returns all the variants of this module depended upon by the SDK.
Variants() []SdkAware
}
@@ -418,8 +431,8 @@
return t.export
}
-// Prevent dependencies from the sdk/module_exports onto their members from being
-// replaced with a preferred prebuilt.
+// ReplaceSourceWithPrebuilt prevents dependencies from the sdk/module_exports onto their members
+// from being replaced with a preferred prebuilt.
func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
return false
}
@@ -431,7 +444,7 @@
return &sdkMemberDependencyTag{memberType: memberType, export: export}
}
-// Interface that must be implemented for every type that can be a member of an
+// SdkMemberType is the interface that must be implemented for every type that can be a member of an
// sdk.
//
// The basic implementation should look something like this, where ModuleType is
@@ -452,43 +465,43 @@
// ...methods...
//
type SdkMemberType interface {
- // The name of the member type property on an sdk module.
+ // SdkPropertyName returns the name of the member type property on an sdk module.
SdkPropertyName() string
// RequiresBpProperty returns true if this member type requires its property to be usable within
// an Android.bp file.
RequiresBpProperty() bool
- // True if the member type supports the sdk/sdk_snapshot, false otherwise.
+ // UsableWithSdkAndSdkSnapshot returns true if the member type supports the sdk/sdk_snapshot,
+ // false otherwise.
UsableWithSdkAndSdkSnapshot() bool
- // Return true if prebuilt host artifacts may be specific to the host OS. Only
- // applicable to modules where HostSupported() is true. If this is true,
- // snapshots will list each host OS variant explicitly and disable all other
- // host OS'es.
+ // IsHostOsDependent returns true if prebuilt host artifacts may be specific to the host OS. Only
+ // applicable to modules where HostSupported() is true. If this is true, snapshots will list each
+ // host OS variant explicitly and disable all other host OS'es.
IsHostOsDependent() bool
- // Add dependencies from the SDK module to all the module variants the member
- // type contributes to the SDK. `names` is the list of module names given in
- // the member type property (as returned by SdkPropertyName()) in the SDK
- // module. The exact set of variants required is determined by the SDK and its
- // properties. The dependencies must be added with the supplied tag.
+ // AddDependencies adds dependencies from the SDK module to all the module variants the member
+ // type contributes to the SDK. `names` is the list of module names given in the member type
+ // property (as returned by SdkPropertyName()) in the SDK module. The exact set of variants
+ // required is determined by the SDK and its properties. The dependencies must be added with the
+ // supplied tag.
//
// The BottomUpMutatorContext provided is for the SDK module.
AddDependencies(ctx SdkDependencyContext, dependencyTag blueprint.DependencyTag, names []string)
- // Return true if the supplied module is an instance of this member type.
+ // IsInstance returns true if the supplied module is an instance of this member type.
//
- // This is used to check the type of each variant before added to the
- // SdkMember. Returning false will cause an error to be logged expaining that
- // the module is not allowed in whichever sdk property it was added.
+ // This is used to check the type of each variant before added to the SdkMember. Returning false
+ // will cause an error to be logged explaining that the module is not allowed in whichever sdk
+ // property it was added.
IsInstance(module Module) bool
// UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a
// source module type.
UsesSourceModuleTypeInSnapshot() bool
- // Add a prebuilt module that the sdk will populate.
+ // AddPrebuiltModule is called to add a prebuilt module that the sdk will populate.
//
// The sdk module code generates the snapshot as follows:
//
@@ -525,7 +538,8 @@
//
AddPrebuiltModule(ctx SdkMemberContext, member SdkMember) BpModule
- // Create a structure into which variant specific properties can be added.
+ // CreateVariantPropertiesStruct creates a structure into which variant specific properties can be
+ // added.
CreateVariantPropertiesStruct() SdkMemberProperties
}
@@ -535,7 +549,8 @@
BottomUpMutatorContext
}
-// Base type for SdkMemberType implementations.
+// SdkMemberTypeBase is the base type for SdkMemberType implementations and must be embedded in any
+// struct that implements SdkMemberType.
type SdkMemberTypeBase struct {
PropertyName string
@@ -572,7 +587,7 @@
return b.UseSourceModuleTypeInSnapshot
}
-// Encapsulates the information about registered SdkMemberTypes.
+// SdkMemberTypesRegistry encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
list []SdkMemberType
@@ -610,14 +625,15 @@
return NewCustomOnceKey(r)
}
-// The set of registered SdkMemberTypes for module_exports modules.
+// ModuleExportsMemberTypes is the set of registered SdkMemberTypes for module_exports modules.
var ModuleExportsMemberTypes = &SdkMemberTypesRegistry{}
-// The set of registered SdkMemberTypes for sdk modules.
+// SdkMemberTypes is the set of registered SdkMemberTypes for sdk modules.
var SdkMemberTypes = &SdkMemberTypesRegistry{}
-// Register an SdkMemberType object to allow them to be used in the sdk and sdk_snapshot module
-// types.
+// RegisterSdkMemberType registers an SdkMemberType object to allow them to be used in the
+// module_exports, module_exports_snapshot and (depending on the value returned from
+// SdkMemberType.UsableWithSdkAndSdkSnapshot) the sdk and sdk_snapshot module types.
func RegisterSdkMemberType(memberType SdkMemberType) {
// All member types are usable with module_exports.
ModuleExportsMemberTypes = ModuleExportsMemberTypes.copyAndAppend(memberType)
@@ -628,7 +644,8 @@
}
}
-// Base structure for all implementations of SdkMemberProperties.
+// SdkMemberPropertiesBase is the base structure for all implementations of SdkMemberProperties and
+// must be embedded in any struct that implements SdkMemberProperties.
//
// Contains common properties that apply across many different member types.
type SdkMemberPropertiesBase struct {
@@ -655,7 +672,7 @@
Compile_multilib string `android:"arch_variant"`
}
-// The os prefix to use for any file paths in the sdk.
+// OsPrefix returns the os prefix to use for any file paths in the sdk.
//
// Is an empty string if the member only provides variants for a single os type, otherwise
// is the OsType.Name.
@@ -671,35 +688,47 @@
return b
}
-// Interface to be implemented on top of a structure that contains variant specific
-// information.
+// SdkMemberProperties is the interface to be implemented on top of a structure that contains
+// variant specific information.
//
-// Struct fields that are capitalized are examined for common values to extract. Fields
-// that are not capitalized are assumed to be arch specific.
+// Struct fields that are capitalized are examined for common values to extract. Fields that are not
+// capitalized are assumed to be arch specific.
type SdkMemberProperties interface {
- // Access the base structure.
+ // Base returns the base structure.
Base() *SdkMemberPropertiesBase
- // Populate this structure with information from the variant.
+ // PopulateFromVariant populates this structure with information from a module variant.
+ //
+ // It will typically be called once for each variant of a member module that the SDK depends upon.
PopulateFromVariant(ctx SdkMemberContext, variant Module)
- // Add the information from this structure to the property set.
+ // AddToPropertySet adds the information from this structure to the property set.
+ //
+ // This will be called for each instance of this structure on which the PopulateFromVariant method
+ // was called and also on a number of different instances of this structure into which properties
+ // common to one or more variants have been copied. Therefore, implementations of this must handle
+ // the case when this structure is only partially populated.
AddToPropertySet(ctx SdkMemberContext, propertySet BpPropertySet)
}
-// Provides access to information common to a specific member.
+// SdkMemberContext provides access to information common to a specific member.
type SdkMemberContext interface {
- // The module context of the sdk common os variant which is creating the snapshot.
+ // SdkModuleContext returns the module context of the sdk common os variant which is creating the
+ // snapshot.
+ //
+ // This is common to all members of the sdk and is not specific to the member being processed.
+ // If information about the member being processed needs to be obtained from this ModuleContext it
+ // must be obtained using one of the OtherModule... methods not the Module... methods.
SdkModuleContext() ModuleContext
- // The builder of the snapshot.
+ // SnapshotBuilder the builder of the snapshot.
SnapshotBuilder() SnapshotBuilder
- // The type of the member.
+ // MemberType returns the type of the member currently being processed.
MemberType() SdkMemberType
- // The name of the member.
+ // Name returns the name of the member currently being processed.
//
// Provided for use by sdk members to create a member specific location within the snapshot
// into which to copy the prebuilt files.
diff --git a/android/testing.go b/android/testing.go
index bd2faa2..7a89fc4 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -491,6 +491,66 @@
ctx.preSingletons = append(ctx.preSingletons, newPreSingleton(name, factory))
}
+// ModuleVariantForTests selects a specific variant of the module with the given
+// name by matching the variations map against the variations of each module
+// variant. A module variant matches the map if every variation that exists in
+// both have the same value. Both the module and the map are allowed to have
+// extra variations that the other doesn't have. Panics if not exactly one
+// module variant matches.
+func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[string]string) TestingModule {
+ modules := []Module{}
+ ctx.VisitAllModules(func(m blueprint.Module) {
+ if ctx.ModuleName(m) == name {
+ am := m.(Module)
+ amMut := am.base().commonProperties.DebugMutators
+ amVar := am.base().commonProperties.DebugVariations
+ matched := true
+ for i, mut := range amMut {
+ if wantedVar, found := matchVariations[mut]; found && amVar[i] != wantedVar {
+ matched = false
+ break
+ }
+ }
+ if matched {
+ modules = append(modules, am)
+ }
+ }
+ })
+
+ if len(modules) == 0 {
+ // Show all the modules or module variants that do exist.
+ var allModuleNames []string
+ var allVariants []string
+ ctx.VisitAllModules(func(m blueprint.Module) {
+ allModuleNames = append(allModuleNames, ctx.ModuleName(m))
+ if ctx.ModuleName(m) == name {
+ allVariants = append(allVariants, m.(Module).String())
+ }
+ })
+
+ if len(allVariants) == 0 {
+ panic(fmt.Errorf("failed to find module %q. All modules:\n %s",
+ name, strings.Join(SortedUniqueStrings(allModuleNames), "\n ")))
+ } else {
+ sort.Strings(allVariants)
+ panic(fmt.Errorf("failed to find module %q matching %v. All variants:\n %s",
+ name, matchVariations, strings.Join(allVariants, "\n ")))
+ }
+ }
+
+ if len(modules) > 1 {
+ moduleStrings := []string{}
+ for _, m := range modules {
+ moduleStrings = append(moduleStrings, m.String())
+ }
+ sort.Strings(moduleStrings)
+ panic(fmt.Errorf("module %q has more than one variant that match %v:\n %s",
+ name, matchVariations, strings.Join(moduleStrings, "\n ")))
+ }
+
+ return newTestingModule(ctx.config, modules[0])
+}
+
func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule {
var module Module
ctx.VisitAllModules(func(m blueprint.Module) {
diff --git a/apex/apex.go b/apex/apex.go
index e3edc68..2d153e2 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1569,6 +1569,11 @@
af.jacocoReportClassesFile = module.JacocoReportClassesFile()
af.lintDepSets = module.LintDepSets()
af.customStem = module.Stem() + ".jar"
+ if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
+ for _, install := range dexpreopter.DexpreoptBuiltInstalledForApex() {
+ af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
+ }
+ }
return af
}
diff --git a/apex/deapexer.go b/apex/deapexer.go
index c70da15..2c1835a 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -97,7 +97,7 @@
// Create and remember the directory into which the .apex file's contents will be unpacked.
deapexerOutput := android.PathForModuleOut(ctx, "deapexer")
- exports := make(map[string]android.Path)
+ exports := make(map[string]android.WritablePath)
// Create mappings from apex relative path to the extracted file's path.
exportedPaths := make(android.Paths, 0, len(exports))
diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go
index 513ddc0..d8a4a7a 100644
--- a/apex/platform_bootclasspath_test.go
+++ b/apex/platform_bootclasspath_test.go
@@ -21,6 +21,7 @@
"android/soong/android"
"android/soong/java"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -325,31 +326,15 @@
}
// TestPlatformBootclasspath_AlwaysUsePrebuiltSdks verifies that the build does not fail when
-// AlwaysUsePrebuiltSdk() returns true. The structure of the modules in this test matches what
-// currently exists in some places in the Android build but it is not the intended structure. It is
-// in fact an invalid structure that should cause build failures. However, fixing that structure
-// will take too long so in the meantime this tests the workarounds to avoid build breakages.
-//
-// The main issues with this structure are:
-// 1. There is no prebuilt_bootclasspath_fragment referencing the "foo" java_sdk_library_import.
-// 2. There is no prebuilt_apex/apex_set which makes the dex implementation jar available to the
-// prebuilt_bootclasspath_fragment and the "foo" java_sdk_library_import.
-//
-// Together these cause the following symptoms:
-// 1. The "foo" java_sdk_library_import does not have a dex implementation jar.
-// 2. The "foo" java_sdk_library_import does not have a myapex variant.
-//
-// TODO(b/179354495): Fix the structure in this test once the main Android build has been fixed.
+// AlwaysUsePrebuiltSdk() returns true.
func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) {
result := android.GroupFixturePreparers(
prepareForTestWithPlatformBootclasspath,
prepareForTestWithMyapex,
// Configure two libraries, the first is a java_sdk_library whose prebuilt will be used because
- // of AlwaysUsePrebuiltsSdk() but does not have an appropriate apex variant and does not provide
- // a boot dex jar. The second is a normal library that is unaffected. The order matters because
- // if the dependency on myapex:foo is filtered out because of either of those conditions then
- // the dependencies resolved by the platform_bootclasspath will not match the configured list
- // and so will fail the test.
+ // of AlwaysUsePrebuiltsSdk(). The second is a normal library that is unaffected. The order
+ // matters, so that the dependencies resolved by the platform_bootclasspath matches the
+ // configured list.
java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"),
java.PrepareForTestWithJavaSdkLibraryFiles,
android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
@@ -394,6 +379,12 @@
permitted_packages: ["foo"],
}
+ prebuilt_apex {
+ name: "myapex",
+ src: "myapex.apex",
+ exported_bootclasspath_fragments: ["mybootclasspath-fragment"],
+ }
+
// A prebuilt java_sdk_library_import that is not preferred by default but will be preferred
// because AlwaysUsePrebuiltSdks() is true.
java_sdk_library_import {
@@ -423,6 +414,23 @@
],
}
+ prebuilt_bootclasspath_fragment {
+ name: "mybootclasspath-fragment",
+ apex_available: [
+ "myapex",
+ ],
+ contents: [
+ "foo",
+ ],
+ hidden_api: {
+ stub_flags: "",
+ annotation_flags: "",
+ metadata: "",
+ index: "",
+ all_flags: "",
+ },
+ }
+
platform_bootclasspath {
name: "myplatform-bootclasspath",
fragments: [
@@ -437,7 +445,7 @@
java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{
// The configured contents of BootJars.
- "platform:prebuilt_foo", // Note: This is the platform not myapex variant.
+ "myapex:prebuilt_foo",
"myapex:bar",
})
@@ -456,16 +464,15 @@
// The platform_bootclasspath intentionally adds dependencies on both source and prebuilt
// modules when available as it does not know which one will be preferred.
- //
- // The source module has an APEX variant but the prebuilt does not.
"myapex:foo",
- "platform:prebuilt_foo",
+ "myapex:prebuilt_foo",
// Only a source module exists.
"myapex:bar",
// The fragments.
"myapex:mybootclasspath-fragment",
+ "myapex:prebuilt_mybootclasspath-fragment",
})
}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index c4794dc..4833a64 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -178,13 +178,19 @@
// If the exported java module provides a dex jar path then add it to the list of apexFiles.
path := child.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
if path != nil {
- p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, apexFile{
+ af := apexFile{
module: child,
moduleDir: ctx.OtherModuleDir(child),
androidMkModuleName: name,
builtFile: path,
class: javaSharedLib,
- })
+ }
+ if module, ok := child.(java.DexpreopterInterface); ok {
+ for _, install := range module.DexpreoptBuiltInstalledForApex() {
+ af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
+ }
+ }
+ p.apexFilesForAndroidMk = append(p.apexFilesForAndroidMk, af)
}
} else if tag == exportedBootclasspathFragmentTag {
// Visit the children of the bootclasspath_fragment.
@@ -195,6 +201,14 @@
})
}
+func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) {
+ for _, fi := range p.apexFilesForAndroidMk {
+ entries.AddStrings("LOCAL_REQUIRED_MODULES", fi.requiredModuleNames...)
+ entries.AddStrings("LOCAL_TARGET_REQUIRED_MODULES", fi.targetRequiredModuleNames...)
+ entries.AddStrings("LOCAL_HOST_REQUIRED_MODULES", fi.hostRequiredModuleNames...)
+ }
+}
+
func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := []android.AndroidMkEntries{
{
@@ -213,6 +227,7 @@
if len(postInstallCommands) > 0 {
entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
}
+ p.addRequiredModules(entries)
},
},
},
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
index 131f0ec..d731f3e 100644
--- a/bazel/cquery/request_type.go
+++ b/bazel/cquery/request_type.go
@@ -25,6 +25,7 @@
// be a subset of OutputFiles. (or shared libraries, this will be equal to OutputFiles,
// but general cc_library will also have dynamic libraries in output files).
RootDynamicLibraries []string
+ TocFile string
}
type getOutputFilesRequestType struct{}
@@ -100,14 +101,15 @@
func (g getCcInfoType) StarlarkFunctionBody() string {
return `
outputFiles = [f.path for f in target.files.to_list()]
+cc_info = providers(target)["CcInfo"]
-includes = providers(target)["CcInfo"].compilation_context.includes.to_list()
-system_includes = providers(target)["CcInfo"].compilation_context.system_includes.to_list()
+includes = cc_info.compilation_context.includes.to_list()
+system_includes = cc_info.compilation_context.system_includes.to_list()
ccObjectFiles = []
staticLibraries = []
rootStaticArchives = []
-linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
+linker_inputs = cc_info.linking_context.linker_inputs.to_list()
for linker_input in linker_inputs:
for library in linker_input.libraries:
@@ -120,11 +122,17 @@
rootDynamicLibraries = []
-if "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo" in providers(target):
- shared_info = providers(target)["@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"]
+shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
+if shared_info_tag in providers(target):
+ shared_info = providers(target)[shared_info_tag]
for lib in shared_info.linker_input.libraries:
rootDynamicLibraries += [lib.dynamic_library.path]
+toc_file = ""
+toc_file_tag = "//build/bazel/rules:generate_toc.bzl%CcTocInfo"
+if toc_file_tag in providers(target):
+ toc_file = providers(target)[toc_file_tag].toc.path
+
returns = [
outputFiles,
staticLibraries,
@@ -132,10 +140,10 @@
includes,
system_includes,
rootStaticArchives,
- rootDynamicLibraries
+ rootDynamicLibraries,
]
-return "|".join([", ".join(r) for r in returns])`
+return "|".join([", ".join(r) for r in returns] + [toc_file])`
}
// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
@@ -146,7 +154,7 @@
var ccObjects []string
splitString := strings.Split(rawString, "|")
- if expectedLen := 7; len(splitString) != expectedLen {
+ if expectedLen := 8; len(splitString) != expectedLen {
return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
}
outputFilesString := splitString[0]
@@ -159,6 +167,7 @@
systemIncludes := splitOrEmpty(splitString[4], ", ")
rootStaticArchives := splitOrEmpty(splitString[5], ", ")
rootDynamicLibraries := splitOrEmpty(splitString[6], ", ")
+ tocFile := splitString[7] // NOTE: Will be the empty string if there wasn't
return CcInfo{
OutputFiles: outputFiles,
CcObjectFiles: ccObjects,
@@ -167,6 +176,7 @@
SystemIncludes: systemIncludes,
RootStaticArchives: rootStaticArchives,
RootDynamicLibraries: rootDynamicLibraries,
+ TocFile: tocFile,
}, nil
}
diff --git a/bazel/cquery/request_type_test.go b/bazel/cquery/request_type_test.go
index 49019ab..34d0832 100644
--- a/bazel/cquery/request_type_test.go
+++ b/bazel/cquery/request_type_test.go
@@ -71,7 +71,7 @@
}{
{
description: "no result",
- input: "||||||",
+ input: "|||||||",
expectedOutput: CcInfo{
OutputFiles: []string{},
CcObjectFiles: []string{},
@@ -80,11 +80,12 @@
SystemIncludes: []string{},
RootStaticArchives: []string{},
RootDynamicLibraries: []string{},
+ TocFile: "",
},
},
{
description: "only output",
- input: "test||||||",
+ input: "test|||||||",
expectedOutput: CcInfo{
OutputFiles: []string{"test"},
CcObjectFiles: []string{},
@@ -93,11 +94,12 @@
SystemIncludes: []string{},
RootStaticArchives: []string{},
RootDynamicLibraries: []string{},
+ TocFile: "",
},
},
{
description: "all items set",
- input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1|rootdynamiclibrary1",
+ input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc",
expectedOutput: CcInfo{
OutputFiles: []string{"out1", "out2"},
CcObjectFiles: []string{"object1", "object2"},
@@ -106,19 +108,20 @@
SystemIncludes: []string{"system/dir", "system/other/dir"},
RootStaticArchives: []string{"rootstaticarchive1"},
RootDynamicLibraries: []string{"rootdynamiclibrary1"},
+ TocFile: "lib.so.toc",
},
},
{
description: "too few result splits",
input: "|",
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 7, []string{"", ""}),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, []string{"", ""}),
},
{
description: "too many result splits",
input: strings.Repeat("|", 8),
expectedOutput: CcInfo{},
- expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 7, make([]string, 9)),
+ expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 8, make([]string, 9)),
},
}
for _, tc := range testCases {
diff --git a/bazel/properties.go b/bazel/properties.go
index ed4e9fc..d3b40a2 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -19,7 +19,6 @@
"path/filepath"
"regexp"
"sort"
- "strings"
)
// BazelTargetModuleProperties contain properties and metadata used for
@@ -32,12 +31,6 @@
Bzl_load_location string `blueprint:"mutated"`
}
-const BazelTargetModuleNamePrefix = "__bp2build__"
-
-func StripNamePrefix(moduleName string) string {
- return strings.TrimPrefix(moduleName, BazelTargetModuleNamePrefix)
-}
-
var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
// Label is used to represent a Bazel compatible Label. Also stores the original
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 5ee04f9..40526a6 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -11,7 +11,6 @@
"build_conversion.go",
"bzl_conversion.go",
"configurability.go",
- "compatibility.go",
"constants.go",
"conversion.go",
"metrics.go",
@@ -37,6 +36,7 @@
"cc_library_conversion_test.go",
"cc_library_headers_conversion_test.go",
"cc_library_static_conversion_test.go",
+ "cc_library_shared_conversion_test.go",
"cc_object_conversion_test.go",
"conversion_test.go",
"filegroup_conversion_test.go",
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 48b2945..45a3cb6 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -43,7 +43,7 @@
writeFiles(ctx, bp2buildDir, bp2buildFiles)
soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
- writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(res.compatLayer))
+ writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(res.metrics))
return res.metrics
}
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 10e2329..f7b392b 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -153,10 +153,10 @@
}
type CodegenContext struct {
- config android.Config
- context android.Context
- mode CodegenMode
- additionalDeps []string
+ config android.Config
+ context android.Context
+ mode CodegenMode
+ additionalDeps []string
unconvertedDepMode unconvertedDepsMode
}
@@ -249,7 +249,6 @@
type conversionResults struct {
buildFileToTargets map[string]BazelTargets
metrics CodegenMetrics
- compatLayer CodegenCompatLayer
}
func (r conversionResults) BuildDirToTargets() map[string]BazelTargets {
@@ -265,10 +264,6 @@
RuleClassCount: make(map[string]int),
}
- compatLayer := CodegenCompatLayer{
- NameToLabelMap: make(map[string]string),
- }
-
dirs := make(map[string]bool)
var errs []error
@@ -285,7 +280,7 @@
if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
metrics.handCraftedTargetCount += 1
metrics.TotalModuleCount += 1
- compatLayer.AddNameToLabelEntry(m.Name(), b.HandcraftedLabel())
+ metrics.AddConvertedModule(m.Name())
pathToBuildFile := getBazelPackagePath(b)
// We are using the entire contents of handcrafted build file, so if multiple targets within
// a package have handcrafted targets, we only want to include the contents one time.
@@ -314,10 +309,8 @@
}
targets = generateBazelTargets(bpCtx, aModule)
for _, t := range targets {
- if t.name == m.Name() {
- // only add targets that exist in Soong to compatibility layer
- compatLayer.AddNameToLabelEntry(m.Name(), t.Label())
- }
+ // only add targets that exist in Soong to compatibility layer
+ metrics.AddConvertedModule(m.Name())
metrics.RuleClassCount[t.ruleClass] += 1
}
} else {
@@ -360,7 +353,6 @@
return conversionResults{
buildFileToTargets: buildFileToTargets,
metrics: metrics,
- compatLayer: compatLayer,
}, errs
}
@@ -710,10 +702,6 @@
return strings.Repeat(" ", indent)
}
-func targetNameForBp2Build(c bpToBuildContext, logicModule blueprint.Module) string {
- return strings.Replace(c.ModuleName(logicModule), bazel.BazelTargetModuleNamePrefix, "", 1)
-}
-
func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string {
name := ""
if c.ModuleSubDir(logicModule) != "" {
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
new file mode 100644
index 0000000..52a07cc
--- /dev/null
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -0,0 +1,366 @@
+// Copyright 2021 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package bp2build
+
+import (
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+const (
+ // See cc/testing.go for more context
+ // TODO(alexmarquez): Split out the preamble into common code?
+ soongCcLibrarySharedPreamble = soongCcLibraryStaticPreamble
+)
+
+func registerCcLibrarySharedModuleTypes(ctx android.RegistrationContext) {
+ cc.RegisterCCBuildComponents(ctx)
+ ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+ ctx.RegisterModuleType("cc_library_headers", cc.LibraryHeaderFactory)
+ ctx.RegisterModuleType("cc_library_static", cc.LibraryStaticFactory)
+}
+
+func runCcLibrarySharedTestCase(t *testing.T, tc bp2buildTestCase) {
+ t.Helper()
+ runBp2BuildTestCase(t, registerCcLibrarySharedModuleTypes, tc)
+}
+
+func TestCcLibrarySharedSimple(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared simple overall test",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{
+ // NOTE: include_dir headers *should not* appear in Bazel hdrs later (?)
+ "include_dir_1/include_dir_1_a.h": "",
+ "include_dir_1/include_dir_1_b.h": "",
+ "include_dir_2/include_dir_2_a.h": "",
+ "include_dir_2/include_dir_2_b.h": "",
+ // NOTE: local_include_dir headers *should not* appear in Bazel hdrs later (?)
+ "local_include_dir_1/local_include_dir_1_a.h": "",
+ "local_include_dir_1/local_include_dir_1_b.h": "",
+ "local_include_dir_2/local_include_dir_2_a.h": "",
+ "local_include_dir_2/local_include_dir_2_b.h": "",
+ // NOTE: export_include_dir headers *should* appear in Bazel hdrs later
+ "export_include_dir_1/export_include_dir_1_a.h": "",
+ "export_include_dir_1/export_include_dir_1_b.h": "",
+ "export_include_dir_2/export_include_dir_2_a.h": "",
+ "export_include_dir_2/export_include_dir_2_b.h": "",
+ // NOTE: Soong implicitly includes headers in the current directory
+ "implicit_include_1.h": "",
+ "implicit_include_2.h": "",
+ },
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_headers {
+ name: "header_lib_1",
+ export_include_dirs: ["header_lib_1"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_headers {
+ name: "header_lib_2",
+ export_include_dirs: ["header_lib_2"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_shared {
+ name: "shared_lib_1",
+ srcs: ["shared_lib_1.cc"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_shared {
+ name: "shared_lib_2",
+ srcs: ["shared_lib_2.cc"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_static {
+ name: "whole_static_lib_1",
+ srcs: ["whole_static_lib_1.cc"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_static {
+ name: "whole_static_lib_2",
+ srcs: ["whole_static_lib_2.cc"],
+ bazel_module: { bp2build_available: false },
+}
+
+cc_library_shared {
+ name: "foo_shared",
+ srcs: [
+ "foo_shared1.cc",
+ "foo_shared2.cc",
+ ],
+ cflags: [
+ "-Dflag1",
+ "-Dflag2"
+ ],
+ shared_libs: [
+ "shared_lib_1",
+ "shared_lib_2"
+ ],
+ whole_static_libs: [
+ "whole_static_lib_1",
+ "whole_static_lib_2"
+ ],
+ include_dirs: [
+ "include_dir_1",
+ "include_dir_2",
+ ],
+ local_include_dirs: [
+ "local_include_dir_1",
+ "local_include_dir_2",
+ ],
+ export_include_dirs: [
+ "export_include_dir_1",
+ "export_include_dir_2"
+ ],
+ header_libs: [
+ "header_lib_1",
+ "header_lib_2"
+ ],
+
+ // TODO: Also support export_header_lib_headers
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ absolute_includes = [
+ "include_dir_1",
+ "include_dir_2",
+ ],
+ copts = [
+ "-Dflag1",
+ "-Dflag2",
+ ],
+ dynamic_deps = [
+ ":shared_lib_1",
+ ":shared_lib_2",
+ ],
+ export_includes = [
+ "export_include_dir_1",
+ "export_include_dir_2",
+ ],
+ implementation_deps = [
+ ":header_lib_1",
+ ":header_lib_2",
+ ],
+ local_includes = [
+ "local_include_dir_1",
+ "local_include_dir_2",
+ ".",
+ ],
+ srcs = [
+ "foo_shared1.cc",
+ "foo_shared2.cc",
+ ],
+ whole_archive_deps = [
+ ":whole_static_lib_1",
+ ":whole_static_lib_2",
+ ],
+)`},
+ })
+}
+
+func TestCcLibrarySharedArchSpecificSharedLib(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared arch-specific shared_libs with whole_static_libs",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_static {
+ name: "static_dep",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "shared_dep",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "foo_shared",
+ arch: { arm64: { shared_libs: ["shared_dep"], whole_static_libs: ["static_dep"] } },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ dynamic_deps = select({
+ "//build/bazel/platforms/arch:arm64": [":shared_dep"],
+ "//conditions:default": [],
+ }),
+ whole_archive_deps = select({
+ "//build/bazel/platforms/arch:arm64": [":static_dep"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestCcLibrarySharedOsSpecificSharedLib(t *testing.T) {
+ runCcLibraryStaticTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared os-specific shared_libs",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "shared_dep",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "foo_shared",
+ target: { android: { shared_libs: ["shared_dep"], } },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ dynamic_deps = select({
+ "//build/bazel/platforms/os:android": [":shared_dep"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestCcLibrarySharedBaseArchOsSpecificSharedLib(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared base, arch, and os-specific shared_libs",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "shared_dep",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "shared_dep2",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "shared_dep3",
+ bazel_module: { bp2build_available: false },
+}
+cc_library_shared {
+ name: "foo_shared",
+ shared_libs: ["shared_dep"],
+ target: { android: { shared_libs: ["shared_dep2"] } },
+ arch: { arm64: { shared_libs: ["shared_dep3"] } },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ dynamic_deps = [":shared_dep"] + select({
+ "//build/bazel/platforms/arch:arm64": [":shared_dep3"],
+ "//conditions:default": [],
+ }) + select({
+ "//build/bazel/platforms/os:android": [":shared_dep2"],
+ "//conditions:default": [],
+ }),
+)`},
+ })
+}
+
+func TestCcLibrarySharedSimpleExcludeSrcs(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared simple exclude_srcs",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{
+ "common.c": "",
+ "foo-a.c": "",
+ "foo-excluded.c": "",
+ },
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "foo_shared",
+ srcs: ["common.c", "foo-*.c"],
+ exclude_srcs: ["foo-excluded.c"],
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ srcs_c = [
+ "common.c",
+ "foo-a.c",
+ ],
+)`},
+ })
+}
+
+func TestCcLibrarySharedStrip(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared stripping",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{},
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "foo_shared",
+ strip: {
+ keep_symbols: false,
+ keep_symbols_and_debug_frame: true,
+ keep_symbols_list: ["sym", "sym2"],
+ all: true,
+ none: false,
+ },
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ strip = {
+ "all": True,
+ "keep_symbols": False,
+ "keep_symbols_and_debug_frame": True,
+ "keep_symbols_list": [
+ "sym",
+ "sym2",
+ ],
+ "none": False,
+ },
+)`},
+ })
+}
+
+func TestCcLibrarySharedVersionScript(t *testing.T) {
+ runCcLibrarySharedTestCase(t, bp2buildTestCase{
+ description: "cc_library_shared version script",
+ moduleTypeUnderTest: "cc_library_shared",
+ moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+ moduleTypeUnderTestBp2BuildMutator: cc.CcLibrarySharedBp2Build,
+ filesystem: map[string]string{
+ "version_script": "",
+ },
+ blueprint: soongCcLibrarySharedPreamble + `
+cc_library_shared {
+ name: "foo_shared",
+ version_script: "version_script",
+ include_build_directory: false,
+}`,
+ expectedBazelTargets: []string{`cc_library_shared(
+ name = "foo_shared",
+ version_script = "version_script",
+)`},
+ })
+}
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 72034fa..91b7478 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -202,7 +202,6 @@
":static_lib_1",
":static_lib_2",
],
- linkstatic = True,
local_includes = [
"local_include_dir_1",
"local_include_dir_2",
@@ -251,7 +250,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
absolute_includes = ["subpackage"],
- linkstatic = True,
local_includes = ["."],
)`},
})
@@ -278,7 +276,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
export_includes = ["subpackage"],
- linkstatic = True,
)`},
})
}
@@ -304,7 +301,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
export_system_includes = ["subpackage"],
- linkstatic = True,
)`},
})
}
@@ -347,7 +343,6 @@
"subpackage3/subsubpackage",
],
export_includes = ["./exported_subsubpackage"],
- linkstatic = True,
local_includes = [
"subsubpackage2",
".",
@@ -378,7 +373,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
absolute_includes = ["subpackage"],
- linkstatic = True,
local_includes = ["subpackage2"],
)`},
})
@@ -408,7 +402,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
absolute_includes = ["subpackage"],
- linkstatic = True,
local_includes = [
"subpackage2",
".",
@@ -444,7 +437,6 @@
"//build/bazel/platforms/arch:arm64": [":static_dep"],
"//conditions:default": [],
}),
- linkstatic = True,
whole_archive_deps = select({
"//build/bazel/platforms/arch:arm64": [":static_dep2"],
"//conditions:default": [],
@@ -480,7 +472,6 @@
"//build/bazel/platforms/os:android": [":static_dep"],
"//conditions:default": [],
}),
- linkstatic = True,
whole_archive_deps = select({
"//build/bazel/platforms/os:android": [":static_dep2"],
"//conditions:default": [],
@@ -530,7 +521,6 @@
"//build/bazel/platforms/os:android": [":static_dep3"],
"//conditions:default": [],
}),
- linkstatic = True,
whole_archive_deps = [":static_dep2"],
)`},
})
@@ -556,7 +546,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = [
"common.c",
"foo-a.c",
@@ -584,7 +573,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["foo-arm.c"],
"//conditions:default": [],
@@ -617,7 +605,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-arm.c"],
"//conditions:default": ["not-for-arm.c"],
@@ -652,7 +639,6 @@
} `,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
@@ -703,7 +689,6 @@
} `,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
@@ -763,7 +748,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs = ["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": ["foo-no-arm.cc"],
@@ -797,7 +781,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs = ["common.cc"] + select({
"//build/bazel/platforms/arch:arm": [],
"//build/bazel/platforms/arch:x86": [
@@ -830,7 +813,6 @@
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
implementation_deps = [":static_dep"],
- linkstatic = True,
)`},
})
}
@@ -857,7 +839,6 @@
} `,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": ["for-lib32.c"],
"//build/bazel/platforms/arch:x86": ["for-lib32.c"],
@@ -892,7 +873,6 @@
} `,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static2",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-lib32.c",
@@ -960,7 +940,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static3",
- linkstatic = True,
srcs_c = ["common.c"] + select({
"//build/bazel/platforms/arch:arm": [
"for-arm.c",
@@ -1075,7 +1054,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static3",
- linkstatic = True,
srcs = [
"//dep:generated_hdr_other_pkg",
"//dep:generated_src_other_pkg",
@@ -1131,7 +1109,6 @@
}`,
expectedBazelTargets: []string{`cc_library_static(
name = "foo_static",
- linkstatic = True,
srcs_c = select({
"//build/bazel/platforms/os:android": ["android_src.c"],
"//conditions:default": [],
@@ -1183,7 +1160,6 @@
"//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
"//conditions:default": [],
}),
- linkstatic = True,
srcs_c = ["common.c"],
)`},
})
@@ -1252,7 +1228,6 @@
"//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
"//conditions:default": [],
}),
- linkstatic = True,
srcs_c = ["common.c"],
)`},
})
@@ -1282,7 +1257,6 @@
"//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
}),
- linkstatic = True,
srcs_as = ["common.S"],
)`},
})
@@ -1303,7 +1277,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "root_empty",
- linkstatic = True,
system_dynamic_deps = [],
)`},
})
@@ -1330,7 +1303,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "static_empty",
- linkstatic = True,
system_dynamic_deps = [],
)`},
})
@@ -1355,7 +1327,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "target_bionic_empty",
- linkstatic = True,
system_dynamic_deps = [],
)`},
})
@@ -1384,7 +1355,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "target_linux_bionic_empty",
- linkstatic = True,
system_dynamic_deps = [],
)`},
})
@@ -1411,7 +1381,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "target_bionic",
- linkstatic = True,
system_dynamic_deps = select({
"//build/bazel/platforms/os:bionic": [":libc"],
"//conditions:default": [],
@@ -1443,7 +1412,6 @@
`,
expectedBazelTargets: []string{`cc_library_static(
name = "target_linux_bionic",
- linkstatic = True,
system_dynamic_deps = [":libc"] + select({
"//build/bazel/platforms/os:linux_bionic": [":libm"],
"//conditions:default": [],
diff --git a/bp2build/compatibility.go b/bp2build/compatibility.go
deleted file mode 100644
index 5baa524..0000000
--- a/bp2build/compatibility.go
+++ /dev/null
@@ -1,31 +0,0 @@
-package bp2build
-
-import (
- "android/soong/bazel"
- "fmt"
-)
-
-// Data from the code generation process that is used to improve compatibility
-// between build systems.
-type CodegenCompatLayer struct {
- // A map from the original module name to the generated/handcrafted Bazel
- // label for legacy build systems to be able to build a fully-qualified
- // Bazel target from an unique module name.
- NameToLabelMap map[string]string
-}
-
-// Log an entry of module name -> Bazel target label.
-func (compatLayer CodegenCompatLayer) AddNameToLabelEntry(name, label string) {
- // The module name may be prefixed with bazel.BazelTargetModuleNamePrefix if
- // generated from bp2build.
- name = bazel.StripNamePrefix(name)
- if existingLabel, ok := compatLayer.NameToLabelMap[name]; ok {
- panic(fmt.Errorf(
- "Module '%s' maps to more than one Bazel target label: %s, %s. "+
- "This shouldn't happen. It probably indicates a bug with the bp2build internals.",
- name,
- existingLabel,
- label))
- }
- compatLayer.NameToLabelMap[name] = label
-}
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 75bc2b4..354abf6 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -16,29 +16,19 @@
Contents string
}
-func CreateSoongInjectionFiles(compatLayer CodegenCompatLayer) []BazelFile {
+func CreateSoongInjectionFiles(metrics CodegenMetrics) []BazelFile {
var files []BazelFile
files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
- files = append(files, newFile("module_name_to_label", GeneratedBuildFileName, nameToLabelAliases(compatLayer.NameToLabelMap)))
+ files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
return files
}
-func nameToLabelAliases(nameToLabelMap map[string]string) string {
- ret := make([]string, len(nameToLabelMap))
-
- for k, v := range nameToLabelMap {
- // v is the fully qualified label rooted at '//'
- ret = append(ret, fmt.Sprintf(
- `alias(
- name = "%s",
- actual = "@%s",
-)`, k, v))
- }
- return strings.Join(ret, "\n\n")
+func convertedModules(convertedModules []string) string {
+ return strings.Join(convertedModules, "\n")
}
func CreateBazelFiles(
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 56ea589..dfa1a9e 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -80,7 +80,7 @@
}
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
- files := CreateSoongInjectionFiles(CodegenCompatLayer{})
+ files := CreateSoongInjectionFiles(CodegenMetrics{})
expectedFilePaths := []bazelFilepath{
{
@@ -92,8 +92,8 @@
basename: "constants.bzl",
},
{
- dir: "module_name_to_label",
- basename: GeneratedBuildFileName,
+ dir: "metrics",
+ basename: "converted_modules.txt",
},
}
@@ -107,9 +107,5 @@
if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename {
t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
}
-
- if expectedFile.basename != GeneratedBuildFileName && actualFile.Contents == "" {
- t.Errorf("Contents of %s unexpected empty.", actualFile)
- }
}
}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 645ef2d..55b928b 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -19,6 +19,8 @@
handCraftedTargetCount int
moduleWithUnconvertedDepsMsgs []string
+
+ convertedModules []string
}
// Print the codegen metrics to stdout.
@@ -37,3 +39,9 @@
len(metrics.moduleWithUnconvertedDepsMsgs),
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
}
+
+func (metrics CodegenMetrics) AddConvertedModule(moduleName string) {
+ // Undo prebuilt_ module name prefix modifications
+ moduleName = android.RemoveOptionalPrebuiltPrefix(moduleName)
+ metrics.convertedModules = append(metrics.convertedModules, moduleName)
+}
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 7a98fd0..67ea70e 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -111,24 +111,23 @@
return
}
-// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
-func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes {
+// bp2BuildParseLibProps returns the attributes for a variant of a cc_library.
+func bp2BuildParseLibProps(ctx android.TopDownMutatorContext, module *Module, isStatic bool) staticOrSharedAttributes {
lib, ok := module.compiler.(*libraryDecorator)
if !ok {
return staticOrSharedAttributes{}
}
+ return bp2buildParseStaticOrSharedProps(ctx, module, lib, isStatic)
+}
- return bp2buildParseStaticOrSharedProps(ctx, module, lib, false)
+// bp2buildParseSharedProps returns the attributes for the shared variant of a cc_library.
+func bp2BuildParseSharedProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes {
+ return bp2BuildParseLibProps(ctx, module, false)
}
// bp2buildParseStaticProps returns the attributes for the static variant of a cc_library.
func bp2BuildParseStaticProps(ctx android.TopDownMutatorContext, module *Module) staticOrSharedAttributes {
- lib, ok := module.compiler.(*libraryDecorator)
- if !ok {
- return staticOrSharedAttributes{}
- }
-
- return bp2buildParseStaticOrSharedProps(ctx, module, lib, true)
+ return bp2BuildParseLibProps(ctx, module, true)
}
func bp2buildParseStaticOrSharedProps(ctx android.TopDownMutatorContext, module *Module, lib *libraryDecorator, isStatic bool) staticOrSharedAttributes {
@@ -178,6 +177,7 @@
Src bazel.LabelAttribute
}
+// NOTE: Used outside of Soong repo project, in the clangprebuilts.go bootstrap_go_package
func Bp2BuildParsePrebuiltLibraryProps(ctx android.TopDownMutatorContext, module *Module) prebuiltAttributes {
var srcLabelAttribute bazel.LabelAttribute
diff --git a/cc/builder.go b/cc/builder.go
index b07acf1..4b0a4b6 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -199,8 +199,18 @@
// Rule for invoking clang-tidy (a clang-based linter).
clangTidy, clangTidyRE = pctx.RemoteStaticRules("clangTidy",
blueprint.RuleParams{
- Command: "rm -f $out && $tidyVars $reTemplate${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
- CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
+ Depfile: "${out}.d",
+ Deps: blueprint.DepsGCC,
+ // Pick bash because some machines with old /bin/sh cannot handle arrays.
+ // All $cFlags and $tidyFlags should have single quotes escaped.
+ // Assume no single quotes in other parameters like $in, $out, $ccCmd.
+ Command: "/bin/bash -c 'SRCF=$in; TIDYF=$out; CLANGFLAGS=($cFlags); " +
+ "rm -f $$TIDYF $${TIDYF}.d && " +
+ "${config.CcWrapper}$ccCmd \"$${CLANGFLAGS[@]}\" -E -o /dev/null $$SRCF " +
+ "-MQ $$TIDYF -MD -MF $${TIDYF}.d && " +
+ "$tidyVars $reTemplate${config.ClangBin}/clang-tidy $tidyFlags $$SRCF " +
+ "-- \"$${CLANGFLAGS[@]}\" && touch $$TIDYF'",
+ CommandDeps: []string{"${config.ClangBin}/clang-tidy", "$ccCmd"},
},
&remoteexec.REParams{
Labels: map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"},
@@ -214,7 +224,7 @@
// (1) New timestamps trigger clang and clang-tidy compilations again.
// (2) Changing source files caused concurrent clang or clang-tidy jobs to crash.
Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
- }, []string{"cFlags", "tidyFlags", "tidyVars"}, []string{})
+ }, []string{"ccCmd", "cFlags", "tidyFlags", "tidyVars"}, []string{})
_ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm")
@@ -437,6 +447,12 @@
}
}
+func escapeSingleQuotes(s string) string {
+ // Replace single quotes to work when embedded in a single quoted string for bash.
+ // Relying on string concatenation of bash to get A'B from quoted 'A'\''B'.
+ return strings.Replace(s, `'`, `'\''`, -1)
+}
+
// Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files
func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles android.Paths,
flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects {
@@ -672,14 +688,12 @@
Description: "clang-tidy " + srcFile.Rel(),
Output: tidyFile,
Input: srcFile,
- // We must depend on objFile, since clang-tidy doesn't
- // support exporting dependencies.
- Implicit: objFile,
- Implicits: cFlagsDeps,
- OrderOnly: pathDeps,
+ Implicits: cFlagsDeps,
+ OrderOnly: pathDeps,
Args: map[string]string{
- "cFlags": shareFlags("cFlags", moduleToolingFlags),
- "tidyFlags": shareFlags("tidyFlags", config.TidyFlagsForSrcFile(srcFile, flags.tidyFlags)),
+ "ccCmd": ccCmd,
+ "cFlags": shareFlags("cFlags", escapeSingleQuotes(moduleToolingFlags)),
+ "tidyFlags": shareFlags("tidyFlags", escapeSingleQuotes(config.TidyFlagsForSrcFile(srcFile, flags.tidyFlags))),
"tidyVars": tidyVars, // short and not shared
},
})
diff --git a/cc/library.go b/cc/library.go
index f568247..703d57f 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -205,6 +205,7 @@
RegisterLibraryBuildComponents(android.InitRegistrationContext)
android.RegisterBp2BuildMutator("cc_library_static", CcLibraryStaticBp2Build)
+ android.RegisterBp2BuildMutator("cc_library_shared", CcLibrarySharedBp2Build)
android.RegisterBp2BuildMutator("cc_library", CcLibraryBp2Build)
}
@@ -216,6 +217,7 @@
ctx.RegisterModuleType("cc_library_host_shared", LibraryHostSharedFactory)
}
+// TODO(b/199902614): Can this be factored to share with the other Attributes?
// For bp2build conversion.
type bazelCcLibraryAttributes struct {
// Attributes pertaining to both static and shared variants.
@@ -274,7 +276,7 @@
// converted, but not their shared variants. For these modules, delegate to
// the cc_library_static bp2build converter temporarily instead.
if android.GenerateCcLibraryStaticOnly(ctx) {
- ccLibraryStaticBp2BuildInternal(ctx, m)
+ ccSharedOrStaticBp2BuildMutatorInternal(ctx, m, "cc_library_static")
return
}
@@ -368,6 +370,7 @@
module, library := NewLibrary(android.HostAndDeviceSupported)
library.BuildOnlyShared()
module.sdkMemberTypes = []android.SdkMemberType{sharedLibrarySdkMemberType}
+ module.bazelHandler = &ccLibraryBazelHandler{module: module}
return module.Init()
}
@@ -601,7 +604,10 @@
handler.module.linker.(*libraryDecorator).unstrippedOutputFile = outputFilePath
- tocFile := getTocFile(ctx, label, ccInfo.OutputFiles)
+ var tocFile android.OptionalPath
+ if len(ccInfo.TocFile) > 0 {
+ tocFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, ccInfo.TocFile))
+ }
handler.module.linker.(*libraryDecorator).tocFile = tocFile
ctx.SetProvider(SharedLibraryInfoProvider, SharedLibraryInfo{
@@ -614,25 +620,6 @@
return true
}
-// getTocFile looks for the .so.toc file in the target's output files, if any. The .so.toc file
-// contains the table of contents of all symbols of a shared object.
-func getTocFile(ctx android.ModuleContext, label string, outputFiles []string) android.OptionalPath {
- var tocFile string
- for _, file := range outputFiles {
- if strings.HasSuffix(file, ".so.toc") {
- if tocFile != "" {
- ctx.ModuleErrorf("The %s target cannot produce more than 1 .toc file.", label)
- }
- tocFile = file
- // Don't break to validate that there are no multiple .toc files per .so.
- }
- }
- if tocFile == "" {
- return android.OptionalPath{}
- }
- return android.OptionalPathForPath(android.PathForBazelOut(ctx, tocFile))
-}
-
func (handler *ccLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, ctx.Arch().ArchType)
@@ -2323,6 +2310,123 @@
return outputFile
}
+func ccSharedOrStaticBp2BuildMutator(ctx android.TopDownMutatorContext, modType string) {
+ module, ok := ctx.Module().(*Module)
+ if !ok {
+ // Not a cc module
+ return
+ }
+ if !module.ConvertWithBp2build(ctx) {
+ return
+ }
+ if ctx.ModuleType() != modType {
+ return
+ }
+
+ ccSharedOrStaticBp2BuildMutatorInternal(ctx, module, modType)
+}
+
+func ccSharedOrStaticBp2BuildMutatorInternal(ctx android.TopDownMutatorContext, module *Module, modType string) {
+ if modType != "cc_library_static" && modType != "cc_library_shared" {
+ panic("ccSharedOrStaticBp2BuildMutatorInternal only supports cc_library_{static,shared}")
+ }
+ isStatic := modType == "cc_library_static"
+
+ compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
+ linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
+ exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
+
+ // Append shared/static{} stanza properties. These won't be specified on
+ // cc_library_* itself, but may be specified in cc_defaults that this module
+ // depends on.
+ libSharedOrStaticAttrs := bp2BuildParseLibProps(ctx, module, isStatic)
+
+ compilerAttrs.srcs.Append(libSharedOrStaticAttrs.Srcs)
+ compilerAttrs.cSrcs.Append(libSharedOrStaticAttrs.Srcs_c)
+ compilerAttrs.asSrcs.Append(libSharedOrStaticAttrs.Srcs_as)
+ compilerAttrs.copts.Append(libSharedOrStaticAttrs.Copts)
+ linkerAttrs.exportedDeps.Append(libSharedOrStaticAttrs.Static_deps)
+ linkerAttrs.dynamicDeps.Append(libSharedOrStaticAttrs.Dynamic_deps)
+ linkerAttrs.wholeArchiveDeps.Append(libSharedOrStaticAttrs.Whole_archive_deps)
+ linkerAttrs.systemDynamicDeps.Append(libSharedOrStaticAttrs.System_dynamic_deps)
+
+ asFlags := compilerAttrs.asFlags
+ if compilerAttrs.asSrcs.IsEmpty() {
+ // Skip asflags for BUILD file simplicity if there are no assembly sources.
+ asFlags = bazel.MakeStringListAttribute(nil)
+ }
+
+ var attrs interface{}
+ if isStatic {
+ attrs = &bazelCcLibraryStaticAttributes{
+ Copts: compilerAttrs.copts,
+ Srcs: compilerAttrs.srcs,
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
+
+ Linkopts: linkerAttrs.linkopts,
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
+ Export_includes: exportedIncludes.Includes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+
+ Cppflags: compilerAttrs.cppFlags,
+ Srcs_c: compilerAttrs.cSrcs,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Srcs_as: compilerAttrs.asSrcs,
+ Asflags: asFlags,
+ }
+ } else {
+ attrs = &bazelCcLibrarySharedAttributes{
+ Srcs: compilerAttrs.srcs,
+ Srcs_c: compilerAttrs.cSrcs,
+ Srcs_as: compilerAttrs.asSrcs,
+
+ Implementation_deps: linkerAttrs.deps,
+ Deps: linkerAttrs.exportedDeps,
+ Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
+ Dynamic_deps: linkerAttrs.dynamicDeps,
+ System_dynamic_deps: linkerAttrs.systemDynamicDeps,
+
+ Copts: compilerAttrs.copts,
+ Cppflags: compilerAttrs.cppFlags,
+ Conlyflags: compilerAttrs.conlyFlags,
+ Asflags: asFlags,
+ Linkopts: linkerAttrs.linkopts,
+
+ Use_libcrt: linkerAttrs.useLibcrt,
+ Rtti: compilerAttrs.rtti,
+
+ Export_includes: exportedIncludes.Includes,
+ Export_system_includes: exportedIncludes.SystemIncludes,
+ Local_includes: compilerAttrs.localIncludes,
+ Absolute_includes: compilerAttrs.absoluteIncludes,
+ Version_script: linkerAttrs.versionScript,
+
+ Strip: stripAttributes{
+ Keep_symbols: linkerAttrs.stripKeepSymbols,
+ Keep_symbols_and_debug_frame: linkerAttrs.stripKeepSymbolsAndDebugFrame,
+ Keep_symbols_list: linkerAttrs.stripKeepSymbolsList,
+ All: linkerAttrs.stripAll,
+ None: linkerAttrs.stripNone,
+ },
+ }
+ }
+
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: modType,
+ Bzl_load_location: fmt.Sprintf("//build/bazel/rules:%s.bzl", modType),
+ }
+
+ ctx.CreateBazelTargetModule(module.Name(), props, attrs)
+}
+
+// TODO(b/199902614): Can this be factored to share with the other Attributes?
type bazelCcLibraryStaticAttributes struct {
Copts bazel.StringListAttribute
Srcs bazel.LabelListAttribute
@@ -2332,7 +2436,6 @@
Dynamic_deps bazel.LabelListAttribute
System_dynamic_deps bazel.LabelListAttribute
Linkopts bazel.StringListAttribute
- Linkstatic bool
Use_libcrt bazel.BoolAttribute
Rtti bazel.BoolAttribute
Export_includes bazel.StringListAttribute
@@ -2346,80 +2449,42 @@
Conlyflags bazel.StringListAttribute
Srcs_as bazel.LabelListAttribute
Asflags bazel.StringListAttribute
-
- Static staticOrSharedAttributes
-}
-
-func ccLibraryStaticBp2BuildInternal(ctx android.TopDownMutatorContext, module *Module) {
- compilerAttrs := bp2BuildParseCompilerProps(ctx, module)
- linkerAttrs := bp2BuildParseLinkerProps(ctx, module)
- exportedIncludes := bp2BuildParseExportedIncludes(ctx, module)
-
- asFlags := compilerAttrs.asFlags
- if compilerAttrs.asSrcs.IsEmpty() {
- // Skip asflags for BUILD file simplicity if there are no assembly sources.
- asFlags = bazel.MakeStringListAttribute(nil)
- }
-
- // Append static{} stanza properties. These won't be specified on
- // cc_library_static itself, but may be specified in cc_defaults that this module
- // depends on.
- staticAttrs := bp2BuildParseStaticProps(ctx, module)
-
- compilerAttrs.srcs.Append(staticAttrs.Srcs)
- compilerAttrs.cSrcs.Append(staticAttrs.Srcs_c)
- compilerAttrs.asSrcs.Append(staticAttrs.Srcs_as)
- compilerAttrs.copts.Append(staticAttrs.Copts)
- linkerAttrs.exportedDeps.Append(staticAttrs.Static_deps)
- linkerAttrs.dynamicDeps.Append(staticAttrs.Dynamic_deps)
- linkerAttrs.wholeArchiveDeps.Append(staticAttrs.Whole_archive_deps)
- linkerAttrs.systemDynamicDeps.Append(staticAttrs.System_dynamic_deps)
-
- attrs := &bazelCcLibraryStaticAttributes{
- Copts: compilerAttrs.copts,
- Srcs: compilerAttrs.srcs,
- Implementation_deps: linkerAttrs.deps,
- Deps: linkerAttrs.exportedDeps,
- Whole_archive_deps: linkerAttrs.wholeArchiveDeps,
- Dynamic_deps: linkerAttrs.dynamicDeps,
- System_dynamic_deps: linkerAttrs.systemDynamicDeps,
-
- Linkopts: linkerAttrs.linkopts,
- Linkstatic: true,
- Use_libcrt: linkerAttrs.useLibcrt,
- Rtti: compilerAttrs.rtti,
- Export_includes: exportedIncludes.Includes,
- Export_system_includes: exportedIncludes.SystemIncludes,
- Local_includes: compilerAttrs.localIncludes,
- Absolute_includes: compilerAttrs.absoluteIncludes,
-
- Cppflags: compilerAttrs.cppFlags,
- Srcs_c: compilerAttrs.cSrcs,
- Conlyflags: compilerAttrs.conlyFlags,
- Srcs_as: compilerAttrs.asSrcs,
- Asflags: asFlags,
- }
-
- props := bazel.BazelTargetModuleProperties{
- Rule_class: "cc_library_static",
- Bzl_load_location: "//build/bazel/rules:cc_library_static.bzl",
- }
-
- ctx.CreateBazelTargetModule(module.Name(), props, attrs)
}
func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) {
- module, ok := ctx.Module().(*Module)
- if !ok {
- // Not a cc module
- return
- }
- if !module.ConvertWithBp2build(ctx) {
- return
- }
- if ctx.ModuleType() != "cc_library_static" {
- return
- }
+ ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_static")
+}
- ccLibraryStaticBp2BuildInternal(ctx, module)
+// TODO(b/199902614): Can this be factored to share with the other Attributes?
+type bazelCcLibrarySharedAttributes struct {
+ Srcs bazel.LabelListAttribute
+ Srcs_c bazel.LabelListAttribute
+ Srcs_as bazel.LabelListAttribute
+
+ Implementation_deps bazel.LabelListAttribute
+ Deps bazel.LabelListAttribute
+ Whole_archive_deps bazel.LabelListAttribute
+ Dynamic_deps bazel.LabelListAttribute
+ System_dynamic_deps bazel.LabelListAttribute
+
+ Linkopts bazel.StringListAttribute
+ Use_libcrt bazel.BoolAttribute
+ Rtti bazel.BoolAttribute
+ Strip stripAttributes
+
+ Export_includes bazel.StringListAttribute
+ Export_system_includes bazel.StringListAttribute
+ Local_includes bazel.StringListAttribute
+ Absolute_includes bazel.StringListAttribute
+ Hdrs bazel.LabelListAttribute
+ Version_script bazel.LabelAttribute
+
+ Copts bazel.StringListAttribute
+ Cppflags bazel.StringListAttribute
+ Conlyflags bazel.StringListAttribute
+ Asflags bazel.StringListAttribute
+}
+
+func CcLibrarySharedBp2Build(ctx android.TopDownMutatorContext) {
+ ccSharedOrStaticBp2BuildMutator(ctx, "cc_library_shared")
}
diff --git a/cc/library_test.go b/cc/library_test.go
index 6b349b6..7ddfaa7 100644
--- a/cc/library_test.go
+++ b/cc/library_test.go
@@ -320,3 +320,48 @@
libfoo.Args["ldFlags"], "-Wl,--dynamic-list,foo.dynamic.txt")
}
+
+func TestCcLibrarySharedWithBazel(t *testing.T) {
+ bp := `
+cc_library_shared {
+ name: "foo",
+ srcs: ["foo.cc"],
+ bazel_module: { label: "//foo/bar:bar" },
+}`
+ config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
+ config.BazelContext = android.MockBazelContext{
+ OutputBaseDir: "outputbase",
+ LabelToCcInfo: map[string]cquery.CcInfo{
+ "//foo/bar:bar": cquery.CcInfo{
+ CcObjectFiles: []string{"foo.o"},
+ Includes: []string{"include"},
+ SystemIncludes: []string{"system_include"},
+ RootDynamicLibraries: []string{"foo.so"},
+ TocFile: "foo.so.toc",
+ },
+ },
+ }
+ ctx := testCcWithConfig(t, config)
+
+ sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
+ producer := sharedFoo.(android.OutputFileProducer)
+ outputFiles, err := producer.OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
+ }
+ expectedOutputFiles := []string{"outputbase/execroot/__main__/foo.so"}
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
+
+ tocFilePath := sharedFoo.(*Module).Toc()
+ if !tocFilePath.Valid() {
+ t.Errorf("Invalid tocFilePath: %s", tocFilePath)
+ }
+ tocFile := tocFilePath.Path()
+ expectedToc := "outputbase/execroot/__main__/foo.so.toc"
+ android.AssertStringEquals(t, "toc file", expectedToc, tocFile.String())
+
+ entries := android.AndroidMkEntriesForTest(t, ctx, sharedFoo)[0]
+ expectedFlags := []string{"-Ioutputbase/execroot/__main__/include", "-isystem outputbase/execroot/__main__/system_include"}
+ gotFlags := entries.EntryMap["LOCAL_EXPORT_CFLAGS"]
+ android.AssertDeepEquals(t, "androidmk exported cflags", expectedFlags, gotFlags)
+}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 1401c75..7733c1b 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -110,17 +110,12 @@
return true
}
- // Don't preopt system server jars that are updatable.
- if global.ApexSystemServerJars.ContainsJar(module.Name) {
- return true
- }
-
// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
// Also preopt system server jars since selinux prevents system server from loading anything from
// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
- !global.SystemServerJars.ContainsJar(module.Name) && !module.PreoptExtractedApk {
+ !AllSystemServerJars(ctx, global).ContainsJar(module.Name) && !module.PreoptExtractedApk {
return true
}
@@ -201,6 +196,14 @@
return profilePath
}
+// Returns the dex location of a system server java library.
+func GetSystemServerDexLocation(global *GlobalConfig, lib string) string {
+ if apex := global.ApexSystemServerJars.ApexOfJar(lib); apex != "" {
+ return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
+ }
+ return fmt.Sprintf("/system/framework/%s.jar", lib)
+}
+
func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
appImage bool, generateDM bool) {
@@ -216,6 +219,13 @@
}
toOdexPath := func(path string) string {
+ if global.ApexSystemServerJars.ContainsJar(module.Name) {
+ return filepath.Join(
+ "/system/framework/oat",
+ arch.String(),
+ strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex")
+ }
+
return filepath.Join(
filepath.Dir(path),
"oat",
@@ -234,20 +244,21 @@
invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
- systemServerJars := NonApexSystemServerJars(ctx, global)
+ systemServerJars := AllSystemServerJars(ctx, global)
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
rule.Command().FlagWithOutput("rm -f ", odexPath)
- if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+ if jarIndex := systemServerJars.IndexOfJar(module.Name); jarIndex >= 0 {
// System server jars should be dexpreopted together: class loader context of each jar
// should include all preceding jars on the system server classpath.
var clcHost android.Paths
var clcTarget []string
- for _, lib := range systemServerJars[:jarIndex] {
+ for i := 0; i < jarIndex; i++ {
+ lib := systemServerJars.Jar(i)
clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
- clcTarget = append(clcTarget, filepath.Join("/system/framework", lib+".jar"))
+ clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib))
}
// Copy the system server jar to a predefined location where dex2oat will find it.
@@ -362,7 +373,7 @@
if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
var compilerFilter string
- if global.SystemServerJars.ContainsJar(module.Name) {
+ if systemServerJars.ContainsJar(module.Name) {
// Jars of system server, use the product option if it is set, speed otherwise.
if global.SystemServerCompilerFilter != "" {
compilerFilter = global.SystemServerCompilerFilter
@@ -416,7 +427,7 @@
// PRODUCT_SYSTEM_SERVER_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
// PRODUCT_OTHER_JAVA_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
- if global.SystemServerJars.ContainsJar(module.Name) {
+ if systemServerJars.ContainsJar(module.Name) {
if global.AlwaysSystemServerDebugInfo {
debugInfo = true
} else if global.NeverSystemServerDebugInfo {
@@ -518,14 +529,15 @@
}
}
-var nonApexSystemServerJarsKey = android.NewOnceKey("nonApexSystemServerJars")
+var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")
// TODO: eliminate the superficial global config parameter by moving global config definition
// from java subpackage to dexpreopt.
-func NonApexSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
- return ctx.Config().Once(nonApexSystemServerJarsKey, func() interface{} {
- return android.RemoveListFromList(global.SystemServerJars.CopyOfJars(), global.ApexSystemServerJars.CopyOfJars())
- }).([]string)
+func AllSystemServerJars(ctx android.PathContext, global *GlobalConfig) *android.ConfiguredJarList {
+ return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
+ allSystemServerJars := global.SystemServerJars.AppendList(global.ApexSystemServerJars)
+ return &allSystemServerJars
+ }).(*android.ConfiguredJarList)
}
// A predefined location for the system server dex jars. This is needed in order to generate
@@ -551,12 +563,12 @@
mctx, isModule := ctx.(android.ModuleContext)
if isModule {
config := GetGlobalConfig(ctx)
- jars := NonApexSystemServerJars(ctx, config)
+ jars := AllSystemServerJars(ctx, config)
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
- depIndex := android.IndexList(dep.Name(), jars)
+ depIndex := jars.IndexOfJar(dep.Name())
if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
- jar := jars[jarIndex]
- dep := jars[depIndex]
+ jar := jars.Jar(jarIndex)
+ dep := jars.Jar(depIndex)
mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+
" '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+
" references from '%s' to '%s'.\n", jar, dep, jar, dep)
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index 4ee61b6..798d776 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -33,17 +33,35 @@
}
func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleConfig {
+ return createTestModuleConfig(
+ name,
+ fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
+}
+
+func testApexModuleConfig(ctx android.PathContext, name, apexName string) *ModuleConfig {
+ return createTestModuleConfig(
+ name,
+ fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, name),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)),
+ android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
+}
+
+func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig {
return &ModuleConfig{
Name: name,
- DexLocation: fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
- BuildPath: android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
- DexPath: android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)),
+ DexLocation: dexLocation,
+ BuildPath: buildPath,
+ DexPath: dexPath,
UncompressedDex: false,
HasApkLibraries: false,
PreoptFlags: nil,
ProfileClassListing: android.OptionalPath{},
ProfileIsTextListing: false,
- EnforceUsesLibrariesStatusFile: android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)),
+ EnforceUsesLibrariesStatusFile: enforceUsesLibrariesStatusFile,
EnforceUsesLibraries: false,
ClassLoaderContexts: nil,
Archs: []android.ArchType{android.Arm},
@@ -140,6 +158,29 @@
}
+func TestDexPreoptApexSystemServerJars(t *testing.T) {
+ config := android.TestConfig("out", nil, "", nil)
+ ctx := android.BuilderContextForTesting(config)
+ globalSoong := globalSoongConfigForTests()
+ global := GlobalConfigForTests(ctx)
+ module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")
+
+ global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
+ []string{"com.android.apex1:service-A"})
+
+ rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wantInstalls := android.RuleBuilderInstalls{
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"},
+ {android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"},
+ }
+
+ android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
+}
+
func TestDexPreoptProfile(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
diff --git a/java/androidmk.go b/java/androidmk.go
index 68ccd82..71370c9 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -61,7 +61,13 @@
var entriesList []android.AndroidMkEntries
if library.hideApexVariantFromMake {
- // For a java library built for an APEX we don't need Make module
+ // For a java library built for an APEX, we don't need a Make module for itself. Otherwise, it
+ // will conflict with the platform variant because they have the same module name in the
+ // makefile. However, we need to add its dexpreopt outputs as sub-modules, if it is preopted.
+ dexpreoptEntries := library.dexpreopter.AndroidMkEntriesForApex()
+ if len(dexpreoptEntries) > 0 {
+ entriesList = append(entriesList, dexpreoptEntries...)
+ }
entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
// Platform variant. If not available for the platform, we don't need Make module.
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index 4108770..52ce77d 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -95,15 +95,6 @@
if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
ctx.AddVariationDependencies(variations, tag, prebuiltName)
addedDep = true
- } else if ctx.Config().AlwaysUsePrebuiltSdks() && len(variations) > 0 {
- // TODO(b/179354495): Remove this code path once the Android build has been fully migrated to
- // use bootclasspath_fragment properly.
- // Some prebuilt java_sdk_library modules do not yet have an APEX variations so try and add a
- // dependency on the non-APEX variant.
- if ctx.OtherModuleDependencyVariantExists(nil, prebuiltName) {
- ctx.AddVariationDependencies(nil, tag, prebuiltName)
- addedDep = true
- }
}
// If no appropriate variant existing for this, so no dependency could be added, then it is an
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 0faae36..e9dc982 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -15,13 +15,46 @@
package java
import (
+ "path/filepath"
+ "strings"
+
"android/soong/android"
"android/soong/dexpreopt"
)
-type dexpreopterInterface interface {
+type DexpreopterInterface interface {
IsInstallable() bool // Structs that embed dexpreopter must implement this.
dexpreoptDisabled(ctx android.BaseModuleContext) bool
+ DexpreoptBuiltInstalledForApex() []dexpreopterInstall
+ AndroidMkEntriesForApex() []android.AndroidMkEntries
+}
+
+type dexpreopterInstall struct {
+ // A unique name to distinguish an output from others for the same java library module. Usually in
+ // the form of `<arch>-<encoded-path>.odex/vdex/art`.
+ name string
+
+ // The name of the input java module.
+ moduleName string
+
+ // The path to the dexpreopt output on host.
+ outputPathOnHost android.Path
+
+ // The directory on the device for the output to install to.
+ installDirOnDevice android.InstallPath
+
+ // The basename (the last segment of the path) for the output to install as.
+ installFileOnDevice string
+}
+
+// The full module name of the output in the makefile.
+func (install *dexpreopterInstall) FullModuleName() string {
+ return install.moduleName + install.SubModuleName()
+}
+
+// The sub-module name of the output in the makefile (the name excluding the java module name).
+func (install *dexpreopterInstall) SubModuleName() string {
+ return "-dexpreopt-" + install.name
}
type dexpreopter struct {
@@ -39,7 +72,9 @@
enforceUsesLibs bool
classLoaderContexts dexpreopt.ClassLoaderContextMap
- builtInstalled string
+ // See the `dexpreopt` function for details.
+ builtInstalled string
+ builtInstalledForApex []dexpreopterInstall
// The config is used for two purposes:
// - Passing dexpreopt information about libraries from Soong to Make. This is needed when
@@ -74,6 +109,17 @@
dexpreopt.DexpreoptRunningInSoong = true
}
+func isApexVariant(ctx android.BaseModuleContext) bool {
+ apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
+ return !apexInfo.IsForPlatform()
+}
+
+func moduleName(ctx android.BaseModuleContext) string {
+ // Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
+ // expected by dexpreopter.
+ return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
+}
+
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
global := dexpreopt.GetGlobalConfig(ctx)
@@ -81,7 +127,7 @@
return true
}
- if inList(ctx.ModuleName(), global.DisablePreoptModules) {
+ if inList(moduleName(ctx), global.DisablePreoptModules) {
return true
}
@@ -93,7 +139,7 @@
return true
}
- if !ctx.Module().(dexpreopterInterface).IsInstallable() {
+ if !ctx.Module().(DexpreopterInterface).IsInstallable() {
return true
}
@@ -101,8 +147,20 @@
return true
}
- // Don't preopt APEX variant module
- if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
+ if isApexVariant(ctx) {
+ // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
+ // building the entire system image.
+ if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) || ctx.Config().UnbundledBuild() {
+ return true
+ }
+ } else {
+ // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
+ if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
+ return true
+ }
+ }
+
+ if !android.IsModulePreferred(ctx.Module()) {
return true
}
@@ -112,17 +170,40 @@
}
func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
- if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
+ if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
return
}
dexpreopt.RegisterToolDeps(ctx)
}
-func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
- return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
+func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
+ return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
+}
+
+// Returns the install path of the dex jar of a module.
+//
+// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
+// than the `name` in the path `/apex/<name>` as suggested in its comment.
+//
+// This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
+// system server jar, which is fine because we currently only preopt system server jars for APEXes.
+func (d *dexpreopter) getInstallPath(
+ ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
+ global := dexpreopt.GetGlobalConfig(ctx)
+ if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
+ dexLocation := dexpreopt.GetSystemServerDexLocation(global, moduleName(ctx))
+ return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
+ }
+ if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
+ filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
+ ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
+ }
+ return defaultInstallPath
}
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
+ global := dexpreopt.GetGlobalConfig(ctx)
+
// TODO(b/148690468): The check on d.installPath is to bail out in cases where
// the dexpreopter struct hasn't been fully initialized before we're called,
// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
@@ -133,7 +214,7 @@
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
- providesUsesLib := ctx.ModuleName()
+ providesUsesLib := moduleName(ctx)
if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
name := ulib.ProvidesUsesLib()
if name != nil {
@@ -147,17 +228,15 @@
return
}
- global := dexpreopt.GetGlobalConfig(ctx)
-
- isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName())
+ isSystemServerJar := global.SystemServerJars.ContainsJar(moduleName(ctx)) ||
+ global.ApexSystemServerJars.ContainsJar(moduleName(ctx))
bootImage := defaultBootImageConfig(ctx)
if global.UseArtImage {
bootImage = artBootImageConfig(ctx)
}
- // System server jars are an exception: they are dexpreopted without updatable bootclasspath.
- dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp && !isSystemServerJar)
+ dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
targets := ctx.MultiTargets()
if len(targets) == 0 {
@@ -199,15 +278,15 @@
profileIsTextListing = true
} else if global.ProfileDir != "" {
profileClassListing = android.ExistentPathForSource(ctx,
- global.ProfileDir, ctx.ModuleName()+".prof")
+ global.ProfileDir, moduleName(ctx)+".prof")
}
}
// Full dexpreopt config, used to create dexpreopt build rules.
dexpreoptConfig := &dexpreopt.ModuleConfig{
- Name: ctx.ModuleName(),
+ Name: moduleName(ctx),
DexLocation: dexLocation,
- BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
+ BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
DexPath: dexJarFile,
ManifestPath: android.OptionalPathForPath(d.manifestFile),
UncompressedDex: d.uncompressedDex,
@@ -256,5 +335,53 @@
dexpreoptRule.Build("dexpreopt", "dexpreopt")
- d.builtInstalled = dexpreoptRule.Installs().String()
+ if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
+ // APEX variants of java libraries are hidden from Make, so their dexpreopt outputs need special
+ // handling. Currently, for APEX variants of java libraries, only those in the system server
+ // classpath are handled here. Preopting of boot classpath jars in the ART APEX are handled in
+ // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
+ for _, install := range dexpreoptRule.Installs() {
+ // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
+ installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
+ installBase := filepath.Base(install.To)
+ arch := filepath.Base(installDir)
+ installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
+ // The installs will be handled by Make as sub-modules of the java library.
+ d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
+ name: arch + "-" + installBase,
+ moduleName: moduleName(ctx),
+ outputPathOnHost: install.From,
+ installDirOnDevice: installPath,
+ installFileOnDevice: installBase,
+ })
+ }
+ } else {
+ // The installs will be handled by Make as LOCAL_SOONG_BUILT_INSTALLED of the java library
+ // module.
+ d.builtInstalled = dexpreoptRule.Installs().String()
+ }
+}
+
+func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
+ return d.builtInstalledForApex
+}
+
+func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
+ var entries []android.AndroidMkEntries
+ for _, install := range d.builtInstalledForApex {
+ install := install
+ entries = append(entries, android.AndroidMkEntries{
+ Class: "ETC",
+ SubName: install.SubModuleName(),
+ OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
+ ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+ entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.ToMakePath().String())
+ entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
+ entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
+ },
+ },
+ })
+ }
+ return entries
}
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index 8dc7b79..1c1070a 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"runtime"
+ "strings"
"testing"
"android/soong/android"
@@ -24,11 +25,17 @@
"android/soong/dexpreopt"
)
+func init() {
+ RegisterFakeRuntimeApexMutator()
+}
+
func TestDexpreoptEnabled(t *testing.T) {
tests := []struct {
- name string
- bp string
- enabled bool
+ name string
+ bp string
+ moduleName string
+ apexVariant bool
+ enabled bool
}{
{
name: "app",
@@ -148,13 +155,81 @@
}`,
enabled: true,
},
+ {
+ name: "apex variant",
+ bp: `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ apexVariant: true,
+ enabled: false,
+ },
+ {
+ name: "apex variant of apex system server jar",
+ bp: `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "service-foo",
+ apexVariant: true,
+ enabled: true,
+ },
+ {
+ name: "apex variant of prebuilt apex system server jar",
+ bp: `
+ java_library {
+ name: "prebuilt_service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "prebuilt_service-foo",
+ apexVariant: true,
+ enabled: true,
+ },
+ {
+ name: "platform variant of apex system server jar",
+ bp: `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`,
+ moduleName: "service-foo",
+ apexVariant: false,
+ enabled: false,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- ctx, _ := testJava(t, test.bp)
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
- dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt")
+ result := preparers.RunTestWithBp(t, test.bp)
+ ctx := result.TestContext
+
+ moduleName := "foo"
+ if test.moduleName != "" {
+ moduleName = test.moduleName
+ }
+
+ variant := "android_common"
+ if test.apexVariant {
+ variant += "_apex1000"
+ }
+
+ dexpreopt := ctx.ModuleForTests(moduleName, variant).MaybeRule("dexpreopt")
enabled := dexpreopt.Rule != nil
if enabled != test.enabled {
@@ -220,3 +295,145 @@
testDex2oatToolDep(true, true, true, prebuiltDex2oatPath)
testDex2oatToolDep(false, true, false, prebuiltDex2oatPath)
}
+
+func TestDexpreoptBuiltInstalledForApex(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
+
+ // An APEX system server jar.
+ result := preparers.RunTestWithBp(t, `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`)
+ ctx := result.TestContext
+ module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
+ library := module.Module().(*Library)
+
+ installs := library.dexpreopter.DexpreoptBuiltInstalledForApex()
+
+ android.AssertIntEquals(t, "install count", 2, len(installs))
+
+ android.AssertStringEquals(t, "installs[0] FullModuleName",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ installs[0].FullModuleName())
+
+ android.AssertStringEquals(t, "installs[0] SubModuleName",
+ "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ installs[0].SubModuleName())
+
+ android.AssertStringEquals(t, "installs[1] FullModuleName",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ installs[1].FullModuleName())
+
+ android.AssertStringEquals(t, "installs[1] SubModuleName",
+ "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ installs[1].SubModuleName())
+
+ // Not an APEX system server jar.
+ result = preparers.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ }`)
+ ctx = result.TestContext
+ module = ctx.ModuleForTests("foo", "android_common")
+ library = module.Module().(*Library)
+
+ installs = library.dexpreopter.DexpreoptBuiltInstalledForApex()
+
+ android.AssertIntEquals(t, "install count", 0, len(installs))
+}
+
+func filterDexpreoptEntriesList(entriesList []android.AndroidMkEntries) []android.AndroidMkEntries {
+ var results []android.AndroidMkEntries
+ for _, entries := range entriesList {
+ if strings.Contains(entries.EntryMap["LOCAL_MODULE"][0], "-dexpreopt-") {
+ results = append(results, entries)
+ }
+ }
+ return results
+}
+
+func verifyEntries(t *testing.T, message string, expectedModule string,
+ expectedPrebuiltModuleFile string, expectedModulePath string, expectedInstalledModuleStem string,
+ entries android.AndroidMkEntries) {
+ android.AssertStringEquals(t, message+" LOCAL_MODULE", expectedModule,
+ entries.EntryMap["LOCAL_MODULE"][0])
+
+ android.AssertStringEquals(t, message+" LOCAL_MODULE_CLASS", "ETC",
+ entries.EntryMap["LOCAL_MODULE_CLASS"][0])
+
+ android.AssertStringDoesContain(t, message+" LOCAL_PREBUILT_MODULE_FILE",
+ entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"][0], expectedPrebuiltModuleFile)
+
+ android.AssertStringDoesContain(t, message+" LOCAL_MODULE_PATH",
+ entries.EntryMap["LOCAL_MODULE_PATH"][0], expectedModulePath)
+
+ android.AssertStringEquals(t, message+" LOCAL_INSTALLED_MODULE_STEM",
+ expectedInstalledModuleStem, entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0])
+
+ android.AssertStringEquals(t, message+" LOCAL_NOT_AVAILABLE_FOR_PLATFORM",
+ "false", entries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"][0])
+}
+
+func TestAndroidMkEntriesForApex(t *testing.T) {
+ preparers := android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModules,
+ PrepareForTestWithFakeApexMutator,
+ dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"),
+ )
+
+ // An APEX system server jar.
+ result := preparers.RunTestWithBp(t, `
+ java_library {
+ name: "service-foo",
+ installable: true,
+ srcs: ["a.java"],
+ apex_available: ["com.android.apex1"],
+ }`)
+ ctx := result.TestContext
+ module := ctx.ModuleForTests("service-foo", "android_common_apex1000")
+
+ entriesList := android.AndroidMkEntriesForTest(t, ctx, module.Module())
+ entriesList = filterDexpreoptEntriesList(entriesList)
+
+ android.AssertIntEquals(t, "entries count", 2, len(entriesList))
+
+ verifyEntries(t,
+ "entriesList[0]",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ "/dexpreopt/oat/arm64/javalib.odex",
+ "/system/framework/oat/arm64",
+ "apex@com.android.apex1@javalib@service-foo.jar@classes.odex",
+ entriesList[0])
+
+ verifyEntries(t,
+ "entriesList[1]",
+ "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ "/dexpreopt/oat/arm64/javalib.vdex",
+ "/system/framework/oat/arm64",
+ "apex@com.android.apex1@javalib@service-foo.jar@classes.vdex",
+ entriesList[1])
+
+ // Not an APEX system server jar.
+ result = preparers.RunTestWithBp(t, `
+ java_library {
+ name: "foo",
+ installable: true,
+ srcs: ["a.java"],
+ }`)
+ ctx = result.TestContext
+ module = ctx.ModuleForTests("foo", "android_common")
+
+ entriesList = android.AndroidMkEntriesForTest(t, ctx, module.Module())
+ entriesList = filterDexpreoptEntriesList(entriesList)
+
+ android.AssertIntEquals(t, "entries count", 0, len(entriesList))
+}
diff --git a/java/java.go b/java/java.go
index 1a052b4..e2665ef 100644
--- a/java/java.go
+++ b/java/java.go
@@ -487,7 +487,7 @@
}
// Store uncompressed dex files that are preopted on /system.
- if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !odexOnSystemOther(ctx, dexpreopter.installPath)) {
+ if !dexpreopter.dexpreoptDisabled(ctx) && (ctx.Host() || !dexpreopter.odexOnSystemOther(ctx, dexpreopter.installPath)) {
return true
}
if ctx.Config().UncompressPrivAppDex() &&
@@ -508,7 +508,8 @@
}
j.checkSdkVersions(ctx)
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary
if j.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
@@ -1368,7 +1369,8 @@
// Dex compilation
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", jarName)
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", jarName))
if j.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
@@ -1509,7 +1511,7 @@
return Bool(j.properties.Installable)
}
-var _ dexpreopterInterface = (*Import)(nil)
+var _ DexpreopterInterface = (*Import)(nil)
// java_import imports one or more `.jar` files into the build graph as if they were built by a java_library module.
//
@@ -1622,7 +1624,8 @@
j.hideApexVariantFromMake = true
}
- j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")
+ j.dexpreopter.installPath = j.dexpreopter.getInstallPath(
+ ctx, android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar"))
j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter)
inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")
diff --git a/java/sdk_library.go b/java/sdk_library.go
index ce8f179..1d39071 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1907,6 +1907,7 @@
android.SdkBase
hiddenAPI
+ dexpreopter
properties sdkLibraryImportProperties
@@ -2111,6 +2112,14 @@
}
}
+func (module *SdkLibraryImport) AndroidMkEntries() []android.AndroidMkEntries {
+ // For an SDK library imported from a prebuilt APEX, we don't need a Make module for itself, as we
+ // don't need to install it. However, we need to add its dexpreopt outputs as sub-modules, if it
+ // is preopted.
+ dexpreoptEntries := module.dexpreopter.AndroidMkEntriesForApex()
+ return append(dexpreoptEntries, android.AndroidMkEntries{Disabled: true})
+}
+
var _ android.ApexModule = (*SdkLibraryImport)(nil)
// Implements android.ApexModule
@@ -2208,8 +2217,16 @@
di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
if dexOutputPath := di.PrebuiltExportPath(apexRootRelativePathToJavaLib(module.BaseModuleName())); dexOutputPath != nil {
module.dexJarFile = dexOutputPath
- module.installFile = android.PathForModuleInPartitionInstall(ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName()))
+ installPath := android.PathForModuleInPartitionInstall(
+ ctx, "apex", ai.ApexVariationName, apexRootRelativePathToJavaLib(module.BaseModuleName()))
+ module.installFile = installPath
module.initHiddenAPI(ctx, dexOutputPath, module.findScopePaths(apiScopePublic).stubsImplPath[0], nil)
+
+ // Dexpreopting.
+ module.dexpreopter.installPath = module.dexpreopter.getInstallPath(ctx, installPath)
+ module.dexpreopter.isSDKLibrary = true
+ module.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &module.dexpreopter)
+ module.dexpreopt(ctx, dexOutputPath)
} else {
// This should never happen as a variant for a prebuilt_apex is only created if the
// prebuilt_apex has been configured to export the java library dex file.
@@ -2328,6 +2345,11 @@
}
}
+// to satisfy java.DexpreopterInterface interface
+func (module *SdkLibraryImport) IsInstallable() bool {
+ return true
+}
+
var _ android.RequiredFilesFromPrebuiltApex = (*SdkLibraryImport)(nil)
func (module *SdkLibraryImport) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string {
diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go
index 938bb28..d6c0946 100644
--- a/java/sdk_library_test.go
+++ b/java/sdk_library_test.go
@@ -598,6 +598,7 @@
}
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
+ `dex2oatd`,
`prebuilt_sdklib.stubs`,
`prebuilt_sdklib.stubs.source.test`,
`prebuilt_sdklib.stubs.system`,
@@ -674,7 +675,6 @@
`)
CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
- `dex2oatd`,
`prebuilt_sdklib`,
`sdklib.impl`,
`sdklib.stubs`,
@@ -683,6 +683,7 @@
})
CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
+ `dex2oatd`,
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
`sdklib.xml`,
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index 5311f62..de2a978 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -123,10 +123,16 @@
blueprint.BaseDependencyTag
}
+// The systemserverclasspath_fragment contents must never depend on prebuilts.
+func (systemServerClasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
// Contents of system server fragments in an apex are considered to be directly in the apex, as if
// they were listed in java_libs.
func (systemServerClasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {}
+var _ android.ReplaceSourceWithPrebuilt = systemServerClasspathFragmentContentDepTag
var _ android.CopyDirectlyInAnyApexTag = systemServerClasspathFragmentContentDepTag
// The tag used for the dependency between the systemserverclasspath_fragment module and its contents.
diff --git a/java/testing.go b/java/testing.go
index 138ef8d..a642753 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -451,3 +451,45 @@
output := sourceGlobalCompatConfig.Output(allOutputs[0])
android.AssertPathsRelativeToTopEquals(t, message+": inputs", expectedPaths, output.Implicits)
}
+
+// Register the fake APEX mutator to `android.InitRegistrationContext` as if the real mutator exists
+// at runtime. This must be called in `init()` of a test if the test is going to use the fake APEX
+// mutator. Otherwise, we will be missing the runtime mutator because "soong-apex" is not a
+// dependency, which will cause an inconsistency between testing and runtime mutators.
+func RegisterFakeRuntimeApexMutator() {
+ registerFakeApexMutator(android.InitRegistrationContext)
+}
+
+var PrepareForTestWithFakeApexMutator = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerFakeApexMutator),
+)
+
+func registerFakeApexMutator(ctx android.RegistrationContext) {
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("apex", fakeApexMutator).Parallel()
+ })
+}
+
+type apexModuleBase interface {
+ ApexAvailable() []string
+}
+
+var _ apexModuleBase = (*Library)(nil)
+var _ apexModuleBase = (*SdkLibrary)(nil)
+
+// A fake APEX mutator that creates a platform variant and an APEX variant for modules with
+// `apex_available`. It helps us avoid a dependency on the real mutator defined in "soong-apex",
+// which will cause a cyclic dependency, and it provides an easy way to create an APEX variant for
+// testing without dealing with all the complexities in the real mutator.
+func fakeApexMutator(mctx android.BottomUpMutatorContext) {
+ switch mctx.Module().(type) {
+ case *Library, *SdkLibrary:
+ if len(mctx.Module().(apexModuleBase).ApexAvailable()) > 0 {
+ modules := mctx.CreateVariations("", "apex1000")
+ apexInfo := android.ApexInfo{
+ ApexVariationName: "apex1000",
+ }
+ mctx.SetVariationProvider(modules[1], android.ApexInfoProvider, apexInfo)
+ }
+ }
+}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 63a8f04..47ca3a7 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -28,6 +28,7 @@
"system/librustutils",
"system/logging/liblog",
"system/logging/rust",
+ "system/nfc",
"system/security",
"system/tools/aidl",
"tools/security/fuzzing/example_rust_fuzzer",
diff --git a/sdk/update.go b/sdk/update.go
index c1a94b6..89a5c92 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -765,6 +765,8 @@
name string
}
+var _ android.BpPropertyTag = propertyTag{}
+
// A BpPropertyTag to add to a property that contains references to other sdk members.
//
// This will cause the references to be rewritten to a versioned reference in the version