[automerger skipped] Merge changes Ie769b9a9,Idb4e15b5 into rvc-dev am: 5ba6237c25 am: b3c817cbfc -s ours
am skip reason: Change-Id Ie769b9a99f080b75c1b82e458b5220261e9c1b47 with SHA-1 c60af159eb is in history
Original change: https://googleplex-android-review.googlesource.com/c/platform/build/soong/+/12512444
Change-Id: I19cce99c1f1454c3b446cabe4ed62e7f7f0b16f1
diff --git a/Android.bp b/Android.bp
index 2df1afb..3075d67 100644
--- a/Android.bp
+++ b/Android.bp
@@ -101,19 +101,29 @@
arch: {
arm: {
src: "prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.9/lib/gcc/arm-linux-androideabi/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-arm.o", "libunwind.o", "pr-support.o"],
+ repack_objects_to_keep: [],
+ enabled: false,
},
arm64: {
src: "prebuilts/gcc/linux-x86/aarch64/aarch64-linux-android-4.9/lib/gcc/aarch64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/32/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
x86_64: {
src: "prebuilts/gcc/linux-x86/x86/x86_64-linux-android-4.9/lib/gcc/x86_64-linux-android/4.9.x/libgcc.a",
- repack_objects_to_keep: ["unwind-dw2.o", "unwind-dw2-fde-dip.o"],
+ repack_objects_to_keep: [
+ "unwind-dw2.o",
+ "unwind-dw2-fde-dip.o",
+ ],
},
},
}
diff --git a/OWNERS b/OWNERS
index 8bb5c30..8355d10 100644
--- a/OWNERS
+++ b/OWNERS
@@ -6,7 +6,8 @@
per-file * = patricearruda@google.com
per-file * = paulduffin@google.com
-per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com
+per-file ndk_*.go = danalbert@google.com
per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
per-file tidy.go = srhines@google.com, chh@google.com
per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
+per-file docs/map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 928ca03..ff85661 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,3 @@
[Builtin Hooks]
gofmt = true
+bpfmt = true
diff --git a/android/Android.bp b/android/Android.bp
index 9712c46..a1b5159 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -8,12 +8,14 @@
"soong-android-soongconfig",
"soong-env",
"soong-shared",
+ "soong-ui-metrics_proto",
],
srcs: [
"androidmk.go",
"apex.go",
"api_levels.go",
"arch.go",
+ "bazel_overlay.go",
"config.go",
"csuite_config.go",
"defaults.go",
@@ -23,7 +25,9 @@
"filegroup.go",
"hooks.go",
"image.go",
+ "makefile_goal.go",
"makevars.go",
+ "metrics.go",
"module.go",
"mutator.go",
"namespace.go",
@@ -37,6 +41,7 @@
"paths.go",
"phony.go",
"prebuilt.go",
+ "prebuilt_build_tool.go",
"proto.go",
"register.go",
"rule_builder.go",
@@ -44,6 +49,7 @@
"sdk.go",
"singleton.go",
"soong_config_modules.go",
+ "test_suites.go",
"testing.go",
"util.go",
"variable.go",
diff --git a/android/androidmk.go b/android/androidmk.go
index 57908c7..fafbfd6 100644
--- a/android/androidmk.go
+++ b/android/androidmk.go
@@ -58,7 +58,7 @@
Extra []AndroidMkExtraFunc
- preamble bytes.Buffer
+ Entries AndroidMkEntries
}
type AndroidMkExtraFunc func(w io.Writer, outputFile Path)
@@ -342,8 +342,8 @@
}
}
- if amod.noticeFile.Valid() {
- a.SetString("LOCAL_NOTICE_FILE", amod.noticeFile.String())
+ if len(amod.noticeFiles) > 0 {
+ a.SetString("LOCAL_NOTICE_FILE", strings.Join(amod.noticeFiles.Strings(), " "))
}
if host {
@@ -525,7 +525,7 @@
func (data *AndroidMkData) fillInData(config Config, bpPath string, mod blueprint.Module) {
// Get the preamble content through AndroidMkEntries logic.
- entries := AndroidMkEntries{
+ data.Entries = AndroidMkEntries{
Class: data.Class,
SubName: data.SubName,
DistFiles: data.DistFiles,
@@ -536,16 +536,12 @@
Host_required: data.Host_required,
Target_required: data.Target_required,
}
- entries.fillInEntries(config, bpPath, mod)
-
- // preamble doesn't need the footer content.
- entries.footer = bytes.Buffer{}
- entries.write(&data.preamble)
+ data.Entries.fillInEntries(config, bpPath, mod)
// copy entries back to data since it is used in Custom
- data.Required = entries.Required
- data.Host_required = entries.Host_required
- data.Target_required = entries.Target_required
+ data.Required = data.Entries.Required
+ data.Host_required = data.Entries.Host_required
+ data.Target_required = data.Entries.Target_required
}
func translateAndroidModule(ctx SingletonContext, w io.Writer, mod blueprint.Module,
@@ -601,7 +597,9 @@
return
}
- w.Write(data.preamble.Bytes())
+ // write preamble via Entries
+ data.Entries.footer = bytes.Buffer{}
+ data.Entries.write(w)
for _, extra := range data.Extra {
extra(w, data.OutputFile.Path())
diff --git a/android/apex.go b/android/apex.go
index 8ec79ef..c0652a0 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -29,11 +29,22 @@
)
type ApexInfo struct {
- // Name of the apex variant that this module is mutated into
- ApexName string
+ // Name of the apex variation that this module is mutated into
+ ApexVariationName string
MinSdkVersion int
Updatable bool
+ RequiredSdks SdkRefs
+
+ InApexes []string
+}
+
+func (i ApexInfo) mergedName() string {
+ name := "apex" + strconv.Itoa(i.MinSdkVersion)
+ for _, sdk := range i.RequiredSdks {
+ name += "_" + sdk.Name + "_" + sdk.Version
+ }
+ return name
}
// Extracted from ApexModule to make it easier to define custom subsets of the
@@ -65,23 +76,26 @@
apexModuleBase() *ApexModuleBase
- // Marks that this module should be built for the specified APEXes.
+ // Marks that this module should be built for the specified APEX.
// Call this before apex.apexMutator is run.
- BuildForApexes(apexes []ApexInfo)
+ BuildForApex(apex ApexInfo)
- // Returns the APEXes that this module will be built for
- ApexVariations() []ApexInfo
-
- // Returns the name of APEX that this module will be built for. Empty string
- // is returned when 'IsForPlatform() == true'. Note that a module can be
- // included in multiple APEXes, in which case, the module is mutated into
- // multiple modules each of which for an APEX. This method returns the
- // name of the APEX that a variant module is for.
+ // Returns the name of APEX variation that this module will be built for.
+ // Empty string is returned when 'IsForPlatform() == true'. Note that a
+ // module can beincluded in multiple APEXes, in which case, the module
+ // is mutated into one or more variants, each of which is for one or
+ // more APEXes. This method returns the name of the APEX variation of
+ // the module.
// Call this after apex.apexMutator is run.
- ApexName() string
+ ApexVariationName() string
+
+ // Returns the name of the APEX modules that this variant of this module
+ // is present in.
+ // Call this after apex.apexMutator is run.
+ InApexes() []string
// Tests whether this module will be built for the platform or not.
- // This is a shortcut for ApexName() == ""
+ // This is a shortcut for ApexVariationName() == ""
IsForPlatform() bool
// Tests if this module could have APEX variants. APEX variants are
@@ -96,7 +110,7 @@
IsInstallableToApex() bool
// Mutate this module into one or more variants each of which is built
- // for an APEX marked via BuildForApexes().
+ // for an APEX marked via BuildForApex().
CreateApexVariations(mctx BottomUpMutatorContext) []Module
// Tests if this module is available for the specified APEX or ":platform"
@@ -124,6 +138,19 @@
// the private part of the listed APEXes even when it is not included in the
// APEXes.
TestFor() []string
+
+ // Returns nil if this module supports sdkVersion
+ // Otherwise, returns error with reason
+ ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error
+
+ // Returns true if this module needs a unique variation per apex, for example if
+ // use_apex_name_macro is set.
+ UniqueApexVariations() bool
+
+ // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies
+ // that are in the same APEX have unique APEX variations so that the module can link against
+ // the right variant.
+ UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext)
}
type ApexProperties struct {
@@ -133,12 +160,15 @@
//
// "//apex_available:anyapex" is a pseudo APEX name that matches to any APEX.
// "//apex_available:platform" refers to non-APEX partitions like "system.img".
+ // "com.android.gki.*" matches any APEX module name with the prefix "com.android.gki.".
// Default is ["//apex_available:platform"].
Apex_available []string
Info ApexInfo `blueprint:"mutated"`
NotAvailableForPlatform bool `blueprint:"mutated"`
+
+ UniqueApexVariationsForDeps bool `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX
@@ -174,30 +204,68 @@
return nil
}
-func (m *ApexModuleBase) BuildForApexes(apexes []ApexInfo) {
- m.apexVariationsLock.Lock()
- defer m.apexVariationsLock.Unlock()
-nextApex:
- for _, apex := range apexes {
- for _, v := range m.apexVariations {
- if v.ApexName == apex.ApexName {
- continue nextApex
+func (m *ApexModuleBase) UniqueApexVariations() bool {
+ return false
+}
+
+func (m *ApexModuleBase) UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) {
+ // anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list
+ // in common. It is used instead of DepIsInSameApex because it needs to determine if the dep
+ // is in the same APEX due to being directly included, not only if it is included _because_ it
+ // is a dependency.
+ anyInSameApex := func(a, b []ApexInfo) bool {
+ collectApexes := func(infos []ApexInfo) []string {
+ var ret []string
+ for _, info := range infos {
+ ret = append(ret, info.InApexes...)
+ }
+ return ret
+ }
+
+ aApexes := collectApexes(a)
+ bApexes := collectApexes(b)
+ sort.Strings(bApexes)
+ for _, aApex := range aApexes {
+ index := sort.SearchStrings(bApexes, aApex)
+ if index < len(bApexes) && bApexes[index] == aApex {
+ return true
}
}
- m.apexVariations = append(m.apexVariations, apex)
+ return false
}
+
+ mctx.VisitDirectDeps(func(dep Module) {
+ if depApexModule, ok := dep.(ApexModule); ok {
+ if anyInSameApex(depApexModule.apexModuleBase().apexVariations, m.apexVariations) &&
+ (depApexModule.UniqueApexVariations() ||
+ depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
+ m.ApexProperties.UniqueApexVariationsForDeps = true
+ }
+ }
+ })
}
-func (m *ApexModuleBase) ApexVariations() []ApexInfo {
- return m.apexVariations
+func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
+ m.apexVariationsLock.Lock()
+ defer m.apexVariationsLock.Unlock()
+ for _, v := range m.apexVariations {
+ if v.ApexVariationName == apex.ApexVariationName {
+ return
+ }
+ }
+ m.apexVariations = append(m.apexVariations, apex)
}
-func (m *ApexModuleBase) ApexName() string {
- return m.ApexProperties.Info.ApexName
+func (m *ApexModuleBase) ApexVariationName() string {
+ return m.ApexProperties.Info.ApexVariationName
+}
+
+func (m *ApexModuleBase) InApexes() []string {
+ return m.ApexProperties.Info.InApexes
}
func (m *ApexModuleBase) IsForPlatform() bool {
- return m.ApexProperties.Info.ApexName == ""
+ return m.ApexProperties.Info.ApexVariationName == ""
}
func (m *ApexModuleBase) CanHaveApexVariants() bool {
@@ -212,6 +280,7 @@
const (
AvailableToPlatform = "//apex_available:platform"
AvailableToAnyApex = "//apex_available:anyapex"
+ AvailableToGkiApex = "com.android.gki.*"
)
func CheckAvailableForApex(what string, apex_available []string) bool {
@@ -221,7 +290,8 @@
return what == AvailableToPlatform
}
return InList(what, apex_available) ||
- (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available))
+ (what != AvailableToPlatform && InList(AvailableToAnyApex, apex_available)) ||
+ (strings.HasPrefix(what, "com.android.gki.") && InList(AvailableToGkiApex, apex_available))
}
func (m *ApexModuleBase) AvailableFor(what string) bool {
@@ -255,7 +325,7 @@
func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) {
for _, n := range m.ApexProperties.Apex_available {
- if n == AvailableToPlatform || n == AvailableToAnyApex {
+ if n == AvailableToPlatform || n == AvailableToAnyApex || n == AvailableToGkiApex {
continue
}
if !mctx.OtherModuleExists(n) && !mctx.Config().AllowMissingDependencies() {
@@ -272,17 +342,48 @@
func (a byApexName) Len() int { return len(a) }
func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
-func (a byApexName) Less(i, j int) bool { return a[i].ApexName < a[j].ApexName }
+func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName }
+
+// mergeApexVariations deduplicates APEX variations that would build identically into a common
+// variation. It returns the reduced list of variations and a list of aliases from the original
+// variation names to the new variation names.
+func mergeApexVariations(apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
+ sort.Sort(byApexName(apexVariations))
+ seen := make(map[string]int)
+ for _, apexInfo := range apexVariations {
+ apexName := apexInfo.ApexVariationName
+ mergedName := apexInfo.mergedName()
+ if index, exists := seen[mergedName]; exists {
+ merged[index].InApexes = append(merged[index].InApexes, apexName)
+ merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
+ } else {
+ seen[mergedName] = len(merged)
+ apexInfo.ApexVariationName = apexInfo.mergedName()
+ apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+ merged = append(merged, apexInfo)
+ }
+ aliases = append(aliases, [2]string{apexName, mergedName})
+ }
+ return merged, aliases
+}
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
if len(m.apexVariations) > 0 {
m.checkApexAvailableProperty(mctx)
- sort.Sort(byApexName(m.apexVariations))
+ var apexVariations []ApexInfo
+ var aliases [][2]string
+ if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps {
+ apexVariations, aliases = mergeApexVariations(m.apexVariations)
+ } else {
+ apexVariations = m.apexVariations
+ }
+
+ sort.Sort(byApexName(apexVariations))
variations := []string{}
variations = append(variations, "") // Original variation for platform
- for _, apex := range m.apexVariations {
- variations = append(variations, apex.ApexName)
+ for _, apex := range apexVariations {
+ variations = append(variations, apex.ApexVariationName)
}
defaultVariation := ""
@@ -292,12 +393,20 @@
for i, mod := range modules {
platformVariation := i == 0
if platformVariation && !mctx.Host() && !mod.(ApexModule).AvailableFor(AvailableToPlatform) {
- mod.SkipInstall()
+ // Do not install the module for platform, but still allow it to output
+ // uninstallable AndroidMk entries in certain cases when they have
+ // side effects.
+ mod.MakeUninstallable()
}
if !platformVariation {
- mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
+ mod.(ApexModule).apexModuleBase().ApexProperties.Info = apexVariations[i-1]
}
}
+
+ for _, alias := range aliases {
+ mctx.CreateAliasVariation(alias[0], alias[1])
+ }
+
return modules
}
return nil
@@ -323,16 +432,17 @@
// depended on by the specified APEXes. Directly depending means that a module
// is explicitly listed in the build definition of the APEX via properties like
// native_shared_libs, java_libs, etc.
-func UpdateApexDependency(apexes []ApexInfo, moduleName string, directDep bool) {
+func UpdateApexDependency(apex ApexInfo, moduleName string, directDep bool) {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
- for _, apex := range apexes {
- apexesForModule, ok := apexNamesMap()[moduleName]
- if !ok {
- apexesForModule = make(map[string]bool)
- apexNamesMap()[moduleName] = apexesForModule
- }
- apexesForModule[apex.ApexName] = apexesForModule[apex.ApexName] || directDep
+ apexesForModule, ok := apexNamesMap()[moduleName]
+ if !ok {
+ apexesForModule = make(map[string]bool)
+ apexNamesMap()[moduleName] = apexesForModule
+ }
+ apexesForModule[apex.ApexVariationName] = apexesForModule[apex.ApexVariationName] || directDep
+ for _, apexName := range apex.InApexes {
+ apexesForModule[apexName] = apexesForModule[apex.ApexVariationName] || directDep
}
}
@@ -349,12 +459,26 @@
func DirectlyInApex(apexName string, moduleName string) bool {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
- if apexNames, ok := apexNamesMap()[moduleName]; ok {
- return apexNames[apexName]
+ if apexNamesForModule, ok := apexNamesMap()[moduleName]; ok {
+ return apexNamesForModule[apexName]
}
return false
}
+// Tests whether a module named moduleName is directly depended on by all APEXes
+// in a list of apexNames.
+func DirectlyInAllApexes(apexNames []string, moduleName string) bool {
+ apexNamesMapMutex.Lock()
+ defer apexNamesMapMutex.Unlock()
+ for _, apexName := range apexNames {
+ apexNamesForModule := apexNamesMap()[moduleName]
+ if !apexNamesForModule[apexName] {
+ return false
+ }
+ }
+ return true
+}
+
type hostContext interface {
Host() bool
}
@@ -477,3 +601,125 @@
},
})
}
+
+// TODO(b/158059172): remove minSdkVersion allowlist
+var minSdkVersionAllowlist = map[string]int{
+ "adbd": 30,
+ "android.net.ipsec.ike": 30,
+ "androidx-constraintlayout_constraintlayout-solver": 30,
+ "androidx.annotation_annotation": 28,
+ "androidx.arch.core_core-common": 28,
+ "androidx.collection_collection": 28,
+ "androidx.lifecycle_lifecycle-common": 28,
+ "apache-commons-compress": 29,
+ "bouncycastle_ike_digests": 30,
+ "brotli-java": 29,
+ "captiveportal-lib": 28,
+ "flatbuffer_headers": 30,
+ "framework-permission": 30,
+ "framework-statsd": 30,
+ "gemmlowp_headers": 30,
+ "ike-internals": 30,
+ "kotlinx-coroutines-android": 28,
+ "kotlinx-coroutines-core": 28,
+ "libadb_crypto": 30,
+ "libadb_pairing_auth": 30,
+ "libadb_pairing_connection": 30,
+ "libadb_pairing_server": 30,
+ "libadb_protos": 30,
+ "libadb_tls_connection": 30,
+ "libadbconnection_client": 30,
+ "libadbconnection_server": 30,
+ "libadbd_core": 30,
+ "libadbd_services": 30,
+ "libadbd": 30,
+ "libapp_processes_protos_lite": 30,
+ "libasyncio": 30,
+ "libbrotli": 30,
+ "libbuildversion": 30,
+ "libcrypto_static": 30,
+ "libcrypto_utils": 30,
+ "libdiagnose_usb": 30,
+ "libeigen": 30,
+ "liblz4": 30,
+ "libmdnssd": 30,
+ "libneuralnetworks_common": 30,
+ "libneuralnetworks_headers": 30,
+ "libneuralnetworks": 30,
+ "libprocpartition": 30,
+ "libprotobuf-java-lite": 30,
+ "libprotoutil": 30,
+ "libqemu_pipe": 30,
+ "libstats_jni": 30,
+ "libstatslog_statsd": 30,
+ "libstatsmetadata": 30,
+ "libstatspull": 30,
+ "libstatssocket": 30,
+ "libsync": 30,
+ "libtextclassifier_hash_headers": 30,
+ "libtextclassifier_hash_static": 30,
+ "libtflite_kernel_utils": 30,
+ "libwatchdog": 29,
+ "libzstd": 30,
+ "metrics-constants-protos": 28,
+ "net-utils-framework-common": 29,
+ "permissioncontroller-statsd": 28,
+ "philox_random_headers": 30,
+ "philox_random": 30,
+ "service-permission": 30,
+ "service-statsd": 30,
+ "statsd-aidl-ndk_platform": 30,
+ "statsd": 30,
+ "tensorflow_headers": 30,
+ "xz-java": 29,
+}
+
+// Function called while walking an APEX's payload dependencies.
+//
+// Return true if the `to` module should be visited, false otherwise.
+type PayloadDepsCallback func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool
+
+// UpdatableModule represents updatable APEX/APK
+type UpdatableModule interface {
+ Module
+ WalkPayloadDeps(ctx ModuleContext, do PayloadDepsCallback)
+}
+
+// CheckMinSdkVersion checks if every dependency of an updatable module sets min_sdk_version accordingly
+func CheckMinSdkVersion(m UpdatableModule, ctx ModuleContext, minSdkVersion int) {
+ // do not enforce min_sdk_version for host
+ if ctx.Host() {
+ return
+ }
+
+ // do not enforce for coverage build
+ if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") || ctx.DeviceConfig().NativeCoverageEnabled() || ctx.DeviceConfig().ClangCoverageEnabled() {
+ return
+ }
+
+ // do not enforce deps.min_sdk_version if APEX/APK doesn't set min_sdk_version or
+ // min_sdk_version is not finalized (e.g. current or codenames)
+ if minSdkVersion == FutureApiLevel {
+ return
+ }
+
+ m.WalkPayloadDeps(ctx, func(ctx ModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool {
+ if externalDep {
+ // external deps are outside the payload boundary, which is "stable" interface.
+ // We don't have to check min_sdk_version for external dependencies.
+ return false
+ }
+ if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ return false
+ }
+ if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil {
+ toName := ctx.OtherModuleName(to)
+ if ver, ok := minSdkVersionAllowlist[toName]; !ok || ver > minSdkVersion {
+ ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v. Dependency path: %s",
+ minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false))
+ return false
+ }
+ }
+ return true
+ })
+}
diff --git a/android/apex_test.go b/android/apex_test.go
new file mode 100644
index 0000000..db02833
--- /dev/null
+++ b/android/apex_test.go
@@ -0,0 +1,111 @@
+// Copyright 2020 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 android
+
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_mergeApexVariations(t *testing.T) {
+ tests := []struct {
+ name string
+ in []ApexInfo
+ wantMerged []ApexInfo
+ wantAliases [][2]string
+ }{
+ {
+ name: "single",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000", 10000, false, nil, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "merge",
+ in: []ApexInfo{
+ {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000_baz_1"},
+ {"foo", "apex10000_baz_1"},
+ },
+ },
+ {
+ name: "don't merge version",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ {"bar", 30, false, nil, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex30", 30, false, nil, []string{"bar"}},
+ {"apex10000", 10000, false, nil, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex30"},
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "merge updatable",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ {"bar", 10000, true, nil, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000", 10000, true, nil, []string{"bar", "foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000"},
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "don't merge sdks",
+ in: []ApexInfo{
+ {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000_baz_2"},
+ {"foo", "apex10000_baz_1"},
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotMerged, gotAliases := mergeApexVariations(tt.in)
+ if !reflect.DeepEqual(gotMerged, tt.wantMerged) {
+ t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged)
+ }
+ if !reflect.DeepEqual(gotAliases, tt.wantAliases) {
+ t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases)
+ }
+ })
+ }
+}
diff --git a/android/arch.go b/android/arch.go
index d14221f..d055a6f 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -23,6 +23,7 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/proptools"
)
@@ -33,8 +34,6 @@
Arm = newArch("arm", "lib32")
Arm64 = newArch("arm64", "lib64")
- Mips = newArch("mips", "lib32")
- Mips64 = newArch("mips64", "lib64")
X86 = newArch("x86", "lib32")
X86_64 = newArch("x86_64", "lib64")
@@ -46,8 +45,6 @@
var archTypeMap = map[string]ArchType{
"arm": Arm,
"arm64": Arm64,
- "mips": Mips,
- "mips64": Mips64,
"x86": X86,
"x86_64": X86_64,
}
@@ -64,12 +61,6 @@
arm64: {
// Host or device variants with arm64 architecture
},
- mips: {
- // Host or device variants with mips architecture
- },
- mips64: {
- // Host or device variants with mips64 architecture
- },
x86: {
// Host or device variants with x86 architecture
},
@@ -145,18 +136,6 @@
"exynos-m1",
"exynos-m2",
},
- Mips: {
- "mips32_fp",
- "mips32r2_fp",
- "mips32r2_fp_xburst",
- "mips32r2dsp_fp",
- "mips32r2dspr2_fp",
- "mips32r6",
- },
- Mips64: {
- "mips64r2",
- "mips64r6",
- },
X86: {
"amberlake",
"atom",
@@ -193,15 +172,6 @@
Arm: {
"neon",
},
- Mips: {
- "dspr2",
- "rev6",
- "msa",
- },
- Mips64: {
- "rev6",
- "msa",
- },
X86: {
"ssse3",
"sse4",
@@ -239,19 +209,6 @@
"neon",
},
},
- Mips: {
- "mips32r2dspr2_fp": {
- "dspr2",
- },
- "mips32r6": {
- "rev6",
- },
- },
- Mips64: {
- "mips64r6": {
- "rev6",
- },
- },
X86: {
"amberlake": {
"ssse3",
@@ -595,6 +552,15 @@
}
}()
+var BuildArch = func() ArchType {
+ switch runtime.GOARCH {
+ case "amd64":
+ return X86_64
+ default:
+ panic(fmt.Sprintf("unsupported Arch: %s", runtime.GOARCH))
+ }
+}()
+
var (
OsTypeList []OsType
commonTargetMap = make(map[string]Target)
@@ -613,10 +579,10 @@
osArchTypeMap = map[OsType][]ArchType{
Linux: []ArchType{X86, X86_64},
- LinuxBionic: []ArchType{X86_64},
+ LinuxBionic: []ArchType{Arm64, X86_64},
Darwin: []ArchType{X86_64},
Windows: []ArchType{X86, X86_64},
- Android: []ArchType{Arm, Arm64, Mips, Mips64, X86, X86_64},
+ Android: []ArchType{Arm, Arm64, X86, X86_64},
Fuchsia: []ArchType{Arm64, X86_64},
}
)
@@ -733,13 +699,31 @@
}
}
-func osMutator(mctx BottomUpMutatorContext) {
+func osMutator(bpctx blueprint.BottomUpMutatorContext) {
var module Module
var ok bool
- if module, ok = mctx.Module().(Module); !ok {
+ if module, ok = bpctx.Module().(Module); !ok {
+ if bootstrap.IsBootstrapModule(bpctx.Module()) {
+ // Bootstrap Go modules are always the build OS or linux bionic.
+ config := bpctx.Config().(Config)
+ osNames := []string{config.BuildOSTarget.OsVariation()}
+ for _, hostCrossTarget := range config.Targets[LinuxBionic] {
+ if hostCrossTarget.Arch.ArchType == config.BuildOSTarget.Arch.ArchType {
+ osNames = append(osNames, hostCrossTarget.OsVariation())
+ }
+ }
+ osNames = FirstUniqueStrings(osNames)
+ bpctx.CreateVariations(osNames...)
+ }
return
}
+ // Bootstrap Go module support above requires this mutator to be a
+ // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
+ // filters out non-Soong modules. Now that we've handled them, create a
+ // normal android.BottomUpMutatorContext.
+ mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+
base := module.base()
if !base.ArchSpecific() {
@@ -854,7 +838,7 @@
// Valid multilib values include:
// "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
// "first": compile for only a single preferred Target supported by the OsClass. This is generally x86_64 or arm64,
-// but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set.
+// but may be arm for a 32-bit only build.
// "32": compile for only a single 32-bit Target supported by the OsClass.
// "64": compile for only a single 64-bit Target supported by the OsClass.
// "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
@@ -863,13 +847,23 @@
//
// Modules can be initialized with InitAndroidMultiTargetsArchModule, in which case they will be split by OsClass,
// but will have a common Target that is expected to handle all other selected Targets via ctx.MultiTargets().
-func archMutator(mctx BottomUpMutatorContext) {
+func archMutator(bpctx blueprint.BottomUpMutatorContext) {
var module Module
var ok bool
- if module, ok = mctx.Module().(Module); !ok {
+ if module, ok = bpctx.Module().(Module); !ok {
+ if bootstrap.IsBootstrapModule(bpctx.Module()) {
+ // Bootstrap Go modules are always the build architecture.
+ bpctx.CreateVariations(bpctx.Config().(Config).BuildOSTarget.ArchVariation())
+ }
return
}
+ // Bootstrap Go module support above requires this mutator to be a
+ // blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
+ // filters out non-Soong modules. Now that we've handled them, create a
+ // normal android.BottomUpMutatorContext.
+ mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+
base := module.base()
if !base.ArchSpecific() {
@@ -947,7 +941,7 @@
modules := mctx.CreateVariations(targetNames...)
for i, m := range modules {
addTargetProperties(m, targets[i], multiTargets, i == 0)
- m.(Module).base().setArchProperties(mctx)
+ m.base().setArchProperties(mctx)
}
}
@@ -1662,15 +1656,6 @@
{"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}},
- {"mips", "mips32-fp", "", []string{"mips"}},
- {"mips", "mips32r2-fp", "", []string{"mips"}},
- {"mips", "mips32r2-fp-xburst", "", []string{"mips"}},
- //{"mips", "mips32r6", "", []string{"mips"}},
- {"mips", "mips32r2dsp-fp", "", []string{"mips"}},
- {"mips", "mips32r2dspr2-fp", "", []string{"mips"}},
- // mips64r2 is mismatching 64r2 and 64r6 libraries during linking to libgcc
- //{"mips64", "mips64r2", "", []string{"mips64"}},
- {"mips64", "mips64r6", "", []string{"mips64"}},
{"x86", "", "", []string{"x86"}},
{"x86", "atom", "", []string{"x86"}},
{"x86", "haswell", "", []string{"x86"}},
diff --git a/android/bazel_overlay.go b/android/bazel_overlay.go
new file mode 100644
index 0000000..a034282
--- /dev/null
+++ b/android/bazel_overlay.go
@@ -0,0 +1,76 @@
+// Copyright 2020 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 android
+
+import (
+ "fmt"
+ "os"
+ "strings"
+
+ "github.com/google/blueprint"
+)
+
+// The Bazel Overlay singleton is responsible for generating the Ninja actions
+// for calling the soong_build primary builder in the main build.ninja file.
+func init() {
+ RegisterSingletonType("bazel_overlay", BazelOverlaySingleton)
+}
+
+func BazelOverlaySingleton() Singleton {
+ return &bazelOverlaySingleton{}
+}
+
+type bazelOverlaySingleton struct{}
+
+func (c *bazelOverlaySingleton) GenerateBuildActions(ctx SingletonContext) {
+ // Create a build and rule statement, using the Bazel overlay's WORKSPACE
+ // file as the output file marker.
+ var deps Paths
+ moduleListFilePath := pathForBuildToolDep(ctx, ctx.Config().moduleListFile)
+ deps = append(deps, moduleListFilePath)
+ deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
+
+ bazelOverlayDirectory := PathForOutput(ctx, "bazel_overlay")
+ bazelOverlayWorkspaceFile := bazelOverlayDirectory.Join(ctx, "WORKSPACE")
+ primaryBuilder := primaryBuilderPath(ctx)
+ bazelOverlay := ctx.Rule(pctx, "bazelOverlay",
+ blueprint.RuleParams{
+ Command: fmt.Sprintf(
+ "rm -rf ${outDir}/* && %s --bazel_overlay_dir ${outDir} %s && echo WORKSPACE: `cat %s` > ${outDir}/.overlay-depfile.d",
+ primaryBuilder.String(),
+ strings.Join(os.Args[1:], " "),
+ moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile.
+ ),
+ CommandDeps: []string{primaryBuilder.String()},
+ Description: fmt.Sprintf(
+ "Creating the Bazel overlay workspace with %s at $outDir",
+ primaryBuilder.Base()),
+ Deps: blueprint.DepsGCC,
+ Depfile: "${outDir}/.overlay-depfile.d",
+ },
+ "outDir")
+
+ ctx.Build(pctx, BuildParams{
+ Rule: bazelOverlay,
+ Output: bazelOverlayWorkspaceFile,
+ Inputs: deps,
+ Args: map[string]string{
+ "outDir": bazelOverlayDirectory.String(),
+ },
+ })
+
+ // Add a phony target for building the bazel overlay
+ ctx.Phony("bazel_overlay", bazelOverlayWorkspaceFile)
+}
diff --git a/android/config.go b/android/config.go
index 3541f83..dd622e5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -35,6 +35,7 @@
var Bool = proptools.Bool
var String = proptools.String
+var StringDefault = proptools.StringDefault
const FutureApiLevel = 10000
@@ -93,8 +94,9 @@
deviceConfig *deviceConfig
- srcDir string // the path of the root source directory
- buildDir string // the path of the build output directory
+ srcDir string // the path of the root source directory
+ buildDir string // the path of the build output directory
+ moduleListFile string // the path to the file which lists blueprint files to parse.
env map[string]string
envLock sync.Mutex
@@ -316,7 +318,7 @@
// New creates a new Config object. The srcDir argument specifies the path to
// the root source directory. It also loads the config file, if found.
-func NewConfig(srcDir, buildDir string) (Config, error) {
+func NewConfig(srcDir, buildDir string, moduleListFile string) (Config, error) {
// Make a config with default options
config := &config{
ConfigFileName: filepath.Join(buildDir, configFileName),
@@ -328,15 +330,16 @@
buildDir: buildDir,
multilibConflicts: make(map[ArchType]bool),
- fs: pathtools.NewOsFs(absSrcDir),
+ moduleListFile: moduleListFile,
+ fs: pathtools.NewOsFs(absSrcDir),
}
config.deviceConfig = &deviceConfig{
config: config,
}
- // Sanity check the build and source directories. This won't catch strange
- // configurations with symlinks, but at least checks the obvious cases.
+ // Soundness check of the build and source directories. This won't catch strange
+ // configurations with symlinks, but at least checks the obvious case.
absBuildDir, err := filepath.Abs(buildDir)
if err != nil {
return Config{}, err
@@ -720,22 +723,26 @@
return Bool(c.productVariables.Allow_missing_dependencies)
}
+// Returns true if a full platform source tree cannot be assumed.
func (c *config) UnbundledBuild() bool {
return Bool(c.productVariables.Unbundled_build)
}
-func (c *config) UnbundledBuildUsePrebuiltSdks() bool {
- return Bool(c.productVariables.Unbundled_build) && !Bool(c.productVariables.Unbundled_build_sdks_from_source)
+// Returns true if building apps that aren't bundled with the platform.
+// UnbundledBuild() is always true when this is true.
+func (c *config) UnbundledBuildApps() bool {
+ return Bool(c.productVariables.Unbundled_build_apps)
+}
+
+// Returns true if building modules against prebuilt SDKs.
+func (c *config) AlwaysUsePrebuiltSdks() bool {
+ return Bool(c.productVariables.Always_use_prebuilt_sdks)
}
func (c *config) Fuchsia() bool {
return Bool(c.productVariables.Fuchsia)
}
-func (c *config) IsPdkBuild() bool {
- return Bool(c.productVariables.Pdk)
-}
-
func (c *config) MinimizeJavaDebugInfo() bool {
return Bool(c.productVariables.MinimizeJavaDebugInfo) && !Bool(c.productVariables.Eng)
}
@@ -748,14 +755,6 @@
return Bool(c.productVariables.Eng)
}
-func (c *config) DevicePrefer32BitApps() bool {
- return Bool(c.productVariables.DevicePrefer32BitApps)
-}
-
-func (c *config) DevicePrefer32BitExecutables() bool {
- return Bool(c.productVariables.DevicePrefer32BitExecutables)
-}
-
func (c *config) DevicePrimaryArchType() ArchType {
return c.Targets[Android][0].Arch.ArchType
}
@@ -863,16 +862,7 @@
}
func (c *config) LibartImgDeviceBaseAddress() string {
- archType := Common
- if len(c.Targets[Android]) > 0 {
- archType = c.Targets[Android][0].Arch.ArchType
- }
- switch archType {
- default:
- return "0x70000000"
- case Mips, Mips64:
- return "0x5C000000"
- }
+ return "0x70000000"
}
func (c *config) ArtUseReadBarrier() bool {
@@ -883,12 +873,12 @@
enforceList := c.productVariables.EnforceRROTargets
// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
exemptedList := c.productVariables.EnforceRROExemptedTargets
- if exemptedList != nil {
+ if len(exemptedList) > 0 {
if InList(name, exemptedList) {
return false
}
}
- if enforceList != nil {
+ if len(enforceList) > 0 {
if InList("*", enforceList) {
return true
}
@@ -899,7 +889,7 @@
func (c *config) EnforceRROExcludedOverlay(path string) bool {
excluded := c.productVariables.EnforceRROExcludedOverlays
- if excluded != nil {
+ if len(excluded) > 0 {
return HasAnyPrefix(path, excluded)
}
return false
@@ -921,25 +911,6 @@
return c.productVariables.ModulesLoadedByPrivilegedModules
}
-// Expected format for apexJarValue = <apex name>:<jar name>
-func SplitApexJarPair(apexJarValue string) (string, string) {
- var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
- if apexJarPair == nil || len(apexJarPair) != 2 {
- panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
- apexJarValue))
- }
- return apexJarPair[0], apexJarPair[1]
-}
-
-func (c *config) BootJars() []string {
- jars := c.productVariables.BootJars
- for _, p := range c.productVariables.UpdatableBootJars {
- _, jar := SplitApexJarPair(p)
- jars = append(jars, jar)
- }
- return jars
-}
-
func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) {
if c.productVariables.DexpreoptGlobalConfig == nil {
return nil, nil
@@ -988,6 +959,10 @@
return String(c.config.productVariables.DeviceVndkVersion)
}
+func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
+ return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
+}
+
func (c *deviceConfig) PlatformVndkVersion() string {
return String(c.config.productVariables.Platform_vndk_version)
}
@@ -1058,7 +1033,7 @@
HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
coverage = true
}
- if coverage && c.config.productVariables.JavaCoverageExcludePaths != nil {
+ if coverage && len(c.config.productVariables.JavaCoverageExcludePaths) > 0 {
if HasAnyPrefix(path, c.config.productVariables.JavaCoverageExcludePaths) {
coverage = false
}
@@ -1087,12 +1062,12 @@
// NativeCoveragePaths represents any path.
func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
coverage := false
- if c.config.productVariables.NativeCoveragePaths != nil {
+ if len(c.config.productVariables.NativeCoveragePaths) > 0 {
if InList("*", c.config.productVariables.NativeCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.NativeCoveragePaths) {
coverage = true
}
}
- if coverage && c.config.productVariables.NativeCoverageExcludePaths != nil {
+ if coverage && len(c.config.productVariables.NativeCoverageExcludePaths) > 0 {
if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
coverage = false
}
@@ -1163,21 +1138,21 @@
}
func (c *config) IntegerOverflowDisabledForPath(path string) bool {
- if c.productVariables.IntegerOverflowExcludePaths == nil {
+ if len(c.productVariables.IntegerOverflowExcludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.IntegerOverflowExcludePaths)
}
func (c *config) CFIDisabledForPath(path string) bool {
- if c.productVariables.CFIExcludePaths == nil {
+ if len(c.productVariables.CFIExcludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.CFIExcludePaths)
}
func (c *config) CFIEnabledForPath(path string) bool {
- if c.productVariables.CFIIncludePaths == nil {
+ if len(c.productVariables.CFIIncludePaths) == 0 {
return false
}
return HasAnyPrefix(path, c.productVariables.CFIIncludePaths)
@@ -1251,10 +1226,6 @@
return c.productVariables.MissingUsesLibraries
}
-func (c *deviceConfig) BoardVndkRuntimeDisable() bool {
- return Bool(c.config.productVariables.BoardVndkRuntimeDisable)
-}
-
func (c *deviceConfig) DeviceArch() string {
return String(c.config.productVariables.DeviceArch)
}
@@ -1274,3 +1245,189 @@
func (c *deviceConfig) BoardUsesRecoveryAsBoot() bool {
return Bool(c.config.productVariables.BoardUsesRecoveryAsBoot)
}
+
+func (c *deviceConfig) BoardKernelBinaries() []string {
+ return c.config.productVariables.BoardKernelBinaries
+}
+
+func (c *deviceConfig) BoardKernelModuleInterfaceVersions() []string {
+ return c.config.productVariables.BoardKernelModuleInterfaceVersions
+}
+
+// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
+// Such lists are used in the build system for things like bootclasspath jars or system server jars.
+// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
+// module name. The pairs come from Make product variables as a list of colon-separated strings.
+//
+// Examples:
+// - "com.android.art:core-oj"
+// - "platform:framework"
+// - "system_ext:foo"
+//
+type ConfiguredJarList struct {
+ apexes []string // A list of apex components.
+ jars []string // A list of jar components.
+}
+
+// The length of the list.
+func (l *ConfiguredJarList) Len() int {
+ return len(l.jars)
+}
+
+// Apex component of idx-th pair on the list.
+func (l *ConfiguredJarList) apex(idx int) string {
+ return l.apexes[idx]
+}
+
+// Jar component of idx-th pair on the list.
+func (l *ConfiguredJarList) Jar(idx int) string {
+ return l.jars[idx]
+}
+
+// If the list contains a pair with the given jar.
+func (l *ConfiguredJarList) ContainsJar(jar string) bool {
+ return InList(jar, l.jars)
+}
+
+// If the list contains the given (apex, jar) pair.
+func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
+ for i := 0; i < l.Len(); i++ {
+ if apex == l.apex(i) && jar == l.Jar(i) {
+ return true
+ }
+ }
+ return false
+}
+
+// Index of the first pair with the given jar on the list, or -1 if none.
+func (l *ConfiguredJarList) IndexOfJar(jar string) int {
+ return IndexList(jar, l.jars)
+}
+
+// Append an (apex, jar) pair to the list.
+func (l *ConfiguredJarList) Append(apex string, jar string) {
+ l.apexes = append(l.apexes, apex)
+ l.jars = append(l.jars, jar)
+}
+
+// Filter out sublist.
+func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) {
+ apexes := make([]string, 0, l.Len())
+ jars := make([]string, 0, l.Len())
+
+ for i, jar := range l.jars {
+ apex := l.apex(i)
+ if !list.containsApexJarPair(apex, jar) {
+ apexes = append(apexes, apex)
+ jars = append(jars, jar)
+ }
+ }
+
+ l.apexes = apexes
+ l.jars = jars
+}
+
+// A copy of itself.
+func (l *ConfiguredJarList) CopyOf() ConfiguredJarList {
+ return ConfiguredJarList{CopyOf(l.apexes), CopyOf(l.jars)}
+}
+
+// A copy of the list of strings containing jar components.
+func (l *ConfiguredJarList) CopyOfJars() []string {
+ return CopyOf(l.jars)
+}
+
+// A copy of the list of strings with colon-separated (apex, jar) pairs.
+func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
+ pairs := make([]string, 0, l.Len())
+
+ for i, jar := range l.jars {
+ apex := l.apex(i)
+ pairs = append(pairs, apex+":"+jar)
+ }
+
+ return pairs
+}
+
+// A list of build paths based on the given directory prefix.
+func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
+ paths := make(WritablePaths, l.Len())
+ for i, jar := range l.jars {
+ paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
+ }
+ return paths
+}
+
+func ModuleStem(module string) string {
+ // b/139391334: the stem of framework-minus-apex is framework. This is hard coded here until we
+ // find a good way to query the stem of a module before any other mutators are run.
+ if module == "framework-minus-apex" {
+ return "framework"
+ }
+ return module
+}
+
+// A list of on-device paths.
+func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
+ paths := make([]string, l.Len())
+ for i, jar := range l.jars {
+ apex := l.apexes[i]
+ name := ModuleStem(jar) + ".jar"
+
+ var subdir string
+ if apex == "platform" {
+ subdir = "system/framework"
+ } else if apex == "system_ext" {
+ subdir = "system_ext/framework"
+ } else {
+ subdir = filepath.Join("apex", apex, "javalib")
+ }
+
+ if ostype.Class == Host {
+ paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
+ } else {
+ paths[i] = filepath.Join("/", subdir, name)
+ }
+ }
+ return paths
+}
+
+// Expected format for apexJarValue = <apex name>:<jar name>
+func splitConfiguredJarPair(ctx PathContext, str string) (string, string) {
+ pair := strings.SplitN(str, ":", 2)
+ if len(pair) == 2 {
+ return pair[0], pair[1]
+ } else {
+ ReportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+ return "error-apex", "error-jar"
+ }
+}
+
+func CreateConfiguredJarList(ctx PathContext, list []string) ConfiguredJarList {
+ apexes := make([]string, 0, len(list))
+ jars := make([]string, 0, len(list))
+
+ l := ConfiguredJarList{apexes, jars}
+
+ for _, apexjar := range list {
+ apex, jar := splitConfiguredJarPair(ctx, apexjar)
+ l.Append(apex, jar)
+ }
+
+ return l
+}
+
+func EmptyConfiguredJarList() ConfiguredJarList {
+ return ConfiguredJarList{}
+}
+
+var earlyBootJarsKey = NewOnceKey("earlyBootJars")
+
+func (c *config) BootJars() []string {
+ return c.Once(earlyBootJarsKey, func() interface{} {
+ ctx := NullPathContext{Config{c}}
+ list := CreateConfiguredJarList(ctx,
+ append(CopyOf(c.productVariables.BootJars), c.productVariables.UpdatableBootJars...))
+ return list.CopyOfJars()
+ }).([]string)
+}
diff --git a/android/defaults.go b/android/defaults.go
index 23aa7b4..0892adf 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -115,11 +115,6 @@
type DefaultsModuleBase struct {
DefaultableModuleBase
-
- // Container for defaults of the common properties
- commonProperties commonProperties
-
- defaultsVisibilityProperties DefaultsVisibilityProperties
}
// The common pattern for defaults modules is to register separate instances of
@@ -153,12 +148,6 @@
properties() []interface{}
productVariableProperties() interface{}
-
- // Return the defaults common properties.
- common() *commonProperties
-
- // Return the defaults visibility properties.
- defaultsVisibility() *DefaultsVisibilityProperties
}
func (d *DefaultsModuleBase) isDefaults() bool {
@@ -178,19 +167,11 @@
return d.defaultableVariableProperties
}
-func (d *DefaultsModuleBase) common() *commonProperties {
- return &d.commonProperties
-}
-
-func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
- return &d.defaultsVisibilityProperties
-}
-
func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
}
func InitDefaultsModule(module DefaultsModule) {
- commonProperties := module.common()
+ commonProperties := &commonProperties{}
module.AddProperties(
&hostAndDeviceProperties{},
@@ -205,7 +186,7 @@
// Add properties that will not have defaults applied to them.
base := module.base()
- defaultsVisibility := module.defaultsVisibility()
+ defaultsVisibility := &DefaultsVisibilityProperties{}
module.AddProperties(&base.nameProperties, defaultsVisibility)
// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
diff --git a/android/defs.go b/android/defs.go
index 4552224..83daa03 100644
--- a/android/defs.go
+++ b/android/defs.go
@@ -69,7 +69,7 @@
// A symlink rule.
Symlink = pctx.AndroidStaticRule("Symlink",
blueprint.RuleParams{
- Command: "ln -f -s $fromPath $out",
+ Command: "rm -f $out && ln -f -s $fromPath $out",
Description: "symlink $out",
},
"fromPath")
diff --git a/android/env.go b/android/env.go
index 46bd3d6..c7c96d5 100644
--- a/android/env.go
+++ b/android/env.go
@@ -15,9 +15,11 @@
package android
import (
+ "fmt"
"os"
"os/exec"
"strings"
+ "syscall"
"android/soong/env"
)
@@ -30,28 +32,59 @@
// a manifest regeneration.
var originalEnv map[string]string
-var SoongDelveListen string
-var SoongDelvePath string
+var soongDelveListen string
+var soongDelvePath string
+var soongDelveEnv []string
func init() {
// Delve support needs to read this environment variable very early, before NewConfig has created a way to
// access originalEnv with dependencies. Store the value where soong_build can find it, it will manually
// ensure the dependencies are created.
- SoongDelveListen = os.Getenv("SOONG_DELVE")
- SoongDelvePath, _ = exec.LookPath("dlv")
+ soongDelveListen = os.Getenv("SOONG_DELVE")
+ soongDelvePath, _ = exec.LookPath("dlv")
originalEnv = make(map[string]string)
+ soongDelveEnv = []string{}
for _, env := range os.Environ() {
idx := strings.IndexRune(env, '=')
if idx != -1 {
originalEnv[env[:idx]] = env[idx+1:]
+ if env[:idx] != "SOONG_DELVE" {
+ soongDelveEnv = append(soongDelveEnv, env)
+ }
}
}
+
// Clear the environment to prevent use of os.Getenv(), which would not provide dependencies on environment
// variable values. The environment is available through ctx.Config().Getenv, ctx.Config().IsEnvTrue, etc.
os.Clearenv()
}
+func ReexecWithDelveMaybe() {
+ if soongDelveListen == "" {
+ return
+ }
+
+ if soongDelvePath == "" {
+ fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
+ os.Exit(1)
+ }
+ dlvArgv := []string{
+ soongDelvePath,
+ "--listen=:" + soongDelveListen,
+ "--headless=true",
+ "--api-version=2",
+ "exec",
+ os.Args[0],
+ "--",
+ }
+ dlvArgv = append(dlvArgv, os.Args[1:]...)
+ os.Chdir(absSrcDir)
+ syscall.Exec(soongDelvePath, dlvArgv, soongDelveEnv)
+ fmt.Fprintln(os.Stderr, "exec() failed while trying to reexec with Delve")
+ os.Exit(1)
+}
+
// getenv checks either os.Getenv or originalEnv so that it works before or after the init()
// function above. It doesn't add any dependencies on the environment variable, so it should
// only be used for values that won't change. For values that might change use ctx.Config().Getenv.
diff --git a/android/filegroup.go b/android/filegroup.go
index ec522fc..68311e3 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -15,9 +15,7 @@
package android
import (
- "io"
"strings"
- "text/template"
)
func init() {
@@ -71,23 +69,8 @@
return append(Paths{}, fg.srcs...)
}
-var androidMkTemplate = template.Must(template.New("filegroup").Parse(`
-ifdef {{.makeVar}}
- $(error variable {{.makeVar}} set by soong module is already set in make)
-endif
-{{.makeVar}} := {{.value}}
-.KATI_READONLY := {{.makeVar}}
-`))
-
-func (fg *fileGroup) AndroidMk() AndroidMkData {
- return AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data AndroidMkData) {
- if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
- androidMkTemplate.Execute(w, map[string]string{
- "makeVar": makeVar,
- "value": strings.Join(fg.srcs.Strings(), " "),
- })
- }
- },
+func (fg *fileGroup) MakeVars(ctx MakeVarsModuleContext) {
+ if makeVar := String(fg.properties.Export_to_make_var); makeVar != "" {
+ ctx.StrictRaw(makeVar, strings.Join(fg.srcs.Strings(), " "))
}
}
diff --git a/android/hooks.go b/android/hooks.go
index f43a007..85fc081 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -120,6 +120,7 @@
type InstallHookContext interface {
ModuleContext
+ SrcPath() Path
Path() InstallPath
Symlink() bool
}
@@ -134,10 +135,17 @@
type installHookContext struct {
ModuleContext
+ srcPath Path
path InstallPath
symlink bool
}
+var _ InstallHookContext = &installHookContext{}
+
+func (x *installHookContext) SrcPath() Path {
+ return x.srcPath
+}
+
func (x *installHookContext) Path() InstallPath {
return x.path
}
@@ -146,10 +154,11 @@
return x.symlink
}
-func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink bool) {
+func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPath, symlink bool) {
if len(x.install) > 0 {
mctx := &installHookContext{
ModuleContext: ctx,
+ srcPath: srcPath,
path: path,
symlink: symlink,
}
diff --git a/android/makefile_goal.go b/android/makefile_goal.go
new file mode 100644
index 0000000..eae3976
--- /dev/null
+++ b/android/makefile_goal.go
@@ -0,0 +1,99 @@
+// Copyright 2020 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 android
+
+import (
+ "fmt"
+ "io"
+ "path/filepath"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterModuleType("makefile_goal", MakefileGoalFactory)
+}
+
+type makefileGoalProperties struct {
+ // Sources.
+
+ // Makefile goal output file path, relative to PRODUCT_OUT.
+ Product_out_path *string
+}
+
+type makefileGoal struct {
+ ModuleBase
+
+ properties makefileGoalProperties
+
+ // Destination. Output file path of this module.
+ outputFilePath OutputPath
+}
+
+var _ AndroidMkEntriesProvider = (*makefileGoal)(nil)
+var _ OutputFileProducer = (*makefileGoal)(nil)
+
+// Input file of this makefile_goal module. Nil if none specified. May use variable names in makefiles.
+func (p *makefileGoal) inputPath() *string {
+ if p.properties.Product_out_path != nil {
+ return proptools.StringPtr(filepath.Join("$(PRODUCT_OUT)", proptools.String(p.properties.Product_out_path)))
+ }
+ return nil
+}
+
+// OutputFileProducer
+func (p *makefileGoal) OutputFiles(tag string) (Paths, error) {
+ if tag != "" {
+ return nil, fmt.Errorf("unsupported tag %q", tag)
+ }
+ return Paths{p.outputFilePath}, nil
+}
+
+// AndroidMkEntriesProvider
+func (p *makefileGoal) DepsMutator(ctx BottomUpMutatorContext) {
+ if p.inputPath() == nil {
+ ctx.PropertyErrorf("product_out_path", "Path relative to PRODUCT_OUT required")
+ }
+}
+
+func (p *makefileGoal) GenerateAndroidBuildActions(ctx ModuleContext) {
+ filename := filepath.Base(proptools.String(p.inputPath()))
+ p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
+
+ ctx.InstallFile(PathForModuleInstall(ctx, "etc"), ctx.ModuleName(), p.outputFilePath)
+}
+
+func (p *makefileGoal) AndroidMkEntries() []AndroidMkEntries {
+ return []AndroidMkEntries{AndroidMkEntries{
+ Class: "ETC",
+ OutputFile: OptionalPathForPath(p.outputFilePath),
+ ExtraFooters: []AndroidMkExtraFootersFunc{
+ func(w io.Writer, name, prefix, moduleDir string, entries *AndroidMkEntries) {
+ // Can't use Cp because inputPath() is not a valid Path.
+ fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,%s))\n", proptools.String(p.inputPath()), p.outputFilePath)
+ },
+ },
+ }}
+}
+
+// Import a Makefile goal to Soong by copying the file built by
+// the goal to a path visible to Soong. This rule only works on boot images.
+func MakefileGoalFactory() Module {
+ module := &makefileGoal{}
+ module.AddProperties(&module.properties)
+ // This module is device-only
+ InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
+ return module
+}
diff --git a/android/makevars.go b/android/makevars.go
index ff7c8e4..003a9df 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -17,6 +17,7 @@
import (
"bytes"
"fmt"
+ "sort"
"strconv"
"strings"
@@ -34,43 +35,16 @@
}
///////////////////////////////////////////////////////////////////////////////
-// Interface for other packages to use to declare make variables
-type MakeVarsContext interface {
+
+// BaseMakeVarsContext contains the common functions for other packages to use
+// to declare make variables
+type BaseMakeVarsContext interface {
Config() Config
DeviceConfig() DeviceConfig
AddNinjaFileDeps(deps ...string)
- ModuleName(module blueprint.Module) string
- ModuleDir(module blueprint.Module) string
- ModuleSubDir(module blueprint.Module) string
- ModuleType(module blueprint.Module) string
- BlueprintFile(module blueprint.Module) string
-
- ModuleErrorf(module blueprint.Module, format string, args ...interface{})
- Errorf(format string, args ...interface{})
Failed() bool
- VisitAllModules(visit func(Module))
- VisitAllModulesIf(pred func(Module) bool, visit func(Module))
-
- // Verify the make variable matches the Soong version, fail the build
- // if it does not. If the make variable is empty, just set it.
- Strict(name, ninjaStr string)
- // Check to see if the make variable matches the Soong version, warn if
- // it does not. If the make variable is empty, just set it.
- Check(name, ninjaStr string)
-
- // These are equivalent to the above, but sort the make and soong
- // variables before comparing them. They also show the unique entries
- // in each list when displaying the difference, instead of the entire
- // string.
- StrictSorted(name, ninjaStr string)
- CheckSorted(name, ninjaStr string)
-
- // Evaluates a ninja string and returns the result. Used if more
- // complicated modification needs to happen before giving it to Make.
- Eval(ninjaStr string) (string, error)
-
// These are equivalent to Strict and Check, but do not attempt to
// evaluate the values before writing them to the Makefile. They can
// be used when all ninja variables have already been evaluated through
@@ -108,6 +82,48 @@
DistForGoalsWithFilename(goals []string, path Path, filename string)
}
+// MakeVarsContext contains the set of functions available for MakeVarsProvider
+// and SingletonMakeVarsProvider implementations.
+type MakeVarsContext interface {
+ BaseMakeVarsContext
+
+ ModuleName(module blueprint.Module) string
+ ModuleDir(module blueprint.Module) string
+ ModuleSubDir(module blueprint.Module) string
+ ModuleType(module blueprint.Module) string
+ BlueprintFile(module blueprint.Module) string
+
+ ModuleErrorf(module blueprint.Module, format string, args ...interface{})
+ Errorf(format string, args ...interface{})
+
+ VisitAllModules(visit func(Module))
+ VisitAllModulesIf(pred func(Module) bool, visit func(Module))
+
+ // Verify the make variable matches the Soong version, fail the build
+ // if it does not. If the make variable is empty, just set it.
+ Strict(name, ninjaStr string)
+ // Check to see if the make variable matches the Soong version, warn if
+ // it does not. If the make variable is empty, just set it.
+ Check(name, ninjaStr string)
+
+ // These are equivalent to the above, but sort the make and soong
+ // variables before comparing them. They also show the unique entries
+ // in each list when displaying the difference, instead of the entire
+ // string.
+ StrictSorted(name, ninjaStr string)
+ CheckSorted(name, ninjaStr string)
+
+ // Evaluates a ninja string and returns the result. Used if more
+ // complicated modification needs to happen before giving it to Make.
+ Eval(ninjaStr string) (string, error)
+}
+
+// MakeVarsModuleContext contains the set of functions available for modules
+// implementing the ModuleMakeVarsProvider interface.
+type MakeVarsModuleContext interface {
+ BaseMakeVarsContext
+}
+
var _ PathContext = MakeVarsContext(nil)
type MakeVarsProvider func(ctx MakeVarsContext)
@@ -135,6 +151,14 @@
return func(ctx MakeVarsContext) { singleton.MakeVars(ctx) }
}
+// ModuleMakeVarsProvider is a Module with an extra method to provide extra values to be exported to Make.
+type ModuleMakeVarsProvider interface {
+ Module
+
+ // MakeVars uses a MakeVarsModuleContext to provide extra values to be exported to Make.
+ MakeVars(ctx MakeVarsModuleContext)
+}
+
///////////////////////////////////////////////////////////////////////////////
func makeVarsSingletonFunc() Singleton {
@@ -209,10 +233,45 @@
dists = append(dists, mctx.dists...)
}
+ ctx.VisitAllModules(func(m Module) {
+ if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled() {
+ mctx := &makeVarsContext{
+ SingletonContext: ctx,
+ }
+
+ provider.MakeVars(mctx)
+
+ vars = append(vars, mctx.vars...)
+ phonies = append(phonies, mctx.phonies...)
+ dists = append(dists, mctx.dists...)
+ }
+ })
+
if ctx.Failed() {
return
}
+ sort.Slice(vars, func(i, j int) bool {
+ return vars[i].name < vars[j].name
+ })
+ sort.Slice(phonies, func(i, j int) bool {
+ return phonies[i].name < phonies[j].name
+ })
+ lessArr := func(a, b []string) bool {
+ if len(a) == len(b) {
+ for i := range a {
+ if a[i] < b[i] {
+ return true
+ }
+ }
+ return false
+ }
+ return len(a) < len(b)
+ }
+ sort.Slice(dists, func(i, j int) bool {
+ return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths, dists[j].paths)
+ })
+
outBytes := s.writeVars(vars)
if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
diff --git a/android/metrics.go b/android/metrics.go
new file mode 100644
index 0000000..b7aee54
--- /dev/null
+++ b/android/metrics.go
@@ -0,0 +1,87 @@
+// Copyright 2020 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 android
+
+import (
+ "io/ioutil"
+ "runtime"
+
+ "github.com/golang/protobuf/proto"
+
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+)
+
+var soongMetricsOnceKey = NewOnceKey("soong metrics")
+
+type SoongMetrics struct {
+ Modules int
+ Variants int
+}
+
+func ReadSoongMetrics(config Config) SoongMetrics {
+ return config.Get(soongMetricsOnceKey).(SoongMetrics)
+}
+
+func init() {
+ RegisterSingletonType("soong_metrics", soongMetricsSingletonFactory)
+}
+
+func soongMetricsSingletonFactory() Singleton { return soongMetricsSingleton{} }
+
+type soongMetricsSingleton struct{}
+
+func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) {
+ metrics := SoongMetrics{}
+ ctx.VisitAllModules(func(m Module) {
+ if ctx.PrimaryModule(m) == m {
+ metrics.Modules++
+ }
+ metrics.Variants++
+ })
+ ctx.Config().Once(soongMetricsOnceKey, func() interface{} {
+ return metrics
+ })
+}
+
+func collectMetrics(config Config) *soong_metrics_proto.SoongBuildMetrics {
+ metrics := &soong_metrics_proto.SoongBuildMetrics{}
+
+ soongMetrics := ReadSoongMetrics(config)
+ metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules))
+ metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants))
+
+ memStats := runtime.MemStats{}
+ runtime.ReadMemStats(&memStats)
+ metrics.MaxHeapSize = proto.Uint64(memStats.HeapSys)
+ metrics.TotalAllocCount = proto.Uint64(memStats.Mallocs)
+ metrics.TotalAllocSize = proto.Uint64(memStats.TotalAlloc)
+
+ return metrics
+}
+
+func WriteMetrics(config Config, metricsFile string) error {
+ metrics := collectMetrics(config)
+
+ buf, err := proto.Marshal(metrics)
+ if err != nil {
+ return err
+ }
+ err = ioutil.WriteFile(absolutePath(metricsFile), buf, 0666)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/android/module.go b/android/module.go
index 6c6c0ea..337ae40 100644
--- a/android/module.go
+++ b/android/module.go
@@ -19,6 +19,7 @@
"os"
"path"
"path/filepath"
+ "regexp"
"strings"
"text/scanner"
@@ -49,6 +50,8 @@
Implicit Path
Implicits Paths
OrderOnly Paths
+ Validation Path
+ Validations Paths
Default bool
Args map[string]string
}
@@ -105,11 +108,15 @@
type BaseModuleContext interface {
EarlyModuleContext
+ blueprintBaseModuleContext() blueprint.BaseModuleContext
+
OtherModuleName(m blueprint.Module) string
OtherModuleDir(m blueprint.Module) string
OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
OtherModuleExists(name string) bool
+ OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
+ OtherModuleReverseDependencyVariantExists(name string) bool
OtherModuleType(m blueprint.Module) string
GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
@@ -137,6 +144,13 @@
// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
GetTagPath() []blueprint.DependencyTag
+ // GetPathString is supposed to be called in visit function passed in WalkDeps()
+ // and returns a multi-line string showing the modules and dependency tags
+ // among them along the top-down dependency path from a start module to current child module.
+ // skipFirst when set to true, the output doesn't include the start module,
+ // which is already printed when this function is used along with ModuleErrorf().
+ GetPathString(skipFirst bool) string
+
AddMissingDependencies(missingDeps []string)
Target() Target
@@ -184,6 +198,7 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() (*OsType, *ArchType)
RequiredModuleNames() []string
HostRequiredModuleNames() []string
@@ -216,6 +231,16 @@
// For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go
GenerateAndroidBuildActions(ModuleContext)
+ // Add dependencies to the components of a module, i.e. modules that are created
+ // by the module and which are considered to be part of the creating module.
+ //
+ // This is called before prebuilts are renamed so as to allow a dependency to be
+ // added directly to a prebuilt child module instead of depending on a source module
+ // and relying on prebuilt processing to switch to the prebuilt module if preferred.
+ //
+ // A dependency on a prebuilt must include the "prebuilt_" prefix.
+ ComponentDepsMutator(ctx BottomUpMutatorContext)
+
DepsMutator(BottomUpMutatorContext)
base() *ModuleBase
@@ -230,12 +255,16 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() (*OsType, *ArchType)
SkipInstall()
IsSkipInstall() bool
+ MakeUninstallable()
+ ReplacedByPrebuilt()
+ IsReplacedByPrebuilt() bool
ExportedToMake() bool
InitRc() Paths
VintfFragments() Paths
- NoticeFile() OptionalPath
+ NoticeFiles() Paths
AddProperties(props ...interface{})
GetProperties() []interface{}
@@ -256,6 +285,8 @@
RequiredModuleNames() []string
HostRequiredModuleNames() []string
TargetRequiredModuleNames() []string
+
+ filesToInstall() InstallPaths
}
// Qualified id for a module
@@ -514,6 +545,12 @@
SkipInstall bool `blueprint:"mutated"`
+ // Whether the module has been replaced by a prebuilt
+ ReplacedByPrebuilt bool `blueprint:"mutated"`
+
+ // Disabled by mutators. If set to true, it overrides Enabled property.
+ ForcedDisabled bool `blueprint:"mutated"`
+
NamespaceExportedToMake bool `blueprint:"mutated"`
MissingDeps []string `blueprint:"mutated"`
@@ -739,9 +776,9 @@
primaryVisibilityProperty visibilityProperty
noAddressSanitizer bool
- installFiles Paths
+ installFiles InstallPaths
checkbuildFiles Paths
- noticeFile OptionalPath
+ noticeFiles Paths
phonies map[string]Paths
// Used by buildTargetSingleton to create checkbuild and per-directory build targets
@@ -765,6 +802,8 @@
prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
}
+func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}
+
func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
func (m *ModuleBase) AddProperties(props ...interface{}) {
@@ -1004,6 +1043,9 @@
}
func (m *ModuleBase) Enabled() bool {
+ if m.commonProperties.ForcedDisabled {
+ return false
+ }
if m.commonProperties.Enabled == nil {
return !m.Os().DefaultDisabled
}
@@ -1011,7 +1053,7 @@
}
func (m *ModuleBase) Disable() {
- m.commonProperties.Enabled = proptools.BoolPtr(false)
+ m.commonProperties.ForcedDisabled = true
}
func (m *ModuleBase) SkipInstall() {
@@ -1022,26 +1064,42 @@
return m.commonProperties.SkipInstall == true
}
+// Similar to SkipInstall, but if the AndroidMk entry would set
+// LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry
+// rather than leaving it out altogether. That happens in cases where it would
+// have other side effects, in particular when it adds a NOTICE file target,
+// which other install targets might depend on.
+func (m *ModuleBase) MakeUninstallable() {
+ m.SkipInstall()
+}
+
+func (m *ModuleBase) ReplacedByPrebuilt() {
+ m.commonProperties.ReplacedByPrebuilt = true
+ m.SkipInstall()
+}
+
+func (m *ModuleBase) IsReplacedByPrebuilt() bool {
+ return m.commonProperties.ReplacedByPrebuilt
+}
+
func (m *ModuleBase) ExportedToMake() bool {
return m.commonProperties.NamespaceExportedToMake
}
-func (m *ModuleBase) computeInstallDeps(
- ctx blueprint.ModuleContext) Paths {
+func (m *ModuleBase) computeInstallDeps(ctx blueprint.ModuleContext) InstallPaths {
- result := Paths{}
+ var result InstallPaths
// TODO(ccross): we need to use WalkDeps and have some way to know which dependencies require installation
- ctx.VisitDepsDepthFirstIf(isFileInstaller,
- func(m blueprint.Module) {
- fileInstaller := m.(fileInstaller)
- files := fileInstaller.filesToInstall()
- result = append(result, files...)
- })
+ ctx.VisitDepsDepthFirst(func(m blueprint.Module) {
+ if a, ok := m.(Module); ok {
+ result = append(result, a.filesToInstall()...)
+ }
+ })
return result
}
-func (m *ModuleBase) filesToInstall() Paths {
+func (m *ModuleBase) filesToInstall() InstallPaths {
return m.installFiles
}
@@ -1077,12 +1135,16 @@
return false
}
+func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) {
+ return nil, nil
+}
+
func (m *ModuleBase) Owner() string {
return String(m.commonProperties.Owner)
}
-func (m *ModuleBase) NoticeFile() OptionalPath {
- return m.noticeFile
+func (m *ModuleBase) NoticeFiles() Paths {
+ return m.noticeFiles
}
func (m *ModuleBase) setImageVariation(variant string) {
@@ -1135,8 +1197,8 @@
}
func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) {
- allInstalledFiles := Paths{}
- allCheckbuildFiles := Paths{}
+ var allInstalledFiles InstallPaths
+ var allCheckbuildFiles Paths
ctx.VisitAllModuleVariants(func(module Module) {
a := module.base()
allInstalledFiles = append(allInstalledFiles, a.installFiles...)
@@ -1152,7 +1214,7 @@
if len(allInstalledFiles) > 0 {
name := namespacePrefix + ctx.ModuleName() + "-install"
- ctx.Phony(name, allInstalledFiles...)
+ ctx.Phony(name, allInstalledFiles.Paths()...)
m.installTarget = PathForPhony(ctx, name)
deps = append(deps, m.installTarget)
}
@@ -1289,7 +1351,7 @@
suffix = append(suffix, ctx.Arch().ArchType.String())
}
if apex, ok := m.module.(ApexModule); ok && !apex.IsForPlatform() {
- suffix = append(suffix, apex.ApexName())
+ suffix = append(suffix, apex.ApexVariationName())
}
ctx.Variable(pctx, "moduleDesc", desc)
@@ -1327,12 +1389,25 @@
}
})
- notice := proptools.StringDefault(m.commonProperties.Notice, "NOTICE")
+ m.noticeFiles = make([]Path, 0)
+ optPath := OptionalPath{}
+ notice := proptools.StringDefault(m.commonProperties.Notice, "")
if module := SrcIsModule(notice); module != "" {
- m.noticeFile = ctx.ExpandOptionalSource(¬ice, "notice")
- } else {
+ optPath = ctx.ExpandOptionalSource(¬ice, "notice")
+ } else if notice != "" {
noticePath := filepath.Join(ctx.ModuleDir(), notice)
- m.noticeFile = ExistentPathForSource(ctx, noticePath)
+ optPath = ExistentPathForSource(ctx, noticePath)
+ }
+ if optPath.Valid() {
+ m.noticeFiles = append(m.noticeFiles, optPath.Path())
+ } else {
+ for _, notice = range []string{"LICENSE", "LICENCE", "NOTICE"} {
+ noticePath := filepath.Join(ctx.ModuleDir(), notice)
+ optPath = ExistentPathForSource(ctx, noticePath)
+ if optPath.Valid() {
+ m.noticeFiles = append(m.noticeFiles, optPath.Path())
+ }
+ }
}
m.module.GenerateAndroidBuildActions(ctx)
@@ -1473,6 +1548,12 @@
return b.bp.OtherModuleDependencyTag(m)
}
func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
+func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
+ return b.bp.OtherModuleDependencyVariantExists(variations, name)
+}
+func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
+ return b.bp.OtherModuleReverseDependencyVariantExists(name)
+}
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
return b.bp.OtherModuleType(m)
}
@@ -1481,11 +1562,15 @@
return b.bp.GetDirectDepWithTag(name, tag)
}
+func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
+ return b.bp
+}
+
type moduleContext struct {
bp blueprint.ModuleContext
baseModuleContext
- installDeps Paths
- installFiles Paths
+ installDeps InstallPaths
+ installFiles InstallPaths
checkbuildFiles Paths
module Module
phonies map[string]Paths
@@ -1524,6 +1609,7 @@
Inputs: params.Inputs.Strings(),
Implicits: params.Implicits.Strings(),
OrderOnly: params.OrderOnly.Strings(),
+ Validations: params.Validations.Strings(),
Args: params.Args,
Optional: !params.Default,
}
@@ -1543,13 +1629,17 @@
if params.Implicit != nil {
bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
}
+ if params.Validation != nil {
+ bparams.Validations = append(bparams.Validations, params.Validation.String())
+ }
bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
- bparams.Depfile = proptools.NinjaEscapeList([]string{bparams.Depfile})[0]
+ bparams.Validations = proptools.NinjaEscapeList(bparams.Validations)
+ bparams.Depfile = proptools.NinjaEscape(bparams.Depfile)
return bparams
}
@@ -1787,6 +1877,41 @@
return b.tagPath
}
+// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
+// a dependency tag.
+var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
+
+// PrettyPrintTag returns string representation of the tag, but prefers
+// custom String() method if available.
+func PrettyPrintTag(tag blueprint.DependencyTag) string {
+ // Use tag's custom String() method if available.
+ if stringer, ok := tag.(fmt.Stringer); ok {
+ return stringer.String()
+ }
+
+ // Otherwise, get a default string representation of the tag's struct.
+ tagString := fmt.Sprintf("%T: %+v", tag, tag)
+
+ // Remove the boilerplate from BaseDependencyTag as it adds no value.
+ tagString = tagCleaner.ReplaceAllString(tagString, "")
+ return tagString
+}
+
+func (b *baseModuleContext) GetPathString(skipFirst bool) string {
+ sb := strings.Builder{}
+ tagPath := b.GetTagPath()
+ walkPath := b.GetWalkPath()
+ if !skipFirst {
+ sb.WriteString(walkPath[0].String())
+ }
+ for i, m := range walkPath[1:] {
+ sb.WriteString("\n")
+ sb.WriteString(fmt.Sprintf(" via tag %s\n", PrettyPrintTag(tagPath[i])))
+ sb.WriteString(fmt.Sprintf(" -> %s", m.String()))
+ }
+ return sb.String()
+}
+
func (m *moduleContext) VisitAllModuleVariants(visit func(Module)) {
m.bp.VisitAllModuleVariants(func(module blueprint.Module) {
visit(module.(Module))
@@ -1911,6 +2036,10 @@
return m.module.InstallBypassMake()
}
+func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) {
+ return m.module.InstallForceOS()
+}
+
func (m *moduleContext) skipInstall(fullInstallPath InstallPath) bool {
if m.module.base().commonProperties.SkipInstall {
return true
@@ -1950,11 +2079,11 @@
rule blueprint.Rule, deps []Path) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, false)
+ m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false)
if !m.skipInstall(fullInstallPath) {
- deps = append(deps, m.installDeps...)
+ deps = append(deps, m.installDeps.Paths()...)
var implicitDeps, orderOnlyDeps Paths
@@ -1984,7 +2113,7 @@
func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
+ m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true)
if !m.skipInstall(fullInstallPath) {
@@ -2013,7 +2142,7 @@
// (e.g. /apex/...)
func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath {
fullInstallPath := installPath.Join(m, name)
- m.module.base().hooks.runInstallHooks(m, fullInstallPath, true)
+ m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true)
if !m.skipInstall(fullInstallPath) {
m.Build(pctx, BuildParams{
@@ -2035,29 +2164,6 @@
m.checkbuildFiles = append(m.checkbuildFiles, srcPath)
}
-type fileInstaller interface {
- filesToInstall() Paths
-}
-
-func isFileInstaller(m blueprint.Module) bool {
- _, ok := m.(fileInstaller)
- return ok
-}
-
-func isAndroidModule(m blueprint.Module) bool {
- _, ok := m.(Module)
- return ok
-}
-
-func findStringInSlice(str string, slice []string) int {
- for i, s := range slice {
- if s == str {
- return i
- }
- }
- return -1
-}
-
// SrcIsModule decodes module references in the format ":name" into the module name, or empty string if the input
// was not a module reference.
func SrcIsModule(s string) (module string) {
@@ -2159,7 +2265,7 @@
return nil
}
if len(paths) > 1 {
- reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
+ ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
pathContextName(ctx, module))
return nil
}
@@ -2363,4 +2469,10 @@
Classes []string `json:"class,omitempty"`
Installed_paths []string `json:"installed,omitempty"`
SrcJars []string `json:"srcjars,omitempty"`
+ Paths []string `json:"path,omitempty"`
+}
+
+func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error {
+ bpctx := ctx.blueprintBaseModuleContext()
+ return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents)
}
diff --git a/android/mutator.go b/android/mutator.go
index 77d5f43..5212553 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -75,6 +75,7 @@
type RegisterMutatorsContext interface {
TopDown(name string, m TopDownMutator) MutatorHandle
BottomUp(name string, m BottomUpMutator) MutatorHandle
+ BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle
}
type RegisterMutatorFunc func(RegisterMutatorsContext)
@@ -115,6 +116,18 @@
// a DefaultableHook.
RegisterDefaultsPreArchMutators,
+ // Add dependencies on any components so that any component references can be
+ // resolved within the deps mutator.
+ //
+ // Must be run after defaults so it can be used to create dependencies on the
+ // component modules that are creating in a DefaultableHook.
+ //
+ // Must be run before RegisterPrebuiltsPreArchMutators, i.e. before prebuilts are
+ // renamed. That is so that if a module creates components using a prebuilt module
+ // type that any dependencies (which must use prebuilt_ prefixes) are resolved to
+ // the prebuilt module and not the source module.
+ RegisterComponentsMutator,
+
// Create an association between prebuilt modules and their corresponding source
// modules (if any).
//
@@ -131,9 +144,9 @@
}
func registerArchMutator(ctx RegisterMutatorsContext) {
- ctx.BottomUp("os", osMutator).Parallel()
+ ctx.BottomUpBlueprint("os", osMutator).Parallel()
ctx.BottomUp("image", imageMutator).Parallel()
- ctx.BottomUp("arch", archMutator).Parallel()
+ ctx.BottomUpBlueprint("arch", archMutator).Parallel()
}
var preDeps = []RegisterMutatorFunc{
@@ -202,7 +215,9 @@
AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string)
AddInterVariantDependency(tag blueprint.DependencyTag, from, to blueprint.Module)
ReplaceDependencies(string)
+ ReplaceDependenciesIf(string, blueprint.ReplaceDependencyPredicate)
AliasVariation(variationName string)
+ CreateAliasVariation(fromVariationName, toVariationName string)
}
type bottomUpMutatorContext struct {
@@ -211,16 +226,21 @@
finalPhase bool
}
+func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
+ finalPhase bool) BottomUpMutatorContext {
+
+ return &bottomUpMutatorContext{
+ bp: ctx,
+ baseModuleContext: a.base().baseModuleContextFactory(ctx),
+ finalPhase: finalPhase,
+ }
+}
+
func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
finalPhase := x.finalPhase
f := func(ctx blueprint.BottomUpMutatorContext) {
if a, ok := ctx.Module().(Module); ok {
- actx := &bottomUpMutatorContext{
- bp: ctx,
- baseModuleContext: a.base().baseModuleContextFactory(ctx),
- finalPhase: finalPhase,
- }
- m(actx)
+ m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
}
}
mutator := &mutator{name: name, bottomUpMutator: f}
@@ -228,6 +248,12 @@
return mutator
}
+func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle {
+ mutator := &mutator{name: name, bottomUpMutator: m}
+ x.mutators = append(x.mutators, mutator)
+ return mutator
+}
+
func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle {
f := func(ctx blueprint.TopDownMutatorContext) {
if a, ok := ctx.Module().(Module); ok {
@@ -252,8 +278,21 @@
return mutator
}
+func RegisterComponentsMutator(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("component-deps", componentDepsMutator).Parallel()
+}
+
+// A special mutator that runs just prior to the deps mutator to allow the dependencies
+// on component modules to be added so that they can depend directly on a prebuilt
+// module.
+func componentDepsMutator(ctx BottomUpMutatorContext) {
+ if m := ctx.Module(); m.Enabled() {
+ m.ComponentDepsMutator(ctx)
+ }
+}
+
func depsMutator(ctx BottomUpMutatorContext) {
- if m, ok := ctx.Module().(Module); ok && m.Enabled() {
+ if m := ctx.Module(); m.Enabled() {
m.DepsMutator(ctx)
}
}
@@ -403,6 +442,14 @@
b.bp.ReplaceDependencies(name)
}
+func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate blueprint.ReplaceDependencyPredicate) {
+ b.bp.ReplaceDependenciesIf(name, predicate)
+}
+
func (b *bottomUpMutatorContext) AliasVariation(variationName string) {
b.bp.AliasVariation(variationName)
}
+
+func (b *bottomUpMutatorContext) CreateAliasVariation(fromVariationName, toVariationName string) {
+ b.bp.CreateAliasVariation(fromVariationName, toVariationName)
+}
diff --git a/android/neverallow.go b/android/neverallow.go
index 2eba4a9..8b8e1ac 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -56,6 +56,7 @@
AddNeverAllowRules(createJavaDeviceForHostRules()...)
AddNeverAllowRules(createCcSdkVariantRules()...)
AddNeverAllowRules(createUncompressDexRules()...)
+ AddNeverAllowRules(createMakefileGoalRules()...)
}
// Add a NeverAllow rule to the set of rules to apply.
@@ -145,11 +146,18 @@
"prebuilts",
}
- // Core library constraints. The sdk_version: "none" can only be used in core library projects.
+ // Additional whitelisted path only used for ART testing, which needs access to core library
+ // targets. This does not affect the contents of a device image (system, vendor, etc.).
+ var artTests = []string{
+ "art/test",
+ }
+
+ // Core library constraints. The sdk_version: "none" can only be used in core library projects and ART tests.
// Access to core library targets is restricted using visibility rules.
rules := []Rule{
NeverAllow().
NotIn(coreLibraryProjects...).
+ NotIn(artTests...).
With("sdk_version", "none").
WithoutMatcher("name", Regexp("^android_.*stubs_current$")),
}
@@ -186,7 +194,12 @@
// This sometimes works because the APEX modules that contain derive_sdk and
// derive_sdk_prefer32 suppress the platform installation rules, but fails when
// the APEX modules contain the SDK variant and the platform variant still exists.
- "frameworks/base/apex/sdkextensions/derive_sdk",
+ "packages/modules/SdkExtensions/derive_sdk",
+ // These are for apps and shouldn't be used by non-SDK variant modules.
+ "prebuilts/ndk",
+ "tools/test/graphicsbenchmark/apps/sample_app",
+ "tools/test/graphicsbenchmark/functional_tests/java",
+ "vendor/xts/gts-tests/hostsidetests/gamedevicecert/apps/javatests",
}
platformVariantPropertiesAllowedList := []string{
@@ -220,6 +233,15 @@
}
}
+func createMakefileGoalRules() []Rule {
+ return []Rule{
+ NeverAllow().
+ ModuleType("makefile_goal").
+ WithoutMatcher("product_out_path", Regexp("^boot[0-9a-zA-Z.-]*[.]img$")).
+ Because("Only boot images may be imported as a makefile goal."),
+ }
+}
+
func neverallowMutator(ctx BottomUpMutatorContext) {
m, ok := ctx.Module().(Module)
if !ok {
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 45d36a6..56a07dc 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -326,6 +326,20 @@
"module \"outside_art_libraries\": violates neverallow",
},
},
+ {
+ name: "disallowed makefile_goal",
+ fs: map[string][]byte{
+ "Android.bp": []byte(`
+ makefile_goal {
+ name: "foo",
+ product_out_path: "boot/trap.img"
+ }
+ `),
+ },
+ expectedErrors: []string{
+ "Only boot images may be imported as a makefile goal.",
+ },
+ },
}
func TestNeverallow(t *testing.T) {
@@ -350,6 +364,7 @@
ctx.RegisterModuleType("java_library", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule)
ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule)
+ ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule)
ctx.PostDepsMutators(RegisterNeverallowMutator)
ctx.Register(config)
@@ -438,3 +453,22 @@
func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) {
}
+
+type mockMakefileGoalProperties struct {
+ Product_out_path *string
+}
+
+type mockMakefileGoalModule struct {
+ ModuleBase
+ properties mockMakefileGoalProperties
+}
+
+func newMockMakefileGoalModule() Module {
+ m := &mockMakefileGoalModule{}
+ m.AddProperties(&m.properties)
+ InitAndroidModule(m)
+ return m
+}
+
+func (p *mockMakefileGoalModule) GenerateAndroidBuildActions(ModuleContext) {
+}
diff --git a/android/notices.go b/android/notices.go
index bf273b5..07cf3e4 100644
--- a/android/notices.go
+++ b/android/notices.go
@@ -22,7 +22,7 @@
func init() {
pctx.SourcePathVariable("merge_notices", "build/soong/scripts/mergenotice.py")
- pctx.SourcePathVariable("generate_notice", "build/make/tools/generate-notice-files.py")
+ pctx.SourcePathVariable("generate_notice", "build/soong/scripts/generate-notice-files.py")
pctx.HostBinToolVariable("minigzip", "minigzip")
}
diff --git a/android/override_module.go b/android/override_module.go
index 3d8b18b..f8342d5 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -28,6 +28,7 @@
// module based on it.
import (
+ "sort"
"sync"
"github.com/google/blueprint"
@@ -161,6 +162,11 @@
// Should NOT be used in the same mutator as addOverride.
func (b *OverridableModuleBase) getOverrides() []OverrideModule {
+ b.overridesLock.Lock()
+ sort.Slice(b.overrides, func(i, j int) bool {
+ return b.overrides[i].Name() < b.overrides[j].Name()
+ })
+ b.overridesLock.Unlock()
return b.overrides
}
@@ -223,6 +229,11 @@
// next phase.
func overrideModuleDepsMutator(ctx BottomUpMutatorContext) {
if module, ok := ctx.Module().(OverrideModule); ok {
+ base := String(module.getOverrideModuleProperties().Base)
+ if !ctx.OtherModuleExists(base) {
+ ctx.PropertyErrorf("base", "%q is not a valid module name", base)
+ return
+ }
// See if there's a prebuilt module that overrides this override module with prefer flag,
// in which case we call SkipInstall on the corresponding variant later.
ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
diff --git a/android/paths.go b/android/paths.go
index e2e1faf..3825d45 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -43,6 +43,14 @@
var _ PathContext = SingletonContext(nil)
var _ PathContext = ModuleContext(nil)
+// "Null" path context is a minimal path context for a given config.
+type NullPathContext struct {
+ config Config
+}
+
+func (NullPathContext) AddNinjaFileDeps(...string) {}
+func (ctx NullPathContext) Config() Config { return ctx.config }
+
type ModuleInstallPathContext interface {
BaseModuleContext
@@ -53,6 +61,7 @@
InstallInRecovery() bool
InstallInRoot() bool
InstallBypassMake() bool
+ InstallForceOS() (*OsType, *ArchType)
}
var _ ModuleInstallPathContext = ModuleContext(nil)
@@ -77,13 +86,13 @@
// attempts ctx.ModuleErrorf for a better error message first, then falls
// back to ctx.Errorf.
func reportPathError(ctx PathContext, err error) {
- reportPathErrorf(ctx, "%s", err.Error())
+ ReportPathErrorf(ctx, "%s", err.Error())
}
-// reportPathErrorf will register an error with the attached context. It
+// ReportPathErrorf will register an error with the attached context. It
// attempts ctx.ModuleErrorf for a better error message first, then falls
// back to ctx.Errorf.
-func reportPathErrorf(ctx PathContext, format string, args ...interface{}) {
+func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
if mctx, ok := ctx.(moduleErrorf); ok {
mctx.ModuleErrorf(format, args...)
} else if ectx, ok := ctx.(errorfContext); ok {
@@ -146,7 +155,7 @@
if path, ok := p.(genPathProvider); ok {
return path.genPathWithExt(ctx, subdir, ext)
}
- reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleGen(ctx)
}
@@ -156,7 +165,7 @@
if path, ok := p.(objPathProvider); ok {
return path.objPathWithExt(ctx, subdir, ext)
}
- reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleObj(ctx)
}
@@ -167,7 +176,7 @@
if path, ok := p.(resPathProvider); ok {
return path.resPathWithName(ctx, name)
}
- reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleRes(ctx)
}
@@ -371,6 +380,18 @@
}
func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (Paths, error) {
+ excludePaths := func(paths Paths) Paths {
+ if len(expandedExcludes) == 0 {
+ return paths
+ }
+ remainder := make(Paths, 0, len(paths))
+ for _, p := range paths {
+ if !InList(p.String(), expandedExcludes) {
+ remainder = append(remainder, p)
+ }
+ }
+ return remainder
+ }
if m, t := SrcIsModuleWithTag(s); m != "" {
module := ctx.GetDirectDepWithTag(m, sourceOrOutputDepTag(t))
if module == nil {
@@ -381,20 +402,11 @@
if err != nil {
return nil, fmt.Errorf("path dependency %q: %s", s, err)
}
- return outputFiles, nil
+ return excludePaths(outputFiles), nil
} else if t != "" {
return nil, fmt.Errorf("path dependency %q is not an output file producing module", s)
} else if srcProducer, ok := module.(SourceFileProducer); ok {
- moduleSrcs := srcProducer.Srcs()
- for _, e := range expandedExcludes {
- for j := 0; j < len(moduleSrcs); j++ {
- if moduleSrcs[j].String() == e {
- moduleSrcs = append(moduleSrcs[:j], moduleSrcs[j+1:]...)
- j--
- }
- }
- }
- return moduleSrcs, nil
+ return excludePaths(srcProducer.Srcs()), nil
} else {
return nil, fmt.Errorf("path dependency %q is not a source file producing module", s)
}
@@ -404,13 +416,12 @@
} else {
p := pathForModuleSrc(ctx, s)
if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
- reportPathErrorf(ctx, "%s: %s", p, err.Error())
+ ReportPathErrorf(ctx, "%s: %s", p, err.Error())
} else if !exists && !ctx.Config().testAllowNonExistentPaths {
- reportPathErrorf(ctx, "module source path %q does not exist", p)
+ ReportPathErrorf(ctx, "module source path %q does not exist", p)
}
- j := findStringInSlice(p.String(), expandedExcludes)
- if j >= 0 {
+ if InList(p.String(), expandedExcludes) {
return nil, nil
}
return Paths{p}, nil
@@ -434,7 +445,7 @@
}
path := filepath.Clean(p)
if !strings.HasPrefix(path, prefix) {
- reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
+ ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
continue
}
@@ -482,6 +493,24 @@
// FirstUniquePaths returns all unique elements of a Paths, keeping the first copy of each. It
// modifies the Paths slice contents in place, and returns a subslice of the original slice.
func FirstUniquePaths(list Paths) Paths {
+ // 128 was chosen based on BenchmarkFirstUniquePaths results.
+ if len(list) > 128 {
+ return firstUniquePathsMap(list)
+ }
+ return firstUniquePathsList(list)
+}
+
+// SortedUniquePaths returns all unique elements of a Paths in sorted order. It modifies the
+// Paths slice contents in place, and returns a subslice of the original slice.
+func SortedUniquePaths(list Paths) Paths {
+ unique := FirstUniquePaths(list)
+ sort.Slice(unique, func(i, j int) bool {
+ return unique[i].String() < unique[j].String()
+ })
+ return unique
+}
+
+func firstUniquePathsList(list Paths) Paths {
k := 0
outer:
for i := 0; i < len(list); i++ {
@@ -496,13 +525,18 @@
return list[:k]
}
-// SortedUniquePaths returns what its name says
-func SortedUniquePaths(list Paths) Paths {
- unique := FirstUniquePaths(list)
- sort.Slice(unique, func(i, j int) bool {
- return unique[i].String() < unique[j].String()
- })
- return unique
+func firstUniquePathsMap(list Paths) Paths {
+ k := 0
+ seen := make(map[Path]bool, len(list))
+ for i := 0; i < len(list); i++ {
+ if seen[list[i]] {
+ continue
+ }
+ seen[list[i]] = true
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
}
// LastUniquePaths returns all unique elements of a Paths, keeping the last copy of each. It
@@ -767,7 +801,7 @@
}
if pathtools.IsGlob(path.String()) {
- reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+ ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
}
if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
@@ -779,9 +813,9 @@
modCtx.AddMissingDependencies([]string{path.String()})
}
} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
- reportPathErrorf(ctx, "%s: %s", path, err.Error())
+ ReportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists && !ctx.Config().testAllowNonExistentPaths {
- reportPathErrorf(ctx, "source path %q does not exist", path)
+ ReportPathErrorf(ctx, "source path %q does not exist", path)
}
return path
}
@@ -797,7 +831,7 @@
}
if pathtools.IsGlob(path.String()) {
- reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+ ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
return OptionalPath{}
}
@@ -842,17 +876,17 @@
if srcPath, ok := path.(SourcePath); ok {
relDir = srcPath.path
} else {
- reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
+ ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
return OptionalPath{}
}
dir := filepath.Join(p.config.srcDir, p.path, relDir)
// Use Glob so that we are run again if the directory is added.
if pathtools.IsGlob(dir) {
- reportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
+ ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
}
paths, err := ctx.GlobWithDeps(dir, nil)
if err != nil {
- reportPathErrorf(ctx, "glob: %s", err.Error())
+ ReportPathErrorf(ctx, "glob: %s", err.Error())
return OptionalPath{}
}
if len(paths) == 0 {
@@ -886,6 +920,22 @@
var _ Path = OutputPath{}
var _ WritablePath = OutputPath{}
+// toolDepPath is a Path representing a dependency of the build tool.
+type toolDepPath struct {
+ basePath
+}
+
+var _ Path = toolDepPath{}
+
+// pathForBuildToolDep returns a toolDepPath representing the given path string.
+// There is no validation for the path, as it is "trusted": It may fail
+// normal validation checks. For example, it may be an absolute path.
+// Only use this function to construct paths for dependencies of the build
+// tool invocation.
+func pathForBuildToolDep(ctx PathContext, path string) toolDepPath {
+ return toolDepPath{basePath{path, ctx.Config(), ""}}
+}
+
// PathForOutput joins the provided paths and returns an OutputPath that is
// validated to not escape the build dir.
// On error, it will return a usable, but invalid OutputPath, and report a ModuleError.
@@ -927,7 +977,7 @@
// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
if strings.Contains(ext, "/") {
- reportPathErrorf(ctx, "extension %q cannot contain /", ext)
+ ReportPathErrorf(ctx, "extension %q cannot contain /", ext)
}
ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
ret.rel = pathtools.ReplaceExtension(p.rel, ext)
@@ -980,10 +1030,10 @@
}
return nil
} else if len(paths) == 0 {
- reportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
+ ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
return nil
} else if len(paths) > 1 {
- reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
+ ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
}
return paths[0]
}
@@ -1227,22 +1277,51 @@
// PathForModuleInstall returns a Path representing the install path for the
// module appended with paths...
func PathForModuleInstall(ctx ModuleInstallPathContext, pathComponents ...string) InstallPath {
+ os := ctx.Os()
+ arch := ctx.Arch().ArchType
+ forceOS, forceArch := ctx.InstallForceOS()
+ if forceOS != nil {
+ os = *forceOS
+ }
+ if forceArch != nil {
+ arch = *forceArch
+ }
+ partition := modulePartition(ctx, os)
+
+ ret := pathForInstall(ctx, os, arch, partition, ctx.Debug(), pathComponents...)
+
+ if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
+ ret = ret.ToMakePath()
+ }
+
+ return ret
+}
+
+func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, debug bool,
+ pathComponents ...string) InstallPath {
+
var outPaths []string
- if ctx.Device() {
- partition := modulePartition(ctx)
+
+ if os.Class == Device {
outPaths = []string{"target", "product", ctx.Config().DeviceName(), partition}
} else {
- switch ctx.Os() {
- case Linux:
- outPaths = []string{"host", "linux-x86"}
- case LinuxBionic:
- // TODO: should this be a separate top level, or shared with linux-x86?
- outPaths = []string{"host", "linux_bionic-x86"}
- default:
- outPaths = []string{"host", ctx.Os().String() + "-x86"}
+ osName := os.String()
+ if os == Linux {
+ // instead of linux_glibc
+ osName = "linux"
}
+ // SOONG_HOST_OUT is set to out/host/$(HOST_OS)-$(HOST_PREBUILT_ARCH)
+ // and HOST_PREBUILT_ARCH is forcibly set to x86 even on x86_64 hosts. We don't seem
+ // to have a plan to fix it (see the comment in build/make/core/envsetup.mk).
+ // Let's keep using x86 for the existing cases until we have a need to support
+ // other architectures.
+ archName := arch.String()
+ if os.Class == Host && (arch == X86_64 || arch == Common) {
+ archName = "x86"
+ }
+ outPaths = []string{"host", osName + "-" + archName, partition}
}
- if ctx.Debug() {
+ if debug {
outPaths = append([]string{"debug"}, outPaths...)
}
outPaths = append(outPaths, pathComponents...)
@@ -1253,9 +1332,6 @@
}
ret := InstallPath{basePath{path, ctx.Config(), ""}, ""}
- if ctx.InstallBypassMake() && ctx.Config().EmbeddedInMake() {
- ret = ret.ToMakePath()
- }
return ret
}
@@ -1283,47 +1359,76 @@
return "/" + rel
}
-func modulePartition(ctx ModuleInstallPathContext) string {
+func modulePartition(ctx ModuleInstallPathContext, os OsType) string {
var partition string
- if ctx.InstallInData() {
- partition = "data"
- } else if ctx.InstallInTestcases() {
+ if ctx.InstallInTestcases() {
+ // "testcases" install directory can be used for host or device modules.
partition = "testcases"
- } else if ctx.InstallInRamdisk() {
- if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
- partition = "recovery/root/first_stage_ramdisk"
+ } else if os.Class == Device {
+ if ctx.InstallInData() {
+ partition = "data"
+ } else if ctx.InstallInRamdisk() {
+ if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() {
+ partition = "recovery/root/first_stage_ramdisk"
+ } else {
+ partition = "ramdisk"
+ }
+ if !ctx.InstallInRoot() {
+ partition += "/system"
+ }
+ } else if ctx.InstallInRecovery() {
+ if ctx.InstallInRoot() {
+ partition = "recovery/root"
+ } else {
+ // the layout of recovery partion is the same as that of system partition
+ partition = "recovery/root/system"
+ }
+ } else if ctx.SocSpecific() {
+ partition = ctx.DeviceConfig().VendorPath()
+ } else if ctx.DeviceSpecific() {
+ partition = ctx.DeviceConfig().OdmPath()
+ } else if ctx.ProductSpecific() {
+ partition = ctx.DeviceConfig().ProductPath()
+ } else if ctx.SystemExtSpecific() {
+ partition = ctx.DeviceConfig().SystemExtPath()
+ } else if ctx.InstallInRoot() {
+ partition = "root"
} else {
- partition = "ramdisk"
+ partition = "system"
}
- if !ctx.InstallInRoot() {
- partition += "/system"
+ if ctx.InstallInSanitizerDir() {
+ partition = "data/asan/" + partition
}
- } else if ctx.InstallInRecovery() {
- if ctx.InstallInRoot() {
- partition = "recovery/root"
- } else {
- // the layout of recovery partion is the same as that of system partition
- partition = "recovery/root/system"
- }
- } else if ctx.SocSpecific() {
- partition = ctx.DeviceConfig().VendorPath()
- } else if ctx.DeviceSpecific() {
- partition = ctx.DeviceConfig().OdmPath()
- } else if ctx.ProductSpecific() {
- partition = ctx.DeviceConfig().ProductPath()
- } else if ctx.SystemExtSpecific() {
- partition = ctx.DeviceConfig().SystemExtPath()
- } else if ctx.InstallInRoot() {
- partition = "root"
- } else {
- partition = "system"
- }
- if ctx.InstallInSanitizerDir() {
- partition = "data/asan/" + partition
}
return partition
}
+type InstallPaths []InstallPath
+
+// Paths returns the InstallPaths as a Paths
+func (p InstallPaths) Paths() Paths {
+ if p == nil {
+ return nil
+ }
+ ret := make(Paths, len(p))
+ for i, path := range p {
+ ret[i] = path
+ }
+ return ret
+}
+
+// Strings returns the string forms of the install paths.
+func (p InstallPaths) Strings() []string {
+ if p == nil {
+ return nil
+ }
+ ret := make([]string, len(p))
+ for i, path := range p {
+ ret[i] = path.String()
+ }
+ return ret
+}
+
// validateSafePath validates a path that we trust (may contain ninja variables).
// Ensures that each path component does not attempt to leave its component.
func validateSafePath(pathComponents ...string) (string, error) {
@@ -1353,7 +1458,7 @@
func PathForPhony(ctx PathContext, phony string) WritablePath {
if strings.ContainsAny(phony, "$/") {
- reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
+ ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
}
return PhonyPath{basePath{phony, ctx.Config(), ""}}
}
@@ -1419,7 +1524,7 @@
func Rel(ctx PathContext, basePath string, targetPath string) string {
rel, isRel := MaybeRel(ctx, basePath, targetPath)
if !isRel {
- reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
+ ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
return ""
}
return rel
@@ -1461,3 +1566,15 @@
}
return filepath.Join(absSrcDir, path)
}
+
+// A DataPath represents the path of a file to be used as data, for example
+// a test library to be installed alongside a test.
+// The data file should be installed (copied from `<SrcPath>`) to
+// `<install_root>/<RelativeInstallPath>/<filename>`, or
+// `<install_root>/<filename>` if RelativeInstallPath is empty.
+type DataPath struct {
+ // The path of the data file that should be copied into the data directory
+ SrcPath Path
+ // The install path of the data file, relative to the install root.
+ RelativeInstallPath string
+}
diff --git a/android/paths_test.go b/android/paths_test.go
index 7a32026..d099f65 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -18,6 +18,7 @@
"errors"
"fmt"
"reflect"
+ "strconv"
"strings"
"testing"
@@ -205,6 +206,8 @@
inRamdisk bool
inRecovery bool
inRoot bool
+ forceOS *OsType
+ forceArch *ArchType
}
func (m moduleInstallPathContextImpl) Config() Config {
@@ -241,6 +244,10 @@
return false
}
+func (m moduleInstallPathContextImpl) InstallForceOS() (*OsType, *ArchType) {
+ return m.forceOS, m.forceArch
+}
+
func pathTestConfig(buildDir string) Config {
return TestConfig(buildDir, nil, "", nil)
}
@@ -248,8 +255,8 @@
func TestPathForModuleInstall(t *testing.T) {
testConfig := pathTestConfig("")
- hostTarget := Target{Os: Linux}
- deviceTarget := Target{Os: Android}
+ hostTarget := Target{Os: Linux, Arch: Arch{ArchType: X86}}
+ deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
testCases := []struct {
name string
@@ -598,6 +605,41 @@
},
in: []string{"nativetest", "my_test"},
out: "target/product/test_device/data/asan/data/nativetest/my_test",
+ }, {
+ name: "device testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inTestcases: true,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "target/product/test_device/testcases/my_test/my_test_bin",
+ }, {
+ name: "host testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: hostTarget.Os,
+ target: hostTarget,
+ },
+ inTestcases: true,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "host/linux-x86/testcases/my_test/my_test_bin",
+ }, {
+ name: "forced host testcases",
+ ctx: &moduleInstallPathContextImpl{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ inTestcases: true,
+ forceOS: &Linux,
+ forceArch: &X86,
+ },
+ in: []string{"my_test", "my_test_bin"},
+ out: "host/linux-x86/testcases/my_test/my_test_bin",
},
}
@@ -1051,6 +1093,21 @@
rels: []string{"gen/c"},
},
{
+ name: "output file provider with exclude",
+ bp: `
+ test {
+ name: "foo",
+ srcs: [":b", ":c"],
+ exclude_srcs: [":c"]
+ }
+ output_file_provider {
+ name: "c",
+ outs: ["gen/c"],
+ }`,
+ srcs: []string{buildDir + "/.intermediates/ofp/b/gen/b"},
+ rels: []string{"gen/b"},
+ },
+ {
name: "special characters glob",
bp: `
test {
@@ -1216,3 +1273,51 @@
// out/system/framework/boot.art out/system/framework/oat/arm/boot.vdex
// boot.art oat/arm/boot.vdex
}
+
+func BenchmarkFirstUniquePaths(b *testing.B) {
+ implementations := []struct {
+ name string
+ f func(Paths) Paths
+ }{
+ {
+ name: "list",
+ f: firstUniquePathsList,
+ },
+ {
+ name: "map",
+ f: firstUniquePathsMap,
+ },
+ }
+ const maxSize = 1024
+ uniquePaths := make(Paths, maxSize)
+ for i := range uniquePaths {
+ uniquePaths[i] = PathForTesting(strconv.Itoa(i))
+ }
+ samePath := make(Paths, maxSize)
+ for i := range samePath {
+ samePath[i] = uniquePaths[0]
+ }
+
+ f := func(b *testing.B, imp func(Paths) Paths, paths Paths) {
+ for i := 0; i < b.N; i++ {
+ b.ReportAllocs()
+ paths = append(Paths(nil), paths...)
+ imp(paths)
+ }
+ }
+
+ for n := 1; n <= maxSize; n <<= 1 {
+ b.Run(strconv.Itoa(n), func(b *testing.B) {
+ for _, implementation := range implementations {
+ b.Run(implementation.name, func(b *testing.B) {
+ b.Run("same", func(b *testing.B) {
+ f(b, implementation.f, samePath[:n])
+ })
+ b.Run("unique", func(b *testing.B) {
+ f(b, implementation.f, uniquePaths[:n])
+ })
+ })
+ }
+ })
+ }
+}
diff --git a/android/prebuilt.go b/android/prebuilt.go
index ee4a13a..734871b 100644
--- a/android/prebuilt.go
+++ b/android/prebuilt.go
@@ -30,6 +30,16 @@
ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators)
}
+// Marks a dependency tag as possibly preventing a reference to a source from being
+// replaced with the prebuilt.
+type ReplaceSourceWithPrebuilt interface {
+ blueprint.DependencyTag
+
+ // Return true if the dependency defined by this tag should be replaced with the
+ // prebuilt.
+ ReplaceSourceWithPrebuilt() bool
+}
+
type prebuiltDependencyTag struct {
blueprint.BaseDependencyTag
}
@@ -52,6 +62,9 @@
SourceExists bool `blueprint:"mutated"`
UsePrebuilt bool `blueprint:"mutated"`
+
+ // Set if the module has been renamed to remove the "prebuilt_" prefix.
+ PrebuiltRenamedToSource bool `blueprint:"mutated"`
}
type Prebuilt struct {
@@ -188,25 +201,38 @@
}
func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
- ctx.BottomUp("prebuilts", PrebuiltMutator).Parallel()
+ ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
}
func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
+ ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
}
-// PrebuiltMutator ensures that there is always a module with an undecorated name, and marks
-// prebuilt modules that have both a prebuilt and a source module.
-func PrebuiltMutator(ctx BottomUpMutatorContext) {
+// PrebuiltRenameMutator ensures that there always is a module with an
+// undecorated name.
+func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Prebuilt() != nil {
- p := m.Prebuilt()
name := m.base().BaseModuleName()
- if ctx.OtherModuleExists(name) {
- ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
- p.properties.SourceExists = true
- } else {
+ if !ctx.OtherModuleExists(name) {
ctx.Rename(name)
+ m.Prebuilt().properties.PrebuiltRenamedToSource = true
+ }
+ }
+}
+
+// PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
+// corresponding source module, if one exists for the same variant.
+func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
+ if m, ok := ctx.Module().(PrebuiltInterface); ok && m.Enabled() && m.Prebuilt() != nil {
+ p := m.Prebuilt()
+ if !p.properties.PrebuiltRenamedToSource {
+ name := m.base().BaseModuleName()
+ if ctx.OtherModuleReverseDependencyVariantExists(name) {
+ ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
+ p.properties.SourceExists = true
+ }
}
}
}
@@ -227,7 +253,7 @@
p := m.(PrebuiltInterface).Prebuilt()
if p.usePrebuilt(ctx, s) {
p.properties.UsePrebuilt = true
- s.SkipInstall()
+ s.ReplacedByPrebuilt()
}
})
}
@@ -244,7 +270,13 @@
name := m.base().BaseModuleName()
if p.properties.UsePrebuilt {
if p.properties.SourceExists {
- ctx.ReplaceDependencies(name)
+ ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+ if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
+ return t.ReplaceSourceWithPrebuilt()
+ }
+
+ return true
+ })
}
} else {
m.SkipInstall()
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
new file mode 100644
index 0000000..1dcf199
--- /dev/null
+++ b/android/prebuilt_build_tool.go
@@ -0,0 +1,94 @@
+// Copyright 2020 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 android
+
+func init() {
+ RegisterModuleType("prebuilt_build_tool", prebuiltBuildToolFactory)
+}
+
+type prebuiltBuildToolProperties struct {
+ // Source file to be executed for this build tool
+ Src *string `android:"path,arch_variant"`
+
+ // Extra files that should trigger rules using this tool to rebuild
+ Deps []string `android:"path,arch_variant"`
+
+ // Create a make variable with the specified name that contains the path to
+ // this prebuilt built tool, relative to the root of the source tree.
+ Export_to_make_var *string
+}
+
+type prebuiltBuildTool struct {
+ ModuleBase
+ prebuilt Prebuilt
+
+ properties prebuiltBuildToolProperties
+
+ toolPath OptionalPath
+}
+
+func (t *prebuiltBuildTool) Name() string {
+ return t.prebuilt.Name(t.ModuleBase.Name())
+}
+
+func (t *prebuiltBuildTool) Prebuilt() *Prebuilt {
+ return &t.prebuilt
+}
+
+func (t *prebuiltBuildTool) DepsMutator(ctx BottomUpMutatorContext) {
+ if t.properties.Src == nil {
+ ctx.PropertyErrorf("src", "missing prebuilt source file")
+ }
+}
+
+func (t *prebuiltBuildTool) GenerateAndroidBuildActions(ctx ModuleContext) {
+ sourcePath := t.prebuilt.SingleSourcePath(ctx)
+ installedPath := PathForModuleOut(ctx, t.ModuleBase.Name())
+ deps := PathsForModuleSrc(ctx, t.properties.Deps)
+
+ ctx.Build(pctx, BuildParams{
+ Rule: Symlink,
+ Output: installedPath,
+ Input: sourcePath,
+ Implicits: deps,
+ Args: map[string]string{
+ "fromPath": "$$PWD/" + sourcePath.String(),
+ },
+ })
+
+ t.toolPath = OptionalPathForPath(installedPath)
+}
+
+func (t *prebuiltBuildTool) MakeVars(ctx MakeVarsModuleContext) {
+ if makeVar := String(t.properties.Export_to_make_var); makeVar != "" {
+ ctx.StrictRaw(makeVar, t.toolPath.String())
+ }
+}
+
+func (t *prebuiltBuildTool) HostToolPath() OptionalPath {
+ return t.toolPath
+}
+
+var _ HostToolProvider = &prebuiltBuildTool{}
+
+// prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
+// in genrules with the "tools" property.
+func prebuiltBuildToolFactory() Module {
+ module := &prebuiltBuildTool{}
+ module.AddProperties(&module.properties)
+ InitSingleSourcePrebuiltModule(module, &module.properties, "Src")
+ InitAndroidArchModule(module, HostSupportedNoCross, MultilibFirst)
+ return module
+}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index e8c5121..6c3cd9e 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -22,9 +22,10 @@
)
var prebuiltsTests = []struct {
- name string
- modules string
- prebuilt bool
+ name string
+ replaceBp bool // modules is added to default bp boilerplate if false.
+ modules string
+ prebuilt []OsType
}{
{
name: "no prebuilt",
@@ -32,7 +33,7 @@
source {
name: "bar",
}`,
- prebuilt: false,
+ prebuilt: nil,
},
{
name: "no source prebuilt not preferred",
@@ -42,7 +43,7 @@
prefer: false,
srcs: ["prebuilt_file"],
}`,
- prebuilt: true,
+ prebuilt: []OsType{Android, BuildOs},
},
{
name: "no source prebuilt preferred",
@@ -52,7 +53,7 @@
prefer: true,
srcs: ["prebuilt_file"],
}`,
- prebuilt: true,
+ prebuilt: []OsType{Android, BuildOs},
},
{
name: "prebuilt not preferred",
@@ -66,7 +67,7 @@
prefer: false,
srcs: ["prebuilt_file"],
}`,
- prebuilt: false,
+ prebuilt: nil,
},
{
name: "prebuilt preferred",
@@ -80,7 +81,7 @@
prefer: true,
srcs: ["prebuilt_file"],
}`,
- prebuilt: true,
+ prebuilt: []OsType{Android, BuildOs},
},
{
name: "prebuilt no file not preferred",
@@ -93,7 +94,7 @@
name: "bar",
prefer: false,
}`,
- prebuilt: false,
+ prebuilt: nil,
},
{
name: "prebuilt no file preferred",
@@ -106,7 +107,7 @@
name: "bar",
prefer: true,
}`,
- prebuilt: false,
+ prebuilt: nil,
},
{
name: "prebuilt file from filegroup preferred",
@@ -120,7 +121,40 @@
prefer: true,
srcs: [":fg"],
}`,
- prebuilt: true,
+ prebuilt: []OsType{Android, BuildOs},
+ },
+ {
+ name: "prebuilt module for device only",
+ modules: `
+ source {
+ name: "bar",
+ }
+
+ prebuilt {
+ name: "bar",
+ host_supported: false,
+ prefer: true,
+ srcs: ["prebuilt_file"],
+ }`,
+ prebuilt: []OsType{Android},
+ },
+ {
+ name: "prebuilt file for host only",
+ modules: `
+ source {
+ name: "bar",
+ }
+
+ prebuilt {
+ name: "bar",
+ prefer: true,
+ target: {
+ host: {
+ srcs: ["prebuilt_file"],
+ },
+ },
+ }`,
+ prebuilt: []OsType{BuildOs},
},
{
name: "prebuilt override not preferred",
@@ -139,7 +173,7 @@
prefer: false,
srcs: ["prebuilt_file"],
}`,
- prebuilt: false,
+ prebuilt: nil,
},
{
name: "prebuilt override preferred",
@@ -158,7 +192,72 @@
prefer: true,
srcs: ["prebuilt_file"],
}`,
- prebuilt: true,
+ prebuilt: []OsType{Android, BuildOs},
+ },
+ {
+ name: "prebuilt including default-disabled OS",
+ replaceBp: true,
+ modules: `
+ source {
+ name: "foo",
+ deps: [":bar"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ source {
+ name: "bar",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ prebuilt {
+ name: "bar",
+ prefer: true,
+ srcs: ["prebuilt_file"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }`,
+ prebuilt: []OsType{Android, BuildOs, Windows},
+ },
+ {
+ name: "fall back to source for default-disabled OS",
+ replaceBp: true,
+ modules: `
+ source {
+ name: "foo",
+ deps: [":bar"],
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ source {
+ name: "bar",
+ target: {
+ windows: {
+ enabled: true,
+ },
+ },
+ }
+
+ prebuilt {
+ name: "bar",
+ prefer: true,
+ srcs: ["prebuilt_file"],
+ }`,
+ prebuilt: []OsType{Android, BuildOs},
},
}
@@ -170,15 +269,26 @@
for _, test := range prebuiltsTests {
t.Run(test.name, func(t *testing.T) {
- bp := `
- source {
- name: "foo",
- deps: [":bar"],
- }
- ` + test.modules
- config := TestConfig(buildDir, nil, bp, fs)
+ bp := test.modules
+ if !test.replaceBp {
+ bp = bp + `
+ source {
+ name: "foo",
+ deps: [":bar"],
+ }`
+ }
+ config := TestArchConfig(buildDir, nil, bp, fs)
- ctx := NewTestContext()
+ // Add windows to the target list to test the logic when a variant is
+ // disabled by default.
+ if !Windows.DefaultDisabled {
+ t.Errorf("windows is assumed to be disabled by default")
+ }
+ config.config.Targets[Windows] = []Target{
+ {Windows, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", ""},
+ }
+
+ ctx := NewTestArchContext()
registerTestPrebuiltBuildComponents(ctx)
ctx.RegisterModuleType("filegroup", FileGroupFactory)
ctx.Register(config)
@@ -188,61 +298,83 @@
_, errs = ctx.PrepareBuildActions(config)
FailIfErrored(t, errs)
- foo := ctx.ModuleForTests("foo", "")
+ for _, variant := range ctx.ModuleVariantsForTests("foo") {
+ foo := ctx.ModuleForTests("foo", variant)
+ t.Run(foo.Module().Target().Os.String(), func(t *testing.T) {
+ var dependsOnSourceModule, dependsOnPrebuiltModule bool
+ ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
+ if _, ok := m.(*sourceModule); ok {
+ dependsOnSourceModule = true
+ }
+ if p, ok := m.(*prebuiltModule); ok {
+ dependsOnPrebuiltModule = true
+ if !p.Prebuilt().properties.UsePrebuilt {
+ t.Errorf("dependency on prebuilt module not marked used")
+ }
+ }
+ })
- var dependsOnSourceModule, dependsOnPrebuiltModule bool
- ctx.VisitDirectDeps(foo.Module(), func(m blueprint.Module) {
- if _, ok := m.(*sourceModule); ok {
- dependsOnSourceModule = true
- }
- if p, ok := m.(*prebuiltModule); ok {
- dependsOnPrebuiltModule = true
- if !p.Prebuilt().properties.UsePrebuilt {
- t.Errorf("dependency on prebuilt module not marked used")
+ moduleIsDisabled := !foo.Module().Enabled()
+ deps := foo.Module().(*sourceModule).deps
+ if moduleIsDisabled {
+ if len(deps) > 0 {
+ t.Errorf("disabled module got deps: %v", deps)
+ }
+ } else {
+ if len(deps) != 1 {
+ t.Errorf("deps does not have single path, but is %v", deps)
+ }
}
- }
- })
- deps := foo.Module().(*sourceModule).deps
- if deps == nil || len(deps) != 1 {
- t.Errorf("deps does not have single path, but is %v", deps)
- }
- var usingSourceFile, usingPrebuiltFile bool
- if deps[0].String() == "source_file" {
- usingSourceFile = true
- }
- if deps[0].String() == "prebuilt_file" {
- usingPrebuiltFile = true
- }
+ var usingSourceFile, usingPrebuiltFile bool
+ if len(deps) > 0 && deps[0].String() == "source_file" {
+ usingSourceFile = true
+ }
+ if len(deps) > 0 && deps[0].String() == "prebuilt_file" {
+ usingPrebuiltFile = true
+ }
- if test.prebuilt {
- if !dependsOnPrebuiltModule {
- t.Errorf("doesn't depend on prebuilt module")
- }
- if !usingPrebuiltFile {
- t.Errorf("doesn't use prebuilt_file")
- }
+ prebuilt := false
+ for _, os := range test.prebuilt {
+ if os == foo.Module().Target().Os {
+ prebuilt = true
+ }
+ }
- if dependsOnSourceModule {
- t.Errorf("depends on source module")
- }
- if usingSourceFile {
- t.Errorf("using source_file")
- }
- } else {
- if dependsOnPrebuiltModule {
- t.Errorf("depends on prebuilt module")
- }
- if usingPrebuiltFile {
- t.Errorf("using prebuilt_file")
- }
+ if prebuilt {
+ if moduleIsDisabled {
+ t.Errorf("dependent module for prebuilt is disabled")
+ }
- if !dependsOnSourceModule {
- t.Errorf("doesn't depend on source module")
- }
- if !usingSourceFile {
- t.Errorf("doesn't use source_file")
- }
+ if !dependsOnPrebuiltModule {
+ t.Errorf("doesn't depend on prebuilt module")
+ }
+ if !usingPrebuiltFile {
+ t.Errorf("doesn't use prebuilt_file")
+ }
+
+ if dependsOnSourceModule {
+ t.Errorf("depends on source module")
+ }
+ if usingSourceFile {
+ t.Errorf("using source_file")
+ }
+ } else if !moduleIsDisabled {
+ if dependsOnPrebuiltModule {
+ t.Errorf("depends on prebuilt module")
+ }
+ if usingPrebuiltFile {
+ t.Errorf("using prebuilt_file")
+ }
+
+ if !dependsOnSourceModule {
+ t.Errorf("doesn't depend on source module")
+ }
+ if !usingSourceFile {
+ t.Errorf("doesn't use source_file")
+ }
+ }
+ })
}
})
}
@@ -261,7 +393,7 @@
ModuleBase
prebuilt Prebuilt
properties struct {
- Srcs []string `android:"path"`
+ Srcs []string `android:"path,arch_variant"`
}
src Path
}
@@ -270,7 +402,7 @@
m := &prebuiltModule{}
m.AddProperties(&m.properties)
InitPrebuiltModule(m, &m.properties.Srcs)
- InitAndroidModule(m)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
return m
}
@@ -298,7 +430,7 @@
}
type sourceModuleProperties struct {
- Deps []string `android:"path"`
+ Deps []string `android:"path,arch_variant"`
}
type sourceModule struct {
@@ -314,7 +446,7 @@
func newSourceModule() Module {
m := &sourceModule{}
m.AddProperties(&m.properties)
- InitAndroidModule(m)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
InitOverridableModule(m, nil)
return m
}
@@ -345,7 +477,7 @@
m := &overrideSourceModule{}
m.AddProperties(&sourceModuleProperties{})
- InitAndroidModule(m)
+ InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
InitOverrideModule(m)
return m
}
diff --git a/android/sdk.go b/android/sdk.go
index e823106..9ea7ff4 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -34,10 +34,8 @@
RequiredSdks() SdkRefs
}
-// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
-// built with SDK
-type SdkAware interface {
- Module
+// Provided to improve code navigation with the IDE.
+type sdkAwareWithoutModule interface {
RequiredSdks
sdkBase() *SdkBase
@@ -48,6 +46,13 @@
BuildWithSdks(sdks SdkRefs)
}
+// SdkAware is the interface that must be supported by any module to become a member of SDK or to be
+// built with SDK
+type SdkAware interface {
+ Module
+ sdkAwareWithoutModule
+}
+
// SdkRef refers to a version of an SDK
type SdkRef struct {
Name string
@@ -266,6 +271,9 @@
SdkMemberType() SdkMemberType
}
+var _ SdkMemberTypeDependencyTag = (*sdkMemberDependencyTag)(nil)
+var _ ReplaceSourceWithPrebuilt = (*sdkMemberDependencyTag)(nil)
+
type sdkMemberDependencyTag struct {
blueprint.BaseDependencyTag
memberType SdkMemberType
@@ -275,6 +283,12 @@
return t.memberType
}
+// Prevent dependencies from the sdk/module_exports onto their members from being
+// replaced with a preferred prebuilt.
+func (t *sdkMemberDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
func DependencyTagForSdkMemberType(memberType SdkMemberType) SdkMemberTypeDependencyTag {
return &sdkMemberDependencyTag{memberType: memberType}
}
@@ -313,6 +327,12 @@
// SdkAware and be added with an SdkMemberTypeDependencyTag tag.
HasTransitiveSdkMembers() 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() 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
@@ -375,6 +395,7 @@
PropertyName string
SupportsSdk bool
TransitiveSdkMembers bool
+ HostOsDependent bool
}
func (b *SdkMemberTypeBase) SdkPropertyName() string {
@@ -389,6 +410,10 @@
return b.TransitiveSdkMembers
}
+func (b *SdkMemberTypeBase) IsHostOsDependent() bool {
+ return b.HostOsDependent
+}
+
// Encapsulates the information about registered SdkMemberTypes.
type SdkMemberTypesRegistry struct {
// The list of types sorted by property name.
@@ -457,8 +482,7 @@
// Base structure for all implementations of SdkMemberProperties.
//
-// Contains common properties that apply across many different member types. These
-// are not affected by the optimization to extract common values.
+// Contains common properties that apply across many different member types.
type SdkMemberPropertiesBase struct {
// The number of unique os types supported by the member variants.
//
@@ -480,9 +504,7 @@
Os OsType `sdk:"keep"`
// The setting to use for the compile_multilib property.
- //
- // This property is set after optimization so there is no point in trying to optimize it.
- Compile_multilib string `sdk:"keep"`
+ Compile_multilib string `android:"arch_variant"`
}
// The os prefix to use for any file paths in the sdk.
diff --git a/android/test_suites.go b/android/test_suites.go
new file mode 100644
index 0000000..34e487e
--- /dev/null
+++ b/android/test_suites.go
@@ -0,0 +1,75 @@
+// Copyright 2020 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 android
+
+func init() {
+ RegisterSingletonType("testsuites", testSuiteFilesFactory)
+}
+
+func testSuiteFilesFactory() Singleton {
+ return &testSuiteFiles{}
+}
+
+type testSuiteFiles struct {
+ robolectric WritablePath
+}
+
+type TestSuiteModule interface {
+ Module
+ TestSuites() []string
+}
+
+func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) {
+ files := make(map[string]map[string]InstallPaths)
+
+ ctx.VisitAllModules(func(m Module) {
+ if tsm, ok := m.(TestSuiteModule); ok {
+ for _, testSuite := range tsm.TestSuites() {
+ if files[testSuite] == nil {
+ files[testSuite] = make(map[string]InstallPaths)
+ }
+ name := ctx.ModuleName(m)
+ files[testSuite][name] = append(files[testSuite][name], tsm.filesToInstall()...)
+ }
+ }
+ })
+
+ t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
+
+ ctx.Phony("robolectric-tests", t.robolectric)
+}
+
+func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
+ ctx.DistForGoal("robolectric-tests", t.robolectric)
+}
+
+func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
+ var installedPaths InstallPaths
+ for _, module := range SortedStringKeys(files) {
+ installedPaths = append(installedPaths, files[module]...)
+ }
+ testCasesDir := pathForInstall(ctx, BuildOs, X86, "testcases", false).ToMakePath()
+
+ outputFile := PathForOutput(ctx, "packaging", "robolectric-tests.zip")
+ rule := NewRuleBuilder()
+ rule.Command().BuiltTool(ctx, "soong_zip").
+ FlagWithOutput("-o ", outputFile).
+ FlagWithArg("-P ", "host/testcases").
+ FlagWithArg("-C ", testCasesDir.String()).
+ FlagWithRspFileInputList("-r ", installedPaths.Paths())
+ rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip")
+
+ return outputFile
+}
diff --git a/android/testing.go b/android/testing.go
index 90989ef..8ea4168 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -18,6 +18,7 @@
"fmt"
"path/filepath"
"regexp"
+ "sort"
"strings"
"testing"
@@ -118,13 +119,24 @@
if module == nil {
// find all the modules that do exist
- allModuleNames := []string{}
+ var allModuleNames []string
+ var allVariants []string
ctx.VisitAllModules(func(m blueprint.Module) {
- allModuleNames = append(allModuleNames, m.(Module).Name()+"("+ctx.ModuleSubDir(m)+")")
+ allModuleNames = append(allModuleNames, ctx.ModuleName(m))
+ if ctx.ModuleName(m) == name {
+ allVariants = append(allVariants, ctx.ModuleSubDir(m))
+ }
})
+ sort.Strings(allModuleNames)
+ sort.Strings(allVariants)
- panic(fmt.Errorf("failed to find module %q variant %q."+
- "\nall modules: %v", name, variant, allModuleNames))
+ if len(allVariants) == 0 {
+ panic(fmt.Errorf("failed to find module %q. All modules:\n %s",
+ name, strings.Join(allModuleNames, "\n ")))
+ } else {
+ panic(fmt.Errorf("failed to find module %q variant %q. All variants:\n %s",
+ name, variant, strings.Join(allVariants, "\n ")))
+ }
}
return TestingModule{module}
@@ -175,19 +187,21 @@
}
}
-func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
+func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) {
+ var searchedRules []string
for _, p := range provider.BuildParamsForTests() {
+ searchedRules = append(searchedRules, p.Rule.String())
if strings.Contains(p.Rule.String(), rule) {
- return newTestingBuildParams(provider, p)
+ return newTestingBuildParams(provider, p), searchedRules
}
}
- return TestingBuildParams{}
+ return TestingBuildParams{}, searchedRules
}
func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
- p := maybeBuildParamsFromRule(provider, rule)
+ p, searchRules := maybeBuildParamsFromRule(provider, rule)
if p.Rule == nil {
- panic(fmt.Errorf("couldn't find rule %q", rule))
+ panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules))
}
return p
}
@@ -263,7 +277,8 @@
// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
// BuildParams if no rule is found.
func (m TestingModule) MaybeRule(rule string) TestingBuildParams {
- return maybeBuildParamsFromRule(m.module, rule)
+ r, _ := maybeBuildParamsFromRule(m.module, rule)
+ return r
}
// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
@@ -316,7 +331,8 @@
// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
// BuildParams if no rule is found.
func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams {
- return maybeBuildParamsFromRule(s.provider, rule)
+ r, _ := maybeBuildParamsFromRule(s.provider, rule)
+ return r
}
// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
@@ -382,7 +398,7 @@
if !found {
t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs))
for i, err := range errs {
- t.Errorf("errs[%d] = %s", i, err)
+ t.Errorf("errs[%d] = %q", i, err)
}
}
}
diff --git a/android/util.go b/android/util.go
index ade851e..65c5f1b 100644
--- a/android/util.go
+++ b/android/util.go
@@ -79,6 +79,20 @@
return string(ret)
}
+func SortedIntKeys(m interface{}) []int {
+ v := reflect.ValueOf(m)
+ if v.Kind() != reflect.Map {
+ panic(fmt.Sprintf("%#v is not a map", m))
+ }
+ keys := v.MapKeys()
+ s := make([]int, 0, len(keys))
+ for _, key := range keys {
+ s = append(s, int(key.Int()))
+ }
+ sort.Ints(s)
+ return s
+}
+
func SortedStringKeys(m interface{}) []string {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Map {
@@ -141,6 +155,16 @@
return false
}
+// Returns true if any string in the given list has the given suffix.
+func SuffixInList(list []string, suffix string) bool {
+ for _, s := range list {
+ if strings.HasSuffix(s, suffix) {
+ return true
+ }
+ }
+ return false
+}
+
// IndexListPred returns the index of the element which in the given `list` satisfying the predicate, or -1 if there is no such element.
func IndexListPred(pred func(s string) bool, list []string) int {
for i, l := range list {
@@ -193,6 +217,14 @@
// FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func FirstUniqueStrings(list []string) []string {
+ // 128 was chosen based on BenchmarkFirstUniqueStrings results.
+ if len(list) > 128 {
+ return firstUniqueStringsMap(list)
+ }
+ return firstUniqueStringsList(list)
+}
+
+func firstUniqueStringsList(list []string) []string {
k := 0
outer:
for i := 0; i < len(list); i++ {
@@ -207,6 +239,20 @@
return list[:k]
}
+func firstUniqueStringsMap(list []string) []string {
+ k := 0
+ seen := make(map[string]bool, len(list))
+ for i := 0; i < len(list); i++ {
+ if seen[list[i]] {
+ continue
+ }
+ seen[list[i]] = true
+ list[k] = list[i]
+ k++
+ }
+ return list[:k]
+}
+
// LastUniqueStrings returns all unique elements of a slice of strings, keeping the last copy of
// each. It modifies the slice contents in place, and returns a subslice of the original slice.
func LastUniqueStrings(list []string) []string {
diff --git a/android/util_test.go b/android/util_test.go
index 1f9ca36..25b52ca 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -17,6 +17,7 @@
import (
"fmt"
"reflect"
+ "strconv"
"testing"
)
@@ -59,15 +60,25 @@
}
func TestFirstUniqueStrings(t *testing.T) {
- for _, testCase := range firstUniqueStringsTestCases {
- out := FirstUniqueStrings(testCase.in)
- if !reflect.DeepEqual(out, testCase.out) {
+ f := func(t *testing.T, imp func([]string) []string, in, want []string) {
+ t.Helper()
+ out := imp(in)
+ if !reflect.DeepEqual(out, want) {
t.Errorf("incorrect output:")
- t.Errorf(" input: %#v", testCase.in)
- t.Errorf(" expected: %#v", testCase.out)
+ t.Errorf(" input: %#v", in)
+ t.Errorf(" expected: %#v", want)
t.Errorf(" got: %#v", out)
}
}
+
+ for _, testCase := range firstUniqueStringsTestCases {
+ t.Run("list", func(t *testing.T) {
+ f(t, firstUniqueStringsList, testCase.in, testCase.out)
+ })
+ t.Run("map", func(t *testing.T) {
+ f(t, firstUniqueStringsMap, testCase.in, testCase.out)
+ })
+ }
}
var lastUniqueStringsTestCases = []struct {
@@ -568,3 +579,51 @@
})
}
}
+
+func BenchmarkFirstUniqueStrings(b *testing.B) {
+ implementations := []struct {
+ name string
+ f func([]string) []string
+ }{
+ {
+ name: "list",
+ f: firstUniqueStringsList,
+ },
+ {
+ name: "map",
+ f: firstUniqueStringsMap,
+ },
+ }
+ const maxSize = 1024
+ uniqueStrings := make([]string, maxSize)
+ for i := range uniqueStrings {
+ uniqueStrings[i] = strconv.Itoa(i)
+ }
+ sameString := make([]string, maxSize)
+ for i := range sameString {
+ sameString[i] = uniqueStrings[0]
+ }
+
+ f := func(b *testing.B, imp func([]string) []string, s []string) {
+ for i := 0; i < b.N; i++ {
+ b.ReportAllocs()
+ s = append([]string(nil), s...)
+ imp(s)
+ }
+ }
+
+ for n := 1; n <= maxSize; n <<= 1 {
+ b.Run(strconv.Itoa(n), func(b *testing.B) {
+ for _, implementation := range implementations {
+ b.Run(implementation.name, func(b *testing.B) {
+ b.Run("same", func(b *testing.B) {
+ f(b, implementation.f, sameString[:n])
+ })
+ b.Run("unique", func(b *testing.B) {
+ f(b, implementation.f, uniqueStrings[:n])
+ })
+ })
+ }
+ })
+ }
+}
diff --git a/android/variable.go b/android/variable.go
index 983c235..53f081e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -49,6 +49,14 @@
Exclude_static_libs []string `android:"arch_variant"`
} `android:"arch_variant"`
+ Malloc_zero_contents struct {
+ Cflags []string `android:"arch_variant"`
+ } `android:"arch_variant"`
+
+ Malloc_pattern_fill_contents struct {
+ Cflags []string `android:"arch_variant"`
+ } `android:"arch_variant"`
+
Safestack struct {
Cflags []string `android:"arch_variant"`
} `android:"arch_variant"`
@@ -95,6 +103,9 @@
Sanitize struct {
Address *bool
}
+ Optimize struct {
+ Enabled *bool
+ }
}
Pdk struct {
@@ -155,13 +166,14 @@
Platform_min_supported_target_sdk_version *string `json:",omitempty"`
Platform_base_os *string `json:",omitempty"`
- DeviceName *string `json:",omitempty"`
- DeviceArch *string `json:",omitempty"`
- DeviceArchVariant *string `json:",omitempty"`
- DeviceCpuVariant *string `json:",omitempty"`
- DeviceAbi []string `json:",omitempty"`
- DeviceVndkVersion *string `json:",omitempty"`
- DeviceSystemSdkVersions []string `json:",omitempty"`
+ DeviceName *string `json:",omitempty"`
+ DeviceArch *string `json:",omitempty"`
+ DeviceArchVariant *string `json:",omitempty"`
+ DeviceCpuVariant *string `json:",omitempty"`
+ DeviceAbi []string `json:",omitempty"`
+ DeviceVndkVersion *string `json:",omitempty"`
+ DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"`
+ DeviceSystemSdkVersions []string `json:",omitempty"`
DeviceSecondaryArch *string `json:",omitempty"`
DeviceSecondaryArchVariant *string `json:",omitempty"`
@@ -203,27 +215,29 @@
AppsDefaultVersionName *string `json:",omitempty"`
- Allow_missing_dependencies *bool `json:",omitempty"`
- Unbundled_build *bool `json:",omitempty"`
- Unbundled_build_sdks_from_source *bool `json:",omitempty"`
- Malloc_not_svelte *bool `json:",omitempty"`
- Safestack *bool `json:",omitempty"`
- HostStaticBinaries *bool `json:",omitempty"`
- Binder32bit *bool `json:",omitempty"`
- UseGoma *bool `json:",omitempty"`
- UseRBE *bool `json:",omitempty"`
- UseRBEJAVAC *bool `json:",omitempty"`
- UseRBER8 *bool `json:",omitempty"`
- UseRBED8 *bool `json:",omitempty"`
- Debuggable *bool `json:",omitempty"`
- Eng *bool `json:",omitempty"`
- Treble_linker_namespaces *bool `json:",omitempty"`
- Enforce_vintf_manifest *bool `json:",omitempty"`
- Pdk *bool `json:",omitempty"`
- Uml *bool `json:",omitempty"`
- Use_lmkd_stats_log *bool `json:",omitempty"`
- Arc *bool `json:",omitempty"`
- MinimizeJavaDebugInfo *bool `json:",omitempty"`
+ Allow_missing_dependencies *bool `json:",omitempty"`
+ Unbundled_build *bool `json:",omitempty"`
+ Unbundled_build_apps *bool `json:",omitempty"`
+ Always_use_prebuilt_sdks *bool `json:",omitempty"`
+ Malloc_not_svelte *bool `json:",omitempty"`
+ Malloc_zero_contents *bool `json:",omitempty"`
+ Malloc_pattern_fill_contents *bool `json:",omitempty"`
+ Safestack *bool `json:",omitempty"`
+ HostStaticBinaries *bool `json:",omitempty"`
+ Binder32bit *bool `json:",omitempty"`
+ UseGoma *bool `json:",omitempty"`
+ UseRBE *bool `json:",omitempty"`
+ UseRBEJAVAC *bool `json:",omitempty"`
+ UseRBER8 *bool `json:",omitempty"`
+ UseRBED8 *bool `json:",omitempty"`
+ Debuggable *bool `json:",omitempty"`
+ Eng *bool `json:",omitempty"`
+ Treble_linker_namespaces *bool `json:",omitempty"`
+ Enforce_vintf_manifest *bool `json:",omitempty"`
+ Uml *bool `json:",omitempty"`
+ Use_lmkd_stats_log *bool `json:",omitempty"`
+ Arc *bool `json:",omitempty"`
+ MinimizeJavaDebugInfo *bool `json:",omitempty"`
Check_elf_files *bool `json:",omitempty"`
@@ -264,10 +278,6 @@
// Set by NewConfig
Native_coverage *bool
- DevicePrefer32BitApps *bool `json:",omitempty"`
- DevicePrefer32BitExecutables *bool `json:",omitempty"`
- HostPrefer32BitExecutables *bool `json:",omitempty"`
-
SanitizeHost []string `json:",omitempty"`
SanitizeDevice []string `json:",omitempty"`
SanitizeDeviceDiag []string `json:",omitempty"`
@@ -298,8 +308,6 @@
BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
BoardSepolicyM4Defs []string `json:",omitempty"`
- BoardVndkRuntimeDisable *bool `json:",omitempty"`
-
VendorVars map[string]map[string]string `json:",omitempty"`
Ndk_abis *bool `json:",omitempty"`
@@ -336,6 +344,9 @@
InstallExtraFlattenedApexes *bool `json:",omitempty"`
BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
+
+ BoardKernelBinaries []string `json:",omitempty"`
+ BoardKernelModuleInterfaceVersions []string `json:",omitempty"`
}
func boolPtr(v bool) *bool {
@@ -378,8 +389,10 @@
AAPTCharacteristics: stringPtr("nosdcard"),
AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
- Malloc_not_svelte: boolPtr(true),
- Safestack: boolPtr(false),
+ Malloc_not_svelte: boolPtr(true),
+ Malloc_zero_contents: boolPtr(false),
+ Malloc_pattern_fill_contents: boolPtr(false),
+ Safestack: boolPtr(false),
}
if runtime.GOOS == "linux" {
diff --git a/android/writedocs.go b/android/writedocs.go
index 9e43e80..4eb15e6 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -44,6 +44,10 @@
}
func (c *docsSingleton) GenerateBuildActions(ctx SingletonContext) {
+ var deps Paths
+ deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().moduleListFile))
+ deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
+
// Generate build system docs for the primary builder. Generating docs reads the source
// files used to build the primary builder, but that dependency will be picked up through
// the dependency on the primary builder itself. There are no dependencies on the
@@ -63,6 +67,7 @@
ctx.Build(pctx, BuildParams{
Rule: soongDocs,
Output: docsFile,
+ Inputs: deps,
Args: map[string]string{
"outDir": PathForOutput(ctx, "docs").String(),
},
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 8860984..eaf06c5 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -40,26 +40,31 @@
append bool
}
+var trueValue = &bpparser.Bool{
+ Value: true,
+}
+
var rewriteProperties = map[string](func(variableAssignmentContext) error){
// custom functions
- "LOCAL_32_BIT_ONLY": local32BitOnly,
- "LOCAL_AIDL_INCLUDES": localAidlIncludes,
- "LOCAL_ASSET_DIR": localizePathList("asset_dirs"),
- "LOCAL_C_INCLUDES": localIncludeDirs,
- "LOCAL_EXPORT_C_INCLUDE_DIRS": exportIncludeDirs,
- "LOCAL_JARJAR_RULES": localizePath("jarjar_rules"),
- "LOCAL_LDFLAGS": ldflags,
- "LOCAL_MODULE_CLASS": prebuiltClass,
- "LOCAL_MODULE_STEM": stem,
- "LOCAL_MODULE_HOST_OS": hostOs,
- "LOCAL_RESOURCE_DIR": localizePathList("resource_dirs"),
- "LOCAL_SANITIZE": sanitize(""),
- "LOCAL_SANITIZE_DIAG": sanitize("diag."),
- "LOCAL_STRIP_MODULE": strip(),
- "LOCAL_CFLAGS": cflags,
- "LOCAL_UNINSTALLABLE_MODULE": invert("installable"),
- "LOCAL_PROGUARD_ENABLED": proguardEnabled,
- "LOCAL_MODULE_PATH": prebuiltModulePath,
+ "LOCAL_32_BIT_ONLY": local32BitOnly,
+ "LOCAL_AIDL_INCLUDES": localAidlIncludes,
+ "LOCAL_ASSET_DIR": localizePathList("asset_dirs"),
+ "LOCAL_C_INCLUDES": localIncludeDirs,
+ "LOCAL_EXPORT_C_INCLUDE_DIRS": exportIncludeDirs,
+ "LOCAL_JARJAR_RULES": localizePath("jarjar_rules"),
+ "LOCAL_LDFLAGS": ldflags,
+ "LOCAL_MODULE_CLASS": prebuiltClass,
+ "LOCAL_MODULE_STEM": stem,
+ "LOCAL_MODULE_HOST_OS": hostOs,
+ "LOCAL_RESOURCE_DIR": localizePathList("resource_dirs"),
+ "LOCAL_SANITIZE": sanitize(""),
+ "LOCAL_SANITIZE_DIAG": sanitize("diag."),
+ "LOCAL_STRIP_MODULE": strip(),
+ "LOCAL_CFLAGS": cflags,
+ "LOCAL_UNINSTALLABLE_MODULE": invert("installable"),
+ "LOCAL_PROGUARD_ENABLED": proguardEnabled,
+ "LOCAL_MODULE_PATH": prebuiltModulePath,
+ "LOCAL_REPLACE_PREBUILT_APK_INSTALLED": prebuiltPreprocessed,
// composite functions
"LOCAL_MODULE_TAGS": includeVariableIf(bpVariable{"tags", bpparser.ListType}, not(valueDumpEquals("optional"))),
@@ -111,6 +116,7 @@
"LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile",
"LOCAL_TEST_CONFIG": "test_config",
+ "LOCAL_RRO_THEME": "theme",
})
addStandardProperties(bpparser.ListType,
map[string]string{
@@ -383,11 +389,15 @@
if err != nil {
return err
}
- if val.(*bpparser.Bool).Value {
+ boolValue, ok := val.(*bpparser.Bool)
+ if !ok {
+ return fmt.Errorf("value should evaluate to boolean literal")
+ }
+ if boolValue.Value {
thirtyTwo := &bpparser.String{
Value: "32",
}
- setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
+ return setVariable(ctx.file, false, ctx.prefix, "compile_multilib", thirtyTwo, true)
}
return nil
}
@@ -490,10 +500,6 @@
Value: false,
}
- trueValue := &bpparser.Bool{
- Value: true,
- }
-
if inList("windows") {
err = setVariable(ctx.file, ctx.append, "target.windows", "enabled", trueValue, true)
}
@@ -699,6 +705,11 @@
return nil
}
+func prebuiltPreprocessed(ctx variableAssignmentContext) error {
+ ctx.mkvalue = ctx.mkvalue.Clone()
+ return setVariable(ctx.file, false, ctx.prefix, "preprocessed", trueValue, true)
+}
+
func cflags(ctx variableAssignmentContext) error {
// The Soong replacement for CFLAGS doesn't need the same extra escaped quotes that were present in Make
ctx.mkvalue = ctx.mkvalue.Clone()
@@ -825,8 +836,6 @@
var propertyPrefixes = []struct{ mk, bp string }{
{"arm", "arch.arm"},
{"arm64", "arch.arm64"},
- {"mips", "arch.mips"},
- {"mips64", "arch.mips64"},
{"x86", "arch.x86"},
{"x86_64", "arch.x86_64"},
{"32", "multilib.lib32"},
@@ -923,6 +932,7 @@
"BUILD_HOST_JAVA_LIBRARY": "java_library_host",
"BUILD_HOST_DALVIK_JAVA_LIBRARY": "java_library_host_dalvik",
"BUILD_PACKAGE": "android_app",
+ "BUILD_RRO_PACKAGE": "runtime_resource_overlay",
"BUILD_CTS_EXECUTABLE": "cc_binary", // will be further massaged by bpfix depending on the output path
"BUILD_CTS_SUPPORT_PACKAGE": "cts_support_package", // will be rewritten to android_test by bpfix
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 9d0c3ac..03cf74d 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -34,6 +34,7 @@
defs []bpparser.Definition
localAssignments map[string]*bpparser.Property
globalAssignments map[string]*bpparser.Expression
+ variableRenames map[string]string
scope mkparser.Scope
module *bpparser.Module
@@ -43,6 +44,10 @@
inModule bool
}
+var invalidVariableStringToReplacement = map[string]string{
+ "-": "_dash_",
+}
+
func (f *bpFile) insertComment(s string) {
f.comments = append(f.comments, &bpparser.CommentGroup{
Comments: []*bpparser.Comment{
@@ -120,10 +125,12 @@
scope: androidScope(),
localAssignments: make(map[string]*bpparser.Property),
globalAssignments: make(map[string]*bpparser.Expression),
+ variableRenames: make(map[string]string),
}
var conds []*conditional
var assignmentCond *conditional
+ var tree *bpparser.File
for _, node := range nodes {
file.setMkPos(p.Unpack(node.Pos()), p.Unpack(node.End()))
@@ -200,24 +207,46 @@
}
}
- tree := &bpparser.File{
+ tree = &bpparser.File{
Defs: file.defs,
Comments: file.comments,
}
// check for common supported but undesirable structures and clean them up
fixer := bpfix.NewFixer(tree)
- tree, err := fixer.Fix(bpfix.NewFixRequest().AddAll())
- if err != nil {
- return "", []error{err}
+ fixedTree, fixerErr := fixer.Fix(bpfix.NewFixRequest().AddAll())
+ if fixerErr != nil {
+ errs = append(errs, fixerErr)
+ } else {
+ tree = fixedTree
}
out, err := bpparser.Print(tree)
if err != nil {
- return "", []error{err}
+ errs = append(errs, err)
+ return "", errs
}
- return string(out), nil
+ return string(out), errs
+}
+
+func renameVariableWithInvalidCharacters(name string) string {
+ renamed := ""
+ for invalid, replacement := range invalidVariableStringToReplacement {
+ if strings.Contains(name, invalid) {
+ renamed = strings.ReplaceAll(name, invalid, replacement)
+ }
+ }
+
+ return renamed
+}
+
+func invalidVariableStrings() string {
+ invalidStrings := make([]string, 0, len(invalidVariableStringToReplacement))
+ for s := range invalidVariableStringToReplacement {
+ invalidStrings = append(invalidStrings, "\""+s+"\"")
+ }
+ return strings.Join(invalidStrings, ", ")
}
func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
@@ -234,6 +263,12 @@
name := assignment.Name.Value(nil)
prefix := ""
+ if newName := renameVariableWithInvalidCharacters(name); newName != "" {
+ file.warnf("Variable names cannot contain: %s. Renamed \"%s\" to \"%s\"", invalidVariableStrings(), name, newName)
+ file.variableRenames[name] = newName
+ name = newName
+ }
+
if strings.HasPrefix(name, "LOCAL_") {
for _, x := range propertyPrefixes {
if strings.HasSuffix(name, "_"+x.mk) {
@@ -337,11 +372,11 @@
var err error
switch typ {
case bpparser.ListType:
- exp, err = makeToListExpression(val, file.scope)
+ exp, err = makeToListExpression(val, file)
case bpparser.StringType:
- exp, err = makeToStringExpression(val, file.scope)
+ exp, err = makeToStringExpression(val, file)
case bpparser.BoolType:
- exp, err = makeToBoolExpression(val)
+ exp, err = makeToBoolExpression(val, file)
default:
panic("unknown type")
}
@@ -354,7 +389,6 @@
}
func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
-
if prefix != "" {
name = prefix + "." + name
}
@@ -424,6 +458,9 @@
}
file.defs = append(file.defs, a)
} else {
+ if _, ok := file.globalAssignments[name]; ok {
+ return fmt.Errorf("cannot assign a variable multiple times: \"%s\"", name)
+ }
a := &bpparser.Assignment{
Name: name,
NamePos: pos,
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index 7e1a72c..2448acc 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -876,7 +876,7 @@
prebuilt_etc {
name: "etc.test1",
src: "mymod",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -896,7 +896,7 @@
name: "etc.test1",
src: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
}
`,
@@ -913,7 +913,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
device_specific: true,
}
@@ -931,7 +931,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
@@ -950,7 +950,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
product_specific: true,
}
@@ -968,7 +968,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
}
@@ -986,7 +986,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
system_ext_specific: true,
@@ -1005,7 +1005,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1023,7 +1023,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1041,7 +1041,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
proprietary: true,
}
@@ -1059,7 +1059,7 @@
expected: `
prebuilt_etc {
name: "etc.test1",
- sub_dir: "foo/bar",
+ relative_install_path: "foo/bar",
recovery: true,
}
@@ -1098,7 +1098,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1174,7 +1174,7 @@
name: "foo",
src: "foo.txt",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1193,7 +1193,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1212,7 +1212,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
}
`,
},
@@ -1231,7 +1231,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
@@ -1251,7 +1251,7 @@
name: "foo",
src: "foo.fw",
- sub_dir: "bar",
+ relative_install_path: "bar",
proprietary: true,
}
`,
@@ -1341,6 +1341,124 @@
}
`,
},
+ {
+ desc: "android_test_import prebuilt",
+ in: `
+ include $(CLEAR_VARS)
+ LOCAL_MODULE := foo
+ LOCAL_SRC_FILES := foo.apk
+ LOCAL_MODULE_CLASS := APPS
+ LOCAL_MODULE_TAGS := tests
+ LOCAL_MODULE_SUFFIX := .apk
+ LOCAL_CERTIFICATE := PRESIGNED
+ LOCAL_REPLACE_PREBUILT_APK_INSTALLED := $(LOCAL_PATH)/foo.apk
+ LOCAL_COMPATIBILITY_SUITE := cts
+ include $(BUILD_PREBUILT)
+ `,
+ expected: `
+android_test_import {
+ name: "foo",
+ srcs: ["foo.apk"],
+
+ certificate: "PRESIGNED",
+ preprocessed: true,
+ test_suites: ["cts"],
+}
+`,
+ },
+ {
+ desc: "dashed_variable gets renamed",
+ in: `
+ include $(CLEAR_VARS)
+
+ dashed-variable:= a.cpp
+
+ LOCAL_MODULE:= test
+ LOCAL_SRC_FILES:= $(dashed-variable)
+ include $(BUILD_EXECUTABLE)
+ `,
+ expected: `
+
+// ANDROIDMK TRANSLATION WARNING: Variable names cannot contain: "-". Renamed "dashed-variable" to "dashed_dash_variable"
+dashed_dash_variable = ["a.cpp"]
+cc_binary {
+
+ name: "test",
+ srcs: dashed_dash_variable,
+}
+`,
+ },
+ {
+ desc: "variableReassigned",
+ in: `
+include $(CLEAR_VARS)
+
+src_files:= a.cpp
+
+LOCAL_SRC_FILES:= $(src_files)
+LOCAL_MODULE:= test
+include $(BUILD_EXECUTABLE)
+
+# clear locally used variable
+src_files:=
+`,
+ expected: `
+
+
+src_files = ["a.cpp"]
+cc_binary {
+ name: "test",
+
+ srcs: src_files,
+}
+
+// clear locally used variable
+// ANDROIDMK TRANSLATION ERROR: cannot assign a variable multiple times: "src_files"
+// src_files :=
+`,
+ },
+ {
+ desc: "undefined_boolean_var",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= a.cpp
+LOCAL_MODULE:= test
+LOCAL_32_BIT_ONLY := $(FLAG)
+include $(BUILD_EXECUTABLE)
+`,
+ expected: `
+cc_binary {
+ name: "test",
+ srcs: ["a.cpp"],
+ // ANDROIDMK TRANSLATION ERROR: value should evaluate to boolean literal
+ // LOCAL_32_BIT_ONLY := $(FLAG)
+
+}
+`,
+ },
+ {
+ desc: "runtime_resource_overlay",
+ in: `
+include $(CLEAR_VARS)
+LOCAL_PACKAGE_NAME := foo
+LOCAL_PRODUCT_MODULE := true
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SDK_VERSION := current
+LOCAL_RRO_THEME := FooTheme
+
+include $(BUILD_RRO_PACKAGE)
+`,
+ expected: `
+runtime_resource_overlay {
+ name: "foo",
+ product_specific: true,
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ theme: "FooTheme",
+
+}
+`,
+ },
}
func TestEndToEnd(t *testing.T) {
diff --git a/androidmk/androidmk/values.go b/androidmk/androidmk/values.go
index 6b18a65..9618142 100644
--- a/androidmk/androidmk/values.go
+++ b/androidmk/androidmk/values.go
@@ -60,8 +60,7 @@
}, nil
}
-func makeToStringExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToStringExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
var val bpparser.Expression
var err error
@@ -70,18 +69,18 @@
}
for i, s := range ms.Strings[1:] {
- if ret, ok := ms.Variables[i].EvalFunction(scope); ok {
+ if ret, ok := ms.Variables[i].EvalFunction(file.scope); ok {
if len(ret) > 1 {
return nil, fmt.Errorf("Unexpected list value %s", ms.Dump())
}
val, err = addValues(val, stringToStringValue(ret[0]))
} else {
- name := ms.Variables[i].Name
- if !name.Const() {
- return nil, fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ name, err := extractVariableName(ms.Variables[i].Name, file)
+ if err != nil {
+ return nil, err
}
tmp := &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.String{},
}
@@ -125,8 +124,7 @@
}
-func makeToListExpression(ms *mkparser.MakeString, scope mkparser.Scope) (bpparser.Expression, error) {
-
+func makeToListExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
fields := ms.Split(" \t")
var listOfListValues []bpparser.Expression
@@ -135,14 +133,14 @@
for _, f := range fields {
if len(f.Variables) == 1 && f.Strings[0] == "" && f.Strings[1] == "" {
- if ret, ok := f.Variables[0].EvalFunction(scope); ok {
+ if ret, ok := f.Variables[0].EvalFunction(file.scope); ok {
listValue.Values = append(listValue.Values, stringListToStringValueList(ret)...)
} else {
- // Variable by itself, variable is probably a list
- if !f.Variables[0].Name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(f.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
- if f.Variables[0].Name.Value(nil) == "TOP" {
+ if name == "TOP" {
listValue.Values = append(listValue.Values, &bpparser.String{
Value: ".",
})
@@ -151,14 +149,14 @@
listOfListValues = append(listOfListValues, listValue)
}
listOfListValues = append(listOfListValues, &bpparser.Variable{
- Name: f.Variables[0].Name.Value(nil),
+ Name: name,
Value: &bpparser.List{},
})
listValue = &bpparser.List{}
}
}
} else {
- s, err := makeToStringExpression(f, scope)
+ s, err := makeToStringExpression(f, file)
if err != nil {
return nil, err
}
@@ -208,15 +206,15 @@
}, nil
}
-func makeToBoolExpression(ms *mkparser.MakeString) (bpparser.Expression, error) {
+func makeToBoolExpression(ms *mkparser.MakeString, file *bpFile) (bpparser.Expression, error) {
if !ms.Const() {
if len(ms.Variables) == 1 && ms.Strings[0] == "" && ms.Strings[1] == "" {
- name := ms.Variables[0].Name
- if !name.Const() {
- return nil, fmt.Errorf("unsupported non-const variable name")
+ name, err := extractVariableName(ms.Variables[0].Name, file)
+ if err != nil {
+ return nil, err
}
return &bpparser.Variable{
- Name: name.Value(nil),
+ Name: name,
Value: &bpparser.Bool{},
}, nil
} else {
@@ -226,3 +224,17 @@
return stringToBoolValue(ms.Value(nil))
}
+
+func extractVariableName(name *mkparser.MakeString, file *bpFile) (string, error) {
+ if !name.Const() {
+ return "", fmt.Errorf("Unsupported non-const variable name %s", name.Dump())
+ }
+
+ variableName := name.Value(nil)
+
+ if newName, ok := file.variableRenames[variableName]; ok {
+ variableName = newName
+ }
+
+ return variableName, nil
+}
diff --git a/androidmk/cmd/androidmk.go b/androidmk/cmd/androidmk.go
index 00488eb..d2f4324 100644
--- a/androidmk/cmd/androidmk.go
+++ b/androidmk/cmd/androidmk.go
@@ -45,12 +45,13 @@
}
output, errs := androidmk.ConvertFile(os.Args[1], bytes.NewBuffer(b))
+ if len(output) > 0 {
+ fmt.Print(output)
+ }
if len(errs) > 0 {
for _, err := range errs {
fmt.Fprintln(os.Stderr, "ERROR: ", err)
}
os.Exit(1)
}
-
- fmt.Print(output)
}
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 490a0e3..0d23685 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -125,8 +125,8 @@
bouncycastle_ike_digests(minSdkVersion:current)
brotli-java(minSdkVersion:current)
captiveportal-lib(minSdkVersion:29)
-captiveportal-lib(minSdkVersion:current)
car-ui-lib(minSdkVersion:28)
+car-ui-lib-overlayable(minSdkVersion:28)
CellBroadcastApp(minSdkVersion:29)
CellBroadcastServiceModule(minSdkVersion:29)
codecs_g711dec(minSdkVersion:29)
@@ -136,18 +136,23 @@
conscrypt.module.public.api.stubs(minSdkVersion:(no version))
core-lambda-stubs(minSdkVersion:(no version))
core.current.stubs(minSdkVersion:(no version))
+crtbegin_dynamic(minSdkVersion:16)
crtbegin_dynamic(minSdkVersion:apex_inherit)
+crtbegin_dynamic1(minSdkVersion:16)
crtbegin_dynamic1(minSdkVersion:apex_inherit)
+crtbegin_so(minSdkVersion:16)
crtbegin_so(minSdkVersion:apex_inherit)
+crtbegin_so1(minSdkVersion:16)
crtbegin_so1(minSdkVersion:apex_inherit)
+crtbrand(minSdkVersion:16)
crtbrand(minSdkVersion:apex_inherit)
+crtend_android(minSdkVersion:16)
crtend_android(minSdkVersion:apex_inherit)
+crtend_so(minSdkVersion:16)
crtend_so(minSdkVersion:apex_inherit)
datastallprotosnano(minSdkVersion:29)
-datastallprotosnano(minSdkVersion:current)
derive_sdk(minSdkVersion:current)
derive_sdk_prefer32(minSdkVersion:current)
-dnsresolver_aidl_interface-ndk_platform(minSdkVersion:29)
dnsresolver_aidl_interface-unstable-ndk_platform(minSdkVersion:29)
DocumentsUI-res-lib(minSdkVersion:29)
exoplayer2-extractor(minSdkVersion:16)
@@ -172,7 +177,6 @@
ike-internals(minSdkVersion:current)
InProcessTethering(minSdkVersion:current)
ipmemorystore-aidl-interfaces-java(minSdkVersion:29)
-ipmemorystore-aidl-interfaces-java(minSdkVersion:current)
ipmemorystore-aidl-interfaces-unstable-java(minSdkVersion:29)
jni_headers(minSdkVersion:29)
jsr305(minSdkVersion:14)
@@ -223,7 +227,6 @@
libc++demangle(minSdkVersion:apex_inherit)
libc_headers(minSdkVersion:apex_inherit)
libc_headers_arch(minSdkVersion:apex_inherit)
-libc_scudo(minSdkVersion:apex_inherit)
libcap(minSdkVersion:29)
libclang_rt.hwasan-aarch64-android.llndk(minSdkVersion:(no version))
libcodec2(minSdkVersion:29)
@@ -278,6 +281,7 @@
libFLAC-headers(minSdkVersion:29)
libflacextractor(minSdkVersion:29)
libfmq(minSdkVersion:29)
+libfmq-base(minSdkVersion:29)
libFraunhoferAAC(minSdkVersion:29)
libgav1(minSdkVersion:29)
libgcc_stripped(minSdkVersion:(no version))
@@ -339,6 +343,10 @@
libprocessgroup(minSdkVersion:29)
libprocessgroup_headers(minSdkVersion:29)
libprocpartition(minSdkVersion:(no version))
+libprofile-clang-extras(minSdkVersion:(no version))
+libprofile-clang-extras_ndk(minSdkVersion:(no version))
+libprofile-extras(minSdkVersion:(no version))
+libprofile-extras_ndk(minSdkVersion:(no version))
libprotobuf-cpp-lite(minSdkVersion:29)
libprotobuf-java-lite(minSdkVersion:current)
libprotobuf-java-nano(minSdkVersion:9)
@@ -369,7 +377,6 @@
libstagefright_metadatautils(minSdkVersion:29)
libstagefright_mp3dec(minSdkVersion:29)
libstagefright_mpeg2extractor(minSdkVersion:29)
-libstagefright_mpeg2support(minSdkVersion:29)
libstagefright_mpeg2support_nocrypto(minSdkVersion:29)
libstats_jni(minSdkVersion:(no version))
libstatslog_resolv(minSdkVersion:29)
@@ -378,13 +385,11 @@
libstatspush_compat(minSdkVersion:29)
libstatssocket(minSdkVersion:(no version))
libstatssocket_headers(minSdkVersion:29)
-libsync(minSdkVersion:(no version))
libsystem_headers(minSdkVersion:apex_inherit)
libsysutils(minSdkVersion:apex_inherit)
libtetherutilsjni(minSdkVersion:current)
libtextclassifier(minSdkVersion:(no version))
libtextclassifier-java(minSdkVersion:28)
-libtextclassifier-java(minSdkVersion:current)
libtextclassifier_flatbuffer_headers(minSdkVersion:(no version))
libtextclassifier_hash_headers(minSdkVersion:(no version))
libtextclassifier_hash_static(minSdkVersion:(no version))
@@ -404,13 +409,12 @@
libwebm(minSdkVersion:29)
libyuv(minSdkVersion:29)
libyuv_static(minSdkVersion:29)
-libz_current(minSdkVersion:(no version))
libzstd(minSdkVersion:(no version))
+marisa-trie(minSdkVersion:(no version))
media_ndk_headers(minSdkVersion:29)
media_plugin_headers(minSdkVersion:29)
mediaswcodec(minSdkVersion:29)
metrics-constants-protos(minSdkVersion:29)
-metrics-constants-protos(minSdkVersion:current)
ndk_crtbegin_so.19(minSdkVersion:(no version))
ndk_crtbegin_so.21(minSdkVersion:(no version))
ndk_crtbegin_so.27(minSdkVersion:(no version))
@@ -423,16 +427,14 @@
ndk_libunwind(minSdkVersion:(no version))
net-utils-device-common(minSdkVersion:29)
net-utils-framework-common(minSdkVersion:current)
-netd_aidl_interface-java(minSdkVersion:current)
+netd_aidl_interface-java(minSdkVersion:29)
netd_aidl_interface-unstable-java(minSdkVersion:29)
netd_event_listener_interface-ndk_platform(minSdkVersion:29)
+netd_event_listener_interface-unstable-ndk_platform(minSdkVersion:29)
netlink-client(minSdkVersion:29)
-netlink-client(minSdkVersion:current)
networkstack-aidl-interfaces-java(minSdkVersion:29)
-networkstack-aidl-interfaces-java(minSdkVersion:current)
networkstack-aidl-interfaces-unstable-java(minSdkVersion:29)
networkstack-client(minSdkVersion:29)
-networkstack-client(minSdkVersion:current)
NetworkStackApiStableDependencies(minSdkVersion:29)
NetworkStackApiStableLib(minSdkVersion:29)
networkstackprotos(minSdkVersion:29)
diff --git a/apex/androidmk.go b/apex/androidmk.go
index e4cdef0..1b53a67 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -33,17 +33,12 @@
Disabled: true,
}
}
- writers := []android.AndroidMkData{}
- writers = append(writers, a.androidMkForType())
- return android.AndroidMkData{
- Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
- for _, data := range writers {
- data.Custom(w, name, prefix, moduleDir, data)
- }
- }}
+ return a.androidMkForType()
}
-func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string) []string {
+func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, apexName, moduleDir string,
+ apexAndroidMkData android.AndroidMkData) []string {
+
// apexBundleName comes from the 'name' property; apexName comes from 'apex_name' property.
// An apex is installed to /system/apex/<apexBundleName> and is activated at /apex/<apexName>
// In many cases, the two names are the same, but could be different in general.
@@ -57,6 +52,11 @@
return moduleNames
}
+ // b/162366062. Prevent GKI APEXes to emit make rules to avoid conflicts.
+ if strings.HasPrefix(apexName, "com.android.gki.") && apexType != flattenedApex {
+ return moduleNames
+ }
+
// b/140136207. When there are overriding APEXes for a VNDK APEX, the symbols file for the overridden
// APEX and the overriding APEX will have the same installation paths at /apex/com.android.vndk.v<ver>
// as their apexName will be the same. To avoid the path conflicts, skip installing the symbol files
@@ -78,6 +78,8 @@
}
}
+ seenDataOutPaths := make(map[string]bool)
+
for _, fi := range a.filesInfo {
if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake {
continue
@@ -87,9 +89,9 @@
var moduleName string
if linkToSystemLib {
- moduleName = fi.moduleName
+ moduleName = fi.androidMkModuleName
} else {
- moduleName = fi.moduleName + "." + apexBundleName + a.suffix
+ moduleName = fi.androidMkModuleName + "." + apexBundleName + a.suffix
}
if !android.InList(moduleName, moduleNames) {
@@ -124,9 +126,20 @@
if len(fi.symlinks) > 0 {
fmt.Fprintln(w, "LOCAL_MODULE_SYMLINKS :=", strings.Join(fi.symlinks, " "))
}
+ newDataPaths := []android.DataPath{}
+ for _, path := range fi.dataPaths {
+ dataOutPath := modulePath + ":" + path.SrcPath.Rel()
+ if ok := seenDataOutPaths[dataOutPath]; !ok {
+ newDataPaths = append(newDataPaths, path)
+ seenDataOutPaths[dataOutPath] = true
+ }
+ }
+ if len(newDataPaths) > 0 {
+ fmt.Fprintln(w, "LOCAL_TEST_DATA :=", strings.Join(cc.AndroidMkDataPaths(newDataPaths), " "))
+ }
- if fi.module != nil && fi.module.NoticeFile().Valid() {
- fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", fi.module.NoticeFile().Path().String())
+ if fi.module != nil && len(fi.module.NoticeFiles()) > 0 {
+ fmt.Fprintln(w, "LOCAL_NOTICE_FILE :=", strings.Join(fi.module.NoticeFiles().Strings(), " "))
}
} else {
modulePath = pathWhenActivated
@@ -206,7 +219,7 @@
if !ok {
panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
}
- fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile())
+ fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.InstallFile())
fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String())
fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
case nativeSharedLib, nativeExecutable, nativeTest:
@@ -225,14 +238,26 @@
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
if a.primaryApexType {
+ // To install companion files (init_rc, vintf_fragments)
+ // Copy some common properties of apexBundle to apex_manifest
+ commonProperties := []string{
+ "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ }
+ for _, name := range commonProperties {
+ if value, ok := apexAndroidMkData.Entries.EntryMap[name]; ok {
+ fmt.Fprintln(w, name+" := "+strings.Join(value, " "))
+ }
+ }
+
// Make apex_manifest.pb module for this APEX to override all other
// modules in the APEXes being overridden by this APEX
var patterns []string
for _, o := range a.overridableProperties.Overrides {
patterns = append(patterns, "%."+o+a.suffix)
}
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
-
+ if len(patterns) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
+ }
if len(a.compatSymlinks) > 0 {
// For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
@@ -246,9 +271,9 @@
}
// m <module_name> will build <module_name>.<apex_name> as well.
- if fi.moduleName != moduleName && a.primaryApexType {
- fmt.Fprintln(w, ".PHONY: "+fi.moduleName)
- fmt.Fprintln(w, fi.moduleName+": "+moduleName)
+ if fi.androidMkModuleName != moduleName && a.primaryApexType {
+ fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
+ fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
}
}
return moduleNames
@@ -282,7 +307,7 @@
apexType := a.properties.ApexType
if a.installable() {
apexName := proptools.StringDefault(a.properties.Apex_name, name)
- moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir)
+ moduleNames = a.androidMkForFiles(w, name, apexName, moduleDir, data)
}
if apexType == flattenedApex {
@@ -305,7 +330,23 @@
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
- fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+
+ // Because apex writes .mk with Custom(), we need to write manually some common properties
+ // which are available via data.Entries
+ commonProperties := []string{
+ "LOCAL_INIT_RC", "LOCAL_VINTF_FRAGMENTS",
+ "LOCAL_PROPRIETARY_MODULE", "LOCAL_VENDOR_MODULE", "LOCAL_ODM_MODULE", "LOCAL_PRODUCT_MODULE", "LOCAL_SYSTEM_EXT_MODULE",
+ "LOCAL_MODULE_OWNER",
+ }
+ for _, name := range commonProperties {
+ if value, ok := data.Entries.EntryMap[name]; ok {
+ fmt.Fprintln(w, name+" := "+strings.Join(value, " "))
+ }
+ }
+
+ if len(a.overridableProperties.Overrides) > 0 {
+ fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+ }
if len(moduleNames) > 0 {
fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
}
@@ -331,7 +372,7 @@
fmt.Fprintln(w, "include $(BUILD_PREBUILT)")
if apexType == imageApex {
- fmt.Fprintln(w, "ALL_MODULES.$(LOCAL_MODULE).BUNDLE :=", a.bundleModuleFile.String())
+ fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String())
}
if len(a.lintReports) > 0 {
fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS :=",
diff --git a/apex/apex.go b/apex/apex.go
index 927aa0b..5e6ee93 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -16,9 +16,7 @@
import (
"fmt"
- "path"
"path/filepath"
- "regexp"
"sort"
"strings"
"sync"
@@ -44,6 +42,9 @@
imageApexType = "image"
zipApexType = "zip"
flattenedApexType = "flattened"
+
+ ext4FsType = "ext4"
+ f2fsFsType = "f2fs"
)
type dependencyTag struct {
@@ -56,6 +57,7 @@
var (
sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
+ jniLibTag = dependencyTag{name: "jniLib", payload: true}
executableTag = dependencyTag{name: "executable", payload: true}
javaLibTag = dependencyTag{name: "javaLib", payload: true}
prebuiltTag = dependencyTag{name: "prebuilt", payload: true}
@@ -64,6 +66,7 @@
certificateTag = dependencyTag{name: "certificate"}
usesTag = dependencyTag{name: "uses"}
androidAppTag = dependencyTag{name: "androidApp", payload: true}
+ rroTag = dependencyTag{name: "rro", payload: true}
bpfTag = dependencyTag{name: "bpf", payload: true}
apexAvailBaseline = makeApexAvailableBaseline()
@@ -186,18 +189,11 @@
//
// Module separator
//
- m["com.android.conscrypt"] = []string{
- "libnativehelper_header_only",
- }
- //
- // Module separator
- //
m["com.android.extservices"] = []string{
"error_prone_annotations",
"ExtServices-core",
"ExtServices",
"libtextclassifier-java",
- "libz_current",
"textclassifier-statsd",
"TextClassifierNotificationLibNoManifest",
"TextClassifierServiceLibNoManifest",
@@ -397,7 +393,6 @@
"libbinderthreadstateutils",
"libbluetooth-types-header",
"libbufferhub_headers",
- "libc_scudo",
"libcodec2",
"libcodec2_headers",
"libcodec2_hidl@1.0",
@@ -502,7 +497,6 @@
"libbase_ndk",
"libfuse",
"libfuse_jni",
- "libnativehelper_header_only",
}
//
// Module separator
@@ -594,10 +588,8 @@
"android.hardware.tetheroffload.config-V1.0-java",
"android.hardware.tetheroffload.control-V1.0-java",
"android.hidl.base-V1.0-java",
- "ipmemorystore-aidl-interfaces-java",
"libcgrouprc",
"libcgrouprc_format",
- "libnativehelper_compat_libc++",
"libtetherutilsjni",
"libvndksupport",
"net-utils-framework-common",
@@ -782,7 +774,8 @@
}
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
- ctx.TopDown("apex_deps", apexDepsMutator)
+ ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
+ ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
ctx.BottomUp("apex", apexMutator).Parallel()
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
@@ -795,36 +788,59 @@
if !mctx.Module().Enabled() {
return
}
- var apexBundles []android.ApexInfo
- var directDep bool
- if a, ok := mctx.Module().(*apexBundle); ok && !a.vndkApex {
- apexBundles = []android.ApexInfo{{
- ApexName: mctx.ModuleName(),
- MinSdkVersion: a.minSdkVersion(mctx),
- Updatable: a.Updatable(),
- }}
- directDep = true
- } else if am, ok := mctx.Module().(android.ApexModule); ok {
- apexBundles = am.ApexVariations()
- directDep = false
+ a, ok := mctx.Module().(*apexBundle)
+ if !ok || a.vndkApex {
+ return
+ }
+ apexInfo := android.ApexInfo{
+ ApexVariationName: mctx.ModuleName(),
+ MinSdkVersion: a.minSdkVersion(mctx),
+ RequiredSdks: a.RequiredSdks(),
+ Updatable: a.Updatable(),
+ InApexes: []string{mctx.ModuleName()},
}
- if len(apexBundles) == 0 {
+ useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
+ excludeVndkLibs := useVndk && proptools.Bool(a.properties.Use_vndk_as_stable)
+ if !useVndk && proptools.Bool(a.properties.Use_vndk_as_stable) {
+ mctx.PropertyErrorf("use_vndk_as_stable", "not supported for system/system_ext APEXes")
return
}
- cur := mctx.Module().(android.DepIsInSameApex)
-
- mctx.VisitDirectDeps(func(child android.Module) {
- depName := mctx.OtherModuleName(child)
- if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() &&
- (cur.DepIsInSameApex(mctx, child) || inAnySdk(child)) {
- android.UpdateApexDependency(apexBundles, depName, directDep)
- am.BuildForApexes(apexBundles)
+ mctx.WalkDeps(func(child, parent android.Module) bool {
+ am, ok := child.(android.ApexModule)
+ if !ok || !am.CanHaveApexVariants() {
+ return false
}
+ if !parent.(android.DepIsInSameApex).DepIsInSameApex(mctx, child) {
+ return false
+ }
+ if excludeVndkLibs {
+ if c, ok := child.(*cc.Module); ok && c.IsVndk() {
+ return false
+ }
+ }
+
+ depName := mctx.OtherModuleName(child)
+ // If the parent is apexBundle, this child is directly depended.
+ _, directDep := parent.(*apexBundle)
+ android.UpdateApexDependency(apexInfo, depName, directDep)
+ am.BuildForApex(apexInfo)
+ return true
})
}
+func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
+ if am, ok := mctx.Module().(android.ApexModule); ok {
+ // Check if any dependencies use unique apex variations. If so, use unique apex variations
+ // for this module.
+ am.UpdateUniqueApexVariationsForDeps(mctx)
+ }
+}
+
// mark if a module cannot be available to platform. A module cannot be available
// to platform if 1) it is explicitly marked as not available (i.e. "//apex_available:platform"
// is absent) or 2) it depends on another module that isn't (or can't be) available to platform
@@ -837,18 +853,6 @@
if am, ok := mctx.Module().(android.ApexModule); ok {
availableToPlatform := am.AvailableFor(android.AvailableToPlatform)
- // In a rare case when a lib is marked as available only to an apex
- // but the apex doesn't exist. This can happen in a partial manifest branch
- // like master-art. Currently, libstatssocket in the stats APEX is causing
- // this problem.
- // Include the lib in platform because the module SDK that ought to provide
- // it doesn't exist, so it would otherwise be left out completely.
- // TODO(b/154888298) remove this by adding those libraries in module SDKS and skipping
- // this check for libraries provided by SDKs.
- if !availableToPlatform && !android.InAnyApex(am.Name()) {
- availableToPlatform = true
- }
-
// If any of the dep is not available to platform, this module is also considered
// as being not available to platform even if it has "//apex_available:platform"
mctx.VisitDirectDeps(func(child android.Module) {
@@ -1002,10 +1006,13 @@
})
}
-type apexNativeDependencies struct {
+type ApexNativeDependencies struct {
// List of native libraries
Native_shared_libs []string
+ // List of JNI libraries
+ Jni_libs []string
+
// List of native executables
Binaries []string
@@ -1015,19 +1022,19 @@
type apexMultilibProperties struct {
// Native dependencies whose compile_multilib is "first"
- First apexNativeDependencies
+ First ApexNativeDependencies
// Native dependencies whose compile_multilib is "both"
- Both apexNativeDependencies
+ Both ApexNativeDependencies
// Native dependencies whose compile_multilib is "prefer32"
- Prefer32 apexNativeDependencies
+ Prefer32 ApexNativeDependencies
// Native dependencies whose compile_multilib is "32"
- Lib32 apexNativeDependencies
+ Lib32 ApexNativeDependencies
// Native dependencies whose compile_multilib is "64"
- Lib64 apexNativeDependencies
+ Lib64 ApexNativeDependencies
}
type apexBundleProperties struct {
@@ -1049,11 +1056,7 @@
// Default: /system/sepolicy/apex/<module_name>_file_contexts.
File_contexts *string `android:"path"`
- // List of native shared libs that are embedded inside this APEX bundle
- Native_shared_libs []string
-
- // List of executables that are embedded inside this APEX bundle
- Binaries []string
+ ApexNativeDependencies
// List of java libraries that are embedded inside this APEX bundle
Java_libs []string
@@ -1061,9 +1064,6 @@
// List of prebuilt files that are embedded inside this APEX bundle
Prebuilts []string
- // List of tests that are embedded inside this APEX bundle
- Tests []string
-
// List of BPF programs inside APEX
Bpfs []string
@@ -1130,8 +1130,17 @@
// Default is false.
Updatable *bool
- // The minimum SDK version that this apex must be compatible with.
+ // The minimum SDK version that this apex must be compatibile with.
Min_sdk_version *string
+
+ // If set true, VNDK libs are considered as stable libs and are not included in this apex.
+ // Should be only used in non-system apexes (e.g. vendor: true).
+ // Default is false.
+ Use_vndk_as_stable *bool
+
+ // The type of filesystem to use for an image apex. Either 'ext4' or 'f2fs'.
+ // Default 'ext4'.
+ Payload_fs_type *string
}
type apexTargetBundleProperties struct {
@@ -1162,6 +1171,9 @@
// List of APKs to package inside APEX
Apps []string
+ // List of runtime resource overlays (RROs) inside APEX
+ Rros []string
+
// Names of modules to be overridden. Listed modules can only be other binaries
// (in Make or Soong).
// This does not completely prevent installation of the overridden binaries, but if both
@@ -1254,14 +1266,17 @@
// apexFile represents a file in an APEX bundle
type apexFile struct {
- builtFile android.Path
- stem string
- moduleName string
- installDir string
- class apexFileClass
- module android.Module
+ builtFile android.Path
+ stem string
+ // Module name of `module` in AndroidMk. Note the generated AndroidMk module for
+ // apexFile is named something like <AndroidMk module name>.<apex name>[<apex suffix>]
+ androidMkModuleName string
+ installDir string
+ class apexFileClass
+ module android.Module
// list of symlinks that will be created in installDir that point to this apexFile
symlinks []string
+ dataPaths []android.DataPath
transitiveDep bool
moduleDir string
@@ -1274,23 +1289,25 @@
certificate java.Certificate // only for apps
overriddenPackageName string // only for apps
- noticeFile android.OptionalPath
+ isJniLib bool
+
+ noticeFiles android.Paths
}
-func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile {
+func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, installDir string, class apexFileClass, module android.Module) apexFile {
ret := apexFile{
- builtFile: builtFile,
- moduleName: moduleName,
- installDir: installDir,
- class: class,
- module: module,
+ builtFile: builtFile,
+ androidMkModuleName: androidMkModuleName,
+ installDir: installDir,
+ class: class,
+ module: module,
}
if module != nil {
ret.moduleDir = ctx.OtherModuleDir(module)
ret.requiredModuleNames = module.RequiredModuleNames()
ret.targetRequiredModuleNames = module.TargetRequiredModuleNames()
ret.hostRequiredModuleNames = module.HostRequiredModuleNames()
- ret.noticeFile = module.NoticeFile()
+ ret.noticeFiles = module.NoticeFiles()
}
return ret
}
@@ -1319,7 +1336,7 @@
func (af *apexFile) SymlinkPaths() []string {
var ret []string
for _, symlink := range af.symlinks {
- ret = append(ret, filepath.Join(af.installDir, symlink))
+ ret = append(ret, af.apexRelativePath(symlink))
}
return ret
}
@@ -1334,6 +1351,24 @@
return false
}
+type fsType int
+
+const (
+ ext4 fsType = iota
+ f2fs
+)
+
+func (f fsType) string() string {
+ switch f {
+ case ext4:
+ return ext4FsType
+ case f2fs:
+ return f2fsFsType
+ default:
+ panic(fmt.Errorf("unknown APEX payload type %d", f))
+ }
+}
+
type apexBundle struct {
android.ModuleBase
android.DefaultableModuleBase
@@ -1359,7 +1394,7 @@
container_certificate_file android.Path
container_private_key_file android.Path
- fileContexts android.Path
+ fileContexts android.WritablePath
// list of files to be included in this apex
filesInfo []apexFile
@@ -1399,29 +1434,37 @@
// Optional list of lint report zip files for apexes that contain java or app modules
lintReports android.Paths
+
+ payloadFsType fsType
}
func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext,
- native_shared_libs []string, binaries []string, tests []string,
+ nativeModules ApexNativeDependencies,
target android.Target, imageVariation string) {
// Use *FarVariation* to be able to depend on modules having
// conflicting variations with this module. This is required since
// arch variant of an APEX bundle is 'common' but it is 'arm' or 'arm64'
// for native shared libs.
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: imageVariation},
- {Mutator: "link", Variation: "shared"},
- {Mutator: "version", Variation: ""}, // "" is the non-stub variant
- }...), sharedLibTag, native_shared_libs...)
- ctx.AddFarVariationDependencies(append(target.Variations(),
- blueprint.Variation{Mutator: "image", Variation: imageVariation}),
- executableTag, binaries...)
+ binVariations := target.Variations()
+ libVariations := append(target.Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: imageVariation},
- {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }...), testTag, tests...)
+ if ctx.Device() {
+ binVariations = append(binVariations,
+ blueprint.Variation{Mutator: "image", Variation: imageVariation})
+ libVariations = append(libVariations,
+ blueprint.Variation{Mutator: "image", Variation: imageVariation},
+ blueprint.Variation{Mutator: "version", Variation: ""}) // "" is the non-stub variant
+ }
+
+ ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
+
+ ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
+
+ ctx.AddFarVariationDependencies(binVariations, executableTag, nativeModules.Binaries...)
+
+ ctx.AddFarVariationDependencies(binVariations, testTag, nativeModules.Tests...)
}
func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
@@ -1444,6 +1487,7 @@
targets := ctx.MultiTargets()
config := ctx.DeviceConfig()
+ imageVariation := a.getImageVariation(ctx)
a.combineProperties(ctx)
@@ -1454,91 +1498,69 @@
}
}
for i, target := range targets {
- // When multilib.* is omitted for native_shared_libs, it implies
- // multilib.both.
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(config)},
- {Mutator: "link", Variation: "shared"},
- }...), sharedLibTag, a.properties.Native_shared_libs...)
-
- // When multilib.* is omitted for tests, it implies
- // multilib.both.
- ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: a.getImageVariation(config)},
- {Mutator: "test_per_src", Variation: ""}, // "" is the all-tests variant
- }...), testTag, a.properties.Tests...)
+ // When multilib.* is omitted for native_shared_libs/jni_libs/tests, it implies
+ // multilib.both
+ addDependenciesForNativeModules(ctx,
+ ApexNativeDependencies{
+ Native_shared_libs: a.properties.Native_shared_libs,
+ Tests: a.properties.Tests,
+ Jni_libs: a.properties.Jni_libs,
+ Binaries: nil,
+ },
+ target, imageVariation)
// Add native modules targetting both ABIs
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Both.Native_shared_libs,
- a.properties.Multilib.Both.Binaries,
- a.properties.Multilib.Both.Tests,
+ a.properties.Multilib.Both,
target,
- a.getImageVariation(config))
+ imageVariation)
isPrimaryAbi := i == 0
if isPrimaryAbi {
// When multilib.* is omitted for binaries, it implies
- // multilib.first.
- ctx.AddFarVariationDependencies(append(target.Variations(),
- blueprint.Variation{Mutator: "image", Variation: a.getImageVariation(config)}),
- executableTag, a.properties.Binaries...)
+ // multilib.first
+ addDependenciesForNativeModules(ctx,
+ ApexNativeDependencies{
+ Native_shared_libs: nil,
+ Tests: nil,
+ Jni_libs: nil,
+ Binaries: a.properties.Binaries,
+ },
+ target, imageVariation)
// Add native modules targetting the first ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.First.Native_shared_libs,
- a.properties.Multilib.First.Binaries,
- a.properties.Multilib.First.Tests,
+ a.properties.Multilib.First,
target,
- a.getImageVariation(config))
+ imageVariation)
}
switch target.Arch.ArchType.Multilib {
case "lib32":
// Add native modules targetting 32-bit ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Lib32.Native_shared_libs,
- a.properties.Multilib.Lib32.Binaries,
- a.properties.Multilib.Lib32.Tests,
+ a.properties.Multilib.Lib32,
target,
- a.getImageVariation(config))
+ imageVariation)
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Prefer32.Native_shared_libs,
- a.properties.Multilib.Prefer32.Binaries,
- a.properties.Multilib.Prefer32.Tests,
+ a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
+ imageVariation)
case "lib64":
// Add native modules targetting 64-bit ABI
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Lib64.Native_shared_libs,
- a.properties.Multilib.Lib64.Binaries,
- a.properties.Multilib.Lib64.Tests,
+ a.properties.Multilib.Lib64,
target,
- a.getImageVariation(config))
+ imageVariation)
if !has32BitTarget {
addDependenciesForNativeModules(ctx,
- a.properties.Multilib.Prefer32.Native_shared_libs,
- a.properties.Multilib.Prefer32.Binaries,
- a.properties.Multilib.Prefer32.Tests,
+ a.properties.Multilib.Prefer32,
target,
- a.getImageVariation(config))
- }
-
- if strings.HasPrefix(ctx.ModuleName(), "com.android.runtime") && target.Os.Class == android.Device {
- for _, sanitizer := range ctx.Config().SanitizeDevice() {
- if sanitizer == "hwaddress" {
- addDependenciesForNativeModules(ctx,
- []string{"libclang_rt.hwasan-aarch64-android"},
- nil, nil, target, a.getImageVariation(config))
- break
- }
- }
+ imageVariation)
}
}
-
}
// For prebuilt_etc, use the first variant (64 on 64/32bit device,
@@ -1597,6 +1619,8 @@
}
ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
androidAppTag, a.overridableProperties.Apps...)
+ ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(),
+ rroTag, a.overridableProperties.Rros...)
}
func (a *apexBundle) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
@@ -1639,15 +1663,33 @@
return proptools.Bool(a.properties.Test_only_unsigned_payload)
}
-func (a *apexBundle) getImageVariation(config android.DeviceConfig) string {
+func (a *apexBundle) getImageVariation(ctx android.BottomUpMutatorContext) string {
+ deviceConfig := ctx.DeviceConfig()
if a.vndkApex {
- return cc.VendorVariationPrefix + a.vndkVersion(config)
+ return cc.VendorVariationPrefix + a.vndkVersion(deviceConfig)
}
- if config.VndkVersion() != "" && proptools.Bool(a.properties.Use_vendor) {
- return cc.VendorVariationPrefix + config.PlatformVndkVersion()
- } else {
- return android.CoreVariation
+
+ var prefix string
+ var vndkVersion string
+ if deviceConfig.VndkVersion() != "" {
+ if proptools.Bool(a.properties.Use_vendor) {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ } else if a.SocSpecific() || a.DeviceSpecific() {
+ prefix = cc.VendorVariationPrefix
+ vndkVersion = deviceConfig.VndkVersion()
+ } else if a.ProductSpecific() {
+ prefix = cc.ProductVariationPrefix
+ vndkVersion = deviceConfig.ProductVndkVersion()
+ }
}
+ if vndkVersion == "current" {
+ vndkVersion = deviceConfig.PlatformVndkVersion()
+ }
+ if vndkVersion != "" {
+ return prefix + vndkVersion
+ }
+ return android.CoreVariation
}
func (a *apexBundle) EnableSanitizer(sanitizerName string) {
@@ -1674,6 +1716,23 @@
return android.InList(sanitizerName, globalSanitizerNames)
}
+func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string) {
+ if ctx.Device() && sanitizerName == "hwaddress" && strings.HasPrefix(a.Name(), "com.android.runtime") {
+ for _, target := range ctx.MultiTargets() {
+ if target.Arch.ArchType.Multilib == "lib64" {
+ ctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
+ {Mutator: "image", Variation: a.getImageVariation(ctx)},
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: ""}, // "" is the non-stub variant
+ }...), sharedLibTag, "libclang_rt.hwasan-aarch64-android")
+ break
+ }
+ }
+ }
+}
+
+var _ cc.Coverage = (*apexBundle)(nil)
+
func (a *apexBundle) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
return ctx.Device() && ctx.DeviceConfig().NativeCoverageEnabled()
}
@@ -1690,6 +1749,8 @@
a.properties.IsCoverageVariant = coverage
}
+func (a *apexBundle) EnableCoverageIfNeeded() {}
+
// TODO(jiyong) move apexFileFor* close to the apexFile type definition
func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile {
// Decide the APEX-local directory by the multilib of the library
@@ -1701,10 +1762,10 @@
case "lib64":
dirInApex = "lib64"
}
- dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if ccMod.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, ccMod.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath())
if handleSpecialLibs && cc.InstallToBootstrap(ccMod.BaseModuleName(), ctx.Config()) {
// Special case for Bionic libs and other libs installed with them. This is
// to prevent those libs from being included in the search path
@@ -1720,24 +1781,28 @@
}
fileToCopy := ccMod.OutputFile().Path()
- return newApexFile(ctx, fileToCopy, ccMod.Name(), dirInApex, nativeSharedLib, ccMod)
+ androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName
+ return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod)
}
func apexFileForExecutable(ctx android.BaseModuleContext, cc *cc.Module) apexFile {
- dirInApex := filepath.Join("bin", cc.RelativeInstallPath())
+ dirInApex := "bin"
if cc.Target().NativeBridge == android.NativeBridgeEnabled {
dirInApex = filepath.Join(dirInApex, cc.Target().NativeBridgeRelativePath)
}
+ dirInApex = filepath.Join(dirInApex, cc.RelativeInstallPath())
fileToCopy := cc.OutputFile().Path()
- af := newApexFile(ctx, fileToCopy, cc.Name(), dirInApex, nativeExecutable, cc)
+ androidMkModuleName := cc.BaseModuleName() + cc.Properties.SubName
+ af := newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeExecutable, cc)
af.symlinks = cc.Symlinks()
+ af.dataPaths = cc.DataPaths()
return af
}
func apexFileForPyBinary(ctx android.BaseModuleContext, py *python.Module) apexFile {
dirInApex := "bin"
fileToCopy := py.HostToolPath().Path()
- return newApexFile(ctx, fileToCopy, py.Name(), dirInApex, pyBinary, py)
+ return newApexFile(ctx, fileToCopy, py.BaseModuleName(), dirInApex, pyBinary, py)
}
func apexFileForGoBinary(ctx android.BaseModuleContext, depName string, gb bootstrap.GoBinaryTool) apexFile {
dirInApex := "bin"
@@ -1756,38 +1821,38 @@
func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
dirInApex := filepath.Join("bin", sh.SubDir())
fileToCopy := sh.OutputFile()
- af := newApexFile(ctx, fileToCopy, sh.Name(), dirInApex, shBinary, sh)
+ af := newApexFile(ctx, fileToCopy, sh.BaseModuleName(), dirInApex, shBinary, sh)
af.symlinks = sh.Symlinks()
return af
}
-type javaDependency interface {
- DexJar() android.Path
+type javaModule interface {
+ android.Module
+ BaseModuleName() string
+ DexJarBuildPath() android.Path
JacocoReportClassesFile() android.Path
LintDepSets() java.LintDepSets
Stem() string
}
-var _ javaDependency = (*java.Library)(nil)
-var _ javaDependency = (*java.SdkLibrary)(nil)
-var _ javaDependency = (*java.DexImport)(nil)
-var _ javaDependency = (*java.SdkLibraryImport)(nil)
+var _ javaModule = (*java.Library)(nil)
+var _ javaModule = (*java.SdkLibrary)(nil)
+var _ javaModule = (*java.DexImport)(nil)
+var _ javaModule = (*java.SdkLibraryImport)(nil)
-func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile {
+func apexFileForJavaLibrary(ctx android.BaseModuleContext, module javaModule) apexFile {
dirInApex := "javalib"
- fileToCopy := lib.DexJar()
- // Remove prebuilt_ if necessary so the source and prebuilt modules have the same name.
- name := strings.TrimPrefix(module.Name(), "prebuilt_")
- af := newApexFile(ctx, fileToCopy, name, dirInApex, javaSharedLib, module)
- af.jacocoReportClassesFile = lib.JacocoReportClassesFile()
- af.lintDepSets = lib.LintDepSets()
- af.stem = lib.Stem() + ".jar"
+ fileToCopy := module.DexJarBuildPath()
+ af := newApexFile(ctx, fileToCopy, module.BaseModuleName(), dirInApex, javaSharedLib, module)
+ af.jacocoReportClassesFile = module.JacocoReportClassesFile()
+ af.lintDepSets = module.LintDepSets()
+ af.stem = module.Stem() + ".jar"
return af
}
func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
- dirInApex := filepath.Join("etc", prebuilt.SubDir())
+ dirInApex := filepath.Join(prebuilt.BaseDir(), prebuilt.SubDir())
fileToCopy := prebuilt.OutputFile()
return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
}
@@ -1805,6 +1870,7 @@
OutputFile() android.Path
JacocoReportClassesFile() android.Path
Certificate() java.Certificate
+ BaseModuleName() string
}) apexFile {
appDir := "app"
if aapp.Privileged() {
@@ -1812,7 +1878,7 @@
}
dirInApex := filepath.Join(appDir, aapp.InstallApkName())
fileToCopy := aapp.OutputFile()
- af := newApexFile(ctx, fileToCopy, aapp.Name(), dirInApex, app, aapp)
+ af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
af.jacocoReportClassesFile = aapp.JacocoReportClassesFile()
af.certificate = aapp.Certificate()
@@ -1824,6 +1890,21 @@
return af
}
+func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, rro java.RuntimeResourceOverlayModule) apexFile {
+ rroDir := "overlay"
+ dirInApex := filepath.Join(rroDir, rro.Theme())
+ fileToCopy := rro.OutputFile()
+ af := newApexFile(ctx, fileToCopy, rro.Name(), dirInApex, app, rro)
+ af.certificate = rro.Certificate()
+
+ if a, ok := rro.(interface {
+ OverriddenManifestPackageName() string
+ }); ok {
+ af.overriddenPackageName = a.OverriddenManifestPackageName()
+ }
+ return af
+}
+
func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, bpfProgram bpf.BpfModule) apexFile {
dirInApex := filepath.Join("etc", "bpf")
return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram)
@@ -1838,22 +1919,23 @@
return true
}
-// Function called while walking an APEX's payload dependencies.
-//
-// Return true if the `to` module should be visited, false otherwise.
-type payloadDepsCallback func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool
-
// Visit dependencies that contributes to the payload of this APEX
-func (a *apexBundle) walkPayloadDeps(ctx android.ModuleContext, do payloadDepsCallback) {
+func (a *apexBundle) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
am, ok := child.(android.ApexModule)
if !ok || !am.CanHaveApexVariants() {
return false
}
+ dt := ctx.OtherModuleDependencyTag(child)
+
+ if _, ok := dt.(android.ExcludeFromApexContentsTag); ok {
+ return false
+ }
+
// Check for the direct dependencies that contribute to the payload
- if dt, ok := ctx.OtherModuleDependencyTag(child).(dependencyTag); ok {
- if dt.payload {
+ if adt, ok := dt.(dependencyTag); ok {
+ if adt.payload {
return do(ctx, parent, am, false /* externalDep */)
}
// As soon as the dependency graph crosses the APEX boundary, don't go further.
@@ -1861,7 +1943,7 @@
}
// Check for the indirect dependencies if it is considered as part of the APEX
- if am.ApexName() != "" {
+ if android.InList(ctx.ModuleName(), am.InApexes()) {
return do(ctx, parent, am, false /* externalDep */)
}
@@ -1870,7 +1952,21 @@
}
func (a *apexBundle) minSdkVersion(ctx android.BaseModuleContext) int {
- ver := proptools.StringDefault(a.properties.Min_sdk_version, "current")
+ ver := proptools.String(a.properties.Min_sdk_version)
+ if ver == "" {
+ return android.FutureApiLevel
+ }
+ // Treat the current codenames as "current", which means future API version (10000)
+ // Otherwise, ApiStrToNum converts codename(non-finalized) to a value from [9000...]
+ // and would fail to build against "current".
+ if android.InList(ver, ctx.Config().PlatformVersionActiveCodenames()) {
+ return android.FutureApiLevel
+ }
+ // In "REL" branch, "current" is mapped to finalized sdk version
+ if ctx.Config().PlatformSdkCodename() == "REL" && ver == "current" {
+ return ctx.Config().PlatformSdkVersionInt()
+ }
+ // Finalized codenames are OKAY and will be converted to int
intVer, err := android.ApiStrToNum(ctx, ver)
if err != nil {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
@@ -1878,24 +1974,6 @@
return intVer
}
-// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
-// a dependency tag.
-var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:blueprint.BaseDependencyTag{}\E(, )?`)
-
-func PrettyPrintTag(tag blueprint.DependencyTag) string {
- // Use tag's custom String() method if available.
- if stringer, ok := tag.(fmt.Stringer); ok {
- return stringer.String()
- }
-
- // Otherwise, get a default string representation of the tag's struct.
- tagString := fmt.Sprintf("%#v", tag)
-
- // Remove the boilerplate from BaseDependencyTag as it adds no value.
- tagString = tagCleaner.ReplaceAllString(tagString, "")
- return tagString
-}
-
func (a *apexBundle) Updatable() bool {
return proptools.Bool(a.properties.Updatable)
}
@@ -1909,6 +1987,13 @@
return
}
+ // Because APEXes targeting other than system/system_ext partitions
+ // can't set apex_available, we skip checks for these APEXes
+ if a.SocSpecific() || a.DeviceSpecific() ||
+ (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ return
+ }
+
// Coverage build adds additional dependencies for the coverage-only runtime libraries.
// Requiring them and their transitive depencies with apex_available is not right
// because they just add noise.
@@ -1916,7 +2001,7 @@
return
}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
@@ -1936,14 +2021,7 @@
if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
return true
}
- message := ""
- tagPath := ctx.GetTagPath()
- // Skip the first module as that will be added at the start of the error message by ctx.ModuleErrorf().
- walkPath := ctx.GetWalkPath()[1:]
- for i, m := range walkPath {
- message = fmt.Sprintf("%s\n via tag %s\n -> %s", message, PrettyPrintTag(tagPath[i]), m.String())
- }
- ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, message)
+ ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true))
// Visit this module's dependencies to check and report any issues with their availability.
return true
})
@@ -1959,8 +2037,57 @@
}
}
+func (a *apexBundle) checkMinSdkVersion(ctx android.ModuleContext) {
+ if a.testApex || a.vndkApex {
+ return
+ }
+ // Meaningless to check min_sdk_version when building use_vendor modules against non-Trebleized targets
+ if proptools.Bool(a.properties.Use_vendor) && ctx.DeviceConfig().VndkVersion() == "" {
+ return
+ }
+ android.CheckMinSdkVersion(a, ctx, a.minSdkVersion(ctx))
+}
+
+// Ensures that a lib providing stub isn't statically linked
+func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext) {
+ // Practically, we only care about regular APEXes on the device.
+ if ctx.Host() || a.testApex || a.vndkApex {
+ return
+ }
+
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ if ccm, ok := to.(*cc.Module); ok {
+ apexName := ctx.ModuleName()
+ fromName := ctx.OtherModuleName(from)
+ toName := ctx.OtherModuleName(to)
+
+ // If `to` is not actually in the same APEX as `from` then it does not need apex_available and neither
+ // do any of its dependencies.
+ if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) {
+ // As soon as the dependency graph crosses the APEX boundary, don't go further.
+ return false
+ }
+
+ // The dynamic linker and crash_dump tool in the runtime APEX is the only exception to this rule.
+ // It can't make the static dependencies dynamic because it can't
+ // do the dynamic linking for itself.
+ if apexName == "com.android.runtime" && (fromName == "linker" || fromName == "crash_dump") {
+ return false
+ }
+
+ isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !android.DirectlyInApex(apexName, toName)
+ if isStubLibraryFromOtherApex && !externalDep {
+ ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+
+ "It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false))
+ }
+
+ }
+ return true
+ })
+}
+
func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuild()
+ buildFlattenedAsDefault := ctx.Config().FlattenApex() && !ctx.Config().UnbundledBuildApps()
switch a.properties.ApexType {
case imageApex:
if buildFlattenedAsDefault {
@@ -1996,6 +2123,8 @@
a.checkApexAvailability(ctx)
a.checkUpdatable(ctx)
+ a.checkMinSdkVersion(ctx)
+ a.checkStaticLinkingToStubLibraries(ctx)
handleSpecialLibs := !android.Bool(a.properties.Ignore_system_library_special_case)
@@ -2028,7 +2157,7 @@
})
var filesInfo []apexFile
- // TODO(jiyong) do this using walkPayloadDeps
+ // TODO(jiyong) do this using WalkPayloadDeps
ctx.WalkDepsBlueprint(func(child, parent blueprint.Module) bool {
depTag := ctx.OtherModuleDependencyTag(child)
if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok {
@@ -2037,17 +2166,25 @@
depName := ctx.OtherModuleName(child)
if _, isDirectDep := parent.(*apexBundle); isDirectDep {
switch depTag {
- case sharedLibTag:
+ case sharedLibTag, jniLibTag:
+ isJniLib := depTag == jniLibTag
if c, ok := child.(*cc.Module); ok {
fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
+ fi.isJniLib = isJniLib
filesInfo = append(filesInfo, fi)
- // bootstrap bionic libs are treated as provided by system
- if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+ // Collect the list of stub-providing libs except:
+ // - VNDK libs are only for vendors
+ // - bootstrap bionic libs are treated as provided by system
+ if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
provideNativeLibs = append(provideNativeLibs, fi.Stem())
}
return true // track transitive dependencies
} else {
- ctx.PropertyErrorf("native_shared_libs", "%q is not a cc_library or cc_library_shared module", depName)
+ propertyName := "native_shared_libs"
+ if isJniLib {
+ propertyName = "jni_libs"
+ }
+ ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName)
}
case executableTag:
if cc, ok := child.(*cc.Module); ok {
@@ -2065,7 +2202,7 @@
case javaLibTag:
switch child.(type) {
case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport:
- af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module))
+ af := apexFileForJavaLibrary(ctx, child.(javaModule))
if !af.Ok() {
ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
return false
@@ -2088,13 +2225,19 @@
if ap.Privileged() {
appDir = "priv-app"
}
- af := newApexFile(ctx, ap.OutputFile(), ap.Name(),
+ af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(),
filepath.Join(appDir, ap.BaseModuleName()), appSet, ap)
af.certificate = java.PresignedCertificate
filesInfo = append(filesInfo, af)
} else {
ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
}
+ case rroTag:
+ if rro, ok := child.(java.RuntimeResourceOverlayModule); ok {
+ filesInfo = append(filesInfo, apexFileForRuntimeResourceOverlay(ctx, rro))
+ } else {
+ ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
+ }
case bpfTag:
if bpfProgram, ok := child.(bpf.BpfModule); ok {
filesToCopy, _ := bpfProgram.OutputFiles("")
@@ -2121,13 +2264,13 @@
// We do not add this variation to `filesInfo`, as it has no output;
// however, we do add the other variations of this module as indirect
// dependencies (see below).
- return true
} else {
// Single-output test module (where `test_per_src: false`).
af := apexFileForExecutable(ctx, ccTest)
af.class = nativeTest
filesInfo = append(filesInfo, af)
}
+ return true // track transitive dependencies
} else {
ctx.PropertyErrorf("tests", "%q is not a cc module", depName)
}
@@ -2165,9 +2308,13 @@
// don't include it in this APEX
return false
}
+ if cc.UseVndk() && proptools.Bool(a.properties.Use_vndk_as_stable) && cc.IsVndk() {
+ requireNativeLibs = append(requireNativeLibs, ":vndk")
+ return false
+ }
af := apexFileForNativeLibrary(ctx, cc, handleSpecialLibs)
af.transitiveDep = true
- if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), ctx.OtherModuleName(cc)) && (cc.IsStubs() || cc.HasStubsVariants()) {
+ if !a.Host() && !android.DirectlyInApex(ctx.ModuleName(), depName) && (cc.IsStubs() || cc.HasStubsVariants()) {
// If the dependency is a stubs lib, don't include it in this APEX,
// but make sure that the lib is installed on the device.
// In case no APEX is having the lib, the lib is installed to the system
@@ -2175,8 +2322,17 @@
//
// Always include if we are a host-apex however since those won't have any
// system libraries.
- if !android.DirectlyInAnyApex(ctx, cc.Name()) && !android.InList(cc.Name(), a.requiredDeps) {
- a.requiredDeps = append(a.requiredDeps, cc.Name())
+ if !android.DirectlyInAnyApex(ctx, depName) {
+ // we need a module name for Make
+ name := cc.BaseModuleName() + cc.Properties.SubName
+ if proptools.Bool(a.properties.Use_vendor) {
+ // we don't use subName(.vendor) for a "use_vendor: true" apex
+ // which is supposed to be installed in /system
+ name = cc.BaseModuleName()
+ }
+ if !android.InList(name, a.requiredDeps) {
+ a.requiredDeps = append(a.requiredDeps, name)
+ }
}
requireNativeLibs = append(requireNativeLibs, af.Stem())
// Don't track further
@@ -2192,7 +2348,7 @@
// use the name of the generated test binary (`fileToCopy`) instead of the name
// of the original test module (`depName`, shared by all `test_per_src`
// variations of that module).
- af.moduleName = filepath.Base(af.builtFile.String())
+ af.androidMkModuleName = filepath.Base(af.builtFile.String())
// these are not considered transitive dep
af.transitiveDep = false
filesInfo = append(filesInfo, af)
@@ -2206,7 +2362,7 @@
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
}
} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
- ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", PrettyPrintTag(depTag), depName)
+ ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName)
}
}
}
@@ -2262,22 +2418,15 @@
a.installDir = android.PathForModuleInstall(ctx, "apex")
a.filesInfo = filesInfo
- if a.properties.ApexType != zipApex {
- if a.properties.File_contexts == nil {
- a.fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
- } else {
- a.fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
- if a.Platform() {
- if matched, err := path.Match("system/sepolicy/**/*", a.fileContexts.String()); err != nil || !matched {
- ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", a.fileContexts)
- }
- }
- }
- if !android.ExistentPathForSource(ctx, a.fileContexts.String()).Valid() {
- ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts)
- return
- }
+ switch proptools.StringDefault(a.properties.Payload_fs_type, ext4FsType) {
+ case ext4FsType:
+ a.payloadFsType = ext4
+ case f2fsFsType:
+ a.payloadFsType = f2fs
+ default:
+ ctx.PropertyErrorf("payload_fs_type", "%q is not a valid filesystem for apex [ext4, f2fs]", *a.properties.Payload_fs_type)
}
+
// Optimization. If we are building bundled APEX, for the files that are gathered due to the
// transitive dependencies, don't place them inside the APEX, but place a symlink pointing
// the same library in the system partition, thus effectively sharing the same libraries
@@ -2287,6 +2436,13 @@
a.installable() &&
!proptools.Bool(a.properties.Use_vendor)
+ // APEXes targeting other than system/system_ext partitions use vendor/product variants.
+ // So we can't link them to /system/lib libs which are core variants.
+ if a.SocSpecific() || a.DeviceSpecific() ||
+ (a.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ a.linkToSystemLib = false
+ }
+
// We don't need the optimization for updatable APEXes, as it might give false signal
// to the system health when the APEXes are still bundled (b/149805758)
if a.Updatable() && a.properties.ApexType == imageApex {
@@ -2301,6 +2457,8 @@
// prepare apex_manifest.json
a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
+ a.buildFileContexts(ctx)
+
a.setCertificateAndPrivateKey(ctx)
if a.properties.ApexType == flattenedApex {
a.buildFlattenedApex(ctx)
@@ -2369,9 +2527,6 @@
module.AddProperties(&module.properties)
module.AddProperties(&module.targetProperties)
module.AddProperties(&module.overridableProperties)
- module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
- return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
- })
android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
android.InitSdkAwareModule(module)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index ecdb88e..acb9f80 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -92,6 +92,24 @@
}
}
+// withNativeBridgeTargets sets configuration with targets including:
+// - X86_64 (primary)
+// - X86 (secondary)
+// - Arm64 on X86_64 (native bridge)
+// - Arm on X86 (native bridge)
+func withNativeBridgeEnabled(_ map[string][]byte, config android.Config) {
+ config.Targets[android.Android] = []android.Target{
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86_64", NativeBridgeRelativePath: "arm64"},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "x86", NativeBridgeRelativePath: "arm"},
+ }
+}
+
func withManifestPackageNameOverrides(specs []string) testCustomizer {
return func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.ManifestPackageNameOverrides = specs
@@ -167,6 +185,9 @@
"build/make/core/proguard.flags": nil,
"build/make/core/proguard_basic_keeps.flags": nil,
"dummy.txt": nil,
+ "baz": nil,
+ "bar/baz": nil,
+ "testdata/baz": nil,
"AppSet.apks": nil,
}
@@ -186,6 +207,7 @@
config.TestProductVariables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Q")
config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
+ config.TestProductVariables.Platform_version_active_codenames = []string{"R"}
config.TestProductVariables.Platform_vndk_version = proptools.StringPtr("VER")
for _, handler := range handlers {
@@ -212,19 +234,22 @@
ctx.RegisterModuleType("apex_set", apexSetFactory)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
- cc.RegisterRequiredBuildComponentsForTest(ctx)
+ android.RegisterPrebuiltMutators(ctx)
- // Register this after the prebuilt mutators have been registered (in
- // cc.RegisterRequiredBuildComponentsForTest) to match what happens at runtime.
+ // Register these after the prebuilt mutators have been registered to match what
+ // happens at runtime.
ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
+ cc.RegisterRequiredBuildComponentsForTest(ctx)
+
ctx.RegisterModuleType("cc_test", cc.TestFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
- ctx.RegisterModuleType("prebuilt_etc", prebuilt_etc.PrebuiltEtcFactory)
+ prebuilt_etc.RegisterPrebuiltEtcBuildComponents(ctx)
ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
@@ -255,6 +280,14 @@
_ = os.RemoveAll(buildDir)
}
+// ensure that 'result' equals 'expected'
+func ensureEquals(t *testing.T, result string, expected string) {
+ t.Helper()
+ if result != expected {
+ t.Errorf("%q != %q", expected, result)
+ }
+}
+
// ensure that 'result' contains 'expected'
func ensureContains(t *testing.T, result string, expected string) {
t.Helper()
@@ -263,6 +296,15 @@
}
}
+// ensure that 'result' contains 'expected' exactly one time
+func ensureContainsOnce(t *testing.T, result string, expected string) {
+ t.Helper()
+ count := strings.Count(result, expected)
+ if count != 1 {
+ t.Errorf("%q is found %d times (expected 1 time) in %q", expected, count, result)
+ }
+}
+
// ensures that 'result' does not contain 'notExpected'
func ensureNotContains(t *testing.T, result string, notExpected string) {
t.Helper()
@@ -374,7 +416,14 @@
system_shared_libs: [],
static_executable: true,
stl: "none",
- apex_available: [ "myapex" ],
+ apex_available: [ "myapex", "com.android.gki.*" ],
+ }
+
+ apex {
+ name: "com.android.gki.fake",
+ binaries: ["foo"],
+ key: "myapex.key",
+ file_contexts: ":myapex-file_contexts",
}
cc_library_shared {
@@ -481,13 +530,13 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000")
// Ensure that apex variant is created for the indirect dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -558,6 +607,7 @@
native_shared_libs: ["mylib"],
java_libs: ["myjar"],
apps: ["AppFoo"],
+ rros: ["rro"],
bpfs: ["bpf"],
}
@@ -600,6 +650,11 @@
apex_available: [ "myapex" ],
}
+ runtime_resource_overlay {
+ name: "rro",
+ theme: "blue",
+ }
+
bpf {
name: "bpf",
srcs: ["bpf.c", "bpf2.c"],
@@ -611,6 +666,7 @@
"javalib/myjar.jar",
"lib64/mylib.so",
"app/AppFoo/AppFoo.apk",
+ "overlay/blue/rro.apk",
"etc/bpf/bpf.o",
"etc/bpf/bpf2.o",
})
@@ -677,10 +733,10 @@
ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned")
// Ensure that APEX variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that APEX variant is created for the indirect dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so")
@@ -754,7 +810,7 @@
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with the latest version of stubs for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so")
@@ -762,9 +818,9 @@
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
// Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex)
- ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so")
+ ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so")
// .. and not linking to the stubs variant of mylib3
- ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so")
// Ensure that stubs libs are built without -include flags
mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
@@ -844,7 +900,7 @@
// Ensure that dependency of stubs is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with version 10 of libfoo
ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so")
@@ -936,22 +992,149 @@
}
+func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
+ ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+ bp := `
+ apex {
+ name: "com.android.runtime",
+ key: "com.android.runtime.key",
+ native_shared_libs: ["libc"],
+ }
+
+ apex_key {
+ name: "com.android.runtime.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libc",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ stubs: { versions: ["1"] },
+ apex_available: ["com.android.runtime"],
+
+ sanitize: {
+ hwaddress: true,
+ }
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libclang_rt.hwasan-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ srcs: [""],
+ stubs: { versions: ["1"] },
+
+ sanitize: {
+ never: true,
+ },
+ }
+ `
+ // override bp to use hard-coded names: com.android.runtime and libc
+ fs["Android.bp"] = []byte(bp)
+ fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
+ })
+
+ ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+ "lib64/bionic/libc.so",
+ "lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
+ })
+
+ hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+
+ installed := hwasan.Description("install libclang_rt.hwasan")
+ ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
+
+ symlink := hwasan.Description("install symlink libclang_rt.hwasan")
+ ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so")
+ ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so")
+}
+
+func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
+ ctx, _ := testApex(t, "", func(fs map[string][]byte, config android.Config) {
+ bp := `
+ apex {
+ name: "com.android.runtime",
+ key: "com.android.runtime.key",
+ native_shared_libs: ["libc"],
+ }
+
+ apex_key {
+ name: "com.android.runtime.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libc",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ stubs: { versions: ["1"] },
+ apex_available: ["com.android.runtime"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "libclang_rt.hwasan-aarch64-android",
+ no_libcrt: true,
+ nocrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ srcs: [""],
+ stubs: { versions: ["1"] },
+
+ sanitize: {
+ never: true,
+ },
+ }
+ `
+ // override bp to use hard-coded names: com.android.runtime and libc
+ fs["Android.bp"] = []byte(bp)
+ fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
+
+ config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
+ })
+
+ ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
+ "lib64/bionic/libc.so",
+ "lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
+ })
+
+ hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+
+ installed := hwasan.Description("install libclang_rt.hwasan")
+ ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
+
+ symlink := hwasan.Description("install symlink libclang_rt.hwasan")
+ ensureEquals(t, symlink.Args["fromPath"], "/apex/com.android.runtime/lib64/bionic/libclang_rt.hwasan-aarch64-android.so")
+ ensureContains(t, symlink.Output.String(), "/system/lib64/libclang_rt.hwasan-aarch64-android.so")
+}
+
func TestApexDependsOnLLNDKTransitively(t *testing.T) {
testcases := []struct {
name string
minSdkVersion string
+ apexVariant string
shouldLink string
shouldNotLink []string
}{
{
name: "should link to the latest",
- minSdkVersion: "current",
+ minSdkVersion: "",
+ apexVariant: "apex10000",
shouldLink: "30",
shouldNotLink: []string{"29"},
},
{
name: "should link to llndk#29",
- minSdkVersion: "29",
+ minSdkVersion: "min_sdk_version: \"29\",",
+ apexVariant: "apex29",
shouldLink: "29",
shouldNotLink: []string{"30"},
},
@@ -964,7 +1147,7 @@
key: "myapex.key",
use_vendor: true,
native_shared_libs: ["mylib"],
- min_sdk_version: "`+tc.minSdkVersion+`",
+ `+tc.minSdkVersion+`
}
apex_key {
@@ -981,6 +1164,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1009,13 +1193,13 @@
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
for _, ver := range tc.shouldNotLink {
ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
}
- mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink)
})
}
@@ -1070,9 +1254,9 @@
// Ensure that libc is not included (since it has stubs and not listed in native_shared_libs)
ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
- mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
- mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
+ mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"]
// For dependency to libc
// Ensure that mylib is linking with the latest version of stubs
@@ -1085,7 +1269,7 @@
// For dependency to libm
// Ensure that mylib is linking with the non-stub (impl) variant
- ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so")
+ ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so")
// ... and not linking to the stub variant
ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29/libm.so")
// ... and is not compiling with the stub
@@ -1099,7 +1283,7 @@
ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28/libdl.so")
ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29/libdl.so")
// ... and not linking to the non-stub (impl) variant
- ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so")
+ ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_apex10000/libdl.so")
// ... Cflags from stub is correctly exported to mylib
ensureContains(t, mylibCFlags, "__LIBDL_API__=27")
ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27")
@@ -1111,24 +1295,24 @@
ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so")
}
-func TestApexUseStubsAccordingToMinSdkVersionInUnbundledBuild(t *testing.T) {
+func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) {
// there are three links between liba --> libz
- // 1) myapex -> libx -> liba -> libz : this should be #2 link, but fallback to #1
- // 2) otherapex -> liby -> liba -> libz : this should be #3 link
+ // 1) myapex -> libx -> liba -> libz : this should be #29 link, but fallback to #28
+ // 2) otherapex -> liby -> liba -> libz : this should be #30 link
// 3) (platform) -> liba -> libz : this should be non-stub link
ctx, _ := testApex(t, `
apex {
name: "myapex",
key: "myapex.key",
native_shared_libs: ["libx"],
- min_sdk_version: "2",
+ min_sdk_version: "29",
}
apex {
name: "otherapex",
key: "myapex.key",
native_shared_libs: ["liby"],
- min_sdk_version: "3",
+ min_sdk_version: "30",
}
apex_key {
@@ -1143,6 +1327,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1151,6 +1336,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "otherapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1162,6 +1348,7 @@
"//apex_available:anyapex",
"//apex_available:platform",
],
+ min_sdk_version: "29",
}
cc_library {
@@ -1169,10 +1356,10 @@
system_shared_libs: [],
stl: "none",
stubs: {
- versions: ["1", "3"],
+ versions: ["28", "30"],
},
}
- `, withUnbundledBuild)
+ `)
expectLink := func(from, from_variant, to, to_variant string) {
ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
@@ -1184,14 +1371,14 @@
}
// platform liba is linked to non-stub version
expectLink("liba", "shared", "libz", "shared")
- // liba in myapex is linked to #1
- expectLink("liba", "shared_myapex", "libz", "shared_1")
- expectNoLink("liba", "shared_myapex", "libz", "shared_3")
- expectNoLink("liba", "shared_myapex", "libz", "shared")
- // liba in otherapex is linked to #3
- expectLink("liba", "shared_otherapex", "libz", "shared_3")
- expectNoLink("liba", "shared_otherapex", "libz", "shared_1")
- expectNoLink("liba", "shared_otherapex", "libz", "shared")
+ // liba in myapex is linked to #28
+ expectLink("liba", "shared_apex29", "libz", "shared_28")
+ expectNoLink("liba", "shared_apex29", "libz", "shared_30")
+ expectNoLink("liba", "shared_apex29", "libz", "shared")
+ // liba in otherapex is linked to #30
+ expectLink("liba", "shared_apex30", "libz", "shared_30")
+ expectNoLink("liba", "shared_apex30", "libz", "shared_28")
+ expectNoLink("liba", "shared_apex30", "libz", "shared")
}
func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
@@ -1215,6 +1402,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "R",
}
cc_library {
@@ -1243,12 +1431,12 @@
// to distinguish them from finalized and future_api(10000)
// In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000
// (refer android/api_levels.go)
- expectLink("libx", "shared_myapex", "libz", "shared_9000")
- expectNoLink("libx", "shared_myapex", "libz", "shared_29")
- expectNoLink("libx", "shared_myapex", "libz", "shared")
+ expectLink("libx", "shared_apex10000", "libz", "shared_9000")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared_29")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
-func TestApexMinSdkVersionDefaultsToLatest(t *testing.T) {
+func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) {
ctx, _ := testApex(t, `
apex {
name: "myapex",
@@ -1288,9 +1476,9 @@
ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
- expectLink("libx", "shared_myapex", "libz", "shared_2")
- expectNoLink("libx", "shared_myapex", "libz", "shared_1")
- expectNoLink("libx", "shared_myapex", "libz", "shared")
+ expectLink("libx", "shared_apex10000", "libz", "shared_2")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared_1")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
@@ -1357,6 +1545,7 @@
name: "libx",
shared_libs: ["libbar"],
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1373,7 +1562,7 @@
libFlags := ld.Args["libFlags"]
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
- expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
+ expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_30")
}
func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
@@ -1394,18 +1583,19 @@
cc_library {
name: "libx",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
`)
// ensure apex variant of c++ is linked with static unwinder
- cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
+ cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module)
ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
// note that platform variant is not.
cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
}
-func TestInvalidMinSdkVersion(t *testing.T) {
+func TestApexMinSdkVersion_ErrorIfIncompatibleStubs(t *testing.T) {
testApexError(t, `"libz" .*: not found a version\(<=29\)`, `
apex {
name: "myapex",
@@ -1426,6 +1616,7 @@
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
cc_library {
@@ -1437,12 +1628,15 @@
},
}
`)
+}
- testApexError(t, `"myapex" .*: min_sdk_version: SDK version should be .*`, `
+func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) {
+ testApexError(t, `module "mylib".*: should support min_sdk_version\(29\)`, `
apex {
name: "myapex",
key: "myapex.key",
- min_sdk_version: "abc",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
}
apex_key {
@@ -1450,6 +1644,67 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_Okay(t *testing.T) {
+ testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["libfoo"],
+ java_libs: ["libbar"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libfoo",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libfoo_dep"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ cc_library {
+ name: "libfoo_dep",
+ srcs: ["mylib.cpp"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ java_library {
+ name: "libbar",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ static_libs: ["libbar_dep"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
+
+ java_library {
+ name: "libbar_dep",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ apex_available: ["myapex"],
+ min_sdk_version: "29",
+ }
`)
}
@@ -1500,6 +1755,7 @@
srcs: ["foo/bar/MyClass.java"],
sdk_version: "current",
apex_available: ["myapex"],
+ min_sdk_version: "29",
}
`,
},
@@ -1569,6 +1825,135 @@
}
}
+func TestApexMinSdkVersion_ErrorIfDepIsNewer(t *testing.T) {
+ testApexError(t, `module "mylib2".*: should support min_sdk_version\(29\) for "myapex"`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "29",
+ }
+
+ // indirect part of the apex
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ ],
+ min_sdk_version: "30",
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_ErrorIfDepIsNewer_Java(t *testing.T) {
+ testApexError(t, `module "bar".*: should support min_sdk_version\(29\) for "myapex"`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ apps: ["AppFoo"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ android_app {
+ name: "AppFoo",
+ srcs: ["foo/bar/MyClass.java"],
+ sdk_version: "current",
+ min_sdk_version: "29",
+ system_modules: "none",
+ stl: "none",
+ static_libs: ["bar"],
+ apex_available: [ "myapex" ],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ srcs: ["a.java"],
+ apex_available: [ "myapex" ],
+ }
+ `)
+}
+
+func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ min_sdk_version: "29",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ // mylib in myapex will link to mylib2#29
+ // mylib in otherapex will link to mylib2(non-stub) in otherapex as well
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["myapex", "otherapex"],
+ min_sdk_version: "29",
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: ["otherapex"],
+ stubs: { versions: ["29", "30"] },
+ min_sdk_version: "30",
+ }
+
+ apex {
+ name: "otherapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "mylib2"],
+ min_sdk_version: "30",
+ }
+ `)
+ expectLink := func(from, from_variant, to, to_variant string) {
+ ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld")
+ libFlags := ld.Args["libFlags"]
+ ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
+ }
+ expectLink("mylib", "shared_apex29", "mylib2", "shared_29")
+ expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
+}
+
func TestFilesInSubDir(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1631,6 +2016,64 @@
ensureListContains(t, dirs, "bin/foo/bar")
}
+func TestFilesInSubDirWhenNativeBridgeEnabled(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ multilib: {
+ both: {
+ native_shared_libs: ["mylib"],
+ binaries: ["mybin"],
+ },
+ },
+ compile_multilib: "both",
+ native_bridge_supported: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ }
+
+ cc_binary {
+ name: "mybin",
+ relative_install_path: "foo/bar",
+ system_shared_libs: [],
+ static_executable: true,
+ stl: "none",
+ apex_available: [ "myapex" ],
+ native_bridge_supported: true,
+ compile_multilib: "both", // default is "first" for binary
+ multilib: {
+ lib64: {
+ suffix: "64",
+ },
+ },
+ }
+ `, withNativeBridgeEnabled)
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/foo/bar/mybin",
+ "bin/foo/bar/mybin64",
+ "bin/arm/foo/bar/mybin",
+ "bin/arm64/foo/bar/mybin64",
+ "lib/foo/bar/mylib.so",
+ "lib/arm/foo/bar/mylib.so",
+ "lib64/foo/bar/mylib.so",
+ "lib64/arm64/foo/bar/mylib.so",
+ })
+}
+
func TestUseVendor(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -1677,15 +2120,15 @@
inputsString := strings.Join(inputsList, " ")
// ensure that the apex includes vendor variants of the direct and indirect deps
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib.so")
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib2.so")
+ ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so")
+ ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so")
// ensure that the apex does not include core variants
- ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib.so")
- ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so")
+ ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so")
+ ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib2.so")
}
-func TestUseVendorRestriction(t *testing.T) {
+func TestUseVendorNotAllowedForSystemApexes(t *testing.T) {
testApexError(t, `module "myapex" .*: use_vendor: not allowed`, `
apex {
name: "myapex",
@@ -1741,6 +2184,224 @@
`)
}
+func TestVendorApex(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["mybin"],
+ vendor: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ vendor: true,
+ shared_libs: ["libfoo"],
+ }
+ cc_library {
+ name: "libfoo",
+ proprietary: true,
+ }
+ `)
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/mybin",
+ "lib64/libfoo.so",
+ // TODO(b/159195575): Add an option to use VNDK libs from VNDK APEX
+ "lib64/libc++.so",
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, `LOCAL_MODULE_PATH := /tmp/target/product/test_device/vendor/apex`)
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
+ ensureListNotContains(t, requireNativeLibs, ":vndk")
+}
+
+func TestVendorApex_use_vndk_as_stable(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ binaries: ["mybin"],
+ vendor: true,
+ use_vndk_as_stable: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ vendor: true,
+ shared_libs: ["libvndk", "libvendor"],
+ }
+ cc_library {
+ name: "libvndk",
+ vndk: {
+ enabled: true,
+ },
+ vendor_available: true,
+ }
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ }
+ `)
+
+ vendorVariant := "android_vendor.VER_arm64_armv8-a"
+
+ ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld")
+ libs := names(ldRule.Args["libFlags"])
+ // VNDK libs(libvndk/libc++) as they are
+ ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so")
+ ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so")
+ // non-stable Vendor libs as APEX variants
+ ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so")
+
+ // VNDK libs are not included when use_vndk_as_stable: true
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "bin/mybin",
+ "lib64/libvendor.so",
+ })
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"])
+ ensureListContains(t, requireNativeLibs, ":vndk")
+}
+
+func TestVendorApex_withPrebuiltFirmware(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ prebuilts: ["myfirmware"],
+ vendor: true,
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ prebuilt_firmware {
+ name: "myfirmware",
+ src: "myfirmware.bin",
+ filename_from_src: true,
+ vendor: true,
+ }
+ `)
+
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "firmware/myfirmware.bin",
+ })
+}
+
+func TestAndroidMk_UseVendorRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ use_vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ apex_available: ["myapex"],
+ }
+ `, func(fs map[string][]byte, config android.Config) {
+ setUseVendorAllowListForTest(config, []string{"myapex"})
+ })
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc libm libdl\n")
+}
+
+func TestAndroidMk_VendorApexRequired(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vendor: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ vendor_available: true,
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += libc.vendor libm.vendor libdl.vendor\n")
+}
+
+func TestAndroidMkWritesCommonProperties(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ vintf_fragments: ["fragment.xml"],
+ init_rc: ["init.rc"],
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ cc_binary {
+ name: "mybin",
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ name := apexBundle.BaseModuleName()
+ prefix := "TARGET_"
+ var builder strings.Builder
+ data.Custom(&builder, name, prefix, "", data)
+ androidMk := builder.String()
+ ensureContains(t, androidMk, "LOCAL_VINTF_FRAGMENTS := fragment.xml\n")
+ ensureContains(t, androidMk, "LOCAL_INIT_RC := init.rc\n")
+}
+
func TestStaticLinking(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -2000,6 +2661,7 @@
"otherapex",
],
recovery_available: true,
+ min_sdk_version: "29",
}
cc_library {
name: "mylib2",
@@ -2010,7 +2672,22 @@
"myapex",
"otherapex",
],
+ static_libs: ["mylib3"],
+ recovery_available: true,
+ min_sdk_version: "29",
+ }
+ cc_library {
+ name: "mylib3",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "otherapex",
+ ],
use_apex_name_macro: true,
+ recovery_available: true,
+ min_sdk_version: "29",
}
`)
@@ -2020,19 +2697,43 @@
ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
- // When cc_library sets use_apex_name_macro: true
- // apex variants define additional macro to distinguish which apex variant it is built for
+ // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and
+ // each variant defines additional macros to distinguish which apex variant it is built for
+
+ // non-APEX variant does not have __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+ // recovery variant does not set __ANDROID_SDK_VERSION__
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
+
+ // When a dependency of a cc_library sets use_apex_name_macro: true each apex gets a unique
+ // variant.
// non-APEX variant does not have __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
@@ -2041,17 +2742,17 @@
// APEX variant has __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
- ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
// APEX variant has __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
- ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
// recovery variant does not set __ANDROID_SDK_VERSION__
- mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
}
@@ -2504,15 +3205,7 @@
stl: "none",
apex_available: [ "myapex" ],
}
- `+vndkLibrariesTxtFiles("current"),
- withTargets(map[android.OsType][]android.Target{
- android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm64", NativeBridgeRelativePath: "x86_64"},
- {Os: android.Android, Arch: android.Arch{ArchType: android.X86, ArchVariant: "silvermont", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeEnabled, NativeBridgeHostArchName: "arm", NativeBridgeRelativePath: "x86"},
- },
- }))
+ `+vndkLibrariesTxtFiles("current"), withNativeBridgeEnabled)
ensureExactContents(t, ctx, "myapex", "android_common_image", []string{
"lib/libvndk.so",
@@ -2607,7 +3300,8 @@
withBinder32bit,
withTargets(map[android.OsType][]android.Target{
android.Android: []android.Target{
- {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
+ {Os: android.Android, Arch: android.Arch{ArchType: android.Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}},
+ NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
},
}),
)
@@ -2618,6 +3312,40 @@
})
}
+func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex_vndk {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: ":myapex-file_contexts",
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "libz",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ stubs: {
+ symbol_file: "libz.map.txt",
+ versions: ["30"],
+ }
+ }
+ `+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{
+ "libz.map.txt": nil,
+ }))
+
+ apexManifestRule := ctx.ModuleForTests("myapex", "android_common_image").Rule("apexManifestRule")
+ provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
+ ensureListEmpty(t, provideNativeLibs)
+}
+
func TestDependenciesInApexManifest(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -2804,7 +3532,7 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
@@ -2860,7 +3588,7 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so")
@@ -2944,9 +3672,9 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex")
- ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -3031,110 +3759,104 @@
}
}
-func TestFileContexts(t *testing.T) {
+func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) {
ctx, _ := testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`)
module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule := module.Rule("apexRule")
- actual := apexRule.Args["file_contexts"]
- expected := "system/sepolicy/apex/myapex-file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts")
+}
+func TestFileContexts_ShouldBeUnderSystemSepolicyForSystemApexes(t *testing.T) {
testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- file_contexts: "my_own_file_contexts",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ file_contexts: "my_own_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`, withFiles(map[string][]byte{
"my_own_file_contexts": nil,
}))
+}
+func TestFileContexts_ProductSpecificApexes(t *testing.T) {
testApexError(t, `"myapex" .*: file_contexts: cannot find`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: "product_specific_file_contexts",
- }
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: "product_specific_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`)
- ctx, _ = testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: "product_specific_file_contexts",
- }
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: "product_specific_file_contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
`, withFiles(map[string][]byte{
"product_specific_file_contexts": nil,
}))
- module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule = module.Rule("apexRule")
- actual = apexRule.Args["file_contexts"]
- expected = "product_specific_file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
+}
- ctx, _ = testApex(t, `
- apex {
- name: "myapex",
- key: "myapex.key",
- product_specific: true,
- file_contexts: ":my-file-contexts",
- }
+func TestFileContexts_SetViaFileGroup(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ product_specific: true,
+ file_contexts: ":my-file-contexts",
+ }
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
- filegroup {
- name: "my-file-contexts",
- srcs: ["product_specific_file_contexts"],
- }
+ filegroup {
+ name: "my-file-contexts",
+ srcs: ["product_specific_file_contexts"],
+ }
`, withFiles(map[string][]byte{
"product_specific_file_contexts": nil,
}))
- module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
- apexRule = module.Rule("apexRule")
- actual = apexRule.Args["file_contexts"]
- expected = "product_specific_file_contexts"
- if actual != expected {
- t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
- }
+ module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+ rule := module.Output("file_contexts")
+ ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts")
}
func TestApexKeyFromOtherModule(t *testing.T) {
@@ -3247,14 +3969,38 @@
private_key: "testkey.pem",
}
+ filegroup {
+ name: "fg",
+ srcs: [
+ "baz",
+ "bar/baz"
+ ],
+ }
+
cc_test {
name: "mytest",
gtest: false,
srcs: ["mytest.cpp"],
relative_install_path: "test",
+ shared_libs: ["mylib"],
system_shared_libs: [],
static_executable: true,
stl: "none",
+ data: [":fg"],
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ filegroup {
+ name: "fg2",
+ srcs: [
+ "testdata/baz"
+ ],
}
cc_test {
@@ -3270,14 +4016,23 @@
system_shared_libs: [],
static_executable: true,
stl: "none",
+ data: [
+ ":fg",
+ ":fg2",
+ ],
}
`)
apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
copyCmds := apexRule.Args["copy_commands"]
- // Ensure that test dep is copied into apex.
+ // Ensure that test dep (and their transitive dependencies) are copied into apex.
ensureContains(t, copyCmds, "image.apex/bin/test/mytest")
+ ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
+
+ //Ensure that test data are copied into apex.
+ ensureContains(t, copyCmds, "image.apex/bin/test/baz")
+ ensureContains(t, copyCmds, "image.apex/bin/test/bar/baz")
// Ensure that test deps built with `test_per_src` are copied into apex.
ensureContains(t, copyCmds, "image.apex/bin/test/mytest1")
@@ -3285,9 +4040,9 @@
ensureContains(t, copyCmds, "image.apex/bin/test/mytest3")
// Ensure the module is correctly translated.
- apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
- data := android.AndroidMkDataForTest(t, config, "", apexBundle)
- name := apexBundle.BaseModuleName()
+ bundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", bundle)
+ name := bundle.BaseModuleName()
prefix := "TARGET_"
var builder strings.Builder
data.Custom(&builder, name, prefix, "", data)
@@ -3299,6 +4054,13 @@
ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex\n")
ensureContains(t, androidMk, "LOCAL_MODULE := apex_pubkey.myapex\n")
ensureContains(t, androidMk, "LOCAL_MODULE := myapex\n")
+
+ flatBundle := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle)
+ data = android.AndroidMkDataForTest(t, config, "", flatBundle)
+ data.Custom(&builder, name, prefix, "", data)
+ flatAndroidMk := builder.String()
+ ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :baz :bar/baz\n")
+ ensureContainsOnce(t, flatAndroidMk, "LOCAL_TEST_DATA := :testdata/baz\n")
}
func TestInstallExtraFlattenedApexes(t *testing.T) {
@@ -3377,8 +4139,8 @@
apexRule2 := module2.Rule("apexRule")
copyCmds2 := apexRule2.Args["copy_commands"]
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_commonapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_apex10000")
ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so")
ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so")
ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so")
@@ -3558,14 +4320,14 @@
ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
- appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs")
+ appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs")
// JNI libraries are uncompressed
if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") {
t.Errorf("jni libs are not uncompressed for AppFoo")
}
// JNI libraries including transitive deps are
for _, jni := range []string{"libjni", "libfoo"} {
- jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
+ jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile()
// ... embedded inside APK (jnilibs.zip)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX
@@ -3597,6 +4359,7 @@
dex_preopt: {
enabled: false,
},
+ apex_available: ["myapex"],
}
android_app_import {
@@ -3608,6 +4371,7 @@
enabled: false,
},
filename: "AwesomePrebuiltAppFooPriv.apk",
+ apex_available: ["myapex"],
}
`)
@@ -3649,6 +4413,7 @@
filename: "AppFooPrebuilt.apk",
presigned: true,
prefer: true,
+ apex_available: ["myapex"],
}
`, withFiles(map[string][]byte{
"AppFooPrebuilt.apk": nil,
@@ -3762,11 +4527,11 @@
func TestApexAvailable_IndirectDep(t *testing.T) {
// libbbaz is an indirect dep
testApexError(t, `requires "libbaz" that is not available for the APEX. Dependency path:
-.*via tag apex\.dependencyTag.*"sharedLib".*
+.*via tag apex\.dependencyTag.*name:sharedLib.*
.*-> libfoo.*link:shared.*
-.*via tag cc\.DependencyTag.*"shared".*
+.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
.*-> libbar.*link:shared.*
-.*via tag cc\.DependencyTag.*"shared".*
+.*via tag cc\.libraryDependencyTag.*Kind:sharedLibraryDependency.*
.*-> libbaz.*link:shared.*`, `
apex {
name: "myapex",
@@ -4062,6 +4827,7 @@
stl: "libc++",
system_shared_libs: [],
apex_available: [ "myapex" ],
+ min_sdk_version: "29",
}
`, withUnbundledBuild)
@@ -4075,7 +4841,7 @@
// the dependency names directly here but for some reason the names are blank in
// this test.
for _, lib := range []string{"libc++", "mylib"} {
- apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
+ apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits
nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
if len(apexImplicits) != len(nonApexImplicits)+1 {
t.Errorf("%q missing unwinder dep", lib)
@@ -4462,6 +5228,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
cc_library {
@@ -4474,6 +5241,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
java_library {
@@ -4487,6 +5255,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
java_library {
@@ -4499,6 +5268,7 @@
"myapex.updatable",
"//apex_available:platform",
],
+ min_sdk_version: "current",
}
`
@@ -4552,6 +5322,98 @@
ensureRealfileExists(t, files, "lib64/myotherlib.so") // this is a real file
}
+func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) {
+ ctx, config := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library_shared {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["myotherlib"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "//apex_available:platform",
+ ],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "myotherlib",
+ srcs: ["prebuilt.so"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "//apex_available:platform",
+ ],
+ }
+ `)
+
+ apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+ data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+ var builder strings.Builder
+ data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data)
+ androidMk := builder.String()
+ // `myotherlib` is added to `myapex` as symlink
+ ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+ ensureNotContains(t, androidMk, "LOCAL_MODULE := prebuilt_myotherlib.myapex\n")
+ ensureNotContains(t, androidMk, "LOCAL_MODULE := myotherlib.myapex\n")
+ // `myapex` should have `myotherlib` in its required line, not `prebuilt_myotherlib`
+ ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += mylib.myapex myotherlib apex_manifest.pb.myapex apex_pubkey.myapex\n")
+}
+
+func TestApexWithJniLibs(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ jni_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+ `)
+
+ rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule")
+ // Notice mylib2.so (transitive dep) is not added as a jni_lib
+ ensureEquals(t, rule.Args["opt"], "-a jniLibs mylib.so")
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "lib64/mylib.so",
+ "lib64/mylib2.so",
+ })
+}
+
func TestApexMutatorsDontRunIfDisabled(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -4635,96 +5497,9 @@
ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$")
}
-func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
+func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
t.Helper()
- bp = bp + `
- filegroup {
- name: "some-updatable-apex-file_contexts",
- srcs: [
- "system/sepolicy/apex/some-updatable-apex-file_contexts",
- ],
- }
-
- filegroup {
- name: "some-non-updatable-apex-file_contexts",
- srcs: [
- "system/sepolicy/apex/some-non-updatable-apex-file_contexts",
- ],
- }
- `
- bp += cc.GatherRequiredDepsForTest(android.Android)
- bp += java.GatherRequiredDepsForTest()
- bp += dexpreopt.BpToolModulesForTest()
-
- fs := map[string][]byte{
- "a.java": nil,
- "a.jar": nil,
- "build/make/target/product/security": nil,
- "apex_manifest.json": nil,
- "AndroidManifest.xml": nil,
- "system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
- "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
- "system/sepolicy/apex/com.android.art.something-file_contexts": nil,
- "framework/aidl/a.aidl": nil,
- }
- cc.GatherRequiredFilesForTest(fs)
-
- ctx := android.NewTestArchContext()
- ctx.RegisterModuleType("apex", BundleFactory)
- ctx.RegisterModuleType("apex_key", ApexKeyFactory)
- ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- cc.RegisterRequiredBuildComponentsForTest(ctx)
- java.RegisterJavaBuildComponents(ctx)
- java.RegisterSystemModulesBuildComponents(ctx)
- java.RegisterAppBuildComponents(ctx)
- java.RegisterDexpreoptBootJarsComponents(ctx)
- ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
- ctx.PreDepsMutators(RegisterPreDepsMutators)
- ctx.PostDepsMutators(RegisterPostDepsMutators)
-
- config := android.TestArchConfig(buildDir, nil, bp, fs)
- ctx.Register(config)
-
- _ = dexpreopt.GlobalSoongConfigForTests(config)
- dexpreopt.RegisterToolModulesForTest(ctx)
- pathCtx := android.PathContextForTesting(config)
- dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- transformDexpreoptConfig(dexpreoptConfig)
- dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
- _, errs := ctx.ParseBlueprintsFiles("Android.bp")
- android.FailIfErrored(t, errs)
-
- _, errs = ctx.PrepareBuildActions(config)
- if errmsg == "" {
- android.FailIfErrored(t, errs)
- } else if len(errs) > 0 {
- android.FailIfNoMatchingErrors(t, errmsg, errs)
- return
- } else {
- t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
- }
-}
-
-func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
- testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- updatable: true,
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
- `)
-}
-
-func TestNoUpdatableJarsInBootImage(t *testing.T) {
bp := `
java_library {
name: "some-updatable-apex-lib",
@@ -4793,77 +5568,176 @@
apex_key {
name: "com.android.art.something.key",
}
- `
- var error string
+ filegroup {
+ name: "some-updatable-apex-file_contexts",
+ srcs: [
+ "system/sepolicy/apex/some-updatable-apex-file_contexts",
+ ],
+ }
+
+ filegroup {
+ name: "some-non-updatable-apex-file_contexts",
+ srcs: [
+ "system/sepolicy/apex/some-non-updatable-apex-file_contexts",
+ ],
+ }
+ `
+ bp += cc.GatherRequiredDepsForTest(android.Android)
+ bp += java.GatherRequiredDepsForTest()
+ bp += dexpreopt.BpToolModulesForTest()
+
+ fs := map[string][]byte{
+ "a.java": nil,
+ "a.jar": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "AndroidManifest.xml": nil,
+ "system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
+ "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil,
+ "system/sepolicy/apex/com.android.art.something-file_contexts": nil,
+ "framework/aidl/a.aidl": nil,
+ }
+ cc.GatherRequiredFilesForTest(fs)
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("apex", BundleFactory)
+ ctx.RegisterModuleType("apex_key", ApexKeyFactory)
+ ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ android.RegisterPrebuiltMutators(ctx)
+ cc.RegisterRequiredBuildComponentsForTest(ctx)
+ java.RegisterJavaBuildComponents(ctx)
+ java.RegisterSystemModulesBuildComponents(ctx)
+ java.RegisterAppBuildComponents(ctx)
+ java.RegisterDexpreoptBootJarsComponents(ctx)
+ ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
+ ctx.PreDepsMutators(RegisterPreDepsMutators)
+ ctx.PostDepsMutators(RegisterPostDepsMutators)
+
+ config := android.TestArchConfig(buildDir, nil, bp, fs)
+ ctx.Register(config)
+
+ _ = dexpreopt.GlobalSoongConfigForTests(config)
+ dexpreopt.RegisterToolModulesForTest(ctx)
+ pathCtx := android.PathContextForTesting(config)
+ dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+ transformDexpreoptConfig(dexpreoptConfig)
+ dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
+
+ _, errs := ctx.ParseBlueprintsFiles("Android.bp")
+ android.FailIfErrored(t, errs)
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if errmsg == "" {
+ android.FailIfErrored(t, errs)
+ } else if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, errmsg, errs)
+ return
+ } else {
+ t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
+ }
+}
+
+func TestUpdatable_should_set_min_sdk_version(t *testing.T) {
+ testApexError(t, `"myapex" .*: updatable: updatable APEXes should set min_sdk_version`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ updatable: true,
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ `)
+}
+
+func TestNoUpdatableJarsInBootImage(t *testing.T) {
+ var err string
var transform func(*dexpreopt.GlobalConfig)
- // updatable jar from ART apex in the ART boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-art-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ config := android.TestArchConfig(buildDir, nil, "", nil)
+ ctx := android.PathContextForTesting(config)
- // updatable jar from ART apex in the framework boot image => error
- error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-art-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
- // updatable jar from some other apex in the ART boot image => error
- error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
+ err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image`
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // non-updatable jar from some other apex in the ART boot image => error
- error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-non-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
+ err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // updatable jar from some other apex in the framework boot image => error
- error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
+ err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // non-updatable jar from some other apex in the framework boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-non-updatable-apex-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
+ err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // nonexistent jar in the ART boot image => error
- error = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"nonexistent"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
- // nonexistent jar in the framework boot image => error
- error = "failed to find a dex jar path for module 'nonexistent'"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"nonexistent"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
+ err = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // platform jar in the ART boot image => error
- error = "module 'some-platform-lib' is not allowed in the ART boot image"
- transform = func(config *dexpreopt.GlobalConfig) {
- config.ArtApexJars = []string{"some-platform-lib"}
- }
- testNoUpdatableJarsInBootImage(t, error, bp, transform)
+ t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
+ err = "failed to find a dex jar path for module 'nonexistent'"
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
- // platform jar in the framework boot image => ok
- transform = func(config *dexpreopt.GlobalConfig) {
- config.BootJars = []string{"some-platform-lib"}
- }
- testNoUpdatableJarsInBootImage(t, "", bp, transform)
+ t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
+ err = `module "some-platform-lib" is not allowed in the ART boot image`
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, err, transform)
+ })
+
+ t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
+ transform = func(config *dexpreopt.GlobalConfig) {
+ config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
+ }
+ testNoUpdatableJarsInBootImage(t, "", transform)
+ })
}
func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJars []string, rules []android.Rule) {
@@ -5097,6 +5971,42 @@
}
}
+func TestNoStaticLinkingToStubsLib(t *testing.T) {
+ testApexError(t, `.*required by "mylib" is a native library providing stub.*`, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ static_libs: ["otherlib"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [ "myapex" ],
+ }
+
+ cc_library {
+ name: "otherlib",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ apex_available: [ "myapex" ],
+ }
+ `)
+}
+
func TestApexKeysTxt(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -5192,6 +6102,41 @@
}
}
+func TestNonPreferredPrebuiltDependency(t *testing.T) {
+ _, _ = testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ stubs: {
+ versions: ["10000"],
+ },
+ apex_available: ["myapex"],
+ }
+
+ cc_prebuilt_library_shared {
+ name: "mylib",
+ prefer: false,
+ srcs: ["prebuilt.so"],
+ stubs: {
+ versions: ["10000"],
+ },
+ apex_available: ["myapex"],
+ }
+ `)
+}
+
func TestMain(m *testing.M) {
run := func() int {
setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 72ad66d..c5680ad 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -17,6 +17,7 @@
import (
"encoding/json"
"fmt"
+ "path"
"path/filepath"
"runtime"
"sort"
@@ -62,6 +63,8 @@
pctx.HostBinToolVariable("jsonmodify", "jsonmodify")
pctx.HostBinToolVariable("conv_apex_manifest", "conv_apex_manifest")
pctx.HostBinToolVariable("extract_apks", "extract_apks")
+ pctx.HostBinToolVariable("make_f2fs", "make_f2fs")
+ pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs")
}
var (
@@ -115,12 +118,12 @@
`--payload_type image ` +
`--key ${key} ${opt_flags} ${image_dir} ${out} `,
CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
- "${mke2fs}", "${resize2fs}", "${sefcontext_compile}",
+ "${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}",
"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
Rspfile: "${out}.copy_commands",
RspfileContent: "${copy_commands}",
Description: "APEX ${image_dir} => ${out}",
- }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest")
+ }, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -189,6 +192,17 @@
optCommands = append(optCommands, "-v name "+*a.properties.Apex_name)
}
+ // collect jniLibs. Notice that a.filesInfo is already sorted
+ var jniLibs []string
+ for _, fi := range a.filesInfo {
+ if fi.isJniLib && !android.InList(fi.Stem(), jniLibs) {
+ jniLibs = append(jniLibs, fi.Stem())
+ }
+ }
+ if len(jniLibs) > 0 {
+ optCommands = append(optCommands, "-a jniLibs "+strings.Join(jniLibs, " "))
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: apexManifestRule,
Input: manifestSrc,
@@ -220,27 +234,60 @@
})
}
+func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) {
+ if a.properties.ApexType == zipApex {
+ return
+ }
+ var fileContexts android.Path
+ if a.properties.File_contexts == nil {
+ fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
+ } else {
+ fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
+ }
+ if a.Platform() {
+ if matched, err := path.Match("system/sepolicy/**/*", fileContexts.String()); err != nil || !matched {
+ ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", fileContexts)
+ return
+ }
+ }
+ if !android.ExistentPathForSource(ctx, fileContexts.String()).Valid() {
+ ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts)
+ return
+ }
+
+ output := android.PathForModuleOut(ctx, "file_contexts")
+ rule := android.NewRuleBuilder()
+ // remove old file
+ rule.Command().Text("rm").FlagWithOutput("-f ", output)
+ // copy file_contexts
+ rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
+ // new line
+ rule.Command().Text("echo").Text(">>").Output(output)
+ // force-label /apex_manifest.pb and / as system_file so that apexd can read them
+ rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+ rule.Build(pctx, ctx, "file_contexts."+a.Name(), "Generate file_contexts")
+
+ a.fileContexts = output.OutputPath
+}
+
func (a *apexBundle) buildNoticeFiles(ctx android.ModuleContext, apexFileName string) android.NoticeOutputs {
var noticeFiles android.Paths
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if externalDep {
// As soon as the dependency graph crosses the APEX boundary, don't go further.
return false
}
- notice := to.NoticeFile()
- if notice.Valid() {
- noticeFiles = append(noticeFiles, notice.Path())
- }
+ notices := to.NoticeFiles()
+ noticeFiles = append(noticeFiles, notices...)
return true
})
for _, fi := range a.filesInfo {
- if fi.noticeFile.Valid() {
- noticeFiles = append(noticeFiles, fi.noticeFile.Path())
- }
+ noticeFiles = append(noticeFiles, fi.noticeFiles...)
}
if len(noticeFiles) == 0 {
@@ -360,6 +407,19 @@
symlinkDest := android.PathForModuleOut(ctx, "image"+suffix, symlinkPath).String()
copyCommands = append(copyCommands, "ln -sfn "+filepath.Base(destPath)+" "+symlinkDest)
}
+ for _, d := range fi.dataPaths {
+ // TODO(eakammer): This is now the third repetition of ~this logic for test paths, refactoring should be possible
+ relPath := d.SrcPath.Rel()
+ dataPath := d.SrcPath.String()
+ if !strings.HasSuffix(dataPath, relPath) {
+ panic(fmt.Errorf("path %q does not end with %q", dataPath, relPath))
+ }
+
+ dataDest := android.PathForModuleOut(ctx, "image"+suffix, fi.apexRelativePath(relPath), d.RelativeInstallPath).String()
+
+ copyCommands = append(copyCommands, "cp -f "+d.SrcPath.String()+" "+dataDest)
+ implicitInputs = append(implicitInputs, d.SrcPath)
+ }
}
// TODO(jiyong): use RuleBuilder
@@ -418,6 +478,9 @@
pathInApex := f.Path()
if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
executablePaths = append(executablePaths, pathInApex)
+ for _, d := range f.dataPaths {
+ readOnlyPaths = append(readOnlyPaths, filepath.Join(f.installDir, d.RelativeInstallPath, d.SrcPath.Rel()))
+ }
for _, s := range f.symlinks {
executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
}
@@ -525,6 +588,8 @@
optFlags = append(optFlags, "--manifest_json "+a.manifestJsonOut.String())
}
+ optFlags = append(optFlags, "--payload_fs_type "+a.payloadFsType.string())
+
ctx.Build(pctx, android.BuildParams{
Rule: apexRule,
Implicits: implicitInputs,
@@ -591,7 +656,7 @@
a.container_certificate_file,
a.container_private_key_file,
}
- if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
rule = java.SignapkRE
args["implicits"] = strings.Join(implicits.Strings(), ",")
args["outCommaList"] = a.outputFile.String()
@@ -714,7 +779,7 @@
}
depInfos := android.DepNameToDepInfoMap{}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
if from.Name() == to.Name() {
// This can happen for cc.reuseObjTag. We are not interested in tracking this.
// As soon as the dependency graph crosses the APEX boundary, don't go further.
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 37457e9..1c27146 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -21,7 +21,6 @@
"android/soong/android"
"android/soong/java"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -257,9 +256,6 @@
// list of commands to create symlinks for backward compatibility.
// these commands will be attached as LOCAL_POST_INSTALL_CMD
compatSymlinks []string
-
- hostRequired []string
- postInstallCommands []string
}
type ApexSetProperties struct {
@@ -346,43 +342,21 @@
for _, overridden := range a.properties.Overrides {
a.compatSymlinks = append(a.compatSymlinks, makeCompatSymlinks(overridden, ctx)...)
}
-
- if ctx.Config().InstallExtraFlattenedApexes() {
- // flattened apex should be in /system_ext/apex
- flattenedApexDir := android.PathForModuleInstall(&systemExtContext{ctx}, "apex", a.BaseModuleName())
- a.postInstallCommands = append(a.postInstallCommands,
- fmt.Sprintf("$(HOST_OUT_EXECUTABLES)/deapexer --debugfs_path $(HOST_OUT_EXECUTABLES)/debugfs extract %s %s",
- a.outputApex.String(),
- flattenedApexDir.ToMakePath().String(),
- ))
- a.hostRequired = []string{"deapexer", "debugfs"}
- }
-}
-
-type systemExtContext struct {
- android.ModuleContext
-}
-
-func (*systemExtContext) SystemExtSpecific() bool {
- return true
}
func (a *ApexSet) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
- Class: "ETC",
- OutputFile: android.OptionalPathForPath(a.outputApex),
- Include: "$(BUILD_PREBUILT)",
- Host_required: a.hostRequired,
+ Class: "ETC",
+ OutputFile: android.OptionalPathForPath(a.outputApex),
+ Include: "$(BUILD_PREBUILT)",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_MODULE_PATH", a.installDir.ToMakePath().String())
entries.SetString("LOCAL_MODULE_STEM", a.installFilename)
entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !a.installable())
entries.AddStrings("LOCAL_OVERRIDES_MODULES", a.properties.Overrides...)
- postInstallCommands := append([]string{}, a.postInstallCommands...)
- postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
- if len(postInstallCommands) > 0 {
- entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(postInstallCommands, " && "))
+ if len(a.compatSymlinks) > 0 {
+ entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(a.compatSymlinks, " && "))
}
},
},
diff --git a/apex/vndk_test.go b/apex/vndk_test.go
index 8557fae..60b6ed5 100644
--- a/apex/vndk_test.go
+++ b/apex/vndk_test.go
@@ -117,44 +117,7 @@
})
t.Run("VNDK APEX supports coverage variants", func(t *testing.T) {
- ctx, _ := testApex(t, bp+`
- cc_library {
- name: "libprofile-extras",
- vendor_available: true,
- recovery_available: true,
- native_coverage: false,
- system_shared_libs: [],
- stl: "none",
- notice: "custom_notice",
- }
- cc_library {
- name: "libprofile-clang-extras",
- vendor_available: true,
- recovery_available: true,
- native_coverage: false,
- system_shared_libs: [],
- stl: "none",
- notice: "custom_notice",
- }
- cc_library {
- name: "libprofile-extras_ndk",
- vendor_available: true,
- native_coverage: false,
- system_shared_libs: [],
- stl: "none",
- notice: "custom_notice",
- sdk_version: "current",
- }
- cc_library {
- name: "libprofile-clang-extras_ndk",
- vendor_available: true,
- native_coverage: false,
- system_shared_libs: [],
- stl: "none",
- notice: "custom_notice",
- sdk_version: "current",
- }
- `, func(fs map[string][]byte, config android.Config) {
+ ctx, _ := testApex(t, bp, func(fs map[string][]byte, config android.Config) {
config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
})
diff --git a/bpf/bpf.go b/bpf/bpf.go
index 4b52375..297e13a 100644
--- a/bpf/bpf.go
+++ b/bpf/bpf.go
@@ -67,6 +67,10 @@
func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
cflags := []string{
"-nostdlibinc",
+
+ // Make paths in deps files relative
+ "-no-canonical-prefixes",
+
"-O2",
"-isystem bionic/libc/include",
"-isystem bionic/libc/kernel/uapi",
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index e291578..b244e3a 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -44,11 +44,9 @@
"bpfix/bpfix.go",
],
testSrcs: [
- "bpfix/bpfix_test.go",
+ "bpfix/bpfix_test.go",
],
deps: [
"blueprint-parser",
],
}
-
-
diff --git a/bpfix/bpfix/bpfix.go b/bpfix/bpfix/bpfix.go
index a1c5de1..faec473 100644
--- a/bpfix/bpfix/bpfix.go
+++ b/bpfix/bpfix/bpfix.go
@@ -128,6 +128,10 @@
Name: "removeSoongConfigBoolVariable",
Fix: removeSoongConfigBoolVariable,
},
+ {
+ Name: "removePdkProperty",
+ Fix: runPatchListMod(removePdkProperty),
+ },
}
func NewFixRequest() FixRequest {
@@ -408,6 +412,8 @@
switch mod.Type {
case "android_app":
mod.Type = "android_test"
+ case "android_app_import":
+ mod.Type = "android_test_import"
case "java_library", "java_library_installable":
mod.Type = "java_test"
case "java_library_host":
@@ -531,7 +537,7 @@
updated = true
} else if trimmedPath := strings.TrimPrefix(path, f.prefix+"/"); trimmedPath != path {
m.Properties = append(m.Properties, &parser.Property{
- Name: "sub_dir",
+ Name: "relative_install_path",
Value: &parser.String{Value: trimmedPath},
})
updated = true
@@ -579,6 +585,8 @@
// 'srcs' --> 'src' conversion
convertToSingleSource(mod, "src")
+ renameProperty(mod, "sub_dir", "relative_install_dir")
+
// The rewriter converts LOCAL_MODULE_PATH attribute into a struct attribute
// 'local_module_path'. Analyze its contents and create the correct sub_dir:,
// filename: and boolean attributes combination
@@ -951,7 +959,8 @@
case strings.Contains(mod.Type, "cc_test"),
strings.Contains(mod.Type, "cc_library_static"),
strings.Contains(mod.Type, "java_test"),
- mod.Type == "android_test":
+ mod.Type == "android_test",
+ mod.Type == "android_test_import":
continue
case strings.Contains(mod.Type, "cc_lib"):
replaceStr += `// WARNING: Module tags are not supported in Soong.
@@ -988,6 +997,25 @@
return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, replaceStr)
}
+func removePdkProperty(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
+ prop, ok := mod.GetProperty("product_variables")
+ if !ok {
+ return nil
+ }
+ propMap, ok := prop.Value.(*parser.Map)
+ if !ok {
+ return nil
+ }
+ pdkProp, ok := propMap.GetProperty("pdk")
+ if !ok {
+ return nil
+ }
+ if len(propMap.Properties) > 1 {
+ return patchlist.Add(pdkProp.Pos().Offset, pdkProp.End().Offset+2, "")
+ }
+ return patchlist.Add(prop.Pos().Offset, prop.End().Offset+2, "")
+}
+
func mergeMatchingModuleProperties(mod *parser.Module, buf []byte, patchlist *parser.PatchList) error {
return mergeMatchingProperties(&mod.Properties, buf, patchlist)
}
diff --git a/bpfix/bpfix/bpfix_test.go b/bpfix/bpfix/bpfix_test.go
index 64a7b93..ef9814f 100644
--- a/bpfix/bpfix/bpfix_test.go
+++ b/bpfix/bpfix/bpfix_test.go
@@ -742,6 +742,22 @@
}
`,
},
+ {
+ name: "prebuilt_etc sub_dir",
+ in: `
+ prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ sub_dir: "baz",
+ }
+ `,
+ out: `prebuilt_etc {
+ name: "foo",
+ src: "bar",
+ relative_install_dir: "baz",
+ }
+ `,
+ },
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -982,3 +998,61 @@
})
}
}
+
+func TestRemovePdkProperty(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ out string
+ }{
+ {
+ name: "remove property",
+ in: `
+ cc_library_shared {
+ name: "foo",
+ product_variables: {
+ other: {
+ bar: true,
+ },
+ pdk: {
+ enabled: false,
+ },
+ },
+ }
+ `,
+ out: `
+ cc_library_shared {
+ name: "foo",
+ product_variables: {
+ other: {
+ bar: true,
+ },
+ },
+ }
+ `,
+ },
+ {
+ name: "remove property and empty product_variables",
+ in: `
+ cc_library_shared {
+ name: "foo",
+ product_variables: {
+ pdk: {
+ enabled: false,
+ },
+ },
+ }
+ `,
+ out: `
+ cc_library_shared {
+ name: "foo",
+ }
+ `,
+ },
+ }
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ runPass(t, test.in, test.out, runPatchListMod(removePdkProperty))
+ })
+ }
+}
diff --git a/build_kzip.bash b/build_kzip.bash
index 008030f..0018ea9 100755
--- a/build_kzip.bash
+++ b/build_kzip.bash
@@ -19,16 +19,20 @@
# The extraction might fail for some source files, so run with -k and then check that
# sufficiently many files were generated.
declare -r out="${OUT_DIR:-out}"
+
# Build extraction files for C++ and Java. Build `merge_zips` which we use later.
build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k merge_zips xref_cxx xref_java
-#Build extraction file for Go files in build/soong directory.
+
+# Build extraction file for Go the files in build/{blueprint,soong} directories.
declare -r abspath_out=$(realpath "${out}")
declare -r go_extractor=$(realpath prebuilts/build-tools/linux-x86/bin/go_extractor)
declare -r go_root=$(realpath prebuilts/go/linux-x86)
+declare -r vnames_path=$(realpath build/soong/vnames.go.json)
+declare -r source_root=$PWD
for dir in blueprint soong; do
(cd "build/$dir";
- "$go_extractor" --goroot="$go_root" --rules=vnames.go.json --canonicalize_package_corpus \
- --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
+ KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" --rules="${vnames_path}" \
+ --canonicalize_package_corpus --output "${abspath_out}/soong/build_${dir}.go.kzip" ./...
)
done
diff --git a/cc/Android.bp b/cc/Android.bp
index 9ece05f..831911e 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -19,6 +19,7 @@
"check.go",
"coverage.go",
"gen.go",
+ "image.go",
"linkable.go",
"lto.go",
"makevars.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index cb83e7e..380b4e9 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -92,6 +92,9 @@
if len(c.Properties.AndroidMkWholeStaticLibs) > 0 {
entries.AddStrings("LOCAL_WHOLE_STATIC_LIBRARIES", c.Properties.AndroidMkWholeStaticLibs...)
}
+ if len(c.Properties.AndroidMkHeaderLibs) > 0 {
+ entries.AddStrings("LOCAL_HEADER_LIBRARIES", c.Properties.AndroidMkHeaderLibs...)
+ }
entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType)
if c.UseVndk() {
entries.SetBool("LOCAL_USE_VNDK", true)
@@ -146,17 +149,34 @@
return []android.AndroidMkEntries{entries}
}
-func androidMkWriteTestData(data android.Paths, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+func AndroidMkDataPaths(data []android.DataPath) []string {
var testFiles []string
for _, d := range data {
- rel := d.Rel()
- path := d.String()
+ rel := d.SrcPath.Rel()
+ path := d.SrcPath.String()
if !strings.HasSuffix(path, rel) {
panic(fmt.Errorf("path %q does not end with %q", path, rel))
}
path = strings.TrimSuffix(path, rel)
- testFiles = append(testFiles, path+":"+rel)
+ testFileString := path + ":" + rel
+ if len(d.RelativeInstallPath) > 0 {
+ testFileString += ":" + d.RelativeInstallPath
+ }
+ testFiles = append(testFiles, testFileString)
}
+ return testFiles
+}
+
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
+ if len(extraTestConfigs) > 0 {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+ })
+ }
+}
+
+func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+ testFiles := AndroidMkDataPaths(data)
if len(testFiles) > 0 {
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
entries.AddStrings("LOCAL_TEST_DATA", testFiles...)
@@ -194,29 +214,15 @@
}
func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) {
- if library.sAbiOutputFile.Valid() {
- entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
- "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiOutputFile.String())
- if library.sAbiDiff.Valid() && !library.static() {
- entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES",
- "$(LOCAL_ADDITIONAL_DEPENDENCIES) "+library.sAbiDiff.String())
- entries.SetString("HEADER_ABI_DIFFS",
- "$(HEADER_ABI_DIFFS) "+library.sAbiDiff.String())
- }
+ if library.sAbiDiff.Valid() && !library.static() {
+ entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff.String())
}
}
// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries
func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) {
- if library.sAbiOutputFile.Valid() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
- library.sAbiOutputFile.String())
- if library.sAbiDiff.Valid() && !library.static() {
- fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_ADDITIONAL_DEPENDENCIES) ",
- library.sAbiDiff.String())
- fmt.Fprintln(w, "HEADER_ABI_DIFFS := $(HEADER_ABI_DIFFS) ",
- library.sAbiDiff.String())
- }
+ if library.sAbiDiff.Valid() && !library.static() {
+ fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", library.sAbiDiff.String())
}
}
@@ -274,10 +280,8 @@
entries.SubName = "." + library.stubsVersion()
}
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
- // Note library.skipInstall() has a special case to get here for static
- // libraries that otherwise would have skipped installation and hence not
- // have executed AndroidMkEntries at all. The reason is to ensure they get
- // a NOTICE file make target which other libraries might depend on.
+ // library.makeUninstallable() depends on this to bypass SkipInstall() for
+ // static libraries.
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
if library.buildStubs() {
entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
@@ -349,8 +353,11 @@
entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
}
})
-
- androidMkWriteTestData(benchmark.data, ctx, entries)
+ dataPaths := []android.DataPath{}
+ for _, srcPath := range benchmark.data {
+ dataPaths = append(dataPaths, android.DataPath{SrcPath: srcPath})
+ }
+ androidMkWriteTestData(dataPaths, ctx, entries)
}
func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
@@ -370,9 +377,11 @@
if !BoolDefault(test.Properties.Auto_gen_config, true) {
entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true)
}
+ entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...)
})
androidMkWriteTestData(test.data, ctx, entries)
+ androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
}
func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
@@ -452,6 +461,9 @@
entries.SetString("LOCAL_MODULE_PATH", path)
entries.SetString("LOCAL_MODULE_STEM", stem)
entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+ if c.parsedCoverageXmlPath.String() != "" {
+ entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
+ }
})
}
@@ -500,10 +512,14 @@
entries.Class = "HEADER_LIBRARIES"
}
+ entries.SubName = ""
+
+ if c.sanitizerProperties.CfiEnabled {
+ entries.SubName += ".cfi"
+ }
+
if c.androidMkVendorSuffix {
- entries.SubName = vendorSuffix
- } else {
- entries.SubName = ""
+ entries.SubName += vendorSuffix
}
entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
diff --git a/cc/binary.go b/cc/binary.go
index 565cb8a..b3ce5ff 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -83,7 +83,7 @@
type binaryDecorator struct {
*baseLinker
*baseInstaller
- stripper
+ stripper Stripper
Properties BinaryLinkerProperties
@@ -130,34 +130,12 @@
deps = binary.baseLinker.linkerDeps(ctx, deps)
if ctx.toolchain().Bionic() {
if !Bool(binary.baseLinker.Properties.Nocrt) {
- if !ctx.useSdk() {
- if binary.static() {
- deps.CrtBegin = "crtbegin_static"
- } else {
- deps.CrtBegin = "crtbegin_dynamic"
- }
- deps.CrtEnd = "crtend_android"
+ if binary.static() {
+ deps.CrtBegin = "crtbegin_static"
} else {
- // TODO(danalbert): Add generation of crt objects.
- // For `sdk_version: "current"`, we don't actually have a
- // freshly generated set of CRT objects. Use the last stable
- // version.
- version := ctx.sdkVersion()
- if version == "current" {
- version = getCurrentNdkPrebuiltVersion(ctx)
- }
-
- if binary.static() {
- deps.CrtBegin = "ndk_crtbegin_static." + version
- } else {
- if binary.static() {
- deps.CrtBegin = "ndk_crtbegin_static." + version
- } else {
- deps.CrtBegin = "ndk_crtbegin_dynamic." + version
- }
- deps.CrtEnd = "ndk_crtend_android." + version
- }
+ deps.CrtBegin = "crtbegin_dynamic"
}
+ deps.CrtEnd = "crtend_android"
}
if binary.static() {
@@ -339,14 +317,14 @@
}
builderFlags := flagsToBuilderFlags(flags)
-
- if binary.stripper.needsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
+ if binary.stripper.NeedsStrip(ctx) {
if ctx.Darwin() {
- builderFlags.stripUseGnuStrip = true
+ stripFlags.StripUseGnuStrip = true
}
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
- binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+ binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
}
binary.unstrippedOutputFile = outputFile
@@ -355,7 +333,7 @@
afterPrefixSymbols := outputFile
outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName)
TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile,
- flagsToBuilderFlags(flags), afterPrefixSymbols)
+ builderFlags, afterPrefixSymbols)
}
outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName)
@@ -369,10 +347,10 @@
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile)
- if binary.stripper.needsStrip(ctx) {
+ if binary.stripper.NeedsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
binary.distFiles = android.MakeDefaultDistFiles(out)
- binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+ binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
}
binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -467,7 +445,7 @@
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
+ if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go
index 88ac513..a1abc72 100644
--- a/cc/binary_sdk_member.go
+++ b/cc/binary_sdk_member.go
@@ -20,6 +20,7 @@
"android/soong/android"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
func init() {
@@ -28,7 +29,8 @@
var ccBinarySdkMemberType = &binarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "native_binaries",
+ PropertyName: "native_binaries",
+ HostOsDependent: true,
},
}
@@ -44,9 +46,13 @@
if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name)
}
- mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "version", Variation: version},
- }...), dependencyTag, name)
+ variations := target.Variations()
+ if mctx.Device() {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
+ blueprint.Variation{Mutator: "version", Variation: version})
+ }
+ mctx.AddFarVariationDependencies(variations, dependencyTag, name)
}
}
}
@@ -65,7 +71,15 @@
}
func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
- return ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
+ pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary")
+
+ ccModule := member.Variants()[0].(*Module)
+
+ if stl := ccModule.stl.Properties.Stl; stl != nil {
+ pbm.AddProperty("stl", proptools.String(stl))
+ }
+
+ return pbm
}
func (mt *binarySdkMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
@@ -105,6 +119,10 @@
//
// This field is exported as its contents may not be arch specific.
SystemSharedLibs []string
+
+ // Arch specific flags.
+ StaticExecutable bool
+ Nocrt bool
}
func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
@@ -113,6 +131,10 @@
p.archType = ccModule.Target().Arch.ArchType.String()
p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
+ binaryLinker := ccModule.linker.(*binaryDecorator)
+ p.StaticExecutable = binaryLinker.static()
+ p.Nocrt = Bool(binaryLinker.baseLinker.Properties.Nocrt)
+
if ccModule.linker != nil {
specifiedDeps := specifiedDeps{}
specifiedDeps = ccModule.linker.linkerSpecifiedDeps(specifiedDeps)
@@ -123,10 +145,6 @@
}
func (p *nativeBinaryInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
- if p.Compile_multilib != "" {
- propertySet.AddProperty("compile_multilib", p.Compile_multilib)
- }
-
builder := ctx.SnapshotBuilder()
if p.outputFile != nil {
propertySet.AddProperty("srcs", []string{nativeBinaryPathFor(*p)})
@@ -143,4 +161,11 @@
if p.SystemSharedLibs != nil {
propertySet.AddPropertyWithTag("system_shared_libs", p.SystemSharedLibs, builder.SdkMemberReferencePropertyTag(false))
}
+
+ if p.StaticExecutable {
+ propertySet.AddProperty("static_executable", p.StaticExecutable)
+ }
+ if p.Nocrt {
+ propertySet.AddProperty("nocrt", p.Nocrt)
+ }
}
diff --git a/cc/builder.go b/cc/builder.go
index 5deb129..ef65348 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -38,13 +38,6 @@
)
var (
- abiCheckAllowFlags = []string{
- "-allow-unreferenced-changes",
- "-allow-unreferenced-elf-symbol-changes",
- }
-)
-
-var (
pctx = android.NewPackageContext("android/soong/cc")
cc = pctx.AndroidRemoteStaticRule("cc", android.RemoteRuleSupports{Goma: true, RBE: true},
@@ -107,6 +100,15 @@
},
"arCmd", "arFlags")
+ arWithLibs = pctx.AndroidStaticRule("arWithLibs",
+ blueprint.RuleParams{
+ Command: "rm -f ${out} && $arCmd $arObjFlags $out @${out}.rsp && $arCmd $arLibFlags $out $arLibs",
+ CommandDeps: []string{"$arCmd"},
+ Rspfile: "${out}.rsp",
+ RspfileContent: "${arObjs}",
+ },
+ "arCmd", "arObjFlags", "arObjs", "arLibFlags", "arLibs")
+
darwinStrip = pctx.AndroidStaticRule("darwinStrip",
blueprint.RuleParams{
Command: "${config.MacStripPath} -u -r -o $out $in",
@@ -173,12 +175,21 @@
},
"crossCompile", "format")
- clangTidy = pctx.AndroidStaticRule("clangTidy",
+ clangTidy, clangTidyRE = remoteexec.StaticRules(pctx, "clangTidy",
blueprint.RuleParams{
- Command: "rm -f $out && ${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
+ Command: "rm -f $out && $reTemplate${config.ClangBin}/clang-tidy $tidyFlags $in -- $cFlags && touch $out",
CommandDeps: []string{"${config.ClangBin}/clang-tidy"},
},
- "cFlags", "tidyFlags")
+ &remoteexec.REParams{
+ Labels: map[string]string{"type": "lint", "tool": "clang-tidy", "lang": "cpp"},
+ ExecStrategy: "${config.REClangTidyExecStrategy}",
+ Inputs: []string{"$in"},
+ // OutputFile here is $in for remote-execution since its possible that
+ // clang-tidy modifies the given input file itself and $out refers to the
+ // ".tidy" file generated for ninja-dependency reasons.
+ OutputFiles: []string{"$in"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
+ }, []string{"cFlags", "tidyFlags"}, []string{})
_ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm")
@@ -237,8 +248,7 @@
sAbiDiff = pctx.RuleFunc("sAbiDiff",
func(ctx android.PackageRuleContext) blueprint.RuleParams {
- // TODO(b/78139997): Add -check-all-apis back
- commandStr := "($sAbiDiffer ${allowFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
+ commandStr := "($sAbiDiffer ${extraFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})"
commandStr += "|| (echo 'error: Please update ABI references with: $$ANDROID_BUILD_TOP/development/vndk/tools/header-checker/utils/create_reference_dumps.py ${createReferenceDumpFlags} -l ${libName}'"
commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)"
commandStr += " && exit 1)"
@@ -247,7 +257,7 @@
CommandDeps: []string{"$sAbiDiffer"},
}
},
- "allowFlags", "referenceDump", "libName", "arch", "createReferenceDumpFlags")
+ "extraFlags", "referenceDump", "libName", "arch", "createReferenceDumpFlags")
unzipRefSAbiDump = pctx.AndroidStaticRule("unzipRefSAbiDump",
blueprint.RuleParams{
@@ -256,9 +266,9 @@
zip = pctx.AndroidStaticRule("zip",
blueprint.RuleParams{
- Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
+ Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp",
CommandDeps: []string{"${SoongZipCmd}"},
- Rspfile: "$out.rsp",
+ Rspfile: "${out}.rsp",
RspfileContent: "$in",
})
@@ -272,23 +282,30 @@
kytheExtract = pctx.StaticRule("kythe",
blueprint.RuleParams{
Command: `rm -f $out && ` +
- `KYTHE_CORPUS=${kytheCorpus} KYTHE_OUTPUT_FILE=$out KYTHE_VNAMES=$kytheVnames KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+ `KYTHE_CORPUS=${kytheCorpus} ` +
+ `KYTHE_OUTPUT_FILE=$out ` +
+ `KYTHE_VNAMES=$kytheVnames ` +
+ `KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` +
+ `KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` +
`$cxxExtractor $cFlags $in `,
CommandDeps: []string{"$cxxExtractor", "$kytheVnames"},
},
"cFlags")
)
+func PwdPrefix() string {
+ // Darwin doesn't have /proc
+ if runtime.GOOS != "darwin" {
+ return "PWD=/proc/self/cwd"
+ }
+ return ""
+}
+
func init() {
// We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
// debug output. That way two builds in two different directories will
// create the same output.
- if runtime.GOOS != "darwin" {
- pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
- } else {
- // Darwin doesn't have /proc
- pctx.StaticVariable("relPwd", "")
- }
+ pctx.StaticVariable("relPwd", PwdPrefix())
pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
pctx.Import("android/soong/remoteexec")
@@ -333,18 +350,22 @@
groupStaticLibs bool
- stripKeepSymbols bool
- stripKeepSymbolsList string
- stripKeepSymbolsAndDebugFrame bool
- stripKeepMiniDebugInfo bool
- stripAddGnuDebuglink bool
- stripUseGnuStrip bool
-
proto android.ProtoFlags
protoC bool
protoOptionsFile bool
yacc *YaccProperties
+ lex *LexProperties
+}
+
+type StripFlags struct {
+ Toolchain config.Toolchain
+ StripKeepSymbols bool
+ StripKeepSymbolsList string
+ StripKeepSymbolsAndDebugFrame bool
+ StripKeepMiniDebugInfo bool
+ StripAddGnuDebuglink bool
+ StripUseGnuStrip bool
}
type Objects struct {
@@ -562,8 +583,13 @@
tidyFile := android.ObjPathWithExt(ctx, subdir, srcFile, "tidy")
tidyFiles = append(tidyFiles, tidyFile)
+ rule := clangTidy
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CLANG_TIDY") {
+ rule = clangTidyRE
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: clangTidy,
+ Rule: rule,
Description: "clang-tidy " + srcFile.Rel(),
Output: tidyFile,
Input: srcFile,
@@ -584,7 +610,7 @@
sAbiDumpFiles = append(sAbiDumpFiles, sAbiDumpFile)
dumpRule := sAbiDump
- if ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_DUMPER") {
dumpRule = sAbiDumpRE
}
ctx.Build(pctx, android.BuildParams{
@@ -614,26 +640,45 @@
}
// Generate a rule for compiling multiple .o files to a static library (.a)
-func TransformObjToStaticLib(ctx android.ModuleContext, objFiles android.Paths,
+func TransformObjToStaticLib(ctx android.ModuleContext,
+ objFiles android.Paths, wholeStaticLibs android.Paths,
flags builderFlags, outputFile android.ModuleOutPath, deps android.Paths) {
arCmd := "${config.ClangBin}/llvm-ar"
- arFlags := "crsPD"
+ arFlags := ""
if !ctx.Darwin() {
arFlags += " -format=gnu"
}
- ctx.Build(pctx, android.BuildParams{
- Rule: ar,
- Description: "static link " + outputFile.Base(),
- Output: outputFile,
- Inputs: objFiles,
- Implicits: deps,
- Args: map[string]string{
- "arFlags": arFlags,
- "arCmd": arCmd,
- },
- })
+ if len(wholeStaticLibs) == 0 {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: ar,
+ Description: "static link " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: objFiles,
+ Implicits: deps,
+ Args: map[string]string{
+ "arFlags": "crsPD" + arFlags,
+ "arCmd": arCmd,
+ },
+ })
+
+ } else {
+ ctx.Build(pctx, android.BuildParams{
+ Rule: arWithLibs,
+ Description: "static link " + outputFile.Base(),
+ Output: outputFile,
+ Inputs: append(objFiles, wholeStaticLibs...),
+ Implicits: deps,
+ Args: map[string]string{
+ "arCmd": arCmd,
+ "arObjFlags": "crsPD" + arFlags,
+ "arObjs": strings.Join(objFiles.Strings(), " "),
+ "arLibFlags": "cqsL" + arFlags,
+ "arLibs": strings.Join(wholeStaticLibs.Strings(), " "),
+ },
+ })
+ }
}
// Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries,
@@ -700,7 +745,7 @@
"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
"crtEnd": crtEnd.String(),
}
- if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
rule = ldRE
args["implicitOutputs"] = strings.Join(implicitOutputs.Strings(), ",")
args["implicitInputs"] = strings.Join(deps.Strings(), ",")
@@ -744,7 +789,7 @@
"arch": ctx.Arch().ArchType.Name,
"exportedHeaderFlags": exportedHeaderFlags,
}
- if ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ABI_LINKER") {
rule = sAbiLinkRE
rbeImplicits := implicits.Strings()
for _, p := range strings.Split(exportedHeaderFlags, " ") {
@@ -778,27 +823,36 @@
}
func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
- baseName, exportedHeaderFlags string, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
+ baseName, exportedHeaderFlags string, checkAllApis, isLlndk, isNdk, isVndkExt bool) android.OptionalPath {
outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
libName := strings.TrimSuffix(baseName, filepath.Ext(baseName))
createReferenceDumpFlags := ""
- localAbiCheckAllowFlags := append([]string(nil), abiCheckAllowFlags...)
- if exportedHeaderFlags == "" {
- localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only")
+ var extraFlags []string
+ if checkAllApis {
+ extraFlags = append(extraFlags, "-check-all-apis")
+ } else {
+ extraFlags = append(extraFlags,
+ "-allow-unreferenced-changes",
+ "-allow-unreferenced-elf-symbol-changes")
}
+
+ if exportedHeaderFlags == "" {
+ extraFlags = append(extraFlags, "-advice-only")
+ }
+
if isLlndk || isNdk {
createReferenceDumpFlags = "--llndk"
if isLlndk {
// TODO(b/130324828): "-consider-opaque-types-different" should apply to
// both LLNDK and NDK shared libs. However, a known issue in header-abi-diff
// breaks libaaudio. Remove the if-guard after the issue is fixed.
- localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-consider-opaque-types-different")
+ extraFlags = append(extraFlags, "-consider-opaque-types-different")
}
}
if isVndkExt {
- localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions")
+ extraFlags = append(extraFlags, "-allow-extensions")
}
ctx.Build(pctx, android.BuildParams{
@@ -811,7 +865,7 @@
"referenceDump": referenceDump.String(),
"libName": libName,
"arch": ctx.Arch().ArchType.Name,
- "allowFlags": strings.Join(localAbiCheckAllowFlags, " "),
+ "extraFlags": strings.Join(extraFlags, " "),
"createReferenceDumpFlags": createReferenceDumpFlags,
},
})
@@ -858,7 +912,7 @@
"ldCmd": ldCmd,
"ldFlags": flags.globalLdFlags + " " + flags.localLdFlags,
}
- if ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_CXX_LINKS") {
rule = partialLdRE
args["inCommaList"] = strings.Join(objFiles.Strings(), ",")
args["implicitInputs"] = strings.Join(deps.Strings(), ",")
@@ -892,26 +946,26 @@
}
func TransformStrip(ctx android.ModuleContext, inputFile android.Path,
- outputFile android.WritablePath, flags builderFlags) {
+ outputFile android.WritablePath, flags StripFlags) {
- crossCompile := gccCmd(flags.toolchain, "")
+ crossCompile := gccCmd(flags.Toolchain, "")
args := ""
- if flags.stripAddGnuDebuglink {
+ if flags.StripAddGnuDebuglink {
args += " --add-gnu-debuglink"
}
- if flags.stripKeepMiniDebugInfo {
+ if flags.StripKeepMiniDebugInfo {
args += " --keep-mini-debug-info"
}
- if flags.stripKeepSymbols {
+ if flags.StripKeepSymbols {
args += " --keep-symbols"
}
- if flags.stripKeepSymbolsList != "" {
- args += " -k" + flags.stripKeepSymbolsList
+ if flags.StripKeepSymbolsList != "" {
+ args += " -k" + flags.StripKeepSymbolsList
}
- if flags.stripKeepSymbolsAndDebugFrame {
+ if flags.StripKeepSymbolsAndDebugFrame {
args += " --keep-symbols-and-debug-frame"
}
- if flags.stripUseGnuStrip {
+ if flags.StripUseGnuStrip {
args += " --use-gnu-strip"
}
diff --git a/cc/cc.go b/cc/cc.go
index 0f874f1..70229be 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -96,6 +96,9 @@
HeaderLibs []string
RuntimeLibs []string
+ // Used for data dependencies adjacent to tests
+ DataLibs []string
+
StaticUnwinderIfLegacy bool
ReexportSharedLibHeaders, ReexportStaticLibHeaders, ReexportHeaderLibHeaders []string
@@ -124,13 +127,18 @@
StaticLibs, LateStaticLibs, WholeStaticLibs android.Paths
// Paths to .o files
- Objs Objects
+ Objs Objects
+ // Paths to .o files in dependencies that provide them. Note that these lists
+ // aren't complete since prebuilt modules don't provide the .o files.
StaticLibObjs Objects
WholeStaticLibObjs Objects
+ // Paths to .a files in prebuilts. Complements WholeStaticLibObjs to contain
+ // the libs from all whole_static_lib dependencies.
+ WholeStaticLibsFromPrebuilts android.Paths
+
// Paths to generated source files
GeneratedSources android.Paths
- GeneratedHeaders android.Paths
GeneratedDeps android.Paths
Flags []string
@@ -202,6 +210,7 @@
protoOptionsFile bool // Whether to look for a .options file next to the .proto
Yacc *YaccProperties
+ Lex *LexProperties
}
// Properties used to compile all C or C++ modules
@@ -223,6 +232,7 @@
AndroidMkStaticLibs []string `blueprint:"mutated"`
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
AndroidMkWholeStaticLibs []string `blueprint:"mutated"`
+ AndroidMkHeaderLibs []string `blueprint:"mutated"`
HideFromMake bool `blueprint:"mutated"`
PreventInstall bool `blueprint:"mutated"`
ApexesProvidingSharedLibs []string `blueprint:"mutated"`
@@ -270,6 +280,13 @@
// Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
// variant to have a ".sdk" suffix.
SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
+
+ // Normally Soong uses the directory structure to decide which modules
+ // should be included (framework) or excluded (non-framework) from the
+ // vendor snapshot, but this property allows a partner to exclude a
+ // module normally thought of as a framework module from the vendor
+ // snapshot.
+ Exclude_from_vendor_snapshot *bool
}
type VendorProperties struct {
@@ -335,7 +352,7 @@
isNDKStubLibrary() bool
useClangLld(actx ModuleContext) bool
isForPlatform() bool
- apexName() string
+ apexVariationName() string
apexSdkVersion() int
hasStubsVariants() bool
isStubs() bool
@@ -409,51 +426,137 @@
inSanitizerDir() bool
hostToolPath() android.OptionalPath
relativeInstallPath() string
- skipInstall(mod *Module)
+ makeUninstallable(mod *Module)
}
type xref interface {
XrefCcFiles() android.Paths
}
+type libraryDependencyKind int
+
+const (
+ headerLibraryDependency = iota
+ sharedLibraryDependency
+ staticLibraryDependency
+)
+
+func (k libraryDependencyKind) String() string {
+ switch k {
+ case headerLibraryDependency:
+ return "headerLibraryDependency"
+ case sharedLibraryDependency:
+ return "sharedLibraryDependency"
+ case staticLibraryDependency:
+ return "staticLibraryDependency"
+ default:
+ panic(fmt.Errorf("unknown libraryDependencyKind %d", k))
+ }
+}
+
+type libraryDependencyOrder int
+
+const (
+ earlyLibraryDependency = -1
+ normalLibraryDependency = 0
+ lateLibraryDependency = 1
+)
+
+func (o libraryDependencyOrder) String() string {
+ switch o {
+ case earlyLibraryDependency:
+ return "earlyLibraryDependency"
+ case normalLibraryDependency:
+ return "normalLibraryDependency"
+ case lateLibraryDependency:
+ return "lateLibraryDependency"
+ default:
+ panic(fmt.Errorf("unknown libraryDependencyOrder %d", o))
+ }
+}
+
+// libraryDependencyTag is used to tag dependencies on libraries. Unlike many dependency
+// tags that have a set of predefined tag objects that are reused for each dependency, a
+// libraryDependencyTag is designed to contain extra metadata and is constructed as needed.
+// That means that comparing a libraryDependencyTag for equality will only be equal if all
+// of the metadata is equal. Most usages will want to type assert to libraryDependencyTag and
+// then check individual metadata fields instead.
+type libraryDependencyTag struct {
+ blueprint.BaseDependencyTag
+
+ // These are exported so that fmt.Printf("%#v") can call their String methods.
+ Kind libraryDependencyKind
+ Order libraryDependencyOrder
+
+ wholeStatic bool
+
+ reexportFlags bool
+ explicitlyVersioned bool
+ dataLib bool
+ ndk bool
+
+ staticUnwinder bool
+
+ makeSuffix string
+}
+
+// header returns true if the libraryDependencyTag is tagging a header lib dependency.
+func (d libraryDependencyTag) header() bool {
+ return d.Kind == headerLibraryDependency
+}
+
+// shared returns true if the libraryDependencyTag is tagging a shared lib dependency.
+func (d libraryDependencyTag) shared() bool {
+ return d.Kind == sharedLibraryDependency
+}
+
+// shared returns true if the libraryDependencyTag is tagging a static lib dependency.
+func (d libraryDependencyTag) static() bool {
+ return d.Kind == staticLibraryDependency
+}
+
+// dependencyTag is used for tagging miscellanous dependency types that don't fit into
+// libraryDependencyTag. Each tag object is created globally and reused for multiple
+// dependencies (although since the object contains no references, assigning a tag to a
+// variable and modifying it will not modify the original). Users can compare the tag
+// returned by ctx.OtherModuleDependencyTag against the global original
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
var (
- sharedExportDepTag = DependencyTag{Name: "shared", Library: true, Shared: true, ReexportFlags: true}
- earlySharedDepTag = DependencyTag{Name: "early_shared", Library: true, Shared: true}
- lateSharedDepTag = DependencyTag{Name: "late shared", Library: true, Shared: true}
- staticExportDepTag = DependencyTag{Name: "static", Library: true, ReexportFlags: true}
- lateStaticDepTag = DependencyTag{Name: "late static", Library: true}
- staticUnwinderDepTag = DependencyTag{Name: "static unwinder", Library: true}
- wholeStaticDepTag = DependencyTag{Name: "whole static", Library: true, ReexportFlags: true}
- headerDepTag = DependencyTag{Name: "header", Library: true}
- headerExportDepTag = DependencyTag{Name: "header", Library: true, ReexportFlags: true}
- genSourceDepTag = DependencyTag{Name: "gen source"}
- genHeaderDepTag = DependencyTag{Name: "gen header"}
- genHeaderExportDepTag = DependencyTag{Name: "gen header", ReexportFlags: true}
- objDepTag = DependencyTag{Name: "obj"}
- linkerFlagsDepTag = DependencyTag{Name: "linker flags file"}
- dynamicLinkerDepTag = DependencyTag{Name: "dynamic linker"}
- reuseObjTag = DependencyTag{Name: "reuse objects"}
- staticVariantTag = DependencyTag{Name: "static variant"}
- ndkStubDepTag = DependencyTag{Name: "ndk stub", Library: true}
- ndkLateStubDepTag = DependencyTag{Name: "ndk late stub", Library: true}
- vndkExtDepTag = DependencyTag{Name: "vndk extends", Library: true}
- runtimeDepTag = DependencyTag{Name: "runtime lib"}
- coverageDepTag = DependencyTag{Name: "coverage"}
- testPerSrcDepTag = DependencyTag{Name: "test_per_src"}
+ genSourceDepTag = dependencyTag{name: "gen source"}
+ genHeaderDepTag = dependencyTag{name: "gen header"}
+ genHeaderExportDepTag = dependencyTag{name: "gen header export"}
+ objDepTag = dependencyTag{name: "obj"}
+ linkerFlagsDepTag = dependencyTag{name: "linker flags file"}
+ dynamicLinkerDepTag = dependencyTag{name: "dynamic linker"}
+ reuseObjTag = dependencyTag{name: "reuse objects"}
+ staticVariantTag = dependencyTag{name: "static variant"}
+ vndkExtDepTag = dependencyTag{name: "vndk extends"}
+ dataLibDepTag = dependencyTag{name: "data lib"}
+ runtimeDepTag = dependencyTag{name: "runtime lib"}
+ testPerSrcDepTag = dependencyTag{name: "test_per_src"}
)
func IsSharedDepTag(depTag blueprint.DependencyTag) bool {
- ccDepTag, ok := depTag.(DependencyTag)
- return ok && ccDepTag.Shared
+ ccLibDepTag, ok := depTag.(libraryDependencyTag)
+ return ok && ccLibDepTag.shared()
+}
+
+func IsStaticDepTag(depTag blueprint.DependencyTag) bool {
+ ccLibDepTag, ok := depTag.(libraryDependencyTag)
+ return ok && ccLibDepTag.static()
}
func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool {
- ccDepTag, ok := depTag.(DependencyTag)
+ ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag == runtimeDepTag
}
func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
- ccDepTag, ok := depTag.(DependencyTag)
+ ccDepTag, ok := depTag.(dependencyTag)
return ok && ccDepTag == testPerSrcDepTag
}
@@ -586,6 +689,13 @@
return String(c.Properties.Min_sdk_version)
}
+func (c *Module) SplitPerApiLevel() bool {
+ if linker, ok := c.linker.(*objectLinker); ok {
+ return linker.isCrt()
+ }
+ return false
+}
+
func (c *Module) AlwaysSdk() bool {
return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
}
@@ -746,6 +856,15 @@
return c.outputFile
}
+func (c *Module) CoverageFiles() android.Paths {
+ if c.linker != nil {
+ if library, ok := c.linker.(libraryInterface); ok {
+ return library.objs().coverageFiles
+ }
+ }
+ panic(fmt.Errorf("CoverageFiles called on non-library module: %q", c.BaseModuleName()))
+}
+
var _ LinkableInterface = (*Module)(nil)
func (c *Module) UnstrippedOutputFile() android.Path {
@@ -810,15 +929,8 @@
}
c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
- switch class {
- case android.Device:
- return ctx.Config().DevicePrefer32BitExecutables()
- case android.HostCross:
- // Windows builds always prefer 32-bit
- return true
- default:
- return false
- }
+ // Windows builds always prefer 32-bit
+ return class == android.HostCross
})
android.InitAndroidArchModule(c, c.hod, c.multilib)
android.InitApexModule(c)
@@ -855,7 +967,7 @@
func (c *Module) UseSdk() bool {
if c.canUseSdk() {
- return String(c.Properties.Sdk_version) != ""
+ return String(c.Properties.Sdk_version) != "" || c.SplitPerApiLevel()
}
return false
}
@@ -865,7 +977,7 @@
}
func (c *Module) IsNdk() bool {
- return inList(c.Name(), ndkMigratedLibs)
+ return inList(c.BaseModuleName(), ndkKnownLibs)
}
func (c *Module) isLlndk(config android.Config) bool {
@@ -930,48 +1042,6 @@
return ""
}
-// Returns true only when this module is configured to have core, product and vendor
-// variants.
-func (c *Module) HasVendorVariant() bool {
- return c.IsVndk() || Bool(c.VendorProperties.Vendor_available)
-}
-
-const (
- // VendorVariationPrefix is the variant prefix used for /vendor code that compiles
- // against the VNDK.
- VendorVariationPrefix = "vendor."
-
- // ProductVariationPrefix is the variant prefix used for /product code that compiles
- // against the VNDK.
- ProductVariationPrefix = "product."
-)
-
-// Returns true if the module is "product" variant. Usually these modules are installed in /product
-func (c *Module) inProduct() bool {
- return c.Properties.ImageVariationPrefix == ProductVariationPrefix
-}
-
-// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
-func (c *Module) inVendor() bool {
- return c.Properties.ImageVariationPrefix == VendorVariationPrefix
-}
-
-func (c *Module) InRamdisk() bool {
- return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk()
-}
-
-func (c *Module) InRecovery() bool {
- return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
-}
-
-func (c *Module) OnlyInRamdisk() bool {
- return c.ModuleBase.InstallInRamdisk()
-}
-
-func (c *Module) OnlyInRecovery() bool {
- return c.ModuleBase.InstallInRecovery()
-}
-
func (c *Module) IsStubs() bool {
if library, ok := c.linker.(*libraryDecorator); ok {
return library.buildStubs()
@@ -1045,6 +1115,10 @@
return nil
}
+func (c *Module) ExcludeFromVendorSnapshot() bool {
+ return Bool(c.Properties.Exclude_from_vendor_snapshot)
+}
+
func isBionic(name string) bool {
switch name {
case "libc", "libm", "libdl", "libdl_android", "linker":
@@ -1055,7 +1129,7 @@
func InstallToBootstrap(name string, config android.Config) bool {
if name == "libclang_rt.hwasan-aarch64-android" {
- return inList("hwaddress", config.SanitizeDevice())
+ return true
}
return isBionic(name)
}
@@ -1079,16 +1153,6 @@
moduleContextImpl
}
-func (ctx *moduleContext) ProductSpecific() bool {
- return ctx.ModuleContext.ProductSpecific() ||
- (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk())
-}
-
-func (ctx *moduleContext) SocSpecific() bool {
- return ctx.ModuleContext.SocSpecific() ||
- (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk())
-}
-
type moduleContextImpl struct {
mod *Module
ctx BaseModuleContext
@@ -1184,28 +1248,17 @@
return ctx.mod.MustUseVendorVariant()
}
-func (ctx *moduleContextImpl) inProduct() bool {
- return ctx.mod.inProduct()
-}
-
-func (ctx *moduleContextImpl) inVendor() bool {
- return ctx.mod.inVendor()
-}
-
-func (ctx *moduleContextImpl) inRamdisk() bool {
- return ctx.mod.InRamdisk()
-}
-
-func (ctx *moduleContextImpl) inRecovery() bool {
- return ctx.mod.InRecovery()
-}
-
// Check whether ABI dumps should be created for this module.
func (ctx *moduleContextImpl) shouldCreateSourceAbiDump() bool {
if ctx.ctx.Config().IsEnvTrue("SKIP_ABI_CHECKS") {
return false
}
+ // Coverage builds have extra symbols.
+ if ctx.mod.isCoverageVariant() {
+ return false
+ }
+
if ctx.ctx.Fuchsia() {
return false
}
@@ -1249,8 +1302,8 @@
return ctx.mod.IsForPlatform()
}
-func (ctx *moduleContextImpl) apexName() string {
- return ctx.mod.ApexName()
+func (ctx *moduleContextImpl) apexVariationName() string {
+ return ctx.mod.ApexVariationName()
}
func (ctx *moduleContextImpl) apexSdkVersion() int {
@@ -1385,6 +1438,15 @@
return ok && test.isAllTestsVariation()
}
+func (c *Module) DataPaths() []android.DataPath {
+ if p, ok := c.installer.(interface {
+ dataPaths() []android.DataPath
+ }); ok {
+ return p.dataPaths()
+ }
+ return nil
+}
+
func (c *Module) getNameSuffixWithVndkVersion(ctx android.ModuleContext) string {
// Returns the name suffix for product and vendor variants. If the VNDK version is not
// "current", it will append the VNDK version to the name suffix.
@@ -1442,8 +1504,11 @@
c.Properties.SubName += ramdiskSuffix
} else if c.InRecovery() && !c.OnlyInRecovery() {
c.Properties.SubName += recoverySuffix
- } else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
+ } else if c.IsSdkVariant() && (c.Properties.SdkAndPlatformVariantVisibleToMake || c.SplitPerApiLevel()) {
c.Properties.SubName += sdkSuffix
+ if c.SplitPerApiLevel() {
+ c.Properties.SubName += "." + c.SdkVersion()
+ }
}
ctx := &moduleContext{
@@ -1616,7 +1681,7 @@
for _, feature := range c.features {
feature.begin(ctx)
}
- if ctx.useSdk() {
+ if ctx.useSdk() && c.IsSdkVariant() {
version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch())
if err != nil {
ctx.PropertyErrorf("sdk_version", err.Error())
@@ -1719,6 +1784,22 @@
return name, ""
}
+func GetCrtVariations(ctx android.BottomUpMutatorContext,
+ m LinkableInterface) []blueprint.Variation {
+ if ctx.Os() != android.Android {
+ return nil
+ }
+ if m.UseSdk() {
+ return []blueprint.Variation{
+ {Mutator: "sdk", Variation: "sdk"},
+ {Mutator: "ndk_api", Variation: m.SdkVersion()},
+ }
+ }
+ return []blueprint.Variation{
+ {Mutator: "sdk", Variation: ""},
+ }
+}
+
func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if !c.Enabled() {
return
@@ -1737,8 +1818,6 @@
variantNdkLibs := []string{}
variantLateNdkLibs := []string{}
if ctx.Os() == android.Android {
- version := ctx.sdkVersion()
-
// rewriteLibs takes a list of names of shared libraries and scans it for three types
// of names:
//
@@ -1780,12 +1859,8 @@
for _, entry := range list {
// strip #version suffix out
name, _ := StubsLibNameAndVersion(entry)
- if ctx.useSdk() && inList(name, ndkPrebuiltSharedLibraries) {
- if !inList(name, ndkMigratedLibs) {
- nonvariantLibs = append(nonvariantLibs, name+".ndk."+version)
- } else {
- variantLibs = append(variantLibs, name+ndkLibrarySuffix)
- }
+ if ctx.useSdk() && inList(name, ndkKnownLibs) {
+ variantLibs = append(variantLibs, name+ndkLibrarySuffix)
} else if ctx.useVndk() {
nonvariantLibs = append(nonvariantLibs, rewriteVendorLibs(entry))
} else if (ctx.Platform() || ctx.ProductSpecific()) && inList(name, *vendorPublicLibraries) {
@@ -1840,9 +1915,9 @@
vendorSnapshotHeaderLibs := vendorSnapshotHeaderLibs(actx.Config())
for _, lib := range deps.HeaderLibs {
- depTag := headerDepTag
+ depTag := libraryDependencyTag{Kind: headerLibraryDependency}
if inList(lib, deps.ReexportHeaderLibHeaders) {
- depTag = headerExportDepTag
+ depTag.reexportFlags = true
}
lib = rewriteSnapshotLibs(lib, vendorSnapshotHeaderLibs)
@@ -1865,7 +1940,7 @@
vendorSnapshotStaticLibs := vendorSnapshotStaticLibs(actx.Config())
for _, lib := range deps.WholeStaticLibs {
- depTag := wholeStaticDepTag
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, wholeStatic: true, reexportFlags: true}
if impl, ok := syspropImplLibraries[lib]; ok {
lib = impl
}
@@ -1878,9 +1953,9 @@
}
for _, lib := range deps.StaticLibs {
- depTag := StaticDepTag
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency}
if inList(lib, deps.ReexportStaticLibHeaders) {
- depTag = staticExportDepTag
+ depTag.reexportFlags = true
}
if impl, ok := syspropImplLibraries[lib]; ok {
@@ -1898,24 +1973,26 @@
// so that native libraries/binaries are linked with static unwinder
// because Q libc doesn't have unwinder APIs
if deps.StaticUnwinderIfLegacy {
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, staticUnwinder: true}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs))
+ }, depTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs))
}
for _, lib := range deps.LateStaticLibs {
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency, Order: lateLibraryDependency}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, lateStaticDepTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs))
+ }, depTag, rewriteSnapshotLibs(lib, vendorSnapshotStaticLibs))
}
- addSharedLibDependencies := func(depTag DependencyTag, name string, version string) {
+ addSharedLibDependencies := func(depTag libraryDependencyTag, name string, version string) {
var variations []blueprint.Variation
variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
if version != "" && VersionVariantAvailable(c) {
// Version is explicitly specified. i.e. libFoo#30
variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
- depTag.ExplicitlyVersioned = true
+ depTag.explicitlyVersioned = true
}
actx.AddVariationDependencies(variations, depTag, name)
@@ -1937,12 +2014,9 @@
var sharedLibNames []string
for _, lib := range deps.SharedLibs {
- depTag := SharedDepTag
- if c.static() {
- depTag = SharedFromStaticDepTag
- }
+ depTag := libraryDependencyTag{Kind: sharedLibraryDependency}
if inList(lib, deps.ReexportSharedLibHeaders) {
- depTag = sharedExportDepTag
+ depTag.reexportFlags = true
}
if impl, ok := syspropImplLibraries[lib]; ok {
@@ -1962,11 +2036,16 @@
// linking against both the stubs lib and the non-stubs lib at the same time.
continue
}
- addSharedLibDependencies(lateSharedDepTag, lib, "")
+ depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency}
+ addSharedLibDependencies(depTag, lib, "")
}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "shared"},
+ }, dataLibDepTag, deps.DataLibs...)
+
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
}, runtimeDepTag, deps.RuntimeLibs...)
actx.AddDependency(c, genSourceDepTag, deps.GeneratedSources...)
@@ -1983,11 +2062,14 @@
vendorSnapshotObjects := vendorSnapshotObjects(actx.Config())
+ crtVariations := GetCrtVariations(ctx, c)
if deps.CrtBegin != "" {
- actx.AddVariationDependencies(nil, CrtBeginDepTag, rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects))
+ actx.AddVariationDependencies(crtVariations, CrtBeginDepTag,
+ rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects))
}
if deps.CrtEnd != "" {
- actx.AddVariationDependencies(nil, CrtEndDepTag, rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects))
+ actx.AddVariationDependencies(crtVariations, CrtEndDepTag,
+ rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects))
}
if deps.LinkerFlagsFile != "" {
actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
@@ -1997,10 +2079,14 @@
}
version := ctx.sdkVersion()
+
+ ndkStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, ndk: true, makeSuffix: "." + version}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "ndk_api", Variation: version},
{Mutator: "link", Variation: "shared"},
}, ndkStubDepTag, variantNdkLibs...)
+
+ ndkLateStubDepTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: lateLibraryDependency, ndk: true, makeSuffix: "." + version}
actx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "ndk_api", Variation: version},
{Mutator: "link", Variation: "shared"},
@@ -2024,7 +2110,19 @@
// Whether a module can link to another module, taking into
// account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface, tag DependencyTag) {
+func checkLinkType(ctx android.ModuleContext, from LinkableInterface, to LinkableInterface,
+ tag blueprint.DependencyTag) {
+
+ switch t := tag.(type) {
+ case dependencyTag:
+ if t != vndkExtDepTag {
+ return
+ }
+ case libraryDependencyTag:
+ default:
+ return
+ }
+
if from.Module().Target().Os != android.Android {
// Host code is not restricted
return
@@ -2182,8 +2280,6 @@
directStaticDeps := []LinkableInterface{}
directSharedDeps := []LinkableInterface{}
- vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
-
reexportExporter := func(exporter exportedFlagsProducer) {
depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, exporter.exportedDirs()...)
depPaths.ReexportedSystemDirs = append(depPaths.ReexportedSystemDirs, exporter.exportedSystemDirs()...)
@@ -2192,6 +2288,19 @@
depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, exporter.exportedGeneratedHeaders()...)
}
+ // For the dependency from platform to apex, use the latest stubs
+ c.apexSdkVersion = android.FutureApiLevel
+ if !c.IsForPlatform() {
+ c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
+ }
+
+ if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
+ // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
+ // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
+ // (b/144430859)
+ c.apexSdkVersion = android.FutureApiLevel
+ }
+
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
@@ -2212,8 +2321,6 @@
fallthrough
case genHeaderDepTag, genHeaderExportDepTag:
if genRule, ok := dep.(genrule.SourceFileGenerator); ok {
- depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders,
- genRule.GeneratedSourceFiles()...)
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps,
genRule.GeneratedDeps()...)
dirs := genRule.GeneratedHeaderDirs()
@@ -2282,52 +2389,24 @@
}
}
- // For the dependency from platform to apex, use the latest stubs
- c.apexSdkVersion = android.FutureApiLevel
- if !c.IsForPlatform() {
- c.apexSdkVersion = c.ApexProperties.Info.MinSdkVersion
- }
+ checkLinkType(ctx, c, ccDep, depTag)
- if android.InList("hwaddress", ctx.Config().SanitizeDevice()) {
- // In hwasan build, we override apexSdkVersion to the FutureApiLevel(10000)
- // so that even Q(29/Android10) apexes could use the dynamic unwinder by linking the newer stubs(e.g libc(R+)).
- // (b/144430859)
- c.apexSdkVersion = android.FutureApiLevel
- }
+ linkFile := ccDep.OutputFile()
- if depTag == staticUnwinderDepTag {
- // Use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
- if c.apexSdkVersion <= android.SdkVersion_Android10 {
- depTag = StaticDepTag
- } else {
+ if libDepTag, ok := depTag.(libraryDependencyTag); ok {
+ // Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859)
+ if libDepTag.staticUnwinder && c.apexSdkVersion > android.SdkVersion_Android10 {
return
}
- }
- // Extract ExplicitlyVersioned field from the depTag and reset it inside the struct.
- // Otherwise, SharedDepTag and lateSharedDepTag with ExplicitlyVersioned set to true
- // won't be matched to SharedDepTag and lateSharedDepTag.
- explicitlyVersioned := false
- if t, ok := depTag.(DependencyTag); ok {
- explicitlyVersioned = t.ExplicitlyVersioned
- t.ExplicitlyVersioned = false
- depTag = t
- }
-
- if t, ok := depTag.(DependencyTag); ok && t.Library {
- depIsStatic := false
- switch depTag {
- case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
- depIsStatic = true
- }
- if ccDep.CcLibrary() && !depIsStatic {
+ if ccDep.CcLibrary() && !libDepTag.static() {
depIsStubs := ccDep.BuildStubs()
depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
- depInSameApex := android.DirectlyInApex(c.ApexName(), depName)
+ depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName)
depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
var useThisDep bool
- if depIsStubs && explicitlyVersioned {
+ if depIsStubs && libDepTag.explicitlyVersioned {
// Always respect dependency to the versioned stubs (i.e. libX#10)
useThisDep = true
} else if !depHasStubs {
@@ -2353,13 +2432,13 @@
}
}
} else {
- // If building for APEX, use stubs only when it is not from
- // the same APEX
- useThisDep = (depInSameApex != depIsStubs)
+ // If building for APEX, use stubs when the parent is in any APEX that
+ // the child is not in.
+ useThisDep = (depInSameApexes != depIsStubs)
}
// when to use (unspecified) stubs, check min_sdk_version and choose the right one
- if useThisDep && depIsStubs && !explicitlyVersioned {
+ if useThisDep && depIsStubs && !libDepTag.explicitlyVersioned {
versionToUse, err := c.ChooseSdkVersion(ccDep.StubsVersions(), c.apexSdkVersion)
if err != nil {
ctx.OtherModuleErrorf(dep, err.Error())
@@ -2379,7 +2458,7 @@
// by default, use current version of LLNDK
versionToUse := ""
versions := stubsVersionsFor(ctx.Config())[depName]
- if c.ApexName() != "" && len(versions) > 0 {
+ if c.ApexVariationName() != "" && len(versions) > 0 {
// if this is for use_vendor apex && dep has stubsVersions
// apply the same rule of apex sdk enforcement to choose right version
var err error
@@ -2401,11 +2480,10 @@
if _, ok := ccDep.(*Module); ok {
if i, ok := ccDep.(*Module).linker.(exportedFlagsProducer); ok {
depPaths.SystemIncludeDirs = append(depPaths.SystemIncludeDirs, i.exportedSystemDirs()...)
- depPaths.GeneratedHeaders = append(depPaths.GeneratedHeaders, i.exportedGeneratedHeaders()...)
depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, i.exportedDeps()...)
depPaths.Flags = append(depPaths.Flags, i.exportedFlags()...)
- if t.ReexportFlags {
+ if libDepTag.reexportFlags {
reexportExporter(i)
// Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library.
// Re-exported shared library headers must be included as well since they can help us with type information
@@ -2417,200 +2495,169 @@
}
}
}
- checkLinkType(ctx, c, ccDep, t)
- }
- var ptr *android.Paths
- var depPtr *android.Paths
+ var ptr *android.Paths
+ var depPtr *android.Paths
- linkFile := ccDep.OutputFile()
- depFile := android.OptionalPath{}
+ depFile := android.OptionalPath{}
- switch depTag {
- case ndkStubDepTag, SharedDepTag, SharedFromStaticDepTag, sharedExportDepTag:
- ptr = &depPaths.SharedLibs
- depPtr = &depPaths.SharedLibsDeps
- depFile = ccDep.Toc()
- directSharedDeps = append(directSharedDeps, ccDep)
-
- case earlySharedDepTag:
- ptr = &depPaths.EarlySharedLibs
- depPtr = &depPaths.EarlySharedLibsDeps
- depFile = ccDep.Toc()
- directSharedDeps = append(directSharedDeps, ccDep)
- case lateSharedDepTag, ndkLateStubDepTag:
- ptr = &depPaths.LateSharedLibs
- depPtr = &depPaths.LateSharedLibsDeps
- depFile = ccDep.Toc()
- case StaticDepTag, staticExportDepTag:
- ptr = nil
- directStaticDeps = append(directStaticDeps, ccDep)
- case lateStaticDepTag:
- ptr = &depPaths.LateStaticLibs
- case wholeStaticDepTag:
- ptr = &depPaths.WholeStaticLibs
- if !ccDep.CcLibraryInterface() || !ccDep.Static() {
- ctx.ModuleErrorf("module %q not a static library", depName)
- return
- }
-
- // Because the static library objects are included, this only makes sense
- // in the context of proper cc.Modules.
- if ccWholeStaticLib, ok := ccDep.(*Module); ok {
- staticLib := ccWholeStaticLib.linker.(libraryInterface)
- if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
- postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
- for i := range missingDeps {
- missingDeps[i] += postfix
- }
- ctx.AddMissingDependencies(missingDeps)
+ switch {
+ case libDepTag.header():
+ // nothing
+ case libDepTag.shared():
+ ptr = &depPaths.SharedLibs
+ switch libDepTag.Order {
+ case earlyLibraryDependency:
+ ptr = &depPaths.EarlySharedLibs
+ depPtr = &depPaths.EarlySharedLibsDeps
+ case normalLibraryDependency:
+ ptr = &depPaths.SharedLibs
+ depPtr = &depPaths.SharedLibsDeps
+ directSharedDeps = append(directSharedDeps, ccDep)
+ case lateLibraryDependency:
+ ptr = &depPaths.LateSharedLibs
+ depPtr = &depPaths.LateSharedLibsDeps
+ default:
+ panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
- depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
- } else {
- ctx.ModuleErrorf(
- "non-cc.Modules cannot be included as whole static libraries.", depName)
- return
- }
- case headerDepTag:
- // Nothing
- case objDepTag:
- depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
- case CrtBeginDepTag:
- depPaths.CrtBegin = linkFile
- case CrtEndDepTag:
- depPaths.CrtEnd = linkFile
- case dynamicLinkerDepTag:
- depPaths.DynamicLinker = linkFile
- }
-
- switch depTag {
- case StaticDepTag, staticExportDepTag, lateStaticDepTag:
- if !ccDep.CcLibraryInterface() || !ccDep.Static() {
- ctx.ModuleErrorf("module %q not a static library", depName)
- return
- }
-
- // When combining coverage files for shared libraries and executables, coverage files
- // in static libraries act as if they were whole static libraries. The same goes for
- // source based Abi dump files.
- // This should only be done for cc.Modules
- if c, ok := ccDep.(*Module); ok {
- staticLib := c.linker.(libraryInterface)
- depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
- staticLib.objs().coverageFiles...)
- depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
- staticLib.objs().sAbiDumpFiles...)
- }
- }
-
- if ptr != nil {
- if !linkFile.Valid() {
- if !ctx.Config().AllowMissingDependencies() {
- ctx.ModuleErrorf("module %q missing output file", depName)
- } else {
- ctx.AddMissingDependencies([]string{depName})
- }
- return
- }
- *ptr = append(*ptr, linkFile.Path())
- }
-
- if depPtr != nil {
- dep := depFile
- if !dep.Valid() {
- dep = linkFile
- }
- *depPtr = append(*depPtr, dep.Path())
- }
-
- vendorSuffixModules := vendorSuffixModules(ctx.Config())
-
- baseLibName := func(depName string) string {
- libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
- libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
- libName = strings.TrimPrefix(libName, "prebuilt_")
- return libName
- }
-
- makeLibName := func(depName string) string {
- libName := baseLibName(depName)
- isLLndk := isLlndkLibrary(libName, ctx.Config())
- isVendorPublicLib := inList(libName, *vendorPublicLibraries)
- bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
-
- if c, ok := ccDep.(*Module); ok {
- // Use base module name for snapshots when exporting to Makefile.
- if c.isSnapshotPrebuilt() {
- baseName := c.BaseModuleName()
-
- if c.IsVndk() {
- return baseName + ".vendor"
+ depFile = ccDep.Toc()
+ case libDepTag.static():
+ if libDepTag.wholeStatic {
+ ptr = &depPaths.WholeStaticLibs
+ if !ccDep.CcLibraryInterface() || !ccDep.Static() {
+ ctx.ModuleErrorf("module %q not a static library", depName)
+ return
}
- if vendorSuffixModules[baseName] {
- return baseName + ".vendor"
+ // Because the static library objects are included, this only makes sense
+ // in the context of proper cc.Modules.
+ if ccWholeStaticLib, ok := ccDep.(*Module); ok {
+ staticLib := ccWholeStaticLib.linker.(libraryInterface)
+ if missingDeps := staticLib.getWholeStaticMissingDeps(); missingDeps != nil {
+ postfix := " (required by " + ctx.OtherModuleName(dep) + ")"
+ for i := range missingDeps {
+ missingDeps[i] += postfix
+ }
+ ctx.AddMissingDependencies(missingDeps)
+ }
+ if _, ok := ccWholeStaticLib.linker.(prebuiltLinkerInterface); ok {
+ depPaths.WholeStaticLibsFromPrebuilts = append(depPaths.WholeStaticLibsFromPrebuilts, linkFile.Path())
+ } else {
+ depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Append(staticLib.objs())
+ }
} else {
- return baseName
+ ctx.ModuleErrorf(
+ "non-cc.Modules cannot be included as whole static libraries.", depName)
+ return
+ }
+
+ } else {
+ switch libDepTag.Order {
+ case earlyLibraryDependency:
+ panic(fmt.Errorf("early static libs not suppported"))
+ case normalLibraryDependency:
+ // static dependencies will be handled separately so they can be ordered
+ // using transitive dependencies.
+ ptr = nil
+ directStaticDeps = append(directStaticDeps, ccDep)
+ case lateLibraryDependency:
+ ptr = &depPaths.LateStaticLibs
+ default:
+ panic(fmt.Errorf("unexpected library dependency order %d", libDepTag.Order))
}
}
}
- if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() {
- // The vendor module is a no-vendor-variant VNDK library. Depend on the
- // core module instead.
- return libName
- } else if c.UseVndk() && bothVendorAndCoreVariantsExist {
- // The vendor module in Make will have been renamed to not conflict with the core
- // module, so update the dependency name here accordingly.
- return libName + c.getNameSuffixWithVndkVersion(ctx)
- } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
- return libName + vendorPublicLibrarySuffix
- } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
- return libName + ramdiskSuffix
- } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
- return libName + recoverySuffix
- } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
- return libName + nativeBridgeSuffix
- } else {
- return libName
- }
- }
+ if libDepTag.static() && !libDepTag.wholeStatic {
+ if !ccDep.CcLibraryInterface() || !ccDep.Static() {
+ ctx.ModuleErrorf("module %q not a static library", depName)
+ return
+ }
- // Export the shared libs to Make.
- switch depTag {
- case SharedDepTag, sharedExportDepTag, lateSharedDepTag, earlySharedDepTag:
- if ccDep.CcLibrary() {
- if ccDep.BuildStubs() && android.InAnyApex(depName) {
- // Add the dependency to the APEX(es) providing the library so that
- // m <module> can trigger building the APEXes as well.
- for _, an := range android.GetApexesForModule(depName) {
- c.Properties.ApexesProvidingSharedLibs = append(
- c.Properties.ApexesProvidingSharedLibs, an)
- }
+ // When combining coverage files for shared libraries and executables, coverage files
+ // in static libraries act as if they were whole static libraries. The same goes for
+ // source based Abi dump files.
+ if c, ok := ccDep.(*Module); ok {
+ staticLib := c.linker.(libraryInterface)
+ depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+ staticLib.objs().coverageFiles...)
+ depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles,
+ staticLib.objs().sAbiDumpFiles...)
+ } else if c, ok := ccDep.(LinkableInterface); ok {
+ // Handle non-CC modules here
+ depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles,
+ c.CoverageFiles()...)
}
}
- // Note: the order of libs in this list is not important because
- // they merely serve as Make dependencies and do not affect this lib itself.
- c.Properties.AndroidMkSharedLibs = append(
- c.Properties.AndroidMkSharedLibs, makeLibName(depName))
- // Record baseLibName for snapshots.
- c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName))
- case ndkStubDepTag, ndkLateStubDepTag:
- c.Properties.AndroidMkSharedLibs = append(
- c.Properties.AndroidMkSharedLibs,
- depName+"."+ccDep.ApiLevel())
- case StaticDepTag, staticExportDepTag, lateStaticDepTag:
- c.Properties.AndroidMkStaticLibs = append(
- c.Properties.AndroidMkStaticLibs, makeLibName(depName))
- case runtimeDepTag:
- c.Properties.AndroidMkRuntimeLibs = append(
- c.Properties.AndroidMkRuntimeLibs, makeLibName(depName))
- // Record baseLibName for snapshots.
- c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
- case wholeStaticDepTag:
- c.Properties.AndroidMkWholeStaticLibs = append(
- c.Properties.AndroidMkWholeStaticLibs, makeLibName(depName))
+ if ptr != nil {
+ if !linkFile.Valid() {
+ if !ctx.Config().AllowMissingDependencies() {
+ ctx.ModuleErrorf("module %q missing output file", depName)
+ } else {
+ ctx.AddMissingDependencies([]string{depName})
+ }
+ return
+ }
+ *ptr = append(*ptr, linkFile.Path())
+ }
+
+ if depPtr != nil {
+ dep := depFile
+ if !dep.Valid() {
+ dep = linkFile
+ }
+ *depPtr = append(*depPtr, dep.Path())
+ }
+
+ makeLibName := c.makeLibName(ctx, ccDep, depName) + libDepTag.makeSuffix
+ switch {
+ case libDepTag.header():
+ c.Properties.AndroidMkHeaderLibs = append(
+ c.Properties.AndroidMkHeaderLibs, makeLibName)
+ case libDepTag.shared():
+ if ccDep.CcLibrary() {
+ if ccDep.BuildStubs() && android.InAnyApex(depName) {
+ // Add the dependency to the APEX(es) providing the library so that
+ // m <module> can trigger building the APEXes as well.
+ for _, an := range android.GetApexesForModule(depName) {
+ c.Properties.ApexesProvidingSharedLibs = append(
+ c.Properties.ApexesProvidingSharedLibs, an)
+ }
+ }
+ }
+
+ // Note: the order of libs in this list is not important because
+ // they merely serve as Make dependencies and do not affect this lib itself.
+ c.Properties.AndroidMkSharedLibs = append(
+ c.Properties.AndroidMkSharedLibs, makeLibName)
+ // Record baseLibName for snapshots.
+ c.Properties.SnapshotSharedLibs = append(c.Properties.SnapshotSharedLibs, baseLibName(depName))
+ case libDepTag.static():
+ if libDepTag.wholeStatic {
+ c.Properties.AndroidMkWholeStaticLibs = append(
+ c.Properties.AndroidMkWholeStaticLibs, makeLibName)
+ } else {
+ c.Properties.AndroidMkStaticLibs = append(
+ c.Properties.AndroidMkStaticLibs, makeLibName)
+ }
+ }
+ } else {
+ switch depTag {
+ case runtimeDepTag:
+ c.Properties.AndroidMkRuntimeLibs = append(
+ c.Properties.AndroidMkRuntimeLibs, c.makeLibName(ctx, ccDep, depName)+libDepTag.makeSuffix)
+ // Record baseLibName for snapshots.
+ c.Properties.SnapshotRuntimeLibs = append(c.Properties.SnapshotRuntimeLibs, baseLibName(depName))
+ case objDepTag:
+ depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path())
+ case CrtBeginDepTag:
+ depPaths.CrtBegin = linkFile
+ case CrtEndDepTag:
+ depPaths.CrtEnd = linkFile
+ case dynamicLinkerDepTag:
+ depPaths.DynamicLinker = linkFile
+ }
}
})
@@ -2621,7 +2668,6 @@
depPaths.Flags = android.FirstUniqueStrings(depPaths.Flags)
depPaths.IncludeDirs = android.FirstUniquePaths(depPaths.IncludeDirs)
depPaths.SystemIncludeDirs = android.FirstUniquePaths(depPaths.SystemIncludeDirs)
- depPaths.GeneratedHeaders = android.FirstUniquePaths(depPaths.GeneratedHeaders)
depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps)
depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs)
depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs)
@@ -2636,6 +2682,61 @@
return depPaths
}
+// baseLibName trims known prefixes and suffixes
+func baseLibName(depName string) string {
+ libName := strings.TrimSuffix(depName, llndkLibrarySuffix)
+ libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix)
+ libName = strings.TrimPrefix(libName, "prebuilt_")
+ return libName
+}
+
+func (c *Module) makeLibName(ctx android.ModuleContext, ccDep LinkableInterface, depName string) string {
+ vendorSuffixModules := vendorSuffixModules(ctx.Config())
+ vendorPublicLibraries := vendorPublicLibraries(ctx.Config())
+
+ libName := baseLibName(depName)
+ isLLndk := isLlndkLibrary(libName, ctx.Config())
+ isVendorPublicLib := inList(libName, *vendorPublicLibraries)
+ bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
+
+ if c, ok := ccDep.(*Module); ok {
+ // Use base module name for snapshots when exporting to Makefile.
+ if c.isSnapshotPrebuilt() {
+ baseName := c.BaseModuleName()
+
+ if c.IsVndk() {
+ return baseName + ".vendor"
+ }
+
+ if vendorSuffixModules[baseName] {
+ return baseName + ".vendor"
+ } else {
+ return baseName
+ }
+ }
+ }
+
+ if ctx.DeviceConfig().VndkUseCoreVariant() && ccDep.IsVndk() && !ccDep.MustUseVendorVariant() && !c.InRamdisk() && !c.InRecovery() {
+ // The vendor module is a no-vendor-variant VNDK library. Depend on the
+ // core module instead.
+ return libName
+ } else if c.UseVndk() && bothVendorAndCoreVariantsExist {
+ // The vendor module in Make will have been renamed to not conflict with the core
+ // module, so update the dependency name here accordingly.
+ return libName + c.getNameSuffixWithVndkVersion(ctx)
+ } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
+ return libName + vendorPublicLibrarySuffix
+ } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
+ return libName + ramdiskSuffix
+ } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
+ return libName + recoverySuffix
+ } else if ccDep.Module().Target().NativeBridge == android.NativeBridgeEnabled {
+ return libName + nativeBridgeSuffix
+ } else {
+ return libName
+ }
+}
+
func (c *Module) InstallInData() bool {
if c.installer == nil {
return false
@@ -2661,12 +2762,12 @@
return c.InRecovery()
}
-func (c *Module) SkipInstall() {
+func (c *Module) MakeUninstallable() {
if c.installer == nil {
- c.ModuleBase.SkipInstall()
+ c.ModuleBase.MakeUninstallable()
return
}
- c.installer.skipInstall(c)
+ c.installer.makeUninstallable(c)
}
func (c *Module) HostToolPath() android.OptionalPath {
@@ -2806,6 +2907,16 @@
}
}
+func (c *Module) UniqueApexVariations() bool {
+ if u, ok := c.compiler.(interface {
+ uniqueApexVariations() bool
+ }); ok {
+ return u.uniqueApexVariations()
+ } else {
+ return false
+ }
+}
+
// Return true if the module is ever installable.
func (c *Module) EverInstallable() bool {
return c.installer != nil &&
@@ -2847,29 +2958,82 @@
}
func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
- if depTag, ok := ctx.OtherModuleDependencyTag(dep).(DependencyTag); ok {
- if cc, ok := dep.(*Module); ok {
- if cc.HasStubsVariants() {
- if depTag.Shared && depTag.Library {
- // dynamic dep to a stubs lib crosses APEX boundary
- return false
- }
- if IsRuntimeDepTag(depTag) {
- // runtime dep to a stubs lib also crosses APEX boundary
- return false
- }
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ libDepTag, isLibDepTag := depTag.(libraryDependencyTag)
+
+ if cc, ok := dep.(*Module); ok {
+ if cc.HasStubsVariants() {
+ if isLibDepTag && libDepTag.shared() {
+ // dynamic dep to a stubs lib crosses APEX boundary
+ return false
}
- if depTag.FromStatic {
- // shared_lib dependency from a static lib is considered as crossing
- // the APEX boundary because the dependency doesn't actually is
- // linked; the dependency is used only during the compilation phase.
+ if IsRuntimeDepTag(depTag) {
+ // runtime dep to a stubs lib also crosses APEX boundary
return false
}
}
+ if isLibDepTag && c.static() && libDepTag.shared() {
+ // shared_lib dependency from a static lib is considered as crossing
+ // the APEX boundary because the dependency doesn't actually is
+ // linked; the dependency is used only during the compilation phase.
+ return false
+ }
+ }
+ if depTag == llndkImplDep {
+ // We don't track beyond LLNDK
+ return false
}
return true
}
+// b/154667674: refactor this to handle "current" in a consistent way
+func decodeSdkVersionString(ctx android.BaseModuleContext, versionString string) (int, error) {
+ if versionString == "" {
+ return 0, fmt.Errorf("not specified")
+ }
+ if versionString == "current" {
+ if ctx.Config().PlatformSdkCodename() == "REL" {
+ return ctx.Config().PlatformSdkVersionInt(), nil
+ }
+ return android.FutureApiLevel, nil
+ }
+ return android.ApiStrToNum(ctx, versionString)
+}
+
+func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700)
+ if strings.HasPrefix(ctx.OtherModuleName(c), "libclang_rt") {
+ return nil
+ }
+ // b/154569636: set min_sdk_version correctly for toolchain_libraries
+ if c.ToolchainLibrary() {
+ return nil
+ }
+ // We don't check for prebuilt modules
+ if _, ok := c.linker.(prebuiltLinkerInterface); ok {
+ return nil
+ }
+ minSdkVersion := c.MinSdkVersion()
+ if minSdkVersion == "apex_inherit" {
+ return nil
+ }
+ if minSdkVersion == "" {
+ // JNI libs within APK-in-APEX fall into here
+ // Those are okay to set sdk_version instead
+ // We don't have to check if this is a SDK variant because
+ // non-SDK variant resets sdk_version, which works too.
+ minSdkVersion = c.SdkVersion()
+ }
+ ver, err := decodeSdkVersionString(ctx, minSdkVersion)
+ if err != nil {
+ return err
+ }
+ if ver > sdkVersion {
+ return fmt.Errorf("newer SDK(%v)", ver)
+ }
+ return nil
+}
+
//
// Defaults
//
@@ -2905,6 +3069,7 @@
&BinaryLinkerProperties{},
&TestProperties{},
&TestBinaryProperties{},
+ &BenchmarkProperties{},
&FuzzProperties{},
&StlProperties{},
&SanitizeProperties{},
@@ -2931,6 +3096,9 @@
lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs,
lib.baseCompiler.Properties.Target.Vendor.Exclude_srcs...)
+
+ lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources,
+ lib.baseCompiler.Properties.Target.Vendor.Exclude_generated_sources...)
}
}
@@ -2941,228 +3109,14 @@
lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs,
lib.baseCompiler.Properties.Target.Recovery.Exclude_srcs...)
+
+ lib.baseCompiler.Properties.Exclude_generated_sources = append(lib.baseCompiler.Properties.Exclude_generated_sources,
+ lib.baseCompiler.Properties.Target.Recovery.Exclude_generated_sources...)
}
}
-var _ android.ImageInterface = (*Module)(nil)
-
-func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
- // Sanity check
- vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
- productSpecific := mctx.ProductSpecific()
-
- if m.VendorProperties.Vendor_available != nil && vendorSpecific {
- mctx.PropertyErrorf("vendor_available",
- "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
- }
-
- if vndkdep := m.vndkdep; vndkdep != nil {
- if vndkdep.isVndk() {
- if vendorSpecific || productSpecific {
- if !vndkdep.isVndkExt() {
- mctx.PropertyErrorf("vndk",
- "must set `extends: \"...\"` to vndk extension")
- } else if m.VendorProperties.Vendor_available != nil {
- mctx.PropertyErrorf("vendor_available",
- "must not set at the same time as `vndk: {extends: \"...\"}`")
- }
- } else {
- if vndkdep.isVndkExt() {
- mctx.PropertyErrorf("vndk",
- "must set `vendor: true` or `product_specific: true` to set `extends: %q`",
- m.getVndkExtendsModuleName())
- }
- if m.VendorProperties.Vendor_available == nil {
- mctx.PropertyErrorf("vndk",
- "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
- }
- }
- } else {
- if vndkdep.isVndkSp() {
- mctx.PropertyErrorf("vndk",
- "must set `enabled: true` to set `support_system_process: true`")
- }
- if vndkdep.isVndkExt() {
- mctx.PropertyErrorf("vndk",
- "must set `enabled: true` to set `extends: %q`",
- m.getVndkExtendsModuleName())
- }
- }
- }
-
- var coreVariantNeeded bool = false
- var ramdiskVariantNeeded bool = false
- var recoveryVariantNeeded bool = false
-
- var vendorVariants []string
- var productVariants []string
-
- platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
- boardVndkVersion := mctx.DeviceConfig().VndkVersion()
- productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
- if boardVndkVersion == "current" {
- boardVndkVersion = platformVndkVersion
- }
- if productVndkVersion == "current" {
- productVndkVersion = platformVndkVersion
- }
-
- if boardVndkVersion == "" {
- // If the device isn't compiling against the VNDK, we always
- // use the core mode.
- coreVariantNeeded = true
- } else if _, ok := m.linker.(*llndkStubDecorator); ok {
- // LL-NDK stubs only exist in the vendor and product variants,
- // since the real libraries will be used in the core variant.
- vendorVariants = append(vendorVariants,
- platformVndkVersion,
- boardVndkVersion,
- )
- productVariants = append(productVariants,
- platformVndkVersion,
- productVndkVersion,
- )
- } else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
- // ... and LL-NDK headers as well
- vendorVariants = append(vendorVariants,
- platformVndkVersion,
- boardVndkVersion,
- )
- productVariants = append(productVariants,
- platformVndkVersion,
- productVndkVersion,
- )
- } else if m.isSnapshotPrebuilt() {
- // Make vendor variants only for the versions in BOARD_VNDK_VERSION and
- // PRODUCT_EXTRA_VNDK_VERSIONS.
- if snapshot, ok := m.linker.(interface {
- version() string
- }); ok {
- vendorVariants = append(vendorVariants, snapshot.version())
- } else {
- mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
- }
- } else if m.HasVendorVariant() && !m.isVndkExt() {
- // This will be available in /system, /vendor and /product
- // or a /system directory that is available to vendor and product.
- coreVariantNeeded = true
-
- // We assume that modules under proprietary paths are compatible for
- // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
- // PLATFORM_VNDK_VERSION.
- if isVendorProprietaryPath(mctx.ModuleDir()) {
- vendorVariants = append(vendorVariants, boardVndkVersion)
- } else {
- vendorVariants = append(vendorVariants, platformVndkVersion)
- }
-
- // vendor_available modules are also available to /product.
- productVariants = append(productVariants, platformVndkVersion)
- // VNDK is always PLATFORM_VNDK_VERSION
- if !m.IsVndk() {
- productVariants = append(productVariants, productVndkVersion)
- }
- } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
- // This will be available in /vendor (or /odm) only
- // We assume that modules under proprietary paths are compatible for
- // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
- // PLATFORM_VNDK_VERSION.
- if isVendorProprietaryPath(mctx.ModuleDir()) {
- vendorVariants = append(vendorVariants, boardVndkVersion)
- } else {
- vendorVariants = append(vendorVariants, platformVndkVersion)
- }
- } else {
- // This is either in /system (or similar: /data), or is a
- // modules built with the NDK. Modules built with the NDK
- // will be restricted using the existing link type checks.
- coreVariantNeeded = true
- }
-
- if boardVndkVersion != "" && productVndkVersion != "" {
- if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" {
- // The module has "product_specific: true" that does not create core variant.
- coreVariantNeeded = false
- productVariants = append(productVariants, productVndkVersion)
- }
- } else {
- // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no
- // restriction to use system libs.
- // No product variants defined in this case.
- productVariants = []string{}
- }
-
- if Bool(m.Properties.Ramdisk_available) {
- ramdiskVariantNeeded = true
- }
-
- if m.ModuleBase.InstallInRamdisk() {
- ramdiskVariantNeeded = true
- coreVariantNeeded = false
- }
-
- if Bool(m.Properties.Recovery_available) {
- recoveryVariantNeeded = true
- }
-
- if m.ModuleBase.InstallInRecovery() {
- recoveryVariantNeeded = true
- coreVariantNeeded = false
- }
-
- for _, variant := range android.FirstUniqueStrings(vendorVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant)
- }
-
- for _, variant := range android.FirstUniqueStrings(productVariants) {
- m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant)
- }
-
- m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
- m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
- m.Properties.CoreVariantNeeded = coreVariantNeeded
-}
-
-func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
- return c.Properties.CoreVariantNeeded
-}
-
-func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
- return c.Properties.RamdiskVariantNeeded
-}
-
-func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
- return c.Properties.RecoveryVariantNeeded
-}
-
-func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
- return c.Properties.ExtraVariants
-}
-
-func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
- m := module.(*Module)
- if variant == android.RamdiskVariation {
- m.MakeAsPlatform()
- } else if variant == android.RecoveryVariation {
- m.MakeAsPlatform()
- squashRecoverySrcs(m)
- } else if strings.HasPrefix(variant, VendorVariationPrefix) {
- m.Properties.ImageVariationPrefix = VendorVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
- squashVendorSrcs(m)
-
- // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
- // Hide other vendor variants to avoid collision.
- vndkVersion := ctx.DeviceConfig().VndkVersion()
- if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
- m.Properties.HideFromMake = true
- m.SkipInstall()
- }
- } else if strings.HasPrefix(variant, ProductVariationPrefix) {
- m.Properties.ImageVariationPrefix = ProductVariationPrefix
- m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
- squashVendorSrcs(m)
- }
+func (c *Module) IsSdkVariant() bool {
+ return c.Properties.IsSdkVariant || c.AlwaysSdk()
}
func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index f73e021..a4c0677 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -258,7 +258,8 @@
}
}
-func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) {
+ t.Helper()
mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
if !ok {
t.Errorf("%q must have output\n", moduleName)
@@ -271,12 +272,27 @@
}
snapshotPath := filepath.Join(subDir, snapshotFilename)
- out := singleton.Output(snapshotPath)
- if out.Input.String() != outputFiles[0].String() {
- t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+ if include {
+ out := singleton.Output(snapshotPath)
+ if out.Input.String() != outputFiles[0].String() {
+ t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
+ }
+ } else {
+ out := singleton.MaybeOutput(snapshotPath)
+ if out.Rule != nil {
+ t.Errorf("There must be no rule for module %q output file %q", moduleName, outputFiles[0])
+ }
}
}
+func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+ checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true)
+}
+
+func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+ checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false)
+}
+
func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
t.Helper()
assertString(t, params.Rule.String(), android.WriteFile.String())
@@ -526,6 +542,103 @@
checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", []string{"libc++.so", "libvndk2.so", "libvndk_sp.so"})
}
+func TestDataLibs(t *testing.T) {
+ bp := `
+ cc_test_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ gtest: false,
+ }
+
+ cc_test {
+ name: "main_test",
+ data_libs: ["test_lib"],
+ gtest: false,
+ }
+ `
+
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+
+ ctx := testCcWithConfig(t, config)
+ module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
+ testBinary := module.(*Module).linker.(*testBinary)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Errorf("Expected cc_test to produce output files, error: %s", err)
+ return
+ }
+ if len(outputFiles) != 1 {
+ t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
+ return
+ }
+ if len(testBinary.dataPaths()) != 1 {
+ t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+ return
+ }
+
+ outputPath := outputFiles[0].String()
+ testBinaryPath := testBinary.dataPaths()[0].SrcPath.String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ return
+ }
+ if !strings.HasSuffix(testBinaryPath, "/test_lib.so") {
+ t.Errorf("expected test data file to be 'test_lib.so', but was '%s'", testBinaryPath)
+ return
+ }
+}
+
+func TestDataLibsRelativeInstallPath(t *testing.T) {
+ bp := `
+ cc_test_library {
+ name: "test_lib",
+ srcs: ["test_lib.cpp"],
+ relative_install_path: "foo/bar/baz",
+ gtest: false,
+ }
+
+ cc_test {
+ name: "main_test",
+ data_libs: ["test_lib"],
+ gtest: false,
+ }
+ `
+
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+
+ ctx := testCcWithConfig(t, config)
+ module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
+ testBinary := module.(*Module).linker.(*testBinary)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected cc_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 1 {
+ t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ entries := android.AndroidMkEntriesForTest(t, config, "", module)[0]
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
+ }
+}
+
func TestVndkWhenVndkVersionIsNotSet(t *testing.T) {
ctx := testCcNoVndk(t, `
cc_library {
@@ -833,7 +946,7 @@
`)
}
-func TestVendorSnapshot(t *testing.T) {
+func TestVendorSnapshotCapture(t *testing.T) {
bp := `
cc_library {
name: "libvndk",
@@ -916,17 +1029,25 @@
filepath.Join(sharedDir, "libvendor_available.so.json"))
// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
+ // Also cfi variants are captured, except for prebuilts like toolchain_library
staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
+ staticCfiVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static_cfi", archType, archVariant)
staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.cfi.a", staticDir, staticCfiVariant)
checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.cfi.a", staticDir, staticCfiVariant)
checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+ checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.cfi.a", staticDir, staticCfiVariant)
jsonFiles = append(jsonFiles,
filepath.Join(staticDir, "libb.a.json"),
filepath.Join(staticDir, "libvndk.a.json"),
+ filepath.Join(staticDir, "libvndk.cfi.a.json"),
filepath.Join(staticDir, "libvendor.a.json"),
- filepath.Join(staticDir, "libvendor_available.a.json"))
+ filepath.Join(staticDir, "libvendor.cfi.a.json"),
+ filepath.Join(staticDir, "libvendor_available.a.json"),
+ filepath.Join(staticDir, "libvendor_available.cfi.a.json"))
// For binary executables, all vendor:true and vendor_available modules are captured.
if archType == "arm64" {
@@ -958,6 +1079,445 @@
}
}
+func TestVendorSnapshotUse(t *testing.T) {
+ frameworkBp := `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ compile_multilib: "64",
+ }
+
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "64",
+ }
+
+ cc_binary {
+ name: "bin",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "64",
+ }
+`
+
+ vndkBp := `
+ vndk_prebuilt_shared {
+ name: "libvndk",
+ version: "BOARD",
+ target_arch: "arm64",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ arch: {
+ arm64: {
+ srcs: ["libvndk.so"],
+ },
+ },
+ }
+`
+
+ vendorProprietaryBp := `
+ cc_library {
+ name: "libvendor_without_snapshot",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ compile_multilib: "64",
+ }
+
+ cc_library_shared {
+ name: "libclient",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ shared_libs: ["libvndk"],
+ static_libs: ["libvendor", "libvendor_without_snapshot"],
+ compile_multilib: "64",
+ }
+
+ cc_binary {
+ name: "bin_without_snapshot",
+ vendor: true,
+ nocrt: true,
+ no_libcrt: true,
+ stl: "none",
+ system_shared_libs: [],
+ static_libs: ["libvndk"],
+ compile_multilib: "64",
+ }
+
+ vendor_snapshot_static {
+ name: "libvndk",
+ version: "BOARD",
+ target_arch: "arm64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libvndk.a",
+ },
+ },
+ }
+
+ vendor_snapshot_shared {
+ name: "libvendor",
+ version: "BOARD",
+ target_arch: "arm64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libvendor.so",
+ },
+ },
+ }
+
+ vendor_snapshot_static {
+ name: "libvendor",
+ version: "BOARD",
+ target_arch: "arm64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "libvendor.a",
+ },
+ },
+ }
+
+ vendor_snapshot_binary {
+ name: "bin",
+ version: "BOARD",
+ target_arch: "arm64",
+ vendor: true,
+ arch: {
+ arm64: {
+ src: "bin",
+ },
+ },
+ }
+`
+ depsBp := GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "vendor/Android.bp": []byte(vendorProprietaryBp),
+ "vendor/libvndk.a": nil,
+ "vendor/libvendor.a": nil,
+ "vendor/libvendor.so": nil,
+ "vendor/bin": nil,
+ "vndk/Android.bp": []byte(vndkBp),
+ "vndk/libvndk.so": nil,
+ }
+
+ config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := CreateTestContext()
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "vendor/Android.bp", "vndk/Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ sharedVariant := "android_vendor.BOARD_arm64_armv8-a_shared"
+ staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+ binaryVariant := "android_vendor.BOARD_arm64_armv8-a"
+
+ // libclient uses libvndk.vndk.BOARD.arm64, libvendor.vendor_static.BOARD.arm64, libvendor_without_snapshot
+ libclientLdRule := ctx.ModuleForTests("libclient", sharedVariant).Rule("ld")
+ libclientFlags := libclientLdRule.Args["libFlags"]
+
+ for _, input := range [][]string{
+ []string{sharedVariant, "libvndk.vndk.BOARD.arm64"},
+ []string{staticVariant, "libvendor.vendor_static.BOARD.arm64"},
+ []string{staticVariant, "libvendor_without_snapshot"},
+ } {
+ outputPaths := getOutputPaths(ctx, input[0] /* variant */, []string{input[1]} /* module name */)
+ if !strings.Contains(libclientFlags, outputPaths[0].String()) {
+ t.Errorf("libflags for libclient must contain %#v, but was %#v", outputPaths[0], libclientFlags)
+ }
+ }
+
+ // bin_without_snapshot uses libvndk.vendor_static.BOARD.arm64
+ binWithoutSnapshotLdRule := ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Rule("ld")
+ binWithoutSnapshotFlags := binWithoutSnapshotLdRule.Args["libFlags"]
+ libVndkStaticOutputPaths := getOutputPaths(ctx, staticVariant, []string{"libvndk.vendor_static.BOARD.arm64"})
+ if !strings.Contains(binWithoutSnapshotFlags, libVndkStaticOutputPaths[0].String()) {
+ t.Errorf("libflags for bin_without_snapshot must contain %#v, but was %#v",
+ libVndkStaticOutputPaths[0], binWithoutSnapshotFlags)
+ }
+
+ // libvendor.so is installed by libvendor.vendor_shared.BOARD.arm64
+ ctx.ModuleForTests("libvendor.vendor_shared.BOARD.arm64", sharedVariant).Output("libvendor.so")
+
+ // libvendor_without_snapshot.so is installed by libvendor_without_snapshot
+ ctx.ModuleForTests("libvendor_without_snapshot", sharedVariant).Output("libvendor_without_snapshot.so")
+
+ // bin is installed by bin.vendor_binary.BOARD.arm64
+ ctx.ModuleForTests("bin.vendor_binary.BOARD.arm64", binaryVariant).Output("bin")
+
+ // bin_without_snapshot is installed by bin_without_snapshot
+ ctx.ModuleForTests("bin_without_snapshot", binaryVariant).Output("bin_without_snapshot")
+
+ // libvendor and bin don't have vendor.BOARD variant
+ libvendorVariants := ctx.ModuleVariantsForTests("libvendor")
+ if inList(sharedVariant, libvendorVariants) {
+ t.Errorf("libvendor must not have variant %#v, but it does", sharedVariant)
+ }
+
+ binVariants := ctx.ModuleVariantsForTests("bin")
+ if inList(binaryVariant, binVariants) {
+ t.Errorf("bin must not have variant %#v, but it does", sharedVariant)
+ }
+}
+
+func TestVendorSnapshotSanitizer(t *testing.T) {
+ bp := `
+ vendor_snapshot_static {
+ name: "libsnapshot",
+ vendor: true,
+ target_arch: "arm64",
+ version: "BOARD",
+ arch: {
+ arm64: {
+ src: "libsnapshot.a",
+ cfi: {
+ src: "libsnapshot.cfi.a",
+ }
+ },
+ },
+ }
+`
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := testCcWithConfig(t, config)
+
+ // Check non-cfi and cfi variant.
+ staticVariant := "android_vendor.BOARD_arm64_armv8-a_static"
+ staticCfiVariant := "android_vendor.BOARD_arm64_armv8-a_static_cfi"
+
+ staticModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticVariant).Module().(*Module)
+ assertString(t, staticModule.outputFile.Path().Base(), "libsnapshot.a")
+
+ staticCfiModule := ctx.ModuleForTests("libsnapshot.vendor_static.BOARD.arm64", staticCfiVariant).Module().(*Module)
+ assertString(t, staticCfiModule.outputFile.Path().Base(), "libsnapshot.cfi.a")
+}
+
+func assertExcludeFromVendorSnapshotIs(t *testing.T, c *Module, expected bool) {
+ t.Helper()
+ if c.ExcludeFromVendorSnapshot() != expected {
+ t.Errorf("expected %q ExcludeFromVendorSnapshot to be %t", c.String(), expected)
+ }
+}
+
+func TestVendorSnapshotExclude(t *testing.T) {
+
+ // This test verifies that the exclude_from_vendor_snapshot property
+ // makes its way from the Android.bp source file into the module data
+ // structure. It also verifies that modules are correctly included or
+ // excluded in the vendor snapshot based on their path (framework or
+ // vendor) and the exclude_from_vendor_snapshot property.
+
+ frameworkBp := `
+ cc_library_shared {
+ name: "libinclude",
+ srcs: ["src/include.cpp"],
+ vendor_available: true,
+ }
+ cc_library_shared {
+ name: "libexclude",
+ srcs: ["src/exclude.cpp"],
+ vendor: true,
+ exclude_from_vendor_snapshot: true,
+ }
+ `
+
+ vendorProprietaryBp := `
+ cc_library_shared {
+ name: "libvendor",
+ srcs: ["vendor.cpp"],
+ vendor: true,
+ }
+ `
+
+ depsBp := GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/include.cpp": nil,
+ "framework/exclude.cpp": nil,
+ "device/Android.bp": []byte(vendorProprietaryBp),
+ "device/vendor.cpp": nil,
+ }
+
+ config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := CreateTestContext()
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp", "device/Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ // Test an include and exclude framework module.
+ assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", coreVariant).Module().(*Module), false)
+ assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libinclude", vendorVariant).Module().(*Module), false)
+ assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libexclude", vendorVariant).Module().(*Module), true)
+
+ // A vendor module is excluded, but by its path, not the
+ // exclude_from_vendor_snapshot property.
+ assertExcludeFromVendorSnapshotIs(t, ctx.ModuleForTests("libvendor", vendorVariant).Module().(*Module), false)
+
+ // Verify the content of the vendor snapshot.
+
+ snapshotDir := "vendor-snapshot"
+ snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+ snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+ var includeJsonFiles []string
+ var excludeJsonFiles []string
+
+ for _, arch := range [][]string{
+ []string{"arm64", "armv8-a"},
+ []string{"arm", "armv7-a-neon"},
+ } {
+ archType := arch[0]
+ archVariant := arch[1]
+ archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+ sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
+ sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+ // Included modules
+ checkSnapshot(t, ctx, snapshotSingleton, "libinclude", "libinclude.so", sharedDir, sharedVariant)
+ includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libinclude.so.json"))
+
+ // Excluded modules
+ checkSnapshotExclude(t, ctx, snapshotSingleton, "libexclude", "libexclude.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libexclude.so.json"))
+ checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+ excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor.so.json"))
+ }
+
+ // Verify that each json file for an included module has a rule.
+ for _, jsonFile := range includeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+ t.Errorf("include json file %q not found", jsonFile)
+ }
+ }
+
+ // Verify that each json file for an excluded module has no rule.
+ for _, jsonFile := range excludeJsonFiles {
+ if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
+ t.Errorf("exclude json file %q found", jsonFile)
+ }
+ }
+}
+
+func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) {
+
+ // This test verifies that using the exclude_from_vendor_snapshot
+ // property on a module in a vendor proprietary path generates an
+ // error. These modules are already excluded, so we prohibit using the
+ // property in this way, which could add to confusion.
+
+ vendorProprietaryBp := `
+ cc_library_shared {
+ name: "libvendor",
+ srcs: ["vendor.cpp"],
+ vendor: true,
+ exclude_from_vendor_snapshot: true,
+ }
+ `
+
+ depsBp := GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "deps/Android.bp": []byte(depsBp),
+ "device/Android.bp": []byte(vendorProprietaryBp),
+ "device/vendor.cpp": nil,
+ }
+
+ config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := CreateTestContext()
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "device/Android.bp"})
+ android.FailIfErrored(t, errs)
+
+ _, errs = ctx.PrepareBuildActions(config)
+ android.CheckErrorsAgainstExpectations(t, errs, []string{
+ `module "libvendor\{.+,image:vendor.+,arch:arm64_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+ `module "libvendor\{.+,image:vendor.+,arch:arm_.+\}" in vendor proprietary path "device" may not use "exclude_from_vendor_snapshot: true"`,
+ })
+}
+
+func TestVendorSnapshotExcludeWithVendorAvailable(t *testing.T) {
+
+ // This test verifies that using the exclude_from_vendor_snapshot
+ // property on a module that is vendor available generates an error. A
+ // vendor available module must be captured in the vendor snapshot and
+ // must not built from source when building the vendor image against
+ // the vendor snapshot.
+
+ frameworkBp := `
+ cc_library_shared {
+ name: "libinclude",
+ srcs: ["src/include.cpp"],
+ vendor_available: true,
+ exclude_from_vendor_snapshot: true,
+ }
+ `
+
+ depsBp := GatherRequiredDepsForTest(android.Android)
+
+ mockFS := map[string][]byte{
+ "deps/Android.bp": []byte(depsBp),
+ "framework/Android.bp": []byte(frameworkBp),
+ "framework/include.cpp": nil,
+ }
+
+ config := TestConfig(buildDir, android.Android, nil, "", mockFS)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ ctx := CreateTestContext()
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"deps/Android.bp", "framework/Android.bp"})
+ android.FailIfErrored(t, errs)
+
+ _, errs = ctx.PrepareBuildActions(config)
+ android.CheckErrorsAgainstExpectations(t, errs, []string{
+ `module "libinclude\{.+,image:,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+ `module "libinclude\{.+,image:,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+ `module "libinclude\{.+,image:vendor.+,arch:arm64_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+ `module "libinclude\{.+,image:vendor.+,arch:arm_.+\}" may not use both "vendor_available: true" and "exclude_from_vendor_snapshot: true"`,
+ })
+}
+
func TestDoubleLoadableDepError(t *testing.T) {
// Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
@@ -2869,6 +3429,52 @@
}
}
+func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) {
+ bp := `
+ cc_prebuilt_test_library_shared {
+ name: "test_lib",
+ relative_install_path: "foo/bar/baz",
+ srcs: ["srcpath/dontusethispath/baz.so"],
+ }
+
+ cc_test {
+ name: "main_test",
+ data_libs: ["test_lib"],
+ gtest: false,
+ }
+ `
+
+ config := TestConfig(buildDir, android.Android, nil, bp, nil)
+ config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+ config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true)
+
+ ctx := testCcWithConfig(t, config)
+ module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module()
+ testBinary := module.(*Module).linker.(*testBinary)
+ outputFiles, err := module.(android.OutputFileProducer).OutputFiles("")
+ if err != nil {
+ t.Fatalf("Expected cc_test to produce output files, error: %s", err)
+ }
+ if len(outputFiles) != 1 {
+ t.Errorf("expected exactly one output file. output files: [%s]", outputFiles)
+ }
+ if len(testBinary.dataPaths()) != 1 {
+ t.Errorf("expected exactly one test data file. test data files: [%s]", testBinary.dataPaths())
+ }
+
+ outputPath := outputFiles[0].String()
+
+ if !strings.HasSuffix(outputPath, "/main_test") {
+ t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath)
+ }
+ entries := android.AndroidMkEntriesForTest(t, config, "", module)[0]
+ if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") {
+ t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+
+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0])
+ }
+}
+
func TestVersionedStubs(t *testing.T) {
ctx := testCc(t, `
cc_library_shared {
diff --git a/cc/compiler.go b/cc/compiler.go
index 08ce133..c268dec 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -86,6 +86,10 @@
// genrule modules.
Generated_sources []string `android:"arch_variant"`
+ // list of generated sources that should not be used to build the C/C++ module.
+ // This is most useful in the arch/multilib variants to remove non-common files
+ Exclude_generated_sources []string `android:"arch_variant"`
+
// list of generated headers to add to the include path. These are the names
// of genrule modules.
Generated_headers []string `android:"arch_variant"`
@@ -107,6 +111,7 @@
Gnu_extensions *bool
Yacc *YaccProperties
+ Lex *LexProperties
Aidl struct {
// list of directories that will be added to the aidl include paths.
@@ -150,6 +155,10 @@
// List of additional cflags that should be used to build the vendor
// variant of the C/C++ module.
Cflags []string
+
+ // list of generated sources that should not be used to
+ // build the vendor variant of the C/C++ module.
+ Exclude_generated_sources []string
}
Recovery struct {
// list of source files that should only be used in the
@@ -163,6 +172,10 @@
// List of additional cflags that should be used to build the recovery
// variant of the C/C++ module.
Cflags []string
+
+ // list of generated sources that should not be used to
+ // build the recovery variant of the C/C++ module.
+ Exclude_generated_sources []string
}
}
@@ -177,8 +190,14 @@
// Build and link with OpenMP
Openmp *bool `android:"arch_variant"`
+ // Deprecated.
// Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__
Use_apex_name_macro *bool
+
+ // Adds two macros for apex variants in addition to __ANDROID_APEX__
+ // * __ANDROID_APEX_COM_ANDROID_FOO__
+ // * __ANDROID_APEX_NAME__="com.android.foo"
+ UseApexNameMacro bool `blueprint:"mutated"`
}
func NewBaseCompiler() *baseCompiler {
@@ -227,6 +246,7 @@
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps.GeneratedSources = append(deps.GeneratedSources, compiler.Properties.Generated_sources...)
+ deps.GeneratedSources = removeListFromList(deps.GeneratedSources, compiler.Properties.Exclude_generated_sources)
deps.GeneratedHeaders = append(deps.GeneratedHeaders, compiler.Properties.Generated_headers...)
android.ProtoDeps(ctx, &compiler.Proto)
@@ -241,6 +261,10 @@
return deps
}
+func (compiler *baseCompiler) useApexNameMacro() bool {
+ return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro
+}
+
// Return true if the module is in the WarningAllowedProjects.
func warningsAreAllowed(subdir string) bool {
subdir += "/"
@@ -276,6 +300,7 @@
flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
flags.Yacc = compiler.Properties.Yacc
+ flags.Lex = compiler.Properties.Lex
// Include dir cflags
localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
@@ -300,8 +325,7 @@
if !(ctx.useSdk() || ctx.useVndk()) || ctx.Host() {
flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
"${config.CommonGlobalIncludes}",
- tc.IncludeFlags(),
- "${config.CommonNativehelperInclude}")
+ tc.IncludeFlags())
}
if ctx.useSdk() {
@@ -323,10 +347,11 @@
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_RECOVERY__")
}
- if ctx.apexName() != "" {
+ if ctx.apexVariationName() != "" {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__")
- if Bool(compiler.Properties.Use_apex_name_macro) {
- flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexName())+"__")
+ if compiler.useApexNameMacro() {
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__")
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'")
}
if ctx.Device() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion()))
@@ -544,16 +569,22 @@
return false
}
+func (compiler *baseCompiler) uniqueApexVariations() bool {
+ return compiler.useApexNameMacro()
+}
+
+var invalidDefineCharRegex = regexp.MustCompile("[^a-zA-Z0-9_]")
+
// makeDefineString transforms a name of an APEX module into a value to be used as value for C define
// For example, com.android.foo => COM_ANDROID_FOO
func makeDefineString(name string) string {
- return strings.ReplaceAll(strings.ToUpper(name), ".", "_")
+ return invalidDefineCharRegex.ReplaceAllString(strings.ToUpper(name), "_")
}
var gnuToCReplacer = strings.NewReplacer("gnu", "c")
func ndkPathDeps(ctx ModuleContext) android.Paths {
- if ctx.useSdk() {
+ if ctx.Module().(*Module).IsSdkVariant() {
// The NDK sysroot timestamp file depends on all the NDK sysroot files
// (headers and libraries).
return android.Paths{getNdkBaseTimestampFile(ctx)}
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index 7edb0c9..ce4bdfb 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -15,8 +15,6 @@
"arm_device.go",
"arm64_device.go",
"arm64_fuchsia_device.go",
- "mips_device.go",
- "mips64_device.go",
"x86_device.go",
"x86_64_device.go",
"x86_64_fuchsia_device.go",
@@ -25,6 +23,8 @@
"x86_linux_host.go",
"x86_linux_bionic_host.go",
"x86_windows_host.go",
+
+ "arm64_linux_host.go",
],
testSrcs: [
"tidy_test.go",
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 19aedd9..62d8cc8 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -32,15 +32,13 @@
"-march=armv8-a",
},
"armv8-2a": []string{
- "-march=armv8.2a",
+ "-march=armv8.2-a",
},
}
arm64Ldflags = []string{
- "-Wl,-m,aarch64_elf64_le_vec",
"-Wl,--hash-style=gnu",
"-Wl,-z,separate-code",
- "-fuse-ld=gold",
"-Wl,--icf=safe",
}
@@ -94,7 +92,6 @@
pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " "))
pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " "))
- pctx.StaticVariable("Arm64IncludeFlags", bionicHeaders("arm64"))
pctx.StaticVariable("Arm64ClangCflags", strings.Join(ClangFilterUnknownCflags(arm64Cflags), " "))
pctx.StaticVariable("Arm64ClangLdflags", strings.Join(ClangFilterUnknownCflags(arm64Ldflags), " "))
@@ -166,7 +163,7 @@
}
func (t *toolchainArm64) IncludeFlags() string {
- return "${config.Arm64IncludeFlags}"
+ return ""
}
func (t *toolchainArm64) ClangTriple() string {
diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go
new file mode 100644
index 0000000..74642c2
--- /dev/null
+++ b/cc/config/arm64_linux_host.go
@@ -0,0 +1,94 @@
+// Copyright 2020 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 config
+
+import (
+ "android/soong/android"
+ "strings"
+)
+
+var (
+ // This is a host toolchain but flags for device toolchain are required
+ // as the flags are actually for Bionic-based builds.
+ linuxCrossCflags = ClangFilterUnknownCflags(append(deviceGlobalCflags,
+ // clang by default enables PIC when the clang triple is set to *-android.
+ // See toolchain/llvm-project/clang/lib/Driver/ToolChains/CommonArgs.cpp#920.
+ // However, for this host target, we don't set "-android" to avoid __ANDROID__ macro
+ // which stands for "Android device target". Keeping PIC on is required because
+ // many modules we have (e.g. Bionic) assume PIC.
+ "-fpic",
+ ))
+
+ linuxCrossLdflags = ClangFilterUnknownCflags([]string{
+ "-Wl,-z,noexecstack",
+ "-Wl,-z,relro",
+ "-Wl,-z,now",
+ "-Wl,--build-id=md5",
+ "-Wl,--warn-shared-textrel",
+ "-Wl,--fatal-warnings",
+ "-Wl,--hash-style=gnu",
+ "-Wl,--no-undefined-version",
+ })
+)
+
+func init() {
+ pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " "))
+ pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " "))
+}
+
+// toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android
+// target. The overridden methods below show the differences.
+type toolchainLinuxArm64 struct {
+ toolchainArm64
+}
+
+func (toolchainLinuxArm64) ClangTriple() string {
+ // Note the absence of "-android" suffix. The compiler won't define __ANDROID__
+ return "aarch64-linux"
+}
+
+func (toolchainLinuxArm64) ClangCflags() string {
+ // The inherited flags + extra flags
+ return "${config.Arm64ClangCflags} ${config.LinuxBionicArm64Cflags}"
+}
+
+func linuxArm64ToolchainFactory(arch android.Arch) Toolchain {
+ archVariant := "armv8-a" // for host, default to armv8-a
+ toolchainClangCflags := []string{arm64ClangArchVariantCflagsVar[archVariant]}
+
+ // We don't specify CPU architecture for host. Conservatively assume
+ // the host CPU needs the fix
+ extraLdflags := "-Wl,--fix-cortex-a53-843419"
+
+ ret := toolchainLinuxArm64{}
+
+ // add the extra ld and lld flags
+ ret.toolchainArm64.ldflags = strings.Join([]string{
+ "${config.Arm64Ldflags}",
+ "${config.LinuxBionicArm64Ldflags}",
+ extraLdflags,
+ }, " ")
+ ret.toolchainArm64.lldflags = strings.Join([]string{
+ "${config.Arm64Lldflags}",
+ "${config.LinuxBionicArm64Ldflags}",
+ extraLdflags,
+ }, " ")
+ ret.toolchainArm64.toolchainClangCflags = strings.Join(toolchainClangCflags, " ")
+ return &ret
+}
+
+func init() {
+ registerToolchainFactory(android.LinuxBionic, android.Arm64, linuxArm64ToolchainFactory)
+}
diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go
index d37e486..f01c638 100644
--- a/cc/config/arm_device.go
+++ b/cc/config/arm_device.go
@@ -175,7 +175,6 @@
pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " "))
pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " "))
- pctx.StaticVariable("ArmIncludeFlags", bionicHeaders("arm"))
// Clang cflags
pctx.StaticVariable("ArmToolchainClangCflags", strings.Join(ClangFilterUnknownCflags(armToolchainCflags), " "))
@@ -269,7 +268,7 @@
}
func (t *toolchainArm) IncludeFlags() string {
- return "${config.ArmIncludeFlags}"
+ return ""
}
func (t *toolchainArm) ClangTriple() string {
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 2e0b241..7db405c 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -15,6 +15,7 @@
package config
import (
+ "android/soong/android"
"sort"
"strings"
)
@@ -51,7 +52,7 @@
// http://b/153759688
"-fuse-init-array",
- // arm + arm64 + mips + mips64
+ // arm + arm64
"-fgcse-after-reload",
"-frerun-cse-after-loop",
"-frename-registers",
@@ -70,11 +71,6 @@
"-fno-tree-copy-prop",
"-fno-tree-loop-optimize",
- // mips + mips64
- "-msynci",
- "-mno-synci",
- "-mno-fused-madd",
-
// x86 + x86_64
"-finline-limit=300",
"-fno-inline-functions-called-once",
@@ -87,14 +83,18 @@
// Ldflags that should be filtered out when linking with clang lld
var ClangUnknownLldflags = sorted([]string{
- "-fuse-ld=gold",
"-Wl,--fix-cortex-a8",
"-Wl,--no-fix-cortex-a8",
- "-Wl,-m,aarch64_elf64_le_vec",
})
var ClangLibToolingUnknownCflags = sorted([]string{})
+// List of tidy checks that should be disabled globally. When the compiler is
+// updated, some checks enabled by this module may be disabled if they have
+// become more strict, or if they are a new match for a wildcard group like
+// `modernize-*`.
+var ClangTidyDisableChecks = []string{}
+
func init() {
pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{
"-D__compiler_offsetof=__builtin_offsetof",
@@ -209,25 +209,34 @@
}
func ClangFilterUnknownCflags(cflags []string) []string {
- ret := make([]string, 0, len(cflags))
- for _, f := range cflags {
- if !inListSorted(f, ClangUnknownCflags) {
- ret = append(ret, f)
+ result, _ := android.FilterList(cflags, ClangUnknownCflags)
+ return result
+}
+
+func clangTidyNegateChecks(checks []string) []string {
+ ret := make([]string, 0, len(checks))
+ for _, c := range checks {
+ if strings.HasPrefix(c, "-") {
+ ret = append(ret, c)
+ } else {
+ ret = append(ret, "-"+c)
}
}
-
return ret
}
-func ClangFilterUnknownLldflags(lldflags []string) []string {
- ret := make([]string, 0, len(lldflags))
- for _, f := range lldflags {
- if !inListSorted(f, ClangUnknownLldflags) {
- ret = append(ret, f)
- }
- }
+func ClangRewriteTidyChecks(checks []string) []string {
+ checks = append(checks, clangTidyNegateChecks(ClangTidyDisableChecks)...)
+ // clang-tidy does not allow later arguments to override earlier arguments,
+ // so if we just disabled an argument that was explicitly enabled we must
+ // remove the enabling argument from the list.
+ result, _ := android.FilterList(checks, ClangTidyDisableChecks)
+ return result
+}
- return ret
+func ClangFilterUnknownLldflags(lldflags []string) []string {
+ result, _ := android.FilterList(lldflags, ClangUnknownLldflags)
+ return result
}
func inListSorted(s string, list []string) bool {
diff --git a/cc/config/global.go b/cc/config/global.go
index 57d8db9..32f163d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -32,6 +32,7 @@
"-Wno-unused",
"-Winit-self",
"-Wpointer-arith",
+ "-Wunreachable-code-loop-increment",
// Make paths in deps files relative
"-no-canonical-prefixes",
@@ -51,6 +52,7 @@
"-Werror=date-time",
"-Werror=pragma-pack",
"-Werror=pragma-pack-suspicious-include",
+ "-Werror=unreachable-code-loop-increment",
}
commonGlobalConlyflags = []string{}
@@ -259,23 +261,15 @@
pctx.VariableFunc("RECXXPool", remoteexec.EnvOverrideFunc("RBE_CXX_POOL", remoteexec.DefaultPool))
pctx.VariableFunc("RECXXLinksPool", remoteexec.EnvOverrideFunc("RBE_CXX_LINKS_POOL", remoteexec.DefaultPool))
+ pctx.VariableFunc("REClangTidyPool", remoteexec.EnvOverrideFunc("RBE_CLANG_TIDY_POOL", remoteexec.DefaultPool))
pctx.VariableFunc("RECXXLinksExecStrategy", remoteexec.EnvOverrideFunc("RBE_CXX_LINKS_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
+ pctx.VariableFunc("REClangTidyExecStrategy", remoteexec.EnvOverrideFunc("RBE_CLANG_TIDY_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
pctx.VariableFunc("REAbiDumperExecStrategy", remoteexec.EnvOverrideFunc("RBE_ABI_DUMPER_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
pctx.VariableFunc("REAbiLinkerExecStrategy", remoteexec.EnvOverrideFunc("RBE_ABI_LINKER_EXEC_STRATEGY", remoteexec.LocalExecStrategy))
}
var HostPrebuiltTag = pctx.VariableConfigMethod("HostPrebuiltTag", android.Config.PrebuiltOS)
-func bionicHeaders(kernelArch string) string {
- return strings.Join([]string{
- "-isystem bionic/libc/include",
- "-isystem bionic/libc/kernel/uapi",
- "-isystem bionic/libc/kernel/uapi/asm-" + kernelArch,
- "-isystem bionic/libc/kernel/android/scsi",
- "-isystem bionic/libc/kernel/android/uapi",
- }, " ")
-}
-
func envOverrideFunc(envVar, defaultVal string) func(ctx android.PackageVarContext) string {
return func(ctx android.PackageVarContext) string {
if override := ctx.Config().Getenv(envVar); override != "" {
diff --git a/cc/config/integer_overflow_blacklist.txt b/cc/config/integer_overflow_blocklist.txt
similarity index 100%
rename from cc/config/integer_overflow_blacklist.txt
rename to cc/config/integer_overflow_blocklist.txt
diff --git a/cc/config/mips64_device.go b/cc/config/mips64_device.go
deleted file mode 100644
index c2af951..0000000
--- a/cc/config/mips64_device.go
+++ /dev/null
@@ -1,147 +0,0 @@
-// Copyright 2015 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 config
-
-import (
- "strings"
-
- "android/soong/android"
-)
-
-var (
- mips64Cflags = []string{
- "-Umips",
-
- // Help catch common 32/64-bit errors.
- "-Werror=implicit-function-declaration",
- }
-
- mips64ClangCflags = append(mips64Cflags, []string{
- "-fintegrated-as",
- }...)
-
- mips64Cppflags = []string{}
-
- mips64Ldflags = []string{
- "-Wl,--allow-shlib-undefined",
- }
-
- mips64ArchVariantCflags = map[string][]string{
- "mips64r2": []string{
- "-mips64r2",
- "-msynci",
- },
- "mips64r6": []string{
- "-mips64r6",
- "-msynci",
- },
- }
-)
-
-const (
- mips64GccVersion = "4.9"
-)
-
-func init() {
- pctx.StaticVariable("mips64GccVersion", mips64GccVersion)
-
- pctx.SourcePathVariable("Mips64GccRoot",
- "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mips64GccVersion}")
-
- pctx.StaticVariable("Mips64IncludeFlags", bionicHeaders("mips"))
-
- // Clang cflags
- pctx.StaticVariable("Mips64ClangCflags", strings.Join(ClangFilterUnknownCflags(mips64ClangCflags), " "))
- pctx.StaticVariable("Mips64ClangLdflags", strings.Join(ClangFilterUnknownCflags(mips64Ldflags), " "))
- pctx.StaticVariable("Mips64ClangCppflags", strings.Join(ClangFilterUnknownCflags(mips64Cppflags), " "))
-
- // Extended cflags
-
- // Architecture variant cflags
- for variant, cflags := range mips64ArchVariantCflags {
- pctx.StaticVariable("Mips64"+variant+"VariantClangCflags",
- strings.Join(ClangFilterUnknownCflags(cflags), " "))
- }
-}
-
-type toolchainMips64 struct {
- toolchain64Bit
- clangCflags string
- toolchainClangCflags string
-}
-
-func (t *toolchainMips64) Name() string {
- return "mips64"
-}
-
-func (t *toolchainMips64) GccRoot() string {
- return "${config.Mips64GccRoot}"
-}
-
-func (t *toolchainMips64) GccTriple() string {
- return "mips64el-linux-android"
-}
-
-func (t *toolchainMips64) GccVersion() string {
- return mips64GccVersion
-}
-
-func (t *toolchainMips64) IncludeFlags() string {
- return "${config.Mips64IncludeFlags}"
-}
-
-func (t *toolchainMips64) ClangTriple() string {
- return t.GccTriple()
-}
-
-func (t *toolchainMips64) ToolchainClangCflags() string {
- return t.toolchainClangCflags
-}
-
-func (t *toolchainMips64) ClangAsflags() string {
- return "-fno-integrated-as"
-}
-
-func (t *toolchainMips64) ClangCflags() string {
- return t.clangCflags
-}
-
-func (t *toolchainMips64) ClangCppflags() string {
- return "${config.Mips64ClangCppflags}"
-}
-
-func (t *toolchainMips64) ClangLdflags() string {
- return "${config.Mips64ClangLdflags}"
-}
-
-func (t *toolchainMips64) ClangLldflags() string {
- // TODO: define and use Mips64ClangLldflags
- return "${config.Mips64ClangLdflags}"
-}
-
-func (toolchainMips64) LibclangRuntimeLibraryArch() string {
- return "mips64"
-}
-
-func mips64ToolchainFactory(arch android.Arch) Toolchain {
- return &toolchainMips64{
- clangCflags: "${config.Mips64ClangCflags}",
- toolchainClangCflags: "${config.Mips64" + arch.ArchVariant + "VariantClangCflags}",
- }
-}
-
-func init() {
- registerToolchainFactory(android.Android, android.Mips64, mips64ToolchainFactory)
-}
diff --git a/cc/config/mips_device.go b/cc/config/mips_device.go
deleted file mode 100644
index ddbc41b..0000000
--- a/cc/config/mips_device.go
+++ /dev/null
@@ -1,186 +0,0 @@
-// Copyright 2015 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 config
-
-import (
- "strings"
-
- "android/soong/android"
-)
-
-var (
- mipsCflags = []string{
- "-fomit-frame-pointer",
- "-Umips",
- }
-
- mipsClangCflags = append(mipsCflags, []string{
- "-fPIC",
- "-fintegrated-as",
- }...)
-
- mipsCppflags = []string{}
-
- mipsLdflags = []string{
- "-Wl,--allow-shlib-undefined",
- }
-
- mipsToolchainLdflags = []string{
- "-Wl,-melf32ltsmip",
- }
-
- mipsArchVariantCflags = map[string][]string{
- "mips32-fp": []string{
- "-mips32",
- "-mfp32",
- "-modd-spreg",
- "-mno-synci",
- },
- "mips32r2-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-msynci",
- },
- "mips32r2-fp-xburst": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mno-fused-madd",
- "-mno-synci",
- },
- "mips32r2dsp-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mdsp",
- "-msynci",
- },
- "mips32r2dspr2-fp": []string{
- "-mips32r2",
- "-mfp32",
- "-modd-spreg",
- "-mdspr2",
- "-msynci",
- },
- "mips32r6": []string{
- "-mips32r6",
- "-mfp64",
- "-mno-odd-spreg",
- "-msynci",
- },
- }
-)
-
-const (
- mipsGccVersion = "4.9"
-)
-
-func init() {
- pctx.StaticVariable("mipsGccVersion", mipsGccVersion)
-
- pctx.SourcePathVariable("MipsGccRoot",
- "prebuilts/gcc/${HostPrebuiltTag}/mips/mips64el-linux-android-${mipsGccVersion}")
-
- pctx.StaticVariable("MipsToolchainLdflags", strings.Join(mipsToolchainLdflags, " "))
- pctx.StaticVariable("MipsIncludeFlags", bionicHeaders("mips"))
-
- // Clang cflags
- pctx.StaticVariable("MipsClangCflags", strings.Join(ClangFilterUnknownCflags(mipsClangCflags), " "))
- pctx.StaticVariable("MipsClangLdflags", strings.Join(ClangFilterUnknownCflags(mipsLdflags), " "))
- pctx.StaticVariable("MipsClangCppflags", strings.Join(ClangFilterUnknownCflags(mipsCppflags), " "))
-
- // Extended cflags
-
- // Architecture variant cflags
- for variant, cflags := range mipsArchVariantCflags {
- pctx.StaticVariable("Mips"+variant+"VariantClangCflags",
- strings.Join(ClangFilterUnknownCflags(cflags), " "))
- }
-}
-
-type toolchainMips struct {
- toolchain32Bit
- clangCflags string
- toolchainClangCflags string
-}
-
-func (t *toolchainMips) Name() string {
- return "mips"
-}
-
-func (t *toolchainMips) GccRoot() string {
- return "${config.MipsGccRoot}"
-}
-
-func (t *toolchainMips) GccTriple() string {
- return "mips64el-linux-android"
-}
-
-func (t *toolchainMips) GccVersion() string {
- return mipsGccVersion
-}
-
-func (t *toolchainMips) IncludeFlags() string {
- return "${config.MipsIncludeFlags}"
-}
-
-func (t *toolchainMips) ClangTriple() string {
- return "mipsel-linux-android"
-}
-
-func (t *toolchainMips) ToolchainClangLdflags() string {
- return "${config.MipsToolchainLdflags}"
-}
-
-func (t *toolchainMips) ToolchainClangCflags() string {
- return t.toolchainClangCflags
-}
-
-func (t *toolchainMips) ClangAsflags() string {
- return "-fPIC -fno-integrated-as"
-}
-
-func (t *toolchainMips) ClangCflags() string {
- return t.clangCflags
-}
-
-func (t *toolchainMips) ClangCppflags() string {
- return "${config.MipsClangCppflags}"
-}
-
-func (t *toolchainMips) ClangLdflags() string {
- return "${config.MipsClangLdflags}"
-}
-
-func (t *toolchainMips) ClangLldflags() string {
- // TODO: define and use MipsClangLldflags
- return "${config.MipsClangLdflags}"
-}
-
-func (toolchainMips) LibclangRuntimeLibraryArch() string {
- return "mips"
-}
-
-func mipsToolchainFactory(arch android.Arch) Toolchain {
- return &toolchainMips{
- clangCflags: "${config.MipsClangCflags}",
- toolchainClangCflags: "${config.Mips" + arch.ArchVariant + "VariantClangCflags}",
- }
-}
-
-func init() {
- registerToolchainFactory(android.Android, android.Mips, mipsToolchainFactory)
-}
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index dd52a0e..4ac9e58 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -30,10 +30,12 @@
}
return strings.Join([]string{
"-*",
+ "bugprone*",
"clang-diagnostic-unused-command-line-argument",
"google*",
"misc-macro-parentheses",
"performance*",
+ "-bugprone-narrowing-conversions",
"-google-readability*",
"-google-runtime-references",
}, ",")
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 6f2e807..578434b 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -23,6 +23,8 @@
"android.hardware.identity-ndk_platform",
"android.hardware.nfc@1.2",
"android.hardware.power-ndk_platform",
+ "android.hardware.powerstats-ndk_platform",
+ "android.hardware.powerstats-unstable-ndk_platform",
"android.hardware.rebootescrow-ndk_platform",
"android.hardware.vibrator-ndk_platform",
"libbinder",
diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go
index bcfae5d..1e25a3b 100644
--- a/cc/config/x86_64_device.go
+++ b/cc/config/x86_64_device.go
@@ -103,7 +103,6 @@
pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " "))
pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Lldflags, " "))
- pctx.StaticVariable("X86_64IncludeFlags", bionicHeaders("x86"))
// Clang cflags
pctx.StaticVariable("X86_64ClangCflags", strings.Join(ClangFilterUnknownCflags(x86_64Cflags), " "))
@@ -145,7 +144,7 @@
}
func (t *toolchainX86_64) IncludeFlags() string {
- return "${config.X86_64IncludeFlags}"
+ return ""
}
func (t *toolchainX86_64) ClangTriple() string {
diff --git a/cc/config/x86_darwin_host.go b/cc/config/x86_darwin_host.go
index 8eb79e3..81c907d 100644
--- a/cc/config/x86_darwin_host.go
+++ b/cc/config/x86_darwin_host.go
@@ -66,6 +66,7 @@
"10.13",
"10.14",
"10.15",
+ "11.0",
}
darwinAvailableLibraries = append(
diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go
index 64392dc..fe83098 100644
--- a/cc/config/x86_device.go
+++ b/cc/config/x86_device.go
@@ -114,7 +114,6 @@
pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " "))
pctx.StaticVariable("X86Lldflags", strings.Join(x86Lldflags, " "))
- pctx.StaticVariable("X86IncludeFlags", bionicHeaders("x86"))
// Clang cflags
pctx.StaticVariable("X86ClangCflags", strings.Join(ClangFilterUnknownCflags(x86ClangCflags), " "))
@@ -156,7 +155,7 @@
}
func (t *toolchainX86) IncludeFlags() string {
- return "${config.X86IncludeFlags}"
+ return ""
}
func (t *toolchainX86) ClangTriple() string {
diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go
index fb1cdeb..fa625e3 100644
--- a/cc/config/x86_linux_bionic_host.go
+++ b/cc/config/x86_linux_bionic_host.go
@@ -70,8 +70,6 @@
pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " "))
pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLldflags, " "))
- pctx.StaticVariable("LinuxBionicIncludeFlags", bionicHeaders("x86"))
-
// Use the device gcc toolchain for now
pctx.StaticVariable("LinuxBionicGccRoot", "${X86_64GccRoot}")
}
@@ -97,7 +95,7 @@
}
func (t *toolchainLinuxBionic) IncludeFlags() string {
- return "${config.LinuxBionicIncludeFlags}"
+ return ""
}
func (t *toolchainLinuxBionic) ClangTriple() string {
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index cd0a508..b5b5553 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -49,7 +49,11 @@
windowsClangCppflags = []string{}
- windowsX86ClangCppflags = []string{}
+ windowsX86ClangCppflags = []string{
+ // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj
+ // exception model for 32-bit.
+ "-fsjlj-exceptions",
+ }
windowsX8664ClangCppflags = []string{}
diff --git a/cc/coverage.go b/cc/coverage.go
index 4431757..aa1fdf6 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -22,6 +22,8 @@
"android/soong/android"
)
+const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
+
type CoverageProperties struct {
Native_coverage *bool
@@ -65,10 +67,10 @@
if cov.Properties.NeedCoverageVariant {
ctx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, coverageDepTag, getGcovProfileLibraryName(ctx))
+ }, CoverageDepTag, getGcovProfileLibraryName(ctx))
ctx.AddVariationDependencies([]blueprint.Variation{
{Mutator: "link", Variation: "static"},
- }, coverageDepTag, getClangProfileLibraryName(ctx))
+ }, CoverageDepTag, getClangProfileLibraryName(ctx))
}
return deps
}
@@ -92,7 +94,7 @@
// flags that the module may use.
flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
} else if clangCoverage {
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-fprofile-instr-generate", "-fcoverage-mapping")
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, "-fcoverage-mapping", "-Wno-pass-failed")
}
}
@@ -103,10 +105,14 @@
// For static libraries, the only thing that changes our object files
// are included whole static libraries, so check to see if any of
// those have coverage enabled.
- ctx.VisitDirectDepsWithTag(wholeStaticDepTag, func(m android.Module) {
- if cc, ok := m.(*Module); ok && cc.coverage != nil {
- if cc.coverage.linkCoverage {
- cov.linkCoverage = true
+ ctx.VisitDirectDeps(func(m android.Module) {
+ if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok {
+ if depTag.static() && depTag.wholeStatic {
+ if cc, ok := m.(*Module); ok && cc.coverage != nil {
+ if cc.coverage.linkCoverage {
+ cov.linkCoverage = true
+ }
+ }
}
}
})
@@ -134,14 +140,14 @@
if gcovCoverage {
flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage")
- coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), coverageDepTag).(*Module)
+ coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module)
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
} else if clangCoverage {
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-fprofile-instr-generate")
+ flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag)
- coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), coverageDepTag).(*Module)
+ coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
}
}
@@ -150,25 +156,30 @@
}
func (cov *coverage) begin(ctx BaseModuleContext) {
+ if ctx.Host() {
+ // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
+ // Just turn off for now.
+ } else {
+ cov.Properties = SetCoverageProperties(ctx, cov.Properties, ctx.nativeCoverage(), ctx.useSdk(), ctx.sdkVersion())
+ }
+}
+
+func SetCoverageProperties(ctx android.BaseModuleContext, properties CoverageProperties, moduleTypeHasCoverage bool,
+ useSdk bool, sdkVersion string) CoverageProperties {
// Coverage is disabled globally
if !ctx.DeviceConfig().NativeCoverageEnabled() {
- return
+ return properties
}
var needCoverageVariant bool
var needCoverageBuild bool
- if ctx.Host() {
- // TODO(dwillemsen): because of -nodefaultlibs, we must depend on libclang_rt.profile-*.a
- // Just turn off for now.
- } else if !ctx.nativeCoverage() {
- // Native coverage is not supported for this module type.
- } else {
+ if moduleTypeHasCoverage {
// Check if Native_coverage is set to false. This property defaults to true.
- needCoverageVariant = BoolDefault(cov.Properties.Native_coverage, true)
- if sdk_version := ctx.sdkVersion(); ctx.useSdk() && sdk_version != "current" {
+ needCoverageVariant = BoolDefault(properties.Native_coverage, true)
+ if useSdk && sdkVersion != "current" {
// Native coverage is not supported for SDK versions < 23
- if fromApi, err := strconv.Atoi(sdk_version); err == nil && fromApi < 23 {
+ if fromApi, err := strconv.Atoi(sdkVersion); err == nil && fromApi < 23 {
needCoverageVariant = false
}
}
@@ -179,8 +190,10 @@
}
}
- cov.Properties.NeedCoverageBuild = needCoverageBuild
- cov.Properties.NeedCoverageVariant = needCoverageVariant
+ properties.NeedCoverageBuild = needCoverageBuild
+ properties.NeedCoverageVariant = needCoverageVariant
+
+ return properties
}
// Coverage is an interface for non-CC modules to implement to be mutated for coverage
@@ -190,6 +203,7 @@
PreventInstall()
HideFromMake()
MarkAsCoverageVariant(bool)
+ EnableCoverageIfNeeded()
}
func coverageMutator(mctx android.BottomUpMutatorContext) {
@@ -212,14 +226,17 @@
m[1].(*Module).coverage.Properties.IsCoverageVariant = true
}
} else if cov, ok := mctx.Module().(Coverage); ok && cov.IsNativeCoverageNeeded(mctx) {
- // APEX modules fall here
+ // APEX and Rust modules fall here
// Note: variant "" is also created because an APEX can be depended on by another
// module which are split into "" and "cov" variants. e.g. when cc_test refers
// to an APEX via 'data' property.
m := mctx.CreateVariations("", "cov")
- m[0].(Coverage).MarkAsCoverageVariant(true)
+ m[0].(Coverage).MarkAsCoverageVariant(false)
m[0].(Coverage).PreventInstall()
m[0].(Coverage).HideFromMake()
+
+ m[1].(Coverage).MarkAsCoverageVariant(true)
+ m[1].(Coverage).EnableCoverageIfNeeded()
}
}
diff --git a/cc/fuzz.go b/cc/fuzz.go
index ee24300..5295418 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -35,6 +35,9 @@
Componentid *int64 `json:"componentid,omitempty"`
// Hotlists in Google's bug tracking system that bugs should be marked with.
Hotlists []string `json:"hotlists,omitempty"`
+ // Specify whether this fuzz target was submitted by a researcher. Defaults
+ // to false.
+ Researcher_submitted *bool `json:"researcher_submitted,omitempty"`
}
func (f *FuzzConfig) String() string {
@@ -126,7 +129,7 @@
func collectAllSharedDependencies(ctx android.SingletonContext, module android.Module) android.Paths {
var fringe []android.Module
- seen := make(map[android.Module]bool)
+ seen := make(map[string]bool)
// Enumerate the first level of dependencies, as we discard all non-library
// modules in the BFS loop below.
@@ -140,15 +143,15 @@
for i := 0; i < len(fringe); i++ {
module := fringe[i]
- if seen[module] {
+ if seen[module.Name()] {
continue
}
- seen[module] = true
+ seen[module.Name()] = true
ccModule := module.(*Module)
sharedLibraries = append(sharedLibraries, ccModule.UnstrippedOutputFile())
ctx.VisitDirectDeps(module, func(dep android.Module) {
- if isValidSharedDependency(dep) && !seen[dep] {
+ if isValidSharedDependency(dep) && !seen[dep.Name()] {
fringe = append(fringe, dep)
}
})
@@ -198,6 +201,11 @@
return installLocation
}
+// Get the device-only shared library symbols install directory.
+func sharedLibrarySymbolsInstallLocation(libraryPath android.Path, archString string) string {
+ return filepath.Join("$(PRODUCT_OUT)/symbols/data/fuzz/", archString, "/lib/", libraryPath.Base())
+}
+
func (fuzz *fuzzBinary) install(ctx ModuleContext, file android.Path) {
fuzz.binaryDecorator.baseInstaller.dir = filepath.Join(
"fuzz", ctx.Target().Arch.ArchType.String(), ctx.ModuleName())
@@ -250,13 +258,13 @@
}
// Grab the list of required shared libraries.
- seen := make(map[android.Module]bool)
+ seen := make(map[string]bool)
var sharedLibraries android.Paths
ctx.WalkDeps(func(child, parent android.Module) bool {
- if seen[child] {
+ if seen[child.Name()] {
return false
}
- seen[child] = true
+ seen[child.Name()] = true
if isValidSharedDependency(child) {
sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
@@ -269,6 +277,12 @@
fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
sharedLibraryInstallLocation(
lib, ctx.Host(), ctx.Arch().ArchType.String()))
+
+ // Also add the dependency on the shared library symbols dir.
+ if !ctx.Host() {
+ fuzz.installedSharedDeps = append(fuzz.installedSharedDeps,
+ sharedLibrarySymbolsInstallLocation(lib, ctx.Arch().ArchType.String()))
+ }
}
}
@@ -355,10 +369,10 @@
return
}
- // Discard vendor-NDK-linked + ramdisk + recovery modules, they're duplicates of
+ // Discard ramdisk + recovery modules, they're duplicates of
// fuzz targets we're going to package anyway.
if !ccModule.Enabled() || ccModule.Properties.PreventInstall ||
- ccModule.UseVndk() || ccModule.InRamdisk() || ccModule.InRecovery() {
+ ccModule.InRamdisk() || ccModule.InRecovery() {
return
}
@@ -367,8 +381,6 @@
return
}
- s.fuzzTargets[module.Name()] = true
-
hostOrTargetString := "target"
if ccModule.Host() {
hostOrTargetString = "host"
@@ -390,7 +402,7 @@
command := builder.Command().BuiltTool(ctx, "soong_zip").
Flag("-j").
FlagWithOutput("-o ", corpusZip)
- command.FlagWithRspFileInputList("-l ", fuzzModule.corpus)
+ command.FlagWithRspFileInputList("-r ", fuzzModule.corpus)
files = append(files, fileToZip{corpusZip, ""})
}
@@ -421,12 +433,24 @@
continue
}
sharedLibraryInstalled[installDestination] = true
+
// Escape all the variables, as the install destination here will be called
// via. $(eval) in Make.
installDestination = strings.ReplaceAll(
installDestination, "$", "$$")
s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
library.String()+":"+installDestination)
+
+ // Ensure that on device, the library is also reinstalled to the /symbols/
+ // dir. Symbolized DSO's are always installed to the device when fuzzing, but
+ // we want symbolization tools (like `stack`) to be able to find the symbols
+ // in $ANDROID_PRODUCT_OUT/symbols automagically.
+ if !ccModule.Host() {
+ symbolsInstallDestination := sharedLibrarySymbolsInstallLocation(library, archString)
+ symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$")
+ s.sharedLibInstallStrings = append(s.sharedLibInstallStrings,
+ library.String()+":"+symbolsInstallDestination)
+ }
}
// The executable.
@@ -458,6 +482,17 @@
builder.Build(pctx, ctx, "create-"+fuzzZip.String(),
"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
+ // Don't add modules to 'make haiku' that are set to not be exported to the
+ // fuzzing infrastructure.
+ if config := fuzzModule.Properties.Fuzz_config; config != nil {
+ if ccModule.Host() && !BoolDefault(config.Fuzz_on_haiku_host, true) {
+ return
+ } else if !BoolDefault(config.Fuzz_on_haiku_device, true) {
+ return
+ }
+ }
+
+ s.fuzzTargets[module.Name()] = true
archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
})
diff --git a/cc/gen.go b/cc/gen.go
index b0aadc6..ccc3d0e 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -34,9 +34,9 @@
var (
lex = pctx.AndroidStaticRule("lex",
blueprint.RuleParams{
- Command: "M4=$m4Cmd $lexCmd -o$out $in",
+ Command: "M4=$m4Cmd $lexCmd $flags -o$out $in",
CommandDeps: []string{"$lexCmd", "$m4Cmd"},
- })
+ }, "flags")
sysprop = pctx.AndroidStaticRule("sysprop",
blueprint.RuleParams{
@@ -153,12 +153,23 @@
}
}
-func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) {
+type LexProperties struct {
+ // list of module-specific flags that will be used for .l and .ll compiles
+ Flags []string
+}
+
+func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) {
+ var flags []string
+ if props != nil {
+ flags = props.Flags
+ }
+ flagsString := strings.Join(flags[:], " ")
ctx.Build(pctx, android.BuildParams{
Rule: lex,
Description: "lex " + lexFile.Rel(),
Output: outFile,
Input: lexFile,
+ Args: map[string]string{"flags": flagsString},
})
}
@@ -235,11 +246,11 @@
case ".l":
cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
srcFiles[i] = cFile
- genLex(ctx, srcFile, cFile)
+ genLex(ctx, srcFile, cFile, buildFlags.lex)
case ".ll":
cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
srcFiles[i] = cppFile
- genLex(ctx, srcFile, cppFile)
+ genLex(ctx, srcFile, cppFile, buildFlags.lex)
case ".proto":
ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
srcFiles[i] = ccFile
diff --git a/cc/genrule.go b/cc/genrule.go
index 66d1784..cce4a83 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -84,7 +84,7 @@
// If not, we assume modules under proprietary paths are compatible for
// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
// PLATFORM_VNDK_VERSION.
- if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) {
+ if vndkVersion == "current" || !isVendorProprietaryModule(ctx) {
variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
} else {
variants = append(variants, VendorVariationPrefix+vndkVersion)
diff --git a/cc/genrule_test.go b/cc/genrule_test.go
index d38cf27..a366f76 100644
--- a/cc/genrule_test.go
+++ b/cc/genrule_test.go
@@ -76,3 +76,42 @@
t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Inputs.Strings())
}
}
+
+func TestLibraryGenruleCmd(t *testing.T) {
+ bp := `
+ cc_library {
+ name: "libboth",
+ }
+
+ cc_library_shared {
+ name: "libshared",
+ }
+
+ cc_library_static {
+ name: "libstatic",
+ }
+
+ cc_genrule {
+ name: "gen",
+ tool_files: ["tool"],
+ srcs: [
+ ":libboth",
+ ":libshared",
+ ":libstatic",
+ ],
+ cmd: "$(location tool) $(in) $(out)",
+ out: ["out"],
+ }
+ `
+ ctx := testCc(t, bp)
+
+ gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out")
+ expected := []string{"libboth.so", "libshared.so", "libstatic.a"}
+ var got []string
+ for _, input := range gen.Inputs {
+ got = append(got, input.Base())
+ }
+ if !reflect.DeepEqual(expected, got) {
+ t.Errorf(`want inputs %v, got %v`, expected, got)
+ }
+}
diff --git a/cc/image.go b/cc/image.go
new file mode 100644
index 0000000..ea6f567
--- /dev/null
+++ b/cc/image.go
@@ -0,0 +1,348 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package cc
+
+// This file contains image variant related things, including image mutator functions, utility
+// functions to determine where a module is installed, etc.
+
+import (
+ "strings"
+
+ "android/soong/android"
+)
+
+var _ android.ImageInterface = (*Module)(nil)
+
+type imageVariantType string
+
+const (
+ coreImageVariant imageVariantType = "core"
+ vendorImageVariant imageVariantType = "vendor"
+ productImageVariant imageVariantType = "product"
+ ramdiskImageVariant imageVariantType = "ramdisk"
+ recoveryImageVariant imageVariantType = "recovery"
+ hostImageVariant imageVariantType = "host"
+)
+
+func (c *Module) getImageVariantType() imageVariantType {
+ if c.Host() {
+ return hostImageVariant
+ } else if c.inVendor() {
+ return vendorImageVariant
+ } else if c.inProduct() {
+ return productImageVariant
+ } else if c.InRamdisk() {
+ return ramdiskImageVariant
+ } else if c.InRecovery() {
+ return recoveryImageVariant
+ } else {
+ return coreImageVariant
+ }
+}
+
+const (
+ // VendorVariationPrefix is the variant prefix used for /vendor code that compiles
+ // against the VNDK.
+ VendorVariationPrefix = "vendor."
+
+ // ProductVariationPrefix is the variant prefix used for /product code that compiles
+ // against the VNDK.
+ ProductVariationPrefix = "product."
+)
+
+func (ctx *moduleContext) ProductSpecific() bool {
+ return ctx.ModuleContext.ProductSpecific() ||
+ (ctx.mod.HasVendorVariant() && ctx.mod.inProduct() && !ctx.mod.IsVndk())
+}
+
+func (ctx *moduleContext) SocSpecific() bool {
+ return ctx.ModuleContext.SocSpecific() ||
+ (ctx.mod.HasVendorVariant() && ctx.mod.inVendor() && !ctx.mod.IsVndk())
+}
+
+func (ctx *moduleContextImpl) inProduct() bool {
+ return ctx.mod.inProduct()
+}
+
+func (ctx *moduleContextImpl) inVendor() bool {
+ return ctx.mod.inVendor()
+}
+
+func (ctx *moduleContextImpl) inRamdisk() bool {
+ return ctx.mod.InRamdisk()
+}
+
+func (ctx *moduleContextImpl) inRecovery() bool {
+ return ctx.mod.InRecovery()
+}
+
+// Returns true only when this module is configured to have core, product and vendor
+// variants.
+func (c *Module) HasVendorVariant() bool {
+ return c.IsVndk() || Bool(c.VendorProperties.Vendor_available)
+}
+
+// Returns true if the module is "product" variant. Usually these modules are installed in /product
+func (c *Module) inProduct() bool {
+ return c.Properties.ImageVariationPrefix == ProductVariationPrefix
+}
+
+// Returns true if the module is "vendor" variant. Usually these modules are installed in /vendor
+func (c *Module) inVendor() bool {
+ return c.Properties.ImageVariationPrefix == VendorVariationPrefix
+}
+
+func (c *Module) InRamdisk() bool {
+ return c.ModuleBase.InRamdisk() || c.ModuleBase.InstallInRamdisk()
+}
+
+func (c *Module) InRecovery() bool {
+ return c.ModuleBase.InRecovery() || c.ModuleBase.InstallInRecovery()
+}
+
+func (c *Module) OnlyInRamdisk() bool {
+ return c.ModuleBase.InstallInRamdisk()
+}
+
+func (c *Module) OnlyInRecovery() bool {
+ return c.ModuleBase.InstallInRecovery()
+}
+
+func (m *Module) ImageMutatorBegin(mctx android.BaseModuleContext) {
+ // Validation check
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+ productSpecific := mctx.ProductSpecific()
+
+ if m.VendorProperties.Vendor_available != nil && vendorSpecific {
+ mctx.PropertyErrorf("vendor_available",
+ "doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
+ }
+
+ if vndkdep := m.vndkdep; vndkdep != nil {
+ if vndkdep.isVndk() {
+ if vendorSpecific || productSpecific {
+ if !vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `extends: \"...\"` to vndk extension")
+ } else if m.VendorProperties.Vendor_available != nil {
+ mctx.PropertyErrorf("vendor_available",
+ "must not set at the same time as `vndk: {extends: \"...\"}`")
+ }
+ } else {
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `vendor: true` or `product_specific: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ }
+ if m.VendorProperties.Vendor_available == nil {
+ mctx.PropertyErrorf("vndk",
+ "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
+ }
+ }
+ } else {
+ if vndkdep.isVndkSp() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `support_system_process: true`")
+ }
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ }
+ }
+ }
+
+ var coreVariantNeeded bool = false
+ var ramdiskVariantNeeded bool = false
+ var recoveryVariantNeeded bool = false
+
+ var vendorVariants []string
+ var productVariants []string
+
+ platformVndkVersion := mctx.DeviceConfig().PlatformVndkVersion()
+ boardVndkVersion := mctx.DeviceConfig().VndkVersion()
+ productVndkVersion := mctx.DeviceConfig().ProductVndkVersion()
+ if boardVndkVersion == "current" {
+ boardVndkVersion = platformVndkVersion
+ }
+ if productVndkVersion == "current" {
+ productVndkVersion = platformVndkVersion
+ }
+
+ if boardVndkVersion == "" {
+ // If the device isn't compiling against the VNDK, we always
+ // use the core mode.
+ coreVariantNeeded = true
+ } else if _, ok := m.linker.(*llndkStubDecorator); ok {
+ // LL-NDK stubs only exist in the vendor and product variants,
+ // since the real libraries will be used in the core variant.
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ boardVndkVersion,
+ )
+ productVariants = append(productVariants,
+ platformVndkVersion,
+ productVndkVersion,
+ )
+ } else if _, ok := m.linker.(*llndkHeadersDecorator); ok {
+ // ... and LL-NDK headers as well
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ boardVndkVersion,
+ )
+ productVariants = append(productVariants,
+ platformVndkVersion,
+ productVndkVersion,
+ )
+ } else if m.isSnapshotPrebuilt() {
+ // Make vendor variants only for the versions in BOARD_VNDK_VERSION and
+ // PRODUCT_EXTRA_VNDK_VERSIONS.
+ if snapshot, ok := m.linker.(interface {
+ version() string
+ }); ok {
+ vendorVariants = append(vendorVariants, snapshot.version())
+ } else {
+ mctx.ModuleErrorf("version is unknown for snapshot prebuilt")
+ }
+ } else if m.HasVendorVariant() && !m.isVndkExt() {
+ // This will be available in /system, /vendor and /product
+ // or a /system directory that is available to vendor and product.
+ coreVariantNeeded = true
+
+ // We assume that modules under proprietary paths are compatible for
+ // BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
+ // PLATFORM_VNDK_VERSION.
+ if isVendorProprietaryModule(mctx) {
+ vendorVariants = append(vendorVariants, boardVndkVersion)
+ } else {
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ }
+
+ // vendor_available modules are also available to /product.
+ productVariants = append(productVariants, platformVndkVersion)
+ // VNDK is always PLATFORM_VNDK_VERSION
+ if !m.IsVndk() {
+ productVariants = append(productVariants, productVndkVersion)
+ }
+ } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
+ // This will be available in /vendor (or /odm) only
+
+ // kernel_headers is a special module type whose exported headers
+ // are coming from DeviceKernelHeaders() which is always vendor
+ // dependent. They'll always have both vendor variants.
+ // For other modules, we assume that modules under proprietary
+ // paths are compatible for BOARD_VNDK_VERSION. The other modules
+ // are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
+ if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+ vendorVariants = append(vendorVariants,
+ platformVndkVersion,
+ boardVndkVersion,
+ )
+ } else if isVendorProprietaryModule(mctx) {
+ vendorVariants = append(vendorVariants, boardVndkVersion)
+ } else {
+ vendorVariants = append(vendorVariants, platformVndkVersion)
+ }
+ } else {
+ // This is either in /system (or similar: /data), or is a
+ // modules built with the NDK. Modules built with the NDK
+ // will be restricted using the existing link type checks.
+ coreVariantNeeded = true
+ }
+
+ if boardVndkVersion != "" && productVndkVersion != "" {
+ if coreVariantNeeded && productSpecific && String(m.Properties.Sdk_version) == "" {
+ // The module has "product_specific: true" that does not create core variant.
+ coreVariantNeeded = false
+ productVariants = append(productVariants, productVndkVersion)
+ }
+ } else {
+ // Unless PRODUCT_PRODUCT_VNDK_VERSION is set, product partition has no
+ // restriction to use system libs.
+ // No product variants defined in this case.
+ productVariants = []string{}
+ }
+
+ if Bool(m.Properties.Ramdisk_available) {
+ ramdiskVariantNeeded = true
+ }
+
+ if m.ModuleBase.InstallInRamdisk() {
+ ramdiskVariantNeeded = true
+ coreVariantNeeded = false
+ }
+
+ if Bool(m.Properties.Recovery_available) {
+ recoveryVariantNeeded = true
+ }
+
+ if m.ModuleBase.InstallInRecovery() {
+ recoveryVariantNeeded = true
+ coreVariantNeeded = false
+ }
+
+ for _, variant := range android.FirstUniqueStrings(vendorVariants) {
+ m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, VendorVariationPrefix+variant)
+ }
+
+ for _, variant := range android.FirstUniqueStrings(productVariants) {
+ m.Properties.ExtraVariants = append(m.Properties.ExtraVariants, ProductVariationPrefix+variant)
+ }
+
+ m.Properties.RamdiskVariantNeeded = ramdiskVariantNeeded
+ m.Properties.RecoveryVariantNeeded = recoveryVariantNeeded
+ m.Properties.CoreVariantNeeded = coreVariantNeeded
+}
+
+func (c *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+ return c.Properties.CoreVariantNeeded
+}
+
+func (c *Module) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return c.Properties.RamdiskVariantNeeded
+}
+
+func (c *Module) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+ return c.Properties.RecoveryVariantNeeded
+}
+
+func (c *Module) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+ return c.Properties.ExtraVariants
+}
+
+func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
+ m := module.(*Module)
+ if variant == android.RamdiskVariation {
+ m.MakeAsPlatform()
+ } else if variant == android.RecoveryVariation {
+ m.MakeAsPlatform()
+ squashRecoverySrcs(m)
+ } else if strings.HasPrefix(variant, VendorVariationPrefix) {
+ m.Properties.ImageVariationPrefix = VendorVariationPrefix
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, VendorVariationPrefix)
+ squashVendorSrcs(m)
+
+ // Makefile shouldn't know vendor modules other than BOARD_VNDK_VERSION.
+ // Hide other vendor variants to avoid collision.
+ vndkVersion := ctx.DeviceConfig().VndkVersion()
+ if vndkVersion != "current" && vndkVersion != "" && vndkVersion != m.Properties.VndkVersion {
+ m.Properties.HideFromMake = true
+ m.SkipInstall()
+ }
+ } else if strings.HasPrefix(variant, ProductVariationPrefix) {
+ m.Properties.ImageVariationPrefix = ProductVariationPrefix
+ m.Properties.VndkVersion = strings.TrimPrefix(variant, ProductVariationPrefix)
+ squashVendorSrcs(m)
+ }
+}
diff --git a/cc/installer.go b/cc/installer.go
index 0b4a68c..e551c63 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -107,6 +107,6 @@
return String(installer.Properties.Relative_install_path)
}
-func (installer *baseInstaller) skipInstall(mod *Module) {
- mod.ModuleBase.SkipInstall()
+func (installer *baseInstaller) makeUninstallable(mod *Module) {
+ mod.ModuleBase.MakeUninstallable()
}
diff --git a/cc/library.go b/cc/library.go
index 24c0629..92853b5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -28,7 +28,6 @@
"android/soong/android"
"android/soong/cc/config"
- "android/soong/genrule"
)
type LibraryProperties struct {
@@ -102,6 +101,10 @@
// Symbol tags that should be ignored from the symbol file
Exclude_symbol_tags []string
+
+ // Run checks on all APIs (in addition to the ones referred by
+ // one of exported ELF symbols.)
+ Check_all_apis *bool
}
// Order symbols in .bss section by their sizes. Only useful for shared libraries.
@@ -333,7 +336,7 @@
tocFile android.OptionalPath
flagExporter
- stripper
+ stripper Stripper
// If we're used as a whole_static_lib, our missing dependencies need
// to be given
@@ -797,21 +800,8 @@
deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, library.StaticProperties.Static.Export_static_lib_headers...)
} else if library.shared() {
if ctx.toolchain().Bionic() && !Bool(library.baseLinker.Properties.Nocrt) {
- if !ctx.useSdk() {
- deps.CrtBegin = "crtbegin_so"
- deps.CrtEnd = "crtend_so"
- } else {
- // TODO(danalbert): Add generation of crt objects.
- // For `sdk_version: "current"`, we don't actually have a
- // freshly generated set of CRT objects. Use the last stable
- // version.
- version := ctx.sdkVersion()
- if version == "current" {
- version = getCurrentNdkPrebuiltVersion(ctx)
- }
- deps.CrtBegin = "ndk_crtbegin_so." + version
- deps.CrtEnd = "ndk_crtend_so." + version
- }
+ deps.CrtBegin = "crtbegin_so"
+ deps.CrtEnd = "crtend_so"
}
deps.WholeStaticLibs = append(deps.WholeStaticLibs, library.SharedProperties.Shared.Whole_static_libs...)
deps.StaticLibs = append(deps.StaticLibs, library.SharedProperties.Shared.Static_libs...)
@@ -895,7 +885,7 @@
}
}
- TransformObjToStaticLib(ctx, library.objects.objFiles, builderFlags, outputFile, objs.tidyFiles)
+ TransformObjToStaticLib(ctx, library.objects.objFiles, deps.WholeStaticLibsFromPrebuilts, builderFlags, outputFile, objs.tidyFiles)
library.coverageOutputFile = TransformCoverageFilesToZip(ctx, library.objects, ctx.ModuleName())
@@ -965,13 +955,14 @@
library.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
- if library.stripper.needsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
+ if library.stripper.NeedsStrip(ctx) {
if ctx.Darwin() {
- builderFlags.stripUseGnuStrip = true
+ stripFlags.StripUseGnuStrip = true
}
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
- library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+ library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
}
library.unstrippedOutputFile = outputFile
@@ -986,10 +977,10 @@
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
library.distFile = versionedOutputFile
- if library.stripper.needsStrip(ctx) {
+ if library.stripper.NeedsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
library.distFile = out
- library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+ library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
}
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -1037,6 +1028,10 @@
return library.unstrippedOutputFile
}
+func (library *libraryDecorator) disableStripping() {
+ library.stripper.StripProperties.Strip.None = BoolPtr(true)
+}
+
func (library *libraryDecorator) nativeCoverage() bool {
if library.header() || library.buildStubs() {
return false
@@ -1073,9 +1068,14 @@
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
if library.shouldCreateSourceAbiDump(ctx) {
- vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
- if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
- vndkVersion = ver
+ var vndkVersion string
+
+ if ctx.useVndk() {
+ // For modules linking against vndk, follow its vndk version
+ vndkVersion = ctx.Module().(*Module).VndkVersion()
+ } else {
+ // Regard the other modules as PLATFORM_VNDK_VERSION
+ vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
}
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1097,7 +1097,9 @@
refAbiDumpFile := getRefAbiDumpFile(ctx, vndkVersion, fileName)
if refAbiDumpFile != nil {
library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
- refAbiDumpFile, fileName, exportedHeaderFlags, ctx.isLlndk(ctx.Config()), ctx.isNdk(), ctx.isVndkExt())
+ refAbiDumpFile, fileName, exportedHeaderFlags,
+ Bool(library.Properties.Header_abi_checker.Check_all_apis),
+ ctx.isLlndk(ctx.Config()), ctx.isNdk(), ctx.isVndkExt())
}
}
}
@@ -1354,16 +1356,15 @@
return android.CheckAvailableForApex(what, list)
}
-func (library *libraryDecorator) skipInstall(mod *Module) {
+func (library *libraryDecorator) makeUninstallable(mod *Module) {
if library.static() && library.buildStatic() && !library.buildStubs() {
- // If we're asked to skip installation of a static library (in particular
- // when it's not //apex_available:platform) we still want an AndroidMk entry
- // for it to ensure we get the relevant NOTICE file targets (cf.
- // notice_files.mk) that other libraries might depend on. AndroidMkEntries
- // always sets LOCAL_UNINSTALLABLE_MODULE for these entries.
+ // If we're asked to make a static library uninstallable we don't do
+ // anything since AndroidMkEntries always sets LOCAL_UNINSTALLABLE_MODULE
+ // for these entries. This is done to still get the make targets for NOTICE
+ // files from notice_files.mk, which other libraries might depend on.
return
}
- mod.ModuleBase.SkipInstall()
+ mod.ModuleBase.MakeUninstallable()
}
var versioningMacroNamesListKey = android.NewOnceKey("versioningMacroNamesList")
@@ -1459,6 +1460,12 @@
static.linker.(prebuiltLibraryInterface).setStatic()
shared.linker.(prebuiltLibraryInterface).setShared()
+ if library.buildShared() {
+ mctx.AliasVariation("shared")
+ } else if library.buildStatic() {
+ mctx.AliasVariation("static")
+ }
+
if !library.buildStatic() {
static.linker.(prebuiltLibraryInterface).disablePrebuilt()
}
@@ -1490,18 +1497,22 @@
if _, ok := library.(*Module); ok {
reuseStaticLibrary(mctx, static.(*Module), shared.(*Module))
}
+ mctx.AliasVariation("shared")
} else if library.BuildStaticVariant() {
variations := append([]string{"static"}, variations...)
modules := mctx.CreateLocalVariations(variations...)
modules[0].(LinkableInterface).SetStatic()
+ mctx.AliasVariation("static")
} else if library.BuildSharedVariant() {
variations := append([]string{"shared"}, variations...)
modules := mctx.CreateLocalVariations(variations...)
modules[0].(LinkableInterface).SetShared()
+ mctx.AliasVariation("shared")
} else if len(variations) > 0 {
mctx.CreateLocalVariations(variations...)
+ mctx.AliasVariation(variations[0])
}
}
}
@@ -1548,13 +1559,14 @@
// "" is for the non-stubs variant
versions = append([]string{""}, versions...)
- modules := mctx.CreateVariations(versions...)
+ modules := mctx.CreateLocalVariations(versions...)
for i, m := range modules {
if versions[i] != "" {
m.(LinkableInterface).SetBuildStubs()
m.(LinkableInterface).SetStubsVersions(versions[i])
}
}
+ mctx.AliasVariation("")
}
func VersionVariantAvailable(module interface {
@@ -1569,7 +1581,8 @@
// (which is unnamed) and zero or more stubs variants.
func VersionMutator(mctx android.BottomUpMutatorContext) {
if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
- if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
+ if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
+ !library.IsSdkVariant() {
versions := library.StubsVersions()
normalizeVersions(mctx, versions)
if mctx.Failed() {
@@ -1588,7 +1601,7 @@
if c, ok := library.(*Module); ok && c.IsStubs() {
stubsVersionsLock.Lock()
defer stubsVersionsLock.Unlock()
- // For LLNDK llndk_library, we borrow vstubs.ersions from its implementation library.
+ // For LLNDK llndk_library, we borrow stubs.versions from its implementation library.
// Since llndk_library has dependency to its implementation library,
// we can safely access stubsVersionsFor() with its baseModuleName.
versions := stubsVersionsFor(mctx.Config())[c.BaseModuleName()]
@@ -1599,17 +1612,10 @@
return
}
- mctx.CreateVariations("")
+ mctx.CreateLocalVariations("")
+ mctx.AliasVariation("")
return
}
- if genrule, ok := mctx.Module().(*genrule.Module); ok {
- if _, ok := genrule.Extra.(*GenruleExtraProperties); ok {
- if VersionVariantAvailable(genrule) {
- mctx.CreateVariations("")
- return
- }
- }
- }
}
// maybeInjectBoringSSLHash adds a rule to run bssl_inject_hash on the output file if the module has the
@@ -1621,8 +1627,7 @@
// TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries.
injectBoringSSLHash := Bool(inject)
ctx.VisitDirectDeps(func(dep android.Module) {
- tag := ctx.OtherModuleDependencyTag(dep)
- if tag == StaticDepTag || tag == staticExportDepTag || tag == wholeStaticDepTag || tag == lateStaticDepTag {
+ if tag, ok := ctx.OtherModuleDependencyTag(dep).(libraryDependencyTag); ok && tag.static() {
if cc, ok := dep.(*Module); ok {
if library, ok := cc.linker.(*libraryDecorator); ok {
if Bool(library.Properties.Inject_bssl_hash) {
diff --git a/cc/library_headers.go b/cc/library_headers.go
index b7ab390..8b3dbeb 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -25,8 +25,9 @@
var headersLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "native_header_libs",
- SupportsSdk: true,
+ PropertyName: "native_header_libs",
+ SupportsSdk: true,
+ HostOsDependent: true,
},
prebuiltModuleType: "cc_prebuilt_library_headers",
noOutputFiles: true,
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a7a1de2..ecfdc99 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -27,8 +27,9 @@
var sharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "native_shared_libs",
- SupportsSdk: true,
+ PropertyName: "native_shared_libs",
+ SupportsSdk: true,
+ HostOsDependent: true,
},
prebuiltModuleType: "cc_prebuilt_library_shared",
linkTypes: []string{"shared"},
@@ -36,8 +37,9 @@
var staticLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "native_static_libs",
- SupportsSdk: true,
+ PropertyName: "native_static_libs",
+ SupportsSdk: true,
+ HostOsDependent: true,
},
prebuiltModuleType: "cc_prebuilt_library_static",
linkTypes: []string{"static"},
@@ -45,8 +47,9 @@
var staticAndSharedLibrarySdkMemberType = &librarySdkMemberType{
SdkMemberTypeBase: android.SdkMemberTypeBase{
- PropertyName: "native_libs",
- SupportsSdk: true,
+ PropertyName: "native_libs",
+ SupportsSdk: true,
+ HostOsDependent: true,
},
prebuiltModuleType: "cc_prebuilt_library",
linkTypes: []string{"static", "shared"},
@@ -79,18 +82,19 @@
if version == "" {
version = LatestStubsVersionFor(mctx.Config(), name)
}
+ variations := target.Variations()
+ if mctx.Device() {
+ variations = append(variations,
+ blueprint.Variation{Mutator: "image", Variation: android.CoreVariation},
+ blueprint.Variation{Mutator: "version", Variation: version})
+ }
if mt.linkTypes == nil {
- mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: android.CoreVariation},
- {Mutator: "version", Variation: version},
- }...), dependencyTag, name)
+ mctx.AddFarVariationDependencies(variations, dependencyTag, name)
} else {
for _, linkType := range mt.linkTypes {
- mctx.AddFarVariationDependencies(append(target.Variations(), []blueprint.Variation{
- {Mutator: "image", Variation: android.CoreVariation},
- {Mutator: "link", Variation: linkType},
- {Mutator: "version", Variation: version},
- }...), dependencyTag, name)
+ libVariations := append(variations,
+ blueprint.Variation{Mutator: "link", Variation: linkType})
+ mctx.AddFarVariationDependencies(libVariations, dependencyTag, name)
}
}
}
@@ -115,6 +119,14 @@
ccModule := member.Variants()[0].(*Module)
+ if proptools.Bool(ccModule.Properties.Recovery_available) {
+ pbm.AddProperty("recovery_available", true)
+ }
+
+ if proptools.Bool(ccModule.VendorProperties.Vendor_available) {
+ pbm.AddProperty("vendor_available", true)
+ }
+
sdkVersion := ccModule.SdkVersion()
if sdkVersion != "" {
pbm.AddProperty("sdk_version", sdkVersion)
@@ -124,6 +136,14 @@
if stl != nil {
pbm.AddProperty("stl", proptools.String(stl))
}
+
+ if lib, ok := ccModule.linker.(*libraryDecorator); ok {
+ uhs := lib.Properties.Unique_host_soname
+ if uhs != nil {
+ pbm.AddProperty("unique_host_soname", proptools.Bool(uhs))
+ }
+ }
+
return pbm
}
@@ -201,6 +221,11 @@
// Add properties that may, or may not, be arch specific.
func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+ if libInfo.SanitizeNever {
+ sanitizeSet := outputProperties.AddPropertySet("sanitize")
+ sanitizeSet.AddProperty("never", true)
+ }
+
// Copy the generated library to the snapshot and add a reference to it in the .bp module.
if libInfo.outputFile != nil {
nativeLibraryPath := nativeLibraryPathFor(libInfo)
@@ -226,7 +251,7 @@
for _, propertyInfo := range includeDirProperties {
// Calculate the base directory in the snapshot into which the files will be copied.
// lib.ArchType is "" for common properties.
- targetDir := filepath.Join(libInfo.archType, propertyInfo.snapshotDir)
+ targetDir := filepath.Join(libInfo.OsPrefix(), libInfo.archType, propertyInfo.snapshotDir)
propertyName := propertyInfo.propertyName
@@ -266,8 +291,8 @@
}
// Add the collated include dir properties to the output.
- for property, dirs := range includeDirs {
- outputProperties.AddProperty(property, dirs)
+ for _, property := range android.SortedStringKeys(includeDirs) {
+ outputProperties.AddProperty(property, includeDirs[property])
}
if len(libInfo.StubsVersion) > 0 {
@@ -348,6 +373,9 @@
// not vary by arch so cannot be android specific.
StubsVersion string `sdk:"ignored-on-host"`
+ // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects.
+ SanitizeNever bool `android:"arch_variant"`
+
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
@@ -372,7 +400,11 @@
// Make sure that the include directories are unique.
p.ExportedIncludeDirs = android.FirstUniquePaths(exportedIncludeDirs)
p.exportedGeneratedIncludeDirs = android.FirstUniquePaths(exportedGeneratedIncludeDirs)
- p.ExportedSystemIncludeDirs = android.FirstUniquePaths(ccModule.ExportedSystemIncludeDirs())
+
+ // Take a copy before filtering out duplicates to avoid changing the slice owned by the
+ // ccModule.
+ dirs := append(android.Paths(nil), ccModule.ExportedSystemIncludeDirs()...)
+ p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs)
p.ExportedFlags = ccModule.ExportedFlags()
if ccModule.linker != nil {
@@ -390,6 +422,10 @@
if ccModule.HasStubsVariants() {
p.StubsVersion = ccModule.StubsVersion()
}
+
+ if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) {
+ p.SanitizeNever = true
+ }
}
func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path {
diff --git a/cc/linkable.go b/cc/linkable.go
index 4a70d48..4c84163 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -1,9 +1,9 @@
package cc
import (
- "github.com/google/blueprint"
-
"android/soong/android"
+
+ "github.com/google/blueprint"
)
type LinkableInterface interface {
@@ -12,6 +12,7 @@
CcLibraryInterface() bool
OutputFile() android.OptionalPath
+ CoverageFiles() android.Paths
IncludeDirs() android.Paths
SetDepsInLinkOrder([]android.Path)
@@ -55,32 +56,23 @@
SdkVersion() string
AlwaysSdk() bool
+ IsSdkVariant() bool
ToolchainLibrary() bool
NdkPrebuiltStl() bool
StubDecorator() bool
}
-type DependencyTag struct {
- blueprint.BaseDependencyTag
- Name string
- Library bool
- Shared bool
+var (
+ CrtBeginDepTag = dependencyTag{name: "crtbegin"}
+ CrtEndDepTag = dependencyTag{name: "crtend"}
+ CoverageDepTag = dependencyTag{name: "coverage"}
+)
- ReexportFlags bool
-
- ExplicitlyVersioned bool
-
- FromStatic bool
+func SharedDepTag() blueprint.DependencyTag {
+ return libraryDependencyTag{Kind: sharedLibraryDependency}
}
-var (
- SharedDepTag = DependencyTag{Name: "shared", Library: true, Shared: true}
- StaticDepTag = DependencyTag{Name: "static", Library: true}
-
- // Same as SharedDepTag, but from a static lib
- SharedFromStaticDepTag = DependencyTag{Name: "shared from static", Library: true, Shared: true, FromStatic: true}
-
- CrtBeginDepTag = DependencyTag{Name: "crtbegin"}
- CrtEndDepTag = DependencyTag{Name: "crtend"}
-)
+func StaticDepTag() blueprint.DependencyTag {
+ return libraryDependencyTag{Kind: staticLibraryDependency}
+}
diff --git a/cc/linker.go b/cc/linker.go
index 0099265..58f8a29 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -298,17 +298,6 @@
}
}
- if inList("libc_scudo", deps.SharedLibs) {
- // libc_scudo is an alternate implementation of all
- // allocation functions (malloc, free), that uses
- // the scudo allocator instead of the default native
- // allocator. If this library is in the list, make
- // sure it's first so it properly overrides the
- // allocation functions of all other shared libraries.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- deps.SharedLibs = append([]string{"libc_scudo"}, deps.SharedLibs...)
- }
-
// If libc and libdl are both in system_shared_libs make sure libdl comes after libc
// to avoid loading libdl before libc.
if inList("libdl", systemSharedLibs) && inList("libc", systemSharedLibs) &&
@@ -454,11 +443,10 @@
}
}
- if ctx.useSdk() && (ctx.Arch().ArchType != android.Mips && ctx.Arch().ArchType != android.Mips64) {
+ if ctx.useSdk() {
// The bionic linker now has support gnu style hashes (which are much faster!), but shipping
// to older devices requires the old style hash. Fortunately, we can build with both and
// it'll work anywhere.
- // This is not currently supported on MIPS architectures.
flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--hash-style=both")
}
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 7ff20f4..b3f9d61 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -179,7 +179,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &llndkStubDecorator{
libraryDecorator: library,
@@ -225,6 +225,8 @@
func llndkHeadersFactory() android.Module {
module, library := NewLibrary(android.DeviceSupported)
library.HeaderOnly()
+ module.stl = nil
+ module.sanitize = nil
decorator := &llndkHeadersDecorator{
libraryDecorator: library,
diff --git a/cc/lto.go b/cc/lto.go
index 4489fc7..9868cdf 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -148,24 +148,31 @@
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
tag := mctx.OtherModuleDependencyTag(dep)
- switch tag {
- case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag, objDepTag, reuseObjTag:
- if dep, ok := dep.(*Module); ok && dep.lto != nil &&
- !dep.lto.Disabled() {
- if full && !Bool(dep.lto.Properties.Lto.Full) {
- dep.lto.Properties.FullDep = true
- }
- if thin && !Bool(dep.lto.Properties.Lto.Thin) {
- dep.lto.Properties.ThinDep = true
- }
- }
-
- // Recursively walk static dependencies
- return true
- }
+ libTag, isLibTag := tag.(libraryDependencyTag)
// Do not recurse down non-static dependencies
- return false
+ if isLibTag {
+ if !libTag.static() {
+ return false
+ }
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
+ }
+ }
+
+ if dep, ok := dep.(*Module); ok && dep.lto != nil &&
+ !dep.lto.Disabled() {
+ if full && !Bool(dep.lto.Properties.Lto.Full) {
+ dep.lto.Properties.FullDep = true
+ }
+ if thin && !Bool(dep.lto.Properties.Lto.Thin) {
+ dep.lto.Properties.ThinDep = true
+ }
+ }
+
+ // Recursively walk static dependencies
+ return true
})
}
}
diff --git a/cc/makevars.go b/cc/makevars.go
index 0f9f4c1..dcfd6d8 100644
--- a/cc/makevars.go
+++ b/cc/makevars.go
@@ -97,7 +97,6 @@
ctx.Strict("CLANG_EXTERNAL_CFLAGS", "${config.ClangExternalCflags}")
ctx.Strict("GLOBAL_CLANG_CFLAGS_NO_OVERRIDE", "${config.NoOverrideClangGlobalCflags}")
ctx.Strict("GLOBAL_CLANG_CPPFLAGS_NO_OVERRIDE", "")
- ctx.Strict("NDK_PREBUILT_SHARED_LIBRARIES", strings.Join(ndkPrebuiltSharedLibs, " "))
ctx.Strict("BOARD_VNDK_VERSION", ctx.DeviceConfig().VndkVersion())
@@ -149,8 +148,6 @@
ctx.Strict("AIDL_CPP", "${aidlCmd}")
ctx.Strict("ALLOWED_MANUAL_INTERFACE_PATHS", strings.Join(allowedManualInterfacePaths, " "))
- ctx.Strict("M4", "${m4Cmd}")
-
ctx.Strict("RS_GLOBAL_INCLUDES", "${config.RsGlobalIncludes}")
ctx.Strict("SOONG_STRIP_PATH", "${stripPath}")
@@ -174,8 +171,8 @@
ctx.StrictRaw("SRC_HEADERS", strings.Join(includes, " "))
ctx.StrictRaw("SRC_SYSTEM_HEADERS", strings.Join(systemIncludes, " "))
- sort.Strings(ndkMigratedLibs)
- ctx.Strict("NDK_MIGRATED_LIBS", strings.Join(ndkMigratedLibs, " "))
+ sort.Strings(ndkKnownLibs)
+ ctx.Strict("NDK_KNOWN_LIBS", strings.Join(ndkKnownLibs, " "))
hostTargets := ctx.Config().Targets[android.BuildOs]
makeVarsToolchain(ctx, "", hostTargets[0])
diff --git a/cc/ndk_api_coverage_parser/.gitignore b/cc/ndk_api_coverage_parser/.gitignore
new file mode 100644
index 0000000..fd94eac
--- /dev/null
+++ b/cc/ndk_api_coverage_parser/.gitignore
@@ -0,0 +1,140 @@
+# From https://github.com/github/gitignore/blob/master/Python.gitignore
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/cc/ndk_api_coverage_parser/Android.bp b/cc/ndk_api_coverage_parser/Android.bp
new file mode 100644
index 0000000..8d9827c
--- /dev/null
+++ b/cc/ndk_api_coverage_parser/Android.bp
@@ -0,0 +1,46 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+python_library_host {
+ name: "ndk_api_coverage_parser_lib",
+ pkg_path: "ndk_api_coverage_parser",
+ srcs: [
+ "__init__.py",
+ ],
+}
+
+python_test_host {
+ name: "test_ndk_api_coverage_parser",
+ main: "test_ndk_api_coverage_parser.py",
+ srcs: [
+ "test_ndk_api_coverage_parser.py",
+ ],
+ libs: [
+ "ndk_api_coverage_parser_lib",
+ "symbolfile",
+ ],
+}
+
+python_binary_host {
+ name: "ndk_api_coverage_parser",
+ main: "__init__.py",
+ srcs: [
+ "__init__.py",
+ ],
+ libs: [
+ "symbolfile",
+ ],
+}
diff --git a/cc/ndk_api_coverage_parser/OWNERS b/cc/ndk_api_coverage_parser/OWNERS
new file mode 100644
index 0000000..a90c48c
--- /dev/null
+++ b/cc/ndk_api_coverage_parser/OWNERS
@@ -0,0 +1 @@
+sophiez@google.com
diff --git a/cc/ndk_api_coverage_parser/__init__.py b/cc/ndk_api_coverage_parser/__init__.py
new file mode 100755
index 0000000..7817c78
--- /dev/null
+++ b/cc/ndk_api_coverage_parser/__init__.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Generates xml of NDK libraries used for API coverage analysis."""
+import argparse
+import json
+import os
+import sys
+
+from xml.etree.ElementTree import Element, SubElement, tostring
+from symbolfile import ALL_ARCHITECTURES, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser
+
+
+ROOT_ELEMENT_TAG = 'ndk-library'
+SYMBOL_ELEMENT_TAG = 'symbol'
+ARCHITECTURE_ATTRIBUTE_KEY = 'arch'
+DEPRECATED_ATTRIBUTE_KEY = 'is_deprecated'
+PLATFORM_ATTRIBUTE_KEY = 'is_platform'
+NAME_ATTRIBUTE_KEY = 'name'
+VARIABLE_TAG = 'var'
+EXPOSED_TARGET_TAGS = (
+ 'vndk',
+ 'apex',
+ 'llndk',
+)
+API_LEVEL_TAG_PREFIXES = (
+ 'introduced=',
+ 'introduced-',
+)
+
+
+def parse_tags(tags):
+ """Parses tags and save needed tags in the created attributes.
+
+ Return attributes dictionary.
+ """
+ attributes = {}
+ arch = []
+ for tag in tags:
+ if tag.startswith(tuple(API_LEVEL_TAG_PREFIXES)):
+ key, _, value = tag.partition('=')
+ attributes.update({key: value})
+ elif tag in ALL_ARCHITECTURES:
+ arch.append(tag)
+ elif tag in EXPOSED_TARGET_TAGS:
+ attributes.update({tag: 'True'})
+ attributes.update({ARCHITECTURE_ATTRIBUTE_KEY: ','.join(arch)})
+ return attributes
+
+
+class XmlGenerator(object):
+ """Output generator that writes parsed symbol file to a xml file."""
+ def __init__(self, output_file):
+ self.output_file = output_file
+
+ def convertToXml(self, versions):
+ """Writes all symbol data to the output file."""
+ root = Element(ROOT_ELEMENT_TAG)
+ for version in versions:
+ if VARIABLE_TAG in version.tags:
+ continue
+ version_attributes = parse_tags(version.tags)
+ _, _, postfix = version.name.partition('_')
+ is_platform = postfix == 'PRIVATE' or postfix == 'PLATFORM'
+ is_deprecated = postfix == 'DEPRECATED'
+ version_attributes.update({PLATFORM_ATTRIBUTE_KEY: str(is_platform)})
+ version_attributes.update({DEPRECATED_ATTRIBUTE_KEY: str(is_deprecated)})
+ for symbol in version.symbols:
+ if VARIABLE_TAG in symbol.tags:
+ continue
+ attributes = {NAME_ATTRIBUTE_KEY: symbol.name}
+ attributes.update(version_attributes)
+ # If same version tags already exist, it will be overwrite here.
+ attributes.update(parse_tags(symbol.tags))
+ SubElement(root, SYMBOL_ELEMENT_TAG, attributes)
+ return root
+
+ def write_xml_to_file(self, root):
+ """Write xml element root to output_file."""
+ parsed_data = tostring(root)
+ output_file = open(self.output_file, "wb")
+ output_file.write(parsed_data)
+
+ def write(self, versions):
+ root = self.convertToXml(versions)
+ self.write_xml_to_file(root)
+
+
+def parse_args():
+ """Parses and returns command line arguments."""
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('symbol_file', type=os.path.realpath, help='Path to symbol file.')
+ parser.add_argument(
+ 'output_file', type=os.path.realpath,
+ help='The output parsed api coverage file.')
+ parser.add_argument(
+ '--api-map', type=os.path.realpath, required=True,
+ help='Path to the API level map JSON file.')
+ return parser.parse_args()
+
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ with open(args.api_map) as map_file:
+ api_map = json.load(map_file)
+
+ with open(args.symbol_file) as symbol_file:
+ try:
+ versions = SymbolFileParser(symbol_file, api_map, "", FUTURE_API_LEVEL,
+ True, True).parse()
+ except MultiplyDefinedSymbolError as ex:
+ sys.exit('{}: error: {}'.format(args.symbol_file, ex))
+
+ generator = XmlGenerator(args.output_file)
+ generator.write(versions)
+
+if __name__ == '__main__':
+ main()
diff --git a/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
new file mode 100644
index 0000000..3ec14c1
--- /dev/null
+++ b/cc/ndk_api_coverage_parser/test_ndk_api_coverage_parser.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for ndk_api_coverage_parser.py."""
+import io
+import textwrap
+import unittest
+
+from xml.etree.ElementTree import fromstring
+from symbolfile import FUTURE_API_LEVEL, SymbolFileParser
+import ndk_api_coverage_parser as nparser
+
+
+# pylint: disable=missing-docstring
+
+
+# https://stackoverflow.com/a/24349916/632035
+def etree_equal(elem1, elem2):
+ """Returns true if the two XML elements are equal.
+
+ xml.etree.ElementTree's comparison operator cares about the ordering of
+ elements and attributes, but they are stored in an unordered dict so the
+ ordering is not deterministic.
+
+ lxml is apparently API compatible with xml and does use an OrderedDict, but
+ we don't have it in the tree.
+ """
+ if elem1.tag != elem2.tag:
+ return False
+ if elem1.text != elem2.text:
+ return False
+ if elem1.tail != elem2.tail:
+ return False
+ if elem1.attrib != elem2.attrib:
+ return False
+ if len(elem1) != len(elem2):
+ return False
+ return all(etree_equal(c1, c2) for c1, c2 in zip(elem1, elem2))
+
+
+class ApiCoverageSymbolFileParserTest(unittest.TestCase):
+ def test_parse(self):
+ input_file = io.StringIO(textwrap.dedent(u"""\
+ LIBLOG { # introduced-arm64=24 introduced-x86=24 introduced-x86_64=24
+ global:
+ android_name_to_log_id; # apex llndk introduced=23
+ android_log_id_to_name; # llndk arm
+ __android_log_assert; # introduced-x86=23
+ __android_log_buf_print; # var
+ __android_log_buf_write;
+ local:
+ *;
+ };
+
+ LIBLOG_PLATFORM {
+ android_fdtrack; # llndk
+ android_net; # introduced=23
+ };
+
+ LIBLOG_FOO { # var
+ android_var;
+ };
+ """))
+ parser = SymbolFileParser(input_file, {}, "", FUTURE_API_LEVEL, True, True)
+ generator = nparser.XmlGenerator(io.StringIO())
+ result = generator.convertToXml(parser.parse())
+ expected = fromstring('<ndk-library><symbol apex="True" arch="" introduced="23" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_name_to_log_id" /><symbol arch="arm" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_log_id_to_name" /><symbol arch="" introduced-arm64="24" introduced-x86="23" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_assert" /><symbol arch="" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_buf_write" /><symbol arch="" is_deprecated="False" is_platform="True" llndk="True" name="android_fdtrack" /><symbol arch="" introduced="23" is_deprecated="False" is_platform="True" name="android_net" /></ndk-library>')
+ self.assertTrue(etree_equal(expected, result))
+
+
+def main():
+ suite = unittest.TestLoader().loadTestsFromName(__name__)
+ unittest.TextTestRunner(verbosity=3).run(suite)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5744bb2..60f931d 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -17,7 +17,6 @@
import (
"fmt"
"path/filepath"
- "strings"
"github.com/google/blueprint"
@@ -131,14 +130,6 @@
m.licensePath = android.PathForModuleSrc(ctx, String(m.properties.License))
- // When generating NDK prebuilts, skip installing MIPS headers,
- // but keep them when doing regular platform build.
- // Ndk_abis property is only set to true with build/soong/scripts/build-ndk-prebuilts.sh
- // TODO: Revert this once MIPS is supported in NDK again.
- if ctx.Config().NdkAbis() && strings.Contains(ctx.ModuleName(), "mips") {
- return
- }
-
srcFiles := android.PathsForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs)
for _, header := range srcFiles {
installDir := getHeaderInstallDir(ctx, header, String(m.properties.From),
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 119ca40..fe3efc0 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -25,49 +25,31 @@
"android/soong/android"
)
-var (
- toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
+func init() {
+ pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
+ pctx.HostBinToolVariable("ndk_api_coverage_parser", "ndk_api_coverage_parser")
+}
+var (
genStubSrc = pctx.AndroidStaticRule("genStubSrc",
blueprint.RuleParams{
- Command: "$toolPath --arch $arch --api $apiLevel --api-map " +
- "$apiMap $flags $in $out",
- CommandDeps: []string{"$toolPath"},
+ Command: "$ndkStubGenerator --arch $arch --api $apiLevel " +
+ "--api-map $apiMap $flags $in $out",
+ CommandDeps: []string{"$ndkStubGenerator"},
}, "arch", "apiLevel", "apiMap", "flags")
+ parseNdkApiRule = pctx.AndroidStaticRule("parseNdkApiRule",
+ blueprint.RuleParams{
+ Command: "$ndk_api_coverage_parser $in $out --api-map $apiMap",
+ CommandDeps: []string{"$ndk_api_coverage_parser"},
+ }, "apiMap")
+
ndkLibrarySuffix = ".ndk"
- ndkPrebuiltSharedLibs = []string{
- "aaudio",
- "amidi",
- "android",
- "binder_ndk",
- "c",
- "camera2ndk",
- "dl",
- "EGL",
- "GLESv1_CM",
- "GLESv2",
- "GLESv3",
- "jnigraphics",
- "log",
- "mediandk",
- "nativewindow",
- "m",
- "neuralnetworks",
- "OpenMAXAL",
- "OpenSLES",
- "stdc++",
- "sync",
- "vulkan",
- "z",
- }
- ndkPrebuiltSharedLibraries = addPrefix(append([]string(nil), ndkPrebuiltSharedLibs...), "lib")
-
- // These libraries have migrated over to the new ndk_library, which is added
- // as a variation dependency via depsMutator.
- ndkMigratedLibs = []string{}
- ndkMigratedLibsLock sync.Mutex // protects ndkMigratedLibs writes during parallel BeginMutator
+ // Added as a variation dependency via depsMutator.
+ ndkKnownLibs = []string{}
+ // protects ndkKnownLibs writes during parallel BeginMutator.
+ ndkKnownLibsLock sync.Mutex
)
// Creates a stub shared library based on the provided version file.
@@ -95,9 +77,9 @@
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
- // Private property for use by the mutator that splits per-API level.
- // can be one of <number:sdk_version> or <codename> or "current"
- // passed to "gen_stub_libs.py" as it is
+ // Private property for use by the mutator that splits per-API level. Can be
+ // one of <number:sdk_version> or <codename> or "current" passed to
+ // "ndkstubgen.py" as it is
ApiLevel string `blueprint:"mutated"`
// True if this API is not yet ready to be shipped in the NDK. It will be
@@ -111,8 +93,9 @@
properties libraryProperties
- versionScriptPath android.ModuleGenPath
- installPath android.Path
+ versionScriptPath android.ModuleGenPath
+ parsedCoverageXmlPath android.ModuleOutPath
+ installPath android.Path
}
// OMG GO
@@ -127,6 +110,10 @@
func normalizeNdkApiLevel(ctx android.BaseModuleContext, apiLevel string,
arch android.Arch) (string, error) {
+ if apiLevel == "" {
+ panic("empty apiLevel not allowed")
+ }
+
if apiLevel == "current" {
return apiLevel, nil
}
@@ -135,8 +122,6 @@
firstArchVersions := map[android.ArchType]int{
android.Arm: minVersion,
android.Arm64: 21,
- android.Mips: minVersion,
- android.Mips64: 21,
android.X86: minVersion,
android.X86_64: 21,
}
@@ -155,7 +140,8 @@
// supported version here instead.
version, err := strconv.Atoi(apiLevel)
if err != nil {
- return "", fmt.Errorf("API level must be an integer (is %q)", apiLevel)
+ // Non-integer API levels are codenames.
+ return apiLevel, nil
}
version = intMax(version, minVersion)
@@ -201,40 +187,61 @@
return version >= unversionedUntil, nil
}
-func generateStubApiVariants(mctx android.BottomUpMutatorContext, c *stubDecorator) {
- platformVersion := mctx.Config().PlatformSdkVersionInt()
+func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module,
+ propName string, propValue string, perSplit func(*Module, string)) {
+ platformVersion := ctx.Config().PlatformSdkVersionInt()
- firstSupportedVersion, err := normalizeNdkApiLevel(mctx, String(c.properties.First_version),
- mctx.Arch())
+ firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue,
+ ctx.Arch())
if err != nil {
- mctx.PropertyErrorf("first_version", err.Error())
+ ctx.PropertyErrorf(propName, err.Error())
}
- firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion, platformVersion)
+ firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion,
+ platformVersion)
if err != nil {
// In theory this is impossible because we've already run this through
// normalizeNdkApiLevel above.
- mctx.PropertyErrorf("first_version", err.Error())
+ ctx.PropertyErrorf(propName, err.Error())
}
var versionStrs []string
for version := firstGenVersion; version <= platformVersion; version++ {
versionStrs = append(versionStrs, strconv.Itoa(version))
}
- versionStrs = append(versionStrs, mctx.Config().PlatformVersionActiveCodenames()...)
+ versionStrs = append(versionStrs, ctx.Config().PlatformVersionActiveCodenames()...)
versionStrs = append(versionStrs, "current")
- modules := mctx.CreateVariations(versionStrs...)
+ modules := ctx.CreateVariations(versionStrs...)
for i, module := range modules {
- module.(*Module).compiler.(*stubDecorator).properties.ApiLevel = versionStrs[i]
+ perSplit(module.(*Module), versionStrs[i])
}
}
-func NdkApiMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok {
+func NdkApiMutator(ctx android.BottomUpMutatorContext) {
+ if m, ok := ctx.Module().(*Module); ok {
if m.Enabled() {
if compiler, ok := m.compiler.(*stubDecorator); ok {
- generateStubApiVariants(mctx, compiler)
+ if ctx.Os() != android.Android {
+ // These modules are always android.DeviceEnabled only, but
+ // those include Fuchsia devices, which we don't support.
+ ctx.Module().Disable()
+ return
+ }
+ generatePerApiVariants(ctx, m, "first_version",
+ String(compiler.properties.First_version),
+ func(m *Module, version string) {
+ m.compiler.(*stubDecorator).properties.ApiLevel =
+ version
+ })
+ } else if m.SplitPerApiLevel() && m.IsSdkVariant() {
+ if ctx.Os() != android.Android {
+ return
+ }
+ generatePerApiVariants(ctx, m, "min_sdk_version",
+ m.MinSdkVersion(), func(m *Module, version string) {
+ m.Properties.Sdk_version = &version
+ })
}
}
}
@@ -248,14 +255,14 @@
ctx.PropertyErrorf("name", "Do not append %q manually, just use the base name", ndkLibrarySuffix)
}
- ndkMigratedLibsLock.Lock()
- defer ndkMigratedLibsLock.Unlock()
- for _, lib := range ndkMigratedLibs {
+ ndkKnownLibsLock.Lock()
+ defer ndkKnownLibsLock.Unlock()
+ for _, lib := range ndkKnownLibs {
if lib == name {
return
}
}
- ndkMigratedLibs = append(ndkMigratedLibs, name)
+ ndkKnownLibs = append(ndkKnownLibs, name)
}
func addStubLibraryCompilerFlags(flags Flags) Flags {
@@ -310,14 +317,36 @@
return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath
}
+func parseSymbolFileForCoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
+ apiLevelsJson := android.GetApiLevelsJson(ctx)
+ symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
+ outputFileName := strings.Split(symbolFilePath.Base(), ".")[0]
+ parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFileName+".xml")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: parseNdkApiRule,
+ Description: "parse ndk api symbol file for api coverage: " + symbolFilePath.Rel(),
+ Outputs: []android.WritablePath{parsedApiCoveragePath},
+ Input: symbolFilePath,
+ Implicits: []android.Path{apiLevelsJson},
+ Args: map[string]string{
+ "apiMap": apiLevelsJson.String(),
+ },
+ })
+ return parsedApiCoveragePath
+}
+
func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
if !strings.HasSuffix(String(c.properties.Symbol_file), ".map.txt") {
ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
}
- objs, versionScript := compileStubLibrary(ctx, flags, String(c.properties.Symbol_file),
+ symbolFile := String(c.properties.Symbol_file)
+ objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
c.properties.ApiLevel, "")
c.versionScriptPath = versionScript
+ if c.properties.ApiLevel == "current" && ctx.PrimaryArch() {
+ c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
+ }
return objs
}
@@ -376,7 +405,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &stubDecorator{
libraryDecorator: library,
@@ -393,8 +422,8 @@
return module
}
-// ndk_library creates a stub library that exposes dummy implementation
-// of functions and variables for use at build time only.
+// ndk_library creates a library that exposes a stub implementation of functions
+// and variables for use at build time only.
func NdkLibraryFactory() android.Module {
module := newStubLibrary()
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth)
diff --git a/cc/ndk_prebuilt.go b/cc/ndk_prebuilt.go
index c4d7708..acdc581 100644
--- a/cc/ndk_prebuilt.go
+++ b/cc/ndk_prebuilt.go
@@ -145,6 +145,7 @@
libraryDecorator: library,
}
module.installer = nil
+ module.Properties.Sdk_version = StringPtr("minimum")
module.Properties.HideFromMake = true
module.Properties.AlwaysSdk = true
module.Properties.Sdk_version = StringPtr("current")
diff --git a/cc/ndkstubgen/.gitignore b/cc/ndkstubgen/.gitignore
new file mode 100644
index 0000000..fd94eac
--- /dev/null
+++ b/cc/ndkstubgen/.gitignore
@@ -0,0 +1,140 @@
+# From https://github.com/github/gitignore/blob/master/Python.gitignore
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/cc/ndkstubgen/Android.bp b/cc/ndkstubgen/Android.bp
new file mode 100644
index 0000000..85dfaee
--- /dev/null
+++ b/cc/ndkstubgen/Android.bp
@@ -0,0 +1,48 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+python_binary_host {
+ name: "ndkstubgen",
+ pkg_path: "ndkstubgen",
+ main: "__init__.py",
+ srcs: [
+ "__init__.py",
+ ],
+ libs: [
+ "symbolfile",
+ ],
+}
+
+python_library_host {
+ name: "ndkstubgenlib",
+ pkg_path: "ndkstubgen",
+ srcs: [
+ "__init__.py",
+ ],
+ libs: [
+ "symbolfile",
+ ],
+}
+
+python_test_host {
+ name: "test_ndkstubgen",
+ srcs: [
+ "test_ndkstubgen.py",
+ ],
+ libs: [
+ "ndkstubgenlib",
+ ],
+}
diff --git a/cc/ndkstubgen/OWNERS b/cc/ndkstubgen/OWNERS
new file mode 100644
index 0000000..f0d8733
--- /dev/null
+++ b/cc/ndkstubgen/OWNERS
@@ -0,0 +1 @@
+danalbert@google.com
diff --git a/cc/ndkstubgen/__init__.py b/cc/ndkstubgen/__init__.py
new file mode 100755
index 0000000..2f4326a
--- /dev/null
+++ b/cc/ndkstubgen/__init__.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Generates source for stub shared libraries for the NDK."""
+import argparse
+import json
+import logging
+import os
+import sys
+
+import symbolfile
+
+
+class Generator:
+ """Output generator that writes stub source files and version scripts."""
+ def __init__(self, src_file, version_script, arch, api, llndk, apex):
+ self.src_file = src_file
+ self.version_script = version_script
+ self.arch = arch
+ self.api = api
+ self.llndk = llndk
+ self.apex = apex
+
+ def write(self, versions):
+ """Writes all symbol data to the output files."""
+ for version in versions:
+ self.write_version(version)
+
+ def write_version(self, version):
+ """Writes a single version block's data to the output files."""
+ if symbolfile.should_omit_version(version, self.arch, self.api,
+ self.llndk, self.apex):
+ return
+
+ section_versioned = symbolfile.symbol_versioned_in_api(
+ version.tags, self.api)
+ version_empty = True
+ pruned_symbols = []
+ for symbol in version.symbols:
+ if symbolfile.should_omit_symbol(symbol, self.arch, self.api,
+ self.llndk, self.apex):
+ continue
+
+ if symbolfile.symbol_versioned_in_api(symbol.tags, self.api):
+ version_empty = False
+ pruned_symbols.append(symbol)
+
+ if len(pruned_symbols) > 0:
+ if not version_empty and section_versioned:
+ self.version_script.write(version.name + ' {\n')
+ self.version_script.write(' global:\n')
+ for symbol in pruned_symbols:
+ emit_version = symbolfile.symbol_versioned_in_api(
+ symbol.tags, self.api)
+ if section_versioned and emit_version:
+ self.version_script.write(' ' + symbol.name + ';\n')
+
+ weak = ''
+ if 'weak' in symbol.tags:
+ weak = '__attribute__((weak)) '
+
+ if 'var' in symbol.tags:
+ self.src_file.write('{}int {} = 0;\n'.format(
+ weak, symbol.name))
+ else:
+ self.src_file.write('{}void {}() {{}}\n'.format(
+ weak, symbol.name))
+
+ if not version_empty and section_versioned:
+ base = '' if version.base is None else ' ' + version.base
+ self.version_script.write('}' + base + ';\n')
+
+
+def parse_args():
+ """Parses and returns command line arguments."""
+ parser = argparse.ArgumentParser()
+
+ parser.add_argument('-v', '--verbose', action='count', default=0)
+
+ parser.add_argument(
+ '--api', required=True, help='API level being targeted.')
+ parser.add_argument(
+ '--arch', choices=symbolfile.ALL_ARCHITECTURES, required=True,
+ help='Architecture being targeted.')
+ parser.add_argument(
+ '--llndk', action='store_true', help='Use the LLNDK variant.')
+ parser.add_argument(
+ '--apex', action='store_true', help='Use the APEX variant.')
+
+ parser.add_argument(
+ '--api-map', type=os.path.realpath, required=True,
+ help='Path to the API level map JSON file.')
+
+ parser.add_argument(
+ 'symbol_file', type=os.path.realpath, help='Path to symbol file.')
+ parser.add_argument(
+ 'stub_src', type=os.path.realpath,
+ help='Path to output stub source file.')
+ parser.add_argument(
+ 'version_script', type=os.path.realpath,
+ help='Path to output version script.')
+
+ return parser.parse_args()
+
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ with open(args.api_map) as map_file:
+ api_map = json.load(map_file)
+ api = symbolfile.decode_api_level(args.api, api_map)
+
+ verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
+ verbosity = args.verbose
+ if verbosity > 2:
+ verbosity = 2
+ logging.basicConfig(level=verbose_map[verbosity])
+
+ with open(args.symbol_file) as symbol_file:
+ try:
+ versions = symbolfile.SymbolFileParser(symbol_file, api_map,
+ args.arch, api, args.llndk,
+ args.apex).parse()
+ except symbolfile.MultiplyDefinedSymbolError as ex:
+ sys.exit('{}: error: {}'.format(args.symbol_file, ex))
+
+ with open(args.stub_src, 'w') as src_file:
+ with open(args.version_script, 'w') as version_file:
+ generator = Generator(src_file, version_file, args.arch, api,
+ args.llndk, args.apex)
+ generator.write(versions)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py
new file mode 100755
index 0000000..70bcf78
--- /dev/null
+++ b/cc/ndkstubgen/test_ndkstubgen.py
@@ -0,0 +1,378 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for ndkstubgen.py."""
+import io
+import textwrap
+import unittest
+
+import ndkstubgen
+import symbolfile
+
+
+# pylint: disable=missing-docstring
+
+
+class GeneratorTest(unittest.TestCase):
+ def test_omit_version(self):
+ # Thorough testing of the cases involved here is handled by
+ # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
+ False, False)
+
+ version = symbolfile.Version('VERSION_PRIVATE', None, [], [
+ symbolfile.Symbol('foo', []),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ version = symbolfile.Version('VERSION', None, ['x86'], [
+ symbolfile.Symbol('foo', []),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ version = symbolfile.Version('VERSION', None, ['introduced=14'], [
+ symbolfile.Symbol('foo', []),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ def test_omit_symbol(self):
+ # Thorough testing of the cases involved here is handled by
+ # SymbolPresenceTest.
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
+ False, False)
+
+ version = symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', ['x86']),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ version = symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', ['introduced=14']),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ version = symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', ['llndk']),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ version = symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', ['apex']),
+ ])
+ generator.write_version(version)
+ self.assertEqual('', src_file.getvalue())
+ self.assertEqual('', version_file.getvalue())
+
+ def test_write(self):
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
+ False, False)
+
+ versions = [
+ symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', []),
+ symbolfile.Symbol('bar', ['var']),
+ symbolfile.Symbol('woodly', ['weak']),
+ symbolfile.Symbol('doodly', ['weak', 'var']),
+ ]),
+ symbolfile.Version('VERSION_2', 'VERSION_1', [], [
+ symbolfile.Symbol('baz', []),
+ ]),
+ symbolfile.Version('VERSION_3', 'VERSION_1', [], [
+ symbolfile.Symbol('qux', ['versioned=14']),
+ ]),
+ ]
+
+ generator.write(versions)
+ expected_src = textwrap.dedent("""\
+ void foo() {}
+ int bar = 0;
+ __attribute__((weak)) void woodly() {}
+ __attribute__((weak)) int doodly = 0;
+ void baz() {}
+ void qux() {}
+ """)
+ self.assertEqual(expected_src, src_file.getvalue())
+
+ expected_version = textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo;
+ bar;
+ woodly;
+ doodly;
+ };
+ VERSION_2 {
+ global:
+ baz;
+ } VERSION_1;
+ """)
+ self.assertEqual(expected_version, version_file.getvalue())
+
+
+class IntegrationTest(unittest.TestCase):
+ def test_integration(self):
+ api_map = {
+ 'O': 9000,
+ 'P': 9001,
+ }
+
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo; # var
+ bar; # x86
+ fizz; # introduced=O
+ buzz; # introduced=P
+ local:
+ *;
+ };
+
+ VERSION_2 { # arm
+ baz; # introduced=9
+ qux; # versioned=14
+ } VERSION_1;
+
+ VERSION_3 { # introduced=14
+ woodly;
+ doodly; # var
+ } VERSION_2;
+
+ VERSION_4 { # versioned=9
+ wibble;
+ wizzes; # llndk
+ waggle; # apex
+ } VERSION_2;
+
+ VERSION_5 { # versioned=14
+ wobble;
+ } VERSION_4;
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9,
+ False, False)
+ versions = parser.parse()
+
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
+ False, False)
+ generator.write(versions)
+
+ expected_src = textwrap.dedent("""\
+ int foo = 0;
+ void baz() {}
+ void qux() {}
+ void wibble() {}
+ void wobble() {}
+ """)
+ self.assertEqual(expected_src, src_file.getvalue())
+
+ expected_version = textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo;
+ };
+ VERSION_2 {
+ global:
+ baz;
+ } VERSION_1;
+ VERSION_4 {
+ global:
+ wibble;
+ } VERSION_2;
+ """)
+ self.assertEqual(expected_version, version_file.getvalue())
+
+ def test_integration_future_api(self):
+ api_map = {
+ 'O': 9000,
+ 'P': 9001,
+ 'Q': 9002,
+ }
+
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo; # introduced=O
+ bar; # introduced=P
+ baz; # introduced=Q
+ local:
+ *;
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9001,
+ False, False)
+ versions = parser.parse()
+
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9001,
+ False, False)
+ generator.write(versions)
+
+ expected_src = textwrap.dedent("""\
+ void foo() {}
+ void bar() {}
+ """)
+ self.assertEqual(expected_src, src_file.getvalue())
+
+ expected_version = textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo;
+ bar;
+ };
+ """)
+ self.assertEqual(expected_version, version_file.getvalue())
+
+ def test_multiple_definition(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo;
+ foo;
+ bar;
+ baz;
+ qux; # arm
+ local:
+ *;
+ };
+
+ VERSION_2 {
+ global:
+ bar;
+ qux; # arm64
+ } VERSION_1;
+
+ VERSION_PRIVATE {
+ global:
+ baz;
+ } VERSION_2;
+
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False,
+ False)
+
+ with self.assertRaises(
+ symbolfile.MultiplyDefinedSymbolError) as ex_context:
+ parser.parse()
+ self.assertEqual(['bar', 'foo'],
+ ex_context.exception.multiply_defined_symbols)
+
+ def test_integration_with_apex(self):
+ api_map = {
+ 'O': 9000,
+ 'P': 9001,
+ }
+
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo; # var
+ bar; # x86
+ fizz; # introduced=O
+ buzz; # introduced=P
+ local:
+ *;
+ };
+
+ VERSION_2 { # arm
+ baz; # introduced=9
+ qux; # versioned=14
+ } VERSION_1;
+
+ VERSION_3 { # introduced=14
+ woodly;
+ doodly; # var
+ } VERSION_2;
+
+ VERSION_4 { # versioned=9
+ wibble;
+ wizzes; # llndk
+ waggle; # apex
+ bubble; # apex llndk
+ duddle; # llndk apex
+ } VERSION_2;
+
+ VERSION_5 { # versioned=14
+ wobble;
+ } VERSION_4;
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, api_map, 'arm', 9,
+ False, True)
+ versions = parser.parse()
+
+ src_file = io.StringIO()
+ version_file = io.StringIO()
+ generator = ndkstubgen.Generator(src_file, version_file, 'arm', 9,
+ False, True)
+ generator.write(versions)
+
+ expected_src = textwrap.dedent("""\
+ int foo = 0;
+ void baz() {}
+ void qux() {}
+ void wibble() {}
+ void waggle() {}
+ void bubble() {}
+ void duddle() {}
+ void wobble() {}
+ """)
+ self.assertEqual(expected_src, src_file.getvalue())
+
+ expected_version = textwrap.dedent("""\
+ VERSION_1 {
+ global:
+ foo;
+ };
+ VERSION_2 {
+ global:
+ baz;
+ } VERSION_1;
+ VERSION_4 {
+ global:
+ wibble;
+ waggle;
+ bubble;
+ duddle;
+ } VERSION_2;
+ """)
+ self.assertEqual(expected_version, version_file.getvalue())
+
+def main():
+ suite = unittest.TestLoader().loadTestsFromName(__name__)
+ unittest.TextTestRunner(verbosity=3).run(suite)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/cc/object.go b/cc/object.go
index 15a529e..778d131 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -55,6 +55,10 @@
// if set, the path to a linker script to pass to ld -r when combining multiple object files.
Linker_script *string `android:"path,arch_variant"`
+
+ // Indicates that this module is a CRT object. CRT objects will be split
+ // into a variant per-API level between min_sdk_version and current.
+ Crt *bool
}
func newObject() *Module {
@@ -162,3 +166,7 @@
func (object *objectLinker) object() bool {
return true
}
+
+func (object *objectLinker) isCrt() bool {
+ return Bool(object.Properties.Crt)
+}
diff --git a/cc/pgo.go b/cc/pgo.go
index 88903bb..6bf0ad0 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -34,7 +34,7 @@
globalPgoProfileProjects = []string{
"toolchain/pgo-profiles",
- "vendor/google_data/pgo-profiles",
+ "vendor/google_data/pgo_profile",
}
)
@@ -199,8 +199,8 @@
return false
}
- // If at least one property exists, validate that all properties exist
- if !profileKindPresent || !filePresent || !benchmarksPresent {
+ // profileKindPresent and filePresent are mandatory properties.
+ if !profileKindPresent || !filePresent {
var missing []string
if !profileKindPresent {
missing = append(missing, "profile kind (either \"instrumentation\" or \"sampling\" property)")
@@ -208,13 +208,15 @@
if !filePresent {
missing = append(missing, "profile_file property")
}
- if !benchmarksPresent {
- missing = append(missing, "non-empty benchmarks property")
- }
missingProps := strings.Join(missing, ", ")
ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps)
}
+ // Benchmark property is mandatory for instrumentation PGO.
+ if isInstrumentation && !benchmarksPresent {
+ ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property")
+ }
+
if isSampling && isInstrumentation {
ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set")
}
@@ -288,15 +290,16 @@
// Add flags to profile this module based on its profile_kind
if props.ShouldProfileModule && props.isInstrumentation() {
+ // Instrumentation PGO use and gather flags cannot coexist.
return props.addInstrumentationProfileGatherFlags(ctx, flags)
} else if props.ShouldProfileModule && props.isSampling() {
- return props.addSamplingProfileGatherFlags(ctx, flags)
+ flags = props.addSamplingProfileGatherFlags(ctx, flags)
} else if ctx.DeviceConfig().SamplingPGO() {
- return props.addSamplingProfileGatherFlags(ctx, flags)
+ flags = props.addSamplingProfileGatherFlags(ctx, flags)
}
if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") {
- return props.addProfileUseFlags(ctx, flags)
+ flags = props.addProfileUseFlags(ctx, flags)
}
return flags
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index b7c0bf2..1ee096e 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -26,6 +26,7 @@
ctx.RegisterModuleType("cc_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_shared", PrebuiltSharedLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_library_static", PrebuiltStaticLibraryFactory)
+ ctx.RegisterModuleType("cc_prebuilt_test_library_shared", PrebuiltSharedTestLibraryFactory)
ctx.RegisterModuleType("cc_prebuilt_object", prebuiltObjectFactory)
ctx.RegisterModuleType("cc_prebuilt_binary", prebuiltBinaryFactory)
}
@@ -43,6 +44,11 @@
// Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined
// symbols, etc), default true.
Check_elf_files *bool
+
+ // Optionally provide an import library if this is a Windows PE DLL prebuilt.
+ // This is needed only if this library is linked by other modules in build time.
+ // Only makes sense for the Windows target.
+ Windows_import_lib *string `android:"path,arch_variant"`
}
type prebuiltLinker struct {
@@ -109,12 +115,20 @@
in := android.PathForModuleSrc(ctx, srcs[0])
+ if p.static() {
+ return in
+ }
+
if p.shared() {
p.unstrippedOutputFile = in
libName := p.libraryDecorator.getLibName(ctx) + flags.Toolchain.ShlibSuffix()
- if p.needsStrip(ctx) {
+ outputFile := android.PathForModuleOut(ctx, libName)
+ var implicits android.Paths
+
+ if p.stripper.NeedsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
stripped := android.PathForModuleOut(ctx, "stripped", libName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
@@ -122,10 +136,41 @@
// depending on a table of contents file instead of the library itself.
tocFile := android.PathForModuleOut(ctx, libName+".toc")
p.tocFile = android.OptionalPathForPath(tocFile)
- TransformSharedObjectToToc(ctx, in, tocFile, builderFlags)
- }
+ TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
- return in
+ if ctx.Windows() && p.properties.Windows_import_lib != nil {
+ // Consumers of this library actually links to the import library in build
+ // time and dynamically links to the DLL in run time. i.e.
+ // a.exe <-- static link --> foo.lib <-- dynamic link --> foo.dll
+ importLibSrc := android.PathForModuleSrc(ctx, String(p.properties.Windows_import_lib))
+ importLibName := p.libraryDecorator.getLibName(ctx) + ".lib"
+ importLibOutputFile := android.PathForModuleOut(ctx, importLibName)
+ implicits = append(implicits, importLibOutputFile)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Description: "prebuilt import library",
+ Input: importLibSrc,
+ Output: importLibOutputFile,
+ Args: map[string]string{
+ "cpFlags": "-L",
+ },
+ })
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Description: "prebuilt shared library",
+ Implicits: implicits,
+ Input: in,
+ Output: outputFile,
+ Args: map[string]string{
+ "cpFlags": "-L",
+ },
+ })
+
+ return outputFile
+ }
}
return nil
@@ -155,10 +200,6 @@
p.properties.Srcs = nil
}
-func (p *prebuiltLibraryLinker) skipInstall(mod *Module) {
- mod.ModuleBase.SkipInstall()
-}
-
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewLibrary(hod)
module.compiler = nil
@@ -167,7 +208,6 @@
libraryDecorator: library,
}
module.linker = prebuilt
- module.installer = prebuilt
module.AddProperties(&prebuilt.properties)
@@ -200,6 +240,16 @@
return module.Init()
}
+// cc_prebuilt_test_library_shared installs a precompiled shared library
+// to be used as a data dependency of a test-related module (such as cc_test, or
+// cc_test_library).
+func PrebuiltSharedTestLibraryFactory() android.Module {
+ module, library := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyShared()
+ library.baseInstaller = NewTestInstaller()
+ return module.Init()
+}
+
func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
module, library := NewPrebuiltLibrary(hod)
library.BuildOnlyShared()
@@ -274,35 +324,68 @@
type prebuiltBinaryLinker struct {
*binaryDecorator
prebuiltLinker
+
+ toolPath android.OptionalPath
}
var _ prebuiltLinkerInterface = (*prebuiltBinaryLinker)(nil)
+func (p *prebuiltBinaryLinker) hostToolPath() android.OptionalPath {
+ return p.toolPath
+}
+
func (p *prebuiltBinaryLinker) link(ctx ModuleContext,
flags Flags, deps PathDeps, objs Objects) android.Path {
// TODO(ccross): verify shared library dependencies
if len(p.properties.Srcs) > 0 {
- builderFlags := flagsToBuilderFlags(flags)
-
fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
in := p.Prebuilt.SingleSourcePath(ctx)
-
+ outputFile := android.PathForModuleOut(ctx, fileName)
p.unstrippedOutputFile = in
- if p.needsStrip(ctx) {
- stripped := android.PathForModuleOut(ctx, "stripped", fileName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
- in = stripped
- }
+ if ctx.Host() {
+ // Host binaries are symlinked to their prebuilt source locations. That
+ // way they are executed directly from there so the linker resolves their
+ // shared library dependencies relative to that location (using
+ // $ORIGIN/../lib(64):$ORIGIN/lib(64) as RUNPATH). This way the prebuilt
+ // repository can supply the expected versions of the shared libraries
+ // without interference from what is in the out tree.
- // Copy binaries to a name matching the final installed name
- outputFile := android.PathForModuleOut(ctx, fileName)
- ctx.Build(pctx, android.BuildParams{
- Rule: android.CpExecutable,
- Description: "prebuilt",
- Output: outputFile,
- Input: in,
- })
+ // These shared lib paths may point to copies of the libs in
+ // .intermediates, which isn't where the binary will load them from, but
+ // it's fine for dependency tracking. If a library dependency is updated,
+ // the symlink will get a new timestamp, along with any installed symlinks
+ // handled in make.
+ sharedLibPaths := deps.EarlySharedLibs
+ sharedLibPaths = append(sharedLibPaths, deps.SharedLibs...)
+ sharedLibPaths = append(sharedLibPaths, deps.LateSharedLibs...)
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Symlink,
+ Output: outputFile,
+ Input: in,
+ Implicits: sharedLibPaths,
+ Args: map[string]string{
+ "fromPath": "$$PWD/" + in.String(),
+ },
+ })
+
+ p.toolPath = android.OptionalPathForPath(outputFile)
+ } else {
+ if p.stripper.NeedsStrip(ctx) {
+ stripped := android.PathForModuleOut(ctx, "stripped", fileName)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, flagsToStripFlags(flags))
+ in = stripped
+ }
+
+ // Copy binaries to a name matching the final installed name
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.CpExecutable,
+ Description: "prebuilt",
+ Output: outputFile,
+ Input: in,
+ })
+ }
return outputFile
}
@@ -329,6 +412,7 @@
binaryDecorator: binary,
}
module.linker = prebuilt
+ module.installer = prebuilt
module.AddProperties(&prebuilt.properties)
diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go
index 242d835..52416ac 100644
--- a/cc/prebuilt_test.go
+++ b/cc/prebuilt_test.go
@@ -15,6 +15,7 @@
package cc
import (
+ "path/filepath"
"testing"
"android/soong/android"
@@ -22,6 +23,25 @@
"github.com/google/blueprint"
)
+func testPrebuilt(t *testing.T, bp string, fs map[string][]byte) *android.TestContext {
+ config := TestConfig(buildDir, android.Android, nil, bp, fs)
+ ctx := CreateTestContext()
+
+ // Enable androidmk support.
+ // * Register the singleton
+ // * Configure that we are inside make
+ // * Add CommonOS to ensure that androidmk processing works.
+ android.RegisterAndroidMkBuildComponents(ctx)
+ android.SetInMakeForTests(config)
+
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+ return ctx
+}
+
func TestPrebuilt(t *testing.T) {
bp := `
cc_library {
@@ -84,7 +104,15 @@
}
`
- ctx := testPrebuilt(t, bp)
+ ctx := testPrebuilt(t, bp, map[string][]byte{
+ "liba.so": nil,
+ "libb.a": nil,
+ "libd.so": nil,
+ "libe.a": nil,
+ "libf.a": nil,
+ "libf.so": nil,
+ "crtx.o": nil,
+ })
// Verify that all the modules exist and that their dependencies were connected correctly
liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module()
@@ -143,35 +171,6 @@
}
}
-func testPrebuilt(t *testing.T, bp string) *android.TestContext {
-
- fs := map[string][]byte{
- "liba.so": nil,
- "libb.a": nil,
- "libd.so": nil,
- "libe.a": nil,
- "libf.a": nil,
- "libf.so": nil,
- "crtx.o": nil,
- }
- config := TestConfig(buildDir, android.Android, nil, bp, fs)
- ctx := CreateTestContext()
-
- // Enable androidmk support.
- // * Register the singleton
- // * Configure that we are inside make
- // * Add CommonOS to ensure that androidmk processing works.
- android.RegisterAndroidMkBuildComponents(ctx)
- android.SetInMakeForTests(config)
-
- ctx.Register(config)
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
- return ctx
-}
-
func TestPrebuiltLibraryShared(t *testing.T) {
ctx := testPrebuilt(t, `
cc_prebuilt_library_shared {
@@ -181,10 +180,12 @@
none: true,
},
}
- `)
+ `, map[string][]byte{
+ "libf.so": nil,
+ })
shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
- assertString(t, shared.OutputFile().String(), "libf.so")
+ assertString(t, shared.OutputFile().Path().Base(), "libtest.so")
}
func TestPrebuiltLibraryStatic(t *testing.T) {
@@ -193,10 +194,12 @@
name: "libtest",
srcs: ["libf.a"],
}
- `)
+ `, map[string][]byte{
+ "libf.a": nil,
+ })
static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
- assertString(t, static.OutputFile().String(), "libf.a")
+ assertString(t, static.OutputFile().Path().Base(), "libf.a")
}
func TestPrebuiltLibrary(t *testing.T) {
@@ -213,11 +216,108 @@
none: true,
},
}
- `)
+ `, map[string][]byte{
+ "libf.a": nil,
+ "libf.so": nil,
+ })
shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module)
- assertString(t, shared.OutputFile().String(), "libf.so")
+ assertString(t, shared.OutputFile().Path().Base(), "libtest.so")
static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module)
- assertString(t, static.OutputFile().String(), "libf.a")
+ assertString(t, static.OutputFile().Path().Base(), "libf.a")
+}
+
+func TestPrebuiltLibraryStem(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library {
+ name: "libfoo",
+ stem: "libbar",
+ static: {
+ srcs: ["libfoo.a"],
+ },
+ shared: {
+ srcs: ["libfoo.so"],
+ },
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libfoo.a": nil,
+ "libfoo.so": nil,
+ })
+
+ static := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module)
+ assertString(t, static.OutputFile().Path().Base(), "libfoo.a")
+
+ shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libbar.so")
+}
+
+func TestPrebuiltLibrarySharedStem(t *testing.T) {
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_shared {
+ name: "libfoo",
+ stem: "libbar",
+ srcs: ["libfoo.so"],
+ strip: {
+ none: true,
+ },
+ }
+ `, map[string][]byte{
+ "libfoo.so": nil,
+ })
+
+ shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module)
+ assertString(t, shared.OutputFile().Path().Base(), "libbar.so")
+}
+
+func TestPrebuiltSymlinkedHostBinary(t *testing.T) {
+ if android.BuildOs != android.Linux {
+ t.Skipf("Skipping host prebuilt testing that is only supported on %s not %s", android.Linux, android.BuildOs)
+ }
+
+ ctx := testPrebuilt(t, `
+ cc_prebuilt_library_shared {
+ name: "libfoo",
+ device_supported: false,
+ host_supported: true,
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc_x86_64/lib64/libfoo.so"],
+ },
+ },
+ }
+
+ cc_prebuilt_binary {
+ name: "foo",
+ device_supported: false,
+ host_supported: true,
+ shared_libs: ["libfoo"],
+ target: {
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc_x86_64/bin/foo"],
+ },
+ },
+ }
+ `, map[string][]byte{
+ "libfoo.so": nil,
+ "foo": nil,
+ })
+
+ fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink")
+ assertString(t, fooRule.Output.String(),
+ filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo"))
+ assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo")
+
+ var libfooDep android.Path
+ for _, dep := range fooRule.Implicits {
+ if dep.Base() == "libfoo.so" {
+ libfooDep = dep
+ break
+ }
+ }
+ assertString(t, libfooDep.String(),
+ filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so"))
}
diff --git a/cc/pylintrc b/cc/pylintrc
index ed49dd7..2032d4e 100644
--- a/cc/pylintrc
+++ b/cc/pylintrc
@@ -1,280 +1,11 @@
-[MASTER]
-
-# Specify a configuration file.
-#rcfile=
-
-# Python code to execute, usually for sys.path manipulation such as
-# pygtk.require().
-#init-hook=
-
-# Profiled execution.
-profile=no
-
-# Add files or directories to the blacklist. They should be base names, not
-# paths.
-ignore=CVS
-
-# Pickle collected data for later comparisons.
-persistent=yes
-
-# List of plugins (as comma separated values of python modules names) to load,
-# usually to register additional checkers.
-load-plugins=
-
-
[MESSAGES CONTROL]
-
-# Enable the message, report, category or checker with the given id(s). You can
-# either give multiple identifier separated by comma (,) or put this option
-# multiple time. See also the "--disable" option for examples.
-#enable=
-
-# Disable the message, report, category or checker with the given id(s). You
-# can either give multiple identifiers separated by comma (,) or put this
-# option multiple times (only on the command line, not in the configuration
-# file where it should appear only once).You can also use "--disable=all" to
-# disable everything first and then reenable specific checks. For example, if
-# you want to run only the similarities checker, you can use "--disable=all
-# --enable=similarities". If you want to run only the classes checker, but have
-# no Warning level messages displayed, use"--disable=all --enable=classes
-# --disable=W"
disable=design,fixme
-
-[REPORTS]
-
-# Set the output format. Available formats are text, parseable, colorized, msvs
-# (visual studio) and html. You can also give a reporter class, eg
-# mypackage.mymodule.MyReporterClass.
-output-format=text
-
-# Put messages in a separate file for each module / package specified on the
-# command line instead of printing them on stdout. Reports (if any) will be
-# written in a file name "pylint_global.[txt|html]".
-files-output=no
-
-# Tells whether to display a full report or only the messages
-reports=yes
-
-# Python expression which should return a note less than 10 (10 is the highest
-# note). You have access to the variables errors warning, statement which
-# respectively contain the number of errors / warnings messages and the total
-# number of statements analyzed. This is used by the global evaluation report
-# (RP0004).
-evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
-
-# Add a comment according to your evaluation note. This is used by the global
-# evaluation report (RP0004).
-comment=no
-
-# Template used to display messages. This is a python new-style format string
-# used to format the message information. See doc for all details
-#msg-template=
-
-
[BASIC]
-
-# Required attributes for module, separated by a comma
-required-attributes=
-
-# List of builtins function names that should not be used, separated by a comma
-bad-functions=map,filter,apply,input
-
-# Regular expression which should only match correct module names
-module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
-
-# Regular expression which should only match correct module level names
-const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
-
-# Regular expression which should only match correct class names
-class-rgx=[A-Z_][a-zA-Z0-9]+$
-
-# Regular expression which should only match correct function names
-function-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct method names
-method-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct instance attribute names
-attr-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct argument names
-argument-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct variable names
-variable-rgx=[a-z_][a-z0-9_]{2,30}$
-
-# Regular expression which should only match correct attribute names in class
-# bodies
-class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
-
-# Regular expression which should only match correct list comprehension /
-# generator expression variable names
-inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
-
-# Good variable names which should always be accepted, separated by a comma
good-names=i,j,k,ex,Run,_
-# Bad variable names which should always be refused, separated by a comma
-bad-names=foo,bar,baz,toto,tutu,tata
-
-# Regular expression which should only match function or class names that do
-# not require a docstring.
-no-docstring-rgx=__.*__
-
-# Minimum line length for functions/classes that require docstrings, shorter
-# ones are exempt.
-docstring-min-length=-1
-
-
-[TYPECHECK]
-
-# Tells whether missing members accessed in mixin class should be ignored. A
-# mixin class is detected if its name ends with "mixin" (case insensitive).
-ignore-mixin-members=yes
-
-# List of classes names for which member attributes should not be checked
-# (useful for classes with attributes dynamically set).
-ignored-classes=SQLObject
-
-# When zope mode is activated, add a predefined set of Zope acquired attributes
-# to generated-members.
-zope=no
-
-# List of members which are set dynamically and missed by pylint inference
-# system, and so shouldn't trigger E0201 when accessed. Python regular
-# expressions are accepted.
-generated-members=REQUEST,acl_users,aq_parent
-
-
-[MISCELLANEOUS]
-
-# List of note tags to take in consideration, separated by a comma.
-notes=FIXME,XXX,TODO
-
-
[SIMILARITIES]
-
-# Minimum lines number of a similarity.
-min-similarity-lines=4
-
-# Ignore comments when computing similarities.
-ignore-comments=yes
-
-# Ignore docstrings when computing similarities.
-ignore-docstrings=yes
-
-# Ignore imports when computing similarities.
-ignore-imports=no
-
+ignore-imports=yes
[VARIABLES]
-
-# Tells whether we should check for unused import in __init__ files.
-init-import=no
-
-# A regular expression matching the beginning of the name of dummy variables
-# (i.e. not used).
dummy-variables-rgx=_|dummy
-
-# List of additional names supposed to be defined in builtins. Remember that
-# you should avoid to define new builtins when possible.
-additional-builtins=
-
-
-[FORMAT]
-
-# Maximum number of characters on a single line.
-max-line-length=80
-
-# Regexp for a line that is allowed to be longer than the limit.
-ignore-long-lines=^\s*(# )?<?https?://\S+>?$
-
-# Allow the body of an if to be on the same line as the test if there is no
-# else.
-single-line-if-stmt=no
-
-# List of optional constructs for which whitespace checking is disabled
-no-space-check=trailing-comma,dict-separator
-
-# Maximum number of lines in a module
-max-module-lines=1000
-
-# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
-# tab).
-indent-string=' '
-
-
-[IMPORTS]
-
-# Deprecated modules which should not be used, separated by a comma
-deprecated-modules=regsub,TERMIOS,Bastion,rexec
-
-# Create a graph of every (i.e. internal and external) dependencies in the
-# given file (report RP0402 must not be disabled)
-import-graph=
-
-# Create a graph of external dependencies in the given file (report RP0402 must
-# not be disabled)
-ext-import-graph=
-
-# Create a graph of internal dependencies in the given file (report RP0402 must
-# not be disabled)
-int-import-graph=
-
-
-[DESIGN]
-
-# Maximum number of arguments for function / method
-max-args=5
-
-# Argument names that match this expression will be ignored. Default to name
-# with leading underscore
-ignored-argument-names=_.*
-
-# Maximum number of locals for function / method body
-max-locals=15
-
-# Maximum number of return / yield for function / method body
-max-returns=6
-
-# Maximum number of branch for function / method body
-max-branches=12
-
-# Maximum number of statements in function / method body
-max-statements=50
-
-# Maximum number of parents for a class (see R0901).
-max-parents=7
-
-# Maximum number of attributes for a class (see R0902).
-max-attributes=7
-
-# Minimum number of public methods for a class (see R0903).
-min-public-methods=2
-
-# Maximum number of public methods for a class (see R0904).
-max-public-methods=20
-
-
-[CLASSES]
-
-# List of interface methods to ignore, separated by a comma. This is used for
-# instance to not check methods defines in Zope's Interface base class.
-ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
-
-# List of method names used to declare (i.e. assign) instance attributes.
-defining-attr-methods=__init__,__new__,setUp
-
-# List of valid names for the first argument in a class method.
-valid-classmethod-first-arg=cls
-
-# List of valid names for the first argument in a metaclass class method.
-valid-metaclass-classmethod-first-arg=mcs
-
-
-[EXCEPTIONS]
-
-# Exceptions that will emit a warning when being caught. Defaults to
-# "Exception"
-overgeneral-exceptions=Exception
diff --git a/cc/rs.go b/cc/rs.go
index 9149e17..ba69f23 100644
--- a/cc/rs.go
+++ b/cc/rs.go
@@ -25,8 +25,8 @@
func init() {
pctx.VariableFunc("rsCmd", func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() {
- // Use RenderScript prebuilts for unbundled builds but not PDK builds
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ // Use RenderScript prebuilts for unbundled builds
return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin/llvm-rs-cc")
} else {
return ctx.Config().HostToolPath(ctx, "llvm-rs-cc").String()
diff --git a/cc/sabi.go b/cc/sabi.go
index 8cef170..ef6bead 100644
--- a/cc/sabi.go
+++ b/cc/sabi.go
@@ -83,10 +83,7 @@
((c.IsVndk() && c.UseVndk()) || c.isLlndk(mctx.Config()) ||
(c.sabi != nil && c.sabi.Properties.CreateSAbiDumps)) {
mctx.VisitDirectDeps(func(m android.Module) {
- tag := mctx.OtherModuleDependencyTag(m)
- switch tag {
- case StaticDepTag, staticExportDepTag, lateStaticDepTag, wholeStaticDepTag:
-
+ if tag, ok := mctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok && tag.static() {
cc, _ := m.(*Module)
if cc == nil {
return
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 463a02a..174dcfe 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -55,17 +55,15 @@
}
cfiCflags = []string{"-flto", "-fsanitize-cfi-cross-dso",
- "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blacklist.txt"}
+ "-fsanitize-blacklist=external/compiler-rt/lib/cfi/cfi_blocklist.txt"}
// -flto and -fvisibility are required by clang when -fsanitize=cfi is
// used, but have no effect on assembly files
cfiAsflags = []string{"-flto", "-fvisibility=default"}
cfiLdflags = []string{"-flto", "-fsanitize-cfi-cross-dso", "-fsanitize=cfi",
"-Wl,-plugin-opt,O1"}
- cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
- cfiStaticLibsMutex sync.Mutex
- hwasanStaticLibsMutex sync.Mutex
+ cfiExportsMapPath = "build/soong/cc/config/cfi_exports.map"
- intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blacklist.txt"}
+ intOverflowCflags = []string{"-fsanitize-blacklist=build/soong/cc/config/integer_overflow_blocklist.txt"}
minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
"-fno-sanitize-recover=integer,undefined"}
@@ -162,6 +160,9 @@
Scudo *bool `android:"arch_variant"`
Scs *bool `android:"arch_variant"`
+ // A modifier for ASAN and HWASAN for write only instrumentation
+ Writeonly *bool `android:"arch_variant"`
+
// Sanitizers to run in the diagnostic mode (as opposed to the release mode).
// Replaces abort() on error with a human-readable error message.
// Address and Thread sanitizers always run in diagnostic mode.
@@ -177,7 +178,7 @@
Recover []string
// value to pass to -fsanitize-blacklist
- Blacklist *string
+ Blocklist *string
} `android:"arch_variant"`
SanitizerEnabled bool `blueprint:"mutated"`
@@ -283,6 +284,15 @@
s.Hwaddress = boolPtr(true)
}
+ if found, globalSanitizers = removeFromList("writeonly", globalSanitizers); found && s.Writeonly == nil {
+ // Hwaddress and Address are set before, so we can check them here
+ // If they aren't explicitly set in the blueprint/SANITIZE_(HOST|TARGET), they would be nil instead of false
+ if s.Address == nil && s.Hwaddress == nil {
+ ctx.ModuleErrorf("writeonly modifier cannot be used without 'address' or 'hwaddress'")
+ }
+ s.Writeonly = boolPtr(true)
+ }
+
if len(globalSanitizers) > 0 {
ctx.ModuleErrorf("unknown global sanitizer option %s", globalSanitizers[0])
}
@@ -311,16 +321,16 @@
}
}
- // CFI needs gold linker, and mips toolchain does not have one.
- if !ctx.Config().EnableCFI() || ctx.Arch().ArchType == android.Mips || ctx.Arch().ArchType == android.Mips64 {
- s.Cfi = nil
- s.Diag.Cfi = nil
+ // Is CFI actually enabled?
+ if !ctx.Config().EnableCFI() {
+ s.Cfi = boolPtr(false)
+ s.Diag.Cfi = boolPtr(false)
}
// Also disable CFI for arm32 until b/35157333 is fixed.
if ctx.Arch().ArchType == android.Arm {
- s.Cfi = nil
- s.Diag.Cfi = nil
+ s.Cfi = boolPtr(false)
+ s.Diag.Cfi = boolPtr(false)
}
// HWASan requires AArch64 hardware feature (top-byte-ignore).
@@ -335,14 +345,14 @@
// Also disable CFI if ASAN is enabled.
if Bool(s.Address) || Bool(s.Hwaddress) {
- s.Cfi = nil
- s.Diag.Cfi = nil
+ s.Cfi = boolPtr(false)
+ s.Diag.Cfi = boolPtr(false)
}
// Disable sanitizers that depend on the UBSan runtime for windows/darwin builds.
if !ctx.Os().Linux() {
- s.Cfi = nil
- s.Diag.Cfi = nil
+ s.Cfi = boolPtr(false)
+ s.Diag.Cfi = boolPtr(false)
s.Misc_undefined = nil
s.Undefined = nil
s.All_undefined = nil
@@ -351,14 +361,15 @@
// Also disable CFI for VNDK variants of components
if ctx.isVndk() && ctx.useVndk() {
- s.Cfi = nil
- s.Diag.Cfi = nil
- }
-
- // Also disable CFI if building against snapshot.
- vndkVersion := ctx.DeviceConfig().VndkVersion()
- if ctx.useVndk() && vndkVersion != "current" && vndkVersion != "" {
- s.Cfi = nil
+ if ctx.static() {
+ // Cfi variant for static vndk should be captured as vendor snapshot,
+ // so don't strictly disable Cfi.
+ s.Cfi = nil
+ s.Diag.Cfi = nil
+ } else {
+ s.Cfi = boolPtr(false)
+ s.Diag.Cfi = boolPtr(false)
+ }
}
// HWASan ramdisk (which is built from recovery) goes over some bootloader limit.
@@ -403,7 +414,7 @@
// TODO(b/131771163): CFI transiently depends on LTO, and thus Fuzzer is
// mutually incompatible.
if Bool(s.Fuzzer) {
- s.Cfi = nil
+ s.Cfi = boolPtr(false)
}
}
@@ -412,16 +423,6 @@
return deps
}
- if ctx.Device() {
- if Bool(sanitize.Properties.Sanitize.Address) {
- // Compiling asan and having libc_scudo in the same
- // executable will cause the executable to crash.
- // Remove libc_scudo since it is only used to override
- // allocation functions which asan already overrides.
- _, deps.SharedLibs = removeFromList("libc_scudo", deps.SharedLibs)
- }
- }
-
return deps
}
@@ -470,6 +471,10 @@
flags.Local.CFlags = append(flags.Local.CFlags, asanCflags...)
flags.Local.LdFlags = append(flags.Local.LdFlags, asanLdflags...)
+ if Bool(sanitize.Properties.Sanitize.Writeonly) {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-asan-instrument-reads=0")
+ }
+
if ctx.Host() {
// -nodefaultlibs (provided with libc++) prevents the driver from linking
// libraries needed with -fsanitize=address. http://b/18650275 (WAI)
@@ -489,6 +494,9 @@
if Bool(sanitize.Properties.Sanitize.Hwaddress) {
flags.Local.CFlags = append(flags.Local.CFlags, hwasanCflags...)
+ if Bool(sanitize.Properties.Sanitize.Writeonly) {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm", "-hwasan-instrument-reads=0")
+ }
}
if Bool(sanitize.Properties.Sanitize.Fuzzer) {
@@ -604,10 +612,10 @@
strings.Join(sanitize.Properties.Sanitize.Diag.No_recover, ","))
}
- blacklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blacklist)
- if blacklist.Valid() {
- flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blacklist.String())
- flags.CFlagsDeps = append(flags.CFlagsDeps, blacklist.Path())
+ blocklist := android.OptionalPathForModuleSrc(ctx, sanitize.Properties.Sanitize.Blocklist)
+ if blocklist.Valid() {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-fsanitize-blacklist="+blocklist.String())
+ flags.CFlagsDeps = append(flags.CFlagsDeps, blocklist.Path())
}
return flags
@@ -720,31 +728,74 @@
}
func isSanitizableDependencyTag(tag blueprint.DependencyTag) bool {
- t, ok := tag.(DependencyTag)
- return ok && t.Library || t == reuseObjTag || t == objDepTag
+ switch t := tag.(type) {
+ case dependencyTag:
+ return t == reuseObjTag || t == objDepTag
+ case libraryDependencyTag:
+ return true
+ default:
+ return false
+ }
+}
+
+// Determines if the current module is a static library going to be captured
+// as vendor snapshot. Such modules must create both cfi and non-cfi variants,
+// except for ones which explicitly disable cfi.
+func needsCfiForVendorSnapshot(mctx android.TopDownMutatorContext) bool {
+ if isVendorProprietaryModule(mctx) {
+ return false
+ }
+
+ c := mctx.Module().(*Module)
+
+ if !c.inVendor() {
+ return false
+ }
+
+ if !c.static() {
+ return false
+ }
+
+ if c.Prebuilt() != nil {
+ return false
+ }
+
+ return c.sanitize != nil &&
+ !Bool(c.sanitize.Properties.Sanitize.Never) &&
+ !c.sanitize.isSanitizerExplicitlyDisabled(cfi)
}
// Propagate sanitizer requirements down from binaries
func sanitizerDepsMutator(t sanitizerType) func(android.TopDownMutatorContext) {
return func(mctx android.TopDownMutatorContext) {
- if c, ok := mctx.Module().(*Module); ok && c.sanitize.isSanitizerEnabled(t) {
- mctx.WalkDeps(func(child, parent android.Module) bool {
- if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
- return false
- }
- if d, ok := child.(*Module); ok && d.sanitize != nil &&
- !Bool(d.sanitize.Properties.Sanitize.Never) &&
- !d.sanitize.isSanitizerExplicitlyDisabled(t) {
- if t == cfi || t == hwasan || t == scs {
- if d.static() {
+ if c, ok := mctx.Module().(*Module); ok {
+ enabled := c.sanitize.isSanitizerEnabled(t)
+ if t == cfi && needsCfiForVendorSnapshot(mctx) {
+ // We shouldn't change the result of isSanitizerEnabled(cfi) to correctly
+ // determine defaultVariation in sanitizerMutator below.
+ // Instead, just mark SanitizeDep to forcefully create cfi variant.
+ enabled = true
+ c.sanitize.Properties.SanitizeDep = true
+ }
+ if enabled {
+ mctx.WalkDeps(func(child, parent android.Module) bool {
+ if !isSanitizableDependencyTag(mctx.OtherModuleDependencyTag(child)) {
+ return false
+ }
+ if d, ok := child.(*Module); ok && d.sanitize != nil &&
+ !Bool(d.sanitize.Properties.Sanitize.Never) &&
+ !d.sanitize.isSanitizerExplicitlyDisabled(t) {
+ if t == cfi || t == hwasan || t == scs {
+ if d.static() {
+ d.sanitize.Properties.SanitizeDep = true
+ }
+ } else {
d.sanitize.Properties.SanitizeDep = true
}
- } else {
- d.sanitize.Properties.SanitizeDep = true
}
- }
- return true
- })
+ return true
+ })
+ }
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok {
// If an APEX module includes a lib which is enabled for a sanitizer T, then
// the APEX module is also enabled for the same sanitizer type.
@@ -963,10 +1014,13 @@
}
// static executable gets static runtime libs
- mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
- {Mutator: "link", Variation: "static"},
- c.ImageVariation(),
- }...), StaticDepTag, deps...)
+ depTag := libraryDependencyTag{Kind: staticLibraryDependency}
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "static"})
+ if c.Device() {
+ variations = append(variations, c.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, deps...)
} else if !c.static() && !c.header() {
// If we're using snapshots and in vendor, redirect to snapshot whenever possible
if c.VndkVersion() == mctx.DeviceConfig().VndkVersion() {
@@ -977,10 +1031,13 @@
}
// dynamic executable and shared libs get shared runtime libs
- mctx.AddFarVariationDependencies(append(mctx.Target().Variations(), []blueprint.Variation{
- {Mutator: "link", Variation: "shared"},
- c.ImageVariation(),
- }...), earlySharedDepTag, runtimeLibrary)
+ depTag := libraryDependencyTag{Kind: sharedLibraryDependency, Order: earlyLibraryDependency}
+ variations := append(mctx.Target().Variations(),
+ blueprint.Variation{Mutator: "link", Variation: "shared"})
+ if c.Device() {
+ variations = append(variations, c.ImageVariation())
+ }
+ mctx.AddFarVariationDependencies(variations, depTag, runtimeLibrary)
}
// static lib does not have dependency to the runtime library. The
// dependency will be added to the executables or shared libs using
@@ -993,6 +1050,7 @@
android.Module
IsSanitizerEnabled(ctx android.BaseModuleContext, sanitizerName string) bool
EnableSanitizer(sanitizerName string)
+ AddSanitizerDependencies(ctx android.BottomUpMutatorContext, sanitizerName string)
}
// Create sanitized variants for modules that need them
@@ -1047,15 +1105,9 @@
// Export the static lib name to make
if c.static() && c.ExportedToMake() {
if t == cfi {
- appendStringSync(c.Name(), cfiStaticLibs(mctx.Config()), &cfiStaticLibsMutex)
+ cfiStaticLibs(mctx.Config()).add(c, c.Name())
} else if t == hwasan {
- if c.UseVndk() {
- appendStringSync(c.Name(), hwasanVendorStaticLibs(mctx.Config()),
- &hwasanStaticLibsMutex)
- } else {
- appendStringSync(c.Name(), hwasanStaticLibs(mctx.Config()),
- &hwasanStaticLibsMutex)
- }
+ hwasanStaticLibs(mctx.Config()).add(c, c.Name())
}
}
} else {
@@ -1079,39 +1131,98 @@
c.sanitize.Properties.SanitizeDep = false
} else if sanitizeable, ok := mctx.Module().(Sanitizeable); ok && sanitizeable.IsSanitizerEnabled(mctx, t.name()) {
// APEX modules fall here
+ sanitizeable.AddSanitizerDependencies(mctx, t.name())
mctx.CreateVariations(t.variationName())
+ } else if c, ok := mctx.Module().(*Module); ok {
+ // Check if it's a snapshot module supporting sanitizer
+ if s, ok := c.linker.(snapshotSanitizer); ok && s.isSanitizerEnabled(t) {
+ // Set default variation as above.
+ defaultVariation := t.variationName()
+ mctx.SetDefaultDependencyVariation(&defaultVariation)
+ modules := mctx.CreateVariations("", t.variationName())
+ modules[0].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, false)
+ modules[1].(*Module).linker.(snapshotSanitizer).setSanitizerVariation(t, true)
+
+ // Export the static lib name to make
+ if c.static() && c.ExportedToMake() {
+ if t == cfi {
+ // use BaseModuleName which is the name for Make.
+ cfiStaticLibs(mctx.Config()).add(c, c.BaseModuleName())
+ }
+ }
+ }
+ }
+ }
+}
+
+type sanitizerStaticLibsMap struct {
+ // libsMap contains one list of modules per each image and each arch.
+ // e.g. libs[vendor]["arm"] contains arm modules installed to vendor
+ libsMap map[imageVariantType]map[string][]string
+ libsMapLock sync.Mutex
+ sanitizerType sanitizerType
+}
+
+func newSanitizerStaticLibsMap(t sanitizerType) *sanitizerStaticLibsMap {
+ return &sanitizerStaticLibsMap{
+ sanitizerType: t,
+ libsMap: make(map[imageVariantType]map[string][]string),
+ }
+}
+
+// Add the current module to sanitizer static libs maps
+// Each module should pass its exported name as names of Make and Soong can differ.
+func (s *sanitizerStaticLibsMap) add(c *Module, name string) {
+ image := c.getImageVariantType()
+ arch := c.Arch().ArchType.String()
+
+ s.libsMapLock.Lock()
+ defer s.libsMapLock.Unlock()
+
+ if _, ok := s.libsMap[image]; !ok {
+ s.libsMap[image] = make(map[string][]string)
+ }
+
+ s.libsMap[image][arch] = append(s.libsMap[image][arch], name)
+}
+
+// Exports makefile variables in the following format:
+// SOONG_{sanitizer}_{image}_{arch}_STATIC_LIBRARIES
+// e.g. SOONG_cfi_core_x86_STATIC_LIBRARIES
+// These are to be used by use_soong_sanitized_static_libraries.
+// See build/make/core/binary.mk for more details.
+func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
+ for _, image := range android.SortedStringKeys(s.libsMap) {
+ archMap := s.libsMap[imageVariantType(image)]
+ for _, arch := range android.SortedStringKeys(archMap) {
+ libs := archMap[arch]
+ sort.Strings(libs)
+
+ key := fmt.Sprintf(
+ "SOONG_%s_%s_%s_STATIC_LIBRARIES",
+ s.sanitizerType.variationName(),
+ image, // already upper
+ arch)
+
+ ctx.Strict(key, strings.Join(libs, " "))
}
}
}
var cfiStaticLibsKey = android.NewOnceKey("cfiStaticLibs")
-func cfiStaticLibs(config android.Config) *[]string {
+func cfiStaticLibs(config android.Config) *sanitizerStaticLibsMap {
return config.Once(cfiStaticLibsKey, func() interface{} {
- return &[]string{}
- }).(*[]string)
+ return newSanitizerStaticLibsMap(cfi)
+ }).(*sanitizerStaticLibsMap)
}
var hwasanStaticLibsKey = android.NewOnceKey("hwasanStaticLibs")
-func hwasanStaticLibs(config android.Config) *[]string {
+func hwasanStaticLibs(config android.Config) *sanitizerStaticLibsMap {
return config.Once(hwasanStaticLibsKey, func() interface{} {
- return &[]string{}
- }).(*[]string)
-}
-
-var hwasanVendorStaticLibsKey = android.NewOnceKey("hwasanVendorStaticLibs")
-
-func hwasanVendorStaticLibs(config android.Config) *[]string {
- return config.Once(hwasanVendorStaticLibsKey, func() interface{} {
- return &[]string{}
- }).(*[]string)
-}
-
-func appendStringSync(item string, list *[]string, mutex *sync.Mutex) {
- mutex.Lock()
- *list = append(*list, item)
- mutex.Unlock()
+ return newSanitizerStaticLibsMap(hwasan)
+ }).(*sanitizerStaticLibsMap)
}
func enableMinimalRuntime(sanitize *sanitize) bool {
@@ -1141,17 +1252,9 @@
}
func cfiMakeVarsProvider(ctx android.MakeVarsContext) {
- cfiStaticLibs := cfiStaticLibs(ctx.Config())
- sort.Strings(*cfiStaticLibs)
- ctx.Strict("SOONG_CFI_STATIC_LIBRARIES", strings.Join(*cfiStaticLibs, " "))
+ cfiStaticLibs(ctx.Config()).exportToMake(ctx)
}
func hwasanMakeVarsProvider(ctx android.MakeVarsContext) {
- hwasanStaticLibs := hwasanStaticLibs(ctx.Config())
- sort.Strings(*hwasanStaticLibs)
- ctx.Strict("SOONG_HWASAN_STATIC_LIBRARIES", strings.Join(*hwasanStaticLibs, " "))
-
- hwasanVendorStaticLibs := hwasanVendorStaticLibs(ctx.Config())
- sort.Strings(*hwasanVendorStaticLibs)
- ctx.Strict("SOONG_HWASAN_VENDOR_STATIC_LIBRARIES", strings.Join(*hwasanVendorStaticLibs, " "))
+ hwasanStaticLibs(ctx.Config()).exportToMake(ctx)
}
diff --git a/cc/sdk.go b/cc/sdk.go
index d05a04a..b68baad 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -41,8 +41,9 @@
modules[0].(*Module).Properties.Sdk_version = nil
modules[1].(*Module).Properties.IsSdkVariant = true
- if ctx.Config().UnbundledBuild() {
+ if ctx.Config().UnbundledBuildApps() {
modules[0].(*Module).Properties.HideFromMake = true
+ modules[0].(*Module).Properties.PreventInstall = true
} else {
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
modules[1].(*Module).Properties.PreventInstall = true
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index 26e7c8d..f27d166 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -61,7 +61,7 @@
func isSnapshotAware(ctx android.ModuleContext, m *Module) bool {
if _, _, ok := isVndkSnapshotLibrary(ctx.DeviceConfig(), m); ok {
return ctx.Config().VndkSnapshotBuildArtifacts()
- } else if isVendorSnapshotModule(m, ctx.ModuleDir()) {
+ } else if isVendorSnapshotModule(m, isVendorProprietaryPath(ctx.ModuleDir())) {
return true
}
return false
@@ -81,6 +81,17 @@
return outPath
}
+func combineNotices(ctx android.SingletonContext, paths android.Paths, out string) android.OutputPath {
+ outPath := android.PathForOutput(ctx, out)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cat,
+ Inputs: paths,
+ Output: outPath,
+ Description: "combine notices for " + out,
+ })
+ return outPath
+}
+
func writeStringToFile(ctx android.SingletonContext, content, out string) android.OutputPath {
outPath := android.PathForOutput(ctx, out)
ctx.Build(pctx, android.BuildParams{
diff --git a/cc/stl.go b/cc/stl.go
index 34ff30c..e18fe95 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -239,16 +239,6 @@
flags.Local.CppFlags = append(flags.Local.CppFlags, "-nostdinc++")
flags.extraLibFlags = append(flags.extraLibFlags, "-nostdlib++")
if ctx.Windows() {
- if stl.Properties.SelectedStl == "libc++_static" {
- // These are transitively needed by libc++_static.
- flags.extraLibFlags = append(flags.extraLibFlags,
- "-lmsvcrt", "-lucrt")
- }
- // Use SjLj exceptions for 32-bit. libgcc_eh implements SjLj
- // exception model for 32-bit.
- if ctx.Arch().ArchType == android.X86 {
- flags.Local.CppFlags = append(flags.Local.CppFlags, "-fsjlj-exceptions")
- }
flags.Local.CppFlags = append(flags.Local.CppFlags,
// Disable visiblity annotations since we're using static
// libc++.
diff --git a/cc/strip.go b/cc/strip.go
index 7e560ec..18150dc 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -30,42 +30,42 @@
} `android:"arch_variant"`
}
-type stripper struct {
+type Stripper struct {
StripProperties StripProperties
}
-func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
+func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool {
// TODO(ccross): enable host stripping when embedded in make? Make never had support for stripping host binaries.
- return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None)
+ return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None)
}
-func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
- flags builderFlags, isStaticLib bool) {
- if ctx.Darwin() {
- TransformDarwinStrip(ctx, in, out)
+func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+ flags StripFlags, isStaticLib bool) {
+ if actx.Darwin() {
+ TransformDarwinStrip(actx, in, out)
} else {
if Bool(stripper.StripProperties.Strip.Keep_symbols) {
- flags.stripKeepSymbols = true
+ flags.StripKeepSymbols = true
} else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
- flags.stripKeepSymbolsAndDebugFrame = true
+ flags.StripKeepSymbolsAndDebugFrame = true
} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
- flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
+ flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
} else if !Bool(stripper.StripProperties.Strip.All) {
- flags.stripKeepMiniDebugInfo = true
+ flags.StripKeepMiniDebugInfo = true
}
- if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib {
- flags.stripAddGnuDebuglink = true
+ if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib {
+ flags.StripAddGnuDebuglink = true
}
- TransformStrip(ctx, in, out, flags)
+ TransformStrip(actx, in, out, flags)
}
}
-func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path,
- out android.ModuleOutPath, flags builderFlags) {
- stripper.strip(ctx, in, out, flags, false)
+func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path,
+ out android.ModuleOutPath, flags StripFlags) {
+ stripper.strip(actx, in, out, flags, false)
}
-func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
- flags builderFlags) {
- stripper.strip(ctx, in, out, flags, true)
+func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+ flags StripFlags) {
+ stripper.strip(actx, in, out, flags, true)
}
diff --git a/cc/symbolfile/.gitignore b/cc/symbolfile/.gitignore
new file mode 100644
index 0000000..fd94eac
--- /dev/null
+++ b/cc/symbolfile/.gitignore
@@ -0,0 +1,140 @@
+# From https://github.com/github/gitignore/blob/master/Python.gitignore
+
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
diff --git a/cc/symbolfile/Android.bp b/cc/symbolfile/Android.bp
new file mode 100644
index 0000000..5b43309
--- /dev/null
+++ b/cc/symbolfile/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+python_library_host {
+ name: "symbolfile",
+ pkg_path: "symbolfile",
+ srcs: [
+ "__init__.py",
+ ],
+}
+
+python_test_host {
+ name: "test_symbolfile",
+ srcs: [
+ "test_symbolfile.py",
+ ],
+ libs: [
+ "symbolfile",
+ ],
+}
diff --git a/cc/symbolfile/OWNERS b/cc/symbolfile/OWNERS
new file mode 100644
index 0000000..f0d8733
--- /dev/null
+++ b/cc/symbolfile/OWNERS
@@ -0,0 +1 @@
+danalbert@google.com
diff --git a/cc/gen_stub_libs.py b/cc/symbolfile/__init__.py
old mode 100755
new mode 100644
similarity index 72%
rename from cc/gen_stub_libs.py
rename to cc/symbolfile/__init__.py
index 0de703c..faa3823
--- a/cc/gen_stub_libs.py
+++ b/cc/symbolfile/__init__.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
#
# Copyright (C) 2016 The Android Open Source Project
#
@@ -14,20 +13,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-"""Generates source for stub shared libraries for the NDK."""
-import argparse
-import json
+"""Parser for Android's version script information."""
import logging
-import os
import re
-import sys
ALL_ARCHITECTURES = (
'arm',
'arm64',
- 'mips',
- 'mips64',
'x86',
'x86_64',
)
@@ -59,6 +52,24 @@
return False
+def decode_api_level(api, api_map):
+ """Decodes the API level argument into the API level number.
+
+ For the average case, this just decodes the integer value from the string,
+ but for unreleased APIs we need to translate from the API codename (like
+ "O") to the future API level for that codename.
+ """
+ try:
+ return int(api)
+ except ValueError:
+ pass
+
+ if api == "current":
+ return FUTURE_API_LEVEL
+
+ return api_map[api]
+
+
def decode_api_level_tags(tags, api_map):
"""Decodes API level code names in a list of tags.
@@ -120,7 +131,8 @@
if 'platform-only' in version.tags:
return True
- no_llndk_no_apex = 'llndk' not in version.tags and 'apex' not in version.tags
+ no_llndk_no_apex = ('llndk' not in version.tags
+ and 'apex' not in version.tags)
keep = no_llndk_no_apex or \
('llndk' in version.tags and llndk) or \
('apex' in version.tags and apex)
@@ -207,7 +219,6 @@
class ParseError(RuntimeError):
"""An error that occurred while parsing a symbol file."""
- pass
class MultiplyDefinedSymbolError(RuntimeError):
@@ -219,7 +230,7 @@
self.multiply_defined_symbols = multiply_defined_symbols
-class Version(object):
+class Version:
"""A version block of a symbol file."""
def __init__(self, name, base, tags, symbols):
self.name = name
@@ -239,7 +250,7 @@
return True
-class Symbol(object):
+class Symbol:
"""A symbol definition from a symbol file."""
def __init__(self, name, tags):
self.name = name
@@ -248,7 +259,8 @@
def __eq__(self, other):
return self.name == other.name and set(self.tags) == set(other.tags)
-class SymbolFileParser(object):
+
+class SymbolFileParser:
"""Parses NDK symbol files."""
def __init__(self, input_file, api_map, arch, api, llndk, apex):
self.input_file = input_file
@@ -284,11 +296,13 @@
symbol_names = set()
multiply_defined_symbols = set()
for version in versions:
- if should_omit_version(version, self.arch, self.api, self.llndk, self.apex):
+ if should_omit_version(version, self.arch, self.api, self.llndk,
+ self.apex):
continue
for symbol in version.symbols:
- if should_omit_symbol(symbol, self.arch, self.api, self.llndk, self.apex):
+ if should_omit_symbol(symbol, self.arch, self.api, self.llndk,
+ self.apex):
continue
if symbol.name in symbol_names:
@@ -368,141 +382,3 @@
break
self.current_line = line
return self.current_line
-
-
-class Generator(object):
- """Output generator that writes stub source files and version scripts."""
- def __init__(self, src_file, version_script, arch, api, llndk, apex):
- self.src_file = src_file
- self.version_script = version_script
- self.arch = arch
- self.api = api
- self.llndk = llndk
- self.apex = apex
-
- def write(self, versions):
- """Writes all symbol data to the output files."""
- for version in versions:
- self.write_version(version)
-
- def write_version(self, version):
- """Writes a single version block's data to the output files."""
- if should_omit_version(version, self.arch, self.api, self.llndk, self.apex):
- return
-
- section_versioned = symbol_versioned_in_api(version.tags, self.api)
- version_empty = True
- pruned_symbols = []
- for symbol in version.symbols:
- if should_omit_symbol(symbol, self.arch, self.api, self.llndk, self.apex):
- continue
-
- if symbol_versioned_in_api(symbol.tags, self.api):
- version_empty = False
- pruned_symbols.append(symbol)
-
- if len(pruned_symbols) > 0:
- if not version_empty and section_versioned:
- self.version_script.write(version.name + ' {\n')
- self.version_script.write(' global:\n')
- for symbol in pruned_symbols:
- emit_version = symbol_versioned_in_api(symbol.tags, self.api)
- if section_versioned and emit_version:
- self.version_script.write(' ' + symbol.name + ';\n')
-
- weak = ''
- if 'weak' in symbol.tags:
- weak = '__attribute__((weak)) '
-
- if 'var' in symbol.tags:
- self.src_file.write('{}int {} = 0;\n'.format(
- weak, symbol.name))
- else:
- self.src_file.write('{}void {}() {{}}\n'.format(
- weak, symbol.name))
-
- if not version_empty and section_versioned:
- base = '' if version.base is None else ' ' + version.base
- self.version_script.write('}' + base + ';\n')
-
-
-def decode_api_level(api, api_map):
- """Decodes the API level argument into the API level number.
-
- For the average case, this just decodes the integer value from the string,
- but for unreleased APIs we need to translate from the API codename (like
- "O") to the future API level for that codename.
- """
- try:
- return int(api)
- except ValueError:
- pass
-
- if api == "current":
- return FUTURE_API_LEVEL
-
- return api_map[api]
-
-
-def parse_args():
- """Parses and returns command line arguments."""
- parser = argparse.ArgumentParser()
-
- parser.add_argument('-v', '--verbose', action='count', default=0)
-
- parser.add_argument(
- '--api', required=True, help='API level being targeted.')
- parser.add_argument(
- '--arch', choices=ALL_ARCHITECTURES, required=True,
- help='Architecture being targeted.')
- parser.add_argument(
- '--llndk', action='store_true', help='Use the LLNDK variant.')
- parser.add_argument(
- '--apex', action='store_true', help='Use the APEX variant.')
-
- parser.add_argument(
- '--api-map', type=os.path.realpath, required=True,
- help='Path to the API level map JSON file.')
-
- parser.add_argument(
- 'symbol_file', type=os.path.realpath, help='Path to symbol file.')
- parser.add_argument(
- 'stub_src', type=os.path.realpath,
- help='Path to output stub source file.')
- parser.add_argument(
- 'version_script', type=os.path.realpath,
- help='Path to output version script.')
-
- return parser.parse_args()
-
-
-def main():
- """Program entry point."""
- args = parse_args()
-
- with open(args.api_map) as map_file:
- api_map = json.load(map_file)
- api = decode_api_level(args.api, api_map)
-
- verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
- verbosity = args.verbose
- if verbosity > 2:
- verbosity = 2
- logging.basicConfig(level=verbose_map[verbosity])
-
- with open(args.symbol_file) as symbol_file:
- try:
- versions = SymbolFileParser(symbol_file, api_map, args.arch, api,
- args.llndk, args.apex).parse()
- except MultiplyDefinedSymbolError as ex:
- sys.exit('{}: error: {}'.format(args.symbol_file, ex))
-
- with open(args.stub_src, 'w') as src_file:
- with open(args.version_script, 'w') as version_file:
- generator = Generator(src_file, version_file, args.arch, api,
- args.llndk, args.apex)
- generator.write(versions)
-
-
-if __name__ == '__main__':
- main()
diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py
new file mode 100644
index 0000000..c91131f
--- /dev/null
+++ b/cc/symbolfile/test_symbolfile.py
@@ -0,0 +1,493 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for symbolfile."""
+import io
+import textwrap
+import unittest
+
+import symbolfile
+
+# pylint: disable=missing-docstring
+
+
+class DecodeApiLevelTest(unittest.TestCase):
+ def test_decode_api_level(self):
+ self.assertEqual(9, symbolfile.decode_api_level('9', {}))
+ self.assertEqual(9000, symbolfile.decode_api_level('O', {'O': 9000}))
+
+ with self.assertRaises(KeyError):
+ symbolfile.decode_api_level('O', {})
+
+
+class TagsTest(unittest.TestCase):
+ def test_get_tags_no_tags(self):
+ self.assertEqual([], symbolfile.get_tags(''))
+ self.assertEqual([], symbolfile.get_tags('foo bar baz'))
+
+ def test_get_tags(self):
+ self.assertEqual(['foo', 'bar'], symbolfile.get_tags('# foo bar'))
+ self.assertEqual(['bar', 'baz'], symbolfile.get_tags('foo # bar baz'))
+
+ def test_split_tag(self):
+ self.assertTupleEqual(('foo', 'bar'), symbolfile.split_tag('foo=bar'))
+ self.assertTupleEqual(('foo', 'bar=baz'), symbolfile.split_tag('foo=bar=baz'))
+ with self.assertRaises(ValueError):
+ symbolfile.split_tag('foo')
+
+ def test_get_tag_value(self):
+ self.assertEqual('bar', symbolfile.get_tag_value('foo=bar'))
+ self.assertEqual('bar=baz', symbolfile.get_tag_value('foo=bar=baz'))
+ with self.assertRaises(ValueError):
+ symbolfile.get_tag_value('foo')
+
+ def test_is_api_level_tag(self):
+ self.assertTrue(symbolfile.is_api_level_tag('introduced=24'))
+ self.assertTrue(symbolfile.is_api_level_tag('introduced-arm=24'))
+ self.assertTrue(symbolfile.is_api_level_tag('versioned=24'))
+
+ # Shouldn't try to process things that aren't a key/value tag.
+ self.assertFalse(symbolfile.is_api_level_tag('arm'))
+ self.assertFalse(symbolfile.is_api_level_tag('introduced'))
+ self.assertFalse(symbolfile.is_api_level_tag('versioned'))
+
+ # We don't support arch specific `versioned` tags.
+ self.assertFalse(symbolfile.is_api_level_tag('versioned-arm=24'))
+
+ def test_decode_api_level_tags(self):
+ api_map = {
+ 'O': 9000,
+ 'P': 9001,
+ }
+
+ tags = [
+ 'introduced=9',
+ 'introduced-arm=14',
+ 'versioned=16',
+ 'arm',
+ 'introduced=O',
+ 'introduced=P',
+ ]
+ expected_tags = [
+ 'introduced=9',
+ 'introduced-arm=14',
+ 'versioned=16',
+ 'arm',
+ 'introduced=9000',
+ 'introduced=9001',
+ ]
+ self.assertListEqual(
+ expected_tags, symbolfile.decode_api_level_tags(tags, api_map))
+
+ with self.assertRaises(symbolfile.ParseError):
+ symbolfile.decode_api_level_tags(['introduced=O'], {})
+
+
+class PrivateVersionTest(unittest.TestCase):
+ def test_version_is_private(self):
+ self.assertFalse(symbolfile.version_is_private('foo'))
+ self.assertFalse(symbolfile.version_is_private('PRIVATE'))
+ self.assertFalse(symbolfile.version_is_private('PLATFORM'))
+ self.assertFalse(symbolfile.version_is_private('foo_private'))
+ self.assertFalse(symbolfile.version_is_private('foo_platform'))
+ self.assertFalse(symbolfile.version_is_private('foo_PRIVATE_'))
+ self.assertFalse(symbolfile.version_is_private('foo_PLATFORM_'))
+
+ self.assertTrue(symbolfile.version_is_private('foo_PRIVATE'))
+ self.assertTrue(symbolfile.version_is_private('foo_PLATFORM'))
+
+
+class SymbolPresenceTest(unittest.TestCase):
+ def test_symbol_in_arch(self):
+ self.assertTrue(symbolfile.symbol_in_arch([], 'arm'))
+ self.assertTrue(symbolfile.symbol_in_arch(['arm'], 'arm'))
+
+ self.assertFalse(symbolfile.symbol_in_arch(['x86'], 'arm'))
+
+ def test_symbol_in_api(self):
+ self.assertTrue(symbolfile.symbol_in_api([], 'arm', 9))
+ self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 9))
+ self.assertTrue(symbolfile.symbol_in_api(['introduced=9'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(['introduced-arm=9'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(['introduced-x86=14'], 'arm', 9))
+ self.assertTrue(symbolfile.symbol_in_api(
+ ['introduced-arm=9', 'introduced-x86=21'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(
+ ['introduced=9', 'introduced-x86=21'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(
+ ['introduced=21', 'introduced-arm=9'], 'arm', 14))
+ self.assertTrue(symbolfile.symbol_in_api(
+ ['future'], 'arm', symbolfile.FUTURE_API_LEVEL))
+
+ self.assertFalse(symbolfile.symbol_in_api(['introduced=14'], 'arm', 9))
+ self.assertFalse(symbolfile.symbol_in_api(['introduced-arm=14'], 'arm', 9))
+ self.assertFalse(symbolfile.symbol_in_api(['future'], 'arm', 9))
+ self.assertFalse(symbolfile.symbol_in_api(
+ ['introduced=9', 'future'], 'arm', 14))
+ self.assertFalse(symbolfile.symbol_in_api(
+ ['introduced-arm=9', 'future'], 'arm', 14))
+ self.assertFalse(symbolfile.symbol_in_api(
+ ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14))
+ self.assertFalse(symbolfile.symbol_in_api(
+ ['introduced=9', 'introduced-arm=21'], 'arm', 14))
+ self.assertFalse(symbolfile.symbol_in_api(
+ ['introduced=21', 'introduced-x86=9'], 'arm', 14))
+
+ # Interesting edge case: this symbol should be omitted from the
+ # library, but this call should still return true because none of the
+ # tags indiciate that it's not present in this API level.
+ self.assertTrue(symbolfile.symbol_in_api(['x86'], 'arm', 9))
+
+ def test_verioned_in_api(self):
+ self.assertTrue(symbolfile.symbol_versioned_in_api([], 9))
+ self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 9))
+ self.assertTrue(symbolfile.symbol_versioned_in_api(['versioned=9'], 14))
+
+ self.assertFalse(symbolfile.symbol_versioned_in_api(['versioned=14'], 9))
+
+
+class OmitVersionTest(unittest.TestCase):
+ def test_omit_private(self):
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, [], []), 'arm', 9, False,
+ False))
+
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo_PRIVATE', None, [], []), 'arm', 9,
+ False, False))
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo_PLATFORM', None, [], []), 'arm', 9,
+ False, False))
+
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['platform-only'], []), 'arm',
+ 9, False, False))
+
+ def test_omit_llndk(self):
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9,
+ False, False))
+
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, [], []), 'arm', 9, True,
+ False))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['llndk'], []), 'arm', 9, True,
+ False))
+
+ def test_omit_apex(self):
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False,
+ False))
+
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, [], []), 'arm', 9, False,
+ True))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['apex'], []), 'arm', 9, False,
+ True))
+
+ def test_omit_arch(self):
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, [], []), 'arm', 9, False,
+ False))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['arm'], []), 'arm', 9, False,
+ False))
+
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['x86'], []), 'arm', 9, False,
+ False))
+
+ def test_omit_api(self):
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, [], []), 'arm', 9, False,
+ False))
+ self.assertFalse(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['introduced=9'], []), 'arm',
+ 9, False, False))
+
+ self.assertTrue(
+ symbolfile.should_omit_version(
+ symbolfile.Version('foo', None, ['introduced=14'], []), 'arm',
+ 9, False, False))
+
+
+class OmitSymbolTest(unittest.TestCase):
+ def test_omit_llndk(self):
+ self.assertTrue(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']),
+ 'arm', 9, False, False))
+
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
+ 9, True, False))
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['llndk']),
+ 'arm', 9, True, False))
+
+ def test_omit_apex(self):
+ self.assertTrue(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']),
+ 'arm', 9, False, False))
+
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
+ 9, False, True))
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['apex']),
+ 'arm', 9, False, True))
+
+ def test_omit_arch(self):
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
+ 9, False, False))
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['arm']),
+ 'arm', 9, False, False))
+
+ self.assertTrue(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', ['x86']),
+ 'arm', 9, False, False))
+
+ def test_omit_api(self):
+ self.assertFalse(
+ symbolfile.should_omit_symbol(symbolfile.Symbol('foo', []), 'arm',
+ 9, False, False))
+ self.assertFalse(
+ symbolfile.should_omit_symbol(
+ symbolfile.Symbol('foo', ['introduced=9']), 'arm', 9, False,
+ False))
+
+ self.assertTrue(
+ symbolfile.should_omit_symbol(
+ symbolfile.Symbol('foo', ['introduced=14']), 'arm', 9, False,
+ False))
+
+
+class SymbolFileParseTest(unittest.TestCase):
+ def test_next_line(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ foo
+
+ bar
+ # baz
+ qux
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ self.assertIsNone(parser.current_line)
+
+ self.assertEqual('foo', parser.next_line().strip())
+ self.assertEqual('foo', parser.current_line.strip())
+
+ self.assertEqual('bar', parser.next_line().strip())
+ self.assertEqual('bar', parser.current_line.strip())
+
+ self.assertEqual('qux', parser.next_line().strip())
+ self.assertEqual('qux', parser.current_line.strip())
+
+ self.assertEqual('', parser.next_line())
+ self.assertEqual('', parser.current_line)
+
+ def test_parse_version(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 { # foo bar
+ baz;
+ qux; # woodly doodly
+ };
+
+ VERSION_2 {
+ } VERSION_1; # asdf
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+
+ parser.next_line()
+ version = parser.parse_version()
+ self.assertEqual('VERSION_1', version.name)
+ self.assertIsNone(version.base)
+ self.assertEqual(['foo', 'bar'], version.tags)
+
+ expected_symbols = [
+ symbolfile.Symbol('baz', []),
+ symbolfile.Symbol('qux', ['woodly', 'doodly']),
+ ]
+ self.assertEqual(expected_symbols, version.symbols)
+
+ parser.next_line()
+ version = parser.parse_version()
+ self.assertEqual('VERSION_2', version.name)
+ self.assertEqual('VERSION_1', version.base)
+ self.assertEqual([], version.tags)
+
+ def test_parse_version_eof(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ parser.next_line()
+ with self.assertRaises(symbolfile.ParseError):
+ parser.parse_version()
+
+ def test_unknown_scope_label(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ foo:
+ }
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ parser.next_line()
+ with self.assertRaises(symbolfile.ParseError):
+ parser.parse_version()
+
+ def test_parse_symbol(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ foo;
+ bar; # baz qux
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+
+ parser.next_line()
+ symbol = parser.parse_symbol()
+ self.assertEqual('foo', symbol.name)
+ self.assertEqual([], symbol.tags)
+
+ parser.next_line()
+ symbol = parser.parse_symbol()
+ self.assertEqual('bar', symbol.name)
+ self.assertEqual(['baz', 'qux'], symbol.tags)
+
+ def test_wildcard_symbol_global(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ *;
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ parser.next_line()
+ with self.assertRaises(symbolfile.ParseError):
+ parser.parse_version()
+
+ def test_wildcard_symbol_local(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ local:
+ *;
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ parser.next_line()
+ version = parser.parse_version()
+ self.assertEqual([], version.symbols)
+
+ def test_missing_semicolon(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ foo
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ parser.next_line()
+ with self.assertRaises(symbolfile.ParseError):
+ parser.parse_version()
+
+ def test_parse_fails_invalid_input(self):
+ with self.assertRaises(symbolfile.ParseError):
+ input_file = io.StringIO('foo')
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16,
+ False, False)
+ parser.parse()
+
+ def test_parse(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ local:
+ hidden1;
+ global:
+ foo;
+ bar; # baz
+ };
+
+ VERSION_2 { # wasd
+ # Implicit global scope.
+ woodly;
+ doodly; # asdf
+ local:
+ qwerty;
+ } VERSION_1;
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
+ versions = parser.parse()
+
+ expected = [
+ symbolfile.Version('VERSION_1', None, [], [
+ symbolfile.Symbol('foo', []),
+ symbolfile.Symbol('bar', ['baz']),
+ ]),
+ symbolfile.Version('VERSION_2', 'VERSION_1', ['wasd'], [
+ symbolfile.Symbol('woodly', []),
+ symbolfile.Symbol('doodly', ['asdf']),
+ ]),
+ ]
+
+ self.assertEqual(expected, versions)
+
+ def test_parse_llndk_apex_symbol(self):
+ input_file = io.StringIO(textwrap.dedent("""\
+ VERSION_1 {
+ foo;
+ bar; # llndk
+ baz; # llndk apex
+ qux; # apex
+ };
+ """))
+ parser = symbolfile.SymbolFileParser(input_file, {}, 'arm', 16, False, True)
+
+ parser.next_line()
+ version = parser.parse_version()
+ self.assertEqual('VERSION_1', version.name)
+ self.assertIsNone(version.base)
+
+ expected_symbols = [
+ symbolfile.Symbol('foo', []),
+ symbolfile.Symbol('bar', ['llndk']),
+ symbolfile.Symbol('baz', ['llndk', 'apex']),
+ symbolfile.Symbol('qux', ['apex']),
+ ]
+ self.assertEqual(expected_symbols, version.symbols)
+
+
+def main():
+ suite = unittest.TestLoader().loadTestsFromName(__name__)
+ unittest.TextTestRunner(verbosity=3).run(suite)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/cc/test.go b/cc/test.go
index 95abfbf..619dc4d 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -40,6 +40,12 @@
type TestOptions struct {
// The UID that you want to run the test as on a device.
Run_test_as *string
+
+ // A list of free-formed strings without spaces that categorize the test.
+ Test_suite_tag []string
+
+ // a list of extra test configuration files that should be installed with the module.
+ Extra_test_configs []string `android:"path,arch_variant"`
}
type TestBinaryProperties struct {
@@ -56,6 +62,9 @@
// the test
Data []string `android:"path,arch_variant"`
+ // list of shared library modules that should be installed alongside the test
+ Data_libs []string `android:"arch_variant"`
+
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
Test_suites []string `android:"arch_variant"`
@@ -160,6 +169,10 @@
return test.baseCompiler.Properties.Srcs
}
+func (test *testBinary) dataPaths() []android.DataPath {
+ return test.data
+}
+
func (test *testBinary) isAllTestsVariation() bool {
stem := test.binaryDecorator.Properties.Stem
return stem != nil && *stem == ""
@@ -210,6 +223,7 @@
tests[i].(*Module).linker.(testPerSrc).setSrc(testNames[i], src)
mctx.AddInterVariantDependency(testPerSrcDepTag, all_tests, tests[i])
}
+ mctx.AliasVariation("")
}
}
}
@@ -300,9 +314,10 @@
testDecorator
*binaryDecorator
*baseCompiler
- Properties TestBinaryProperties
- data android.Paths
- testConfig android.Path
+ Properties TestBinaryProperties
+ data []android.DataPath
+ testConfig android.Path
+ extraTestConfigs android.Paths
}
func (test *testBinary) linkerProps() []interface{} {
@@ -319,6 +334,7 @@
func (test *testBinary) linkerDeps(ctx DepsContext, deps Deps) Deps {
deps = test.testDecorator.linkerDeps(ctx, deps)
deps = test.binaryDecorator.linkerDeps(ctx, deps)
+ deps.DataLibs = append(deps.DataLibs, test.Properties.Data_libs...)
return deps
}
@@ -329,7 +345,36 @@
}
func (test *testBinary) install(ctx ModuleContext, file android.Path) {
- test.data = android.PathsForModuleSrc(ctx, test.Properties.Data)
+ // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
+ testInstallBase := "/data/local/tmp"
+ if ctx.inVendor() || ctx.useVndk() {
+ testInstallBase = "/data/local/tests/vendor"
+ }
+
+ dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
+
+ for _, dataSrcPath := range dataSrcPaths {
+ test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath})
+ }
+
+ ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) {
+ depName := ctx.OtherModuleName(dep)
+ ccDep, ok := dep.(LinkableInterface)
+
+ if !ok {
+ ctx.ModuleErrorf("data_lib %q is not a linkable cc module", depName)
+ }
+ ccModule, ok := dep.(*Module)
+ if !ok {
+ ctx.ModuleErrorf("data_lib %q is not a cc module", depName)
+ }
+ if ccDep.OutputFile().Valid() {
+ test.data = append(test.data,
+ android.DataPath{SrcPath: ccDep.OutputFile().Path(),
+ RelativeInstallPath: ccModule.installer.relativeInstallPath()})
+ }
+ })
+
var api_level_prop string
var configs []tradefed.Config
var min_level string
@@ -353,6 +398,9 @@
if test.Properties.Test_options.Run_test_as != nil {
configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)})
}
+ for _, tag := range test.Properties.Test_options.Test_suite_tag {
+ configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
+ }
if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
} else if test.Properties.Test_min_api_level != nil {
@@ -370,7 +418,9 @@
}
test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
- test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config)
+ test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase)
+
+ test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs)
test.binaryDecorator.baseInstaller.dir = "nativetest"
test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
@@ -498,6 +548,7 @@
func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Path) {
benchmark.data = android.PathsForModuleSrc(ctx, benchmark.Properties.Data)
+
var configs []tradefed.Config
if Bool(benchmark.Properties.Require_root) {
configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
diff --git a/cc/test_gen_stub_libs.py b/cc/test_gen_stub_libs.py
deleted file mode 100755
index 0b45e71..0000000
--- a/cc/test_gen_stub_libs.py
+++ /dev/null
@@ -1,807 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-"""Tests for gen_stub_libs.py."""
-import io
-import textwrap
-import unittest
-
-import gen_stub_libs as gsl
-
-
-# pylint: disable=missing-docstring
-
-
-class DecodeApiLevelTest(unittest.TestCase):
- def test_decode_api_level(self):
- self.assertEqual(9, gsl.decode_api_level('9', {}))
- self.assertEqual(9000, gsl.decode_api_level('O', {'O': 9000}))
-
- with self.assertRaises(KeyError):
- gsl.decode_api_level('O', {})
-
-
-class TagsTest(unittest.TestCase):
- def test_get_tags_no_tags(self):
- self.assertEqual([], gsl.get_tags(''))
- self.assertEqual([], gsl.get_tags('foo bar baz'))
-
- def test_get_tags(self):
- self.assertEqual(['foo', 'bar'], gsl.get_tags('# foo bar'))
- self.assertEqual(['bar', 'baz'], gsl.get_tags('foo # bar baz'))
-
- def test_split_tag(self):
- self.assertTupleEqual(('foo', 'bar'), gsl.split_tag('foo=bar'))
- self.assertTupleEqual(('foo', 'bar=baz'), gsl.split_tag('foo=bar=baz'))
- with self.assertRaises(ValueError):
- gsl.split_tag('foo')
-
- def test_get_tag_value(self):
- self.assertEqual('bar', gsl.get_tag_value('foo=bar'))
- self.assertEqual('bar=baz', gsl.get_tag_value('foo=bar=baz'))
- with self.assertRaises(ValueError):
- gsl.get_tag_value('foo')
-
- def test_is_api_level_tag(self):
- self.assertTrue(gsl.is_api_level_tag('introduced=24'))
- self.assertTrue(gsl.is_api_level_tag('introduced-arm=24'))
- self.assertTrue(gsl.is_api_level_tag('versioned=24'))
-
- # Shouldn't try to process things that aren't a key/value tag.
- self.assertFalse(gsl.is_api_level_tag('arm'))
- self.assertFalse(gsl.is_api_level_tag('introduced'))
- self.assertFalse(gsl.is_api_level_tag('versioned'))
-
- # We don't support arch specific `versioned` tags.
- self.assertFalse(gsl.is_api_level_tag('versioned-arm=24'))
-
- def test_decode_api_level_tags(self):
- api_map = {
- 'O': 9000,
- 'P': 9001,
- }
-
- tags = [
- 'introduced=9',
- 'introduced-arm=14',
- 'versioned=16',
- 'arm',
- 'introduced=O',
- 'introduced=P',
- ]
- expected_tags = [
- 'introduced=9',
- 'introduced-arm=14',
- 'versioned=16',
- 'arm',
- 'introduced=9000',
- 'introduced=9001',
- ]
- self.assertListEqual(
- expected_tags, gsl.decode_api_level_tags(tags, api_map))
-
- with self.assertRaises(gsl.ParseError):
- gsl.decode_api_level_tags(['introduced=O'], {})
-
-
-class PrivateVersionTest(unittest.TestCase):
- def test_version_is_private(self):
- self.assertFalse(gsl.version_is_private('foo'))
- self.assertFalse(gsl.version_is_private('PRIVATE'))
- self.assertFalse(gsl.version_is_private('PLATFORM'))
- self.assertFalse(gsl.version_is_private('foo_private'))
- self.assertFalse(gsl.version_is_private('foo_platform'))
- self.assertFalse(gsl.version_is_private('foo_PRIVATE_'))
- self.assertFalse(gsl.version_is_private('foo_PLATFORM_'))
-
- self.assertTrue(gsl.version_is_private('foo_PRIVATE'))
- self.assertTrue(gsl.version_is_private('foo_PLATFORM'))
-
-
-class SymbolPresenceTest(unittest.TestCase):
- def test_symbol_in_arch(self):
- self.assertTrue(gsl.symbol_in_arch([], 'arm'))
- self.assertTrue(gsl.symbol_in_arch(['arm'], 'arm'))
-
- self.assertFalse(gsl.symbol_in_arch(['x86'], 'arm'))
-
- def test_symbol_in_api(self):
- self.assertTrue(gsl.symbol_in_api([], 'arm', 9))
- self.assertTrue(gsl.symbol_in_api(['introduced=9'], 'arm', 9))
- self.assertTrue(gsl.symbol_in_api(['introduced=9'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(['introduced-arm=9'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(['introduced-arm=9'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(['introduced-x86=14'], 'arm', 9))
- self.assertTrue(gsl.symbol_in_api(
- ['introduced-arm=9', 'introduced-x86=21'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(
- ['introduced=9', 'introduced-x86=21'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(
- ['introduced=21', 'introduced-arm=9'], 'arm', 14))
- self.assertTrue(gsl.symbol_in_api(
- ['future'], 'arm', gsl.FUTURE_API_LEVEL))
-
- self.assertFalse(gsl.symbol_in_api(['introduced=14'], 'arm', 9))
- self.assertFalse(gsl.symbol_in_api(['introduced-arm=14'], 'arm', 9))
- self.assertFalse(gsl.symbol_in_api(['future'], 'arm', 9))
- self.assertFalse(gsl.symbol_in_api(
- ['introduced=9', 'future'], 'arm', 14))
- self.assertFalse(gsl.symbol_in_api(
- ['introduced-arm=9', 'future'], 'arm', 14))
- self.assertFalse(gsl.symbol_in_api(
- ['introduced-arm=21', 'introduced-x86=9'], 'arm', 14))
- self.assertFalse(gsl.symbol_in_api(
- ['introduced=9', 'introduced-arm=21'], 'arm', 14))
- self.assertFalse(gsl.symbol_in_api(
- ['introduced=21', 'introduced-x86=9'], 'arm', 14))
-
- # Interesting edge case: this symbol should be omitted from the
- # library, but this call should still return true because none of the
- # tags indiciate that it's not present in this API level.
- self.assertTrue(gsl.symbol_in_api(['x86'], 'arm', 9))
-
- def test_verioned_in_api(self):
- self.assertTrue(gsl.symbol_versioned_in_api([], 9))
- self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 9))
- self.assertTrue(gsl.symbol_versioned_in_api(['versioned=9'], 14))
-
- self.assertFalse(gsl.symbol_versioned_in_api(['versioned=14'], 9))
-
-
-class OmitVersionTest(unittest.TestCase):
- def test_omit_private(self):
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, [], []), 'arm', 9, False, False))
-
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo_PRIVATE', None, [], []), 'arm', 9, False, False))
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo_PLATFORM', None, [], []), 'arm', 9, False, False))
-
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['platform-only'], []), 'arm', 9,
- False, False))
-
- def test_omit_llndk(self):
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['llndk'], []), 'arm', 9, False, False))
-
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, [], []), 'arm', 9, True, False))
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['llndk'], []), 'arm', 9, True, False))
-
- def test_omit_apex(self):
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['apex'], []), 'arm', 9, False, False))
-
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, [], []), 'arm', 9, False, True))
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['apex'], []), 'arm', 9, False, True))
-
- def test_omit_arch(self):
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, [], []), 'arm', 9, False, False))
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['arm'], []), 'arm', 9, False, False))
-
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['x86'], []), 'arm', 9, False, False))
-
- def test_omit_api(self):
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, [], []), 'arm', 9, False, False))
- self.assertFalse(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['introduced=9'], []), 'arm', 9,
- False, False))
-
- self.assertTrue(
- gsl.should_omit_version(
- gsl.Version('foo', None, ['introduced=14'], []), 'arm', 9,
- False, False))
-
-
-class OmitSymbolTest(unittest.TestCase):
- def test_omit_llndk(self):
- self.assertTrue(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['llndk']), 'arm', 9, False, False))
-
- self.assertFalse(
- gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, True, False))
- self.assertFalse(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['llndk']), 'arm', 9, True, False))
-
- def test_omit_apex(self):
- self.assertTrue(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['apex']), 'arm', 9, False, False))
-
- self.assertFalse(
- gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, True))
- self.assertFalse(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['apex']), 'arm', 9, False, True))
-
- def test_omit_arch(self):
- self.assertFalse(
- gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, False))
- self.assertFalse(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['arm']), 'arm', 9, False, False))
-
- self.assertTrue(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['x86']), 'arm', 9, False, False))
-
- def test_omit_api(self):
- self.assertFalse(
- gsl.should_omit_symbol(gsl.Symbol('foo', []), 'arm', 9, False, False))
- self.assertFalse(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['introduced=9']), 'arm', 9, False, False))
-
- self.assertTrue(
- gsl.should_omit_symbol(
- gsl.Symbol('foo', ['introduced=14']), 'arm', 9, False, False))
-
-
-class SymbolFileParseTest(unittest.TestCase):
- def test_next_line(self):
- input_file = io.StringIO(textwrap.dedent("""\
- foo
-
- bar
- # baz
- qux
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- self.assertIsNone(parser.current_line)
-
- self.assertEqual('foo', parser.next_line().strip())
- self.assertEqual('foo', parser.current_line.strip())
-
- self.assertEqual('bar', parser.next_line().strip())
- self.assertEqual('bar', parser.current_line.strip())
-
- self.assertEqual('qux', parser.next_line().strip())
- self.assertEqual('qux', parser.current_line.strip())
-
- self.assertEqual('', parser.next_line())
- self.assertEqual('', parser.current_line)
-
- def test_parse_version(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 { # foo bar
- baz;
- qux; # woodly doodly
- };
-
- VERSION_2 {
- } VERSION_1; # asdf
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
-
- parser.next_line()
- version = parser.parse_version()
- self.assertEqual('VERSION_1', version.name)
- self.assertIsNone(version.base)
- self.assertEqual(['foo', 'bar'], version.tags)
-
- expected_symbols = [
- gsl.Symbol('baz', []),
- gsl.Symbol('qux', ['woodly', 'doodly']),
- ]
- self.assertEqual(expected_symbols, version.symbols)
-
- parser.next_line()
- version = parser.parse_version()
- self.assertEqual('VERSION_2', version.name)
- self.assertEqual('VERSION_1', version.base)
- self.assertEqual([], version.tags)
-
- def test_parse_version_eof(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.next_line()
- with self.assertRaises(gsl.ParseError):
- parser.parse_version()
-
- def test_unknown_scope_label(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- foo:
- }
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.next_line()
- with self.assertRaises(gsl.ParseError):
- parser.parse_version()
-
- def test_parse_symbol(self):
- input_file = io.StringIO(textwrap.dedent("""\
- foo;
- bar; # baz qux
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
-
- parser.next_line()
- symbol = parser.parse_symbol()
- self.assertEqual('foo', symbol.name)
- self.assertEqual([], symbol.tags)
-
- parser.next_line()
- symbol = parser.parse_symbol()
- self.assertEqual('bar', symbol.name)
- self.assertEqual(['baz', 'qux'], symbol.tags)
-
- def test_wildcard_symbol_global(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- *;
- };
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.next_line()
- with self.assertRaises(gsl.ParseError):
- parser.parse_version()
-
- def test_wildcard_symbol_local(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- local:
- *;
- };
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.next_line()
- version = parser.parse_version()
- self.assertEqual([], version.symbols)
-
- def test_missing_semicolon(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- foo
- };
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.next_line()
- with self.assertRaises(gsl.ParseError):
- parser.parse_version()
-
- def test_parse_fails_invalid_input(self):
- with self.assertRaises(gsl.ParseError):
- input_file = io.StringIO('foo')
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- parser.parse()
-
- def test_parse(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- local:
- hidden1;
- global:
- foo;
- bar; # baz
- };
-
- VERSION_2 { # wasd
- # Implicit global scope.
- woodly;
- doodly; # asdf
- local:
- qwerty;
- } VERSION_1;
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
- versions = parser.parse()
-
- expected = [
- gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', []),
- gsl.Symbol('bar', ['baz']),
- ]),
- gsl.Version('VERSION_2', 'VERSION_1', ['wasd'], [
- gsl.Symbol('woodly', []),
- gsl.Symbol('doodly', ['asdf']),
- ]),
- ]
-
- self.assertEqual(expected, versions)
-
- def test_parse_llndk_apex_symbol(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- foo;
- bar; # llndk
- baz; # llndk apex
- qux; # apex
- };
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, True)
-
- parser.next_line()
- version = parser.parse_version()
- self.assertEqual('VERSION_1', version.name)
- self.assertIsNone(version.base)
-
- expected_symbols = [
- gsl.Symbol('foo', []),
- gsl.Symbol('bar', ['llndk']),
- gsl.Symbol('baz', ['llndk', 'apex']),
- gsl.Symbol('qux', ['apex']),
- ]
- self.assertEqual(expected_symbols, version.symbols)
-
-
-class GeneratorTest(unittest.TestCase):
- def test_omit_version(self):
- # Thorough testing of the cases involved here is handled by
- # OmitVersionTest, PrivateVersionTest, and SymbolPresenceTest.
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
-
- version = gsl.Version('VERSION_PRIVATE', None, [], [
- gsl.Symbol('foo', []),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- version = gsl.Version('VERSION', None, ['x86'], [
- gsl.Symbol('foo', []),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- version = gsl.Version('VERSION', None, ['introduced=14'], [
- gsl.Symbol('foo', []),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- def test_omit_symbol(self):
- # Thorough testing of the cases involved here is handled by
- # SymbolPresenceTest.
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
-
- version = gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', ['x86']),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- version = gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', ['introduced=14']),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- version = gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', ['llndk']),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- version = gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', ['apex']),
- ])
- generator.write_version(version)
- self.assertEqual('', src_file.getvalue())
- self.assertEqual('', version_file.getvalue())
-
- def test_write(self):
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
-
- versions = [
- gsl.Version('VERSION_1', None, [], [
- gsl.Symbol('foo', []),
- gsl.Symbol('bar', ['var']),
- gsl.Symbol('woodly', ['weak']),
- gsl.Symbol('doodly', ['weak', 'var']),
- ]),
- gsl.Version('VERSION_2', 'VERSION_1', [], [
- gsl.Symbol('baz', []),
- ]),
- gsl.Version('VERSION_3', 'VERSION_1', [], [
- gsl.Symbol('qux', ['versioned=14']),
- ]),
- ]
-
- generator.write(versions)
- expected_src = textwrap.dedent("""\
- void foo() {}
- int bar = 0;
- __attribute__((weak)) void woodly() {}
- __attribute__((weak)) int doodly = 0;
- void baz() {}
- void qux() {}
- """)
- self.assertEqual(expected_src, src_file.getvalue())
-
- expected_version = textwrap.dedent("""\
- VERSION_1 {
- global:
- foo;
- bar;
- woodly;
- doodly;
- };
- VERSION_2 {
- global:
- baz;
- } VERSION_1;
- """)
- self.assertEqual(expected_version, version_file.getvalue())
-
-
-class IntegrationTest(unittest.TestCase):
- def test_integration(self):
- api_map = {
- 'O': 9000,
- 'P': 9001,
- }
-
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- global:
- foo; # var
- bar; # x86
- fizz; # introduced=O
- buzz; # introduced=P
- local:
- *;
- };
-
- VERSION_2 { # arm
- baz; # introduced=9
- qux; # versioned=14
- } VERSION_1;
-
- VERSION_3 { # introduced=14
- woodly;
- doodly; # var
- } VERSION_2;
-
- VERSION_4 { # versioned=9
- wibble;
- wizzes; # llndk
- waggle; # apex
- } VERSION_2;
-
- VERSION_5 { # versioned=14
- wobble;
- } VERSION_4;
- """))
- parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9, False, False)
- versions = parser.parse()
-
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9, False, False)
- generator.write(versions)
-
- expected_src = textwrap.dedent("""\
- int foo = 0;
- void baz() {}
- void qux() {}
- void wibble() {}
- void wobble() {}
- """)
- self.assertEqual(expected_src, src_file.getvalue())
-
- expected_version = textwrap.dedent("""\
- VERSION_1 {
- global:
- foo;
- };
- VERSION_2 {
- global:
- baz;
- } VERSION_1;
- VERSION_4 {
- global:
- wibble;
- } VERSION_2;
- """)
- self.assertEqual(expected_version, version_file.getvalue())
-
- def test_integration_future_api(self):
- api_map = {
- 'O': 9000,
- 'P': 9001,
- 'Q': 9002,
- }
-
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- global:
- foo; # introduced=O
- bar; # introduced=P
- baz; # introduced=Q
- local:
- *;
- };
- """))
- parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9001, False, False)
- versions = parser.parse()
-
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9001, False, False)
- generator.write(versions)
-
- expected_src = textwrap.dedent("""\
- void foo() {}
- void bar() {}
- """)
- self.assertEqual(expected_src, src_file.getvalue())
-
- expected_version = textwrap.dedent("""\
- VERSION_1 {
- global:
- foo;
- bar;
- };
- """)
- self.assertEqual(expected_version, version_file.getvalue())
-
- def test_multiple_definition(self):
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- global:
- foo;
- foo;
- bar;
- baz;
- qux; # arm
- local:
- *;
- };
-
- VERSION_2 {
- global:
- bar;
- qux; # arm64
- } VERSION_1;
-
- VERSION_PRIVATE {
- global:
- baz;
- } VERSION_2;
-
- """))
- parser = gsl.SymbolFileParser(input_file, {}, 'arm', 16, False, False)
-
- with self.assertRaises(gsl.MultiplyDefinedSymbolError) as cm:
- parser.parse()
- self.assertEquals(['bar', 'foo'],
- cm.exception.multiply_defined_symbols)
-
- def test_integration_with_apex(self):
- api_map = {
- 'O': 9000,
- 'P': 9001,
- }
-
- input_file = io.StringIO(textwrap.dedent("""\
- VERSION_1 {
- global:
- foo; # var
- bar; # x86
- fizz; # introduced=O
- buzz; # introduced=P
- local:
- *;
- };
-
- VERSION_2 { # arm
- baz; # introduced=9
- qux; # versioned=14
- } VERSION_1;
-
- VERSION_3 { # introduced=14
- woodly;
- doodly; # var
- } VERSION_2;
-
- VERSION_4 { # versioned=9
- wibble;
- wizzes; # llndk
- waggle; # apex
- bubble; # apex llndk
- duddle; # llndk apex
- } VERSION_2;
-
- VERSION_5 { # versioned=14
- wobble;
- } VERSION_4;
- """))
- parser = gsl.SymbolFileParser(input_file, api_map, 'arm', 9, False, True)
- versions = parser.parse()
-
- src_file = io.StringIO()
- version_file = io.StringIO()
- generator = gsl.Generator(src_file, version_file, 'arm', 9, False, True)
- generator.write(versions)
-
- expected_src = textwrap.dedent("""\
- int foo = 0;
- void baz() {}
- void qux() {}
- void wibble() {}
- void waggle() {}
- void bubble() {}
- void duddle() {}
- void wobble() {}
- """)
- self.assertEqual(expected_src, src_file.getvalue())
-
- expected_version = textwrap.dedent("""\
- VERSION_1 {
- global:
- foo;
- };
- VERSION_2 {
- global:
- baz;
- } VERSION_1;
- VERSION_4 {
- global:
- wibble;
- waggle;
- bubble;
- duddle;
- } VERSION_2;
- """)
- self.assertEqual(expected_version, version_file.getvalue())
-
-def main():
- suite = unittest.TestLoader().loadTestsFromName(__name__)
- unittest.TextTestRunner(verbosity=3).run(suite)
-
-
-if __name__ == '__main__':
- main()
diff --git a/cc/testing.go b/cc/testing.go
index 7a86a8d..52f0829 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -20,8 +20,6 @@
func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) {
RegisterPrebuiltBuildComponents(ctx)
- android.RegisterPrebuiltMutators(ctx)
-
RegisterCCBuildComponents(ctx)
RegisterBinaryBuildComponents(ctx)
RegisterLibraryBuildComponents(ctx)
@@ -30,14 +28,17 @@
ctx.RegisterModuleType("toolchain_library", ToolchainLibraryFactory)
ctx.RegisterModuleType("llndk_library", LlndkLibraryFactory)
ctx.RegisterModuleType("cc_object", ObjectFactory)
+ ctx.RegisterModuleType("cc_genrule", genRuleFactory)
ctx.RegisterModuleType("ndk_prebuilt_shared_stl", NdkPrebuiltSharedStlFactory)
ctx.RegisterModuleType("ndk_prebuilt_object", NdkPrebuiltObjectFactory)
+ ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
}
func GatherRequiredDepsForTest(oses ...android.OsType) string {
ret := `
toolchain_library {
name: "libatomic",
+ defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
native_bridge_supported: true,
@@ -91,6 +92,7 @@
toolchain_library {
name: "libclang_rt.builtins-x86_64-android",
+ defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
native_bridge_supported: true,
@@ -120,6 +122,7 @@
toolchain_library {
name: "libclang_rt.fuzzer-x86_64-android",
+ defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
src: "",
@@ -143,6 +146,7 @@
toolchain_library {
name: "libgcc",
+ defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
src: "",
@@ -150,6 +154,7 @@
toolchain_library {
name: "libgcc_stripped",
+ defaults: ["linux_bionic_supported"],
vendor_available: true,
recovery_available: true,
sdk_version: "current",
@@ -158,6 +163,7 @@
cc_library {
name: "libc",
+ defaults: ["linux_bionic_supported"],
no_libcrt: true,
nocrt: true,
stl: "none",
@@ -174,6 +180,7 @@
}
cc_library {
name: "libm",
+ defaults: ["linux_bionic_supported"],
no_libcrt: true,
nocrt: true,
stl: "none",
@@ -192,8 +199,48 @@
symbol_file: "",
sdk_version: "current",
}
+
+ // Coverage libraries
+ cc_library {
+ name: "libprofile-extras",
+ vendor_available: true,
+ recovery_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ cc_library {
+ name: "libprofile-clang-extras",
+ vendor_available: true,
+ recovery_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ }
+ cc_library {
+ name: "libprofile-extras_ndk",
+ vendor_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ sdk_version: "current",
+ }
+ cc_library {
+ name: "libprofile-clang-extras_ndk",
+ vendor_available: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ stl: "none",
+ notice: "custom_notice",
+ sdk_version: "current",
+ }
+
cc_library {
name: "libdl",
+ defaults: ["linux_bionic_supported"],
no_libcrt: true,
nocrt: true,
stl: "none",
@@ -234,6 +281,7 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -248,6 +296,7 @@
vendor_available: true,
recovery_available: true,
host_supported: true,
+ min_sdk_version: "29",
vndk: {
enabled: true,
support_system_process: true,
@@ -266,6 +315,7 @@
host_supported: false,
vendor_available: true,
recovery_available: true,
+ min_sdk_version: "29",
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -283,10 +333,13 @@
cc_defaults {
name: "crt_defaults",
+ defaults: ["linux_bionic_supported"],
recovery_available: true,
vendor_available: true,
native_bridge_supported: true,
stl: "none",
+ min_sdk_version: "16",
+ crt: true,
apex_available: [
"//apex_available:platform",
"//apex_available:anyapex",
@@ -296,46 +349,26 @@
cc_object {
name: "crtbegin_so",
defaults: ["crt_defaults"],
- recovery_available: true,
- vendor_available: true,
- native_bridge_supported: true,
- stl: "none",
}
cc_object {
name: "crtbegin_dynamic",
defaults: ["crt_defaults"],
- recovery_available: true,
- vendor_available: true,
- native_bridge_supported: true,
- stl: "none",
}
cc_object {
name: "crtbegin_static",
defaults: ["crt_defaults"],
- recovery_available: true,
- vendor_available: true,
- native_bridge_supported: true,
- stl: "none",
}
cc_object {
name: "crtend_so",
defaults: ["crt_defaults"],
- recovery_available: true,
- vendor_available: true,
- native_bridge_supported: true,
- stl: "none",
}
cc_object {
name: "crtend_android",
defaults: ["crt_defaults"],
- recovery_available: true,
- vendor_available: true,
- native_bridge_supported: true,
- stl: "none",
}
cc_library {
@@ -349,45 +382,22 @@
system_shared_libs: [],
}
- cc_library {
- name: "libc.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
+ ndk_library {
+ name: "libc",
+ first_version: "minimum",
+ symbol_file: "libc.map.txt",
}
- cc_library {
- name: "libm.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
+ ndk_library {
+ name: "libm",
+ first_version: "minimum",
+ symbol_file: "libm.map.txt",
}
- cc_library {
- name: "libdl.ndk.current",
- sdk_version: "current",
- stl: "none",
- system_shared_libs: [],
- }
-
- ndk_prebuilt_object {
- name: "ndk_crtbegin_so.27",
- sdk_version: "27",
- }
-
- ndk_prebuilt_object {
- name: "ndk_crtend_so.27",
- sdk_version: "27",
- }
-
- ndk_prebuilt_object {
- name: "ndk_crtbegin_dynamic.27",
- sdk_version: "27",
- }
-
- ndk_prebuilt_object {
- name: "ndk_crtend_android.27",
- sdk_version: "27",
+ ndk_library {
+ name: "libdl",
+ first_version: "minimum",
+ symbol_file: "libdl.map.txt",
}
ndk_prebuilt_shared_stl {
@@ -395,6 +405,7 @@
}
`
+ supportLinuxBionic := false
for _, os := range oses {
if os == android.Fuchsia {
ret += `
@@ -423,7 +434,59 @@
}
`
}
+ if os == android.LinuxBionic {
+ supportLinuxBionic = true
+ ret += `
+ cc_binary {
+ name: "linker",
+ defaults: ["linux_bionic_supported"],
+ recovery_available: true,
+ stl: "none",
+ nocrt: true,
+ static_executable: true,
+ native_coverage: false,
+ system_shared_libs: [],
+ }
+
+ cc_genrule {
+ name: "host_bionic_linker_flags",
+ host_supported: true,
+ device_supported: false,
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+ out: ["linker.flags"],
+ }
+
+ cc_defaults {
+ name: "linux_bionic_supported",
+ host_supported: true,
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+ }
+ `
+ }
}
+
+ if !supportLinuxBionic {
+ ret += `
+ cc_defaults {
+ name: "linux_bionic_supported",
+ }
+ `
+ }
+
return ret
}
@@ -458,13 +521,17 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("cc_fuzz", FuzzFactory)
ctx.RegisterModuleType("cc_test", TestFactory)
+ ctx.RegisterModuleType("cc_test_library", TestLibraryFactory)
ctx.RegisterModuleType("llndk_headers", llndkHeadersFactory)
- ctx.RegisterModuleType("ndk_library", NdkLibraryFactory)
ctx.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("vndk_prebuilt_shared", VndkPrebuiltSharedFactory)
ctx.RegisterModuleType("vndk_libraries_txt", VndkLibrariesTxtFactory)
+ ctx.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
+ ctx.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
+ ctx.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ android.RegisterPrebuiltMutators(ctx)
RegisterRequiredBuildComponentsForTest(ctx)
ctx.RegisterSingletonType("vndk-snapshot", VndkSnapshotSingleton)
ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
diff --git a/cc/tidy.go b/cc/tidy.go
index 364e56c..17471e6 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -109,7 +109,8 @@
tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
}
if len(tidy.Properties.Tidy_checks) > 0 {
- tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",")
+ tidyChecks = tidyChecks + "," + strings.Join(esc(
+ config.ClangRewriteTidyChecks(tidy.Properties.Tidy_checks)), ",")
}
if ctx.Windows() {
// https://b.corp.google.com/issues/120614316
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 042e012..19f5ea4 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -36,8 +36,7 @@
type toolchainLibraryDecorator struct {
*libraryDecorator
-
- stripper
+ stripper Stripper
Properties toolchainLibraryProperties
}
@@ -89,8 +88,8 @@
if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
fileName := ctx.ModuleName() + staticLibraryExtension
outputFile := android.PathForModuleOut(ctx, fileName)
- buildFlags := flagsToBuilderFlags(flags)
- library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags)
+ stripFlags := flagsToStripFlags(flags)
+ library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags)
return outputFile
}
diff --git a/cc/util.go b/cc/util.go
index af26268..40374bf 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -97,9 +97,14 @@
protoOptionsFile: in.protoOptionsFile,
yacc: in.Yacc,
+ lex: in.Lex,
}
}
+func flagsToStripFlags(in Flags) StripFlags {
+ return StripFlags{Toolchain: in.Toolchain}
+}
+
func addPrefix(list []string, prefix string) []string {
for i := range list {
list[i] = prefix + list[i]
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index e9d1c73..85f514c 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -144,7 +144,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &vendorPublicLibraryStubDecorator{
libraryDecorator: library,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index b11b1a8..2819f49 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -80,23 +80,75 @@
}).(*snapshotMap)
}
-type vendorSnapshotLibraryProperties struct {
+type vendorSnapshotBaseProperties struct {
// snapshot version.
Version string
// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64')
Target_arch string
+}
+// vendorSnapshotModuleBase provides common basic functions for all snapshot modules.
+type vendorSnapshotModuleBase struct {
+ baseProperties vendorSnapshotBaseProperties
+ moduleSuffix string
+}
+
+func (p *vendorSnapshotModuleBase) Name(name string) string {
+ return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotModuleBase) NameSuffix() string {
+ versionSuffix := p.version()
+ if p.arch() != "" {
+ versionSuffix += "." + p.arch()
+ }
+
+ return p.moduleSuffix + versionSuffix
+}
+
+func (p *vendorSnapshotModuleBase) version() string {
+ return p.baseProperties.Version
+}
+
+func (p *vendorSnapshotModuleBase) arch() string {
+ return p.baseProperties.Target_arch
+}
+
+func (p *vendorSnapshotModuleBase) isSnapshotPrebuilt() bool {
+ return true
+}
+
+// Call this after creating a snapshot module with module suffix
+// such as vendorSnapshotSharedSuffix
+func (p *vendorSnapshotModuleBase) init(m *Module, suffix string) {
+ p.moduleSuffix = suffix
+ m.AddProperties(&p.baseProperties)
+ android.AddLoadHook(m, func(ctx android.LoadHookContext) {
+ vendorSnapshotLoadHook(ctx, p)
+ })
+}
+
+func vendorSnapshotLoadHook(ctx android.LoadHookContext, p *vendorSnapshotModuleBase) {
+ if p.version() != ctx.DeviceConfig().VndkVersion() {
+ ctx.Module().Disable()
+ return
+ }
+}
+
+type vendorSnapshotLibraryProperties struct {
// Prebuilt file for each arch.
Src *string `android:"arch_variant"`
+ // list of directories that will be added to the include path (using -I).
+ Export_include_dirs []string `android:"arch_variant"`
+
+ // list of directories that will be added to the system path (using -isystem).
+ Export_system_include_dirs []string `android:"arch_variant"`
+
// list of flags that will be used for any module that links against this module.
Export_flags []string `android:"arch_variant"`
- // Check the prebuilt ELF files (e.g. DT_SONAME, DT_NEEDED, resolution of undefined symbols,
- // etc).
- Check_elf_files *bool
-
// Whether this prebuilt needs to depend on sanitize ubsan runtime or not.
Sanitize_ubsan_dep *bool `android:"arch_variant"`
@@ -104,42 +156,24 @@
Sanitize_minimal_dep *bool `android:"arch_variant"`
}
+type snapshotSanitizer interface {
+ isSanitizerEnabled(t sanitizerType) bool
+ setSanitizerVariation(t sanitizerType, enabled bool)
+}
+
type vendorSnapshotLibraryDecorator struct {
+ vendorSnapshotModuleBase
*libraryDecorator
- properties vendorSnapshotLibraryProperties
+ properties vendorSnapshotLibraryProperties
+ sanitizerProperties struct {
+ CfiEnabled bool `blueprint:"mutated"`
+
+ // Library flags for cfi variant.
+ Cfi vendorSnapshotLibraryProperties `android:"arch_variant"`
+ }
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotLibraryDecorator) Name(name string) string {
- return name + p.NameSuffix()
-}
-
-func (p *vendorSnapshotLibraryDecorator) NameSuffix() string {
- versionSuffix := p.version()
- if p.arch() != "" {
- versionSuffix += "." + p.arch()
- }
-
- var linkageSuffix string
- if p.buildShared() {
- linkageSuffix = vendorSnapshotSharedSuffix
- } else if p.buildStatic() {
- linkageSuffix = vendorSnapshotStaticSuffix
- } else {
- linkageSuffix = vendorSnapshotHeaderSuffix
- }
-
- return linkageSuffix + versionSuffix
-}
-
-func (p *vendorSnapshotLibraryDecorator) version() string {
- return p.properties.Version
-}
-
-func (p *vendorSnapshotLibraryDecorator) arch() string {
- return p.properties.Target_arch
-}
-
func (p *vendorSnapshotLibraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
p.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), p.NameSuffix())
return p.libraryDecorator.linkerFlags(ctx, flags)
@@ -165,11 +199,16 @@
return p.libraryDecorator.link(ctx, flags, deps, objs)
}
+ if p.sanitizerProperties.CfiEnabled {
+ p.properties = p.sanitizerProperties.Cfi
+ }
+
if !p.matchesWithDevice(ctx.DeviceConfig()) {
return nil
}
- p.libraryDecorator.exportIncludes(ctx)
+ p.libraryDecorator.reexportDirs(android.PathsForModuleSrc(ctx, p.properties.Export_include_dirs)...)
+ p.libraryDecorator.reexportSystemDirs(android.PathsForModuleSrc(ctx, p.properties.Export_system_include_dirs)...)
p.libraryDecorator.reexportFlags(p.properties.Export_flags...)
in := android.PathForModuleSrc(ctx, *p.properties.Src)
@@ -189,37 +228,43 @@
return in
}
-func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
- return false
-}
-
-func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool {
- return true
-}
-
func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
p.baseInstaller.install(ctx, file)
}
}
-type vendorSnapshotInterface interface {
- version() string
+func (p *vendorSnapshotLibraryDecorator) nativeCoverage() bool {
+ return false
}
-func vendorSnapshotLoadHook(ctx android.LoadHookContext, p vendorSnapshotInterface) {
- if p.version() != ctx.DeviceConfig().VndkVersion() {
- ctx.Module().Disable()
+func (p *vendorSnapshotLibraryDecorator) isSanitizerEnabled(t sanitizerType) bool {
+ switch t {
+ case cfi:
+ return p.sanitizerProperties.Cfi.Src != nil
+ default:
+ return false
+ }
+}
+
+func (p *vendorSnapshotLibraryDecorator) setSanitizerVariation(t sanitizerType, enabled bool) {
+ if !enabled {
+ return
+ }
+ switch t {
+ case cfi:
+ p.sanitizerProperties.CfiEnabled = true
+ default:
return
}
}
-func vendorSnapshotLibrary() (*Module, *vendorSnapshotLibraryDecorator) {
+func vendorSnapshotLibrary(suffix string) (*Module, *vendorSnapshotLibraryDecorator) {
module, library := NewLibrary(android.DeviceSupported)
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
prebuilt := &vendorSnapshotLibraryDecorator{
libraryDecorator: library,
@@ -237,77 +282,47 @@
module.linker = prebuilt
module.installer = prebuilt
+ prebuilt.init(module, suffix)
module.AddProperties(
&prebuilt.properties,
+ &prebuilt.sanitizerProperties,
)
return module, prebuilt
}
func VendorSnapshotSharedFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary()
+ module, prebuilt := vendorSnapshotLibrary(vendorSnapshotSharedSuffix)
prebuilt.libraryDecorator.BuildOnlyShared()
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, prebuilt)
- })
return module.Init()
}
func VendorSnapshotStaticFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary()
+ module, prebuilt := vendorSnapshotLibrary(vendorSnapshotStaticSuffix)
prebuilt.libraryDecorator.BuildOnlyStatic()
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, prebuilt)
- })
return module.Init()
}
func VendorSnapshotHeaderFactory() android.Module {
- module, prebuilt := vendorSnapshotLibrary()
+ module, prebuilt := vendorSnapshotLibrary(vendorSnapshotHeaderSuffix)
prebuilt.libraryDecorator.HeaderOnly()
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, prebuilt)
- })
return module.Init()
}
+var _ snapshotSanitizer = (*vendorSnapshotLibraryDecorator)(nil)
+
type vendorSnapshotBinaryProperties struct {
- // snapshot version.
- Version string
-
- // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
- Target_arch string
-
// Prebuilt file for each arch.
Src *string `android:"arch_variant"`
}
type vendorSnapshotBinaryDecorator struct {
+ vendorSnapshotModuleBase
*binaryDecorator
properties vendorSnapshotBinaryProperties
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotBinaryDecorator) Name(name string) string {
- return name + p.NameSuffix()
-}
-
-func (p *vendorSnapshotBinaryDecorator) NameSuffix() string {
- versionSuffix := p.version()
- if p.arch() != "" {
- versionSuffix += "." + p.arch()
- }
- return vendorSnapshotBinarySuffix + versionSuffix
-}
-
-func (p *vendorSnapshotBinaryDecorator) version() string {
- return p.properties.Version
-}
-
-func (p *vendorSnapshotBinaryDecorator) arch() string {
- return p.properties.Target_arch
-}
-
func (p *vendorSnapshotBinaryDecorator) matchesWithDevice(config android.DeviceConfig) bool {
if config.DeviceArch() != p.arch() {
return false
@@ -325,12 +340,12 @@
}
in := android.PathForModuleSrc(ctx, *p.properties.Src)
- builderFlags := flagsToBuilderFlags(flags)
+ stripFlags := flagsToStripFlags(flags)
p.unstrippedOutputFile = in
binName := in.Base()
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
stripped := android.PathForModuleOut(ctx, "stripped", binName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
@@ -349,8 +364,8 @@
return outputFile
}
-func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool {
- return true
+func (p *vendorSnapshotBinaryDecorator) nativeCoverage() bool {
+ return false
}
func VendorSnapshotBinaryFactory() android.Module {
@@ -372,51 +387,23 @@
module.stl = nil
module.linker = prebuilt
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, prebuilt)
- })
-
+ prebuilt.init(module, vendorSnapshotBinarySuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
type vendorSnapshotObjectProperties struct {
- // snapshot version.
- Version string
-
- // Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
- Target_arch string
-
// Prebuilt file for each arch.
Src *string `android:"arch_variant"`
}
type vendorSnapshotObjectLinker struct {
+ vendorSnapshotModuleBase
objectLinker
properties vendorSnapshotObjectProperties
androidMkVendorSuffix bool
}
-func (p *vendorSnapshotObjectLinker) Name(name string) string {
- return name + p.NameSuffix()
-}
-
-func (p *vendorSnapshotObjectLinker) NameSuffix() string {
- versionSuffix := p.version()
- if p.arch() != "" {
- versionSuffix += "." + p.arch()
- }
- return vendorSnapshotObjectSuffix + versionSuffix
-}
-
-func (p *vendorSnapshotObjectLinker) version() string {
- return p.properties.Version
-}
-
-func (p *vendorSnapshotObjectLinker) arch() string {
- return p.properties.Target_arch
-}
-
func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
if config.DeviceArch() != p.arch() {
return false
@@ -443,10 +430,6 @@
return false
}
-func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool {
- return true
-}
-
func VendorSnapshotObjectFactory() android.Module {
module := newObject()
@@ -457,10 +440,7 @@
}
module.linker = prebuilt
- android.AddLoadHook(module, func(ctx android.LoadHookContext) {
- vendorSnapshotLoadHook(ctx, prebuilt)
- })
-
+ prebuilt.init(module, vendorSnapshotObjectSuffix)
module.AddProperties(&prebuilt.properties)
return module.Init()
}
@@ -484,18 +464,22 @@
var (
// Modules under following directories are ignored. They are OEM's and vendor's
- // proprietary modules(device/, vendor/, and hardware/).
+ // proprietary modules(device/, kernel/, vendor/, and hardware/).
// TODO(b/65377115): Clean up these with more maintainable way
vendorProprietaryDirs = []string{
"device",
+ "kernel",
"vendor",
"hardware",
}
// Modules under following directories are included as they are in AOSP,
- // although hardware/ is normally for vendor's own.
+ // although hardware/ and kernel/ are normally for vendor's own.
// TODO(b/65377115): Clean up these with more maintainable way
aospDirsUnderProprietary = []string{
+ "kernel/configs",
+ "kernel/prebuilts",
+ "kernel/tests",
"hardware/interfaces",
"hardware/libhardware",
"hardware/libhardware_legacy",
@@ -524,18 +508,51 @@
return false
}
+func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
+
+ // Any module in a vendor proprietary path is a vendor proprietary
+ // module.
+
+ if isVendorProprietaryPath(ctx.ModuleDir()) {
+ return true
+ }
+
+ // However if the module is not in a vendor proprietary path, it may
+ // still be a vendor proprietary module. This happens for cc modules
+ // that are excluded from the vendor snapshot, and it means that the
+ // vendor has assumed control of the framework-provided module.
+
+ if c, ok := ctx.Module().(*Module); ok {
+ if c.ExcludeFromVendorSnapshot() {
+ return true
+ }
+ }
+
+ return false
+}
+
// Determine if a module is going to be included in vendor snapshot or not.
//
// Targets of vendor snapshot are "vendor: true" or "vendor_available: true" modules in
// AOSP. They are not guaranteed to be compatible with older vendor images. (e.g. might
// depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
// image and newer system image altogether.
-func isVendorSnapshotModule(m *Module, moduleDir string) bool {
+func isVendorSnapshotModule(m *Module, inVendorProprietaryPath bool) bool {
if !m.Enabled() || m.Properties.HideFromMake {
return false
}
+ // When android/prebuilt.go selects between source and prebuilt, it sets
+ // SkipInstall on the other one to avoid duplicate install rules in make.
+ if m.IsSkipInstall() {
+ return false
+ }
// skip proprietary modules, but include all VNDK (static)
- if isVendorProprietaryPath(moduleDir) && !m.IsVndk() {
+ if inVendorProprietaryPath && !m.IsVndk() {
+ return false
+ }
+ // If the module would be included based on its path, check to see if
+ // the module is marked to be excluded. If so, skip it.
+ if m.ExcludeFromVendorSnapshot() {
return false
}
if m.Target().Os.Class != android.Device {
@@ -552,18 +569,29 @@
if _, ok := m.linker.(*kernelHeadersDecorator); ok {
return false
}
+ // skip llndk_library and llndk_headers which are backward compatible
+ if _, ok := m.linker.(*llndkStubDecorator); ok {
+ return false
+ }
+ if _, ok := m.linker.(*llndkHeadersDecorator); ok {
+ return false
+ }
// Libraries
if l, ok := m.linker.(snapshotLibraryInterface); ok {
// TODO(b/65377115): add full support for sanitizer
if m.sanitize != nil {
- // cfi, scs and hwasan export both sanitized and unsanitized variants for static and header
+ // scs and hwasan export both sanitized and unsanitized variants for static and header
// Always use unsanitized variants of them.
- for _, t := range []sanitizerType{cfi, scs, hwasan} {
+ for _, t := range []sanitizerType{scs, hwasan} {
if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
return false
}
}
+ // cfi also exports both variants. But for static, we capture both.
+ if !l.static() && !l.shared() && m.sanitize.isSanitizerEnabled(cfi) {
+ return false
+ }
}
if l.static() {
return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
@@ -657,6 +685,7 @@
ExportedDirs []string `json:",omitempty"`
ExportedSystemDirs []string `json:",omitempty"`
ExportedFlags []string `json:",omitempty"`
+ Sanitize string `json:",omitempty"`
SanitizeMinimalDep bool `json:",omitempty"`
SanitizeUbsanDep bool `json:",omitempty"`
@@ -706,6 +735,7 @@
var propOut string
if l, ok := m.linker.(snapshotLibraryInterface); ok {
+
// library flags
prop.ExportedFlags = l.exportedFlags()
for _, dir := range l.exportedDirs() {
@@ -738,6 +768,15 @@
if libType != "header" {
libPath := m.outputFile.Path()
stem = libPath.Base()
+ if l.static() && m.sanitize != nil && m.sanitize.isSanitizerEnabled(cfi) {
+ // both cfi and non-cfi variant for static libraries can exist.
+ // attach .cfi to distinguish between cfi and non-cfi.
+ // e.g. libbase.a -> libbase.cfi.a
+ ext := filepath.Ext(stem)
+ stem = strings.TrimSuffix(stem, ext) + ".cfi" + ext
+ prop.Sanitize = "cfi"
+ prop.ModuleName += ".cfi"
+ }
snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
} else {
@@ -785,7 +824,25 @@
}
moduleDir := ctx.ModuleDir(module)
- if !isVendorSnapshotModule(m, moduleDir) {
+ inVendorProprietaryPath := isVendorProprietaryPath(moduleDir)
+
+ if m.ExcludeFromVendorSnapshot() {
+ if inVendorProprietaryPath {
+ // Error: exclude_from_vendor_snapshot applies
+ // to framework-path modules only.
+ ctx.Errorf("module %q in vendor proprietary path %q may not use \"exclude_from_vendor_snapshot: true\"", m.String(), moduleDir)
+ return
+ }
+ if Bool(m.VendorProperties.Vendor_available) {
+ // Error: may not combine "vendor_available:
+ // true" with "exclude_from_vendor_snapshot:
+ // true".
+ ctx.Errorf("module %q may not use both \"vendor_available: true\" and \"exclude_from_vendor_snapshot: true\"", m.String())
+ return
+ }
+ }
+
+ if !isVendorSnapshotModule(m, inVendorProprietaryPath) {
return
}
@@ -794,14 +851,14 @@
headers = append(headers, l.snapshotHeaders()...)
}
- if m.NoticeFile().Valid() {
+ if len(m.NoticeFiles()) > 0 {
noticeName := ctx.ModuleName(m) + ".txt"
noticeOut := filepath.Join(noticeDir, noticeName)
// skip already copied notice file
if !installedNotices[noticeOut] {
installedNotices[noticeOut] = true
- snapshotOutputs = append(snapshotOutputs, copyFile(
- ctx, m.NoticeFile().Path(), noticeOut))
+ snapshotOutputs = append(snapshotOutputs, combineNotices(
+ ctx, m.NoticeFiles(), noticeOut))
}
}
})
diff --git a/cc/vndk.go b/cc/vndk.go
index a060869..9a2fa09 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -26,6 +26,8 @@
"android/soong/android"
"android/soong/cc/config"
"android/soong/etc"
+
+ "github.com/google/blueprint"
)
const (
@@ -127,7 +129,7 @@
return "native:vendor:vndkspext"
}
-func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag DependencyTag) {
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag blueprint.DependencyTag) {
if to.linker == nil {
return
}
@@ -310,7 +312,13 @@
panic(err)
}
- if m.HasStubsVariants() {
+ if m.HasStubsVariants() && name != "libz" {
+ // b/155456180 libz is the ONLY exception here. We don't want to make
+ // libz an LLNDK library because we in general can't guarantee that
+ // libz will behave consistently especially about the compression.
+ // i.e. the compressed output might be different across releases.
+ // As the library is an external one, it's risky to keep the compatibility
+ // promise if it becomes an LLNDK.
mctx.PropertyErrorf("vndk.enabled", "This library provides stubs. Shouldn't be VNDK. Consider making it as LLNDK")
}
@@ -334,7 +342,7 @@
}
}
-// Sanity check for modules that mustn't be VNDK
+// Check for modules that mustn't be VNDK
func shouldSkipVndkMutator(m *Module) bool {
if !m.Enabled() {
return true
@@ -497,18 +505,25 @@
}}
}
+// PrebuiltEtcModule interface
func (txt *vndkLibrariesTxt) OutputFile() android.OutputPath {
return txt.outputFile
}
-func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
- return android.Paths{txt.outputFile}, nil
+// PrebuiltEtcModule interface
+func (txt *vndkLibrariesTxt) BaseDir() string {
+ return "etc"
}
+// PrebuiltEtcModule interface
func (txt *vndkLibrariesTxt) SubDir() string {
return ""
}
+func (txt *vndkLibrariesTxt) OutputFiles(tag string) (android.Paths, error) {
+ return android.Paths{txt.outputFile}, nil
+}
+
func VndkSnapshotSingleton() android.Singleton {
return &vndkSnapshotSingleton{}
}
@@ -553,10 +568,6 @@
return
}
- if ctx.DeviceConfig().BoardVndkRuntimeDisable() {
- return
- }
-
var snapshotOutputs android.Paths
/*
@@ -666,13 +677,13 @@
moduleNames[stem] = ctx.ModuleName(m)
modulePaths[stem] = ctx.ModuleDir(m)
- if m.NoticeFile().Valid() {
+ if len(m.NoticeFiles()) > 0 {
noticeName := stem + ".txt"
// skip already copied notice file
if _, ok := noticeBuilt[noticeName]; !ok {
noticeBuilt[noticeName] = true
- snapshotOutputs = append(snapshotOutputs, copyFile(
- ctx, m.NoticeFile().Path(), filepath.Join(noticeDir, noticeName)))
+ snapshotOutputs = append(snapshotOutputs, combineNotices(
+ ctx, m.NoticeFiles(), filepath.Join(noticeDir, noticeName)))
}
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 5a44c46..9484760 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -142,9 +142,10 @@
builderFlags := flagsToBuilderFlags(flags)
p.unstrippedOutputFile = in
libName := in.Base()
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
stripped := android.PathForModuleOut(ctx, "stripped", libName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
@@ -213,7 +214,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
prebuilt := &vndkPrebuiltLibraryDecorator{
libraryDecorator: library,
diff --git a/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp
index 5397f4b..bc6b068 100644
--- a/cmd/diff_target_files/Android.bp
+++ b/cmd/diff_target_files/Android.bp
@@ -5,12 +5,12 @@
"diff_target_files.go",
"glob.go",
"target_files.go",
- "whitelist.go",
+ "allow_list.go",
"zip_artifact.go",
],
testSrcs: [
"compare_test.go",
"glob_test.go",
- "whitelist_test.go",
+ "allow_list_test.go",
],
}
diff --git a/cmd/diff_target_files/whitelist.go b/cmd/diff_target_files/allow_list.go
similarity index 77%
rename from cmd/diff_target_files/whitelist.go
rename to cmd/diff_target_files/allow_list.go
index f00fc1e..ca55b43 100644
--- a/cmd/diff_target_files/whitelist.go
+++ b/cmd/diff_target_files/allow_list.go
@@ -25,18 +25,13 @@
"unicode"
)
-type jsonWhitelist struct {
- Paths []string
- IgnoreMatchingLines []string
-}
-
-type whitelist struct {
+type allowList struct {
path string
ignoreMatchingLines []string
}
-func parseWhitelists(whitelists []string, whitelistFiles []string) ([]whitelist, error) {
- var ret []whitelist
+func parseAllowLists(allowLists []string, allowListFiles []string) ([]allowList, error) {
+ var ret []allowList
add := func(path string, ignoreMatchingLines []string) {
for _, x := range ret {
@@ -46,24 +41,24 @@
}
}
- ret = append(ret, whitelist{
+ ret = append(ret, allowList{
path: path,
ignoreMatchingLines: ignoreMatchingLines,
})
}
- for _, file := range whitelistFiles {
- newWhitelists, err := parseWhitelistFile(file)
+ for _, file := range allowListFiles {
+ newAllowlists, err := parseAllowListFile(file)
if err != nil {
return nil, err
}
- for _, w := range newWhitelists {
+ for _, w := range newAllowlists {
add(w.path, w.ignoreMatchingLines)
}
}
- for _, s := range whitelists {
+ for _, s := range allowLists {
colon := strings.IndexRune(s, ':')
var ignoreMatchingLines []string
if colon >= 0 {
@@ -75,7 +70,7 @@
return ret, nil
}
-func parseWhitelistFile(file string) ([]whitelist, error) {
+func parseAllowListFile(file string) ([]allowList, error) {
r, err := os.Open(file)
if err != nil {
return nil, err
@@ -84,27 +79,32 @@
d := json.NewDecoder(newJSONCommentStripper(r))
- var jsonWhitelists []jsonWhitelist
+ var jsonAllowLists []struct {
+ Paths []string
+ IgnoreMatchingLines []string
+ }
- err = d.Decode(&jsonWhitelists)
+ if err := d.Decode(&jsonAllowLists); err != nil {
+ return nil, err
+ }
- var whitelists []whitelist
- for _, w := range jsonWhitelists {
+ var allowLists []allowList
+ for _, w := range jsonAllowLists {
for _, p := range w.Paths {
- whitelists = append(whitelists, whitelist{
+ allowLists = append(allowLists, allowList{
path: p,
ignoreMatchingLines: w.IgnoreMatchingLines,
})
}
}
- return whitelists, err
+ return allowLists, err
}
-func filterModifiedPaths(l [][2]*ZipArtifactFile, whitelists []whitelist) ([][2]*ZipArtifactFile, error) {
+func filterModifiedPaths(l [][2]*ZipArtifactFile, allowLists []allowList) ([][2]*ZipArtifactFile, error) {
outer:
for i := 0; i < len(l); i++ {
- for _, w := range whitelists {
+ for _, w := range allowLists {
if match, err := Match(w.path, l[i][0].Name); err != nil {
return l, err
} else if match {
@@ -126,10 +126,10 @@
return l, nil
}
-func filterNewPaths(l []*ZipArtifactFile, whitelists []whitelist) ([]*ZipArtifactFile, error) {
+func filterNewPaths(l []*ZipArtifactFile, allowLists []allowList) ([]*ZipArtifactFile, error) {
outer:
for i := 0; i < len(l); i++ {
- for _, w := range whitelists {
+ for _, w := range allowLists {
if match, err := Match(w.path, l[i].Name); err != nil {
return l, err
} else if match && len(w.ignoreMatchingLines) == 0 {
@@ -192,18 +192,18 @@
return bytes.Compare(bufA, bufB) == 0, nil
}
-func applyWhitelists(diff zipDiff, whitelists []whitelist) (zipDiff, error) {
+func applyAllowLists(diff zipDiff, allowLists []allowList) (zipDiff, error) {
var err error
- diff.modified, err = filterModifiedPaths(diff.modified, whitelists)
+ diff.modified, err = filterModifiedPaths(diff.modified, allowLists)
if err != nil {
return diff, err
}
- diff.onlyInA, err = filterNewPaths(diff.onlyInA, whitelists)
+ diff.onlyInA, err = filterNewPaths(diff.onlyInA, allowLists)
if err != nil {
return diff, err
}
- diff.onlyInB, err = filterNewPaths(diff.onlyInB, whitelists)
+ diff.onlyInB, err = filterNewPaths(diff.onlyInB, allowLists)
if err != nil {
return diff, err
}
diff --git a/cmd/diff_target_files/whitelist_test.go b/cmd/diff_target_files/allow_list_test.go
similarity index 82%
rename from cmd/diff_target_files/whitelist_test.go
rename to cmd/diff_target_files/allow_list_test.go
index 4b19fdd..8410e5a 100644
--- a/cmd/diff_target_files/whitelist_test.go
+++ b/cmd/diff_target_files/allow_list_test.go
@@ -57,10 +57,10 @@
var f2 = bytesToZipArtifactFile("dir/f2", nil)
-func Test_applyWhitelists(t *testing.T) {
+func Test_applyAllowLists(t *testing.T) {
type args struct {
diff zipDiff
- whitelists []whitelist
+ allowLists []allowList
}
tests := []struct {
name string
@@ -74,7 +74,7 @@
diff: zipDiff{
onlyInA: []*ZipArtifactFile{f1a, f2},
},
- whitelists: []whitelist{{path: "dir/f1"}},
+ allowLists: []allowList{{path: "dir/f1"}},
},
want: zipDiff{
onlyInA: []*ZipArtifactFile{f2},
@@ -86,7 +86,7 @@
diff: zipDiff{
onlyInA: []*ZipArtifactFile{f1a, f2},
},
- whitelists: []whitelist{{path: "dir/*"}},
+ allowLists: []allowList{{path: "dir/*"}},
},
want: zipDiff{},
},
@@ -96,7 +96,7 @@
diff: zipDiff{
modified: [][2]*ZipArtifactFile{{f1a, f1b}},
},
- whitelists: []whitelist{{path: "dir/*"}},
+ allowLists: []allowList{{path: "dir/*"}},
},
want: zipDiff{},
},
@@ -106,20 +106,20 @@
diff: zipDiff{
modified: [][2]*ZipArtifactFile{{f1a, f1b}},
},
- whitelists: []whitelist{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}},
+ allowLists: []allowList{{path: "dir/*", ignoreMatchingLines: []string{"foo: .*"}}},
},
want: zipDiff{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- got, err := applyWhitelists(tt.args.diff, tt.args.whitelists)
+ got, err := applyAllowLists(tt.args.diff, tt.args.allowLists)
if (err != nil) != tt.wantErr {
- t.Errorf("applyWhitelists() error = %v, wantErr %v", err, tt.wantErr)
+ t.Errorf("Test_applyAllowLists() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
- t.Errorf("applyWhitelists() = %v, want %v", got, tt.want)
+ t.Errorf("Test_applyAllowLists() = %v, want %v", got, tt.want)
}
})
}
diff --git a/cmd/diff_target_files/compare.go b/cmd/diff_target_files/compare.go
index 00cd9ca..45b6d6b 100644
--- a/cmd/diff_target_files/compare.go
+++ b/cmd/diff_target_files/compare.go
@@ -21,7 +21,7 @@
// compareTargetFiles takes two ZipArtifacts and compares the files they contain by examining
// the path, size, and CRC of each file.
-func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, whitelists []whitelist, filters []string) (zipDiff, error) {
+func compareTargetFiles(priZip, refZip ZipArtifact, artifact string, allowLists []allowList, filters []string) (zipDiff, error) {
priZipFiles, err := priZip.Files()
if err != nil {
return zipDiff{}, fmt.Errorf("error fetching target file lists from primary zip %v", err)
@@ -45,7 +45,7 @@
// Compare the file lists from both builds
diff := diffTargetFilesLists(refZipFiles, priZipFiles)
- return applyWhitelists(diff, whitelists)
+ return applyAllowLists(diff, allowLists)
}
// zipDiff contains the list of files that differ between two zip files.
diff --git a/cmd/diff_target_files/diff_target_files.go b/cmd/diff_target_files/diff_target_files.go
index 75bc8ee..634565b 100644
--- a/cmd/diff_target_files/diff_target_files.go
+++ b/cmd/diff_target_files/diff_target_files.go
@@ -22,8 +22,8 @@
)
var (
- whitelists = newMultiString("whitelist", "whitelist patterns in the form <pattern>[:<regex of line to ignore>]")
- whitelistFiles = newMultiString("whitelist_file", "files containing whitelist definitions")
+ allowLists = newMultiString("allowlist", "allowlist patterns in the form <pattern>[:<regex of line to ignore>]")
+ allowListFiles = newMultiString("allowlist_file", "files containing allowlist definitions")
filters = newMultiString("filter", "filter patterns to apply to files in target-files.zip before comparing")
)
@@ -47,9 +47,9 @@
os.Exit(1)
}
- whitelists, err := parseWhitelists(*whitelists, *whitelistFiles)
+ allowLists, err := parseAllowLists(*allowLists, *allowListFiles)
if err != nil {
- fmt.Fprintf(os.Stderr, "Error parsing whitelists: %v\n", err)
+ fmt.Fprintf(os.Stderr, "Error parsing allowlists: %v\n", err)
os.Exit(1)
}
@@ -67,7 +67,7 @@
}
defer refZip.Close()
- diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, whitelists, *filters)
+ diff, err := compareTargetFiles(priZip, refZip, targetFilesPattern, allowLists, *filters)
if err != nil {
fmt.Fprintf(os.Stderr, "Error comparing zip files: %v\n", err)
os.Exit(1)
diff --git a/cmd/extract_apks/Android.bp b/cmd/extract_apks/Android.bp
index 90548cd..f8fe864 100644
--- a/cmd/extract_apks/Android.bp
+++ b/cmd/extract_apks/Android.bp
@@ -6,7 +6,7 @@
"golang-protobuf-proto",
"soong-cmd-extract_apks-proto",
],
- testSrcs: ["main_test.go"]
+ testSrcs: ["main_test.go"],
}
bootstrap_go_package {
diff --git a/cmd/extract_jar_packages/Android.bp b/cmd/extract_jar_packages/Android.bp
index ea0cbbf..4ea8798 100644
--- a/cmd/extract_jar_packages/Android.bp
+++ b/cmd/extract_jar_packages/Android.bp
@@ -22,4 +22,3 @@
"extract_jar_packages.go",
],
}
-
diff --git a/cmd/extract_linker/Android.bp b/cmd/extract_linker/Android.bp
index fe76ae4..690c4fa 100644
--- a/cmd/extract_linker/Android.bp
+++ b/cmd/extract_linker/Android.bp
@@ -17,4 +17,3 @@
srcs: ["main.go"],
testSrcs: ["main_test.go"],
}
-
diff --git a/cmd/host_bionic_inject/host_bionic_inject.go b/cmd/host_bionic_inject/host_bionic_inject.go
index f7163d7..629f6cc 100644
--- a/cmd/host_bionic_inject/host_bionic_inject.go
+++ b/cmd/host_bionic_inject/host_bionic_inject.go
@@ -105,7 +105,9 @@
err = checkLinker(file, linker, symbols)
if err != nil {
- return 0, err
+ return 0, fmt.Errorf("Linker executable failed verification against app embedded linker: %s\n"+
+ "linker might not be in sync with crtbegin_dynamic.o.",
+ err)
}
start, err := findSymbol(symbols, "_start")
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
index f70c86e..8c97b6d 100644
--- a/cmd/merge_zips/Android.bp
+++ b/cmd/merge_zips/Android.bp
@@ -15,10 +15,10 @@
blueprint_go_binary {
name: "merge_zips",
deps: [
- "android-archive-zip",
- "blueprint-pathtools",
- "soong-jar",
- "soong-zip",
+ "android-archive-zip",
+ "blueprint-pathtools",
+ "soong-jar",
+ "soong-zip",
],
srcs: [
"merge_zips.go",
@@ -27,4 +27,3 @@
"merge_zips_test.go",
],
}
-
diff --git a/cmd/merge_zips/merge_zips.go b/cmd/merge_zips/merge_zips.go
index a95aca9..274c8ee 100644
--- a/cmd/merge_zips/merge_zips.go
+++ b/cmd/merge_zips/merge_zips.go
@@ -429,7 +429,7 @@
if maxOpenZips < 3 {
panic(fmt.Errorf("open zips limit should be above 3"))
}
- // In the dummy element .older points to the most recently opened InputZip, and .newer points to the oldest.
+ // In the fake element .older points to the most recently opened InputZip, and .newer points to the oldest.
head := new(ManagedInputZip)
head.older = head
head.newer = head
diff --git a/cmd/path_interposer/main.go b/cmd/path_interposer/main.go
index cd28b96..a4fe3e4 100644
--- a/cmd/path_interposer/main.go
+++ b/cmd/path_interposer/main.go
@@ -53,14 +53,7 @@
os.Exit(1)
}
- disableError := false
- if e, ok := os.LookupEnv("TEMPORARY_DISABLE_PATH_RESTRICTIONS"); ok {
- disableError = e == "1" || e == "y" || e == "yes" || e == "on" || e == "true"
- }
-
exitCode, err := Main(os.Stdout, os.Stderr, interposer, os.Args, mainOpts{
- disableError: disableError,
-
sendLog: paths.SendLog,
config: paths.GetConfig,
lookupParents: lookupParents,
@@ -79,8 +72,6 @@
socket at <interposer>_log.`)
type mainOpts struct {
- disableError bool
-
sendLog func(logSocket string, entry *paths.LogEntry, done chan interface{})
config func(name string) paths.PathConfig
lookupParents func() []paths.LogProcess
@@ -131,7 +122,7 @@
}, waitForLog)
defer func() { <-waitForLog }()
}
- if config.Error && !opts.disableError {
+ if config.Error {
return 1, fmt.Errorf("%q is not allowed to be used. See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.", base)
}
}
diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp
index a706810d..6fa304e 100644
--- a/cmd/sbox/Android.bp
+++ b/cmd/sbox/Android.bp
@@ -19,4 +19,3 @@
"sbox.go",
],
}
-
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 2536a53..4ebbe68 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -17,14 +17,19 @@
deps: [
"blueprint",
"blueprint-bootstrap",
+ "golang-protobuf-proto",
"soong",
"soong-android",
"soong-env",
+ "soong-ui-metrics_proto",
],
srcs: [
"main.go",
"writedocs.go",
+ "bazel_overlay.go",
+ ],
+ testSrcs: [
+ "bazel_overlay_test.go",
],
primaryBuilder: true,
}
-
diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go
new file mode 100644
index 0000000..72e0fbd
--- /dev/null
+++ b/cmd/soong_build/bazel_overlay.go
@@ -0,0 +1,636 @@
+// Copyright 2020 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 main
+
+import (
+ "android/soong/android"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/bootstrap/bpdoc"
+ "github.com/google/blueprint/proptools"
+)
+
+const (
+ // The default `load` preamble for every generated BUILD file.
+ soongModuleLoad = `package(default_visibility = ["//visibility:public"])
+load("//:soong_module.bzl", "soong_module")
+
+`
+
+ // A macro call in the BUILD file representing a Soong module, with space
+ // for expanding more attributes.
+ soongModuleTarget = `soong_module(
+ name = "%s",
+ module_name = "%s",
+ module_type = "%s",
+ module_variant = "%s",
+ module_deps = %s,
+%s)`
+
+ // A simple provider to mark and differentiate Soong module rule shims from
+ // regular Bazel rules. Every Soong module rule shim returns a
+ // SoongModuleInfo provider, and can only depend on rules returning
+ // SoongModuleInfo in the `module_deps` attribute.
+ providersBzl = `SoongModuleInfo = provider(
+ fields = {
+ "name": "Name of module",
+ "type": "Type of module",
+ "variant": "Variant of module",
+ },
+)
+`
+
+ // The soong_module rule implementation in a .bzl file.
+ soongModuleBzl = `
+%s
+
+load(":providers.bzl", "SoongModuleInfo")
+
+def _generic_soong_module_impl(ctx):
+ return [
+ SoongModuleInfo(
+ name = ctx.attr.module_name,
+ type = ctx.attr.module_type,
+ variant = ctx.attr.module_variant,
+ ),
+ ]
+
+generic_soong_module = rule(
+ implementation = _generic_soong_module_impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_type": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ },
+)
+
+soong_module_rule_map = {
+%s}
+
+_SUPPORTED_TYPES = ["bool", "int", "string"]
+
+def _is_supported_type(value):
+ if type(value) in _SUPPORTED_TYPES:
+ return True
+ elif type(value) == "list":
+ supported = True
+ for v in value:
+ supported = supported and type(v) in _SUPPORTED_TYPES
+ return supported
+ else:
+ return False
+
+# soong_module is a macro that supports arbitrary kwargs, and uses module_type to
+# expand to the right underlying shim.
+def soong_module(name, module_type, **kwargs):
+ soong_module_rule = soong_module_rule_map.get(module_type)
+
+ if soong_module_rule == None:
+ # This module type does not have an existing rule to map to, so use the
+ # generic_soong_module rule instead.
+ generic_soong_module(
+ name = name,
+ module_type = module_type,
+ module_name = kwargs.pop("module_name", ""),
+ module_variant = kwargs.pop("module_variant", ""),
+ module_deps = kwargs.pop("module_deps", []),
+ )
+ else:
+ supported_kwargs = dict()
+ for key, value in kwargs.items():
+ if _is_supported_type(value):
+ supported_kwargs[key] = value
+ soong_module_rule(
+ name = name,
+ **supported_kwargs,
+ )
+`
+
+ // A rule shim for representing a Soong module type and its properties.
+ moduleRuleShim = `
+def _%[1]s_impl(ctx):
+ return [SoongModuleInfo()]
+
+%[1]s = rule(
+ implementation = _%[1]s_impl,
+ attrs = %[2]s
+)
+`
+)
+
+var (
+ // An allowlist of prop types that are surfaced from module props to rule
+ // attributes. (nested) dictionaries are notably absent here, because while
+ // Soong supports multi value typed and nested dictionaries, Bazel's rule
+ // attr() API supports only single-level string_dicts.
+ allowedPropTypes = map[string]bool{
+ "int": true, // e.g. 42
+ "bool": true, // e.g. True
+ "string_list": true, // e.g. ["a", "b"]
+ "string": true, // e.g. "a"
+ }
+
+ // TODO(b/166563303): Specific properties of some module types aren't
+ // recognized by the documentation generator. As a workaround, hardcode a
+ // mapping of the module type to prop name to prop type here, and ultimately
+ // fix the documentation generator to also parse these properties correctly.
+ additionalPropTypes = map[string]map[string]string{
+ // sdk and module_exports props are created at runtime using reflection.
+ // bpdocs isn't wired up to read runtime generated structs.
+ "sdk": {
+ "java_header_libs": "string_list",
+ "java_sdk_libs": "string_list",
+ "java_system_modules": "string_list",
+ "native_header_libs": "string_list",
+ "native_libs": "string_list",
+ "native_objects": "string_list",
+ "native_shared_libs": "string_list",
+ "native_static_libs": "string_list",
+ },
+ "module_exports": {
+ "java_libs": "string_list",
+ "java_tests": "string_list",
+ "native_binaries": "string_list",
+ "native_shared_libs": "string_list",
+ },
+ }
+
+ // Certain module property names are blocklisted/ignored here, for the reasons commented.
+ ignoredPropNames = map[string]bool{
+ "name": true, // redundant, since this is explicitly generated for every target
+ "from": true, // reserved keyword
+ "in": true, // reserved keyword
+ "arch": true, // interface prop type is not supported yet.
+ "multilib": true, // interface prop type is not supported yet.
+ "target": true, // interface prop type is not supported yet.
+ "visibility": true, // Bazel has native visibility semantics. Handle later.
+ "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
+ }
+)
+
+func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string {
+ name := ""
+ if c.ModuleSubDir(logicModule) != "" {
+ // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes.
+ name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule)
+ } else {
+ name = c.ModuleName(logicModule)
+ }
+
+ return strings.Replace(name, "//", "", 1)
+}
+
+func qualifiedTargetLabel(c *blueprint.Context, logicModule blueprint.Module) string {
+ return "//" +
+ packagePath(c, logicModule) +
+ ":" +
+ targetNameWithVariant(c, logicModule)
+}
+
+func packagePath(c *blueprint.Context, logicModule blueprint.Module) string {
+ return filepath.Dir(c.BlueprintFile(logicModule))
+}
+
+func escapeString(s string) string {
+ s = strings.ReplaceAll(s, "\\", "\\\\")
+ return strings.ReplaceAll(s, "\"", "\\\"")
+}
+
+func makeIndent(indent int) string {
+ if indent < 0 {
+ panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent))
+ }
+ return strings.Repeat(" ", indent)
+}
+
+// prettyPrint a property value into the equivalent Starlark representation
+// recursively.
+func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
+ if isZero(propertyValue) {
+ // A property value being set or unset actually matters -- Soong does set default
+ // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
+ // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
+ //
+ // In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default
+ // value of unset attributes.
+ return "", nil
+ }
+
+ var ret string
+ switch propertyValue.Kind() {
+ case reflect.String:
+ ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String()))
+ case reflect.Bool:
+ ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface()))
+ case reflect.Int, reflect.Uint, reflect.Int64:
+ ret = fmt.Sprintf("%v", propertyValue.Interface())
+ case reflect.Ptr:
+ return prettyPrint(propertyValue.Elem(), indent)
+ case reflect.Slice:
+ ret = "[\n"
+ for i := 0; i < propertyValue.Len(); i++ {
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if err != nil {
+ return "", err
+ }
+
+ if indexedValue != "" {
+ ret += makeIndent(indent + 1)
+ ret += indexedValue
+ ret += ",\n"
+ }
+ }
+ ret += makeIndent(indent)
+ ret += "]"
+ case reflect.Struct:
+ ret = "{\n"
+ // Sort and print the struct props by the key.
+ structProps := extractStructProperties(propertyValue, indent)
+ for _, k := range android.SortedStringKeys(structProps) {
+ ret += makeIndent(indent + 1)
+ ret += fmt.Sprintf("%q: %s,\n", k, structProps[k])
+ }
+ ret += makeIndent(indent)
+ ret += "}"
+ case reflect.Interface:
+ // TODO(b/164227191): implement pretty print for interfaces.
+ // Interfaces are used for for arch, multilib and target properties.
+ return "", nil
+ default:
+ return "", fmt.Errorf(
+ "unexpected kind for property struct field: %s", propertyValue.Kind())
+ }
+ return ret, nil
+}
+
+// Converts a reflected property struct value into a map of property names and property values,
+// which each property value correctly pretty-printed and indented at the right nest level,
+// since property structs can be nested. In Starlark, nested structs are represented as nested
+// dicts: https://docs.bazel.build/skylark/lib/dict.html
+func extractStructProperties(structValue reflect.Value, indent int) map[string]string {
+ if structValue.Kind() != reflect.Struct {
+ panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind()))
+ }
+
+ ret := map[string]string{}
+ structType := structValue.Type()
+ for i := 0; i < structValue.NumField(); i++ {
+ field := structType.Field(i)
+ if field.PkgPath != "" {
+ // Skip unexported fields. Some properties are
+ // internal to Soong only, and these fields do not have PkgPath.
+ continue
+ }
+ if proptools.HasTag(field, "blueprint", "mutated") {
+ continue
+ }
+
+ fieldValue := structValue.Field(i)
+ if isZero(fieldValue) {
+ // Ignore zero-valued fields
+ continue
+ }
+
+ propertyName := proptools.PropertyNameForField(field.Name)
+ prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
+ if err != nil {
+ panic(
+ fmt.Errorf(
+ "Error while parsing property: %q. %s",
+ propertyName,
+ err))
+ }
+ if prettyPrintedValue != "" {
+ ret[propertyName] = prettyPrintedValue
+ }
+ }
+
+ return ret
+}
+
+func isStructPtr(t reflect.Type) bool {
+ return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
+}
+
+// Generically extract module properties and types into a map, keyed by the module property name.
+func extractModuleProperties(aModule android.Module) map[string]string {
+ ret := map[string]string{}
+
+ // Iterate over this android.Module's property structs.
+ for _, properties := range aModule.GetProperties() {
+ propertiesValue := reflect.ValueOf(properties)
+ // Check that propertiesValue is a pointer to the Properties struct, like
+ // *cc.BaseLinkerProperties or *java.CompilerProperties.
+ //
+ // propertiesValue can also be type-asserted to the structs to
+ // manipulate internal props, if needed.
+ if isStructPtr(propertiesValue.Type()) {
+ structValue := propertiesValue.Elem()
+ for k, v := range extractStructProperties(structValue, 0) {
+ ret[k] = v
+ }
+ } else {
+ panic(fmt.Errorf(
+ "properties must be a pointer to a struct, got %T",
+ propertiesValue.Interface()))
+ }
+
+ }
+
+ return ret
+}
+
+// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
+// testonly = True, forcing other rules that depend on _test rules to also be
+// marked as testonly = True. This semantic constraint is not present in Soong.
+// To work around, rename "*_test" rules to "*_test_".
+func canonicalizeModuleType(moduleName string) string {
+ if strings.HasSuffix(moduleName, "_test") {
+ return moduleName + "_"
+ }
+
+ return moduleName
+}
+
+type RuleShim struct {
+ // The rule class shims contained in a bzl file. e.g. ["cc_object", "cc_library", ..]
+ rules []string
+
+ // The generated string content of the bzl file.
+ content string
+}
+
+// Create <module>.bzl containing Bazel rule shims for every module type available in Soong and
+// user-specified Go plugins.
+//
+// This function reuses documentation generation APIs to ensure parity between modules-as-docs
+// and modules-as-code, including the names and types of module properties.
+func createRuleShims(packages []*bpdoc.Package) (map[string]RuleShim, error) {
+ var propToAttr func(prop bpdoc.Property, propName string) string
+ propToAttr = func(prop bpdoc.Property, propName string) string {
+ // dots are not allowed in Starlark attribute names. Substitute them with double underscores.
+ propName = strings.ReplaceAll(propName, ".", "__")
+ if !shouldGenerateAttribute(propName) {
+ return ""
+ }
+
+ // Canonicalize and normalize module property types to Bazel attribute types
+ starlarkAttrType := prop.Type
+ if starlarkAttrType == "list of strings" {
+ starlarkAttrType = "string_list"
+ } else if starlarkAttrType == "int64" {
+ starlarkAttrType = "int"
+ } else if starlarkAttrType == "" {
+ var attr string
+ for _, nestedProp := range prop.Properties {
+ nestedAttr := propToAttr(nestedProp, propName+"__"+nestedProp.Name)
+ if nestedAttr != "" {
+ // TODO(b/167662930): Fix nested props resulting in too many attributes.
+ // Let's still generate these, but comment them out.
+ attr += "# " + nestedAttr
+ }
+ }
+ return attr
+ }
+
+ if !allowedPropTypes[starlarkAttrType] {
+ return ""
+ }
+
+ return fmt.Sprintf(" %q: attr.%s(),\n", propName, starlarkAttrType)
+ }
+
+ ruleShims := map[string]RuleShim{}
+ for _, pkg := range packages {
+ content := "load(\":providers.bzl\", \"SoongModuleInfo\")\n"
+
+ bzlFileName := strings.ReplaceAll(pkg.Path, "android/soong/", "")
+ bzlFileName = strings.ReplaceAll(bzlFileName, ".", "_")
+ bzlFileName = strings.ReplaceAll(bzlFileName, "/", "_")
+
+ rules := []string{}
+
+ for _, moduleTypeTemplate := range moduleTypeDocsToTemplates(pkg.ModuleTypes) {
+ attrs := `{
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+`
+ for _, prop := range moduleTypeTemplate.Properties {
+ attrs += propToAttr(prop, prop.Name)
+ }
+
+ for propName, propType := range additionalPropTypes[moduleTypeTemplate.Name] {
+ attrs += fmt.Sprintf(" %q: attr.%s(),\n", propName, propType)
+ }
+
+ attrs += " },"
+
+ rule := canonicalizeModuleType(moduleTypeTemplate.Name)
+ content += fmt.Sprintf(moduleRuleShim, rule, attrs)
+ rules = append(rules, rule)
+ }
+
+ ruleShims[bzlFileName] = RuleShim{content: content, rules: rules}
+ }
+ return ruleShims, nil
+}
+
+func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error {
+ blueprintCtx := ctx.Context
+ blueprintCtx.VisitAllModules(func(module blueprint.Module) {
+ buildFile, err := buildFileForModule(blueprintCtx, module)
+ if err != nil {
+ panic(err)
+ }
+
+ buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n"))
+ buildFile.Close()
+ })
+
+ if err := writeReadOnlyFile(bazelOverlayDir, "WORKSPACE", ""); err != nil {
+ return err
+ }
+
+ if err := writeReadOnlyFile(bazelOverlayDir, "BUILD", ""); err != nil {
+ return err
+ }
+
+ if err := writeReadOnlyFile(bazelOverlayDir, "providers.bzl", providersBzl); err != nil {
+ return err
+ }
+
+ packages, err := getPackages(ctx)
+ if err != nil {
+ return err
+ }
+ ruleShims, err := createRuleShims(packages)
+ if err != nil {
+ return err
+ }
+
+ for bzlFileName, ruleShim := range ruleShims {
+ if err := writeReadOnlyFile(bazelOverlayDir, bzlFileName+".bzl", ruleShim.content); err != nil {
+ return err
+ }
+ }
+
+ return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))
+}
+
+// Generate the content of soong_module.bzl with the rule shim load statements
+// and mapping of module_type to rule shim map for every module type in Soong.
+func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
+ var loadStmts string
+ var moduleRuleMap string
+ for bzlFileName, ruleShim := range bzlLoads {
+ loadStmt := "load(\"//:"
+ loadStmt += bzlFileName
+ loadStmt += ".bzl\""
+ for _, rule := range ruleShim.rules {
+ loadStmt += fmt.Sprintf(", %q", rule)
+ moduleRuleMap += " \"" + rule + "\": " + rule + ",\n"
+ }
+ loadStmt += ")\n"
+ loadStmts += loadStmt
+ }
+
+ return fmt.Sprintf(soongModuleBzl, loadStmts, moduleRuleMap)
+}
+
+func shouldGenerateAttribute(prop string) bool {
+ return !ignoredPropNames[prop]
+}
+
+// props is an unsorted map. This function ensures that
+// the generated attributes are sorted to ensure determinism.
+func propsToAttributes(props map[string]string) string {
+ var attributes string
+ for _, propName := range android.SortedStringKeys(props) {
+ if shouldGenerateAttribute(propName) {
+ attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName])
+ }
+ }
+ return attributes
+}
+
+// Convert a module and its deps and props into a Bazel macro/rule
+// representation in the BUILD file.
+func generateSoongModuleTarget(
+ blueprintCtx *blueprint.Context,
+ module blueprint.Module) string {
+
+ var props map[string]string
+ if aModule, ok := module.(android.Module); ok {
+ props = extractModuleProperties(aModule)
+ }
+ attributes := propsToAttributes(props)
+
+ // TODO(b/163018919): DirectDeps can have duplicate (module, variant)
+ // items, if the modules are added using different DependencyTag. Figure
+ // out the implications of that.
+ depLabels := map[string]bool{}
+ blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) {
+ depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true
+ })
+
+ depLabelList := "[\n"
+ for depLabel, _ := range depLabels {
+ depLabelList += fmt.Sprintf(" %q,\n", depLabel)
+ }
+ depLabelList += " ]"
+
+ return fmt.Sprintf(
+ soongModuleTarget,
+ targetNameWithVariant(blueprintCtx, module),
+ blueprintCtx.ModuleName(module),
+ canonicalizeModuleType(blueprintCtx.ModuleType(module)),
+ blueprintCtx.ModuleSubDir(module),
+ depLabelList,
+ attributes)
+}
+
+func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.File, error) {
+ // Create nested directories for the BUILD file
+ dirPath := filepath.Join(bazelOverlayDir, packagePath(ctx, module))
+ if _, err := os.Stat(dirPath); os.IsNotExist(err) {
+ os.MkdirAll(dirPath, os.ModePerm)
+ }
+ // Open the file for appending, and create it if it doesn't exist
+ f, err := os.OpenFile(
+ filepath.Join(dirPath, "BUILD.bazel"),
+ os.O_APPEND|os.O_CREATE|os.O_WRONLY,
+ 0644)
+ if err != nil {
+ return nil, err
+ }
+
+ // If the file is empty, add the load statement for the `soong_module` rule
+ fi, err := f.Stat()
+ if err != nil {
+ return nil, err
+ }
+ if fi.Size() == 0 {
+ f.Write([]byte(soongModuleLoad + "\n"))
+ }
+
+ return f, nil
+}
+
+// The overlay directory should be read-only, sufficient for bazel query. The files
+// are not intended to be edited by end users.
+func writeReadOnlyFile(dir string, baseName string, content string) error {
+ pathToFile := filepath.Join(bazelOverlayDir, baseName)
+ // 0444 is read-only
+ return ioutil.WriteFile(pathToFile, []byte(content), 0444)
+}
+
+func isZero(value reflect.Value) bool {
+ switch value.Kind() {
+ case reflect.Func, reflect.Map, reflect.Slice:
+ return value.IsNil()
+ case reflect.Array:
+ valueIsZero := true
+ for i := 0; i < value.Len(); i++ {
+ valueIsZero = valueIsZero && isZero(value.Index(i))
+ }
+ return valueIsZero
+ case reflect.Struct:
+ valueIsZero := true
+ for i := 0; i < value.NumField(); i++ {
+ if value.Field(i).CanSet() {
+ valueIsZero = valueIsZero && isZero(value.Field(i))
+ }
+ }
+ return valueIsZero
+ case reflect.Ptr:
+ if !value.IsNil() {
+ return isZero(reflect.Indirect(value))
+ } else {
+ return true
+ }
+ default:
+ zeroValue := reflect.Zero(value.Type())
+ result := value.Interface() == zeroValue.Interface()
+ return result
+ }
+}
diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go
new file mode 100644
index 0000000..f0c8515
--- /dev/null
+++ b/cmd/soong_build/bazel_overlay_test.go
@@ -0,0 +1,464 @@
+// Copyright 2020 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 main
+
+import (
+ "android/soong/android"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+
+ "github.com/google/blueprint/bootstrap/bpdoc"
+)
+
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "bazel_overlay_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+type customModule struct {
+ android.ModuleBase
+}
+
+func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // nothing for now.
+}
+
+func customModuleFactory() android.Module {
+ module := &customModule{}
+ android.InitAndroidModule(module)
+ return module
+}
+
+func TestGenerateBazelOverlayFromBlueprint(t *testing.T) {
+ testCases := []struct {
+ bp string
+ expectedBazelTarget string
+ }{
+ {
+ bp: `custom {
+ name: "foo",
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ ramdisk: true,
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ ramdisk = True,
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ required: ["bar"],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ required = [
+ "bar",
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ target_required: ["qux", "bazqux"],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ target_required = [
+ "qux",
+ "bazqux",
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ dist: {
+ targets: ["goal_foo"],
+ tag: ".foo",
+ },
+ dists: [
+ {
+ targets: ["goal_bar"],
+ tag: ".bar",
+ },
+ ],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ dist = {
+ "tag": ".foo",
+ "targets": [
+ "goal_foo",
+ ],
+ },
+ dists = [
+ {
+ "tag": ".bar",
+ "targets": [
+ "goal_bar",
+ ],
+ },
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ required: ["bar"],
+ target_required: ["qux", "bazqux"],
+ ramdisk: true,
+ owner: "custom_owner",
+ dists: [
+ {
+ tag: ".tag",
+ targets: ["my_goal"],
+ },
+ ],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ dists = [
+ {
+ "tag": ".tag",
+ "targets": [
+ "my_goal",
+ ],
+ },
+ ],
+ owner = "custom_owner",
+ ramdisk = True,
+ required = [
+ "bar",
+ ],
+ target_required = [
+ "qux",
+ "bazqux",
+ ],
+)`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+ ctx := android.NewTestContext()
+ ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ module := ctx.ModuleForTests("foo", "").Module().(*customModule)
+ blueprintCtx := ctx.Context.Context
+
+ actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module)
+ if actualBazelTarget != testCase.expectedBazelTarget {
+ t.Errorf(
+ "Expected generated Bazel target to be '%s', got '%s'",
+ testCase.expectedBazelTarget,
+ actualBazelTarget,
+ )
+ }
+ }
+}
+
+func createPackageFixtures() []*bpdoc.Package {
+ properties := []bpdoc.Property{
+ bpdoc.Property{
+ Name: "int64_prop",
+ Type: "int64",
+ },
+ bpdoc.Property{
+ Name: "int_prop",
+ Type: "int",
+ },
+ bpdoc.Property{
+ Name: "bool_prop",
+ Type: "bool",
+ },
+ bpdoc.Property{
+ Name: "string_prop",
+ Type: "string",
+ },
+ bpdoc.Property{
+ Name: "string_list_prop",
+ Type: "list of strings",
+ },
+ bpdoc.Property{
+ Name: "nested_prop",
+ Type: "",
+ Properties: []bpdoc.Property{
+ bpdoc.Property{
+ Name: "int_prop",
+ Type: "int",
+ },
+ bpdoc.Property{
+ Name: "bool_prop",
+ Type: "bool",
+ },
+ bpdoc.Property{
+ Name: "string_prop",
+ Type: "string",
+ },
+ },
+ },
+ bpdoc.Property{
+ Name: "unknown_type",
+ Type: "unknown",
+ },
+ }
+
+ fooPropertyStruct := &bpdoc.PropertyStruct{
+ Name: "FooProperties",
+ Properties: properties,
+ }
+
+ moduleTypes := []*bpdoc.ModuleType{
+ &bpdoc.ModuleType{
+ Name: "foo_library",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+
+ &bpdoc.ModuleType{
+ Name: "foo_binary",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+ &bpdoc.ModuleType{
+ Name: "foo_test",
+ PropertyStructs: []*bpdoc.PropertyStruct{
+ fooPropertyStruct,
+ },
+ },
+ }
+
+ return [](*bpdoc.Package){
+ &bpdoc.Package{
+ Name: "foo_language",
+ Path: "android/soong/foo",
+ ModuleTypes: moduleTypes,
+ },
+ }
+}
+
+func TestGenerateModuleRuleShims(t *testing.T) {
+ ruleShims, err := createRuleShims(createPackageFixtures())
+ if err != nil {
+ panic(err)
+ }
+
+ if len(ruleShims) != 1 {
+ t.Errorf("Expected to generate 1 rule shim, but got %d", len(ruleShims))
+ }
+
+ fooRuleShim := ruleShims["foo"]
+ expectedRules := []string{"foo_binary", "foo_library", "foo_test_"}
+
+ if len(fooRuleShim.rules) != 3 {
+ t.Errorf("Expected 3 rules, but got %d", len(fooRuleShim.rules))
+ }
+
+ for i, rule := range fooRuleShim.rules {
+ if rule != expectedRules[i] {
+ t.Errorf("Expected rule shim to contain %s, but got %s", expectedRules[i], rule)
+ }
+ }
+
+ expectedBzl := `load(":providers.bzl", "SoongModuleInfo")
+
+def _foo_binary_impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_binary = rule(
+ implementation = _foo_binary_impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+
+def _foo_library_impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_library = rule(
+ implementation = _foo_library_impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+
+def _foo_test__impl(ctx):
+ return [SoongModuleInfo()]
+
+foo_test_ = rule(
+ implementation = _foo_test__impl,
+ attrs = {
+ "module_name": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+ "bool_prop": attr.bool(),
+ "int64_prop": attr.int(),
+ "int_prop": attr.int(),
+# "nested_prop__int_prop": attr.int(),
+# "nested_prop__bool_prop": attr.bool(),
+# "nested_prop__string_prop": attr.string(),
+ "string_list_prop": attr.string_list(),
+ "string_prop": attr.string(),
+ },
+)
+`
+
+ if fooRuleShim.content != expectedBzl {
+ t.Errorf(
+ "Expected the generated rule shim bzl to be:\n%s\nbut got:\n%s",
+ expectedBzl,
+ fooRuleShim.content)
+ }
+}
+
+func TestGenerateSoongModuleBzl(t *testing.T) {
+ ruleShims, err := createRuleShims(createPackageFixtures())
+ if err != nil {
+ panic(err)
+ }
+ actualSoongModuleBzl := generateSoongModuleBzl(ruleShims)
+
+ expectedLoad := "load(\"//:foo.bzl\", \"foo_binary\", \"foo_library\", \"foo_test_\")"
+ expectedRuleMap := `soong_module_rule_map = {
+ "foo_binary": foo_binary,
+ "foo_library": foo_library,
+ "foo_test_": foo_test_,
+}`
+ if !strings.Contains(actualSoongModuleBzl, expectedLoad) {
+ t.Errorf(
+ "Generated soong_module.bzl:\n\n%s\n\n"+
+ "Could not find the load statement in the generated soong_module.bzl:\n%s",
+ actualSoongModuleBzl,
+ expectedLoad)
+ }
+
+ if !strings.Contains(actualSoongModuleBzl, expectedRuleMap) {
+ t.Errorf(
+ "Generated soong_module.bzl:\n\n%s\n\n"+
+ "Could not find the module -> rule map in the generated soong_module.bzl:\n%s",
+ actualSoongModuleBzl,
+ expectedRuleMap)
+ }
+}
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 30381e0..01a39a2 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -18,12 +18,7 @@
"flag"
"fmt"
"os"
- "os/exec"
"path/filepath"
- "strconv"
- "strings"
- "syscall"
- "time"
"github.com/google/blueprint/bootstrap"
@@ -31,11 +26,13 @@
)
var (
- docFile string
+ docFile string
+ bazelOverlayDir string
)
func init() {
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
+ flag.StringVar(&bazelOverlayDir, "bazel_overlay_dir", "", "path to the bazel overlay directory")
}
func newNameResolver(config android.Config) *android.NameResolver {
@@ -55,42 +52,7 @@
}
func main() {
- if android.SoongDelveListen != "" {
- if android.SoongDelvePath == "" {
- fmt.Fprintln(os.Stderr, "SOONG_DELVE is set but failed to find dlv")
- os.Exit(1)
- }
- pid := strconv.Itoa(os.Getpid())
- cmd := []string{android.SoongDelvePath,
- "attach", pid,
- "--headless",
- "-l", android.SoongDelveListen,
- "--api-version=2",
- "--accept-multiclient",
- "--log",
- }
-
- fmt.Println("Starting", strings.Join(cmd, " "))
- dlv := exec.Command(cmd[0], cmd[1:]...)
- dlv.Stdout = os.Stdout
- dlv.Stderr = os.Stderr
- dlv.Stdin = nil
-
- // Put dlv into its own process group so we can kill it and the child process it starts.
- dlv.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
-
- err := dlv.Start()
- if err != nil {
- // Print the error starting dlv and continue.
- fmt.Println(err)
- } else {
- // Kill the process group for dlv when soong_build exits.
- defer syscall.Kill(-dlv.Process.Pid, syscall.SIGKILL)
- // Wait to give dlv a chance to connect and pause the process.
- time.Sleep(time.Second)
- }
- }
-
+ android.ReexecWithDelveMaybe()
flag.Parse()
// The top-level Blueprints file is passed as the first argument.
@@ -99,13 +61,13 @@
ctx := android.NewContext()
ctx.Register()
- configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir)
+ configuration, err := android.NewConfig(srcDir, bootstrap.BuildDir, bootstrap.ModuleListFile)
if err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
- if docFile != "" {
+ if !shouldPrepareBuildActions() {
configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
}
@@ -125,10 +87,34 @@
bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
+ if bazelOverlayDir != "" {
+ if err := createBazelOverlay(ctx, bazelOverlayDir); err != nil {
+ fmt.Fprintf(os.Stderr, "%s", err)
+ os.Exit(1)
+ }
+ }
+
if docFile != "" {
if err := writeDocs(ctx, docFile); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
os.Exit(1)
}
}
+
+ // TODO(ccross): make this a command line argument. Requires plumbing through blueprint
+ // to affect the command line of the primary builder.
+ if shouldPrepareBuildActions() {
+ metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
+ err = android.WriteMetrics(configuration, metricsFile)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
+ os.Exit(1)
+ }
+ }
+}
+
+func shouldPrepareBuildActions() bool {
+ // If we're writing soong_docs or bazel_overlay, don't write build.ninja or
+ // collect metrics.
+ return docFile == "" && bazelOverlayDir == ""
}
diff --git a/cmd/soong_build/writedocs.go b/cmd/soong_build/writedocs.go
index 9424b6c..5fb6e6b 100644
--- a/cmd/soong_build/writedocs.go
+++ b/cmd/soong_build/writedocs.go
@@ -44,7 +44,7 @@
"name": 0,
"src": 1,
"srcs": 2,
- "defautls": 3,
+ "defaults": 3,
"host_supported": 4,
"device_supported": 5,
}
@@ -95,14 +95,17 @@
return result
}
-func writeDocs(ctx *android.Context, filename string) error {
+func getPackages(ctx *android.Context) ([]*bpdoc.Package, error) {
moduleTypeFactories := android.ModuleTypeFactories()
bpModuleTypeFactories := make(map[string]reflect.Value)
for moduleType, factory := range moduleTypeFactories {
bpModuleTypeFactories[moduleType] = reflect.ValueOf(factory)
}
+ return bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
+}
- packages, err := bootstrap.ModuleTypeDocs(ctx.Context, bpModuleTypeFactories)
+func writeDocs(ctx *android.Context, filename string) error {
+ packages, err := getPackages(ctx)
if err != nil {
return err
}
diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp
index 4cdc396..4db0da3 100644
--- a/cmd/soong_env/Android.bp
+++ b/cmd/soong_env/Android.bp
@@ -22,4 +22,3 @@
],
default: true,
}
-
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 89ece8d..4aa62be 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -35,14 +35,14 @@
// A command represents an operation to be executed in the soong build
// system.
type command struct {
- // the flag name (must have double dashes)
+ // The flag name (must have double dashes).
flag string
- // description for the flag (to display when running help)
+ // Description for the flag (to display when running help).
description string
- // Forces the status output into dumb terminal mode.
- forceDumbOutput bool
+ // Stream the build status output into the simple terminal mode.
+ simpleOutput bool
// Sets a prefix string to use for filenames of log files.
logsPrefix string
@@ -70,21 +70,21 @@
stdio: stdio,
run: make,
}, {
- flag: "--dumpvar-mode",
- description: "print the value of the legacy make variable VAR to stdout",
- forceDumbOutput: true,
- logsPrefix: "dumpvars-",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVar,
+ flag: "--dumpvar-mode",
+ description: "print the value of the legacy make variable VAR to stdout",
+ simpleOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVar,
}, {
- flag: "--dumpvars-mode",
- description: "dump the values of one or more legacy make variables, in shell syntax",
- forceDumbOutput: true,
- logsPrefix: "dumpvars-",
- config: dumpVarConfig,
- stdio: customStdio,
- run: dumpVars,
+ flag: "--dumpvars-mode",
+ description: "dump the values of one or more legacy make variables, in shell syntax",
+ simpleOutput: true,
+ logsPrefix: "dumpvars-",
+ config: dumpVarConfig,
+ stdio: customStdio,
+ run: dumpVars,
}, {
flag: "--build-mode",
description: "build modules based on the specified build action",
@@ -125,7 +125,7 @@
os.Exit(1)
}
- output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.forceDumbOutput,
+ output := terminal.NewStatusOutput(c.stdio().Stdout(), os.Getenv("NINJA_STATUS"), c.simpleOutput,
build.OsEnvironment().IsEnvTrue("ANDROID_QUIET_BUILD"))
log := logger.New(output)
@@ -172,7 +172,7 @@
buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
- defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+ defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
defer build.PrintGomaDeprecation(buildCtx, config)
os.MkdirAll(logsDir, 0777)
@@ -182,6 +182,7 @@
stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
stat.AddOutput(status.NewCriticalPath(log))
+ stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, c.logsPrefix+"build_progress.pb")))
buildCtx.Verbosef("Detected %.3v GB total RAM", float32(config.TotalRAM())/(1024*1024*1024))
buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 68d8bc7..2c4cd82 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -24,4 +24,3 @@
],
testSrcs: ["zip2zip_test.go"],
}
-
diff --git a/cmd/zipsync/Android.bp b/cmd/zipsync/Android.bp
index 22feadc..49b5f3e 100644
--- a/cmd/zipsync/Android.bp
+++ b/cmd/zipsync/Android.bp
@@ -22,4 +22,3 @@
"zipsync.go",
],
}
-
diff --git a/cuj/cuj.go b/cuj/cuj.go
index c7ff8ff..3333012 100644
--- a/cuj/cuj.go
+++ b/cuj/cuj.go
@@ -33,8 +33,9 @@
)
type Test struct {
- name string
- args []string
+ name string
+ args []string
+ before func() error
results TestResults
}
@@ -119,6 +120,15 @@
t.results.metrics = met
}
+// Touch the Intent.java file to cause a rebuild of the frameworks to monitor the
+// incremental build speed as mentioned b/152046247. Intent.java file was chosen
+// as it is a key component of the framework and is often modified.
+func touchIntentFile() error {
+ const intentFileName = "frameworks/base/core/java/android/content/Intent.java"
+ currentTime := time.Now().Local()
+ return os.Chtimes(intentFileName, currentTime, currentTime)
+}
+
func main() {
outDir := os.Getenv("OUT_DIR")
if outDir == "" {
@@ -170,6 +180,36 @@
name: "framework_rebuild_twice",
args: []string{"framework"},
},
+ {
+ // Scenario major_inc_build (b/152046247): tracking build speed of major incremental build.
+ name: "major_inc_build_droid",
+ args: []string{"droid"},
+ },
+ {
+ name: "major_inc_build_framework_minus_apex_after_droid_build",
+ args: []string{"framework-minus-apex"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_framework_after_droid_build",
+ args: []string{"framework"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_sync_after_droid_build",
+ args: []string{"sync"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_droid_rebuild",
+ args: []string{"droid"},
+ before: touchIntentFile,
+ },
+ {
+ name: "major_inc_build_update_api_after_droid_rebuild",
+ args: []string{"update-api"},
+ before: touchIntentFile,
+ },
}
cujMetrics := metrics.NewCriticalUserJourneysMetrics()
@@ -178,6 +218,12 @@
for i, t := range tests {
logsSubDir := fmt.Sprintf("%02d_%s", i, t.name)
logsDir := filepath.Join(cujDir, "logs", logsSubDir)
+ if t.before != nil {
+ if err := t.before(); err != nil {
+ fmt.Printf("error running before function on test %q: %v\n", t.name, err)
+ break
+ }
+ }
t.Run(logsDir)
if t.results.err != nil {
fmt.Printf("error running test %q: %s\n", t.name, t.results.err)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 98850e5..21f7bb3 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -40,15 +40,17 @@
DisableGenerateProfile bool // don't generate profiles
ProfileDir string // directory to find profiles in
- BootJars []string // modules for jars that form the boot class path
- UpdatableBootJars []string // jars within apex that form the boot class path
+ BootJars android.ConfiguredJarList // modules for jars that form the boot class path
+ UpdatableBootJars android.ConfiguredJarList // jars within apex that form the boot class path
- ArtApexJars []string // modules for jars that are in the ART APEX
+ ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX
- SystemServerJars []string // jars that form the system server
- SystemServerApps []string // apps that are loaded into system server
- UpdatableSystemServerJars []string // jars within apex that are loaded into system server
- SpeedApps []string // apps that should be speed optimized
+ SystemServerJars []string // jars that form the system server
+ SystemServerApps []string // apps that are loaded into system server
+ UpdatableSystemServerJars android.ConfiguredJarList // jars within apex that are loaded into system server
+ SpeedApps []string // apps that should be speed optimized
+
+ BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error
PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified
@@ -98,6 +100,94 @@
ConstructContext android.Path
}
+// These libs are added as optional dependencies (<uses-library> with android:required set to false).
+// This is because they haven't existed prior to certain SDK version, but classes in them were in
+// bootclasspath jars, etc. So making them hard dependencies (android:required=true) would prevent
+// apps from being installed to such legacy devices.
+var OptionalCompatUsesLibs = []string{
+ "org.apache.http.legacy",
+ "android.test.base",
+ "android.test.mock",
+}
+
+var CompatUsesLibs = []string{
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+}
+
+const UnknownInstallLibraryPath = "error"
+
+// LibraryPath contains paths to the library DEX jar on host and on device.
+type LibraryPath struct {
+ Host android.Path
+ Device string
+}
+
+// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
+type LibraryPaths map[string]*LibraryPath
+
+// Add a new library path to the map, unless a path for this library already exists.
+// If necessary, check that the build and install paths exist.
+func (libPaths LibraryPaths) addLibraryPath(ctx android.ModuleContext, lib string,
+ hostPath, installPath android.Path, strict bool) {
+
+ // If missing dependencies are allowed, the build shouldn't fail when a <uses-library> is
+ // not found. However, this is likely to result is disabling dexpreopt, as it won't be
+ // possible to construct class loader context without on-host and on-device library paths.
+ strict = strict && !ctx.Config().AllowMissingDependencies()
+
+ if hostPath == nil && strict {
+ android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
+ }
+
+ if installPath == nil {
+ if android.InList(lib, CompatUsesLibs) || android.InList(lib, OptionalCompatUsesLibs) {
+ // Assume that compatibility libraries are installed in /system/framework.
+ installPath = android.PathForModuleInstall(ctx, "framework", lib+".jar")
+ } else if strict {
+ android.ReportPathErrorf(ctx, "unknown install path to <uses-library> '%s'", lib)
+ }
+ }
+
+ // Add a library only if the build and install path to it is known.
+ if _, present := libPaths[lib]; !present {
+ var devicePath string
+ if installPath != nil {
+ devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
+ } else {
+ // For some stub libraries the only known thing is the name of their implementation
+ // library, but the library itself is unavailable (missing or part of a prebuilt). In
+ // such cases we still need to add the library to <uses-library> tags in the manifest,
+ // but we cannot use if for dexpreopt.
+ devicePath = UnknownInstallLibraryPath
+ }
+ libPaths[lib] = &LibraryPath{hostPath, devicePath}
+ }
+}
+
+// Add a new library path to the map. Enforce checks that the library paths exist.
+func (libPaths LibraryPaths) AddLibraryPath(ctx android.ModuleContext, lib string, hostPath, installPath android.Path) {
+ libPaths.addLibraryPath(ctx, lib, hostPath, installPath, true)
+}
+
+// Add a new library path to the map, if the library exists (name is not nil).
+// Don't enforce checks that the library paths exist. Some libraries may be missing from the build,
+// but their names still need to be added to <uses-library> tags in the manifest.
+func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.ModuleContext, lib *string, hostPath, installPath android.Path) {
+ if lib != nil {
+ libPaths.addLibraryPath(ctx, *lib, hostPath, installPath, false)
+ }
+}
+
+// Add library paths from the second map to the first map (do not override existing entries).
+func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) {
+ for lib, path := range otherPaths {
+ if _, present := libPaths[lib]; !present {
+ libPaths[lib] = path
+ }
+ }
+}
+
type ModuleConfig struct {
Name string
DexLocation string // dex location on device
@@ -112,10 +202,10 @@
ProfileIsTextListing bool
ProfileBootListing android.OptionalPath
- EnforceUsesLibraries bool
- PresentOptionalUsesLibraries []string
- UsesLibraries []string
- LibraryPaths map[string]android.Path
+ EnforceUsesLibraries bool
+ OptionalUsesLibraries []string
+ UsesLibraries []string
+ LibraryPaths LibraryPaths
Archs []android.ArchType
DexPreoptImages []android.Path
@@ -163,14 +253,6 @@
return ret
}
-func constructPathMap(ctx android.PathContext, paths map[string]string) map[string]android.Path {
- ret := map[string]android.Path{}
- for key, path := range paths {
- ret[key] = constructPath(ctx, path)
- }
- return ret
-}
-
func constructWritablePath(ctx android.PathContext, path string) android.WritablePath {
if path == "" {
return nil
@@ -186,8 +268,12 @@
// Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be
// used to construct the real value manually below.
- DirtyImageObjects string
- BootImageProfiles []string
+ BootJars []string
+ UpdatableBootJars []string
+ ArtApexJars []string
+ UpdatableSystemServerJars []string
+ DirtyImageObjects string
+ BootImageProfiles []string
}
config := GlobalJSONConfig{}
@@ -197,6 +283,10 @@
}
// Construct paths that require a PathContext.
+ config.GlobalConfig.BootJars = android.CreateConfiguredJarList(ctx, config.BootJars)
+ config.GlobalConfig.UpdatableBootJars = android.CreateConfiguredJarList(ctx, config.UpdatableBootJars)
+ config.GlobalConfig.ArtApexJars = android.CreateConfiguredJarList(ctx, config.ArtApexJars)
+ config.GlobalConfig.UpdatableSystemServerJars = android.CreateConfiguredJarList(ctx, config.UpdatableSystemServerJars)
config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects))
config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles)
@@ -262,6 +352,13 @@
// from Make to read the module dexpreopt.config written in the Make config
// stage.
func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) {
+ type jsonLibraryPath struct {
+ Host string
+ Device string
+ }
+
+ type jsonLibraryPaths map[string]jsonLibraryPath
+
type ModuleJSONConfig struct {
*ModuleConfig
@@ -271,12 +368,24 @@
DexPath string
ManifestPath string
ProfileClassListing string
- LibraryPaths map[string]string
+ LibraryPaths jsonLibraryPaths
DexPreoptImages []string
DexPreoptImageLocations []string
PreoptBootClassPathDexFiles []string
}
+ // convert JSON map of library paths to LibraryPaths
+ constructLibraryPaths := func(ctx android.PathContext, paths jsonLibraryPaths) LibraryPaths {
+ m := LibraryPaths{}
+ for lib, path := range paths {
+ m[lib] = &LibraryPath{
+ constructPath(ctx, path.Host),
+ path.Device,
+ }
+ }
+ return m
+ }
+
config := ModuleJSONConfig{}
err := json.Unmarshal(data, &config)
@@ -289,7 +398,7 @@
config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
- config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
+ config.ModuleConfig.LibraryPaths = constructLibraryPaths(ctx, config.LibraryPaths)
config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations
config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)
@@ -330,7 +439,33 @@
func dex2oatPathFromDep(ctx android.ModuleContext) android.Path {
dex2oatBin := dex2oatModuleName(ctx.Config())
- dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag)
+ // Find the right dex2oat module, trying to follow PrebuiltDepTag from source
+ // to prebuilt if there is one. We wouldn't have to do this if the
+ // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was
+ // run after RegisterToolDeps above, but changing that leads to ordering
+ // problems between mutators (RegisterToolDeps needs to run late to act on
+ // final variants, while prebuilt_postdeps needs to run before many of the
+ // PostDeps mutators, like the APEX mutators). Hence we need to dig out the
+ // prebuilt explicitly here instead.
+ var dex2oatModule android.Module
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == dex2oatDepTag {
+ // Found the source module, or prebuilt module that has replaced the source.
+ dex2oatModule = child
+ if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil {
+ return false // If it's the prebuilt we're done.
+ } else {
+ return true // Recurse to check if the source has a prebuilt dependency.
+ }
+ }
+ if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
+ if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil && p.Prebuilt().UsePrebuilt() {
+ dex2oatModule = child // Found a prebuilt that should be used.
+ }
+ }
+ return false
+ })
+
if dex2oatModule == nil {
// If this happens there's probably a missing call to AddToolDeps in DepsMutator.
panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
@@ -361,7 +496,7 @@
SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"),
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"),
- ConstructContext: android.PathForSource(ctx, "build/make/core/construct_context.sh"),
+ ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"),
}
}
@@ -508,12 +643,12 @@
PatternsOnSystemOther: nil,
DisableGenerateProfile: false,
ProfileDir: "",
- BootJars: nil,
- UpdatableBootJars: nil,
- ArtApexJars: nil,
+ BootJars: android.EmptyConfiguredJarList(),
+ UpdatableBootJars: android.EmptyConfiguredJarList(),
+ ArtApexJars: android.EmptyConfiguredJarList(),
SystemServerJars: nil,
SystemServerApps: nil,
- UpdatableSystemServerJars: nil,
+ UpdatableSystemServerJars: android.EmptyConfiguredJarList(),
SpeedApps: nil,
PreoptFlags: nil,
DefaultCompilerFilter: "",
@@ -552,7 +687,7 @@
SoongZip: android.PathForTesting("soong_zip"),
Zip2zip: android.PathForTesting("zip2zip"),
ManifestCheck: android.PathForTesting("manifest_check"),
- ConstructContext: android.PathForTesting("construct_context.sh"),
+ ConstructContext: android.PathForTesting("construct_context"),
}
}).(*GlobalSoongConfig)
}
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index f984966..4dbda49 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -81,15 +81,14 @@
}
if !dexpreoptDisabled(ctx, global, module) {
- // Don't preopt individual boot jars, they will be preopted together.
- if !contains(global.BootJars, module.Name) {
+ if clc := genClassLoaderContext(ctx, global, module); clc != nil {
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
!module.NoCreateAppImage
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
- dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+ dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM)
}
}
}
@@ -102,18 +101,21 @@
return true
}
+ // Don't preopt individual boot jars, they will be preopted together.
+ if global.BootJars.ContainsJar(module.Name) {
+ return true
+ }
+
// Don't preopt system server jars that are updatable.
- for _, p := range global.UpdatableSystemServerJars {
- if _, jar := android.SplitApexJarPair(p); jar == module.Name {
- return true
- }
+ if global.UpdatableSystemServerJars.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 && !contains(global.BootJars, module.Name) &&
+ if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
!contains(global.SystemServerJars, module.Name) && !module.PreoptExtractedApk {
return true
}
@@ -192,9 +194,124 @@
return profilePath
}
+type classLoaderContext struct {
+ // The class loader context using paths in the build.
+ Host android.Paths
+
+ // The class loader context using paths as they will be on the device.
+ Target []string
+}
+
+// A map of class loader contexts for each SDK version.
+// A map entry for "any" version contains libraries that are unconditionally added to class loader
+// context. Map entries for existing versions contains libraries that were in the default classpath
+// until that API version, and should be added to class loader context if and only if the
+// targetSdkVersion in the manifest or APK is less than that API version.
+type classLoaderContextMap map[int]*classLoaderContext
+
+const anySdkVersion int = 9999 // should go last in class loader context
+
+func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext {
+ if _, ok := m[sdkVer]; !ok {
+ m[sdkVer] = &classLoaderContext{}
+ }
+ return m[sdkVer]
+}
+
+func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool {
+ clc := m.getValue(sdkVer)
+ for _, lib := range libs {
+ if p := pathForLibrary(module, lib); p != nil {
+ clc.Host = append(clc.Host, p.Host)
+ clc.Target = append(clc.Target, p.Device)
+ } else {
+ return false
+ }
+ }
+ return true
+}
+
+func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
+ clc := m.getValue(sdkVer)
+ for _, lib := range libs {
+ clc.Host = append(clc.Host, SystemServerDexJarHostPath(ctx, lib))
+ clc.Target = append(clc.Target, filepath.Join("/system/framework", lib+".jar"))
+ }
+}
+
+// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat
+// command for the dexpreopted module. There are three possible cases:
+//
+// 1. System server jars. They have a special class loader context that includes other system
+// server jars.
+//
+// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader
+// context includes build and on-device paths to these libs. In some cases it may happen that
+// the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs
+// library, whose implementation library is missing from the build altogether). In such case
+// dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless,
+// as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in
+// such cases the function returns nil, which disables dexpreopt.
+//
+// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use
+// the unsafe &-classpath workaround that means empty class loader context and absence of runtime
+// check that the class loader context provided by the PackageManager agrees with the stored
+// class loader context recorded in the .odex file.
+//
+func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) *classLoaderContextMap {
+ classLoaderContexts := make(classLoaderContextMap)
+ systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
+ if jarIndex := android.IndexList(module.Name, systemServerJars); 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.
+ classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
+
+ } else if module.EnforceUsesLibraries {
+ // Unconditional class loader context.
+ usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
+ if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 28.
+ const httpLegacy = "org.apache.http.legacy"
+ if !contains(usesLibs, httpLegacy) {
+ if !classLoaderContexts.addLibs(28, module, httpLegacy) {
+ return nil
+ }
+ }
+
+ // Conditional class loader context for API version < 29.
+ usesLibs29 := []string{
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ }
+ if !classLoaderContexts.addLibs(29, module, usesLibs29...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 30.
+ const testBase = "android.test.base"
+ if !contains(usesLibs, testBase) {
+ if !classLoaderContexts.addLibs(30, module, testBase) {
+ return nil
+ }
+ }
+
+ } else {
+ // Pass special class loader context to skip the classpath and collision check.
+ // This will get removed once LOCAL_USES_LIBRARIES is enforced.
+ // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
+ // to the &.
+ }
+
+ return &classLoaderContexts
+}
+
func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
- module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
- appImage bool, generateDM bool) {
+ module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap,
+ profile android.WritablePath, appImage bool, generateDM bool) {
arch := module.Archs[archIdx]
@@ -227,100 +344,24 @@
systemServerJars := NonUpdatableSystemServerJars(ctx, global)
- // The class loader context using paths in the build
- var classLoaderContextHost android.Paths
+ rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
+ rule.Command().FlagWithOutput("rm -f ", odexPath)
- // The class loader context using paths as they will be on the device
- var classLoaderContextTarget []string
-
- // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 28
- var conditionalClassLoaderContextHost28 android.Paths
- var conditionalClassLoaderContextTarget28 []string
-
- // Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 29
- var conditionalClassLoaderContextHost29 android.Paths
- var conditionalClassLoaderContextTarget29 []string
-
- // A flag indicating if the '&' class loader context is used.
- unknownClassLoaderContext := false
-
- if module.EnforceUsesLibraries {
- usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
-
- // Create class loader context for dex2oat from uses libraries and filtered optional libraries
- for _, l := range usesLibs {
-
- classLoaderContextHost = append(classLoaderContextHost,
- pathForLibrary(module, l))
- classLoaderContextTarget = append(classLoaderContextTarget,
- filepath.Join("/system/framework", l+".jar"))
- }
-
- const httpLegacy = "org.apache.http.legacy"
- const httpLegacyImpl = "org.apache.http.legacy.impl"
-
- // org.apache.http.legacy contains classes that were in the default classpath until API 28. If the
- // targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly depend on
- // org.apache.http.legacy, then implicitly add the classes to the classpath for dexpreopt. One the
- // device the classes will be in a file called org.apache.http.legacy.impl.jar.
- module.LibraryPaths[httpLegacyImpl] = module.LibraryPaths[httpLegacy]
-
- if !contains(module.UsesLibraries, httpLegacy) && !contains(module.PresentOptionalUsesLibraries, httpLegacy) {
- conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
- pathForLibrary(module, httpLegacyImpl))
- conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
- filepath.Join("/system/framework", httpLegacyImpl+".jar"))
- }
-
- const hidlBase = "android.hidl.base-V1.0-java"
- const hidlManager = "android.hidl.manager-V1.0-java"
-
- // android.hidl.base-V1.0-java and android.hidl.manager-V1.0 contain classes that were in the default
- // classpath until API 29. If the targetSdkVersion in the manifest or APK is < 29 then implicitly add
- // the classes to the classpath for dexpreopt.
- conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
- pathForLibrary(module, hidlManager))
- conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
- filepath.Join("/system/framework", hidlManager+".jar"))
- conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
- pathForLibrary(module, hidlBase))
- conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
- filepath.Join("/system/framework", hidlBase+".jar"))
- } else if jarIndex := android.IndexList(module.Name, systemServerJars); 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.
- for _, otherJar := range systemServerJars[:jarIndex] {
- classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar))
- classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar")
- }
-
+ if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
// Copy the system server jar to a predefined location where dex2oat will find it.
dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
- } else {
- // Pass special class loader context to skip the classpath and collision check.
- // This will get removed once LOCAL_USES_LIBRARIES is enforced.
- // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
- // to the &.
- unknownClassLoaderContext = true
- }
- rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
- rule.Command().FlagWithOutput("rm -f ", odexPath)
- // Set values in the environment of the rule. These may be modified by construct_context.sh.
- if unknownClassLoaderContext {
- rule.Command().
- Text(`class_loader_context_arg=--class-loader-context=\&`).
- Text(`stored_class_loader_context_arg=""`)
- } else {
- rule.Command().
- Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]").
- Implicits(classLoaderContextHost).
- Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]")
- }
+ checkSystemServerOrder(ctx, jarIndex)
- if module.EnforceUsesLibraries {
+ clc := classLoaderContexts[anySdkVersion]
+ rule.Command().
+ Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clc.Host.Strings(), ":") + "]").
+ Implicits(clc.Host).
+ Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]")
+ } else if module.EnforceUsesLibraries {
+ // Generate command that saves target SDK version in a shell variable.
if module.ManifestPath != nil {
rule.Command().Text(`target_sdk_version="$(`).
Tool(globalSoong.ManifestCheck).
@@ -336,22 +377,30 @@
Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
Text(`)"`)
}
- rule.Command().Textf(`dex_preopt_host_libraries="%s"`,
- strings.Join(classLoaderContextHost.Strings(), " ")).
- Implicits(classLoaderContextHost)
- rule.Command().Textf(`dex_preopt_target_libraries="%s"`,
- strings.Join(classLoaderContextTarget, " "))
- rule.Command().Textf(`conditional_host_libs_28="%s"`,
- strings.Join(conditionalClassLoaderContextHost28.Strings(), " ")).
- Implicits(conditionalClassLoaderContextHost28)
- rule.Command().Textf(`conditional_target_libs_28="%s"`,
- strings.Join(conditionalClassLoaderContextTarget28, " "))
- rule.Command().Textf(`conditional_host_libs_29="%s"`,
- strings.Join(conditionalClassLoaderContextHost29.Strings(), " ")).
- Implicits(conditionalClassLoaderContextHost29)
- rule.Command().Textf(`conditional_target_libs_29="%s"`,
- strings.Join(conditionalClassLoaderContextTarget29, " "))
- rule.Command().Text("source").Tool(globalSoong.ConstructContext).Input(module.DexPath)
+
+ // Generate command that saves host and target class loader context in shell variables.
+ cmd := rule.Command().
+ Text(`eval "$(`).Tool(globalSoong.ConstructContext).
+ Text(` --target-sdk-version ${target_sdk_version}`)
+ for _, ver := range android.SortedIntKeys(classLoaderContexts) {
+ clc := classLoaderContexts.getValue(ver)
+ verString := fmt.Sprintf("%d", ver)
+ if ver == anySdkVersion {
+ verString = "any" // a special keyword that means any SDK version
+ }
+ cmd.Textf(`--host-classpath-for-sdk %s %s`, verString, strings.Join(clc.Host.Strings(), ":")).
+ Implicits(clc.Host).
+ Textf(`--target-classpath-for-sdk %s %s`, verString, strings.Join(clc.Target, ":"))
+ }
+ cmd.Text(`)"`)
+ } else {
+ // Pass special class loader context to skip the classpath and collision check.
+ // This will get removed once LOCAL_USES_LIBRARIES is enforced.
+ // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
+ // to the &.
+ rule.Command().
+ Text(`class_loader_context_arg=--class-loader-context=\&`).
+ Text(`stored_class_loader_context_arg=""`)
}
// Devices that do not have a product partition use a symlink from /product to /system/product.
@@ -540,12 +589,12 @@
return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
}
-func pathForLibrary(module *ModuleConfig, lib string) android.Path {
- path, ok := module.LibraryPaths[lib]
- if !ok {
- panic(fmt.Errorf("unknown library path for %q", lib))
+func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath {
+ if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" {
+ return path
+ } else {
+ return nil
}
- return path
}
func makefileMatch(pattern, s string) bool {
@@ -560,29 +609,13 @@
}
}
-// Expected format for apexJarValue = <apex name>:<jar name>
-func GetJarLocationFromApexJarPair(apexJarValue string) string {
- apex, jar := android.SplitApexJarPair(apexJarValue)
- return filepath.Join("/apex", apex, "javalib", jar+".jar")
-}
-
-func GetJarsFromApexJarPairs(apexJarPairs []string) []string {
- modules := make([]string, len(apexJarPairs))
- for i, p := range apexJarPairs {
- _, jar := android.SplitApexJarPair(p)
- modules[i] = jar
- }
- return modules
-}
-
var nonUpdatableSystemServerJarsKey = android.NewOnceKey("nonUpdatableSystemServerJars")
// TODO: eliminate the superficial global config parameter by moving global config definition
// from java subpackage to dexpreopt.
func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
return ctx.Config().Once(nonUpdatableSystemServerJarsKey, func() interface{} {
- return android.RemoveListFromList(global.SystemServerJars,
- GetJarsFromApexJarPairs(global.UpdatableSystemServerJars))
+ return android.RemoveListFromList(global.SystemServerJars, global.UpdatableSystemServerJars.CopyOfJars())
}).([]string)
}
@@ -601,6 +634,29 @@
}
}
+// Check the order of jars on the system server classpath and give a warning/error if a jar precedes
+// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't
+// have the dependency jar in the class loader context, and it won't be able to resolve any
+// references to its classes and methods.
+func checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
+ mctx, isModule := ctx.(android.ModuleContext)
+ if isModule {
+ config := GetGlobalConfig(ctx)
+ jars := NonUpdatableSystemServerJars(ctx, config)
+ mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+ depIndex := android.IndexList(dep.Name(), jars)
+ if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
+ jar := jars[jarIndex]
+ dep := jars[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)
+ }
+ return true
+ })
+ }
+}
+
func contains(l []string, s string) bool {
for _, e := range l {
if e == s {
diff --git a/dexpreopt/dexpreopt_gen/Android.bp b/dexpreopt/dexpreopt_gen/Android.bp
index 0790391..3f0619c 100644
--- a/dexpreopt/dexpreopt_gen/Android.bp
+++ b/dexpreopt/dexpreopt_gen/Android.bp
@@ -8,4 +8,4 @@
"blueprint-pathtools",
"blueprint-proptools",
],
-}
\ No newline at end of file
+}
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index d239993..ec31549 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -44,7 +44,7 @@
ProfileClassListing: android.OptionalPath{},
ProfileIsTextListing: false,
EnforceUsesLibraries: false,
- PresentOptionalUsesLibraries: nil,
+ OptionalUsesLibraries: nil,
UsesLibraries: nil,
LibraryPaths: nil,
Archs: []android.ArchType{android.Arm},
diff --git a/doc.go b/doc.go
index 543c460..299fd2b 100644
--- a/doc.go
+++ b/doc.go
@@ -46,8 +46,8 @@
//
// Target architecture
// The target architecture is the preferred architecture supported by the selected
-// device. It is most commonly 32-bit arm, but may also be 64-bit arm, 32-bit or
-// 64-bit x86, or mips.
+// device. It is most commonly 32-bit arm, but may also be 64-bit arm, 32-bit
+// x86, or 64-bit x86.
//
// Secondary architecture
// The secondary architecture specifies the architecture to compile a second copy
diff --git a/docs/map_files.md b/docs/map_files.md
new file mode 100644
index 0000000..9fc0d14
--- /dev/null
+++ b/docs/map_files.md
@@ -0,0 +1,174 @@
+# Native API Map Files
+
+Native APIs such as those exposed by the NDK, LL-NDK, or APEX are described by
+map.txt files. These files are [linker version scripts] with comments that are
+semantically meaningful to [gen_stub_libs.py]. For an example of a map file, see
+[libc.map.txt].
+
+[gen_stub_libs.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/gen_stub_libs.py
+[libc.map.txt]: https://cs.android.com/android/platform/superproject/+/master:bionic/libc/libc.map.txt
+[linker version scripts]: https://www.gnu.org/software/gnulib/manual/html_node/LD-Version-Scripts.html
+
+## Basic format
+
+A linker version script defines at least one alphanumeric "version" definition,
+each of which contain a list of symbols. For example:
+
+```txt
+MY_API_R { # introduced=R
+ global:
+ api_foo;
+ api_bar;
+ local:
+ *;
+};
+
+MY_API_S { # introduced=S
+ global:
+ api_baz;
+} MY_API_R;
+```
+
+Comments on the same line as either a version definition or a symbol name have
+meaning. If you need to add any comments that should not be interpreted by the
+stub generator, keep them on their own line. For a list of supported comments,
+see the "Tags" section.
+
+Here, `api_foo` and `api_bar` are exposed in the generated stubs with the
+`MY_API_R` version and `api_baz` is exposed with the `MY_API_S` version. No
+other symbols are defined as public by this API. `MY_API_S` inherits all symbols
+defined by `MY_API_R`.
+
+When generating NDK API stubs from this version script, the stub library for R
+will define `api_foo` and `api_bar`. The stub library for S will define all
+three APIs.
+
+Note that, with few exceptions (see "Special version names" below), the name of
+the version has no inherent meaning.
+
+These map files can (and should) also be used as version scripts for building
+the implementation library rather than just defining the stub interface by using
+the `version_script` property of `cc_library`. This has the effect of limiting
+symbol visibility of the library to expose only the interface named by the map
+file. Without this, APIs that you have not explicitly exposed will still be
+available to users via `dlsym`. Note: All comments are ignored in this case. Any
+symbol named in any `global:` group will be visible.
+
+## Special version names
+
+Version names that end with `_PRIVATE` or `_PLATFORM` will not be exposed in any
+stubs, but will be exposed in the implementation library. Using either of these
+naming schemes is equivalent to marking the version with the `platform-only`
+tag. See the docs for `platform-only` for more information.
+
+## Tags
+
+Comments on the same line as a version definition or a symbol name are
+interpreted by the stub generator. Multiple space-delimited tags may be used on
+the same line. The supported tags are:
+
+### apex
+
+Indicates that the version or symbol is to be exposed in the APEX stubs rather
+than the NDK. May be used in combination with `llndk` if the symbol is exposed
+to both APEX and the LL-NDK.
+
+### future
+
+Indicates that the version or symbol is first introduced in the "future" API
+level. This is an abitrarily high API level used to define APIs that have not
+yet been added to a specific release.
+
+### introduced
+
+Indicates the version in which an API was first introduced. For example,
+`introduced=21` specifies that the API was first added (or first made public) in
+API level 21. This tag can be applied to either a version definition or an
+individual symbol. If applied to a version, all symbols contained in the version
+will have the tag applied. An `introduced` tag on a symbol overrides the value
+set for the version, if both are defined.
+
+Note: The map file alone does not contain all the information needed to
+determine which API level an API was added in. The `first_version` property of
+`ndk_library` will dictate which API levels stubs are generated for. If the
+module sets `first_version: "21"`, no symbols were introduced before API 21.
+
+Codenames can (and typically should) be used when defining new APIs. This allows
+the actual number of the API level to remain vague during development of that
+release. For example, `introduced=S` can be used to define APIs added in S. Any
+code name known to the build system can be used. For a list of versions known to
+the build system, see `out/soong/api_levels.json` (if not present, run `m
+out/soong/api_levels.json` to generate it).
+
+Architecture-specific variants of this tag exist:
+
+* `introduced-arm=VERSION`
+* `introduced-arm64=VERSION`
+* `introduced-x86=VERSION`
+* `introduced-x86_64=VERSION`
+
+The architecture-specific tag will take precedence over the architecture-generic
+tag when generating stubs for that architecture if both are present. If the
+symbol is defined with only architecture-specific tags, it will not be present
+for architectures that are not named.
+
+Note: The architecture-specific tags should, in general, not be used. These are
+primarily needed for APIs that were wrongly inconsistently exposed by libc/libm
+in old versions of Android before the stubs were well maintained. Think hard
+before using an architecture-specific tag for a new API.
+
+### llndk
+
+Indicates that the version or symbol is to be exposed in the LL-NDK stubs rather
+than the NDK. May be used in combination with `apex` if the symbol is exposed to
+both APEX and the LL-NDK.
+
+### platform-only
+
+Indicates that the version or symbol is public in the implementation library but
+should not be exposed in the stub library. Developers can still access them via
+`dlsym`, but they will not be exposed in the stubs so it should at least be
+clear to the developer that they are up to no good.
+
+The typical use for this tag is for exposing an API to the platform that is not
+for use by the NDK, LL-NDK, or APEX. It is preferable to keep such APIs in an
+entirely separate library to protect them from access via `dlsym`, but this is
+not always possible.
+
+### var
+
+Used to define a public global variable. By default all symbols are exposed as
+functions. In the uncommon situation of exposing a global variable, the `var`
+tag may be used.
+
+### versioned=VERSION
+
+Behaves similarly to `introduced` but defines the first version that the stub
+library should apply symbol versioning. For example:
+
+```txt
+R { # introduced=R
+ global:
+ foo;
+ bar; # versioned=S
+ local:
+ *;
+};
+```
+
+The stub library for R will contain symbols for both `foo` and `bar`, but only
+`foo` will include a versioned symbol `foo@R`. The stub library for S will
+contain both symbols, as well as the versioned symbols `foo@R` and `bar@R`.
+
+This tag is not commonly needed and is only used to hide symbol versioning
+mistakes that shipped as part of the platform.
+
+Note: Like `introduced`, the map file does not tell the whole story. The
+`ndk_library` Soong module may define a `unversioned_until` property that sets
+the default for the entire map file.
+
+### weak
+
+Indicates that the symbol should be [weak] in the stub library.
+
+[weak]: https://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/Function-Attributes.html
diff --git a/docs/perf.md b/docs/perf.md
index 538adff..86a27b4 100644
--- a/docs/perf.md
+++ b/docs/perf.md
@@ -12,6 +12,41 @@

+### Critical path
+
+soong_ui logs the wall time of the longest dependency chain compared to the
+elapsed wall time in `$OUT_DIR/soong.log`. For example:
+```
+critical path took 3m10s
+elapsed time 5m16s
+perfect parallelism ratio 60%
+critical path:
+ 0:00 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/policy_2.conf
+ 0:04 build out/target/product/generic_arm64/obj/FAKE/sepolicy_neverallows_intermediates/sepolicy_neverallows
+ 0:13 build out/target/product/generic_arm64/obj/ETC/plat_sepolicy.cil_intermediates/plat_sepolicy.cil
+ 0:01 build out/target/product/generic_arm64/obj/ETC/plat_pub_versioned.cil_intermediates/plat_pub_versioned.cil
+ 0:02 build out/target/product/generic_arm64/obj/ETC/vendor_sepolicy.cil_intermediates/vendor_sepolicy.cil
+ 0:16 build out/target/product/generic_arm64/obj/ETC/sepolicy_intermediates/sepolicy
+ 0:00 build out/target/product/generic_arm64/obj/ETC/plat_seapp_contexts_intermediates/plat_seapp_contexts
+ 0:00 Install: out/target/product/generic_arm64/system/etc/selinux/plat_seapp_contexts
+ 0:02 build out/target/product/generic_arm64/obj/NOTICE.txt
+ 0:00 build out/target/product/generic_arm64/obj/NOTICE.xml.gz
+ 0:00 build out/target/product/generic_arm64/system/etc/NOTICE.xml.gz
+ 0:01 Installed file list: out/target/product/generic_arm64/installed-files.txt
+ 1:00 Target system fs image: out/target/product/generic_arm64/obj/PACKAGING/systemimage_intermediates/system.img
+ 0:01 Install system fs image: out/target/product/generic_arm64/system.img
+ 0:01 Target vbmeta image: out/target/product/generic_arm64/vbmeta.img
+ 1:26 Package target files: out/target/product/generic_arm64/obj/PACKAGING/target_files_intermediates/aosp_arm64-target_files-6663974.zip
+ 0:01 Package: out/target/product/generic_arm64/aosp_arm64-img-6663974.zip
+ 0:01 Dist: /buildbot/dist_dirs/aosp-master-linux-aosp_arm64-userdebug/6663974/aosp_arm64-img-6663974.zip
+```
+
+If the elapsed time is much longer than the critical path then additional
+parallelism on the build machine will improve total build times. If there are
+long individual times listed in the critical path then improving build times
+for those steps or adjusting dependencies so that those steps can run earlier
+in the build graph will improve total build times.
+
### Soong
Soong can be traced and profiled using the standard Go tools. It understands
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 842d9ee..5dd2a86 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,22 +28,29 @@
func init() {
pctx.Import("android/soong/android")
+ RegisterPrebuiltEtcBuildComponents(android.InitRegistrationContext)
+}
- android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
- android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
- android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
- android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
- android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
- android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
+ ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+ ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
+ ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+ ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
+ ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+ ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
}
type prebuiltEtcProperties struct {
// Source file of this prebuilt.
Src *string `android:"path,arch_variant"`
- // optional subdirectory under which this file is installed into
+ // optional subdirectory under which this file is installed into, cannot be specified with relative_install_path, prefer relative_install_path
Sub_dir *string `android:"arch_variant"`
+ // optional subdirectory under which this file is installed into, cannot be specified with sub_dir
+ Relative_install_path *string `android:"arch_variant"`
+
// optional name for the installed file. If unspecified, name of the module is used as the file name
Filename *string `android:"arch_variant"`
@@ -59,10 +66,14 @@
// Whether this module is directly installable to one of the partitions. Default: true.
Installable *bool
+
+ // Install symlinks to the installed file.
+ Symlinks []string `android:"arch_variant"`
}
type PrebuiltEtcModule interface {
android.Module
+ BaseDir() string
SubDir() string
OutputFile() android.OutputPath
}
@@ -154,7 +165,20 @@
}
func (p *PrebuiltEtc) SubDir() string {
- return android.String(p.properties.Sub_dir)
+ if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
+ return subDir
+ }
+ return proptools.String(p.properties.Relative_install_path)
+}
+
+func (p *PrebuiltEtc) BaseDir() string {
+ // If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
+ // socInstallDirBase.
+ installBaseDir := p.installDirBase
+ if p.SocSpecific() && p.socInstallDirBase != "" {
+ installBaseDir = p.socInstallDirBase
+ }
+ return installBaseDir
}
func (p *PrebuiltEtc) Installable() bool {
@@ -177,13 +201,11 @@
}
p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
- // If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
- // socInstallDirBase.
- installBaseDir := p.installDirBase
- if ctx.SocSpecific() && p.socInstallDirBase != "" {
- installBaseDir = p.socInstallDirBase
+ if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
+ ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
- p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, proptools.String(p.properties.Sub_dir))
+
+ p.installDirPath = android.PathForModuleInstall(ctx, p.BaseDir(), p.SubDir())
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
@@ -211,10 +233,13 @@
entries.SetString("LOCAL_MODULE_TAGS", "optional")
entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+ if len(p.properties.Symlinks) > 0 {
+ entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
+ }
entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
if p.additionalDependencies != nil {
for _, path := range *p.additionalDependencies {
- entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+ entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
}
}
},
@@ -287,3 +312,15 @@
android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
return module
}
+
+// prebuilt_dsp installs a DSP related file to <partition>/etc/dsp directory for system image.
+// If soc_specific property is set to true, the DSP related file is installed to the vendor <partition>/dsp
+// directory for vendor image.
+func PrebuiltDSPFactory() android.Module {
+ module := &PrebuiltEtc{}
+ module.socInstallDirBase = "dsp"
+ InitPrebuiltEtcModule(module, "etc/dsp")
+ // This module is device-only
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ return module
+}
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index e13cb3c..8fc36c2 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -49,7 +49,7 @@
os.Exit(run())
}
-func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+func testPrebuiltEtcContext(t *testing.T, bp string) (*android.TestContext, android.Config) {
fs := map[string][]byte{
"foo.conf": nil,
"bar.conf": nil,
@@ -65,7 +65,16 @@
ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+ ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
ctx.Register(config)
+
+ return ctx, config
+}
+
+func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -74,6 +83,24 @@
return ctx, config
}
+func testPrebuiltEtcError(t *testing.T, pattern, bp string) {
+ t.Helper()
+
+ ctx, config := testPrebuiltEtcContext(t, bp)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ android.FailIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
func TestPrebuiltEtcVariants(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc {
@@ -183,6 +210,33 @@
}
}
+func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ relative_install_path: "bar",
+ }
+ `)
+
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+ expected := buildDir + "/target/product/test_device/system/etc/bar"
+ if p.installDirPath.String() != expected {
+ t.Errorf("expected %q, got %q", expected, p.installDirPath.String())
+ }
+}
+
+func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
+ testPrebuiltEtcError(t, "relative_install_path is set. Cannot set sub_dir", `
+ prebuilt_etc {
+ name: "foo.conf",
+ src: "foo.conf",
+ sub_dir: "bar",
+ relative_install_path: "bar",
+ }
+ `)
+}
+
func TestPrebuiltEtcHost(t *testing.T) {
ctx, _ := testPrebuiltEtc(t, `
prebuilt_etc_host {
@@ -281,3 +335,39 @@
})
}
}
+
+func TestPrebuiltDSPDirPath(t *testing.T) {
+ targetPath := filepath.Join(buildDir, "/target/product/test_device")
+ tests := []struct {
+ description string
+ config string
+ expectedPath string
+ }{{
+ description: "prebuilt: system dsp",
+ config: `
+ prebuilt_dsp {
+ name: "foo.conf",
+ src: "foo.conf",
+ }`,
+ expectedPath: filepath.Join(targetPath, "system/etc/dsp"),
+ }, {
+ description: "prebuilt: vendor dsp",
+ config: `
+ prebuilt_dsp {
+ name: "foo.conf",
+ src: "foo.conf",
+ soc_specific: true,
+ sub_dir: "sub_dir",
+ }`,
+ expectedPath: filepath.Join(targetPath, "vendor/dsp/sub_dir"),
+ }}
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ ctx, _ := testPrebuiltEtc(t, tt.config)
+ p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+ if p.installDirPath.String() != tt.expectedPath {
+ t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath)
+ }
+ })
+ }
+}
diff --git a/finder/Android.bp b/finder/Android.bp
index 47b47c9..a5d7fd4 100644
--- a/finder/Android.bp
+++ b/finder/Android.bp
@@ -17,7 +17,7 @@
//
subdirs = [
- "cmd"
+ "cmd",
]
bootstrap_go_package {
@@ -30,8 +30,6 @@
"finder_test.go",
],
deps: [
- "soong-finder-fs",
+ "soong-finder-fs",
],
}
-
-
diff --git a/finder/cmd/Android.bp b/finder/cmd/Android.bp
index 9dc84ae..e066c39 100644
--- a/finder/cmd/Android.bp
+++ b/finder/cmd/Android.bp
@@ -22,8 +22,6 @@
"finder.go",
],
deps: [
- "soong-finder"
+ "soong-finder",
],
}
-
-
diff --git a/finder/finder.go b/finder/finder.go
index 89be0f5..6513fa3 100644
--- a/finder/finder.go
+++ b/finder/finder.go
@@ -325,7 +325,12 @@
// Shutdown declares that the finder is no longer needed and waits for its cleanup to complete
// Currently, that only entails waiting for the database dump to complete.
func (f *Finder) Shutdown() {
- f.waitForDbDump()
+ f.WaitForDbDump()
+}
+
+// WaitForDbDump returns once the database has been written to f.DbPath.
+func (f *Finder) WaitForDbDump() {
+ f.shutdownWaitgroup.Wait()
}
// End of public api
@@ -345,10 +350,6 @@
}
}
-func (f *Finder) waitForDbDump() {
- f.shutdownWaitgroup.Wait()
-}
-
// joinCleanPaths is like filepath.Join but is faster because
// joinCleanPaths doesn't have to support paths ending in "/" or containing ".."
func joinCleanPaths(base string, leaf string) string {
@@ -1393,17 +1394,25 @@
for _, child := range children {
linkBits := child.Mode() & os.ModeSymlink
isLink := linkBits != 0
- if child.IsDir() {
- if !isLink {
+ if isLink {
+ childPath := filepath.Join(path, child.Name())
+ childStat, err := f.filesystem.Stat(childPath)
+ if err != nil {
+ // If stat fails this is probably a broken or dangling symlink, treat it as a file.
+ subfiles = append(subfiles, child.Name())
+ } else if childStat.IsDir() {
// Skip symlink dirs.
// We don't have to support symlink dirs because
// that would cause duplicates.
- subdirs = append(subdirs, child.Name())
+ } else {
+ // We do have to support symlink files because the link name might be
+ // different than the target name
+ // (for example, Android.bp -> build/soong/root.bp)
+ subfiles = append(subfiles, child.Name())
}
+ } else if child.IsDir() {
+ subdirs = append(subdirs, child.Name())
} else {
- // We do have to support symlink files because the link name might be
- // different than the target name
- // (for example, Android.bp -> build/soong/root.bp)
subfiles = append(subfiles, child.Name())
}
diff --git a/finder/finder_test.go b/finder/finder_test.go
index f6d0aa9..88b0c05 100644
--- a/finder/finder_test.go
+++ b/finder/finder_test.go
@@ -20,11 +20,8 @@
"log"
"os"
"path/filepath"
- "reflect"
- "runtime/debug"
"sort"
"testing"
- "time"
"android/soong/finder/fs"
)
@@ -41,7 +38,7 @@
func newFinderWithNumThreads(t *testing.T, filesystem *fs.MockFs, cacheParams CacheParams, numThreads int) *Finder {
f, err := newFinderAndErr(t, filesystem, cacheParams, numThreads)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -62,7 +59,7 @@
func finderWithSameParams(t *testing.T, original *Finder) *Finder {
f, err := finderAndErrorWithSameParams(t, original)
if err != nil {
- fatal(t, err.Error())
+ t.Fatal(err.Error())
}
return f
}
@@ -78,146 +75,13 @@
return f, err
}
-func write(t *testing.T, path string, content string, filesystem *fs.MockFs) {
- parent := filepath.Dir(path)
- filesystem.MkDirs(parent)
- err := filesystem.WriteFile(path, []byte(content), 0777)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func create(t *testing.T, path string, filesystem *fs.MockFs) {
- write(t, path, "hi", filesystem)
-}
-
-func delete(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.Remove(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func removeAll(t *testing.T, path string, filesystem *fs.MockFs) {
- err := filesystem.RemoveAll(path)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func move(t *testing.T, oldPath string, newPath string, filesystem *fs.MockFs) {
- err := filesystem.Rename(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-
-func link(t *testing.T, newPath string, oldPath string, filesystem *fs.MockFs) {
- parentPath := filepath.Dir(newPath)
- err := filesystem.MkDirs(parentPath)
- if err != nil {
- t.Fatal(err.Error())
- }
- err = filesystem.Symlink(oldPath, newPath)
- if err != nil {
- fatal(t, err.Error())
- }
-}
-func read(t *testing.T, path string, filesystem *fs.MockFs) string {
- reader, err := filesystem.Open(path)
- if err != nil {
- t.Fatalf(err.Error())
- }
- bytes, err := ioutil.ReadAll(reader)
- if err != nil {
- t.Fatal(err.Error())
- }
- return string(bytes)
-}
-func modTime(t *testing.T, path string, filesystem *fs.MockFs) time.Time {
- stats, err := filesystem.Lstat(path)
- if err != nil {
- t.Fatal(err.Error())
- }
- return stats.ModTime()
-}
-func setReadable(t *testing.T, path string, readable bool, filesystem *fs.MockFs) {
- err := filesystem.SetReadable(path, readable)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func setReadErr(t *testing.T, path string, readErr error, filesystem *fs.MockFs) {
- err := filesystem.SetReadErr(path, readErr)
- if err != nil {
- t.Fatal(err.Error())
- }
-}
-
-func fatal(t *testing.T, message string) {
- t.Error(message)
- debug.PrintStack()
- t.FailNow()
-}
-
-func assertSameResponse(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
- len(expected), expected, len(actual), actual),
- )
- }
-}
-
-func assertSameStatCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect Stat calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-func assertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
- sort.Strings(actual)
- sort.Strings(expected)
-
- if !reflect.DeepEqual(actual, expected) {
- fatal(
- t,
- fmt.Sprintf(
- "Finder made incorrect ReadDir calls.\n"+
- "Actual:\n"+
- "%v\n"+
- "Expected:\n"+
- "%v\n"+
- "\n",
- actual, expected),
- )
- }
-}
-
// runSimpleTests creates a few files, searches for findme.txt, and checks for the expected matches
func runSimpleTest(t *testing.T, existentPaths []string, expectedMatches []string) {
filesystem := newFs()
root := "/tmp"
filesystem.MkDirs(root)
for _, path := range existentPaths {
- create(t, filepath.Join(root, path), filesystem)
+ fs.Create(t, filepath.Join(root, path), filesystem)
}
finder := newFinder(t,
@@ -237,7 +101,7 @@
for i := range expectedMatches {
absoluteMatches = append(absoluteMatches, filepath.Join(root, expectedMatches[i]))
}
- assertSameResponse(t, foundPaths, absoluteMatches)
+ fs.AssertSameResponse(t, foundPaths, absoluteMatches)
}
// testAgainstSeveralThreadcounts runs the given test for each threadcount that we care to test
@@ -288,7 +152,7 @@
func TestEmptyPath(t *testing.T) {
filesystem := newFs()
root := "/tmp"
- create(t, filepath.Join(root, "findme.txt"), filesystem)
+ fs.Create(t, filepath.Join(root, "findme.txt"), filesystem)
finder := newFinder(
t,
@@ -302,7 +166,7 @@
foundPaths := finder.FindNamedAt("", "findme.txt")
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
}
func TestFilesystemRoot(t *testing.T) {
@@ -311,7 +175,7 @@
filesystem := newFs()
root := "/"
createdPath := "/findme.txt"
- create(t, createdPath, filesystem)
+ fs.Create(t, createdPath, filesystem)
finder := newFinderWithNumThreads(
t,
@@ -326,7 +190,7 @@
foundPaths := finder.FindNamedAt(root, "findme.txt")
- assertSameResponse(t, foundPaths, []string{createdPath})
+ fs.AssertSameResponse(t, foundPaths, []string{createdPath})
}
testAgainstSeveralThreadcounts(t, testWithNumThreads)
@@ -334,7 +198,7 @@
func TestNonexistentDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
_, err := newFinderAndErr(
t,
@@ -346,18 +210,18 @@
1,
)
if err == nil {
- fatal(t, "Did not fail when given a nonexistent root directory")
+ t.Fatal("Did not fail when given a nonexistent root directory")
}
}
func TestExcludeDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/exclude/findme.txt", filesystem)
- create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
- create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
- create(t, "/tmp/subdir/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/exclude/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/exclude/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
finder := newFinder(
t,
@@ -372,7 +236,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/subdir/findme.txt",
"/tmp/subdir/subdir/findme.txt"})
@@ -380,15 +244,15 @@
func TestPruneFiles(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/out/findme.txt", filesystem)
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
- create(t, "/tmp/out/child/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/child/findme.txt", filesystem)
- create(t, "/tmp/out2/.ignore-out-dir", filesystem)
- create(t, "/tmp/out2/sub/findme.txt", filesystem)
+ fs.Create(t, "/tmp/out2/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out2/sub/findme.txt", filesystem)
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/include/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/include/findme.txt", filesystem)
finder := newFinder(
t,
@@ -403,7 +267,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/include/findme.txt"})
}
@@ -412,10 +276,10 @@
// tests of the filesystem root are in TestFilesystemRoot
func TestRootDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -429,17 +293,17 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/a/subdir/findme.txt"})
}
func TestUncachedDir(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/subdir/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/subdir/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/subdir/findme.txt", filesystem)
finder := newFinder(
t,
@@ -456,7 +320,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -464,9 +328,9 @@
func TestSearchingForFilesExcludedFromCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it
finder := newFinder(
@@ -483,7 +347,7 @@
// fail to notice its slowness. Instead, we only ever search the cache for files
// to return, which enforces that we can determine which files will be
// interesting upfront.
- assertSameResponse(t, foundPaths, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{})
finder.Shutdown()
}
@@ -491,12 +355,12 @@
func TestRelativeFilePaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/ignore/hi.txt", filesystem)
- create(t, "/tmp/include/hi.txt", filesystem)
- create(t, "/cwd/hi.txt", filesystem)
- create(t, "/cwd/a/hi.txt", filesystem)
- create(t, "/cwd/a/a/hi.txt", filesystem)
- create(t, "/rel/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/ignore/hi.txt", filesystem)
+ fs.Create(t, "/tmp/include/hi.txt", filesystem)
+ fs.Create(t, "/cwd/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/hi.txt", filesystem)
+ fs.Create(t, "/cwd/a/a/hi.txt", filesystem)
+ fs.Create(t, "/rel/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -509,25 +373,25 @@
defer finder.Shutdown()
foundPaths := finder.FindNamedAt("a", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
foundPaths = finder.FindNamedAt(".", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"hi.txt",
"a/hi.txt",
"a/a/hi.txt"})
foundPaths = finder.FindNamedAt("/rel", "hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/rel/a/hi.txt"})
foundPaths = finder.FindNamedAt("/tmp/include", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/include/hi.txt"})
}
// have to run this test with the race-detector (`go test -race src/android/soong/finder/*.go`)
@@ -535,7 +399,7 @@
func TestRootDirsContainedInOtherRootDirs(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt", filesystem)
finder := newFinder(
t,
@@ -549,15 +413,15 @@
foundPaths := finder.FindNamedAt("/tmp/a", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/b/c/d/e/f/g/h/i/j/findme.txt"})
}
func TestFindFirst(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
- create(t, "/tmp/b/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/a/hi.txt", filesystem)
finder := newFinder(
t,
@@ -571,7 +435,7 @@
foundPaths := finder.FindFirstNamed("hi.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/hi.txt",
"/tmp/b/hi.txt"},
)
@@ -593,7 +457,7 @@
}
sort.Strings(paths)
for _, path := range paths {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -621,7 +485,7 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
foundPaths := <-results
- assertSameResponse(t, foundPaths, paths)
+ fs.AssertSameResponse(t, foundPaths, paths)
}
}
@@ -649,7 +513,7 @@
}
sort.Strings(allFiles)
for _, path := range allFiles {
- create(t, path, filesystem)
+ fs.Create(t, path, filesystem)
}
// set up a finder
@@ -687,16 +551,16 @@
// check that each response was correct
for i := 0; i < numTests; i++ {
testRun := <-testRuns
- assertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
+ fs.AssertSameResponse(t, testRun.foundMatches, testRun.correctMatches)
}
}
func TestStrangelyFormattedPaths(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
finder := newFinder(
t,
@@ -710,7 +574,7 @@
foundPaths := finder.FindNamedAt("//tmp//a//..", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
"/tmp/findme.txt"})
@@ -719,9 +583,9 @@
func TestCorruptedCacheHeader(t *testing.T) {
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- write(t, "/finder/finder-db", "sample header", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Write(t, "/finder/finder-db", "sample header", filesystem)
finder := newFinder(
t,
@@ -735,7 +599,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt",
"/tmp/findme.txt"})
}
@@ -743,8 +607,8 @@
func TestCanUseCache(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -759,11 +623,11 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
finder.Shutdown()
// check results
- cacheText := read(t, finder.DbPath, filesystem)
+ cacheText := fs.Read(t, finder.DbPath, filesystem)
if len(cacheText) < 1 {
t.Fatalf("saved cache db is empty\n")
}
@@ -780,8 +644,8 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
- assertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.StatCalls, statCalls)
finder2.Shutdown()
}
@@ -789,8 +653,8 @@
func TestCorruptedCacheBody(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -807,7 +671,7 @@
// check the response of the first finder
correctResponse := []string{"/tmp/a/findme.txt",
"/tmp/findme.txt"}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numStatCalls := len(filesystem.StatCalls)
numReadDirCalls := len(filesystem.ReadDirCalls)
@@ -828,7 +692,7 @@
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
numNewStatCalls := len(filesystem.StatCalls)
numNewReadDirCalls := len(filesystem.ReadDirCalls)
// It's permissable to make more Stat calls with a corrupted cache because
@@ -853,7 +717,7 @@
func TestStatCalls(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
// run finder
finder := newFinder(
@@ -868,19 +732,19 @@
finder.Shutdown()
// check response
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
}
func TestFileAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -895,11 +759,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/findme.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -908,9 +772,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/c/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c"})
finder2.Shutdown()
}
@@ -918,11 +782,11 @@
func TestDirectoriesAdded(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/ignore.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/ignore.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -936,13 +800,13 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/c/new/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
- create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/new/new2/ignoreme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -950,11 +814,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/a/findme.txt", "/tmp/b/c/new/findme.txt", "/tmp/b/c/new/new2/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b/c", "/tmp/b/c/new", "/tmp/b/c/new/new2"})
finder2.Shutdown()
}
@@ -962,8 +826,8 @@
func TestDirectoryAndSubdirectoryBothUpdated(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi1.txt", filesystem)
- create(t, "/tmp/a/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/hi1.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi1.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -977,12 +841,12 @@
foundPaths := finder.FindNamedAt("/tmp", "hi1.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi1.txt", "/tmp/a/hi1.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/hi2.txt", filesystem)
- create(t, "/tmp/a/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/hi2.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi2.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -990,11 +854,11 @@
foundPaths = finder2.FindAll()
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi1.txt", "/tmp/hi2.txt", "/tmp/a/hi1.txt", "/tmp/a/hi2.txt"})
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a"})
finder2.Shutdown()
}
@@ -1002,11 +866,11 @@
func TestFileDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/ignoreme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
- create(t, "/tmp/b/c/nope.txt", filesystem)
- create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
+ fs.Create(t, "/tmp/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/nope.txt", filesystem)
+ fs.Create(t, "/tmp/b/c/d/irrelevant.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1020,11 +884,11 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- delete(t, "/tmp/b/findme.txt", filesystem)
+ fs.Delete(t, "/tmp/b/findme.txt", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1032,9 +896,9 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/findme.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/c", "/tmp/b/c/d"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
finder2.Shutdown()
}
@@ -1042,11 +906,11 @@
func TestDirectoriesDeleted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1060,7 +924,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1069,7 +933,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- removeAll(t, "/tmp/a/1", filesystem)
+ fs.RemoveAll(t, "/tmp/a/1", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1077,7 +941,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/b/findme.txt"})
// Technically, we don't care whether /tmp/a/1/2 gets Statted or gets skipped
// if the Finder detects the nonexistence of /tmp/a/1
@@ -1087,9 +951,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/a"})
finder2.Shutdown()
}
@@ -1097,11 +961,11 @@
func TestDirectoriesMoved(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1115,7 +979,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1124,7 +988,7 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/c", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/c", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1132,7 +996,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/b/findme.txt",
"/tmp/c/findme.txt",
@@ -1146,20 +1010,20 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/c", "/tmp/c/1", "/tmp/c/1/2"})
finder2.Shutdown()
}
func TestDirectoriesSwapped(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/1/findme.txt", filesystem)
- create(t, "/tmp/a/1/2/findme.txt", filesystem)
- create(t, "/tmp/b/findme.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/1/2/findme.txt", filesystem)
+ fs.Create(t, "/tmp/b/findme.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1173,7 +1037,7 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/a/1/findme.txt",
@@ -1182,9 +1046,9 @@
// modify the filesystem
filesystem.Clock.Tick()
- move(t, "/tmp/a", "/tmp/temp", filesystem)
- move(t, "/tmp/b", "/tmp/a", filesystem)
- move(t, "/tmp/temp", "/tmp/b", filesystem)
+ fs.Move(t, "/tmp/a", "/tmp/temp", filesystem)
+ fs.Move(t, "/tmp/b", "/tmp/a", filesystem)
+ fs.Move(t, "/tmp/temp", "/tmp/b", filesystem)
filesystem.ClearMetrics()
// run the second finder
@@ -1192,7 +1056,7 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt",
"/tmp/a/findme.txt",
"/tmp/b/findme.txt",
@@ -1206,9 +1070,9 @@
// The Finder is currently implemented to always restat every dir and
// to not short-circuit due to nonexistence of parents (but it will remove
// missing dirs from the cache for next time)
- assertSameStatCalls(t, filesystem.StatCalls,
+ fs.AssertSameStatCalls(t, filesystem.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/1", "/tmp/a/1/2", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp", "/tmp/a", "/tmp/b", "/tmp/b/1", "/tmp/b/1/2"})
finder2.Shutdown()
}
@@ -1217,15 +1081,15 @@
// runFsReplacementTest is a helper method called by other tests
func runFsReplacementTest(t *testing.T, fs1 *fs.MockFs, fs2 *fs.MockFs) {
// setup fs1
- create(t, "/tmp/findme.txt", fs1)
- create(t, "/tmp/a/findme.txt", fs1)
- create(t, "/tmp/a/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/findme.txt", fs1)
+ fs.Create(t, "/tmp/a/a/findme.txt", fs1)
// setup fs2 to have the same directories but different files
- create(t, "/tmp/findme.txt", fs2)
- create(t, "/tmp/a/findme.txt", fs2)
- create(t, "/tmp/a/a/ignoreme.txt", fs2)
- create(t, "/tmp/a/b/findme.txt", fs2)
+ fs.Create(t, "/tmp/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/findme.txt", fs2)
+ fs.Create(t, "/tmp/a/a/ignoreme.txt", fs2)
+ fs.Create(t, "/tmp/a/b/findme.txt", fs2)
// run the first finder
finder := newFinder(
@@ -1239,12 +1103,12 @@
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
finder.Shutdown()
// check the response of the first finder
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/a/findme.txt"})
// copy the cache data from the first filesystem to the second
- cacheContent := read(t, finder.DbPath, fs1)
- write(t, finder.DbPath, cacheContent, fs2)
+ cacheContent := fs.Read(t, finder.DbPath, fs1)
+ fs.Write(t, finder.DbPath, cacheContent, fs2)
// run the second finder, with the same config and same cache contents but a different filesystem
finder2 := newFinder(
@@ -1258,11 +1122,11 @@
foundPaths = finder2.FindNamedAt("/tmp", "findme.txt")
// check results
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/findme.txt", "/tmp/a/findme.txt", "/tmp/a/b/findme.txt"})
- assertSameStatCalls(t, fs2.StatCalls,
+ fs.AssertSameStatCalls(t, fs2.StatCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
- assertSameReadDirCalls(t, fs2.ReadDirCalls,
+ fs.AssertSameReadDirCalls(t, fs2.ReadDirCalls,
[]string{"/tmp", "/tmp/a", "/tmp/a/a", "/tmp/a/b"})
finder2.Shutdown()
}
@@ -1292,7 +1156,7 @@
// setup filesystem
filesystem := newFs()
for i := 0; i < 5; i++ {
- create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
+ fs.Create(t, fmt.Sprintf("/tmp/%v/findme.txt", i), filesystem)
}
// run the first finder
@@ -1308,7 +1172,7 @@
finder.Shutdown()
// read db file
- string1 := read(t, finder.DbPath, filesystem)
+ string1 := fs.Read(t, finder.DbPath, filesystem)
err := filesystem.Remove(finder.DbPath)
if err != nil {
@@ -1320,7 +1184,7 @@
finder2.FindNamedAt("/tmp", "findme.txt")
finder2.Shutdown()
- string2 := read(t, finder.DbPath, filesystem)
+ string2 := fs.Read(t, finder.DbPath, filesystem)
if string1 != string2 {
t.Errorf("Running Finder twice generated two dbs not having identical contents.\n"+
@@ -1343,9 +1207,9 @@
func TestNumSyscallsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/misc.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/misc.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1357,15 +1221,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it doesn't check the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, refoundPaths, foundPaths)
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, foundPaths)
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1373,9 +1237,9 @@
func TestChangingParamsOfSecondFind(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/findme.txt", filesystem)
- create(t, "/tmp/a/findme.txt", filesystem)
- create(t, "/tmp/a/metoo.txt", filesystem)
+ fs.Create(t, "/tmp/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/findme.txt", filesystem)
+ fs.Create(t, "/tmp/a/metoo.txt", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1387,15 +1251,15 @@
},
)
foundPaths := finder.FindNamedAt("/tmp", "findme.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/findme.txt", "/tmp/a/findme.txt"})
filesystem.ClearMetrics()
// run the finder again and confirm it gets the right answer without asking the filesystem
refoundPaths := finder.FindNamedAt("/tmp", "metoo.txt")
- assertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
- assertSameStatCalls(t, filesystem.StatCalls, []string{})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, refoundPaths, []string{"/tmp/a/metoo.txt"})
+ fs.AssertSameStatCalls(t, filesystem.StatCalls, []string{})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder.Shutdown()
}
@@ -1403,15 +1267,15 @@
func TestSymlinkPointingToFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/ignoreme.txt", filesystem)
- link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
- link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
- link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
- link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
- link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/ignoreme.txt", filesystem)
+ fs.Link(t, "/tmp/hi.txt", "a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/b/hi.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/c/hi.txt", "/tmp/hi.txt", filesystem)
+ fs.Link(t, "/tmp/d/hi.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/d/bye.txt", "../a/hi.txt", filesystem)
+ fs.Link(t, "/tmp/e/bye.txt", "../a/bye.txt", filesystem)
+ fs.Link(t, "/tmp/f/hi.txt", "somethingThatDoesntExist", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1432,20 +1296,21 @@
"/tmp/d/hi.txt",
"/tmp/f/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
func TestSymlinkPointingToDirectory(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/dir/hi.txt", filesystem)
- create(t, "/tmp/dir/ignoreme.txt", filesystem)
+ fs.Create(t, "/tmp/dir/hi.txt", filesystem)
+ fs.Create(t, "/tmp/dir/ignoreme.txt", filesystem)
- link(t, "/tmp/links/dir", "../dir", filesystem)
- link(t, "/tmp/links/link", "../dir", filesystem)
- link(t, "/tmp/links/broken", "nothingHere", filesystem)
- link(t, "/tmp/links/recursive", "recursive", filesystem)
+ fs.Link(t, "/tmp/links/dir", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/link", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/hi.txt", "../dir", filesystem)
+ fs.Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ fs.Link(t, "/tmp/links/recursive", "recursive", filesystem)
// set up the finder and run it once
finder := newFinder(
@@ -1463,7 +1328,7 @@
correctResponse := []string{
"/tmp/dir/hi.txt",
}
- assertSameResponse(t, foundPaths, correctResponse)
+ fs.AssertSameResponse(t, foundPaths, correctResponse)
}
@@ -1472,9 +1337,9 @@
func TestAddPruneFile(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/out/hi.txt", filesystem)
- create(t, "/tmp/out/a/hi.txt", filesystem)
- create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/hi.txt", filesystem)
+ fs.Create(t, "/tmp/out/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
// do find
finder := newFinder(
@@ -1490,7 +1355,7 @@
foundPaths := finder.FindNamedAt("/tmp", "hi.txt")
// check result
- assertSameResponse(t, foundPaths,
+ fs.AssertSameResponse(t, foundPaths,
[]string{"/tmp/hi.txt",
"/tmp/out/hi.txt",
"/tmp/out/a/hi.txt"},
@@ -1499,19 +1364,19 @@
// modify filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/out/.ignore-out-dir", filesystem)
+ fs.Create(t, "/tmp/out/.ignore-out-dir", filesystem)
// run another find and check its result
finder2 := finderWithSameParams(t, finder)
foundPaths = finder2.FindNamedAt("/tmp", "hi.txt")
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
finder2.Shutdown()
}
func TestUpdatingDbIffChanged(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/b/bye.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/bye.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1526,11 +1391,11 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// modify the filesystem
filesystem.Clock.Tick()
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
filesystem.Clock.Tick()
filesystem.ClearMetrics()
@@ -1539,10 +1404,10 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{"/tmp/b"})
expectedDbWriteTime := filesystem.Clock.Time()
- actualDbWriteTime := modTime(t, finder2.DbPath, filesystem)
+ actualDbWriteTime := fs.ModTime(t, finder2.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Expected to write db at %v, actually wrote db at %v\n",
expectedDbWriteTime, actualDbWriteTime)
@@ -1556,10 +1421,10 @@
foundPaths = finder3.FindAll()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
- assertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameReadDirCalls(t, filesystem.ReadDirCalls, []string{})
finder3.Shutdown()
- actualDbWriteTime = modTime(t, finder3.DbPath, filesystem)
+ actualDbWriteTime = fs.ModTime(t, finder3.DbPath, filesystem)
if actualDbWriteTime != expectedDbWriteTime {
t.Fatalf("Re-wrote db even when contents did not change")
}
@@ -1569,10 +1434,10 @@
func TestDirectoryNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- create(t, "/tmp/a/hi.txt", filesystem)
- create(t, "/tmp/a/a/hi.txt", filesystem)
- create(t, "/tmp/b/hi.txt", filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/b/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1588,12 +1453,12 @@
finder.Shutdown()
allPaths := []string{"/tmp/hi.txt", "/tmp/a/hi.txt", "/tmp/a/a/hi.txt", "/tmp/b/hi.txt"}
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
// modify the filesystem
filesystem.Clock.Tick()
- setReadable(t, "/tmp/a", false, filesystem)
+ fs.SetReadable(t, "/tmp/a", false, filesystem)
filesystem.Clock.Tick()
// run the second finder
@@ -1601,24 +1466,24 @@
foundPaths = finder2.FindAll()
finder2.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt", "/tmp/b/hi.txt"})
// modify the filesystem back
- setReadable(t, "/tmp/a", true, filesystem)
+ fs.SetReadable(t, "/tmp/a", true, filesystem)
// run the third finder
finder3 := finderWithSameParams(t, finder2)
foundPaths = finder3.FindAll()
finder3.Shutdown()
// check results
- assertSameResponse(t, foundPaths, allPaths)
+ fs.AssertSameResponse(t, foundPaths, allPaths)
}
func TestFileNotPermitted(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/hi.txt", filesystem)
- setReadable(t, "/tmp/hi.txt", false, filesystem)
+ fs.Create(t, "/tmp/hi.txt", filesystem)
+ fs.SetReadable(t, "/tmp/hi.txt", false, filesystem)
// run the first finder
finder := newFinder(
@@ -1633,13 +1498,13 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/hi.txt"})
}
func TestCacheEntryPathUnexpectedError(t *testing.T) {
// setup filesystem
filesystem := newFs()
- create(t, "/tmp/a/hi.txt", filesystem)
+ fs.Create(t, "/tmp/a/hi.txt", filesystem)
// run the first finder
finder := newFinder(
@@ -1654,14 +1519,14 @@
foundPaths := finder.FindAll()
finder.Shutdown()
// check results
- assertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
+ fs.AssertSameResponse(t, foundPaths, []string{"/tmp/a/hi.txt"})
// make the directory not readable
- setReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
+ fs.SetReadErr(t, "/tmp/a", os.ErrInvalid, filesystem)
// run the second finder
_, err := finderAndErrorWithSameParams(t, finder)
if err == nil {
- fatal(t, "Failed to detect unexpected filesystem error")
+ t.Fatal("Failed to detect unexpected filesystem error")
}
}
diff --git a/finder/fs/Android.bp b/finder/fs/Android.bp
index 27e3c7d..85929ae 100644
--- a/finder/fs/Android.bp
+++ b/finder/fs/Android.bp
@@ -22,8 +22,10 @@
srcs: [
"fs.go",
"readdir.go",
+ "test.go",
],
testSrcs: [
+ "fs_test.go",
"readdir_test.go",
],
darwin: {
@@ -37,4 +39,3 @@
],
},
}
-
diff --git a/finder/fs/fs.go b/finder/fs/fs.go
index 071f764..d2e3e4a 100644
--- a/finder/fs/fs.go
+++ b/finder/fs/fs.go
@@ -51,6 +51,7 @@
// getting information about files
Open(name string) (file io.ReadCloser, err error)
Lstat(path string) (stats os.FileInfo, err error)
+ Stat(path string) (stats os.FileInfo, err error)
ReadDir(path string) (contents []DirEntryInfo, err error)
InodeNumber(info os.FileInfo) (number uint64, err error)
@@ -99,6 +100,10 @@
return os.Lstat(path)
}
+func (osFs) Stat(path string) (stats os.FileInfo, err error) {
+ return os.Stat(path)
+}
+
func (osFs) ReadDir(path string) (contents []DirEntryInfo, err error) {
entries, err := readdir(path)
if err != nil {
@@ -376,7 +381,7 @@
size int64
modTime time.Time // time at which the inode's contents were modified
permTime time.Time // time at which the inode's permissions were modified
- isDir bool
+ mode os.FileMode
inodeNumber uint64
deviceNumber uint64
}
@@ -390,7 +395,7 @@
}
func (m *mockFileInfo) Mode() os.FileMode {
- return 0
+ return m.mode
}
func (m *mockFileInfo) ModTime() time.Time {
@@ -398,7 +403,7 @@
}
func (m *mockFileInfo) IsDir() bool {
- return m.isDir
+ return m.mode&os.ModeDir != 0
}
func (m *mockFileInfo) Sys() interface{} {
@@ -407,11 +412,11 @@
func (m *MockFs) dirToFileInfo(d *mockDir, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: d.modTime,
permTime: d.permTime,
- isDir: true,
+ mode: os.ModeDir,
inodeNumber: d.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -420,11 +425,11 @@
func (m *MockFs) fileToFileInfo(f *mockFile, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: f.modTime,
permTime: f.permTime,
- isDir: false,
+ mode: 0,
inodeNumber: f.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -432,11 +437,11 @@
func (m *MockFs) linkToFileInfo(l *mockLink, path string) (info *mockFileInfo) {
return &mockFileInfo{
- path: path,
+ path: filepath.Base(path),
size: 1,
modTime: l.modTime,
permTime: l.permTime,
- isDir: false,
+ mode: os.ModeSymlink,
inodeNumber: l.inodeNumber,
deviceNumber: m.deviceNumber,
}
@@ -485,6 +490,16 @@
}
}
+func (m *MockFs) Stat(path string) (stats os.FileInfo, err error) {
+ // resolve symlinks
+ path, err = m.resolve(path, true)
+ if err != nil {
+ return nil, err
+ }
+
+ return m.Lstat(path)
+}
+
func (m *MockFs) InodeNumber(info os.FileInfo) (number uint64, err error) {
mockInfo, ok := info.(*mockFileInfo)
if ok {
diff --git a/finder/fs/fs_test.go b/finder/fs/fs_test.go
new file mode 100644
index 0000000..22a4d7a
--- /dev/null
+++ b/finder/fs/fs_test.go
@@ -0,0 +1,76 @@
+// Copyright 2020 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 fs
+
+import (
+ "os"
+ "testing"
+)
+
+func TestMockFs_LstatStatSymlinks(t *testing.T) {
+ // setup filesystem
+ filesystem := NewMockFs(nil)
+ Create(t, "/tmp/realdir/hi.txt", filesystem)
+ Create(t, "/tmp/realdir/ignoreme.txt", filesystem)
+
+ Link(t, "/tmp/links/dir", "../realdir", filesystem)
+ Link(t, "/tmp/links/file", "../realdir/hi.txt", filesystem)
+ Link(t, "/tmp/links/broken", "nothingHere", filesystem)
+ Link(t, "/tmp/links/recursive", "recursive", filesystem)
+
+ assertStat := func(t *testing.T, stat os.FileInfo, err error, wantName string, wantMode os.FileMode) {
+ t.Helper()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ if g, w := stat.Name(), wantName; g != w {
+ t.Errorf("want name %q, got %q", w, g)
+ }
+ if g, w := stat.Mode(), wantMode; g != w {
+ t.Errorf("%s: want mode %q, got %q", wantName, w, g)
+ }
+ }
+
+ assertErr := func(t *testing.T, err error, wantErr string) {
+ if err == nil || err.Error() != wantErr {
+ t.Errorf("want error %q, got %q", wantErr, err)
+ }
+ }
+
+ stat, err := filesystem.Lstat("/tmp/links/dir")
+ assertStat(t, stat, err, "dir", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/dir")
+ assertStat(t, stat, err, "realdir", os.ModeDir)
+
+ stat, err = filesystem.Lstat("/tmp/links/file")
+ assertStat(t, stat, err, "file", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/file")
+ assertStat(t, stat, err, "hi.txt", 0)
+
+ stat, err = filesystem.Lstat("/tmp/links/broken")
+ assertStat(t, stat, err, "broken", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/broken")
+ assertErr(t, err, "stat /tmp/links/nothingHere: file does not exist")
+
+ stat, err = filesystem.Lstat("/tmp/links/recursive")
+ assertStat(t, stat, err, "recursive", os.ModeSymlink)
+
+ stat, err = filesystem.Stat("/tmp/links/recursive")
+ assertErr(t, err, "read /tmp/links/recursive: too many levels of symbolic links")
+}
diff --git a/finder/fs/test.go b/finder/fs/test.go
new file mode 100644
index 0000000..cb2140e
--- /dev/null
+++ b/finder/fs/test.go
@@ -0,0 +1,146 @@
+// Copyright 2020 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 fs
+
+import (
+ "io/ioutil"
+ "path/filepath"
+ "reflect"
+ "sort"
+ "testing"
+ "time"
+)
+
+func Write(t *testing.T, path string, content string, filesystem *MockFs) {
+ parent := filepath.Dir(path)
+ filesystem.MkDirs(parent)
+ err := filesystem.WriteFile(path, []byte(content), 0777)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Create(t *testing.T, path string, filesystem *MockFs) {
+ Write(t, path, "hi", filesystem)
+}
+
+func Delete(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.Remove(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func RemoveAll(t *testing.T, path string, filesystem *MockFs) {
+ err := filesystem.RemoveAll(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Move(t *testing.T, oldPath string, newPath string, filesystem *MockFs) {
+ err := filesystem.Rename(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Link(t *testing.T, newPath string, oldPath string, filesystem *MockFs) {
+ parentPath := filepath.Dir(newPath)
+ err := filesystem.MkDirs(parentPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ err = filesystem.Symlink(oldPath, newPath)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func Read(t *testing.T, path string, filesystem *MockFs) string {
+ reader, err := filesystem.Open(path)
+ if err != nil {
+ t.Fatalf(err.Error())
+ }
+ bytes, err := ioutil.ReadAll(reader)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return string(bytes)
+}
+
+func ModTime(t *testing.T, path string, filesystem *MockFs) time.Time {
+ stats, err := filesystem.Lstat(path)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+ return stats.ModTime()
+}
+
+func SetReadable(t *testing.T, path string, readable bool, filesystem *MockFs) {
+ err := filesystem.SetReadable(path, readable)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func SetReadErr(t *testing.T, path string, readErr error, filesystem *MockFs) {
+ err := filesystem.SetReadErr(path, readErr)
+ if err != nil {
+ t.Fatal(err.Error())
+ }
+}
+
+func AssertSameResponse(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Expected Finder to return these %v paths:\n %v,\ninstead returned these %v paths: %v\n",
+ len(expected), expected, len(actual), actual)
+ }
+}
+
+func AssertSameStatCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect Stat calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
+
+func AssertSameReadDirCalls(t *testing.T, actual []string, expected []string) {
+ t.Helper()
+ sort.Strings(actual)
+ sort.Strings(expected)
+
+ if !reflect.DeepEqual(actual, expected) {
+ t.Fatalf("Finder made incorrect ReadDir calls.\n"+
+ "Actual:\n"+
+ "%v\n"+
+ "Expected:\n"+
+ "%v\n"+
+ "\n",
+ actual, expected)
+ }
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index fe877fe..1cec289 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -83,7 +83,6 @@
type generatorProperties struct {
// The command to run on one or more input files. Cmd supports substitution of a few variables
- // (the actual substitution is implemented in GenerateAndroidBuildActions below)
//
// Available variables for substitution:
//
@@ -94,9 +93,6 @@
// $(depfile): a file to which dependencies will be written, if the depfile property is set to true
// $(genDir): the sandbox directory for this tool; contains $(out)
// $$: a literal $
- //
- // All files used must be declared as inputs (to ensure proper up-to-date checks).
- // Use "$(in)" directly in Cmd to ensure that all inputs used are declared.
Cmd *string
// Enable reading a file containing dependencies in gcc format after the command completes
@@ -144,6 +140,9 @@
subName string
subDir string
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ modulePaths []string
}
type taskFunc func(ctx android.ModuleContext, rawCommand string, srcFiles android.Paths) []generateTask
@@ -190,6 +189,9 @@
func (g *Module) GenerateAndroidBuildActions(ctx android.ModuleContext) {
g.subName = ctx.ModuleSubDir()
+ // Collect the module directory for IDE info in java/jdeps.go.
+ g.modulePaths = append(g.modulePaths, ctx.ModuleDir())
+
if len(g.properties.Export_include_dirs) > 0 {
for _, dir := range g.properties.Export_include_dirs {
g.exportedIncludeDirs = append(g.exportedIncludeDirs,
@@ -257,9 +259,9 @@
// If AllowMissingDependencies is enabled, the build will not have stopped when
// AddFarVariationDependencies was called on a missing tool, which will result in nonsensical
- // "cmd: unknown location label ..." errors later. Add a dummy file to the local label. The
- // command that uses this dummy file will never be executed because the rule will be replaced with
- // an android.Error rule reporting the missing dependencies.
+ // "cmd: unknown location label ..." errors later. Add a placeholder file to the local label.
+ // The command that uses this placeholder file will never be executed because the rule will be
+ // replaced with an android.Error rule reporting the missing dependencies.
if ctx.Config().AllowMissingDependencies() {
for _, tool := range g.properties.Tools {
if !seenTools[tool] {
@@ -290,9 +292,9 @@
// If AllowMissingDependencies is enabled, the build will not have stopped when
// the dependency was added on a missing SourceFileProducer module, which will result in nonsensical
- // "cmd: label ":..." has no files" errors later. Add a dummy file to the local label. The
- // command that uses this dummy file will never be executed because the rule will be replaced with
- // an android.Error rule reporting the missing dependencies.
+ // "cmd: label ":..." has no files" errors later. Add a placeholder file to the local label.
+ // The command that uses this placeholder file will never be executed because the rule will be
+ // replaced with an android.Error rule reporting the missing dependencies.
ctx.AddMissingDependencies(missingDeps)
addLocationLabel(in, []string{"***missing srcs " + in + "***"})
} else {
@@ -529,6 +531,7 @@
dpInfo.Deps = append(dpInfo.Deps, src)
}
}
+ dpInfo.Paths = append(dpInfo.Paths, g.modulePaths...)
}
func (g *Module) AndroidMk() android.AndroidMkData {
@@ -552,6 +555,12 @@
}
}
+func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Because generated outputs are checked by client modules(e.g. cc_library, ...)
+ // we can safely ignore the check here.
+ return nil
+}
+
func generatorFactory(taskGenerator taskFunc, props ...interface{}) *Module {
module := &Module{
taskGenerator: taskGenerator,
diff --git a/go.mod b/go.mod
index 1483a31..7297dea 100644
--- a/go.mod
+++ b/go.mod
@@ -8,4 +8,4 @@
replace github.com/google/blueprint v0.0.0 => ../blueprint
-go 1.13
+go 1.15
diff --git a/java/Android.bp b/java/Android.bp
index 1fda7f7..92e8ca4 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -10,6 +10,7 @@
"soong-dexpreopt",
"soong-genrule",
"soong-java-config",
+ "soong-python",
"soong-remoteexec",
"soong-tradefed",
],
@@ -38,6 +39,7 @@
"java_resources.go",
"kotlin.go",
"lint.go",
+ "legacy_core_platform_api_usage.go",
"platform_compat_config.go",
"plugin.go",
"prebuilt_apis.go",
@@ -57,6 +59,7 @@
"device_host_converter_test.go",
"dexpreopt_test.go",
"dexpreopt_bootjars_test.go",
+ "hiddenapi_singleton_test.go",
"java_test.go",
"jdeps_test.go",
"kotlin_test.go",
diff --git a/java/aar.go b/java/aar.go
index 8dd752f..667dd9d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -20,6 +20,7 @@
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -99,7 +100,7 @@
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
- sdkLibraries []string
+ sdkLibraries dexpreopt.LibraryPaths
hasNoCode bool
LoggingParent string
resourceFiles android.Paths
@@ -231,6 +232,8 @@
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext)
+ a.sdkLibraries = sdkLibraries
+
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
@@ -357,7 +360,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
- staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) {
+ staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) {
var sharedLibs android.Paths
@@ -366,6 +369,8 @@
sharedLibs = append(sharedLibs, sdkDep.jars...)
}
+ sdkLibraries = make(dexpreopt.LibraryPaths)
+
ctx.VisitDirectDeps(func(module android.Module) {
var exportPackage android.Path
aarDep, _ := module.(AndroidLibraryDependency)
@@ -373,6 +378,10 @@
exportPackage = aarDep.ExportPackage()
}
+ if dep, ok := module.(Dependency); ok {
+ sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs())
+ }
+
switch ctx.OtherModuleDependencyTag(module) {
case instrumentationForTag:
// Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2.
@@ -385,7 +394,8 @@
// (including the java_sdk_library) itself then append any implicit sdk library
// names to the list of sdk libraries to be added to the manifest.
if component, ok := module.(SdkLibraryComponentDependency); ok {
- sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...)
+ sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(),
+ component.DexJarBuildPath(), component.DexJarInstallPath())
}
case frameworkResTag:
@@ -397,7 +407,7 @@
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
- sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
+ sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs())
if aarDep.ExportedAssets().Valid() {
assets = append(assets, aarDep.ExportedAssets().Path())
}
@@ -428,7 +438,6 @@
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
- sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
}
@@ -465,8 +474,8 @@
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
- a.aapt.sdkLibraries = a.exportedSdkLibs
a.aapt.buildActions(ctx, sdkContext(a))
+ a.exportedSdkLibs = a.aapt.sdkLibraries
ctx.CheckbuildFile(a.proguardOptionsFile)
ctx.CheckbuildFile(a.exportPackage)
@@ -625,7 +634,7 @@
}
func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) {
- if !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ if !ctx.Config().AlwaysUsePrebuiltSdks() {
sdkDep := decodeSdkDep(ctx, sdkContext(a))
if sdkDep.useModule && sdkDep.frameworkResModule != "" {
ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule)
@@ -641,9 +650,11 @@
var unzipAAR = pctx.AndroidStaticRule("unzipAAR",
blueprint.RuleParams{
Command: `rm -rf $outDir && mkdir -p $outDir && ` +
- `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out`,
+ `unzip -qoDD -d $outDir $in && rm -rf $outDir/res && touch $out && ` +
+ `${config.MergeZipsCmd} $combinedClassesJar $$(ls $outDir/classes.jar 2> /dev/null) $$(ls $outDir/libs/*.jar 2> /dev/null)`,
+ CommandDeps: []string{"${config.MergeZipsCmd}"},
},
- "outDir")
+ "outDir", "combinedClassesJar")
func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(a.properties.Aars) != 1 {
@@ -661,7 +672,7 @@
}
extractedAARDir := android.PathForModuleOut(ctx, "aar")
- a.classpathFile = extractedAARDir.Join(ctx, "classes.jar")
+ a.classpathFile = extractedAARDir.Join(ctx, "classes-combined.jar")
a.proguardFlags = extractedAARDir.Join(ctx, "proguard.txt")
a.manifest = extractedAARDir.Join(ctx, "AndroidManifest.xml")
@@ -671,7 +682,8 @@
Outputs: android.WritablePaths{a.classpathFile, a.proguardFlags, a.manifest},
Description: "unzip AAR",
Args: map[string]string{
- "outDir": extractedAARDir.String(),
+ "outDir": extractedAARDir.String(),
+ "combinedClassesJar": a.classpathFile.String(),
},
})
@@ -734,7 +746,11 @@
return android.Paths{a.classpathFile}
}
-func (a *AARImport) DexJar() android.Path {
+func (a *AARImport) DexJarBuildPath() android.Path {
+ return nil
+}
+
+func (a *AARImport) DexJarInstallPath() android.Path {
return nil
}
@@ -742,7 +758,7 @@
return nil
}
-func (a *AARImport) ExportedSdkLibs() []string {
+func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths {
return nil
}
@@ -758,6 +774,10 @@
return a.depIsInSameApex(ctx, dep)
}
+func (g *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ return nil
+}
+
var _ android.PrebuiltInterface = (*Import)(nil)
// android_library_import imports an `.aar` file into the build graph as if it was built with android_library.
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 8280cb1..62cd112 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -21,6 +21,7 @@
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/dexpreopt"
)
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -41,18 +42,8 @@
},
"args", "libs")
-// These two libs are added as optional dependencies (<uses-library> with
-// android:required set to false). This is because they haven't existed in pre-P
-// devices, but classes in them were in bootclasspath jars, etc. So making them
-// hard dependencies (android:required=true) would prevent apps from being
-// installed to such legacy devices.
-var optionalUsesLibs = []string{
- "android.test.base",
- "android.test.mock",
-}
-
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths,
isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
var args []string
@@ -79,8 +70,8 @@
args = append(args, "--use-embedded-dex")
}
- for _, usesLib := range sdkLibraries {
- if inList(usesLib, optionalUsesLibs) {
+ for _, usesLib := range android.SortedStringKeys(sdkLibraries) {
+ if inList(usesLib, dexpreopt.OptionalCompatUsesLibs) {
args = append(args, "--optional-uses-library", usesLib)
} else {
args = append(args, "--uses-library", usesLib)
@@ -130,7 +121,7 @@
},
})
- return fixedManifest
+ return fixedManifest.WithoutRel()
}
func manifestMerger(ctx android.ModuleContext, manifest android.Path, staticLibManifests android.Paths,
@@ -155,5 +146,5 @@
},
})
- return mergedManifest
+ return mergedManifest.WithoutRel()
}
diff --git a/java/androidmk.go b/java/androidmk.go
index 08febcd..65c44a3 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -121,18 +121,14 @@
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...)
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...)
if len(library.additionalCheckedModules) != 0 {
entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
}
- if library.dexer.proguardDictionary.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path())
- }
- if library.proguardUsageZip.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.proguardUsageZip.Path())
- }
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary)
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip)
entries.SetString("LOCAL_MODULE_STEM", library.Stem())
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports)
@@ -165,15 +161,23 @@
if j.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig)
}
+ androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries)
androidMkWriteTestData(j.data, entries)
if !BoolDefault(j.testProperties.Auto_gen_config, true) {
entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
}
+ entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", j.testProperties.Test_mainline_modules...)
})
return entriesList
}
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
+ if len(extraTestConfigs) > 0 {
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+ }
+}
+
func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
@@ -335,12 +339,8 @@
if app.jacocoReportClassesFile != nil {
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile)
}
- if app.dexer.proguardDictionary.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path())
- }
- if app.proguardUsageZip.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.proguardUsageZip.Path())
- }
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary)
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip)
if app.Name() == "framework-res" {
entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)")
@@ -439,7 +439,9 @@
if a.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig)
}
+ androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries)
androidMkWriteTestData(a.data, entries)
+ entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", a.testProperties.Test_mainline_modules...)
})
return entriesList
@@ -507,55 +509,14 @@
func (ddoc *Droiddoc) AndroidMkEntries() []android.AndroidMkEntries {
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "JAVA_LIBRARIES",
- OutputFile: android.OptionalPathForPath(ddoc.stubsSrcJar),
+ OutputFile: android.OptionalPathForPath(ddoc.Javadoc.docZip),
Include: "$(BUILD_SYSTEM)/soong_droiddoc_prebuilt.mk",
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
- if BoolDefault(ddoc.Javadoc.properties.Installable, true) && ddoc.Javadoc.docZip != nil {
+ if ddoc.Javadoc.docZip != nil {
entries.SetPath("LOCAL_DROIDDOC_DOC_ZIP", ddoc.Javadoc.docZip)
}
- if ddoc.Javadoc.stubsSrcJar != nil {
- entries.SetPath("LOCAL_DROIDDOC_STUBS_SRCJAR", ddoc.Javadoc.stubsSrcJar)
- }
- },
- },
- ExtraFooters: []android.AndroidMkExtraFootersFunc{
- func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
- if ddoc.checkCurrentApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-current-api")
- fmt.Fprintln(w, ddoc.Name()+"-check-current-api:",
- ddoc.checkCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- ddoc.checkCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
- if ddoc.updateCurrentApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-update-current-api")
- fmt.Fprintln(w, ddoc.Name()+"-update-current-api:",
- ddoc.updateCurrentApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: update-api")
- fmt.Fprintln(w, "update-api:",
- ddoc.updateCurrentApiTimestamp.String())
- }
- if ddoc.checkLastReleasedApiTimestamp != nil {
- fmt.Fprintln(w, ".PHONY:", ddoc.Name()+"-check-last-released-api")
- fmt.Fprintln(w, ddoc.Name()+"-check-last-released-api:",
- ddoc.checkLastReleasedApiTimestamp.String())
-
- if ddoc.Name() == "api-stubs-docs" || ddoc.Name() == "system-api-stubs-docs" {
- fmt.Fprintln(w, ".PHONY: checkapi")
- fmt.Fprintln(w, "checkapi:",
- ddoc.checkLastReleasedApiTimestamp.String())
-
- fmt.Fprintln(w, ".PHONY: droidcore")
- fmt.Fprintln(w, "droidcore: checkapi")
- }
- }
+ entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !BoolDefault(ddoc.Javadoc.properties.Installable, true))
},
},
}}
@@ -677,6 +638,11 @@
}
func (a *AndroidAppImport) AndroidMkEntries() []android.AndroidMkEntries {
+ if !a.IsForPlatform() {
+ // The non-platform variant is placed inside APEX. No reason to
+ // make it available to Make.
+ return nil
+ }
return []android.AndroidMkEntries{android.AndroidMkEntries{
Class: "APPS",
OutputFile: android.OptionalPathForPath(a.outputFile),
@@ -737,7 +703,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
entries.SetBoolIfTrue("LOCAL_PRIVILEGED_MODULE", apkSet.Privileged())
- entries.SetString("LOCAL_APK_SET_MASTER_FILE", apkSet.masterFile)
+ entries.SetString("LOCAL_APK_SET_INSTALL_FILE", apkSet.InstallFile())
entries.SetPath("LOCAL_APKCERTS_FILE", apkSet.apkcertsFile)
entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", apkSet.properties.Overrides...)
},
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index 49cc035..075b7aa 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -310,3 +310,36 @@
t.Errorf("did not expect foo_without_tag's .jar-tagged DistFiles to contain files, but got %v", distFilesWithoutTag[".jar"])
}
}
+
+func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_sdk_library {
+ name: "foo-shared_library",
+ srcs: ["a.java"],
+ }
+ java_sdk_library {
+ name: "foo-no_shared_library",
+ srcs: ["a.java"],
+ shared_library: false,
+ }
+ `)
+
+ // Verify the existence of internal modules
+ ctx.ModuleForTests("foo-shared_library.xml", "android_common")
+
+ testCases := []struct {
+ moduleName string
+ expected []string
+ }{
+ {"foo-shared_library", []string{"foo-shared_library.xml"}},
+ {"foo-no_shared_library", nil},
+ }
+ for _, tc := range testCases {
+ mod := ctx.ModuleForTests(tc.moduleName, "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+ actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
+ if !reflect.DeepEqual(tc.expected, actual) {
+ t.Errorf("Unexpected required modules - expected: %q, actual: %q", tc.expected, actual)
+ }
+ }
+}
diff --git a/java/app.go b/java/app.go
index c9412c4..ae7373f 100755
--- a/java/app.go
+++ b/java/app.go
@@ -28,6 +28,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/dexpreopt"
"android/soong/tradefed"
)
@@ -77,7 +78,7 @@
properties AndroidAppSetProperties
packedOutput android.WritablePath
- masterFile string
+ installFile string
apkcertsFile android.ModuleOutPath
}
@@ -101,8 +102,8 @@
return as.packedOutput
}
-func (as *AndroidAppSet) MasterFile() string {
- return as.masterFile
+func (as *AndroidAppSet) InstallFile() string {
+ return as.installFile
}
func (as *AndroidAppSet) APKCertsFile() android.Path {
@@ -135,10 +136,10 @@
func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
as.apkcertsFile = android.PathForModuleOut(ctx, "apkcerts.txt")
- // We are assuming here that the master file in the APK
+ // We are assuming here that the install file in the APK
// set has `.apk` suffix. If it doesn't the build will fail.
// APK sets containing APEX files are handled elsewhere.
- as.masterFile = as.BaseModuleName() + ".apk"
+ as.installFile = as.BaseModuleName() + ".apk"
screenDensities := "all"
if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -166,7 +167,7 @@
// android_app_set extracts a set of APKs based on the target device
// configuration and installs this set as "split APKs".
-// The extracted set always contains 'master' APK whose name is
+// The extracted set always contains an APK whose name is
// _module_name_.apk and every split APK matching target device.
// The extraction of the density-specific splits depends on
// PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should
@@ -267,6 +268,9 @@
// the logging parent of this app.
Logging_parent *string
+
+ // Whether to rename the package in resources to the override name rather than the base name. Defaults to true.
+ Rename_resources_package *bool
}
// runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay
@@ -283,8 +287,6 @@
aapt
android.OverridableModuleBase
- usesLibrary usesLibrary
-
certificate Certificate
appProperties appProperties
@@ -431,8 +433,10 @@
if String(a.deviceProperties.Min_sdk_version) == "" {
ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.")
}
+
if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil {
a.checkJniLibsSdkVersion(ctx, minSdkVersion)
+ android.CheckMinSdkVersion(a, ctx, int(minSdkVersion))
} else {
ctx.PropertyErrorf("min_sdk_version", "%s", err.Error())
}
@@ -504,10 +508,23 @@
!a.IsForPlatform() || a.appProperties.AlwaysPackageNativeLibs
}
+func generateAaptRenamePackageFlags(packageName string, renameResourcesPackage bool) []string {
+ aaptFlags := []string{"--rename-manifest-package " + packageName}
+ if renameResourcesPackage {
+ // Required to rename the package name in the resources table.
+ aaptFlags = append(aaptFlags, "--rename-resources-package "+packageName)
+ }
+ return aaptFlags
+}
+
func (a *AndroidApp) OverriddenManifestPackageName() string {
return a.overriddenManifestPackageName
}
+func (a *AndroidApp) renameResourcesPackage() bool {
+ return proptools.BoolDefault(a.overridableAppProperties.Rename_resources_package, true)
+}
+
func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) {
a.aapt.usesNonSdkApis = Bool(a.Module.deviceProperties.Platform_apis)
@@ -540,7 +557,7 @@
if !overridden {
manifestPackageName = *a.overridableAppProperties.Package_name
}
- aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+ aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, a.renameResourcesPackage())...)
a.overriddenManifestPackageName = manifestPackageName
}
@@ -583,7 +600,7 @@
return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
}
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path {
a.dexpreopter.installPath = a.installPath(ctx)
if a.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
@@ -594,7 +611,9 @@
a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+ a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs)
a.dexpreopter.manifestFile = a.mergedManifestFile
+ a.exportedSdkLibs = make(dexpreopt.LibraryPaths)
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -663,16 +682,20 @@
return false
}
- path := child.(android.Module).NoticeFile()
- if path.Valid() {
- noticePathSet[path.Path()] = true
+ paths := child.(android.Module).NoticeFiles()
+ if len(paths) > 0 {
+ for _, path := range paths {
+ noticePathSet[path] = true
+ }
}
return true
})
// If the app has one, add it too.
- if a.NoticeFile().Valid() {
- noticePathSet[a.NoticeFile().Path()] = true
+ if len(a.NoticeFiles()) > 0 {
+ for _, path := range a.NoticeFiles() {
+ noticePathSet[path] = true
+ }
}
if len(noticePathSet) == 0 {
@@ -759,6 +782,15 @@
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
+ // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
+ a.usesLibrary.freezeEnforceUsesLibraries()
+
+ // Add implicit SDK libraries to <uses-library> list.
+ for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) {
+ a.usesLibrary.addLib(usesLib, inList(usesLib, dexpreopt.OptionalCompatUsesLibs))
+ }
+
+ // Check that the <uses-library> list is coherent with the manifest.
if a.usesLibrary.enforceUsesLibraries() {
manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
apkDeps = append(apkDeps, manifestCheckFile)
@@ -769,9 +801,9 @@
a.linter.mergedManifest = a.aapt.mergedManifestFile
a.linter.manifest = a.aapt.manifestPath
a.linter.resources = a.aapt.resourceFiles
- a.linter.buildModuleReportZip = ctx.Config().UnbundledBuild()
+ a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
- dexJarFile := a.dexBuildActions(ctx)
+ dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries)
jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
jniJarFile := a.jniBuildActions(jniLibs, ctx)
@@ -852,7 +884,7 @@
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
- if IsJniDepTag(tag) || tag == cc.SharedDepTag {
+ if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) {
if dep, ok := module.(*cc.Module); ok {
if dep.IsNdk() || dep.IsStubs() {
return false
@@ -902,13 +934,13 @@
return jniLibs, certificates
}
-func (a *AndroidApp) walkPayloadDeps(ctx android.ModuleContext,
- do func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool)) {
-
+func (a *AndroidApp) WalkPayloadDeps(ctx android.ModuleContext, do android.PayloadDepsCallback) {
ctx.WalkDeps(func(child, parent android.Module) bool {
isExternal := !a.DepIsInSameApex(ctx, child)
if am, ok := child.(android.ApexModule); ok {
- do(ctx, parent, am, isExternal)
+ if !do(ctx, parent, am, isExternal) {
+ return false
+ }
}
return !isExternal
})
@@ -920,7 +952,7 @@
}
depsInfo := android.DepNameToDepInfoMap{}
- a.walkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) {
+ a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
depName := to.Name()
if info, exist := depsInfo[depName]; exist {
info.From = append(info.From, from.Name())
@@ -940,6 +972,7 @@
MinSdkVersion: toMinSdkVersion,
}
}
+ return true
})
a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo)
@@ -969,6 +1002,8 @@
switch tag {
case ".aapt.srcjar":
return []android.Path{a.aaptSrcJar}, nil
+ case ".export-package.apk":
+ return []android.Path{a.exportPackage}, nil
}
return a.Library.OutputFiles(tag)
}
@@ -993,6 +1028,8 @@
a.appProperties.IsCoverageVariant = coverage
}
+func (a *AndroidApp) EnableCoverageIfNeeded() {}
+
var _ cc.Coverage = (*AndroidApp)(nil)
// android_app compiles sources and Android resources into an Android application package `.apk` file.
@@ -1009,12 +1046,7 @@
module.AddProperties(
&module.aaptProperties,
&module.appProperties,
- &module.overridableAppProperties,
- &module.usesLibrary.usesLibraryProperties)
-
- module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
- return class == android.Device && ctx.Config().DevicePrefer32BitApps()
- })
+ &module.overridableAppProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
@@ -1025,6 +1057,7 @@
}
type appTestProperties struct {
+ // The name of the android_app module that the tests will run against.
Instrumentation_for *string
// if specified, the instrumentation target package name in the manifest is overwritten by it.
@@ -1038,8 +1071,9 @@
testProperties testProperties
- testConfig android.Path
- data android.Paths
+ testConfig android.Path
+ extraTestConfigs android.Paths
+ data android.Paths
}
func (a *AndroidTest) InstallInTestcases() bool {
@@ -1067,6 +1101,7 @@
testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
a.testConfig = a.FixTestConfig(ctx, testConfig)
+ a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
@@ -1132,7 +1167,6 @@
&module.appProperties,
&module.appTestProperties,
&module.overridableAppProperties,
- &module.usesLibrary.usesLibraryProperties,
&module.testProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
@@ -1181,8 +1215,7 @@
&module.aaptProperties,
&module.appProperties,
&module.appTestHelperAppProperties,
- &module.overridableAppProperties,
- &module.usesLibrary.usesLibraryProperties)
+ &module.overridableAppProperties)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
@@ -1285,6 +1318,7 @@
type AndroidAppImport struct {
android.ModuleBase
android.DefaultableModuleBase
+ android.ApexModuleBase
prebuilt android.Prebuilt
properties AndroidAppImportProperties
@@ -1535,7 +1569,9 @@
// TODO: Optionally compress the output apk.
- a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
+ if a.IsForPlatform() {
+ a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile)
+ }
// TODO: androidmk converter jni libs
}
@@ -1586,6 +1622,13 @@
return Bool(a.properties.Privileged)
}
+func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
+ // android_app_import might have extra dependencies via uses_libs property.
+ // Don't track the dependency as we don't automatically add those libraries
+ // to the classpath. It should be explicitly added to java_libs property of APEX
+ return false
+}
+
func (a *AndroidAppImport) sdkVersion() sdkSpec {
return sdkSpecFrom("")
}
@@ -1594,6 +1637,11 @@
return sdkSpecFrom("")
}
+func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Do not check for prebuilts against the min_sdk_version of enclosing APEX
+ return nil
+}
+
func createVariantGroupType(variants []string, variantGroupName string) reflect.Type {
props := reflect.TypeOf((*AndroidAppImportProperties)(nil))
@@ -1640,6 +1688,7 @@
module.processVariants(ctx)
})
+ android.InitApexModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
@@ -1680,7 +1729,6 @@
module := &AndroidTestImport{}
module.AddProperties(&module.properties)
module.AddProperties(&module.dexpreoptProperties)
- module.AddProperties(&module.usesLibrary.usesLibraryProperties)
module.AddProperties(&module.testProperties)
module.AddProperties(&module.testImportProperties)
module.populateAllVariantStructs()
@@ -1690,6 +1738,7 @@
module.dexpreopter.isTest = true
+ android.InitApexModule(module)
android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
android.InitDefaultableModule(module)
android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
@@ -1746,6 +1795,15 @@
Overrides []string
}
+// RuntimeResourceOverlayModule interface is used by the apex package to gather information from
+// a RuntimeResourceOverlay module.
+type RuntimeResourceOverlayModule interface {
+ android.Module
+ OutputFile() android.Path
+ Certificate() Certificate
+ Theme() string
+}
+
func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
sdkDep := decodeSdkDep(ctx, sdkContext(r))
if sdkDep.hasFrameworkLibs() {
@@ -1773,7 +1831,7 @@
if !overridden {
manifestPackageName = *r.overridableProperties.Package_name
}
- aaptLinkFlags = append(aaptLinkFlags, "--rename-manifest-package "+manifestPackageName)
+ aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...)
}
if r.overridableProperties.Target_package_name != nil {
aaptLinkFlags = append(aaptLinkFlags,
@@ -1816,6 +1874,18 @@
return r.sdkVersion()
}
+func (r *RuntimeResourceOverlay) Certificate() Certificate {
+ return r.certificate
+}
+
+func (r *RuntimeResourceOverlay) OutputFile() android.Path {
+ return r.outputFile
+}
+
+func (r *RuntimeResourceOverlay) Theme() string {
+ return String(r.properties.Theme)
+}
+
// runtime_resource_overlay generates a resource-only apk file that can overlay application and
// system resources at run time.
func RuntimeResourceOverlayFactory() android.Module {
@@ -1842,6 +1912,11 @@
// If true, the list of uses_libs and optional_uses_libs modules must match the AndroidManifest.xml file. Defaults
// to true if either uses_libs or optional_uses_libs is set. Will unconditionally default to true in the future.
Enforce_uses_libs *bool
+
+ // Optional name of the <uses-library> provided by this module. This is needed for non-SDK
+ // libraries, because SDK ones are automatically picked up by Soong. The <uses-library> name
+ // normally is the same as the module name, but there are exceptions.
+ Provides_uses_lib *string
}
// usesLibrary provides properties and helper functions for AndroidApp and AndroidAppImport to verify that the
@@ -1852,6 +1927,16 @@
usesLibraryProperties UsesLibraryProperties
}
+func (u *usesLibrary) addLib(lib string, optional bool) {
+ if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) {
+ if optional {
+ u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib)
+ } else {
+ u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib)
+ }
+ }
+}
+
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
if !ctx.Config().UnbundledBuild() {
ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
@@ -1860,13 +1945,10 @@
// creating a cyclic dependency:
// e.g. framework-res -> org.apache.http.legacy -> ... -> framework-res.
if hasFrameworkLibs {
- // dexpreopt/dexpreopt.go needs the paths to the dex jars of these libraries in case construct_context.sh needs
- // to pass them to dex2oat. Add them as a dependency so we can determine the path to the dex jar of each
- // library to dexpreopt.
- ctx.AddVariationDependencies(nil, usesLibTag,
- "org.apache.http.legacy",
- "android.hidl.base-V1.0-java",
- "android.hidl.manager-V1.0-java")
+ // Dexpreopt needs paths to the dex jars of these libraries in order to construct
+ // class loader context for dex2oat. Add them as a dependency with a special tag.
+ ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.CompatUsesLibs...)
+ ctx.AddVariationDependencies(nil, usesLibTag, dexpreopt.OptionalCompatUsesLibs...)
}
}
}
@@ -1878,24 +1960,20 @@
return optionalUsesLibs
}
-// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars.
-func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path {
- usesLibPaths := make(map[string]android.Path)
+// usesLibraryPaths returns a map of module names of shared library dependencies to the paths
+// to their dex jars on host and on device.
+func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.LibraryPaths {
+ usesLibPaths := make(dexpreopt.LibraryPaths)
if !ctx.Config().UnbundledBuild() {
ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
+ dep := ctx.OtherModuleName(m)
if lib, ok := m.(Dependency); ok {
- if dexJar := lib.DexJar(); dexJar != nil {
- usesLibPaths[ctx.OtherModuleName(m)] = dexJar
- } else {
- ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?",
- ctx.OtherModuleName(m))
- }
+ usesLibPaths.AddLibraryPath(ctx, dep, lib.DexJarBuildPath(), lib.DexJarInstallPath())
} else if ctx.Config().AllowMissingDependencies() {
- ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)})
+ ctx.AddMissingDependencies([]string{dep})
} else {
- ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library",
- ctx.OtherModuleName(m))
+ ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library", dep)
}
})
}
@@ -1912,6 +1990,12 @@
return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
}
+// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
+func (u *usesLibrary) freezeEnforceUsesLibraries() {
+ enforce := u.enforceUsesLibraries()
+ u.usesLibraryProperties.Enforce_uses_libs = &enforce
+}
+
// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest.
func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
diff --git a/java/app_builder.go b/java/app_builder.go
index 97ec269..69e462c 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -102,7 +102,7 @@
"certificates": strings.Join(certificateArgs, " "),
"flags": strings.Join(flags, " "),
}
- if ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_SIGNAPK") {
rule = SignapkRE
args["implicits"] = strings.Join(deps.Strings(), ",")
args["outCommaList"] = strings.Join(outputFiles.Strings(), ",")
@@ -241,7 +241,7 @@
args := map[string]string{
"jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
}
- if ctx.Config().IsEnvTrue("RBE_ZIP") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") {
rule = zipRE
args["implicits"] = strings.Join(deps.Strings(), ",")
}
diff --git a/java/app_test.go b/java/app_test.go
index 8ef3152..5367971 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -161,11 +161,11 @@
t.Errorf("wrong partition value: '%s', expected 'system'", s)
}
mkEntries := android.AndroidMkEntriesForTest(t, config, "", module.Module())[0]
- actualMaster := mkEntries.EntryMap["LOCAL_APK_SET_MASTER_FILE"]
- expectedMaster := []string{"foo.apk"}
- if !reflect.DeepEqual(actualMaster, expectedMaster) {
- t.Errorf("Unexpected LOCAL_APK_SET_MASTER_FILE value: '%s', expected: '%s',",
- actualMaster, expectedMaster)
+ actualInstallFile := mkEntries.EntryMap["LOCAL_APK_SET_INSTALL_FILE"]
+ expectedInstallFile := []string{"foo.apk"}
+ if !reflect.DeepEqual(actualInstallFile, expectedInstallFile) {
+ t.Errorf("Unexpected LOCAL_APK_SET_INSTALL_FILE value: '%s', expected: '%s',",
+ actualInstallFile, expectedInstallFile)
}
}
@@ -478,6 +478,24 @@
}
}
+func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) {
+ testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+`
+ android_app {
+ name: "foo",
+ srcs: ["a.java"],
+ updatable: true,
+ sdk_version: "current",
+ min_sdk_version: "29",
+ static_libs: ["bar"],
+ }
+
+ java_library {
+ name: "bar",
+ sdk_version: "current",
+ }
+ `)
+}
+
func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) {
testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
android_app {
@@ -515,16 +533,6 @@
system_shared_libs: [],
sdk_version: "29",
}
-
- ndk_prebuilt_object {
- name: "ndk_crtbegin_so.29",
- sdk_version: "29",
- }
-
- ndk_prebuilt_object {
- name: "ndk_crtend_so.29",
- sdk_version: "29",
- }
`
fs := map[string][]byte{
"prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o": nil,
@@ -537,16 +545,28 @@
inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits
var crtbeginFound, crtendFound bool
+ expectedCrtBegin := ctx.ModuleForTests("crtbegin_so",
+ "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+ expectedCrtEnd := ctx.ModuleForTests("crtend_so",
+ "android_arm64_armv8-a_sdk_29").Rule("partialLd").Output
+ implicits := []string{}
for _, input := range inputs {
- switch input.String() {
- case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtbegin_so.o":
+ implicits = append(implicits, input.String())
+ if strings.HasSuffix(input.String(), expectedCrtBegin.String()) {
crtbeginFound = true
- case "prebuilts/ndk/current/platforms/android-29/arch-arm64/usr/lib/crtend_so.o":
+ } else if strings.HasSuffix(input.String(), expectedCrtEnd.String()) {
crtendFound = true
}
}
- if !crtbeginFound || !crtendFound {
- t.Error("should link with ndk_crtbegin_so.29 and ndk_crtend_so.29")
+ if !crtbeginFound {
+ t.Error(fmt.Sprintf(
+ "expected implicit with suffix %q, have the following implicits:\n%s",
+ expectedCrtBegin, strings.Join(implicits, "\n")))
+ }
+ if !crtendFound {
+ t.Error(fmt.Sprintf(
+ "expected implicit with suffix %q, have the following implicits:\n%s",
+ expectedCrtEnd, strings.Join(implicits, "\n")))
}
}
@@ -1020,6 +1040,35 @@
}
}
+func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) {
+ ctx := testContext()
+
+ run(t, ctx, config)
+
+ foo := ctx.ModuleForTests("foo", "android_common")
+ link := foo.Output("package-res.apk")
+ linkFlags := strings.Split(link.Args["flags"], " ")
+ min := android.IndexList("--min-sdk-version", linkFlags)
+ target := android.IndexList("--target-sdk-version", linkFlags)
+
+ if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
+ t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
+ }
+
+ gotMinSdkVersion := linkFlags[min+1]
+ gotTargetSdkVersion := linkFlags[target+1]
+
+ if gotMinSdkVersion != expectedSdkVersion {
+ t.Errorf("incorrect --min-sdk-version, expected %q got %q",
+ expectedSdkVersion, gotMinSdkVersion)
+ }
+
+ if gotTargetSdkVersion != expectedSdkVersion {
+ t.Errorf("incorrect --target-sdk-version, expected %q got %q",
+ expectedSdkVersion, gotTargetSdkVersion)
+ }
+}
+
func TestAppSdkVersion(t *testing.T) {
testCases := []struct {
name string
@@ -1089,38 +1138,85 @@
config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+ checkSdkVersion(t, config, test.expectedMinSdkVersion)
- ctx := testContext()
-
- run(t, ctx, config)
-
- foo := ctx.ModuleForTests("foo", "android_common")
- link := foo.Output("package-res.apk")
- linkFlags := strings.Split(link.Args["flags"], " ")
- min := android.IndexList("--min-sdk-version", linkFlags)
- target := android.IndexList("--target-sdk-version", linkFlags)
-
- if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
- t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
- }
-
- gotMinSdkVersion := linkFlags[min+1]
- gotTargetSdkVersion := linkFlags[target+1]
-
- if gotMinSdkVersion != test.expectedMinSdkVersion {
- t.Errorf("incorrect --min-sdk-version, expected %q got %q",
- test.expectedMinSdkVersion, gotMinSdkVersion)
- }
-
- if gotTargetSdkVersion != test.expectedMinSdkVersion {
- t.Errorf("incorrect --target-sdk-version, expected %q got %q",
- test.expectedMinSdkVersion, gotTargetSdkVersion)
- }
})
}
}
}
+func TestVendorAppSdkVersion(t *testing.T) {
+ testCases := []struct {
+ name string
+ sdkVersion string
+ platformSdkInt int
+ platformSdkCodename string
+ platformSdkFinal bool
+ deviceCurrentApiLevelForVendorModules string
+ expectedMinSdkVersion string
+ }{
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "REL",
+ platformSdkFinal: true,
+ deviceCurrentApiLevelForVendorModules: "29",
+ expectedMinSdkVersion: "29",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "REL",
+ platformSdkFinal: true,
+ deviceCurrentApiLevelForVendorModules: "28",
+ expectedMinSdkVersion: "28",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "Q",
+ platformSdkFinal: false,
+ deviceCurrentApiLevelForVendorModules: "current",
+ expectedMinSdkVersion: "Q",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "Q",
+ platformSdkFinal: false,
+ deviceCurrentApiLevelForVendorModules: "28",
+ expectedMinSdkVersion: "28",
+ },
+ }
+
+ for _, moduleType := range []string{"android_app", "android_library"} {
+ for _, sdkKind := range []string{"", "system_"} {
+ for _, test := range testCases {
+ t.Run(moduleType+" "+test.name, func(t *testing.T) {
+ bp := fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "%s%s",
+ vendor: true,
+ }`, moduleType, sdkKind, test.sdkVersion)
+
+ config := testAppConfig(nil, bp, nil)
+ config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
+ config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
+ config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+ config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules
+ config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"}
+ checkSdkVersion(t, config, test.expectedMinSdkVersion)
+ })
+ }
+ }
+ }
+}
+
func TestJNIABI(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
@@ -1743,52 +1839,125 @@
base: "foo",
package_name: "org.dandroid.bp",
}
+
+ override_android_app {
+ name: "baz_no_rename_resources",
+ base: "foo",
+ package_name: "org.dandroid.bp",
+ rename_resources_package: false,
+ }
+
+ android_app {
+ name: "foo_no_rename_resources",
+ srcs: ["a.java"],
+ certificate: "expiredkey",
+ overrides: ["qux"],
+ rename_resources_package: false,
+ sdk_version: "current",
+ }
+
+ override_android_app {
+ name: "baz_base_no_rename_resources",
+ base: "foo_no_rename_resources",
+ package_name: "org.dandroid.bp",
+ }
+
+ override_android_app {
+ name: "baz_override_base_rename_resources",
+ base: "foo_no_rename_resources",
+ package_name: "org.dandroid.bp",
+ rename_resources_package: true,
+ }
`)
expectedVariants := []struct {
- moduleName string
- variantName string
- apkName string
- apkPath string
- certFlag string
- lineageFlag string
- overrides []string
- aaptFlag string
- logging_parent string
+ name string
+ moduleName string
+ variantName string
+ apkName string
+ apkPath string
+ certFlag string
+ lineageFlag string
+ overrides []string
+ packageFlag string
+ renameResources bool
+ logging_parent string
}{
{
- moduleName: "foo",
- variantName: "android_common",
- apkPath: "/target/product/test_device/system/app/foo/foo.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux"},
- aaptFlag: "",
- logging_parent: "",
+ name: "foo",
+ moduleName: "foo",
+ variantName: "android_common",
+ apkPath: "/target/product/test_device/system/app/foo/foo.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
+ overrides: []string{"qux"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "",
},
{
- moduleName: "bar",
- variantName: "android_common_bar",
- apkPath: "/target/product/test_device/system/app/bar/bar.apk",
- certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
- lineageFlag: "--lineage lineage.bin",
- overrides: []string{"qux", "foo"},
- aaptFlag: "",
- logging_parent: "bah",
+ name: "foo",
+ moduleName: "bar",
+ variantName: "android_common_bar",
+ apkPath: "/target/product/test_device/system/app/bar/bar.apk",
+ certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8",
+ lineageFlag: "--lineage lineage.bin",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "",
+ renameResources: false,
+ logging_parent: "bah",
},
{
- moduleName: "baz",
- variantName: "android_common_baz",
- apkPath: "/target/product/test_device/system/app/baz/baz.apk",
- certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
- lineageFlag: "",
- overrides: []string{"qux", "foo"},
- aaptFlag: "--rename-manifest-package org.dandroid.bp",
- logging_parent: "",
+ name: "foo",
+ moduleName: "baz",
+ variantName: "android_common_baz",
+ apkPath: "/target/product/test_device/system/app/baz/baz.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
+ },
+ {
+ name: "foo",
+ moduleName: "baz_no_rename_resources",
+ variantName: "android_common_baz_no_rename_resources",
+ apkPath: "/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
+ overrides: []string{"qux", "foo"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
+ },
+ {
+ name: "foo_no_rename_resources",
+ moduleName: "baz_base_no_rename_resources",
+ variantName: "android_common_baz_base_no_rename_resources",
+ apkPath: "/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: false,
+ logging_parent: "",
+ },
+ {
+ name: "foo_no_rename_resources",
+ moduleName: "baz_override_base_rename_resources",
+ variantName: "android_common_baz_override_base_rename_resources",
+ apkPath: "/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk",
+ certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8",
+ lineageFlag: "",
+ overrides: []string{"qux", "foo_no_rename_resources"},
+ packageFlag: "org.dandroid.bp",
+ renameResources: true,
+ logging_parent: "",
},
}
for _, expected := range expectedVariants {
- variant := ctx.ModuleForTests("foo", expected.variantName)
+ variant := ctx.ModuleForTests(expected.name, expected.variantName)
// Check the final apk name
outputs := variant.AllOutputs()
@@ -1834,9 +2003,12 @@
// Check the package renaming flag, if exists.
res := variant.Output("package-res.apk")
aapt2Flags := res.Args["flags"]
- if !strings.Contains(aapt2Flags, expected.aaptFlag) {
- t.Errorf("package renaming flag, %q is missing in aapt2 link flags, %q", expected.aaptFlag, aapt2Flags)
+ checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+ expectedPackage := expected.packageFlag
+ if !expected.renameResources {
+ expectedPackage = ""
}
+ checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expectedPackage)
}
}
@@ -1973,6 +2145,7 @@
res := variant.Output("package-res.apk")
aapt2Flags := res.Args["flags"]
checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+ checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", expected.packageFlag)
checkAapt2LinkFlag(t, aapt2Flags, "rename-instrumentation-target-package", expected.targetPackageFlag)
}
}
@@ -2568,10 +2741,37 @@
sdk_version: "current",
}
+ java_sdk_library {
+ name: "runtime-library",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "static-runtime-helper",
+ srcs: ["a.java"],
+ libs: ["runtime-library"],
+ sdk_version: "current",
+ }
+
android_app {
name: "app",
srcs: ["a.java"],
+ libs: ["qux", "quuz"],
+ static_libs: ["static-runtime-helper"],
+ uses_libs: ["foo"],
+ sdk_version: "current",
+ optional_uses_libs: [
+ "bar",
+ "baz",
+ ],
+ }
+
+ android_app {
+ name: "app_with_stub_deps",
+ srcs: ["a.java"],
libs: ["qux", "quuz.stubs"],
+ static_libs: ["static-runtime-helper"],
uses_libs: ["foo"],
sdk_version: "current",
optional_uses_libs: [
@@ -2600,15 +2800,15 @@
run(t, ctx, config)
app := ctx.ModuleForTests("app", "android_common")
+ appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "android_common")
prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
// Test that implicit dependencies on java_sdk_library instances are passed to the manifest.
manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) {
- t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
- }
- if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) {
- t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ for _, w := range []string{"qux", "quuz", "runtime-library"} {
+ if !strings.Contains(manifestFixerArgs, "--uses-library "+w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
}
// Test that all libraries are verified
@@ -2631,16 +2831,25 @@
t.Errorf("wanted %q in %q", w, cmd)
}
- // Test that only present libraries are preopted
+ // Test that all present libraries are preopted, including implicit SDK dependencies
cmd = app.Rule("dexpreopt").RuleParams.Command
-
- if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+ w := `--target-classpath-for-sdk any` +
+ ` /system/framework/foo.jar` +
+ `:/system/framework/quuz.jar` +
+ `:/system/framework/qux.jar` +
+ `:/system/framework/runtime-library.jar` +
+ `:/system/framework/bar.jar`
+ if !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
- cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+ // TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present
+ if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" {
+ t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries")
+ }
- if w := `dex_preopt_target_libraries="/system/framework/foo.jar /system/framework/bar.jar"`; !strings.Contains(cmd, w) {
+ cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+ if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
}
@@ -2910,6 +3119,7 @@
config := testAppConfig(nil, bp, nil)
if unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
}
ctx := testContext()
@@ -3190,6 +3400,7 @@
res := variant.Output("package-res.apk")
aapt2Flags := res.Args["flags"]
checkAapt2LinkFlag(t, aapt2Flags, "rename-manifest-package", expected.packageFlag)
+ checkAapt2LinkFlag(t, aapt2Flags, "rename-resources-package", "")
checkAapt2LinkFlag(t, aapt2Flags, "rename-overlay-target-package", expected.targetPackageFlag)
}
}
diff --git a/java/builder.go b/java/builder.go
index 7318fcb..3043e46 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -385,7 +385,7 @@
"outDir": android.PathForModuleOut(ctx, "turbine", "classes").String(),
"javaVersion": flags.javaVersion.String(),
}
- if ctx.Config().IsEnvTrue("RBE_TURBINE") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_TURBINE") {
rule = turbineRE
args["implicits"] = strings.Join(deps.Strings(), ",")
}
@@ -452,7 +452,7 @@
annoDir = filepath.Join(shardDir, annoDir)
}
rule := javac
- if ctx.Config().IsEnvTrue("RBE_JAVAC") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAVAC") {
rule = javacRE
}
ctx.Build(pctx, android.BuildParams{
@@ -480,7 +480,7 @@
jarArgs []string, deps android.Paths) {
rule := jar
- if ctx.Config().IsEnvTrue("RBE_JAR") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_JAR") {
rule = jarRE
}
ctx.Build(pctx, android.BuildParams{
diff --git a/java/config/config.go b/java/config/config.go
index 1d0dd61..31e2b0f 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -28,11 +28,13 @@
var (
pctx = android.NewPackageContext("android/soong/java/config")
- DefaultBootclasspathLibraries = []string{"core.platform.api.stubs", "core-lambda-stubs"}
- DefaultSystemModules = "core-platform-api-stubs-system-modules"
- DefaultLibraries = []string{"ext", "framework"}
- DefaultLambdaStubsLibrary = "core-lambda-stubs"
- SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
+ LegacyCorePlatformBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
+ LegacyCorePlatformSystemModules = "legacy-core-platform-api-stubs-system-modules"
+ StableCorePlatformBootclasspathLibraries = []string{"stable.core.platform.api.stubs", "core-lambda-stubs"}
+ StableCorePlatformSystemModules = "stable-core-platform-api-stubs-system-modules"
+ FrameworkLibraries = []string{"ext", "framework"}
+ DefaultLambdaStubsLibrary = "core-lambda-stubs"
+ SdkLambdaStubsPath = "prebuilts/sdk/tools/core-lambda-stubs.jar"
DefaultMakeJacocoExcludeFilter = []string{"org.junit.*", "org.jacoco.*", "org.mockito.*"}
DefaultJacocoExcludeFilter = []string{"org.junit.**", "org.jacoco.**", "org.mockito.**"}
@@ -112,7 +114,7 @@
pctx.SourcePathVariable("JavaKytheExtractorJar", "prebuilts/build-tools/common/framework/javac_extractor.jar")
pctx.SourcePathVariable("Ziptime", "prebuilts/build-tools/${hostPrebuiltTag}/bin/ziptime")
- pctx.SourcePathVariable("GenKotlinBuildFileCmd", "build/soong/scripts/gen-kotlin-build-file.sh")
+ pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file.py")
pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh")
pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh")
@@ -128,7 +130,7 @@
pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks")
pctx.VariableFunc("TurbineJar", func(ctx android.PackageVarContext) string {
turbine := "turbine.jar"
- if ctx.Config().UnbundledBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return "prebuilts/build-tools/common/framework/" + turbine
} else {
return ctx.Config().HostJavaToolPath(ctx, turbine).String()
@@ -163,7 +165,7 @@
pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
- pctx.HostBinToolVariable("Class2Greylist", "class2greylist")
+ pctx.HostBinToolVariable("Class2NonSdkList", "class2nonsdklist")
pctx.HostBinToolVariable("HiddenAPI", "hiddenapi")
hostBinToolVariableWithSdkToolsPrebuilt("Aapt2Cmd", "aapt2")
@@ -178,7 +180,7 @@
func hostBinToolVariableWithSdkToolsPrebuilt(name, tool string) {
pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return filepath.Join("prebuilts/sdk/tools", runtime.GOOS, "bin", tool)
} else {
return ctx.Config().HostToolPath(ctx, tool).String()
@@ -188,7 +190,7 @@
func hostJavaToolVariableWithSdkToolsPrebuilt(name, tool string) {
pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return filepath.Join("prebuilts/sdk/tools/lib", tool+".jar")
} else {
return ctx.Config().HostJavaToolPath(ctx, tool+".jar").String()
@@ -198,7 +200,7 @@
func hostJNIToolVariableWithSdkToolsPrebuilt(name, tool string) {
pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
ext := ".so"
if runtime.GOOS == "darwin" {
ext = ".dylib"
@@ -212,7 +214,7 @@
func hostBinToolVariableWithBuildToolsPrebuilt(name, tool string) {
pctx.VariableFunc(name, func(ctx android.PackageVarContext) string {
- if ctx.Config().UnbundledBuild() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return filepath.Join("prebuilts/build-tools", ctx.Config().PrebuiltOS(), "bin", tool)
} else {
return ctx.Config().HostToolPath(ctx, tool).String()
diff --git a/java/config/makevars.go b/java/config/makevars.go
index b355fad..df447a1 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -25,9 +25,11 @@
}
func makeVarsProvider(ctx android.MakeVarsContext) {
- ctx.Strict("TARGET_DEFAULT_JAVA_LIBRARIES", strings.Join(DefaultLibraries, " "))
- ctx.Strict("TARGET_DEFAULT_BOOTCLASSPATH_LIBRARIES", strings.Join(DefaultBootclasspathLibraries, " "))
- ctx.Strict("DEFAULT_SYSTEM_MODULES", DefaultSystemModules)
+ ctx.Strict("FRAMEWORK_LIBRARIES", strings.Join(FrameworkLibraries, " "))
+
+ // These are used by make when LOCAL_PRIVATE_PLATFORM_APIS is set (equivalent to platform_apis in blueprint):
+ ctx.Strict("LEGACY_CORE_PLATFORM_BOOTCLASSPATH_LIBRARIES", strings.Join(LegacyCorePlatformBootclasspathLibraries, " "))
+ ctx.Strict("LEGACY_CORE_PLATFORM_SYSTEM_MODULES", LegacyCorePlatformSystemModules)
ctx.Strict("ANDROID_JAVA_HOME", "${JavaHome}")
ctx.Strict("ANDROID_JAVA8_HOME", "prebuilts/jdk/jdk8/${hostPrebuiltTag}")
@@ -73,7 +75,7 @@
ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}")
- ctx.Strict("CLASS2GREYLIST", "${Class2Greylist}")
+ ctx.Strict("CLASS2NONSDKLIST", "${Class2NonSdkList}")
ctx.Strict("HIDDENAPI", "${HiddenAPI}")
ctx.Strict("DEX_FLAGS", "${DexFlags}")
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 11e68eb..40a2280 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -19,6 +19,7 @@
"io"
"android/soong/android"
+ "android/soong/dexpreopt"
)
type DeviceHostConverter struct {
@@ -150,7 +151,11 @@
return d.implementationAndResourceJars
}
-func (d *DeviceHostConverter) DexJar() android.Path {
+func (d *DeviceHostConverter) DexJarBuildPath() android.Path {
+ return nil
+}
+
+func (d *DeviceHostConverter) DexJarInstallPath() android.Path {
return nil
}
@@ -158,7 +163,7 @@
return nil
}
-func (d *DeviceHostConverter) ExportedSdkLibs() []string {
+func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths {
return nil
}
diff --git a/java/dex.go b/java/dex.go
index dba2836..21a5926 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -38,6 +38,10 @@
// True if the module containing this has it set by default.
EnabledByDefault bool `blueprint:"mutated"`
+ // If true, runs R8 in Proguard compatibility mode (default).
+ // Otherwise, runs R8 in full mode.
+ Proguard_compatibility *bool
+
// If true, optimize for size by removing unused code. Defaults to true for apps,
// false for libraries and tests.
Shrink *bool
@@ -113,7 +117,6 @@
`rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
`mkdir -p $$(dirname ${outUsage}) && ` +
`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
- `--force-proguard-compatibility ` +
`--no-data-resources ` +
`-printmapping ${outDict} ` +
`-printusage ${outUsage} ` +
@@ -230,6 +233,10 @@
r8Flags = append(r8Flags, opt.Proguard_flags...)
+ if BoolDefault(opt.Proguard_compatibility, true) {
+ r8Flags = append(r8Flags, "--force-proguard-compatibility")
+ }
+
// TODO(ccross): Don't shrink app instrumentation tests by default.
if !Bool(opt.Shrink) {
r8Flags = append(r8Flags, "-dontshrink")
@@ -280,7 +287,7 @@
r8Flags, r8Deps := d.r8Flags(ctx, flags)
rule := r8
args := map[string]string{
- "r8Flags": strings.Join(append(r8Flags, commonFlags...), " "),
+ "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
"zipFlags": zipFlags,
"outDict": proguardDictionary.String(),
"outUsageDir": proguardUsageDir.String(),
@@ -288,7 +295,7 @@
"outUsageZip": proguardUsageZip.String(),
"outDir": outDir.String(),
}
- if ctx.Config().IsEnvTrue("RBE_R8") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") {
rule = r8RE
args["implicits"] = strings.Join(r8Deps.Strings(), ",")
}
@@ -304,7 +311,7 @@
} else {
d8Flags, d8Deps := d8Flags(flags)
rule := d8
- if ctx.Config().IsEnvTrue("RBE_D8") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") {
rule = d8RE
}
ctx.Build(pctx, android.BuildParams{
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 28a2c8a..f1b7178 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -37,7 +37,7 @@
usesLibs []string
optionalUsesLibs []string
enforceUsesLibs bool
- libraryPaths map[string]android.Path
+ libraryPaths dexpreopt.LibraryPaths
builtInstalled string
}
@@ -77,10 +77,6 @@
return true
}
- if ctx.Config().UnbundledBuild() {
- return true
- }
-
if d.isTest {
return true
}
@@ -131,7 +127,8 @@
global := dexpreopt.GetGlobalConfig(ctx)
bootImage := defaultBootImageConfig(ctx)
dexFiles := bootImage.dexPathsDeps.Paths()
- dexLocations := bootImage.dexLocationsDeps
+ // The dex locations for all Android variants are identical.
+ dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
if global.UseArtImage {
bootImage = artBootImageConfig(ctx)
}
@@ -159,6 +156,8 @@
images = append(images, variant.images)
imagesDeps = append(imagesDeps, variant.imagesDeps)
}
+ // The image locations for all Android variants are identical.
+ imageLocations := bootImage.getAnyAndroidVariant().imageLocations()
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
@@ -174,7 +173,7 @@
profileBootListing = android.ExistentPathForSource(ctx,
ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
profileIsTextListing = true
- } else {
+ } else if global.ProfileDir != "" {
profileClassListing = android.ExistentPathForSource(ctx,
global.ProfileDir, ctx.ModuleName()+".prof")
}
@@ -194,15 +193,15 @@
ProfileIsTextListing: profileIsTextListing,
ProfileBootListing: profileBootListing,
- EnforceUsesLibraries: d.enforceUsesLibs,
- PresentOptionalUsesLibraries: d.optionalUsesLibs,
- UsesLibraries: d.usesLibs,
- LibraryPaths: d.libraryPaths,
+ EnforceUsesLibraries: d.enforceUsesLibs,
+ OptionalUsesLibraries: d.optionalUsesLibs,
+ UsesLibraries: d.usesLibs,
+ LibraryPaths: d.libraryPaths,
Archs: archs,
DexPreoptImages: images,
DexPreoptImagesDeps: imagesDeps,
- DexPreoptImageLocations: bootImage.imageLocations,
+ DexPreoptImageLocations: imageLocations,
PreoptBootClassPathDexFiles: dexFiles,
PreoptBootClassPathDexLocations: dexLocations,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2f0cbdb..3addc1a 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -29,29 +29,10 @@
RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
}
-// The image "location" is a symbolic path that with multiarchitecture
-// support doesn't really exist on the device. Typically it is
-// /system/framework/boot.art and should be the same for all supported
-// architectures on the device. The concrete architecture specific
-// content actually ends up in a "filename" that contains an
-// architecture specific directory name such as arm, arm64, mips,
-// mips64, x86, x86_64.
-//
-// Here are some example values for an x86_64 / x86 configuration:
-//
-// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
-// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
-//
-// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
-// will then reconstruct the real path, so the rules must have a dependency on the real path.
-
// Target-independent description of pre-compiled boot image.
type bootImageConfig struct {
- // Whether this image is an extension.
- extension bool
+ // If this image is an extension, the image that it extends.
+ extends *bootImageConfig
// Image name (used in directory names and ninja rule names).
name string
@@ -68,20 +49,13 @@
// Subdirectory where the image files are installed.
installSubdir string
- // The names of jars that constitute this image.
- modules []string
-
- // The "locations" of jars.
- dexLocations []string // for this image
- dexLocationsDeps []string // for the dependency images and in this image
+ // A list of (location, jar) pairs for the Java modules in this image.
+ modules android.ConfiguredJarList
// File paths to jars.
dexPaths android.WritablePaths // for this image
dexPathsDeps android.WritablePaths // for the dependency images and in this image
- // The "locations" of the dependency images and in this image.
- imageLocations []string
-
// File path to a zip archive with all image files (or nil, if not needed).
zip android.WritablePath
@@ -99,6 +73,10 @@
// Target for which the image is generated.
target android.Target
+ // The "locations" of jars.
+ dexLocations []string // for this image
+ dexLocationsDeps []string // for the dependency images and in this image
+
// Paths to image files.
images android.OutputPath // first image file
imagesDeps android.OutputPaths // all files
@@ -121,30 +99,40 @@
return nil
}
-func (image bootImageConfig) moduleName(idx int) string {
+// Return any (the first) variant which is for the device (as opposed to for the host)
+func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant {
+ for _, variant := range image.variants {
+ if variant.target.Os == android.Android {
+ return variant
+ }
+ }
+ return nil
+}
+
+func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string {
// Dexpreopt on the boot class path produces multiple files. The first dex file
// is converted into 'name'.art (to match the legacy assumption that 'name'.art
// exists), and the rest are converted to 'name'-<jar>.art.
- m := image.modules[idx]
+ m := image.modules.Jar(idx)
name := image.stem
- if idx != 0 || image.extension {
- name += "-" + stemOf(m)
+ if idx != 0 || image.extends != nil {
+ name += "-" + android.ModuleStem(m)
}
return name
}
-func (image bootImageConfig) firstModuleNameOrStem() string {
- if len(image.modules) > 0 {
- return image.moduleName(0)
+func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string {
+ if image.modules.Len() > 0 {
+ return image.moduleName(ctx, 0)
} else {
return image.stem
}
}
func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths {
- ret := make(android.OutputPaths, 0, len(image.modules)*len(exts))
- for i := range image.modules {
- name := image.moduleName(i)
+ ret := make(android.OutputPaths, 0, image.modules.Len()*len(exts))
+ for i := 0; i < image.modules.Len(); i++ {
+ name := image.moduleName(ctx, i)
for _, ext := range exts {
ret = append(ret, dir.Join(ctx, name+ext))
}
@@ -152,6 +140,24 @@
return ret
}
+// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really
+// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the
+// same for all supported architectures on the device. The concrete architecture specific files
+// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64.
+//
+// For example a physical file
+// "/apex/com.android.art/javalib/x86/boot.art" has "image location"
+// "/apex/com.android.art/javalib/boot.art" (which is not an actual file).
+//
+// The location is passed as an argument to the ART tools like dex2oat instead of the real path.
+// ART tools will then reconstruct the architecture-specific real path.
+func (image *bootImageVariant) imageLocations() (imageLocations []string) {
+ if image.extends != nil {
+ imageLocations = image.extends.getVariant(image.target).imageLocations()
+ }
+ return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType))
+}
+
func concat(lists ...[]string) []string {
var size int
for _, l := range lists {
@@ -173,20 +179,7 @@
}
func skipDexpreoptBootJars(ctx android.PathContext) bool {
- if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
- return true
- }
-
- if ctx.Config().UnbundledBuild() {
- return true
- }
-
- if len(ctx.Config().Targets[android.Android]) == 0 {
- // Host-only build
- return true
- }
-
- return false
+ return dexpreopt.GetGlobalConfig(ctx).DisablePreopt
}
type dexpreoptBootJars struct {
@@ -204,7 +197,10 @@
// Include dexpreopt files for the primary boot image.
files := map[android.ArchType]android.OutputPaths{}
for _, variant := range artBootImageConfig(ctx).variants {
- files[variant.target.Arch.ArchType] = variant.imagesDeps
+ // We also generate boot images for host (for testing), but we don't need those in the apex.
+ if variant.target.Os == android.Android {
+ files[variant.target.Arch.ArchType] = variant.imagesDeps
+ }
}
return files
}
@@ -251,13 +247,13 @@
return -1, nil
}
- jar, hasJar := module.(interface{ DexJar() android.Path })
+ jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
if !hasJar {
return -1, nil
}
name := ctx.ModuleName(module)
- index := android.IndexList(name, image.modules)
+ index := image.modules.IndexOfJar(name)
if index == -1 {
return -1, nil
}
@@ -266,7 +262,7 @@
apex, isApexModule := module.(android.ApexModule)
fromUpdatableApex := isApexModule && apex.Updatable()
if image.name == artBootImageName {
- if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
+ if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") {
// ok: found the jar in the ART apex
} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
// exception (skip and continue): special "hostdex" platform variant
@@ -276,30 +272,39 @@
return -1, nil
} else if fromUpdatableApex {
// error: this jar is part of an updatable apex other than ART
- ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
+ ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes())
} else {
// error: this jar is part of the platform or a non-updatable apex
- ctx.Errorf("module '%s' is not allowed in the ART boot image", name)
+ ctx.Errorf("module %q is not allowed in the ART boot image", name)
}
} else if image.name == frameworkBootImageName {
if !fromUpdatableApex {
// ok: this jar is part of the platform or a non-updatable apex
} else {
// error: this jar is part of an updatable apex
- ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
+ ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes())
}
} else {
panic("unknown boot image: " + image.name)
}
- return index, jar.DexJar()
+ return index, jar.DexJarBuildPath()
+}
+
+func allHavePrefix(list []string, prefix string) bool {
+ for _, s := range list {
+ if !strings.HasPrefix(s, prefix) {
+ return false
+ }
+ }
+ return true
}
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
// Collect dex jar paths for the boot image modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
- bootDexJars := make(android.Paths, len(image.modules))
+ bootDexJars := make(android.Paths, image.modules.Len())
ctx.VisitAllModules(func(module android.Module) {
if i, j := getBootImageJar(ctx, image, module); i != -1 {
bootDexJars[i] = j
@@ -310,13 +315,13 @@
// Ensure all modules were converted to paths
for i := range bootDexJars {
if bootDexJars[i] == nil {
+ m := image.modules.Jar(i)
if ctx.Config().AllowMissingDependencies() {
- missingDeps = append(missingDeps, image.modules[i])
+ missingDeps = append(missingDeps, m)
bootDexJars[i] = android.PathForOutput(ctx, "missing")
} else {
ctx.Errorf("failed to find a dex jar path for module '%s'"+
- ", note that some jars may be filtered out by module constraints",
- image.modules[i])
+ ", note that some jars may be filtered out by module constraints", m)
}
}
}
@@ -336,10 +341,12 @@
bootFrameworkProfileRule(ctx, image, missingDeps)
updatableBcpPackagesRule(ctx, image, missingDeps)
- var allFiles android.Paths
+ var zipFiles android.Paths
for _, variant := range image.variants {
files := buildBootImageVariant(ctx, variant, profile, missingDeps)
- allFiles = append(allFiles, files.Paths()...)
+ if variant.target.Os == android.Android {
+ zipFiles = append(zipFiles, files.Paths()...)
+ }
}
if image.zip != nil {
@@ -347,8 +354,8 @@
rule.Command().
BuiltTool(ctx, "soong_zip").
FlagWithOutput("-o ", image.zip).
- FlagWithArg("-C ", image.dir.String()).
- FlagWithInputList("-f ", allFiles, " -f ")
+ FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()).
+ FlagWithInputList("-f ", zipFiles, " -f ")
rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image")
}
@@ -363,9 +370,10 @@
global := dexpreopt.GetGlobalConfig(ctx)
arch := image.target.Arch.ArchType
- symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String())
+ os := image.target.Os.String() // We need to distinguish host-x86 and device-x86.
+ symbolsDir := image.symbolsDir.Join(ctx, os, image.installSubdir, arch.String())
symbolsFile := symbolsDir.Join(ctx, image.stem+".oat")
- outputDir := image.dir.Join(ctx, image.installSubdir, arch.String())
+ outputDir := image.dir.Join(ctx, os, image.installSubdir, arch.String())
outputPath := outputDir.Join(ctx, image.stem+".oat")
oatLocation := dexpreopt.PathToLocation(outputPath, arch)
imagePath := outputPath.ReplaceExtension(ctx, "art")
@@ -411,7 +419,7 @@
cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path())
}
- if image.extension {
+ if image.extends != nil {
artImage := image.primaryImages
cmd.
Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
@@ -433,13 +441,18 @@
FlagWithArg("--oat-location=", oatLocation).
FlagWithArg("--image=", imagePath.String()).
FlagWithArg("--instruction-set=", arch.String()).
- FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]).
- FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]).
FlagWithArg("--android-root=", global.EmptyDirectory).
FlagWithArg("--no-inline-from=", "core-oj.jar").
Flag("--force-determinism").
Flag("--abort-on-hard-verifier-error")
+ // Use the default variant/features for host builds.
+ // The map below contains only device CPU info (which might be x86 on some devices).
+ if image.target.Os == android.Android {
+ cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch])
+ cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch])
+ }
+
if global.BootFlags != "" {
cmd.Flag(global.BootFlags)
}
@@ -451,7 +464,6 @@
cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
installDir := filepath.Join("/", image.installSubdir, arch.String())
- vdexInstallDir := filepath.Join("/", image.installSubdir)
var vdexInstalls android.RuleBuilderInstalls
var unstrippedInstalls android.RuleBuilderInstalls
@@ -470,11 +482,10 @@
cmd.ImplicitOutput(vdex)
zipFiles = append(zipFiles, vdex)
- // The vdex files are identical between architectures, install them to a shared location. The Make rules will
- // only use the install rules for one architecture, and will create symlinks into the architecture-specific
- // directories.
+ // Note that the vdex files are identical between architectures.
+ // Make rules will create symlinks to share them between architectures.
vdexInstalls = append(vdexInstalls,
- android.RuleBuilderInstall{vdex, filepath.Join(vdexInstallDir, vdex.Base())})
+ android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())})
}
for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") {
@@ -485,7 +496,7 @@
android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())})
}
- rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+arch.String(), "dexpreopt "+image.name+" jars "+arch.String())
+ rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String())
// save output and installed files for makevars
image.installs = rule.Installs()
@@ -503,7 +514,7 @@
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
- if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+ if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() {
return nil
}
profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
@@ -535,7 +546,7 @@
Tool(globalSoong.Profman).
FlagWithInput("--create-profile-from=", bootImageProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+ FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.prof")
@@ -558,7 +569,7 @@
globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx)
global := dexpreopt.GetGlobalConfig(ctx)
- if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+ if global.DisableGenerateProfile || ctx.Config().UnbundledBuild() {
return nil
}
return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} {
@@ -586,7 +597,7 @@
Flag("--generate-boot-profile").
FlagWithInput("--create-profile-from=", bootFrameworkProfile).
FlagForEachInput("--apk=", image.dexPathsDeps.Paths()).
- FlagForEachArg("--dex-location=", image.dexLocationsDeps).
+ FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps).
FlagWithOutput("--reference-profile-file=", profile)
rule.Install(profile, "/system/etc/boot-image.bprof")
@@ -600,13 +611,13 @@
var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule")
func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath {
- if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
+ if ctx.Config().UnbundledBuild() {
return nil
}
return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} {
global := dexpreopt.GetGlobalConfig(ctx)
- updatableModules := dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)
+ updatableModules := global.UpdatableBootJars.CopyOfJars()
// Collect `permitted_packages` for updatable boot jars.
var updatablePackages []string
@@ -658,27 +669,32 @@
var allPhonies android.Paths
for _, image := range image.variants {
arch := image.target.Arch.ArchType
+ suffix := arch.String()
+ // Host and target might both use x86 arch. We need to ensure the names are unique.
+ if image.target.Os.Class == android.Host {
+ suffix = "host-" + suffix
+ }
// Create a rule to call oatdump.
- output := android.PathForOutput(ctx, "boot."+arch.String()+".oatdump.txt")
+ output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt")
rule := android.NewRuleBuilder()
rule.Command().
// TODO: for now, use the debug version for better error reporting
BuiltTool(ctx, "oatdumpd").
FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
- FlagWithArg("--image=", strings.Join(image.imageLocations, ":")).Implicits(image.imagesDeps.Paths()).
+ FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()).
FlagWithOutput("--output=", output).
FlagWithArg("--instruction-set=", arch.String())
- rule.Build(pctx, ctx, "dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
// Create a phony rule that depends on the output file and prints the path.
- phony := android.PathForPhony(ctx, "dump-oat-boot-"+arch.String())
+ phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix)
rule = android.NewRuleBuilder()
rule.Command().
Implicit(output).
ImplicitOutput(phony).
Text("echo").FlagWithArg("Output in ", output.String())
- rule.Build(pctx, ctx, "phony-dump-oat-boot-"+arch.String(), "dump oat boot "+arch.String())
+ rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String())
allPhonies = append(allPhonies, phony)
}
@@ -716,21 +732,25 @@
if image != nil {
ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String())
ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " "))
- ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " "))
+ ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " "))
var imageNames []string
for _, current := range append(d.otherImages, image) {
imageNames = append(imageNames, current.name)
- for _, current := range current.variants {
- sfx := current.name + "_" + current.target.Arch.ArchType.String()
- ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls.String())
- ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images.String())
- ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps.Strings(), " "))
- ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs.String())
- ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls.String())
+ for _, variant := range current.variants {
+ suffix := ""
+ if variant.target.Os.Class == android.Host {
+ suffix = "_host"
+ }
+ sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String()
+ ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String())
+ ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String())
+ ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " "))
+ ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String())
+ ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String())
}
-
- ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":"))
+ imageLocations := current.getAnyAndroidVariant().imageLocations()
+ ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":"))
ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String())
}
ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " "))
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index e7b3c3b..4a8d3cd 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -24,7 +24,7 @@
"android/soong/dexpreopt"
)
-func TestDexpreoptBootJars(t *testing.T) {
+func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOutputs []string) {
bp := `
java_sdk_library {
name: "foo",
@@ -48,67 +48,88 @@
pathCtx := android.PathContextForTesting(config)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"}
+ dexpreoptConfig.BootJars = android.CreateConfiguredJarList(pathCtx, []string{"platform:foo", "platform:bar", "platform:baz"})
dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
ctx := testContext()
-
RegisterDexpreoptBootJarsComponents(ctx)
-
run(t, ctx, config)
dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
-
- bootArt := dexpreoptBootJars.Output("boot-foo.art")
-
- expectedInputs := []string{
- "dex_artjars/apex/com.android.art/javalib/arm64/boot.art",
- "dex_bootjars_input/foo.jar",
- "dex_bootjars_input/bar.jar",
- "dex_bootjars_input/baz.jar",
- }
+ rule := dexpreoptBootJars.Output(ruleFile)
for i := range expectedInputs {
expectedInputs[i] = filepath.Join(buildDir, "test_device", expectedInputs[i])
}
- inputs := bootArt.Implicits.Strings()
- sort.Strings(inputs)
- sort.Strings(expectedInputs)
-
- if !reflect.DeepEqual(inputs, expectedInputs) {
- t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
- }
-
- expectedOutputs := []string{
- "dex_bootjars/system/framework/arm64/boot.invocation",
-
- "dex_bootjars/system/framework/arm64/boot-foo.art",
- "dex_bootjars/system/framework/arm64/boot-bar.art",
- "dex_bootjars/system/framework/arm64/boot-baz.art",
-
- "dex_bootjars/system/framework/arm64/boot-foo.oat",
- "dex_bootjars/system/framework/arm64/boot-bar.oat",
- "dex_bootjars/system/framework/arm64/boot-baz.oat",
-
- "dex_bootjars/system/framework/arm64/boot-foo.vdex",
- "dex_bootjars/system/framework/arm64/boot-bar.vdex",
- "dex_bootjars/system/framework/arm64/boot-baz.vdex",
-
- "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat",
- "dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat",
- }
-
for i := range expectedOutputs {
expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
}
- outputs := append(android.WritablePaths{bootArt.Output}, bootArt.ImplicitOutputs...).Strings()
+ inputs := rule.Implicits.Strings()
+ sort.Strings(inputs)
+ sort.Strings(expectedInputs)
+
+ outputs := append(android.WritablePaths{rule.Output}, rule.ImplicitOutputs...).Strings()
sort.Strings(outputs)
sort.Strings(expectedOutputs)
+ if !reflect.DeepEqual(inputs, expectedInputs) {
+ t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
+ }
+
if !reflect.DeepEqual(outputs, expectedOutputs) {
t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
}
}
+
+func TestDexpreoptBootJars(t *testing.T) {
+ ruleFile := "boot-foo.art"
+
+ expectedInputs := []string{
+ "dex_artjars/android/apex/com.android.art/javalib/arm64/boot.art",
+ "dex_bootjars_input/foo.jar",
+ "dex_bootjars_input/bar.jar",
+ "dex_bootjars_input/baz.jar",
+ }
+
+ expectedOutputs := []string{
+ "dex_bootjars/android/system/framework/arm64/boot.invocation",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.art",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.art",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.art",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.oat",
+ "dex_bootjars/android/system/framework/arm64/boot-foo.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-bar.vdex",
+ "dex_bootjars/android/system/framework/arm64/boot-baz.vdex",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-foo.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-bar.oat",
+ "dex_bootjars_unstripped/android/system/framework/arm64/boot-baz.oat",
+ }
+
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
+}
+
+// Changes to the boot.zip structure may break the ART APK scanner.
+func TestDexpreoptBootZip(t *testing.T) {
+ ruleFile := "boot.zip"
+
+ ctx := android.PathContextForTesting(testConfig(nil, "", nil))
+ expectedInputs := []string{}
+ for _, target := range ctx.Config().Targets[android.Android] {
+ for _, ext := range []string{".art", ".oat", ".vdex"} {
+ for _, jar := range []string{"foo", "bar", "baz"} {
+ expectedInputs = append(expectedInputs,
+ filepath.Join("dex_bootjars", target.Os.String(), "system/framework", target.Arch.ArchType.String(), "boot-"+jar+ext))
+ }
+ }
+ }
+
+ expectedOutputs := []string{
+ "dex_bootjars/boot.zip",
+ }
+
+ testDexpreoptBoot(t, ruleFile, expectedInputs, expectedOutputs)
+}
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index f8356d1..f0d82ff 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -37,14 +37,12 @@
filepath.Join("/system/framework", m+".jar"))
}
// 2) The jars that are from an updatable apex.
- for _, m := range global.UpdatableSystemServerJars {
- systemServerClasspathLocations = append(systemServerClasspathLocations,
- dexpreopt.GetJarLocationFromApexJarPair(m))
- }
- if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
+ systemServerClasspathLocations = append(systemServerClasspathLocations,
+ global.UpdatableSystemServerJars.DevicePaths(ctx.Config(), android.Android)...)
+ if len(systemServerClasspathLocations) != len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len() {
panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
len(systemServerClasspathLocations),
- len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
+ len(global.SystemServerJars)+global.UpdatableSystemServerJars.Len()))
}
return systemServerClasspathLocations
})
@@ -61,20 +59,14 @@
targets = append(targets, target)
}
}
+ // We may also need the images on host in order to run host-based tests.
+ for _, target := range ctx.Config().Targets[android.BuildOs] {
+ targets = append(targets, target)
+ }
return targets
}
-func stemOf(moduleName string) string {
- // b/139391334: the stem of framework-minus-apex is framework
- // This is hard coded here until we find a good way to query the stem
- // of a module before any other mutators are run
- if moduleName == "framework-minus-apex" {
- return "framework"
- }
- return moduleName
-}
-
var (
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
artBootImageName = "art"
@@ -89,47 +81,34 @@
targets := dexpreoptTargets(ctx)
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
- artModules := global.ArtApexJars
+ artModules := global.ArtApexJars.CopyOf()
// With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco.
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
- artModules = append(artModules, "jacocoagent")
+ artModules.Append("com.android.art", "jacocoagent")
}
- frameworkModules := android.RemoveListFromList(global.BootJars,
- concat(artModules, dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)))
+ frameworkModules := global.BootJars.CopyOf()
+ frameworkModules.RemoveList(artModules)
artSubdir := "apex/com.android.art/javalib"
frameworkSubdir := "system/framework"
- var artLocations, frameworkLocations []string
- for _, m := range artModules {
- artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar"))
- }
- for _, m := range frameworkModules {
- frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar"))
- }
-
// ART config for the primary boot image in the ART apex.
// It includes the Core Libraries.
artCfg := bootImageConfig{
- extension: false,
- name: artBootImageName,
- stem: "boot",
- installSubdir: artSubdir,
- modules: artModules,
- dexLocations: artLocations,
- dexLocationsDeps: artLocations,
+ name: artBootImageName,
+ stem: "boot",
+ installSubdir: artSubdir,
+ modules: artModules,
}
// Framework config for the boot image extension.
// It includes framework libraries and depends on the ART config.
frameworkCfg := bootImageConfig{
- extension: true,
- name: frameworkBootImageName,
- stem: "boot",
- installSubdir: frameworkSubdir,
- modules: frameworkModules,
- dexLocations: frameworkLocations,
- dexLocationsDeps: append(artLocations, frameworkLocations...),
+ extends: &artCfg,
+ name: frameworkBootImageName,
+ stem: "boot",
+ installSubdir: frameworkSubdir,
+ modules: frameworkModules,
}
configs := map[string]*bootImageConfig{
@@ -143,30 +122,28 @@
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
- imageName := c.firstModuleNameOrStem() + ".art"
-
- c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()}
+ imageName := c.firstModuleNameOrStem(ctx) + ".art"
// The path to bootclasspath dex files needs to be known at module
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
// Set up known paths for them, the singleton rules will copy them there.
// TODO(b/143682396): use module dependencies instead
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
- for _, m := range c.modules {
- c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(m)+".jar"))
- }
+ c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
c.dexPathsDeps = c.dexPaths
// Create target-specific variants.
for _, target := range targets {
arch := target.Arch.ArchType
- imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
+ imageDir := c.dir.Join(ctx, target.Os.String(), c.installSubdir, arch.String())
variant := &bootImageVariant{
bootImageConfig: c,
target: target,
images: imageDir.Join(ctx, imageName),
imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
+ dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os),
}
+ variant.dexLocationsDeps = variant.dexLocations
c.variants = append(c.variants, variant)
}
@@ -177,8 +154,8 @@
frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
for i := range targets {
frameworkCfg.variants[i].primaryImages = artCfg.variants[i].images
+ frameworkCfg.variants[i].dexLocationsDeps = append(artCfg.variants[i].dexLocations, frameworkCfg.variants[i].dexLocationsDeps...)
}
- frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
return configs
}).(map[string]*bootImageConfig)
@@ -197,12 +174,9 @@
global := dexpreopt.GetGlobalConfig(ctx)
image := defaultBootImageConfig(ctx)
- updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
- for i, p := range global.UpdatableBootJars {
- updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
- }
+ updatableBootclasspath := global.UpdatableBootJars.DevicePaths(ctx.Config(), android.Android)
- bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...)
+ bootclasspath := append(copyOf(image.getAnyAndroidVariant().dexLocationsDeps), updatableBootclasspath...)
return bootclasspath
})
}
@@ -217,8 +191,8 @@
func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
- ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":"))
+ ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).getAnyAndroidVariant().dexLocationsDeps, ":"))
ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
- ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
+ ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
}
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 862f2bb..e39a556 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -70,10 +70,6 @@
// or .aidl files.
Srcs []string `android:"path,arch_variant"`
- // list of directories rooted at the Android.bp file that will
- // be added to the search paths for finding source files when passing package names.
- Local_sourcepaths []string
-
// list of source files that should not be used to build the Java module.
// This is most useful in the arch/multilib variants to remove non-common files
// filegroup or genrule can be included within this property.
@@ -112,13 +108,20 @@
// local files that are used within user customized droiddoc options.
Arg_files []string `android:"path"`
- // user customized droiddoc args.
+ // user customized droiddoc args. Deprecated, use flags instead.
// Available variables for substitution:
//
// $(location <label>): the path to the arg_files with name <label>
// $$: a literal $
Args *string
+ // user customized droiddoc args. Not compatible with property args.
+ // Available variables for substitution:
+ //
+ // $(location <label>): the path to the arg_files with name <label>
+ // $$: a literal $
+ Flags []string
+
// names of the output files used in args that will be generated
Out []string
@@ -168,10 +171,6 @@
// resources output directory under out/soong/.intermediates.
Resourcesoutdir *string
- // if set to true, collect the values used by the Dev tools and
- // write them in files packaged with the SDK. Defaults to false.
- Write_sdk_values *bool
-
// index.html under current module will be copied to docs out dir, if not null.
Static_doc_index_redirect *string `android:"path"`
@@ -182,28 +181,6 @@
// filegroup or genrule can be included within this property.
Knowntags []string `android:"path"`
- // the generated public API filename by Doclava.
- Api_filename *string
-
- // the generated removed API filename by Doclava.
- Removed_api_filename *string
-
- // the generated removed Dex API filename by Doclava.
- Removed_dex_api_filename *string
-
- // if set to false, don't allow droiddoc to generate stubs source files. Defaults to true.
- Create_stubs *bool
-
- Check_api struct {
- Last_released ApiToCheck
-
- Current ApiToCheck
-
- // do not perform API check against Last_released, in the case that both two specified API
- // files by Last_released are modules which don't exist.
- Ignore_missing_latest_api *bool `blueprint:"mutated"`
- }
-
// if set to true, generate docs through Dokka instead of Doclava.
Dokka_enabled *bool
@@ -212,10 +189,10 @@
}
type DroidstubsProperties struct {
- // the generated public API filename by Metalava.
+ // The generated public API filename by Metalava, defaults to <module>_api.txt
Api_filename *string
- // the generated removed API filename by Metalava.
+ // the generated removed API filename by Metalava, defaults to <module>_removed.txt
Removed_api_filename *string
// the generated removed Dex API filename by Metalava.
@@ -385,7 +362,7 @@
argFiles android.Paths
implicits android.Paths
- args string
+ args []string
docZip android.WritablePath
stubsSrcJar android.WritablePath
@@ -443,16 +420,11 @@
func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) {
if ctx.Device() {
sdkDep := decodeSdkDep(ctx, sdkContext(j))
- if sdkDep.useDefaultLibs {
- ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
- if sdkDep.hasFrameworkLibs() {
- ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
- }
- } else if sdkDep.useModule {
+ if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+ ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
}
}
@@ -627,8 +599,8 @@
}
srcFiles = filterHtml(srcFiles)
- flags := j.collectAidlFlags(ctx, deps)
- srcFiles = j.genSources(ctx, srcFiles, flags)
+ aidlFlags := j.collectAidlFlags(ctx, deps)
+ srcFiles = j.genSources(ctx, srcFiles, aidlFlags)
// srcs may depend on some genrule output.
j.srcJars = srcFiles.FilterByExt(".srcjar")
@@ -637,10 +609,9 @@
j.srcFiles = srcFiles.FilterOutByExt(".srcjar")
j.srcFiles = append(j.srcFiles, deps.srcs...)
- if j.properties.Local_sourcepaths == nil && len(j.srcFiles) > 0 {
- j.properties.Local_sourcepaths = append(j.properties.Local_sourcepaths, ".")
+ if len(j.srcFiles) > 0 {
+ j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."})
}
- j.sourcepaths = android.PathsForModuleSrc(ctx, j.properties.Local_sourcepaths)
j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files)
argFilesMap := map[string]string{}
@@ -657,24 +628,38 @@
}
}
- var err error
- j.args, err = android.Expand(String(j.properties.Args), func(name string) (string, error) {
- if strings.HasPrefix(name, "location ") {
- label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
- if paths, ok := argFilesMap[label]; ok {
- return paths, nil
- } else {
- return "", fmt.Errorf("unknown location label %q, expecting one of %q",
- label, strings.Join(argFileLabels, ", "))
- }
- } else if name == "genDir" {
- return android.PathForModuleGen(ctx).String(), nil
- }
- return "", fmt.Errorf("unknown variable '$(%s)'", name)
- })
+ var argsPropertyName string
+ flags := make([]string, 0)
+ if j.properties.Args != nil && j.properties.Flags != nil {
+ ctx.PropertyErrorf("args", "flags is set. Cannot set args")
+ } else if args := proptools.String(j.properties.Args); args != "" {
+ flags = append(flags, args)
+ argsPropertyName = "args"
+ } else {
+ flags = append(flags, j.properties.Flags...)
+ argsPropertyName = "flags"
+ }
- if err != nil {
- ctx.PropertyErrorf("args", "%s", err.Error())
+ for _, flag := range flags {
+ args, err := android.Expand(flag, func(name string) (string, error) {
+ if strings.HasPrefix(name, "location ") {
+ label := strings.TrimSpace(strings.TrimPrefix(name, "location "))
+ if paths, ok := argFilesMap[label]; ok {
+ return paths, nil
+ } else {
+ return "", fmt.Errorf("unknown location label %q, expecting one of %q",
+ label, strings.Join(argFileLabels, ", "))
+ }
+ } else if name == "genDir" {
+ return android.PathForModuleGen(ctx).String(), nil
+ }
+ return "", fmt.Errorf("unknown variable '$(%s)'", name)
+ })
+
+ if err != nil {
+ ctx.PropertyErrorf(argsPropertyName, "%s", err.Error())
+ }
+ j.args = append(j.args, args)
}
return deps
@@ -732,17 +717,7 @@
type Droiddoc struct {
Javadoc
- properties DroiddocProperties
- apiFile android.WritablePath
- privateApiFile android.WritablePath
- removedApiFile android.WritablePath
- removedDexApiFile android.WritablePath
-
- checkCurrentApiTimestamp android.WritablePath
- updateCurrentApiTimestamp android.WritablePath
- checkLastReleasedApiTimestamp android.WritablePath
-
- apiFilePath android.Path
+ properties DroiddocProperties
}
// droiddoc converts .java source files to documentation using doclava or dokka.
@@ -767,17 +742,18 @@
return module
}
-func (d *Droiddoc) ApiFilePath() android.Path {
- return d.apiFilePath
+func (d *Droiddoc) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "", ".docs.zip":
+ return android.Paths{d.Javadoc.docZip}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
}
func (d *Droiddoc) DepsMutator(ctx android.BottomUpMutatorContext) {
d.Javadoc.addDeps(ctx)
- if Bool(d.properties.Check_api.Ignore_missing_latest_api) {
- ignoreMissingModules(ctx, &d.properties.Check_api.Last_released)
- }
-
if String(d.properties.Custom_template) != "" {
ctx.AddDependency(ctx.Module(), droiddocTemplateTag, String(d.properties.Custom_template))
}
@@ -857,37 +833,6 @@
}
}
-func (d *Droiddoc) stubsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, stubsDir android.WritablePath) {
- if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
- String(d.properties.Api_filename) != "" {
-
- d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
- cmd.FlagWithOutput("-api ", d.apiFile)
- d.apiFilePath = d.apiFile
- }
-
- if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
- apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
- String(d.properties.Removed_api_filename) != "" {
- d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
- cmd.FlagWithOutput("-removedApi ", d.removedApiFile)
- }
-
- if String(d.properties.Removed_dex_api_filename) != "" {
- d.removedDexApiFile = android.PathForModuleOut(ctx, String(d.properties.Removed_dex_api_filename))
- cmd.FlagWithOutput("-removedDexApi ", d.removedDexApiFile)
- }
-
- if BoolDefault(d.properties.Create_stubs, true) {
- cmd.FlagWithArg("-stubs ", stubsDir.String())
- }
-
- if Bool(d.properties.Write_sdk_values) {
- cmd.FlagWithArg("-sdkvalues ", android.PathForModuleOut(ctx, "out").String())
- }
-}
-
func (d *Droiddoc) postDoclavaCmds(ctx android.ModuleContext, rule *android.RuleBuilder) {
if String(d.properties.Static_doc_index_redirect) != "" {
staticDocIndexRedirect := android.PathForModuleSrc(ctx, String(d.properties.Static_doc_index_redirect))
@@ -990,22 +935,15 @@
deps := d.Javadoc.collectDeps(ctx)
d.Javadoc.docZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"docs.zip")
- d.Javadoc.stubsSrcJar = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"stubs.srcjar")
jsilver := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "jsilver.jar")
doclava := android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "doclava.jar")
- java8Home := ctx.Config().Getenv("ANDROID_JAVA8_HOME")
- checkApiClasspath := classpath{jsilver, doclava, android.PathForSource(ctx, java8Home, "lib/tools.jar")}
outDir := android.PathForModuleOut(ctx, "out")
srcJarDir := android.PathForModuleOut(ctx, "srcjars")
- stubsDir := android.PathForModuleOut(ctx, "stubsDir")
rule := android.NewRuleBuilder()
- rule.Command().Text("rm -rf").Text(outDir.String()).Text(stubsDir.String())
- rule.Command().Text("mkdir -p").Text(outDir.String()).Text(stubsDir.String())
-
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, d.Javadoc.srcJars)
var cmd *android.RuleBuilderCommand
@@ -1016,9 +954,7 @@
deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths)
}
- d.stubsFlags(ctx, cmd, stubsDir)
-
- cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+ cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles)
if d.properties.Compat_config != nil {
compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config))
@@ -1047,124 +983,11 @@
FlagWithArg("-C ", outDir.String()).
FlagWithArg("-D ", outDir.String())
- rule.Command().
- BuiltTool(ctx, "soong_zip").
- Flag("-write_if_changed").
- Flag("-jar").
- FlagWithOutput("-o ", d.stubsSrcJar).
- FlagWithArg("-C ", stubsDir.String()).
- FlagWithArg("-D ", stubsDir.String())
-
rule.Restat()
zipSyncCleanupCmd(rule, srcJarDir)
rule.Build(pctx, ctx, "javadoc", desc)
-
- if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") &&
- !ctx.Config().IsPdkBuild() {
-
- apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Api_file))
- removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Current.Removed_api_file))
-
- d.checkCurrentApiTimestamp = android.PathForModuleOut(ctx, "check_current_api.timestamp")
-
- rule := android.NewRuleBuilder()
-
- rule.Command().Text("( true")
-
- rule.Command().
- BuiltTool(ctx, "apicheck").
- Flag("-JXmx1024m").
- FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
- OptionalFlag(d.properties.Check_api.Current.Args).
- Input(apiFile).
- Input(d.apiFile).
- Input(removedApiFile).
- Input(d.removedApiFile)
-
- msg := fmt.Sprintf(`\n******************************\n`+
- `You have tried to change the API from what has been previously approved.\n\n`+
- `To make these errors go away, you have two choices:\n`+
- ` 1. You can add '@hide' javadoc comments to the methods, etc. listed in the\n`+
- ` errors above.\n\n`+
- ` 2. You can update current.txt by executing the following command:\n`+
- ` make %s-update-current-api\n\n`+
- ` To submit the revised current.txt to the main Android repository,\n`+
- ` you will need approval.\n`+
- `******************************\n`, ctx.ModuleName())
-
- rule.Command().
- Text("touch").Output(d.checkCurrentApiTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build(pctx, ctx, "doclavaCurrentApiCheck", "check current API")
-
- d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, "update_current_api.timestamp")
-
- // update API rule
- rule = android.NewRuleBuilder()
-
- rule.Command().Text("( true")
-
- rule.Command().
- Text("cp").Flag("-f").
- Input(d.apiFile).Flag(apiFile.String())
-
- rule.Command().
- Text("cp").Flag("-f").
- Input(d.removedApiFile).Flag(removedApiFile.String())
-
- msg = "failed to update public API"
-
- rule.Command().
- Text("touch").Output(d.updateCurrentApiTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build(pctx, ctx, "doclavaCurrentApiUpdate", "update current API")
- }
-
- if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") &&
- !ctx.Config().IsPdkBuild() {
-
- apiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Api_file))
- removedApiFile := android.PathForModuleSrc(ctx, String(d.properties.Check_api.Last_released.Removed_api_file))
-
- d.checkLastReleasedApiTimestamp = android.PathForModuleOut(ctx, "check_last_released_api.timestamp")
-
- rule := android.NewRuleBuilder()
-
- rule.Command().
- Text("(").
- BuiltTool(ctx, "apicheck").
- Flag("-JXmx1024m").
- FlagWithInputList("-Jclasspath\\ ", checkApiClasspath.Paths(), ":").
- OptionalFlag(d.properties.Check_api.Last_released.Args).
- Input(apiFile).
- Input(d.apiFile).
- Input(removedApiFile).
- Input(d.removedApiFile)
-
- msg := `\n******************************\n` +
- `You have tried to change the API from what has been previously released in\n` +
- `an SDK. Please fix the errors listed above.\n` +
- `******************************\n`
-
- rule.Command().
- Text("touch").Output(d.checkLastReleasedApiTimestamp).
- Text(") || (").
- Text("echo").Flag("-e").Flag(`"` + msg + `"`).
- Text("; exit 38").
- Text(")")
-
- rule.Build(pctx, ctx, "doclavaLastApiCheck", "check last API")
- }
}
//
@@ -1298,7 +1121,8 @@
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Api_filename) != "" {
- d.apiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_api.txt")
+ filename := proptools.StringDefault(d.properties.Api_filename, ctx.ModuleName()+"_api.txt")
+ d.apiFile = android.PathForModuleOut(ctx, filename)
cmd.FlagWithOutput("--api ", d.apiFile)
d.apiFilePath = d.apiFile
}
@@ -1306,7 +1130,8 @@
if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") ||
apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") ||
String(d.properties.Removed_api_filename) != "" {
- d.removedApiFile = android.PathForModuleOut(ctx, ctx.ModuleName()+"_removed.txt")
+ filename := proptools.StringDefault(d.properties.Removed_api_filename, ctx.ModuleName()+"_removed.txt")
+ d.removedApiFile = android.PathForModuleOut(ctx, filename)
cmd.FlagWithOutput("--removed-api ", d.removedApiFile)
}
@@ -1335,7 +1160,7 @@
cmd.Flag("--include-annotations")
validatingNullability :=
- strings.Contains(d.Javadoc.args, "--validate-nullability-from-merged-stubs") ||
+ android.InList("--validate-nullability-from-merged-stubs", d.Javadoc.args) ||
String(d.properties.Validate_nullability_from_list) != ""
migratingNullability := String(d.properties.Previous_api) != ""
@@ -1424,7 +1249,7 @@
}
func (d *Droidstubs) apiToXmlFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) {
- if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() && d.apiFile != nil {
+ if Bool(d.properties.Jdiff_enabled) && d.apiFile != nil {
if d.apiFile.String() == "" {
ctx.ModuleErrorf("API signature file has to be specified in Metalava when jdiff is enabled.")
}
@@ -1448,7 +1273,7 @@
// Metalava uses lots of memory, restrict the number of metalava jobs that can run in parallel.
rule.HighMem()
cmd := rule.Command()
- if ctx.Config().IsEnvTrue("RBE_METALAVA") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_METALAVA") {
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "metalava")
execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
@@ -1458,7 +1283,6 @@
labels["shallow"] = "true"
}
inputs := []string{android.PathForOutput(ctx, "host", ctx.Config().PrebuiltOS(), "framework", "metalava.jar").String()}
- inputs = append(inputs, sourcepaths.Strings()...)
if v := ctx.Config().Getenv("RBE_METALAVA_INPUTS"); v != "" {
inputs = append(inputs, strings.Split(v, ",")...)
}
@@ -1553,14 +1377,14 @@
d.apiLevelsAnnotationsFlags(ctx, cmd)
d.apiToXmlFlags(ctx, cmd)
- if strings.Contains(d.Javadoc.args, "--generate-documentation") {
+ if android.InList("--generate-documentation", d.Javadoc.args) {
// Currently Metalava have the ability to invoke Javadoc in a seperate process.
// Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives
// "--generate-documentation" arg. This is not needed when Metalava removes this feature.
- d.Javadoc.args = d.Javadoc.args + " -nodocs "
+ d.Javadoc.args = append(d.Javadoc.args, "-nodocs")
}
- cmd.Flag(d.Javadoc.args).Implicits(d.Javadoc.argFiles)
+ cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles)
for _, o := range d.Javadoc.properties.Out {
cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
}
@@ -1573,7 +1397,7 @@
// Add API lint options.
- if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().IsPdkBuild() {
+ if BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) {
doApiLint = true
newSince := android.OptionalPathForModuleSrc(ctx, d.properties.Check_api.Api_lint.New_since)
@@ -1640,8 +1464,7 @@
// Add "check released" options. (Detect incompatible API changes from the last public release)
- if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") &&
- !ctx.Config().IsPdkBuild() {
+ if apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") {
doCheckReleased = true
if len(d.Javadoc.properties.Out) > 0 {
@@ -1674,7 +1497,7 @@
impRule := android.NewRuleBuilder()
impCmd := impRule.Command()
- // A dummy action that copies the ninja generated rsp file to a new location. This allows us to
+ // An action that copies the ninja generated rsp file to a new location. This allows us to
// add a large number of inputs to a file without exceeding bash command length limits (which
// would happen if we use the WriteFile rule). The cp is needed because RuleBuilder sets the
// rsp file to be ${output}.rsp.
@@ -1718,8 +1541,7 @@
rule.Build(pctx, ctx, "metalava", "metalava merged")
- if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") &&
- !ctx.Config().IsPdkBuild() {
+ if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") {
if len(d.Javadoc.properties.Out) > 0 {
ctx.PropertyErrorf("out", "out property may not be combined with check_api")
@@ -1833,7 +1655,7 @@
rule.Build(pctx, ctx, "nullabilityWarningsCheck", "nullability warnings check")
}
- if Bool(d.properties.Jdiff_enabled) && !ctx.Config().IsPdkBuild() {
+ if Bool(d.properties.Jdiff_enabled) {
if len(d.Javadoc.properties.Out) > 0 {
ctx.PropertyErrorf("out", "out property may not be combined with jdiff")
}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index b5a0217..63b801a 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -23,8 +23,8 @@
)
var hiddenAPIGenerateCSVRule = pctx.AndroidStaticRule("hiddenAPIGenerateCSV", blueprint.RuleParams{
- Command: "${config.Class2Greylist} --stub-api-flags ${stubAPIFlags} $in $outFlag $out",
- CommandDeps: []string{"${config.Class2Greylist}"},
+ Command: "${config.Class2NonSdkList} --stub-api-flags ${stubAPIFlags} $in $outFlag $out",
+ CommandDeps: []string{"${config.Class2NonSdkList}"},
}, "outFlag", "stubAPIFlags")
type hiddenAPI struct {
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 95dd0bb..b6af3bf 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -43,7 +43,7 @@
return hiddenAPISingletonPathsStruct{
flags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-flags.csv"),
index: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-index.csv"),
- metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-greylist.csv"),
+ metadata: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-unsupported.csv"),
stubFlags: android.PathForOutput(ctx, "hiddenapi", "hiddenapi-stub-flags.txt"),
}
}).(hiddenAPISingletonPathsStruct)
@@ -100,7 +100,7 @@
// Add the android.test.base to the set of stubs only if the android.test.base module is on
// the boot jars list as the runtime will only enforce hiddenapi access against modules on
// that list.
- if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ if inList("android.test.base", ctx.Config().BootJars()) && !ctx.Config().AlwaysUsePrebuiltSdks() {
publicStubModules = append(publicStubModules, "android.test.base.stubs")
}
@@ -116,7 +116,7 @@
// Core Platform API stubs
corePlatformStubModules := []string{
- "core.platform.api.stubs",
+ "legacy.core.platform.api.stubs",
}
// Allow products to define their own stubs for custom product jars that apps can use.
@@ -147,7 +147,7 @@
name := ctx.ModuleName(module)
for moduleList, pathList := range moduleListToPathList {
if i := android.IndexList(name, *moduleList); i != -1 {
- pathList[i] = j.DexJar()
+ pathList[i] = j.DexJarBuildPath()
}
}
}
@@ -163,6 +163,7 @@
return
}
}
+
bootDexJars = append(bootDexJars, jar)
}
}
@@ -217,7 +218,7 @@
}
// flagsRule creates a rule to build hiddenapi-flags.csv out of flags.csv files generated for boot image modules and
-// the greylists.
+// the unsupported API.
func flagsRule(ctx android.SingletonContext) android.Path {
var flagsCSV android.Paths
var greylistRemovedApis android.Paths
@@ -256,19 +257,19 @@
Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")).
FlagWithInput("--csv ", stubFlags).
Inputs(flagsCSV).
- FlagWithInput("--greylist ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist.txt")).
- FlagWithInput("--greylist-ignore-conflicts ", combinedRemovedApis).
- FlagWithInput("--greylist-max-q ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-q.txt")).
- FlagWithInput("--greylist-max-p ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-p.txt")).
- FlagWithInput("--greylist-max-o-ignore-conflicts ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-max-o.txt")).
- FlagWithInput("--blacklist ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blacklist.txt")).
- FlagWithInput("--greylist-packages ",
- android.PathForSource(ctx, "frameworks/base/config/hiddenapi-greylist-packages.txt")).
+ FlagWithInput("--unsupported ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported.txt")).
+ FlagWithInput("--unsupported-ignore-conflicts ", combinedRemovedApis).
+ FlagWithInput("--max-target-q ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-q.txt")).
+ FlagWithInput("--max-target-p ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-p.txt")).
+ FlagWithInput("--max-target-o-ignore-conflicts ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-max-target-o.txt")).
+ FlagWithInput("--blocked ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-force-blocked.txt")).
+ FlagWithInput("--unsupported-packages ",
+ android.PathForSource(ctx, "frameworks/base/config/hiddenapi-unsupported-packages.txt")).
FlagWithOutput("--output ", tempPath)
commitChangeForRestat(rule, tempPath, outputPath)
@@ -293,7 +294,7 @@
return outputPath
}
-// metadataRule creates a rule to build hiddenapi-greylist.csv out of the metadata.csv files generated for boot image
+// metadataRule creates a rule to build hiddenapi-unsupported.csv out of the metadata.csv files generated for boot image
// modules.
func metadataRule(ctx android.SingletonContext) android.Path {
var metadataCSV android.Paths
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
new file mode 100644
index 0000000..bcca93a
--- /dev/null
+++ b/java/hiddenapi_singleton_test.go
@@ -0,0 +1,136 @@
+// Copyright 2020 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 java
+
+import (
+ "android/soong/android"
+ "strings"
+ "testing"
+)
+
+func testConfigWithBootJars(bp string, bootJars []string) android.Config {
+ config := testConfig(nil, bp, nil)
+ config.TestProductVariables.BootJars = bootJars
+ return config
+}
+
+func testContextWithHiddenAPI() *android.TestContext {
+ ctx := testContext()
+ ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+ return ctx
+}
+
+func testHiddenAPI(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) {
+ t.Helper()
+
+ config := testConfigWithBootJars(bp, bootJars)
+ ctx := testContextWithHiddenAPI()
+
+ run(t, ctx, config)
+
+ return ctx, config
+}
+
+func TestHiddenAPISingleton(t *testing.T) {
+ ctx, _ := testHiddenAPI(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+ `, []string{":foo"})
+
+ hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+ want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+ }
+}
+
+func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
+ ctx, _ := testHiddenAPI(t, `
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ }
+ `, []string{":foo"})
+
+ hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+ want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
+ }
+}
+
+func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
+ ctx, _ := testHiddenAPI(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: false,
+ }
+ `, []string{":foo"})
+
+ hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+ fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+ }
+
+ prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
+ if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+ t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+ }
+}
+
+func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
+ ctx, _ := testHiddenAPI(t, `
+ java_library {
+ name: "foo",
+ srcs: ["a.java"],
+ compile_dex: true,
+ }
+
+ java_import {
+ name: "foo",
+ jars: ["a.jar"],
+ compile_dex: true,
+ prefer: true,
+ }
+ `, []string{":foo"})
+
+ hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+ prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar"
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
+ }
+
+ fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
+ if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
+ t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
+ }
+}
diff --git a/java/java.go b/java/java.go
index 486404c..d67e9e0 100644
--- a/java/java.go
+++ b/java/java.go
@@ -29,6 +29,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java/config"
"android/soong/tradefed"
)
@@ -44,7 +45,7 @@
PropertyName: "java_libs",
},
func(j *Library) android.Path {
- implementationJars := j.ImplementationJars()
+ implementationJars := j.ImplementationAndResourcesJars()
if len(implementationJars) != 1 {
panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
}
@@ -140,10 +141,15 @@
// Findbugs
type CompilerProperties struct {
- // list of source files used to compile the Java module. May be .java, .logtags, .proto,
+ // list of source files used to compile the Java module. May be .java, .kt, .logtags, .proto,
// or .aidl files.
Srcs []string `android:"path,arch_variant"`
+ // list Kotlin of source files containing Kotlin code that should be treated as common code in
+ // a codebase that supports Kotlin multiplatform. See
+ // https://kotlinlang.org/docs/reference/multiplatform.html. May be only be .kt files.
+ Common_srcs []string `android:"path,arch_variant"`
+
// list of source files that should not be used to build the Java module.
// This is most useful in the arch/multilib variants to remove non-common files
Exclude_srcs []string `android:"path,arch_variant"`
@@ -410,8 +416,8 @@
// manifest file to use instead of properties.Manifest
overrideManifest android.OptionalPath
- // list of SDK lib names that this java module is exporting
- exportedSdkLibs []string
+ // map of SDK libs exported by this java module to their build and install paths
+ exportedSdkLibs dexpreopt.LibraryPaths
// list of plugins that this java module is exporting
exportedPluginJars android.Paths
@@ -435,18 +441,23 @@
hiddenAPI
dexer
dexpreopter
+ usesLibrary
linter
// list of the xref extraction files
kytheFiles android.Paths
distFiles android.TaggedDistFiles
+
+ // Collect the module directory for IDE info in java/jdeps.go.
+ modulePaths []string
}
func (j *Module) addHostProperties() {
j.AddProperties(
&j.properties,
&j.protoProperties,
+ &j.usesLibraryProperties,
)
}
@@ -484,13 +495,19 @@
ImplementationAndResourcesJars() android.Paths
}
+// Provides build path and install path to DEX jars.
+type UsesLibraryDependency interface {
+ DexJarBuildPath() android.Path
+ DexJarInstallPath() android.Path
+}
+
type Dependency interface {
ApexDependency
+ UsesLibraryDependency
ImplementationJars() android.Paths
ResourceJars() android.Paths
- DexJar() android.Path
AidlIncludeDirs() android.Paths
- ExportedSdkLibs() []string
+ ExportedSdkLibs() dexpreopt.LibraryPaths
ExportedPlugins() (android.Paths, []string)
SrcJarArgs() ([]string, android.Paths)
BaseModuleName() string
@@ -506,7 +523,20 @@
}
func InitJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
- android.InitAndroidArchModule(module, hod, android.MultilibCommon)
+ initJavaModule(module, hod, false)
+}
+
+func InitJavaModuleMultiTargets(module android.DefaultableModule, hod android.HostOrDeviceSupported) {
+ initJavaModule(module, hod, true)
+}
+
+func initJavaModule(module android.DefaultableModule, hod android.HostOrDeviceSupported, multiTargets bool) {
+ multilib := android.MultilibCommon
+ if multiTargets {
+ android.InitAndroidMultiTargetsArchModule(module, hod, multilib)
+ } else {
+ android.InitAndroidArchModule(module, hod, multilib)
+ }
android.InitDefaultableModule(module)
}
@@ -525,6 +555,7 @@
}
var (
+ dataNativeBinsTag = dependencyTag{name: "dataNativeBins"}
staticLibTag = dependencyTag{name: "staticlib"}
libTag = dependencyTag{name: "javalib"}
java9LibTag = dependencyTag{name: "java9lib"}
@@ -533,7 +564,6 @@
bootClasspathTag = dependencyTag{name: "bootclasspath"}
systemModulesTag = dependencyTag{name: "system modules"}
frameworkResTag = dependencyTag{name: "framework-res"}
- frameworkApkTag = dependencyTag{name: "framework-apk"}
kotlinStdlibTag = dependencyTag{name: "kotlin-stdlib"}
kotlinAnnotationsTag = dependencyTag{name: "kotlin-annotations"}
proguardRaiseTag = dependencyTag{name: "proguard-raise"}
@@ -552,7 +582,7 @@
}
type sdkDep struct {
- useModule, useFiles, useDefaultLibs, invalidVersion bool
+ useModule, useFiles, invalidVersion bool
// The modules that will be added to the bootclasspath when targeting 1.8 or lower
bootclasspath []string
@@ -561,7 +591,11 @@
// modules are to be used.
systemModules string
+ // The modules that will be added to the classpath regardless of the Java language level targeted
+ classpath []string
+
// The modules that will be added ot the classpath when targeting 1.9 or higher
+ // (normally these will be on the bootclasspath when targeting 1.8 or lower)
java9Classpath []string
frameworkResModule string
@@ -600,6 +634,21 @@
ctx.Config().UnbundledBuild())
}
+func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool {
+ // Force enable the instrumentation for java code that is built for APEXes ...
+ // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
+ // doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
+ isJacocoAgent := ctx.ModuleName() == "jacocoagent"
+ if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+ if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
+ return true
+ } else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+ return true
+ }
+ }
+ return false
+}
+
func (j *Module) sdkVersion() sdkSpec {
return sdkSpecFrom(String(j.deviceProperties.Sdk_version))
}
@@ -638,18 +687,15 @@
func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) {
sdkDep := decodeSdkDep(ctx, sdkContext)
- if sdkDep.useDefaultLibs {
- ctx.AddVariationDependencies(nil, bootClasspathTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, systemModulesTag, config.DefaultSystemModules)
- if sdkDep.hasFrameworkLibs() {
- ctx.AddVariationDependencies(nil, libTag, config.DefaultLibraries...)
- }
- } else if sdkDep.useModule {
+ if sdkDep.useModule {
ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...)
ctx.AddVariationDependencies(nil, java9LibTag, sdkDep.java9Classpath...)
+ ctx.AddVariationDependencies(nil, libTag, sdkDep.classpath...)
if d.effectiveOptimizeEnabled() && sdkDep.hasStandardLibs() {
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultBootclasspathLibraries...)
- ctx.AddVariationDependencies(nil, proguardRaiseTag, config.DefaultLibraries...)
+ ctx.AddVariationDependencies(nil, proguardRaiseTag, config.LegacyCorePlatformBootclasspathLibraries...)
+ }
+ if d.effectiveOptimizeEnabled() && sdkDep.hasFrameworkLibs() {
+ ctx.AddVariationDependencies(nil, proguardRaiseTag, config.FrameworkLibraries...)
}
}
if sdkDep.systemModules != "" {
@@ -662,12 +708,6 @@
j.linter.deps(ctx)
sdkDeps(ctx, sdkContext(j), j.dexer)
-
- if ctx.ModuleName() == "android_stubs_current" ||
- ctx.ModuleName() == "android_system_stubs_current" ||
- ctx.ModuleName() == "android_test_stubs_current" {
- ctx.AddVariationDependencies(nil, frameworkApkTag, "framework-res")
- }
}
syspropPublicStubs := syspropPublicStubs(ctx.Config())
@@ -834,8 +874,9 @@
func (m *Module) getLinkType(name string) (ret linkType, stubs bool) {
switch name {
- case "core.current.stubs", "core.platform.api.stubs", "stub-annotations",
- "private-stub-annotations-jar", "core-lambda-stubs", "core-generated-annotation-stubs":
+ case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+ "stub-annotations", "private-stub-annotations-jar",
+ "core-lambda-stubs", "core-generated-annotation-stubs":
return javaCore, true
case "android_stubs_current":
return javaSdk, true
@@ -941,12 +982,6 @@
}
}
- // If this is a component library (stubs, etc.) for a java_sdk_library then
- // add the name of that java_sdk_library to the exported sdk libs to make sure
- // that, if necessary, a <uses-library> element for that java_sdk_library is
- // added to the Android manifest.
- j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
-
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -966,7 +1001,7 @@
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...)
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath())
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@@ -977,7 +1012,7 @@
case libTag, instrumentationForTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@@ -989,7 +1024,7 @@
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1016,18 +1051,6 @@
} else {
ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
}
- case frameworkApkTag:
- if ctx.ModuleName() == "android_stubs_current" ||
- ctx.ModuleName() == "android_system_stubs_current" ||
- ctx.ModuleName() == "android_test_stubs_current" {
- // framework stubs.jar need to depend on framework-res.apk, in order to pull the
- // resource files out of there for aapt.
- //
- // Normally the package rule runs aapt, which includes the resource,
- // but we're not running that in our package rule so just copy in the
- // resource files here.
- deps.staticResourceJars = append(deps.staticResourceJars, dep.(*AndroidApp).exportPackage)
- }
case kotlinStdlibTag:
deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
case kotlinAnnotationsTag:
@@ -1064,8 +1087,6 @@
}
})
- j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
-
return deps
}
@@ -1145,9 +1166,9 @@
if flags.javaVersion.usesJavaModules() {
javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
}
- if ctx.Config().MinimizeJavaDebugInfo() {
- // Override the -g flag passed globally to remove local variable debug info to reduce
- // disk and memory usage.
+ if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
+ // For non-host binaries, override the -g flag passed globally to remove
+ // local variable debug info to reduce disk and memory usage.
javacFlags = append(javacFlags, "-g:source,lines")
}
javacFlags = append(javacFlags, "-Xlint:-dep-ann")
@@ -1243,6 +1264,11 @@
flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
}
+ kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, nil)
+ if len(kotlinCommonSrcFiles.FilterOutByExt(".kt")) > 0 {
+ ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files")
+ }
+
srcFiles = j.genSources(ctx, srcFiles, flags)
srcJars := srcFiles.FilterByExt(".srcjar")
@@ -1296,6 +1322,7 @@
// Collect .kt files for AIDEGen
j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, srcFiles.FilterByExt(".kt").Strings()...)
+ j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...)
flags.classpath = append(flags.classpath, deps.kotlinStdlib...)
flags.classpath = append(flags.classpath, deps.kotlinAnnotations...)
@@ -1307,7 +1334,7 @@
// Use kapt for annotation processing
kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar")
kaptResJar := android.PathForModuleOut(ctx, "kapt", "kapt-res.jar")
- kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, srcJars, flags)
+ kotlinKapt(ctx, kaptSrcJar, kaptResJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
srcJars = append(srcJars, kaptSrcJar)
kotlinJars = append(kotlinJars, kaptResJar)
// Disable annotation processing in javac, it's already been handled by kapt
@@ -1316,7 +1343,7 @@
}
kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName)
- kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, srcJars, flags)
+ kotlinCompile(ctx, kotlinJar, kotlinSrcFiles, kotlinCommonSrcFiles, srcJars, flags)
if ctx.Failed() {
return
}
@@ -1466,7 +1493,7 @@
args := map[string]string{
"jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
}
- if ctx.Config().IsEnvTrue("RBE_ZIP") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_ZIP") {
rule = zipRE
args["implicits"] = strings.Join(services.Strings(), ",")
}
@@ -1542,11 +1569,7 @@
j.headerJarFile = j.implementationJarFile
}
- // Force enable the instrumentation for java code that is built for APEXes ...
- // except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
- // doesn't make sense)
- isJacocoAgent := ctx.ModuleName() == "jacocoagent"
- if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+ if j.shouldInstrumentInApex(ctx) {
j.properties.Instrument = true
}
@@ -1591,6 +1614,9 @@
configurationName := j.ConfigurationName()
primary := configurationName == ctx.ModuleName()
+ // If the prebuilt is being used rather than the from source, skip this
+ // module to prevent duplicated classes
+ primary = primary && !j.IsReplacedByPrebuilt()
// Hidden API CSV generation and dex encoding
dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
@@ -1646,7 +1672,7 @@
j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion())
j.linter.javaLanguageLevel = flags.javaVersion.String()
j.linter.kotlinLanguageLevel = "1.3"
- if j.ApexName() != "" && ctx.Config().UnbundledBuild() {
+ if j.ApexVariationName() != "" && ctx.Config().UnbundledBuildApps() {
j.linter.buildModuleReportZip = true
}
j.linter.lint(ctx)
@@ -1777,10 +1803,14 @@
return android.Paths{j.implementationJarFile}
}
-func (j *Module) DexJar() android.Path {
+func (j *Module) DexJarBuildPath() android.Path {
return j.dexJarFile
}
+func (j *Module) DexJarInstallPath() android.Path {
+ return j.installFile
+}
+
func (j *Module) ResourceJars() android.Paths {
if j.resourceJar == nil {
return nil
@@ -1800,8 +1830,7 @@
return j.exportAidlIncludeDirs
}
-func (j *Module) ExportedSdkLibs() []string {
- // exportedSdkLibs is type []string
+func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths {
return j.exportedSdkLibs
}
@@ -1828,6 +1857,7 @@
if j.expandJarjarRules != nil {
dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String())
}
+ dpInfo.Paths = append(dpInfo.Paths, j.modulePaths...)
}
func (j *Module) CompilerDeps() []string {
@@ -1846,6 +1876,24 @@
return j.depIsInSameApex(ctx, dep)
}
+func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ sdkSpec := j.minSdkVersion()
+ if !sdkSpec.specified() {
+ return fmt.Errorf("min_sdk_version is not specified")
+ }
+ if sdkSpec.kind == sdkCore {
+ return nil
+ }
+ ver, err := sdkSpec.effectiveVersion(ctx)
+ if err != nil {
+ return err
+ }
+ if int(ver) > sdkVersion {
+ return fmt.Errorf("newer SDK(%v)", ver)
+ }
+ return nil
+}
+
func (j *Module) Stem() string {
return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
}
@@ -1915,8 +1963,12 @@
j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
}
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
+ j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
j.compile(ctx, nil)
+ // Collect the module directory for IDE info in java/jdeps.go.
+ j.modulePaths = append(j.modulePaths, ctx.ModuleDir())
+
exclusivelyForApex := android.InAnyApex(ctx.ModuleName()) && !j.IsForPlatform()
if (Bool(j.properties.Installable) || ctx.Host()) && !exclusivelyForApex {
var extraInstallDeps android.Paths
@@ -1927,6 +1979,17 @@
j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
+ // If this is a component library (stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath())
+
+ // A non-SDK library may provide a <uses-library> (the name may be different from the module name).
+ if lib := proptools.String(j.usesLibraryProperties.Provides_uses_lib); lib != "" {
+ j.exportedSdkLibs.AddLibraryPath(ctx, lib, j.DexJarBuildPath(), j.DexJarInstallPath())
+ }
+
j.distFiles = j.GenerateTaggedDistFiles(ctx)
}
@@ -2079,6 +2142,12 @@
// Java Tests
//
+// Test option struct.
+type TestOptions struct {
+ // a list of extra test configuration files that should be installed with the module.
+ Extra_test_configs []string `android:"path,arch_variant"`
+}
+
type testProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
@@ -2104,6 +2173,14 @@
// Add parameterized mainline modules to auto generated test config. The options will be
// handled by TradeFed to do downloading and installing the specified modules on the device.
Test_mainline_modules []string
+
+ // Test options.
+ Test_options TestOptions
+}
+
+type hostTestProperties struct {
+ // list of native binary modules that should be installed alongside the test
+ Data_native_bins []string `android:"arch_variant"`
}
type testHelperLibraryProperties struct {
@@ -2127,8 +2204,15 @@
testProperties testProperties
- testConfig android.Path
- data android.Paths
+ testConfig android.Path
+ extraTestConfigs android.Paths
+ data android.Paths
+}
+
+type TestHost struct {
+ Test
+
+ testHostProperties hostTestProperties
}
type TestHelperLibrary struct {
@@ -2146,11 +2230,28 @@
dexJarFile android.Path
}
+func (j *TestHost) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if len(j.testHostProperties.Data_native_bins) > 0 {
+ for _, target := range ctx.MultiTargets() {
+ ctx.AddVariationDependencies(target.Variations(), dataNativeBinsTag, j.testHostProperties.Data_native_bins...)
+ }
+ }
+
+ j.deps(ctx)
+}
+
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
j.testProperties.Test_suites, j.testProperties.Auto_gen_config)
+
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
+ j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs)
+
+ ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) {
+ j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
+ })
+
j.Library.GenerateAndroidBuildActions(ctx)
}
@@ -2291,14 +2392,15 @@
// A java_test_host has a single variant that produces a `.jar` file containing `.class` files that were
// compiled against the host bootclasspath.
func TestHostFactory() android.Module {
- module := &Test{}
+ module := &TestHost{}
module.addHostProperties()
module.AddProperties(&module.testProperties)
+ module.AddProperties(&module.testHostProperties)
module.Module.properties.Installable = proptools.BoolPtr(true)
- InitJavaModule(module, android.HostSupported)
+ InitJavaModuleMultiTargets(module, android.HostSupported)
return module
}
@@ -2430,6 +2532,12 @@
// set the name of the output
Stem *string
+
+ Aidl struct {
+ // directories that should be added as include directories for any aidl sources of modules
+ // that depend on this module, as well as to aidl for this module.
+ Export_include_dirs []string
+ }
}
type Import struct {
@@ -2451,7 +2559,8 @@
dexJarFile android.Path
combinedClasspathFile android.Path
- exportedSdkLibs []string
+ exportedSdkLibs dexpreopt.LibraryPaths
+ exportAidlIncludeDirs android.Paths
}
func (j *Import) sdkVersion() sdkSpec {
@@ -2519,12 +2628,7 @@
TransformJetifier(ctx, outputFile, inputFile)
}
j.combinedClasspathFile = outputFile
-
- // If this is a component library (impl, stubs, etc.) for a java_sdk_library then
- // add the name of that java_sdk_library to the exported sdk libs to make sure
- // that, if necessary, a <uses-library> element for that java_sdk_library is
- // added to the Android manifest.
- j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+ j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
var flags javaBuilderFlags
@@ -2538,7 +2642,7 @@
case libTag, staticLibTag:
flags.classpath = append(flags.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
case bootClasspathTag:
flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
}
@@ -2547,14 +2651,14 @@
case libTag:
flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+ j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
}
}
})
- j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
+ var installFile android.Path
if Bool(j.properties.Installable) {
- ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+ installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
jarName, outputFile)
}
@@ -2562,7 +2666,9 @@
// add the name of that java_sdk_library to the exported sdk libs to make sure
// that, if necessary, a <uses-library> element for that java_sdk_library is
// added to the Android manifest.
- j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile)
+
+ j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
if ctx.Device() && Bool(j.dexProperties.Compile_dex) {
sdkDep := decodeSdkDep(ctx, sdkContext(j))
@@ -2581,6 +2687,13 @@
return
}
+ configurationName := j.BaseModuleName()
+ primary := j.Prebuilt().UsePrebuilt()
+
+ // Hidden API CSV generation and dex encoding
+ dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile,
+ proptools.Bool(j.dexProperties.Uncompress_dex))
+
j.dexJarFile = dexOutputFile
}
}
@@ -2612,15 +2725,19 @@
return android.Paths{j.combinedClasspathFile}
}
-func (j *Import) DexJar() android.Path {
+func (j *Import) DexJarBuildPath() android.Path {
return j.dexJarFile
}
-func (j *Import) AidlIncludeDirs() android.Paths {
+func (j *Import) DexJarInstallPath() android.Path {
return nil
}
-func (j *Import) ExportedSdkLibs() []string {
+func (j *Import) AidlIncludeDirs() android.Paths {
+ return j.exportAidlIncludeDirs
+}
+
+func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths {
return j.exportedSdkLibs
}
@@ -2636,6 +2753,11 @@
return j.depIsInSameApex(ctx, dep)
}
+func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // Do not check for prebuilts against the min_sdk_version of enclosing APEX
+ return nil
+}
+
// Add compile time check for interface implementation
var _ android.IDEInfo = (*Import)(nil)
var _ android.IDECustomizedModuleName = (*Import)(nil)
@@ -2810,10 +2932,15 @@
}
}
-func (j *DexImport) DexJar() android.Path {
+func (j *DexImport) DexJarBuildPath() android.Path {
return j.dexJarFile
}
+func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // we don't check prebuilt modules for sdk_version
+ return nil
+}
+
// dex_import imports a `.jar` file containing classes.dex files.
//
// A dex_import module cannot be used as a dependency of a java_* or android_* module, it can only be installed
@@ -2887,6 +3014,7 @@
&appProperties{},
&appTestProperties{},
&overridableAppProperties{},
+ &testProperties{},
&ImportProperties{},
&AARImportProperties{},
&sdkLibraryProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 266cada..9e63577 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,7 +20,6 @@
"path/filepath"
"reflect"
"regexp"
- "sort"
"strconv"
"strings"
"testing"
@@ -31,6 +30,7 @@
"android/soong/cc"
"android/soong/dexpreopt"
"android/soong/genrule"
+ "android/soong/python"
)
var buildDir string
@@ -81,17 +81,22 @@
ctx.RegisterModuleType("java_plugin", PluginFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
+ ctx.RegisterModuleType("python_binary_host", python.PythonBinaryHostFactory)
RegisterDocsBuildComponents(ctx)
RegisterStubsBuildComponents(ctx)
RegisterSdkLibraryBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
RegisterPrebuiltApisBuildComponents(ctx)
+ ctx.PreDepsMutators(python.RegisterPythonPreDepsMutators)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.RegisterPreSingletonType("overlay", android.SingletonFactoryAdaptor(OverlaySingletonFactory))
ctx.RegisterPreSingletonType("sdk_versions", android.SingletonFactoryAdaptor(sdkPreSingletonFactory))
+ android.RegisterPrebuiltMutators(ctx)
+
// Register module types and mutators from cc needed for JNI testing
cc.RegisterRequiredBuildComponentsForTest(ctx)
@@ -466,7 +471,41 @@
t.Errorf("expected binary wrapper implicits [%q], got %v",
barJar, barWrapperDeps)
}
+}
+func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
+ bp := `
+ java_library {
+ name: "target_library",
+ srcs: ["a.java"],
+ }
+
+ java_binary_host {
+ name: "host_binary",
+ srcs: ["b.java"],
+ }
+ `
+ config := testConfig(nil, bp, nil)
+ config.TestProductVariables.MinimizeJavaDebugInfo = proptools.BoolPtr(true)
+
+ ctx, _ := testJavaWithConfig(t, config)
+
+ // first, check that the -g flag is added to target modules
+ targetLibrary := ctx.ModuleForTests("target_library", "android_common")
+ targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
+ if !strings.Contains(targetJavaFlags, "-g:source,lines") {
+ t.Errorf("target library javac flags %v should contain "+
+ "-g:source,lines override with MinimizeJavaDebugInfo", targetJavaFlags)
+ }
+
+ // check that -g is not overridden for host modules
+ buildOS := android.BuildOs.String()
+ hostBinary := ctx.ModuleForTests("host_binary", buildOS+"_common")
+ hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
+ if strings.Contains(hostJavaFlags, "-g:source,lines") {
+ t.Errorf("java_binary_host javac flags %v should not have "+
+ "-g:source,lines override with MinimizeJavaDebugInfo", hostJavaFlags)
+ }
}
func TestPrebuilts(t *testing.T) {
@@ -536,7 +575,7 @@
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barJar.String())
}
- barDexJar := barModule.Module().(*Import).DexJar()
+ barDexJar := barModule.Module().(*Import).DexJarBuildPath()
if barDexJar != nil {
t.Errorf("bar dex jar build path expected to be nil, got %q", barDexJar)
}
@@ -549,7 +588,7 @@
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, bazJar.String())
}
- bazDexJar := bazModule.Module().(*Import).DexJar().String()
+ bazDexJar := bazModule.Module().(*Import).DexJarBuildPath().String()
expectedDexJar := buildDir + "/.intermediates/baz/android_common/dex/baz.jar"
if bazDexJar != expectedDexJar {
t.Errorf("baz dex jar build path expected %q, got %q", expectedDexJar, bazDexJar)
@@ -611,6 +650,89 @@
t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
}
}
+
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `prebuilt_sdklib.stubs.source.test`,
+ `prebuilt_sdklib.stubs.system`,
+ `prebuilt_sdklib.stubs.test`,
+ })
+}
+
+func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ // This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
+ // dependency is added after prebuilts may have been renamed and so has to use
+ // the renamed name.
+ `sdklib.xml`,
+ })
+}
+
+func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+
+ java_sdk_library_import {
+ name: "sdklib",
+ prefer: true,
+ public: {
+ jars: ["a.jar"],
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `prebuilt_sdklib`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+
+ CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ `prebuilt_sdklib.stubs`,
+ `sdklib.impl`,
+ `sdklib.xml`,
+ })
}
func TestDefaults(t *testing.T) {
@@ -975,16 +1097,26 @@
srcs: ["bar-doc/IBar.aidl"],
path: "bar-doc",
}
- droiddoc {
- name: "bar-doc",
+ droidstubs {
+ name: "bar-stubs",
srcs: [
"bar-doc/a.java",
- "bar-doc/IFoo.aidl",
- ":bar-doc-aidl-srcs",
],
exclude_srcs: [
"bar-doc/b.java"
],
+ api_levels_annotations_dirs: [
+ "droiddoc-templates-sdk",
+ ],
+ api_levels_annotations_enabled: true,
+ }
+ droiddoc {
+ name: "bar-doc",
+ srcs: [
+ ":bar-stubs",
+ "bar-doc/IFoo.aidl",
+ ":bar-doc-aidl-srcs",
+ ],
custom_template: "droiddoc-templates-sdk",
hdf: [
"android.whichdoc offline",
@@ -994,25 +1126,36 @@
],
proofread_file: "libcore-proofread.txt",
todo_file: "libcore-docs-todo.html",
- args: "-offlinemode -title \"libcore\"",
+ flags: ["-offlinemode -title \"libcore\""],
}
`,
map[string][]byte{
"bar-doc/a.java": nil,
"bar-doc/b.java": nil,
})
-
- barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc")
- var javaSrcs []string
- for _, i := range barDoc.Inputs {
- javaSrcs = append(javaSrcs, i.Base())
+ barStubs := ctx.ModuleForTests("bar-stubs", "android_common")
+ barStubsOutputs, err := barStubs.Module().(*Droidstubs).OutputFiles("")
+ if err != nil {
+ t.Errorf("Unexpected error %q retrieving \"bar-stubs\" output file", err)
}
- if len(javaSrcs) != 1 || javaSrcs[0] != "a.java" {
- t.Errorf("inputs of bar-doc must be []string{\"a.java\"}, but was %#v.", javaSrcs)
+ if len(barStubsOutputs) != 1 {
+ t.Errorf("Expected one output from \"bar-stubs\" got %s", barStubsOutputs)
}
- aidl := ctx.ModuleForTests("bar-doc", "android_common").Rule("aidl")
- if g, w := barDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
+ barStubsOutput := barStubsOutputs[0]
+ barDoc := ctx.ModuleForTests("bar-doc", "android_common")
+ javaDoc := barDoc.Rule("javadoc")
+ if g, w := javaDoc.Implicits.Strings(), barStubsOutput.String(); !inList(w, g) {
+ t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
+ }
+
+ expected := "-sourcepath " + buildDir + "/.intermediates/bar-doc/android_common/srcjars "
+ if !strings.Contains(javaDoc.RuleParams.Command, expected) {
+ t.Errorf("bar-doc command does not contain flag %q, but should\n%q", expected, javaDoc.RuleParams.Command)
+ }
+
+ aidl := barDoc.Rule("aidl")
+ if g, w := javaDoc.Implicits.Strings(), aidl.Output.String(); !inList(w, g) {
t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g)
}
@@ -1021,6 +1164,52 @@
}
}
+func TestDroiddocArgsAndFlagsCausesError(t *testing.T) {
+ testJavaError(t, "flags is set. Cannot set args", `
+ droiddoc_exported_dir {
+ name: "droiddoc-templates-sdk",
+ path: ".",
+ }
+ filegroup {
+ name: "bar-doc-aidl-srcs",
+ srcs: ["bar-doc/IBar.aidl"],
+ path: "bar-doc",
+ }
+ droidstubs {
+ name: "bar-stubs",
+ srcs: [
+ "bar-doc/a.java",
+ ],
+ exclude_srcs: [
+ "bar-doc/b.java"
+ ],
+ api_levels_annotations_dirs: [
+ "droiddoc-templates-sdk",
+ ],
+ api_levels_annotations_enabled: true,
+ }
+ droiddoc {
+ name: "bar-doc",
+ srcs: [
+ ":bar-stubs",
+ "bar-doc/IFoo.aidl",
+ ":bar-doc-aidl-srcs",
+ ],
+ custom_template: "droiddoc-templates-sdk",
+ hdf: [
+ "android.whichdoc offline",
+ ],
+ knowntags: [
+ "bar-doc/known_oj_tags.txt",
+ ],
+ proofread_file: "libcore-proofread.txt",
+ todo_file: "libcore-docs-todo.html",
+ flags: ["-offlinemode -title \"libcore\""],
+ args: "-offlinemode -title \"libcore\"",
+ }
+ `)
+}
+
func TestDroidstubs(t *testing.T) {
ctx, _ := testJavaWithFS(t, `
droiddoc_exported_dir {
@@ -1347,8 +1536,7 @@
// test if baz has exported SDK lib names foo and bar to qux
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
- sdkLibs := quxLib.ExportedSdkLibs()
- sort.Strings(sdkLibs)
+ sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs())
if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
t.Errorf("qux should export %q but exports %q", w, sdkLibs)
}
@@ -1416,6 +1604,28 @@
`)
}
+func TestJavaSdkLibrary_Deps(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_sdk_library {
+ name: "sdklib",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "none",
+ public: {
+ enabled: true,
+ },
+ }
+ `)
+
+ CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ `dex2oatd`,
+ `sdklib.impl`,
+ `sdklib.stubs`,
+ `sdklib.stubs.source`,
+ `sdklib.xml`,
+ })
+}
+
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
testJava(t, `
java_sdk_library_import {
@@ -1879,3 +2089,52 @@
t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath)
}
}
+
+func TestAidlExportIncludeDirsFromImports(t *testing.T) {
+ ctx, _ := testJava(t, `
+ java_library {
+ name: "foo",
+ srcs: ["aidl/foo/IFoo.aidl"],
+ libs: ["bar"],
+ }
+
+ java_import {
+ name: "bar",
+ jars: ["a.jar"],
+ aidl: {
+ export_include_dirs: ["aidl/bar"],
+ },
+ }
+ `)
+
+ aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command
+ expectedAidlFlag := "-Iaidl/bar"
+ if !strings.Contains(aidlCommand, expectedAidlFlag) {
+ t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag)
+ }
+}
+
+func TestDataNativeBinaries(t *testing.T) {
+ ctx, config := testJava(t, `
+ java_test_host {
+ name: "foo",
+ srcs: ["a.java"],
+ data_native_bins: ["bin"]
+ }
+
+ python_binary_host {
+ name: "bin",
+ srcs: ["bin.py"],
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+
+ test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost)
+ entries := android.AndroidMkEntriesForTest(t, config, "", test)[0]
+ expected := []string{buildDir + "/.intermediates/bin/" + buildOS + "_x86_64_PY3/bin:bin"}
+ actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"]
+ if !reflect.DeepEqual(expected, actual) {
+ t.Errorf("Unexpected test data - expected: %q, actual: %q", expected, actual)
+ }
+}
diff --git a/java/jdeps.go b/java/jdeps.go
index 4f636a5..2b5ee74 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -75,6 +75,7 @@
dpInfo.Jarjar_rules = android.FirstUniqueStrings(dpInfo.Jarjar_rules)
dpInfo.Jars = android.FirstUniqueStrings(dpInfo.Jars)
dpInfo.SrcJars = android.FirstUniqueStrings(dpInfo.SrcJars)
+ dpInfo.Paths = android.FirstUniqueStrings(dpInfo.Paths)
moduleInfos[name] = dpInfo
mkProvider, ok := module.(android.AndroidMkDataProvider)
diff --git a/java/kotlin.go b/java/kotlin.go
index 673970b..e8c030a 100644
--- a/java/kotlin.go
+++ b/java/kotlin.go
@@ -31,7 +31,9 @@
Command: `rm -rf "$classesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` +
`mkdir -p "$classesDir" "$srcJarDir" "$emptyDir" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" $classesDir $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` +
`-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` +
`${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` +
@@ -52,21 +54,43 @@
Rspfile: "$out.rsp",
RspfileContent: `$in`,
},
- "kotlincFlags", "classpath", "srcJars", "srcJarDir", "classesDir", "kotlinJvmTarget", "kotlinBuildFile",
- "emptyDir", "name")
+ "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir",
+ "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name")
+
+func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath {
+ if len(commonSrcFiles) > 0 {
+ // The list of common_srcs may be too long to put on the command line, but
+ // we can't use the rsp file because it is already being used for srcs.
+ // Insert a second rule to write out the list of resources to a file.
+ commonSrcsList := android.PathForModuleOut(ctx, "kotlinc_common_srcs.list")
+ rule := android.NewRuleBuilder()
+ rule.Command().Text("cp").FlagWithRspFileInputList("", commonSrcFiles).Output(commonSrcsList)
+ rule.Build(pctx, ctx, "kotlin_common_srcs_list", "kotlin common_srcs list")
+ return android.OptionalPathForPath(commonSrcsList)
+ }
+ return android.OptionalPath{}
+}
// kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile.
func kotlinCompile(ctx android.ModuleContext, outputFile android.WritablePath,
- srcFiles, srcJars android.Paths,
+ srcFiles, commonSrcFiles, srcJars android.Paths,
flags javaBuilderFlags) {
var deps android.Paths
deps = append(deps, flags.kotlincClasspath...)
deps = append(deps, srcJars...)
+ deps = append(deps, commonSrcFiles...)
kotlinName := filepath.Join(ctx.ModuleDir(), ctx.ModuleSubDir(), ctx.ModuleName())
kotlinName = strings.ReplaceAll(kotlinName, "/", "__")
+ commonSrcsList := kotlinCommonSrcsList(ctx, commonSrcFiles)
+ commonSrcFilesArg := ""
+ if commonSrcsList.Valid() {
+ deps = append(deps, commonSrcsList.Path())
+ commonSrcFilesArg = "--common_srcs " + commonSrcsList.String()
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: kotlinc,
Description: "kotlinc",
@@ -74,13 +98,14 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
- "kotlincFlags": flags.kotlincFlags,
- "srcJars": strings.Join(srcJars.Strings(), " "),
- "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
- "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
- "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
- "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
+ "kotlincFlags": flags.kotlincFlags,
+ "commonSrcFilesArg": commonSrcFilesArg,
+ "srcJars": strings.Join(srcJars.Strings(), " "),
+ "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(),
+ "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(),
+ "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(),
+ "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(),
// http://b/69160377 kotlinc only supports -jvm-target 1.6 and 1.8
"kotlinJvmTarget": "1.8",
"name": kotlinName,
@@ -93,7 +118,9 @@
Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` +
`mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` +
`${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` +
- `${config.GenKotlinBuildFileCmd} $classpath "$name" "" $out.rsp $srcJarDir/list > $kotlinBuildFile &&` +
+ `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` +
+ ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` +
+ ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` +
`${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` +
`-Xplugin=${config.KotlinKaptJar} ` +
`-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` +
@@ -120,21 +147,31 @@
RspfileContent: `$in`,
},
"kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor",
- "classpath", "srcJars", "srcJarDir", "kaptDir", "kotlinJvmTarget", "kotlinBuildFile", "name",
- "classesJarOut")
+ "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget",
+ "kotlinBuildFile", "name", "classesJarOut")
// kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs
// annotation processors over all of them, producing a srcjar of generated code in outputFile. The srcjar should be
// added as an additional input to kotlinc and javac rules, and the javac rule should have annotation processing
// disabled.
func kotlinKapt(ctx android.ModuleContext, srcJarOutputFile, resJarOutputFile android.WritablePath,
- srcFiles, srcJars android.Paths,
+ srcFiles, commonSrcFiles, srcJars android.Paths,
flags javaBuilderFlags) {
+ srcFiles = append(android.Paths(nil), srcFiles...)
+
var deps android.Paths
deps = append(deps, flags.kotlincClasspath...)
deps = append(deps, srcJars...)
deps = append(deps, flags.processorPath...)
+ deps = append(deps, commonSrcFiles...)
+
+ commonSrcsList := kotlinCommonSrcsList(ctx, commonSrcFiles)
+ commonSrcFilesArg := ""
+ if commonSrcsList.Valid() {
+ deps = append(deps, commonSrcsList.Path())
+ commonSrcFilesArg = "--common_srcs " + commonSrcsList.String()
+ }
kaptProcessorPath := flags.processorPath.FormRepeatedClassPath("-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=")
@@ -162,8 +199,9 @@
Inputs: srcFiles,
Implicits: deps,
Args: map[string]string{
- "classpath": flags.kotlincClasspath.FormJavaClassPath("-classpath"),
+ "classpath": flags.kotlincClasspath.FormJavaClassPath(""),
"kotlincFlags": flags.kotlincFlags,
+ "commonSrcFilesArg": commonSrcFilesArg,
"srcJars": strings.Join(srcJars.Strings(), " "),
"srcJarDir": android.PathForModuleOut(ctx, "kapt", "srcJars").String(),
"kotlinBuildFile": android.PathForModuleOut(ctx, "kapt", "build.xml").String(),
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
new file mode 100644
index 0000000..df1f643
--- /dev/null
+++ b/java/legacy_core_platform_api_usage.go
@@ -0,0 +1,267 @@
+// Copyright 2020 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 java
+
+import (
+ "android/soong/android"
+ "android/soong/java/config"
+)
+
+var legacyCorePlatformApiModules = []string{
+ "AAECarSystemUI",
+ "AAECarSystemUI-tests",
+ "ahat-test-dump",
+ "android.car",
+ "android.test.mock",
+ "android.test.mock.impl",
+ "AoapTestDeviceApp",
+ "AoapTestHostApp",
+ "api-stubs-docs",
+ "art_cts_jvmti_test_library",
+ "art-gtest-jars-MyClassNatives",
+ "atfwd",
+ "BackupEncryption",
+ "BackupFrameworksServicesRoboTests",
+ "backuplib",
+ "BandwidthEnforcementTest",
+ "BlockedNumberProvider",
+ "BluetoothInstrumentationTests",
+ "BluetoothMidiLib",
+ "BluetoothMidiService",
+ "BTTestApp",
+ "CallEnhancement",
+ "CapCtrlInterface",
+ "CarService",
+ "car-service-test-lib",
+ "car-service-test-static-lib",
+ "CertInstaller",
+ "com.qti.location.sdk",
+ "com.qti.media.secureprocessor",
+ "com.qti.snapdragon.sdk.display",
+ "ConfURIDialer",
+ "ConnectivityManagerTest",
+ "ContactsProvider",
+ "CorePerfTests",
+ "core-tests-support",
+ "cronet_impl_common_java",
+ "cronet_impl_native_java",
+ "cronet_impl_platform_java",
+ "CtsAppExitTestCases",
+ "CtsContentTestCases",
+ "CtsIkeTestCases",
+ "CtsLibcoreWycheproofBCTestCases",
+ "CtsMediaTestCases",
+ "CtsNetTestCases",
+ "CtsNetTestCasesLatestSdk",
+ "CtsSecurityTestCases",
+ "CtsSuspendAppsTestCases",
+ "CtsUsageStatsTestCases",
+ "datastatusnotification",
+ "DeadpoolService",
+ "DeadpoolServiceBtServices",
+ "DeviceInfo",
+ "DisplayCutoutEmulationEmu01Overlay",
+ "DocumentsUIGoogleTests",
+ "DocumentsUIPerfTests",
+ "DocumentsUITests",
+ "DocumentsUIUnitTests",
+ "DownloadProvider",
+ "DownloadProviderTests",
+ "DownloadProviderUi",
+ "DynamicSystemInstallationService",
+ "EmergencyInfo-lib",
+ "ethernet-service",
+ "EthernetServiceTests",
+ "ExternalStorageProvider",
+ "face-V1-0-javalib",
+ "FloralClocks",
+ "framework-all",
+ "framework-jobscheduler",
+ "framework-minus-apex",
+ "FrameworkOverlayG6QU3",
+ "FrameworksCoreTests",
+ "FrameworksIkeTests",
+ "FrameworksNetCommonTests",
+ "FrameworksNetTests",
+ "FrameworksServicesRoboTests",
+ "FrameworksServicesTests",
+ "FrameworksUtilTests",
+ "FrameworksWifiTests",
+ "GtsIncrementalInstallTestCases",
+ "GtsIncrementalInstallTriggerApp",
+ "GtsInstallerV2TestCases",
+ "HelloOslo",
+ "hid",
+ "hidl_test_java_java",
+ "hwbinder",
+ "ims",
+ "ims-ext-common",
+ "imssettings",
+ "izat.lib.glue",
+ "KeyChain",
+ "LocalSettingsLib",
+ "LocalTransport",
+ "lockagent",
+ "mediaframeworktest",
+ "mediatek-ims-base",
+ "MmsService",
+ "ModemTestMode",
+ "MtkCapCtrl",
+ "MtpService",
+ "MultiDisplayProvider",
+ "my.tests.snapdragonsdktest",
+ "NetworkSetting",
+ "NetworkStackIntegrationTestsLib",
+ "NetworkStackNextIntegrationTests",
+ "NetworkStackNextTests",
+ "NetworkStackTests",
+ "NetworkStackTestsLib",
+ "NfcNci",
+ "online-gcm-ref-docs",
+ "online-gts-docs",
+ "PerformanceMode",
+ "pixel-power-ext-java",
+ "pixel-power-ext-unstable-java",
+ "pixel-power-ext-V1-java",
+ "platform_library-docs",
+ "PowerStatsService",
+ "PrintSpooler",
+ "pxp-monitor",
+ "QColor",
+ "qcom.fmradio",
+ "qcrilhook",
+ "qcrilhook-static",
+ "qcrilmsgtunnel",
+ "QDCMMobileApp",
+ "Qmmi",
+ "QPerformance",
+ "QtiTelephonyService",
+ "QtiTelephonyServicelibrary",
+ "remoteSimLockAuthentication",
+ "remotesimlockmanagerlibrary",
+ "RollbackTest",
+ "sam",
+ "saminterfacelibrary",
+ "sammanagerlibrary",
+ "service-blobstore",
+ "service-jobscheduler",
+ "services",
+ "services.accessibility",
+ "services.backup",
+ "services.core.unboosted",
+ "services.devicepolicy",
+ "services.print",
+ "services.usage",
+ "services.usb",
+ "Settings-core",
+ "SettingsGoogleOverlayCoral",
+ "SettingsGoogleOverlayFlame",
+ "SettingsLib",
+ "SettingsOverlayG013A",
+ "SettingsOverlayG013B",
+ "SettingsOverlayG013C",
+ "SettingsOverlayG013D",
+ "SettingsOverlayG020A",
+ "SettingsOverlayG020B",
+ "SettingsOverlayG020C",
+ "SettingsOverlayG020D",
+ "SettingsOverlayG020E",
+ "SettingsOverlayG020E_VN",
+ "SettingsOverlayG020F",
+ "SettingsOverlayG020F_VN",
+ "SettingsOverlayG020G",
+ "SettingsOverlayG020G_VN",
+ "SettingsOverlayG020H",
+ "SettingsOverlayG020H_VN",
+ "SettingsOverlayG020I",
+ "SettingsOverlayG020I_VN",
+ "SettingsOverlayG020J",
+ "SettingsOverlayG020M",
+ "SettingsOverlayG020N",
+ "SettingsOverlayG020P",
+ "SettingsOverlayG020Q",
+ "SettingsOverlayG025H",
+ "SettingsOverlayG025J",
+ "SettingsOverlayG025M",
+ "SettingsOverlayG025N",
+ "SettingsOverlayG5NZ6",
+ "SettingsProvider",
+ "SettingsProviderTest",
+ "SettingsRoboTests",
+ "Shell",
+ "ShellTests",
+ "SimContact",
+ "SimContacts",
+ "SimSettings",
+ "sl4a.Common",
+ "StatementService",
+ "SystemUI-core",
+ "SystemUISharedLib",
+ "SystemUI-tests",
+ "tcmiface",
+ "Telecom",
+ "TelecomUnitTests",
+ "telephony-common",
+ "telephony-ext",
+ "TelephonyProviderTests",
+ "TeleService",
+ "testables",
+ "TetheringTests",
+ "TetheringTestsLib",
+ "time_zone_distro_installer",
+ "time_zone_distro_installer-tests",
+ "time_zone_distro-tests",
+ "time_zone_updater",
+ "TMobilePlanProvider",
+ "TvProvider",
+ "uiautomator-stubs-docs",
+ "uimgbamanagerlibrary",
+ "UsbHostExternalManagementTestApp",
+ "UserDictionaryProvider",
+ "UxPerformance",
+ "WallpaperBackup",
+ "WallpaperBackupAgentTests",
+ "WfdCommon",
+ "xdivert",
+}
+
+var legacyCorePlatformApiLookup = make(map[string]struct{})
+
+func init() {
+ for _, module := range legacyCorePlatformApiModules {
+ legacyCorePlatformApiLookup[module] = struct{}{}
+ }
+}
+
+func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool {
+ _, found := legacyCorePlatformApiLookup[ctx.ModuleName()]
+ return found
+}
+
+func corePlatformSystemModules(ctx android.EarlyModuleContext) string {
+ if useLegacyCorePlatformApi(ctx) {
+ return config.LegacyCorePlatformSystemModules
+ } else {
+ return config.StableCorePlatformSystemModules
+ }
+}
+
+func corePlatformBootclasspathLibraries(ctx android.EarlyModuleContext) []string {
+ if useLegacyCorePlatformApi(ctx) {
+ return config.LegacyCorePlatformBootclasspathLibraries
+ } else {
+ return config.StableCorePlatformBootclasspathLibraries
+ }
+}
diff --git a/java/lint.go b/java/lint.go
index 6391067..3a210cc 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -252,7 +252,7 @@
return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
}
-// generateManifest adds a command to the rule to write a dummy manifest cat contains the
+// generateManifest adds a command to the rule to write a simple manifest that contains the
// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
@@ -309,7 +309,7 @@
rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String())
var annotationsZipPath, apiVersionsXMLPath android.Path
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
} else {
@@ -319,7 +319,7 @@
cmd := rule.Command().
Text("(").
- Flag("JAVA_OPTS=-Xmx2048m").
+ Flag("JAVA_OPTS=-Xmx3072m").
FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath).
@@ -395,7 +395,7 @@
}
func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return
}
@@ -513,7 +513,7 @@
rule.Command().BuiltTool(ctx, "soong_zip").
FlagWithOutput("-o ", outputPath).
FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
- FlagWithRspFileInputList("-l ", paths)
+ FlagWithRspFileInputList("-r ", paths)
rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
}
diff --git a/java/robolectric.go b/java/robolectric.go
index c6b07a1..ec112bc 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -21,10 +21,13 @@
"strings"
"android/soong/android"
+ "android/soong/java/config"
+ "android/soong/tradefed"
)
func init() {
android.RegisterModuleType("android_robolectric_test", RobolectricTestFactory)
+ android.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory)
}
var robolectricDefaultLibs = []string{
@@ -32,10 +35,13 @@
"Robolectric_all-target",
"mockito-robolectric-prebuilt",
"truth-prebuilt",
+ // TODO(ccross): this is not needed at link time
+ "junitxml",
}
var (
- roboCoverageLibsTag = dependencyTag{name: "roboSrcs"}
+ roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"}
+ roboRuntimesTag = dependencyTag{name: "roboRuntimes"}
)
type robolectricProperties struct {
@@ -58,13 +64,28 @@
Library
robolectricProperties robolectricProperties
+ testProperties testProperties
libs []string
tests []string
+ manifest android.Path
+ resourceApk android.Path
+
+ combinedJar android.WritablePath
+
roboSrcJar android.Path
+
+ testConfig android.Path
+ data android.Paths
}
+func (r *robolectricTest) TestSuites() []string {
+ return r.testProperties.Test_suites
+}
+
+var _ android.TestSuiteModule = (*robolectricTest)(nil)
+
func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) {
r.Library.DepsMutator(ctx)
@@ -77,9 +98,16 @@
ctx.AddVariationDependencies(nil, libTag, robolectricDefaultLibs...)
ctx.AddVariationDependencies(nil, roboCoverageLibsTag, r.robolectricProperties.Coverage_libs...)
+
+ ctx.AddVariationDependencies(nil, roboRuntimesTag, "robolectric-android-all-prebuilts")
}
func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config,
+ r.testProperties.Test_config_template, r.testProperties.Test_suites,
+ r.testProperties.Auto_gen_config)
+ r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
+
roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
Join(ctx, "com/android/tools/test_config.properties")
@@ -95,6 +123,9 @@
ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app")
}
+ r.manifest = instrumentedApp.mergedManifestFile
+ r.resourceApk = instrumentedApp.outputFile
+
generateRoboTestConfig(ctx, roboTestConfig, instrumentedApp)
r.extraResources = android.Paths{roboTestConfig}
@@ -104,10 +135,30 @@
r.generateRoboSrcJar(ctx, roboSrcJar, instrumentedApp)
r.roboSrcJar = roboSrcJar
- for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
- r.libs = append(r.libs, dep.(Dependency).BaseModuleName())
+ roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar")
+ generateSameDirRoboTestConfigJar(ctx, roboTestConfigJar)
+
+ combinedJarJars := android.Paths{
+ // roboTestConfigJar comes first so that its com/android/tools/test_config.properties
+ // overrides the one from r.extraResources. The r.extraResources one can be removed
+ // once the Make test runner is removed.
+ roboTestConfigJar,
+ r.outputFile,
+ instrumentedApp.implementationAndResourcesJar,
}
+ for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
+ m := dep.(Dependency)
+ r.libs = append(r.libs, m.BaseModuleName())
+ if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) {
+ combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...)
+ }
+ }
+
+ r.combinedJar = android.PathForModuleOut(ctx, "robolectric_combined", r.outputFile.Base())
+ TransformJarsToJar(ctx, r.combinedJar, "combine jars", combinedJarJars, android.OptionalPath{},
+ false, nil, nil)
+
// TODO: this could all be removed if tradefed was used as the test runner, it will find everything
// annotated as a test and run it.
for _, src := range r.compiledJavaSrcs {
@@ -121,14 +172,38 @@
}
r.tests = append(r.tests, s)
}
+
+ r.data = append(r.data, r.manifest, r.resourceApk)
+
+ runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag)
+
+ installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+
+ installedResourceApk := ctx.InstallFile(installPath, ctx.ModuleName()+".apk", r.resourceApk)
+ installedManifest := ctx.InstallFile(installPath, ctx.ModuleName()+"-AndroidManifest.xml", r.manifest)
+ installedConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+
+ var installDeps android.Paths
+ for _, runtime := range runtimes.(*robolectricRuntimes).runtimes {
+ installDeps = append(installDeps, runtime)
+ }
+ installDeps = append(installDeps, installedResourceApk, installedManifest, installedConfig)
+
+ for _, data := range android.PathsForModuleSrc(ctx, r.testProperties.Data) {
+ installedData := ctx.InstallFile(installPath, data.Rel(), data)
+ installDeps = append(installDeps, installedData)
+ }
+
+ ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.combinedJar, installDeps...)
}
-func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath, instrumentedApp *AndroidApp) {
+func generateRoboTestConfig(ctx android.ModuleContext, outputFile android.WritablePath,
+ instrumentedApp *AndroidApp) {
+ rule := android.NewRuleBuilder()
+
manifest := instrumentedApp.mergedManifestFile
resourceApk := instrumentedApp.outputFile
- rule := android.NewRuleBuilder()
-
rule.Command().Text("rm -f").Output(outputFile)
rule.Command().
Textf(`echo "android_merged_manifest=%s" >>`, manifest.String()).Output(outputFile).Text("&&").
@@ -141,6 +216,28 @@
rule.Build(pctx, ctx, "generate_test_config", "generate test_config.properties")
}
+func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) {
+ rule := android.NewRuleBuilder()
+
+ outputDir := outputFile.InSameDir(ctx)
+ configFile := outputDir.Join(ctx, "com/android/tools/test_config.properties")
+ rule.Temporary(configFile)
+ rule.Command().Text("rm -f").Output(outputFile).Output(configFile)
+ rule.Command().Textf("mkdir -p $(dirname %s)", configFile.String())
+ rule.Command().
+ Text("(").
+ Textf(`echo "android_merged_manifest=%s-AndroidManifest.xml" &&`, ctx.ModuleName()).
+ Textf(`echo "android_resource_apk=%s.apk"`, ctx.ModuleName()).
+ Text(") >>").Output(configFile)
+ rule.Command().
+ BuiltTool(ctx, "soong_zip").
+ FlagWithArg("-C ", outputDir.String()).
+ FlagWithInput("-f ", configFile).
+ FlagWithOutput("-o ", outputFile)
+
+ rule.Build(pctx, ctx, "generate_test_config_samedir", "generate test_config.properties")
+}
+
func (r *robolectricTest) generateRoboSrcJar(ctx android.ModuleContext, outputFile android.WritablePath,
instrumentedApp *AndroidApp) {
@@ -202,7 +299,6 @@
fmt.Fprintln(w, "LOCAL_ROBOTEST_TIMEOUT :=", *t)
}
fmt.Fprintln(w, "-include external/robolectric-shadows/run_robotests.mk")
-
}
// An android_robolectric_test module compiles tests against the Robolectric framework that can run on the local host
@@ -218,11 +314,86 @@
module.addHostProperties()
module.AddProperties(
&module.Module.deviceProperties,
- &module.robolectricProperties)
+ &module.robolectricProperties,
+ &module.testProperties)
module.Module.dexpreopter.isTest = true
module.Module.linter.test = true
+ module.testProperties.Test_suites = []string{"robolectric-tests"}
+
InitJavaModule(module, android.DeviceSupported)
return module
}
+
+func (r *robolectricTest) InstallBypassMake() bool { return true }
+func (r *robolectricTest) InstallInTestcases() bool { return true }
+func (r *robolectricTest) InstallForceOS() (*android.OsType, *android.ArchType) {
+ return &android.BuildOs, &android.BuildArch
+}
+
+func robolectricRuntimesFactory() android.Module {
+ module := &robolectricRuntimes{}
+ module.AddProperties(&module.props)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+ return module
+}
+
+type robolectricRuntimesProperties struct {
+ Jars []string `android:"path"`
+ Lib *string
+}
+
+type robolectricRuntimes struct {
+ android.ModuleBase
+
+ props robolectricRuntimesProperties
+
+ runtimes []android.InstallPath
+}
+
+func (r *robolectricRuntimes) TestSuites() []string {
+ return []string{"robolectric-tests"}
+}
+
+var _ android.TestSuiteModule = (*robolectricRuntimes)(nil)
+
+func (r *robolectricRuntimes) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil {
+ ctx.AddVariationDependencies(nil, libTag, String(r.props.Lib))
+ }
+}
+
+func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ files := android.PathsForModuleSrc(ctx, r.props.Jars)
+
+ androidAllDir := android.PathForModuleInstall(ctx, "android-all")
+ for _, from := range files {
+ installedRuntime := ctx.InstallFile(androidAllDir, from.Base(), from)
+ r.runtimes = append(r.runtimes, installedRuntime)
+ }
+
+ if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil {
+ runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag)
+ if runtimeFromSourceModule == nil {
+ if ctx.Config().AllowMissingDependencies() {
+ ctx.AddMissingDependencies([]string{String(r.props.Lib)})
+ } else {
+ ctx.PropertyErrorf("lib", "missing dependency %q", String(r.props.Lib))
+ }
+ return
+ }
+ runtimeFromSourceJar := android.OutputFileForModule(ctx, runtimeFromSourceModule, "")
+
+ runtimeName := fmt.Sprintf("android-all-%s-robolectric-r0.jar",
+ ctx.Config().PlatformSdkCodename())
+ installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar)
+ r.runtimes = append(r.runtimes, installedRuntime)
+ }
+}
+
+func (r *robolectricRuntimes) InstallBypassMake() bool { return true }
+func (r *robolectricRuntimes) InstallInTestcases() bool { return true }
+func (r *robolectricRuntimes) InstallForceOS() (*android.OsType, *android.ArchType) {
+ return &android.BuildOs, &android.BuildArch
+}
diff --git a/java/sdk.go b/java/sdk.go
index 6c16651..56fa12b 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -53,7 +53,7 @@
func UseApiFingerprint(ctx android.BaseModuleContext) bool {
if ctx.Config().UnbundledBuild() &&
- !ctx.Config().UnbundledBuildUsePrebuiltSdks() &&
+ !ctx.Config().AlwaysUsePrebuiltSdks() &&
ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
return true
}
@@ -191,19 +191,22 @@
return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform
}
-// forPdkBuild converts this sdkSpec into another sdkSpec that is for the PDK builds.
-func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec {
- // For PDK builds, use the latest SDK version instead of "current" or ""
- if s.kind == sdkPrivate || s.kind == sdkPublic {
- kind := s.kind
- if kind == sdkPrivate {
- // We don't have prebuilt SDK for private APIs, so use the public SDK
- // instead. This looks odd, but that's how it has been done.
- // TODO(b/148271073): investigate the need for this.
- kind = sdkPublic
+func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec {
+ // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
+ // use it instead of "current" for the vendor partition.
+ currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
+ if currentSdkVersion == "current" {
+ return s
+ }
+
+ if s.kind == sdkPublic || s.kind == sdkSystem {
+ if s.version.isCurrent() {
+ if i, err := strconv.Atoi(currentSdkVersion); err == nil {
+ version := sdkVersion(i)
+ return sdkSpec{s.kind, version, s.raw}
+ }
+ panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
}
- version := sdkVersion(LatestSdkVersionInt(ctx))
- return sdkSpec{kind, version, s.raw}
}
return s
}
@@ -212,9 +215,9 @@
func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool {
if s.version.isCurrent() {
// "current" can be built from source and be from prebuilt SDK
- return ctx.Config().UnbundledBuildUsePrebuiltSdks()
+ return ctx.Config().AlwaysUsePrebuiltSdks()
} else if s.version.isNumbered() {
- // sanity check
+ // validation check
if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest {
panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind))
return false
@@ -233,8 +236,9 @@
if !s.valid() {
return s.version, fmt.Errorf("invalid sdk version %q", s.raw)
}
- if ctx.Config().IsPdkBuild() {
- s = s.forPdkBuild(ctx)
+
+ if ctx.DeviceSpecific() || ctx.SocSpecific() {
+ s = s.forVendorPartition(ctx)
}
if s.version.isNumbered() {
return s.version, nil
@@ -321,6 +325,28 @@
}
}
+func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool {
+ // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
+ // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
+ // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
+ if s.kind != sdkSystem || !s.version.isNumbered() {
+ return true
+ }
+ allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
+ if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
+ systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
+ if len(systemSdkVersions) > 0 {
+ allowedVersions = systemSdkVersions
+ }
+ }
+ if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) {
+ ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
+ s.raw, allowedVersions)
+ return false
+ }
+ return true
+}
+
func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep {
sdkVersion := sdkContext.sdkVersion()
if !sdkVersion.valid() {
@@ -328,8 +354,12 @@
return sdkDep{}
}
- if ctx.Config().IsPdkBuild() {
- sdkVersion = sdkVersion.forPdkBuild(ctx)
+ if ctx.DeviceSpecific() || ctx.SocSpecific() {
+ sdkVersion = sdkVersion.forVendorPartition(ctx)
+ }
+
+ if !sdkVersion.validateSystemSdk(ctx) {
+ return sdkDep{}
}
if sdkVersion.usePrebuilt(ctx) {
@@ -384,25 +414,13 @@
}
}
- // Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
- // or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
- if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() {
- allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
- if ctx.DeviceSpecific() || ctx.SocSpecific() {
- if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
- allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
- }
- }
- if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) {
- ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
- sdkVersion.raw, allowed_versions)
- }
- }
-
switch sdkVersion.kind {
case sdkPrivate:
return sdkDep{
- useDefaultLibs: true,
+ useModule: true,
+ systemModules: corePlatformSystemModules(ctx),
+ bootclasspath: corePlatformBootclasspathLibraries(ctx),
+ classpath: config.FrameworkLibraries,
frameworkResModule: "framework-res",
}
case sdkNone:
@@ -424,9 +442,10 @@
}
case sdkCorePlatform:
return sdkDep{
- useDefaultLibs: true,
- frameworkResModule: "framework-res",
- noFrameworksLibs: true,
+ useModule: true,
+ systemModules: corePlatformSystemModules(ctx),
+ bootclasspath: corePlatformBootclasspathLibraries(ctx),
+ noFrameworksLibs: true,
}
case sdkPublic:
return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
@@ -435,7 +454,12 @@
case sdkTest:
return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
case sdkCore:
- return toModule([]string{"core.current.stubs"}, "", nil)
+ return sdkDep{
+ useModule: true,
+ bootclasspath: []string{"core.current.stubs", config.DefaultLambdaStubsLibrary},
+ systemModules: "core-current-stubs-system-modules",
+ noFrameworksLibs: true,
+ }
case sdkModule:
// TODO(146757305): provide .apk and .aidl that have more APIs for modules
return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx))
@@ -492,7 +516,7 @@
type sdkSingleton struct{}
func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return
}
@@ -612,10 +636,7 @@
if ctx.Config().PlatformSdkCodename() == "REL" {
cmd.Text("echo REL >").Output(out)
- } else if ctx.Config().IsPdkBuild() {
- // TODO: get this from the PDK artifacts?
- cmd.Text("echo PDK >").Output(out)
- } else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ } else if !ctx.Config().AlwaysUsePrebuiltSdks() {
in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil)
if err != nil {
ctx.Errorf("error globbing API files: %s", err)
@@ -644,7 +665,7 @@
}
func sdkMakeVars(ctx android.MakeVarsContext) {
- if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
return
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 0f7bbb5..1a5ef54 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -70,6 +70,12 @@
}
}
+var _ android.ReplaceSourceWithPrebuilt = (*scopeDependencyTag)(nil)
+
+func (tag scopeDependencyTag) ReplaceSourceWithPrebuilt() bool {
+ return false
+}
+
// Provides information about an api scope, e.g. public, system, test.
type apiScope struct {
// The name of the api scope, e.g. public, system, test
@@ -120,25 +126,23 @@
// the prebuilt jar.
sdkVersion string
+ // The annotation that identifies this API level, empty for the public API scope.
+ annotation string
+
// Extra arguments to pass to droidstubs for this scope.
- droidstubsArgs []string
-
- // The args that must be passed to droidstubs to generate the stubs source
- // for this scope.
//
- // The stubs source must include the definitions of everything that is in this
- // api scope and all the scopes that this one extends.
- droidstubsArgsForGeneratingStubsSource []string
+ // This is not used directly but is used to construct the droidstubsArgs.
+ extraArgs []string
- // The args that must be passed to droidstubs to generate the API for this scope.
+ // The args that must be passed to droidstubs to generate the API and stubs source
+ // for this scope, constructed dynamically by initApiScope().
//
// The API only includes the additional members that this scope adds over the scope
// that it extends.
- droidstubsArgsForGeneratingApi []string
-
- // True if the stubs source and api can be created by the same metalava invocation.
- // TODO(b/146727827) Now that metalava supports "API hierarchy", do we still need it?
- createStubsSourceAndApiTogether bool
+ //
+ // The stubs source must include the definitions of everything that is in this
+ // api scope and all the scopes that this one extends.
+ droidstubsArgs []string
// Whether the api scope can be treated as unstable, and should skip compat checks.
unstable bool
@@ -175,21 +179,23 @@
// To get the args needed to generate the stubs source append all the args from
// this scope and all the scopes it extends as each set of args adds additional
// members to the stubs.
- var stubsSourceArgs []string
- for s := scope; s != nil; s = s.extends {
- stubsSourceArgs = append(stubsSourceArgs, s.droidstubsArgs...)
+ var scopeSpecificArgs []string
+ if scope.annotation != "" {
+ scopeSpecificArgs = []string{"--show-annotation", scope.annotation}
}
- scope.droidstubsArgsForGeneratingStubsSource = stubsSourceArgs
+ for s := scope; s != nil; s = s.extends {
+ scopeSpecificArgs = append(scopeSpecificArgs, s.extraArgs...)
- // Currently the args needed to generate the API are the same as the args
- // needed to add additional members.
- apiArgs := scope.droidstubsArgs
- scope.droidstubsArgsForGeneratingApi = apiArgs
+ // Ensure that the generated stubs includes all the API elements from the API scope
+ // that this scope extends.
+ if s != scope && s.annotation != "" {
+ scopeSpecificArgs = append(scopeSpecificArgs, "--show-for-stub-purposes-annotation", s.annotation)
+ }
+ }
- // If the args needed to generate the stubs and API are the same then they
- // can be generated in a single invocation of metalava, otherwise they will
- // need separate invocations.
- scope.createStubsSourceAndApiTogether = reflect.DeepEqual(stubsSourceArgs, apiArgs)
+ // Escape any special characters in the arguments. This is needed because droidstubs
+ // passes these directly to the shell command.
+ scope.droidstubsArgs = proptools.ShellEscapeList(scopeSpecificArgs)
return scope
}
@@ -244,10 +250,10 @@
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
return &module.sdkLibraryProperties.System
},
- apiFilePrefix: "system-",
- moduleSuffix: ".system",
- sdkVersion: "system_current",
- droidstubsArgs: []string{"-showAnnotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)"},
+ apiFilePrefix: "system-",
+ moduleSuffix: ".system",
+ sdkVersion: "system_current",
+ annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS)",
})
apiScopeTest = initApiScope(&apiScope{
name: "test",
@@ -256,11 +262,11 @@
scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
return &module.sdkLibraryProperties.Test
},
- apiFilePrefix: "test-",
- moduleSuffix: ".test",
- sdkVersion: "test_current",
- droidstubsArgs: []string{"-showAnnotation android.annotation.TestApi"},
- unstable: true,
+ apiFilePrefix: "test-",
+ moduleSuffix: ".test",
+ sdkVersion: "test_current",
+ annotation: "android.annotation.TestApi",
+ unstable: true,
})
apiScopeModuleLib = initApiScope(&apiScope{
name: "module-lib",
@@ -277,10 +283,7 @@
apiFilePrefix: "module-lib-",
moduleSuffix: ".module_lib",
sdkVersion: "module_current",
- droidstubsArgs: []string{
- "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
- "--show-for-stub-purposes-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.PRIVILEGED_APPS\\)",
- },
+ annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES)",
})
apiScopeSystemServer = initApiScope(&apiScope{
name: "system-server",
@@ -297,11 +300,11 @@
apiFilePrefix: "system-server-",
moduleSuffix: ".system_server",
sdkVersion: "system_server_current",
- droidstubsArgs: []string{
- "--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ",
- "--hide-annotation android.annotation.Hide",
+ annotation: "android.annotation.SystemApi(client=android.annotation.SystemApi.Client.SYSTEM_SERVER)",
+ extraArgs: []string{
+ "--hide-annotation", "android.annotation.Hide",
// com.android.* classes are okay in this interface"
- "--hide InternalClasses",
+ "--hide", "InternalClasses",
},
})
allApiScopes = apiScopes{
@@ -572,9 +575,7 @@
type commonToSdkLibraryAndImportProperties struct {
// The naming scheme to use for the components that this module creates.
//
- // If not specified then it defaults to "default". The other allowable value is
- // "framework-modules" which matches the scheme currently used by framework modules
- // for the equivalent components represented as separate Soong modules.
+ // If not specified then it defaults to "default".
//
// This is a temporary mechanism to simplify conversion from separate modules for each
// component that follow a different naming pattern to the default one.
@@ -618,8 +619,6 @@
switch schemeProperty {
case "default":
c.namingScheme = &defaultNamingScheme{}
- case "framework-modules":
- c.namingScheme = &frameworkModulesNamingScheme{}
default:
ctx.PropertyErrorf("naming_scheme", "expected 'default' but was %q", schemeProperty)
return false
@@ -849,22 +848,20 @@
}
// to satisfy SdkLibraryComponentDependency
-func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string {
- if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil {
- return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack}
- }
- return nil
+func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
+ return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
}
// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
// (including the java_sdk_library) itself.
type SdkLibraryComponentDependency interface {
+ UsesLibraryDependency
+
// The optional name of the sdk library that should be implicitly added to the
// AndroidManifest of an app that contains code which references the sdk library.
//
- // Returns an array containing 0 or 1 items rather than a *string to make it easier
- // to append this to the list of exported sdk libraries.
- OptionalImplicitSdkLibrary() []string
+ // Returns the name of the optional implicit SDK library or nil, if there isn't one.
+ OptionalImplicitSdkLibrary() *string
}
// Make sure that all the module types that are components of java_sdk_library/_import
@@ -978,21 +975,14 @@
var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
-func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+// Add the dependencies on the child modules in the component deps mutator.
+func (module *SdkLibrary) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
for _, apiScope := range module.getGeneratedApiScopes(ctx) {
// Add dependencies to the stubs library
ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
- // If the stubs source and API cannot be generated together then add an additional dependency on
- // the API module.
- if apiScope.createStubsSourceAndApiTogether {
- // Add a dependency on the stubs source in order to access both stubs source and api information.
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
- } else {
- // Add separate dependencies on the creators of the stubs source files and the API.
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
- ctx.AddVariationDependencies(nil, apiScope.apiFileTag, module.apiModuleName(apiScope))
- }
+ // Add a dependency on the stubs source in order to access both stubs source and api information.
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceAndApiTag, module.stubsSourceModuleName(apiScope))
}
if module.requiresRuntimeImplementationLibrary() {
@@ -1003,7 +993,12 @@
// Add dependency to the rule for generating the xml permissions file
ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
}
+ }
+}
+// Add other dependencies as normal.
+func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
+ if module.requiresRuntimeImplementationLibrary() {
// Only add the deps for the library if it is actually going to be built.
module.Library.deps(ctx)
}
@@ -1047,8 +1042,10 @@
return nil
}
entriesList := module.Library.AndroidMkEntries()
- entries := &entriesList[0]
- entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
+ if module.sharedLibrary() {
+ entries := &entriesList[0]
+ entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
+ }
return entriesList
}
@@ -1138,22 +1135,17 @@
// Creates a static java library that has API stubs
func (module *SdkLibrary) createStubsLibrary(mctx android.DefaultableHookContext, apiScope *apiScope) {
props := struct {
- Name *string
- Visibility []string
- Srcs []string
- Installable *bool
- Sdk_version *string
- System_modules *string
- Patch_module *string
- Libs []string
- Compile_dex *bool
- Java_version *string
- Product_variables struct {
- Pdk struct {
- Enabled *bool
- }
- }
- Openjdk9 struct {
+ Name *string
+ Visibility []string
+ Srcs []string
+ Installable *bool
+ Sdk_version *string
+ System_modules *string
+ Patch_module *string
+ Libs []string
+ Compile_dex *bool
+ Java_version *string
+ Openjdk9 struct {
Srcs []string
Javacflags []string
}
@@ -1180,7 +1172,6 @@
if proptools.Bool(module.sdkLibraryProperties.Annotations_enabled) {
props.Libs = append(props.Libs, "stub-annotations")
}
- props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
@@ -1203,7 +1194,7 @@
// Creates a droidstubs module that creates stubs source files from the given full source
// files and also updates and checks the API specification files.
-func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, createStubSources, createApi bool, scopeSpecificDroidstubsArgs []string) {
+func (module *SdkLibrary) createStubsSourcesAndApi(mctx android.DefaultableHookContext, apiScope *apiScope, name string, scopeSpecificDroidstubsArgs []string) {
props := struct {
Name *string
Visibility []string
@@ -1287,64 +1278,57 @@
}
droidstubsArgs = append(droidstubsArgs, android.JoinWithPrefix(disabledWarnings, "--hide "))
- if !createStubSources {
- // Stubs are not required.
- props.Generate_stubs = proptools.BoolPtr(false)
- }
-
// Add in scope specific arguments.
droidstubsArgs = append(droidstubsArgs, scopeSpecificDroidstubsArgs...)
props.Arg_files = module.sdkLibraryProperties.Droiddoc_option_files
props.Args = proptools.StringPtr(strings.Join(droidstubsArgs, " "))
- if createApi {
- // List of APIs identified from the provided source files are created. They are later
- // compared against to the not-yet-released (a.k.a current) list of APIs and to the
- // last-released (a.k.a numbered) list of API.
- currentApiFileName := apiScope.apiFilePrefix + "current.txt"
- removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
- apiDir := module.getApiDir()
- currentApiFileName = path.Join(apiDir, currentApiFileName)
- removedApiFileName = path.Join(apiDir, removedApiFileName)
+ // List of APIs identified from the provided source files are created. They are later
+ // compared against to the not-yet-released (a.k.a current) list of APIs and to the
+ // last-released (a.k.a numbered) list of API.
+ currentApiFileName := apiScope.apiFilePrefix + "current.txt"
+ removedApiFileName := apiScope.apiFilePrefix + "removed.txt"
+ apiDir := module.getApiDir()
+ currentApiFileName = path.Join(apiDir, currentApiFileName)
+ removedApiFileName = path.Join(apiDir, removedApiFileName)
- // check against the not-yet-release API
- props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
- props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
+ // check against the not-yet-release API
+ props.Check_api.Current.Api_file = proptools.StringPtr(currentApiFileName)
+ props.Check_api.Current.Removed_api_file = proptools.StringPtr(removedApiFileName)
- if !apiScope.unstable {
- // check against the latest released API
- latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
- props.Check_api.Last_released.Api_file = latestApiFilegroupName
- props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
- module.latestRemovedApiFilegroupName(apiScope))
- props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
+ if !apiScope.unstable {
+ // check against the latest released API
+ latestApiFilegroupName := proptools.StringPtr(module.latestApiFilegroupName(apiScope))
+ props.Check_api.Last_released.Api_file = latestApiFilegroupName
+ props.Check_api.Last_released.Removed_api_file = proptools.StringPtr(
+ module.latestRemovedApiFilegroupName(apiScope))
+ props.Check_api.Ignore_missing_latest_api = proptools.BoolPtr(true)
- if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
- // Enable api lint.
- props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
- props.Check_api.Api_lint.New_since = latestApiFilegroupName
+ if proptools.Bool(module.sdkLibraryProperties.Api_lint.Enabled) {
+ // Enable api lint.
+ props.Check_api.Api_lint.Enabled = proptools.BoolPtr(true)
+ props.Check_api.Api_lint.New_since = latestApiFilegroupName
- // If it exists then pass a lint-baseline.txt through to droidstubs.
- baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
- baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
- paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
- if err != nil {
- mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
- }
- if len(paths) == 1 {
- props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
- } else if len(paths) != 0 {
- mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
- }
+ // If it exists then pass a lint-baseline.txt through to droidstubs.
+ baselinePath := path.Join(apiDir, apiScope.apiFilePrefix+"lint-baseline.txt")
+ baselinePathRelativeToRoot := path.Join(mctx.ModuleDir(), baselinePath)
+ paths, err := mctx.GlobWithDeps(baselinePathRelativeToRoot, nil)
+ if err != nil {
+ mctx.ModuleErrorf("error checking for presence of %s: %s", baselinePathRelativeToRoot, err)
+ }
+ if len(paths) == 1 {
+ props.Check_api.Api_lint.Baseline_file = proptools.StringPtr(baselinePath)
+ } else if len(paths) != 0 {
+ mctx.ModuleErrorf("error checking for presence of %s: expected one path, found: %v", baselinePathRelativeToRoot, paths)
}
}
+ }
- // Dist the api txt artifact for sdk builds.
- if !Bool(module.sdkLibraryProperties.No_dist) {
- props.Dist.Targets = []string{"sdk", "win_sdk"}
- props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
- props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
- }
+ // Dist the api txt artifact for sdk builds.
+ if !Bool(module.sdkLibraryProperties.No_dist) {
+ props.Dist.Targets = []string{"sdk", "win_sdk"}
+ props.Dist.Dest = proptools.StringPtr(fmt.Sprintf("%v.txt", module.BaseModuleName()))
+ props.Dist.Dir = proptools.StringPtr(path.Join(module.apiDistPath(apiScope), "api"))
}
mctx.CreateModule(DroidstubsFactory, &props)
@@ -1400,22 +1384,22 @@
return android.Paths{jarPath.Path()}
}
-// Get the apex name for module, "" if it is for platform.
-func getApexNameForModule(module android.Module) string {
+// Get the apex names for module, nil if it is for platform.
+func getApexNamesForModule(module android.Module) []string {
if apex, ok := module.(android.ApexModule); ok {
- return apex.ApexName()
+ return apex.InApexes()
}
- return ""
+ return nil
}
-// Check to see if the other module is within the same named APEX as this module.
+// Check to see if the other module is within the same set of named APEXes as this module.
//
// If either this or the other module are on the platform then this will return
// false.
-func withinSameApexAs(module android.ApexModule, other android.Module) bool {
- name := module.ApexName()
- return name != "" && getApexNameForModule(other) == name
+func withinSameApexesAs(module android.ApexModule, other android.Module) bool {
+ names := module.InApexes()
+ return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other))
}
func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
@@ -1434,7 +1418,7 @@
// Only allow access to the implementation library in the following condition:
// * No sdk_version specified on the referencing module.
// * The referencing module is in the same apex as this.
- if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) {
+ if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) {
if headerJars {
return module.HeaderJars()
} else {
@@ -1527,22 +1511,8 @@
}
for _, scope := range generatedScopes {
- stubsSourceArgs := scope.droidstubsArgsForGeneratingStubsSource
- stubsSourceModuleName := module.stubsSourceModuleName(scope)
-
- // If the args needed to generate the stubs and API are the same then they
- // can be generated in a single invocation of metalava, otherwise they will
- // need separate invocations.
- if scope.createStubsSourceAndApiTogether {
- // Use the stubs source name for legacy reasons.
- module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, true, stubsSourceArgs)
- } else {
- module.createStubsSourcesAndApi(mctx, scope, stubsSourceModuleName, true, false, stubsSourceArgs)
-
- apiArgs := scope.droidstubsArgsForGeneratingApi
- apiName := module.apiModuleName(scope)
- module.createStubsSourcesAndApi(mctx, scope, apiName, false, true, apiArgs)
- }
+ // Use the stubs source name for legacy reasons.
+ module.createStubsSourcesAndApi(mctx, scope, module.stubsSourceModuleName(scope), scope.droidstubsArgs)
module.createStubsLibrary(mctx, scope)
}
@@ -1614,31 +1584,6 @@
var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
-type frameworkModulesNamingScheme struct {
-}
-
-func (s *frameworkModulesNamingScheme) moduleSuffix(scope *apiScope) string {
- suffix := scope.name
- if scope == apiScopeModuleLib {
- suffix = "module_libs_"
- }
- return suffix
-}
-
-func (s *frameworkModulesNamingScheme) stubsLibraryModuleName(scope *apiScope, baseName string) string {
- return fmt.Sprintf("%s-stubs-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-func (s *frameworkModulesNamingScheme) stubsSourceModuleName(scope *apiScope, baseName string) string {
- return fmt.Sprintf("%s-stubs-srcs-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-func (s *frameworkModulesNamingScheme) apiModuleName(scope *apiScope, baseName string) string {
- return fmt.Sprintf("%s-api-%sapi", baseName, s.moduleSuffix(scope))
-}
-
-var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil)
-
func moduleStubLinkType(name string) (stub bool, ret linkType) {
// This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
@@ -1831,7 +1776,7 @@
func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
// If the build is configured to use prebuilts then force this to be preferred.
- if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
+ if mctx.Config().AlwaysUsePrebuiltSdks() {
module.prebuilt.ForcePrefer()
}
@@ -1889,20 +1834,26 @@
props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
}
-func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+// Add the dependencies on the child module in the component deps mutator so that it
+// creates references to the prebuilt and not the source modules.
+func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
for apiScope, scopeProperties := range module.scopeProperties {
if len(scopeProperties.Jars) == 0 {
continue
}
// Add dependencies to the prebuilt stubs library
- ctx.AddVariationDependencies(nil, apiScope.stubsTag, module.stubsLibraryModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsTag, "prebuilt_"+module.stubsLibraryModuleName(apiScope))
if len(scopeProperties.Stub_srcs) > 0 {
// Add dependencies to the prebuilt stubs source library
- ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
+ ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, "prebuilt_"+module.stubsSourceModuleName(apiScope))
}
}
+}
+
+// Add other dependencies as normal.
+func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
implName := module.implLibraryModuleName()
if ctx.OtherModuleExists(implName) {
@@ -1927,6 +1878,11 @@
return false
}
+func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // we don't check prebuilt modules for sdk_version
+ return nil
+}
+
func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
return module.commonOutputFiles(tag)
}
@@ -1976,7 +1932,7 @@
// For consistency with SdkLibrary make the implementation jar available to libraries that
// are within the same APEX.
implLibraryModule := module.implLibraryModule
- if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) {
+ if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) {
if headerJars {
return implLibraryModule.HeaderJars()
} else {
@@ -1999,12 +1955,21 @@
return module.sdkJars(ctx, sdkVersion, false)
}
-// to satisfy apex.javaDependency interface
-func (module *SdkLibraryImport) DexJar() android.Path {
+// to satisfy SdkLibraryDependency interface
+func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
if module.implLibraryModule == nil {
return nil
} else {
- return module.implLibraryModule.DexJar()
+ return module.implLibraryModule.DexJarBuildPath()
+ }
+}
+
+// to satisfy SdkLibraryDependency interface
+func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.DexJarInstallPath()
}
}
@@ -2083,6 +2048,17 @@
return module
}
+func (module *sdkLibraryXml) UniqueApexVariations() bool {
+ // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
+ // mounted APEX, which contains the name of the APEX.
+ return true
+}
+
+// from android.PrebuiltEtcModule
+func (module *sdkLibraryXml) BaseDir() string {
+ return "etc"
+}
+
// from android.PrebuiltEtcModule
func (module *sdkLibraryXml) SubDir() string {
return "permissions"
@@ -2102,11 +2078,16 @@
// do nothing
}
+func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked
+ return nil
+}
+
// File path to the runtime implementation library
func (module *sdkLibraryXml) implPath() string {
implName := proptools.String(module.properties.Lib_name)
- if apexName := module.ApexName(); apexName != "" {
- // TODO(b/146468504): ApexName() is only a soong module name, not apex name.
+ if apexName := module.ApexVariationName(); apexName != "" {
+ // TODO(b/146468504): ApexVariationName() is only a soong module name, not apex name.
// In most cases, this works fine. But when apex_name is set or override_apex is used
// this can be wrong.
return fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, implName)
diff --git a/java/sdk_test.go b/java/sdk_test.go
index 52d2df5..776069d 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -30,7 +30,6 @@
var classpathTestcases = []struct {
name string
unbundled bool
- pdk bool
moduleType string
host android.OsClass
properties string
@@ -49,27 +48,27 @@
}{
{
name: "default",
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
- java8classpath: config.DefaultLibraries,
- java9classpath: config.DefaultLibraries,
+ bootclasspath: config.StableCorePlatformBootclasspathLibraries,
+ system: config.StableCorePlatformSystemModules,
+ java8classpath: config.FrameworkLibraries,
+ java9classpath: config.FrameworkLibraries,
aidl: "-Iframework/aidl",
},
{
name: `sdk_version:"core_platform"`,
properties: `sdk_version:"core_platform"`,
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
+ bootclasspath: config.StableCorePlatformBootclasspathLibraries,
+ system: config.StableCorePlatformSystemModules,
java8classpath: []string{},
aidl: "",
},
{
name: "blank sdk version",
properties: `sdk_version: "",`,
- bootclasspath: config.DefaultBootclasspathLibraries,
- system: config.DefaultSystemModules,
- java8classpath: config.DefaultLibraries,
- java9classpath: config.DefaultLibraries,
+ bootclasspath: config.StableCorePlatformBootclasspathLibraries,
+ system: config.StableCorePlatformSystemModules,
+ java8classpath: config.FrameworkLibraries,
+ java9classpath: config.FrameworkLibraries,
aidl: "-Iframework/aidl",
},
{
@@ -139,11 +138,10 @@
},
{
- name: "core_current",
- properties: `sdk_version: "core_current",`,
- bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
- system: "core-current-stubs-system-modules",
- java9classpath: []string{"core.current.stubs"},
+ name: "core_current",
+ properties: `sdk_version: "core_current",`,
+ bootclasspath: []string{"core.current.stubs", "core-lambda-stubs"},
+ system: "core-current-stubs-system-modules",
},
{
@@ -156,9 +154,9 @@
{
name: "nostdlib system_modules",
- properties: `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
- system: "core-platform-api-stubs-system-modules",
- bootclasspath: []string{"core-platform-api-stubs-system-modules-lib"},
+ properties: `sdk_version: "none", system_modules: "stable-core-platform-api-stubs-system-modules"`,
+ system: "stable-core-platform-api-stubs-system-modules",
+ bootclasspath: []string{"stable-core-platform-api-stubs-system-modules-lib"},
java8classpath: []string{},
},
{
@@ -218,35 +216,6 @@
},
{
- name: "pdk default",
- pdk: true,
- bootclasspath: []string{`""`},
- system: "sdk_public_30_system_modules",
- java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/30/public/framework.aidl",
- },
- {
- name: "pdk current",
- pdk: true,
- properties: `sdk_version: "current",`,
- bootclasspath: []string{`""`},
- system: "sdk_public_30_system_modules",
- java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/30/public/framework.aidl",
- },
- {
- name: "pdk 29",
- pdk: true,
- properties: `sdk_version: "29",`,
- bootclasspath: []string{`""`},
- system: "sdk_public_30_system_modules",
- java8classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- java9classpath: []string{"prebuilts/sdk/30/public/android.jar", "prebuilts/sdk/tools/core-lambda-stubs.jar"},
- aidl: "-pprebuilts/sdk/30/public/framework.aidl",
- },
- {
name: "module_current",
properties: `sdk_version: "module_current",`,
bootclasspath: []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
@@ -385,9 +354,7 @@
config := testConfig(nil, bpJava8, nil)
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
}
ctx := testContext()
run(t, ctx, config)
@@ -408,9 +375,7 @@
config := testConfig(nil, bp, nil)
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
}
ctx := testContext()
run(t, ctx, config)
@@ -434,9 +399,7 @@
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
}
ctx := testContext()
run(t, ctx, config)
@@ -452,9 +415,7 @@
if testcase.unbundled {
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
- }
- if testcase.pdk {
- config.TestProductVariables.Pdk = proptools.BoolPtr(true)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(true)
}
ctx := testContext()
run(t, ctx, config)
diff --git a/java/testing.go b/java/testing.go
index 48e449f..322dc9e 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -16,9 +16,15 @@
import (
"fmt"
+ "reflect"
+ "sort"
+ "testing"
"android/soong/android"
"android/soong/cc"
+ "android/soong/python"
+
+ "github.com/google/blueprint"
)
func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config {
@@ -38,6 +44,9 @@
"prebuilts/sdk/17/public/android.jar": nil,
"prebuilts/sdk/17/public/framework.aidl": nil,
"prebuilts/sdk/17/system/android.jar": nil,
+ "prebuilts/sdk/28/public/android.jar": nil,
+ "prebuilts/sdk/28/public/framework.aidl": nil,
+ "prebuilts/sdk/28/system/android.jar": nil,
"prebuilts/sdk/29/public/android.jar": nil,
"prebuilts/sdk/29/public/framework.aidl": nil,
"prebuilts/sdk/29/system/android.jar": nil,
@@ -81,12 +90,15 @@
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
"prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
+ "bin.py": nil,
+ python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
+ MAIN_FILE = '%main%'`),
+
// For java_sdk_library
- "api/module-lib-current.txt": nil,
- "api/module-lib-removed.txt": nil,
- "api/system-server-current.txt": nil,
- "api/system-server-removed.txt": nil,
- "build/soong/scripts/gen-java-current-api-files.sh": nil,
+ "api/module-lib-current.txt": nil,
+ "api/module-lib-removed.txt": nil,
+ "api/system-server-current.txt": nil,
+ "api/system-server-removed.txt": nil,
}
cc.GatherRequiredFilesForTest(mockFS)
@@ -118,7 +130,8 @@
"android_module_lib_stubs_current",
"android_system_server_stubs_current",
"core.current.stubs",
- "core.platform.api.stubs",
+ "legacy.core.platform.api.stubs",
+ "stable.core.platform.api.stubs",
"kotlin-stdlib",
"kotlin-stdlib-jdk7",
"kotlin-stdlib-jdk8",
@@ -131,7 +144,8 @@
name: "%s",
srcs: ["a.java"],
sdk_version: "none",
- system_modules: "core-platform-api-stubs-system-modules",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
+ compile_dex: true,
}
`, extra)
}
@@ -141,7 +155,7 @@
name: "framework",
srcs: ["a.java"],
sdk_version: "none",
- system_modules: "core-platform-api-stubs-system-modules",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
aidl: {
export_include_dirs: ["framework/aidl"],
},
@@ -156,7 +170,7 @@
name: "android.hidl.base-V1.0-java",
srcs: ["a.java"],
sdk_version: "none",
- system_modules: "core-platform-api-stubs-system-modules",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
installable: true,
}
@@ -164,7 +178,7 @@
name: "android.hidl.manager-V1.0-java",
srcs: ["a.java"],
sdk_version: "none",
- system_modules: "core-platform-api-stubs-system-modules",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
installable: true,
}
@@ -172,14 +186,31 @@
name: "org.apache.http.legacy",
srcs: ["a.java"],
sdk_version: "none",
- system_modules: "core-platform-api-stubs-system-modules",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
+ installable: true,
+ }
+
+ java_library {
+ name: "android.test.base",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
+ installable: true,
+ }
+
+ java_library {
+ name: "android.test.mock",
+ srcs: ["a.java"],
+ sdk_version: "none",
+ system_modules: "stable-core-platform-api-stubs-system-modules",
installable: true,
}
`
systemModules := []string{
"core-current-stubs-system-modules",
- "core-platform-api-stubs-system-modules",
+ "legacy-core-platform-api-stubs-system-modules",
+ "stable-core-platform-api-stubs-system-modules",
}
for _, extra := range systemModules {
@@ -198,3 +229,17 @@
return bp
}
+
+func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
+ t.Helper()
+ module := ctx.ModuleForTests(name, variant).Module()
+ deps := []string{}
+ ctx.VisitDirectDeps(module, func(m blueprint.Module) {
+ deps = append(deps, m.Name())
+ })
+ sort.Strings(deps)
+
+ if actual := deps; !reflect.DeepEqual(expected, actual) {
+ t.Errorf("expected %#q, found %#q", expected, actual)
+ }
+}
diff --git a/phony/phony.go b/phony/phony.go
index 305a434..cb60b9f 100644
--- a/phony/phony.go
+++ b/phony/phony.go
@@ -44,11 +44,6 @@
p.requiredModuleNames = ctx.RequiredModuleNames()
p.hostRequiredModuleNames = ctx.HostRequiredModuleNames()
p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames()
- if len(p.requiredModuleNames) == 0 &&
- len(p.hostRequiredModuleNames) == 0 && len(p.targetRequiredModuleNames) == 0 {
- ctx.PropertyErrorf("required", "phony must not have empty required dependencies "+
- "in order to be useful(and therefore permitted).")
- }
}
func (p *phony) AndroidMk() android.AndroidMkData {
diff --git a/python/binary.go b/python/binary.go
index 695fa12..5a74926 100644
--- a/python/binary.go
+++ b/python/binary.go
@@ -65,7 +65,7 @@
}
var (
- stubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
+ StubTemplateHost = "build/soong/python/scripts/stub_template_host.txt"
)
func NewBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator) {
diff --git a/python/builder.go b/python/builder.go
index 36baecd..dc2d1f1 100644
--- a/python/builder.go
+++ b/python/builder.go
@@ -91,7 +91,7 @@
if !embeddedLauncher {
// the path of stub_template_host.txt from source tree.
- template := android.PathForSource(ctx, stubTemplateHost)
+ template := android.PathForSource(ctx, StubTemplateHost)
implicits = append(implicits, template)
// intermediate output path for __main__.py
diff --git a/python/python.go b/python/python.go
index 8b912be..479c729 100644
--- a/python/python.go
+++ b/python/python.go
@@ -30,9 +30,11 @@
)
func init() {
- android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
- })
+ android.PreDepsMutators(RegisterPythonPreDepsMutators)
+}
+
+func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
}
// the version properties that apply to python libraries and binaries.
@@ -226,15 +228,20 @@
return func(mctx android.BottomUpMutatorContext) {
if base, ok := mctx.Module().(*Module); ok {
versionNames := []string{}
- if base.properties.Version.Py2.Enabled != nil &&
- *(base.properties.Version.Py2.Enabled) == true {
- versionNames = append(versionNames, pyVersion2)
- }
+ // PY3 is first so that we alias the PY3 variant rather than PY2 if both
+ // are available
if !(base.properties.Version.Py3.Enabled != nil &&
*(base.properties.Version.Py3.Enabled) == false) {
versionNames = append(versionNames, pyVersion3)
}
+ if base.properties.Version.Py2.Enabled != nil &&
+ *(base.properties.Version.Py2.Enabled) == true {
+ versionNames = append(versionNames, pyVersion2)
+ }
modules := mctx.CreateVariations(versionNames...)
+ if len(versionNames) > 0 {
+ mctx.AliasVariation(versionNames[0])
+ }
for i, v := range versionNames {
// set the actual version for Python module.
modules[i].(*Module).properties.Actual_version = v
@@ -251,6 +258,18 @@
return android.OptionalPathForPath(p.installer.(*binaryDecorator).path)
}
+func (p *Module) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ if outputFile := p.installSource; outputFile.Valid() {
+ return android.Paths{outputFile.Path()}, nil
+ }
+ return android.Paths{}, nil
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
+}
+
func (p *Module) isEmbeddedLauncherEnabled(actual_version string) bool {
switch actual_version {
case pyVersion2:
diff --git a/python/python_test.go b/python/python_test.go
index 1245ca1..23db24e 100644
--- a/python/python_test.go
+++ b/python/python_test.go
@@ -301,7 +301,7 @@
filepath.Join("dir", "file2.py"): nil,
filepath.Join("dir", "bin.py"): nil,
filepath.Join("dir", "file4.py"): nil,
- stubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
+ StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
MAIN_FILE = '%main%'`),
},
expectedBinaries: []pyModule{
@@ -330,9 +330,7 @@
t.Run(d.desc, func(t *testing.T) {
config := android.TestConfig(buildDir, nil, "", d.mockFiles)
ctx := android.NewTestContext()
- ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("version_split", versionSplitMutator()).Parallel()
- })
+ ctx.PreDepsMutators(RegisterPythonPreDepsMutators)
ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory)
ctx.RegisterModuleType("python_binary_host", PythonBinaryHostFactory)
ctx.RegisterModuleType("python_defaults", defaultsFactory)
diff --git a/rust/Android.bp b/rust/Android.bp
index 24fd830..8618207 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -9,21 +9,35 @@
],
srcs: [
"androidmk.go",
- "compiler.go",
"binary.go",
+ "bindgen.go",
"builder.go",
+ "clippy.go",
+ "compiler.go",
+ "coverage.go",
"library.go",
"prebuilt.go",
"proc_macro.go",
+ "project_json.go",
+ "protobuf.go",
"rust.go",
+ "strip.go",
+ "source_provider.go",
"test.go",
"testing.go",
],
testSrcs: [
"binary_test.go",
+ "bindgen_test.go",
+ "builder_test.go",
+ "clippy_test.go",
"compiler_test.go",
+ "coverage_test.go",
"library_test.go",
+ "project_json_test.go",
+ "protobuf_test.go",
"rust_test.go",
+ "source_provider_test.go",
"test_test.go",
],
pluginFor: ["soong_build"],
diff --git a/rust/OWNERS b/rust/OWNERS
index afd06e4..b5b795c 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,5 +1,5 @@
# Additional owner/reviewers for rust rules, including parent directory owners.
-per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com
+per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, mmaurer@google.com, srhines@google.com
# Limited owners/reviewers of the allowed list.
-per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
+per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, mmaurer@google.com, srhines@google.com
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 99880a8..edae0e6 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -26,18 +26,18 @@
type AndroidMkContext interface {
Name() string
Target() android.Target
- subAndroidMk(*android.AndroidMkData, interface{})
+ SubAndroidMk(*android.AndroidMkData, interface{})
}
-type subAndroidMkProvider interface {
+type SubAndroidMkProvider interface {
AndroidMk(AndroidMkContext, *android.AndroidMkData)
}
-func (mod *Module) subAndroidMk(data *android.AndroidMkData, obj interface{}) {
+func (mod *Module) SubAndroidMk(data *android.AndroidMkData, obj interface{}) {
if mod.subAndroidMkOnce == nil {
- mod.subAndroidMkOnce = make(map[subAndroidMkProvider]bool)
+ mod.subAndroidMkOnce = make(map[SubAndroidMkProvider]bool)
}
- if androidmk, ok := obj.(subAndroidMkProvider); ok {
+ if androidmk, ok := obj.(SubAndroidMkProvider); ok {
if !mod.subAndroidMkOnce[androidmk] {
mod.subAndroidMkOnce[androidmk] = true
androidmk.AndroidMk(mod, data)
@@ -46,6 +46,12 @@
}
func (mod *Module) AndroidMk() android.AndroidMkData {
+ if mod.Properties.HideFromMake {
+ return android.AndroidMkData{
+ Disabled: true,
+ }
+ }
+
ret := android.AndroidMkData{
OutputFile: mod.outputFile,
Include: "$(BUILD_SYSTEM)/soong_rust_prebuilt.mk",
@@ -70,15 +76,19 @@
},
}
- mod.subAndroidMk(&ret, mod.compiler)
-
+ if mod.compiler != nil && !mod.compiler.Disabled() {
+ mod.SubAndroidMk(&ret, mod.compiler)
+ } else if mod.sourceProvider != nil {
+ // If the compiler is disabled, this is a SourceProvider.
+ mod.SubAndroidMk(&ret, mod.sourceProvider)
+ }
ret.SubName += mod.Properties.SubName
return ret
}
func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, binary.baseCompiler)
+ ctx.SubAndroidMk(ret, binary.baseCompiler)
if binary.distFile.Valid() {
ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path())
@@ -86,14 +96,15 @@
ret.Class = "EXECUTABLES"
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", binary.unstrippedOutputFile.String())
+ if binary.coverageOutputZipFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+binary.coverageOutputZipFile.String())
+ }
})
}
func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
test.binaryDecorator.AndroidMk(ctx, ret)
ret.Class = "NATIVE_TESTS"
- ret.SubName = test.getMutatedModuleSubName(ctx.Name())
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
if len(test.Properties.Test_suites) > 0 {
fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
@@ -110,7 +121,7 @@
}
func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, library.baseCompiler)
+ ctx.SubAndroidMk(ret, library.baseCompiler)
if library.rlib() {
ret.Class = "RLIB_LIBRARIES"
@@ -127,14 +138,15 @@
}
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
- if !library.rlib() {
- fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", library.unstrippedOutputFile.String())
+ if library.coverageOutputZipFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE := "+library.coverageOutputZipFile.String())
}
+
})
}
func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
- ctx.subAndroidMk(ret, procMacro.baseCompiler)
+ ctx.SubAndroidMk(ret, procMacro.baseCompiler)
ret.Class = "PROC_MACRO_LIBRARIES"
if procMacro.distFile.Valid() {
@@ -143,13 +155,42 @@
}
+func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ outFile := sourceProvider.OutputFile
+ ret.Class = "ETC"
+ ret.OutputFile = android.OptionalPathForPath(outFile)
+ ret.SubName += sourceProvider.subName
+ ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ _, file := filepath.Split(outFile.String())
+ stem, suffix, _ := android.SplitFileExt(file)
+ fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
+ fmt.Fprintln(w, "LOCAL_MODULE_STEM := "+stem)
+ fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true")
+ })
+}
+
+func (bindgen *bindgenDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.SubAndroidMk(ret, bindgen.BaseSourceProvider)
+}
+
+func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ ctx.SubAndroidMk(ret, proto.BaseSourceProvider)
+}
+
func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
+ var unstrippedOutputFile android.OptionalPath
// Soong installation is only supported for host modules. Have Make
// installation trigger Soong installation.
if ctx.Target().Os.Class == android.Host {
ret.OutputFile = android.OptionalPathForPath(compiler.path)
+ } else if compiler.strippedOutputFile.Valid() {
+ unstrippedOutputFile = ret.OutputFile
+ ret.OutputFile = compiler.strippedOutputFile
}
ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
+ if compiler.strippedOutputFile.Valid() {
+ fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", unstrippedOutputFile)
+ }
path, file := filepath.Split(compiler.path.ToMakePath().String())
stem, suffix, _ := android.SplitFileExt(file)
fmt.Fprintln(w, "LOCAL_MODULE_SUFFIX := "+suffix)
diff --git a/rust/binary.go b/rust/binary.go
index fda056e..1d02453 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,20 +24,13 @@
}
type BinaryCompilerProperties struct {
- // path to the main source file that contains the program entry point (e.g. src/main.rs)
- Srcs []string `android:"path,arch_variant"`
-
- // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib
- // (assuming it has no dylib dependencies already)
- Prefer_dynamic *bool
}
type binaryDecorator struct {
*baseCompiler
+ stripper Stripper
- Properties BinaryCompilerProperties
- distFile android.OptionalPath
- unstrippedOutputFile android.Path
+ Properties BinaryCompilerProperties
}
var _ compiler = (*binaryDecorator)(nil)
@@ -65,10 +58,6 @@
return module, binary
}
-func (binary *binaryDecorator) preferDynamic() bool {
- return Bool(binary.Properties.Prefer_dynamic)
-}
-
func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = binary.baseCompiler.compilerFlags(ctx, flags)
@@ -81,9 +70,6 @@
"-Wl,--no-undefined-version")
}
- if binary.preferDynamic() {
- flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
- }
return flags
}
@@ -91,7 +77,7 @@
deps = binary.baseCompiler.compilerDeps(ctx, deps)
if ctx.toolchain().Bionic() {
- deps = binary.baseCompiler.bionicDeps(ctx, deps)
+ deps = bionicDeps(deps)
deps.CrtBegin = "crtbegin_dynamic"
deps.CrtEnd = "crtend_android"
}
@@ -101,20 +87,53 @@
func (binary *binaryDecorator) compilerProps() []interface{} {
return append(binary.baseCompiler.compilerProps(),
- &binary.Properties)
+ &binary.Properties,
+ &binary.stripper.StripProperties)
+}
+
+func (binary *binaryDecorator) nativeCoverage() bool {
+ return true
}
func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
-
- srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
-
+ srcPath, _ := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
outputFile := android.PathForModuleOut(ctx, fileName)
- binary.unstrippedOutputFile = outputFile
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
- TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+
+ if binary.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
+ binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+ binary.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+
+ binary.coverageFile = outputs.coverageFile
+
+ var coverageFiles android.Paths
+ if outputs.coverageFile != nil {
+ coverageFiles = append(coverageFiles, binary.coverageFile)
+ }
+ if len(deps.coverageFiles) > 0 {
+ coverageFiles = append(coverageFiles, deps.coverageFiles...)
+ }
+ binary.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, binary.getStem(ctx))
return outputFile
}
+
+func (binary *binaryDecorator) coverageOutputZipPath() android.OptionalPath {
+ return binary.coverageOutputZipFile
+}
+
+func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+ // Binaries default to dylib dependencies for device, rlib for host.
+ if ctx.Device() {
+ return dylibAutoDep
+ } else {
+ return rlibAutoDep
+ }
+}
diff --git a/rust/binary_test.go b/rust/binary_test.go
index ab2dae1..cfef57a 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -17,39 +17,112 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
-// Test that the prefer_dynamic property is handled correctly.
-func TestPreferDynamicBinary(t *testing.T) {
+// Test that rustlibs default linkage is correct for binaries.
+func TestBinaryLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ rustlibs: ["libfoo"],
+ host_supported: true,
+ }
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ host_supported: true,
+ }`)
+
+ fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+ fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
+
+ if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) {
+ t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
+ }
+
+ if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
+ t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
+ }
+}
+
+// Test that the path returned by HostToolPath is correct
+func TestHostToolPath(t *testing.T) {
ctx := testRust(t, `
rust_binary_host {
- name: "fizz-buzz-dynamic",
+ name: "fizz-buzz",
srcs: ["foo.rs"],
- prefer_dynamic: true,
- }
+ }`)
+ path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
+ if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
+ t.Errorf("wrong host tool path, expected %q got %q", w, g)
+ }
+}
+
+// Test that the flags being passed to rust_binary modules are as expected
+func TestBinaryFlags(t *testing.T) {
+ ctx := testRust(t, `
rust_binary_host {
name: "fizz-buzz",
srcs: ["foo.rs"],
}`)
fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
- fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
- // Do not compile binary modules with the --test flag.
- flags := fizzBuzzDynamic.Args["rustcFlags"]
+ flags := fizzBuzz.Args["rustcFlags"]
if strings.Contains(flags, "--test") {
t.Errorf("extra --test flag, rustcFlags: %#v", flags)
}
- if !strings.Contains(flags, "prefer-dynamic") {
- t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags)
+}
+
+func TestLinkObjects(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ shared_libs: ["libfoo"],
+ }
+ cc_library {
+ name: "libfoo",
+ }`)
+
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz")
+ linkFlags := fizzBuzz.Args["linkFlags"]
+ if !strings.Contains(linkFlags, "/libfoo.so") {
+ t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
+ }
+}
+
+// Test that stripped versions are correctly generated and used.
+func TestStrippedBinary(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "foo",
+ srcs: ["foo.rs"],
+ }
+ rust_binary {
+ name: "bar",
+ srcs: ["foo.rs"],
+ strip: {
+ none: true
+ }
+ }
+ `)
+
+ foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a")
+ foo.Output("stripped/foo")
+ // Check that the `cp` rules is using the stripped version as input.
+ cp := foo.Rule("android.Cp")
+ if !strings.HasSuffix(cp.Input.String(), "stripped/foo") {
+ t.Errorf("installed binary not based on stripped version: %v", cp.Input)
}
- flags = fizzBuzz.Args["rustcFlags"]
- if strings.Contains(flags, "--test") {
- t.Errorf("extra --test flag, rustcFlags: %#v", flags)
- }
- if strings.Contains(flags, "prefer-dynamic") {
- t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags)
+ fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("stripped/bar")
+ if fizzBar.Rule != nil {
+ t.Errorf("stripped version of bar has been generated")
}
}
diff --git a/rust/bindgen.go b/rust/bindgen.go
new file mode 100644
index 0000000..cafdb8b
--- /dev/null
+++ b/rust/bindgen.go
@@ -0,0 +1,203 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+)
+
+var (
+ defaultBindgenFlags = []string{""}
+
+ // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures.
+ bindgenClangVersion = "clang-r383902c"
+
+ //TODO(b/160803703) Use a prebuilt bindgen instead of the built bindgen.
+ _ = pctx.SourcePathVariable("bindgenCmd", "out/host/${config.HostPrebuiltTag}/bin/bindgen")
+ _ = pctx.SourcePathVariable("bindgenClang",
+ "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/bin/clang")
+ _ = pctx.SourcePathVariable("bindgenLibClang",
+ "${cc_config.ClangBase}/${config.HostPrebuiltTag}/"+bindgenClangVersion+"/lib64/")
+
+ //TODO(ivanlozano) Switch this to RuleBuilder
+ bindgen = pctx.AndroidStaticRule("bindgen",
+ blueprint.RuleParams{
+ Command: "CLANG_PATH=$bindgenClang LIBCLANG_PATH=$bindgenLibClang RUSTFMT=${config.RustBin}/rustfmt " +
+ "$cmd $flags $in -o $out -- -MD -MF $out.d $cflags",
+ CommandDeps: []string{"$cmd"},
+ Deps: blueprint.DepsGCC,
+ Depfile: "$out.d",
+ },
+ "cmd", "flags", "cflags")
+)
+
+func init() {
+ android.RegisterModuleType("rust_bindgen", RustBindgenFactory)
+ android.RegisterModuleType("rust_bindgen_host", RustBindgenHostFactory)
+}
+
+var _ SourceProvider = (*bindgenDecorator)(nil)
+
+type BindgenProperties struct {
+ // The wrapper header file
+ Wrapper_src *string `android:"path,arch_variant"`
+
+ // list of bindgen-specific flags and options
+ Bindgen_flags []string `android:"arch_variant"`
+
+ // list of clang flags required to correctly interpret the headers.
+ Cflags []string `android:"arch_variant"`
+
+ // list of directories relative to the Blueprints file that will
+ // be added to the include path using -I
+ Local_include_dirs []string `android:"arch_variant,variant_prepend"`
+
+ // list of static libraries that provide headers for this binding.
+ Static_libs []string `android:"arch_variant,variant_prepend"`
+
+ // list of shared libraries that provide headers for this binding.
+ Shared_libs []string `android:"arch_variant"`
+
+ // module name of a custom binary/script which should be used instead of the 'bindgen' binary. This custom
+ // binary must expect arguments in a similar fashion to bindgen, e.g.
+ //
+ // "my_bindgen [flags] wrapper_header.h -o [output_path] -- [clang flags]"
+ Custom_bindgen string `android:"path"`
+
+ //TODO(b/161141999) Add support for headers from cc_library_header modules.
+}
+
+type bindgenDecorator struct {
+ *BaseSourceProvider
+
+ Properties BindgenProperties
+}
+
+func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
+ ccToolchain := ctx.RustModule().ccToolchain(ctx)
+
+ var cflags []string
+ var implicits android.Paths
+
+ implicits = append(implicits, deps.depGeneratedHeaders...)
+
+ // Default clang flags
+ cflags = append(cflags, "${cc_config.CommonClangGlobalCflags}")
+ if ctx.Device() {
+ cflags = append(cflags, "${cc_config.DeviceClangGlobalCflags}")
+ }
+
+ // Toolchain clang flags
+ cflags = append(cflags, "-target "+ccToolchain.ClangTriple())
+ cflags = append(cflags, strings.ReplaceAll(ccToolchain.ToolchainClangCflags(), "${config.", "${cc_config."))
+
+ // Dependency clang flags and include paths
+ cflags = append(cflags, deps.depClangFlags...)
+ for _, include := range deps.depIncludePaths {
+ cflags = append(cflags, "-I"+include.String())
+ }
+ for _, include := range deps.depSystemIncludePaths {
+ cflags = append(cflags, "-isystem "+include.String())
+ }
+
+ esc := proptools.NinjaAndShellEscapeList
+
+ // Module defined clang flags and include paths
+ cflags = append(cflags, esc(b.Properties.Cflags)...)
+ for _, include := range b.Properties.Local_include_dirs {
+ cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String())
+ implicits = append(implicits, android.PathForModuleSrc(ctx, include))
+ }
+
+ bindgenFlags := defaultBindgenFlags
+ bindgenFlags = append(bindgenFlags, esc(b.Properties.Bindgen_flags)...)
+
+ wrapperFile := android.OptionalPathForModuleSrc(ctx, b.Properties.Wrapper_src)
+ if !wrapperFile.Valid() {
+ ctx.PropertyErrorf("wrapper_src", "invalid path to wrapper source")
+ }
+
+ outputFile := android.PathForModuleOut(ctx, b.BaseSourceProvider.getStem(ctx)+".rs")
+
+ var cmd, cmdDesc string
+ if b.Properties.Custom_bindgen != "" {
+ cmd = ctx.GetDirectDepWithTag(b.Properties.Custom_bindgen, customBindgenDepTag).(*Module).HostToolPath().String()
+ cmdDesc = b.Properties.Custom_bindgen
+ } else {
+ cmd = "$bindgenCmd"
+ cmdDesc = "bindgen"
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: bindgen,
+ Description: strings.Join([]string{cmdDesc, wrapperFile.Path().Rel()}, " "),
+ Output: outputFile,
+ Input: wrapperFile.Path(),
+ Implicits: implicits,
+ Args: map[string]string{
+ "cmd": cmd,
+ "flags": strings.Join(bindgenFlags, " "),
+ "cflags": strings.Join(cflags, " "),
+ },
+ })
+
+ b.BaseSourceProvider.OutputFile = outputFile
+ return outputFile
+}
+
+func (b *bindgenDecorator) SourceProviderProps() []interface{} {
+ return append(b.BaseSourceProvider.SourceProviderProps(),
+ &b.Properties)
+}
+
+// rust_bindgen generates Rust FFI bindings to C libraries using bindgen given a wrapper header as the primary input.
+// Bindgen has a number of flags to control the generated source, and additional flags can be passed to clang to ensure
+// the header and generated source is appropriately handled.
+func RustBindgenFactory() android.Module {
+ module, _ := NewRustBindgen(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func RustBindgenHostFactory() android.Module {
+ module, _ := NewRustBindgen(android.HostSupported)
+ return module.Init()
+}
+
+func NewRustBindgen(hod android.HostOrDeviceSupported) (*Module, *bindgenDecorator) {
+ bindgen := &bindgenDecorator{
+ BaseSourceProvider: NewSourceProvider(),
+ Properties: BindgenProperties{},
+ }
+
+ module := NewSourceProviderModule(hod, bindgen, false)
+
+ return module, bindgen
+}
+
+func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+ deps = b.BaseSourceProvider.SourceProviderDeps(ctx, deps)
+ if ctx.toolchain().Bionic() {
+ deps = bionicDeps(deps)
+ }
+
+ deps.SharedLibs = append(deps.SharedLibs, b.Properties.Shared_libs...)
+ deps.StaticLibs = append(deps.StaticLibs, b.Properties.Static_libs...)
+ return deps
+}
diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go
new file mode 100644
index 0000000..191da9b
--- /dev/null
+++ b/rust/bindgen_test.go
@@ -0,0 +1,84 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+)
+
+func TestRustBindgen(t *testing.T) {
+ ctx := testRust(t, `
+ rust_bindgen {
+ name: "libbindgen",
+ wrapper_src: "src/any.h",
+ crate_name: "bindgen",
+ stem: "libbindgen",
+ source_stem: "bindings",
+ bindgen_flags: ["--bindgen-flag.*"],
+ cflags: ["--clang-flag()"],
+ shared_libs: ["libfoo_shared"],
+ static_libs: ["libfoo_static"],
+ }
+ cc_library_shared {
+ name: "libfoo_shared",
+ export_include_dirs: ["shared_include"],
+ }
+ cc_library_static {
+ name: "libfoo_static",
+ export_include_dirs: ["static_include"],
+ }
+ `)
+ libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
+ // Ensure that the flags are present and escaped
+ if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") {
+ t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"])
+ }
+ if !strings.Contains(libbindgen.Args["cflags"], "'--clang-flag()'") {
+ t.Errorf("missing clang cflags in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+ }
+ if !strings.Contains(libbindgen.Args["cflags"], "-Ishared_include") {
+ t.Errorf("missing shared_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+ }
+ if !strings.Contains(libbindgen.Args["cflags"], "-Istatic_include") {
+ t.Errorf("missing static_libs exported includes in rust_bindgen rule: cflags %#v", libbindgen.Args["cflags"])
+ }
+}
+
+func TestRustBindgenCustomBindgen(t *testing.T) {
+ ctx := testRust(t, `
+ rust_bindgen {
+ name: "libbindgen",
+ wrapper_src: "src/any.h",
+ crate_name: "bindgen",
+ stem: "libbindgen",
+ source_stem: "bindings",
+ custom_bindgen: "my_bindgen"
+ }
+ rust_binary_host {
+ name: "my_bindgen",
+ srcs: ["foo.rs"],
+ }
+ `)
+
+ libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a").Output("bindings.rs")
+
+ // The rule description should contain the custom binary name rather than bindgen, so checking the description
+ // should be sufficient.
+ if !strings.Contains(libbindgen.Description, "my_bindgen") {
+ t.Errorf("Custom bindgen binary %s not used for libbindgen: rule description %#v", "my_bindgen",
+ libbindgen.Description)
+ }
+}
diff --git a/rust/builder.go b/rust/builder.go
index 27eeec2..654b1e6 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -18,62 +18,102 @@
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/pathtools"
"android/soong/android"
+ "android/soong/cc"
)
var (
_ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc")
rustc = pctx.AndroidStaticRule("rustc",
blueprint.RuleParams{
- Command: "$rustcCmd " +
+ Command: "$envVars $rustcCmd " +
"-C linker=${config.RustLinker} " +
"-C link-args=\"${crtBegin} ${config.RustLinkerArgs} ${linkFlags} ${crtEnd}\" " +
- "--emit link -o $out --emit dep-info=$out.d $in ${libFlags} $rustcFlags",
+ "--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" +
+ " && grep \"^$out:\" $out.d.raw > $out.d",
CommandDeps: []string{"$rustcCmd"},
// Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633
+ // Rustc emits unneeded dependency lines for the .d and input .rs files.
+ // Those extra lines cause ninja warning:
+ // "warning: depfile has multiple output paths"
+ // For ninja, we keep/grep only the dependency rule for the rust $out file.
Deps: blueprint.DepsGCC,
Depfile: "$out.d",
},
- "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd")
+ "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars")
+
+ _ = pctx.SourcePathVariable("clippyCmd", "${config.RustBin}/clippy-driver")
+ clippyDriver = pctx.AndroidStaticRule("clippy",
+ blueprint.RuleParams{
+ Command: "$envVars $clippyCmd " +
+ // Because clippy-driver uses rustc as backend, we need to have some output even during the linting.
+ // Use the metadata output as it has the smallest footprint.
+ "--emit metadata -o $out $in ${libFlags} " +
+ "$rustcFlags $clippyFlags",
+ CommandDeps: []string{"$clippyCmd"},
+ },
+ "rustcFlags", "libFlags", "clippyFlags", "envVars")
+
+ zip = pctx.AndroidStaticRule("zip",
+ blueprint.RuleParams{
+ Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
+ CommandDeps: []string{"${SoongZipCmd}"},
+ Rspfile: "$out.rsp",
+ RspfileContent: "$in",
+ })
+
+ cp = pctx.AndroidStaticRule("cp",
+ blueprint.RuleParams{
+ Command: "cp `cat $outDir.rsp` $outDir",
+ Rspfile: "${outDir}.rsp",
+ RspfileContent: "$in",
+ },
+ "outDir")
)
+type buildOutput struct {
+ outputFile android.Path
+ coverageFile android.Path
+}
+
func init() {
-
+ pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
}
-func TransformSrcToBinary(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) {
+func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "bin", linkDirs)
}
-func TransformSrctoRlib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) {
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", includeDirs)
+func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "rlib", linkDirs)
}
-func TransformSrctoDylib(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) {
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", includeDirs)
+func TransformSrctoDylib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "dylib", linkDirs)
}
-func TransformSrctoStatic(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) {
+func TransformSrctoStatic(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "staticlib", linkDirs)
}
-func TransformSrctoShared(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, includeDirs []string) {
+func TransformSrctoShared(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, linkDirs []string) buildOutput {
flags.RustFlags = append(flags.RustFlags, "-C lto")
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", includeDirs)
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "cdylib", linkDirs)
}
-func TransformSrctoProcMacro(ctx android.ModuleContext, mainSrc android.Path, deps PathDeps,
- flags Flags, outputFile android.WritablePath, includeDirs []string) {
- transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", includeDirs)
+func TransformSrctoProcMacro(ctx ModuleContext, mainSrc android.Path, deps PathDeps,
+ flags Flags, outputFile android.WritablePath, linkDirs []string) buildOutput {
+ return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, "proc-macro", linkDirs)
}
func rustLibsToPaths(libs RustLibraries) android.Paths {
@@ -84,14 +124,19 @@
return paths
}
-func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps PathDeps, flags Flags,
- outputFile android.WritablePath, crate_type string, includeDirs []string) {
+func transformSrctoCrate(ctx ModuleContext, main android.Path, deps PathDeps, flags Flags,
+ outputFile android.WritablePath, crate_type string, linkDirs []string) buildOutput {
var inputs android.Paths
var implicits android.Paths
+ var envVars []string
+ var output buildOutput
var libFlags, rustcFlags, linkFlags []string
- crate_name := ctx.(ModuleContext).CrateName()
- targetTriple := ctx.(ModuleContext).toolchain().RustTriple()
+ var implicitOutputs android.WritablePaths
+
+ output.outputFile = outputFile
+ crate_name := ctx.RustModule().CrateName()
+ targetTriple := ctx.toolchain().RustTriple()
inputs = append(inputs, main)
@@ -106,12 +151,10 @@
rustcFlags = append(rustcFlags, "--target="+targetTriple)
linkFlags = append(linkFlags, "-target "+targetTriple)
}
- // TODO once we have static libraries in the host prebuilt .bp, this
- // should be unconditionally added.
- if !ctx.Host() {
- // If we're on a device build, do not use an implicit sysroot
- rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
- }
+
+ // Suppress an implicit sysroot
+ rustcFlags = append(rustcFlags, "--sysroot=/dev/null")
+
// Collect linker flags
linkFlags = append(linkFlags, flags.GlobalLinkFlags...)
linkFlags = append(linkFlags, flags.LinkFlags...)
@@ -127,7 +170,7 @@
libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String())
}
- for _, path := range includeDirs {
+ for _, path := range linkDirs {
libFlags = append(libFlags, "-L "+path)
}
@@ -137,23 +180,110 @@
implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...)
implicits = append(implicits, deps.StaticLibs...)
implicits = append(implicits, deps.SharedLibs...)
+
if deps.CrtBegin.Valid() {
implicits = append(implicits, deps.CrtBegin.Path(), deps.CrtEnd.Path())
}
+ if flags.Coverage {
+ var gcnoFile android.WritablePath
+ // Provide consistency with cc gcda output, see cc/builder.go init()
+ profileEmitArg := strings.TrimPrefix(cc.PwdPrefix(), "PWD=") + "/"
+
+ if outputFile.Ext() != "" {
+ gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno"))
+ rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
+ ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcda")).String())
+ } else {
+ gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno")
+ rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
+ ctx, outputFile.Base()+".gcda").String())
+ }
+
+ implicitOutputs = append(implicitOutputs, gcnoFile)
+ output.coverageFile = gcnoFile
+ }
+
+ if len(deps.SrcDeps) > 0 {
+ genSubDir := "out/"
+ moduleGenDir := android.PathForModuleOut(ctx, genSubDir)
+ var outputs android.WritablePaths
+
+ for _, genSrc := range deps.SrcDeps {
+ if android.SuffixInList(outputs.Strings(), genSubDir+genSrc.Base()) {
+ ctx.PropertyErrorf("srcs",
+ "multiple source providers generate the same filename output: "+genSrc.Base())
+ }
+ outputs = append(outputs, android.PathForModuleOut(ctx, genSubDir+genSrc.Base()))
+ }
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: cp,
+ Description: "cp " + moduleGenDir.Rel(),
+ Outputs: outputs,
+ Inputs: deps.SrcDeps,
+ Args: map[string]string{
+ "outDir": moduleGenDir.String(),
+ },
+ })
+ implicits = append(implicits, outputs.Paths()...)
+ envVars = append(envVars, "OUT_DIR=$$PWD/"+moduleGenDir.String())
+ }
+
+ if flags.Clippy {
+ clippyFile := android.PathForModuleOut(ctx, outputFile.Base()+".clippy")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: clippyDriver,
+ Description: "clippy " + main.Rel(),
+ Output: clippyFile,
+ ImplicitOutputs: nil,
+ Inputs: inputs,
+ Implicits: implicits,
+ Args: map[string]string{
+ "rustcFlags": strings.Join(rustcFlags, " "),
+ "libFlags": strings.Join(libFlags, " "),
+ "clippyFlags": strings.Join(flags.ClippyFlags, " "),
+ "envVars": strings.Join(envVars, " "),
+ },
+ })
+ // Declare the clippy build as an implicit dependency of the original crate.
+ implicits = append(implicits, clippyFile)
+ }
+
ctx.Build(pctx, android.BuildParams{
- Rule: rustc,
- Description: "rustc " + main.Rel(),
- Output: outputFile,
- Inputs: inputs,
- Implicits: implicits,
+ Rule: rustc,
+ Description: "rustc " + main.Rel(),
+ Output: outputFile,
+ ImplicitOutputs: implicitOutputs,
+ Inputs: inputs,
+ Implicits: implicits,
Args: map[string]string{
"rustcFlags": strings.Join(rustcFlags, " "),
"linkFlags": strings.Join(linkFlags, " "),
"libFlags": strings.Join(libFlags, " "),
"crtBegin": deps.CrtBegin.String(),
"crtEnd": deps.CrtEnd.String(),
+ "envVars": strings.Join(envVars, " "),
},
})
+ return output
+}
+
+func TransformCoverageFilesToZip(ctx ModuleContext,
+ covFiles android.Paths, baseName string) android.OptionalPath {
+ if len(covFiles) > 0 {
+
+ outputFile := android.PathForModuleOut(ctx, baseName+".zip")
+
+ ctx.Build(pctx, android.BuildParams{
+ Rule: zip,
+ Description: "zip " + outputFile.Base(),
+ Inputs: covFiles,
+ Output: outputFile,
+ })
+
+ return android.OptionalPathForPath(outputFile)
+ }
+ return android.OptionalPath{}
}
diff --git a/rust/builder_test.go b/rust/builder_test.go
new file mode 100644
index 0000000..5c11cb7
--- /dev/null
+++ b/rust/builder_test.go
@@ -0,0 +1,42 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import "testing"
+
+func TestSourceProviderCollision(t *testing.T) {
+ testRustError(t, "multiple source providers generate the same filename output: bindings.rs", `
+ rust_binary {
+ name: "source_collider",
+ srcs: [
+ "foo.rs",
+ ":libbindings1",
+ ":libbindings2",
+ ],
+ }
+ rust_bindgen {
+ name: "libbindings1",
+ source_stem: "bindings",
+ crate_name: "bindings1",
+ wrapper_src: "src/any.h",
+ }
+ rust_bindgen {
+ name: "libbindings2",
+ source_stem: "bindings",
+ crate_name: "bindings2",
+ wrapper_src: "src/any.h",
+ }
+ `)
+}
diff --git a/rust/clippy.go b/rust/clippy.go
new file mode 100644
index 0000000..6f0ed7f
--- /dev/null
+++ b/rust/clippy.go
@@ -0,0 +1,48 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "android/soong/rust/config"
+)
+
+type ClippyProperties struct {
+ // name of the lint set that should be used to validate this module.
+ //
+ // Possible values are "default" (for using a sensible set of lints
+ // depending on the module's location), "android" (for the strictest
+ // lint set that applies to all Android platform code), "vendor" (for a
+ // relaxed set) and "none" (to disable the execution of clippy). The
+ // default value is "default". See also the `lints` property.
+ Clippy_lints *string
+}
+
+type clippy struct {
+ Properties ClippyProperties
+}
+
+func (c *clippy) props() []interface{} {
+ return []interface{}{&c.Properties}
+}
+
+func (c *clippy) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+ enabled, lints, err := config.ClippyLintsForDir(ctx.ModuleDir(), c.Properties.Clippy_lints)
+ if err != nil {
+ ctx.PropertyErrorf("clippy_lints", err.Error())
+ }
+ flags.Clippy = enabled
+ flags.ClippyFlags = append(flags.ClippyFlags, lints)
+ return flags, deps
+}
diff --git a/rust/clippy_test.go b/rust/clippy_test.go
new file mode 100644
index 0000000..7815aab
--- /dev/null
+++ b/rust/clippy_test.go
@@ -0,0 +1,92 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "testing"
+
+ "android/soong/android"
+)
+
+func TestClippy(t *testing.T) {
+
+ bp := `
+ // foo uses the default value of clippy_lints
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ // bar forces the use of the "android" lint set
+ rust_library {
+ name: "libbar",
+ srcs: ["foo.rs"],
+ crate_name: "bar",
+ clippy_lints: "android",
+ }
+ // foobar explicitly disable clippy
+ rust_library {
+ name: "libfoobar",
+ srcs: ["foo.rs"],
+ crate_name: "foobar",
+ clippy_lints: "none",
+ }`
+
+ bp = bp + GatherRequiredDepsForTest()
+
+ fs := map[string][]byte{
+ // Reuse the same blueprint file for subdirectories.
+ "external/Android.bp": []byte(bp),
+ "hardware/Android.bp": []byte(bp),
+ }
+
+ var clippyLintTests = []struct {
+ modulePath string
+ fooFlags string
+ }{
+ {"", "${config.ClippyDefaultLints}"},
+ {"external/", ""},
+ {"hardware/", "${config.ClippyVendorLints}"},
+ }
+
+ for _, tc := range clippyLintTests {
+ t.Run("path="+tc.modulePath, func(t *testing.T) {
+
+ config := android.TestArchConfig(buildDir, nil, bp, fs)
+ ctx := CreateTestContext()
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
+ if r.Args["clippyFlags"] != tc.fooFlags {
+ t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["clippyFlags"], tc.fooFlags)
+ }
+
+ r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
+ if r.Args["clippyFlags"] != "${config.ClippyDefaultLints}" {
+ t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["clippyFlags"], "${config.ClippyDefaultLints}")
+ }
+
+ r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy")
+ if r.Rule != nil {
+ t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"])
+ }
+
+ })
+ }
+}
diff --git a/rust/compiler.go b/rust/compiler.go
index 4593165..664578d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -24,18 +24,18 @@
"android/soong/rust/config"
)
-func getEdition(compiler *baseCompiler) string {
+func (compiler *baseCompiler) edition() string {
return proptools.StringDefault(compiler.Properties.Edition, config.DefaultEdition)
}
-func getDenyWarnings(compiler *baseCompiler) bool {
- return BoolDefault(compiler.Properties.Deny_warnings, config.DefaultDenyWarnings)
-}
-
func (compiler *baseCompiler) setNoStdlibs() {
compiler.Properties.No_stdlibs = proptools.BoolPtr(true)
}
+func (compiler *baseCompiler) disableLints() {
+ compiler.Properties.Lints = proptools.StringPtr("none")
+}
+
func NewBaseCompiler(dir, dir64 string, location installLocation) *baseCompiler {
return &baseCompiler{
Properties: BaseCompilerProperties{},
@@ -50,11 +50,22 @@
const (
InstallInSystem installLocation = 0
InstallInData = iota
+
+ incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
)
type BaseCompilerProperties struct {
- // whether to pass "-D warnings" to rustc. Defaults to true.
- Deny_warnings *bool
+ // path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
+ Srcs []string `android:"path,arch_variant"`
+
+ // name of the lint set that should be used to validate this module.
+ //
+ // Possible values are "default" (for using a sensible set of lints
+ // depending on the module's location), "android" (for the strictest
+ // lint set that applies to all Android platform code), "vendor" (for
+ // a relaxed set) and "none" (for ignoring all lint warnings and
+ // errors). The default value is "default".
+ Lints *string
// flags to pass to rustc
Flags []string `android:"path,arch_variant"`
@@ -68,6 +79,9 @@
// list of rust dylib crate dependencies
Dylibs []string `android:"arch_variant"`
+ // list of rust automatic crate dependencies
+ Rustlibs []string `android:"arch_variant"`
+
// list of rust proc_macro crate dependencies
Proc_macros []string `android:"arch_variant"`
@@ -77,7 +91,10 @@
// list of C static library dependencies
Static_libs []string `android:"arch_variant"`
- // crate name, required for libraries. This must be the expected extern crate name used in source
+ // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
+ // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in
+ // source, and is required to conform to an enforced format matching library output files (if the output file is
+ // lib<someName><suffix>, the crate_name property must be <someName>).
Crate_name string `android:"arch_variant"`
// list of features to enable for this crate
@@ -100,16 +117,8 @@
}
type baseCompiler struct {
- Properties BaseCompilerProperties
- pathDeps android.Paths
- rustFlagsDeps android.Paths
- linkFlagsDeps android.Paths
- flags string
- linkFlags string
- depFlags []string
- linkDirs []string
- edition string
- src android.Path //rustc takes a single src file
+ Properties BaseCompilerProperties
+ coverageFile android.Path //rustc generates a single gcno file
// Install related
dir string
@@ -118,6 +127,27 @@
relative string
path android.InstallPath
location installLocation
+
+ coverageOutputZipFile android.OptionalPath
+ distFile android.OptionalPath
+ // Stripped output file. If Valid(), this file will be installed instead of outputFile.
+ strippedOutputFile android.OptionalPath
+}
+
+func (compiler *baseCompiler) Disabled() bool {
+ return false
+}
+
+func (compiler *baseCompiler) SetDisabled() {
+ panic("baseCompiler does not implement SetDisabled()")
+}
+
+func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
+ panic("baseCompiler does not implement coverageOutputZipPath()")
+}
+
+func (compiler *baseCompiler) static() bool {
+ return false
}
var _ compiler = (*baseCompiler)(nil)
@@ -140,12 +170,14 @@
func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags) Flags {
- if getDenyWarnings(compiler) {
- flags.RustFlags = append(flags.RustFlags, "-D warnings")
+ lintFlags, err := config.RustcLintsForDir(ctx.ModuleDir(), compiler.Properties.Lints)
+ if err != nil {
+ ctx.PropertyErrorf("lints", err.Error())
}
+ flags.RustFlags = append(flags.RustFlags, lintFlags)
flags.RustFlags = append(flags.RustFlags, compiler.Properties.Flags...)
flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(compiler.Properties.Features)...)
- flags.RustFlags = append(flags.RustFlags, "--edition="+getEdition(compiler))
+ flags.RustFlags = append(flags.RustFlags, "--edition="+compiler.edition())
flags.LinkFlags = append(flags.LinkFlags, compiler.Properties.Ld_flags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, config.GlobalRustFlags...)
flags.GlobalRustFlags = append(flags.GlobalRustFlags, ctx.toolchain().ToolchainRustFlags())
@@ -177,23 +209,25 @@
func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps {
deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...)
deps.Dylibs = append(deps.Dylibs, compiler.Properties.Dylibs...)
+ deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs...)
deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...)
deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
if !Bool(compiler.Properties.No_stdlibs) {
for _, stdlib := range config.Stdlibs {
- // If we're building for host, use the compiler's stdlibs
- if ctx.Host() {
+ // If we're building for the primary arch of the build host, use the compiler's stdlibs
+ if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() {
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
- // This check is technically insufficient - on the host, where
- // static linking is the default, if one of our static
- // dependencies uses a dynamic library, we need to dynamically
- // link the stdlib as well.
- if (len(deps.Dylibs) > 0) || (!ctx.Host()) {
- // Dynamically linked stdlib
+ // For devices, we always link stdlibs in as dylibs except for ffi static libraries.
+ // (rustc does not support linking libstd as a dylib for ffi static libraries)
+ if ctx.Host() {
+ deps.Rustlibs = append(deps.Rustlibs, stdlib)
+ } else if ctx.RustModule().compiler.static() {
+ deps.Rlibs = append(deps.Rlibs, stdlib)
+ } else {
deps.Dylibs = append(deps.Dylibs, stdlib)
}
}
@@ -201,7 +235,7 @@
return deps
}
-func (compiler *baseCompiler) bionicDeps(ctx DepsContext, deps Deps) Deps {
+func bionicDeps(deps Deps) Deps {
deps.SharedLibs = append(deps.SharedLibs, "liblog")
deps.SharedLibs = append(deps.SharedLibs, "libc")
deps.SharedLibs = append(deps.SharedLibs, "libm")
@@ -222,15 +256,26 @@
if ctx.toolchain().Is64Bit() && compiler.dir64 != "" {
dir = compiler.dir64
}
- if !ctx.Host() || ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+ dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
+ }
+ if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
dir = filepath.Join(dir, ctx.Arch().ArchType.String())
}
return android.PathForModuleInstall(ctx, dir, compiler.subDir,
compiler.relativeInstallPath(), compiler.relative)
}
-func (compiler *baseCompiler) install(ctx ModuleContext, file android.Path) {
- compiler.path = ctx.InstallFile(compiler.installDir(ctx), file.Base(), file)
+func (compiler *baseCompiler) nativeCoverage() bool {
+ return false
+}
+
+func (compiler *baseCompiler) install(ctx ModuleContext) {
+ path := ctx.RustModule().outputFile
+ if compiler.strippedOutputFile.Valid() {
+ path = compiler.strippedOutputFile
+ }
+ compiler.path = ctx.InstallFile(compiler.installDir(ctx), path.Path().Base(), path.Path())
}
func (compiler *baseCompiler) getStem(ctx ModuleContext) string {
@@ -238,7 +283,7 @@
}
func (compiler *baseCompiler) getStemWithoutSuffix(ctx BaseModuleContext) string {
- stem := ctx.baseModuleName()
+ stem := ctx.ModuleName()
if String(compiler.Properties.Stem) != "" {
stem = String(compiler.Properties.Stem)
}
@@ -250,10 +295,25 @@
return String(compiler.Properties.Relative_install_path)
}
-func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path {
- srcPaths := android.PathsForModuleSrc(ctx, srcs)
- if len(srcPaths) != 1 {
- ctx.PropertyErrorf("srcs", "srcs can only contain one path for rust modules")
+// Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs.
+func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, android.Paths) {
+ // The srcs can contain strings with prefix ":".
+ // They are dependent modules of this module, with android.SourceDepTag.
+ // They are not the main source file compiled by rustc.
+ numSrcs := 0
+ srcIndex := 0
+ for i, s := range srcs {
+ if android.SrcIsModule(s) == "" {
+ numSrcs++
+ srcIndex = i
+ }
}
- return srcPaths[0]
+ if numSrcs != 1 {
+ ctx.PropertyErrorf("srcs", incorrectSourcesError)
+ }
+ if srcIndex != 0 {
+ ctx.PropertyErrorf("srcs", "main source file must be the first in srcs")
+ }
+ paths := android.PathsForModuleSrc(ctx, srcs)
+ return paths[srcIndex], paths[1:]
}
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index bbf9f8d..56a8ef8 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -17,6 +17,8 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
// Test that feature flags are being correctly generated.
@@ -43,7 +45,7 @@
// Test that we reject multiple source files.
func TestEnforceSingleSourceFile(t *testing.T) {
- singleSrcError := "srcs can only contain one path for rust modules"
+ singleSrcError := "srcs can only contain one path for a rust file and source providers prefixed by \":\""
// Test libraries
testRustError(t, singleSrcError, `
@@ -74,3 +76,131 @@
host_supported: true,
}`)
}
+
+func TestInstallDir(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_dylib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ rust_binary {
+ name: "fizzbuzz",
+ srcs: ["foo.rs"],
+ }`)
+
+ install_path_lib64 := ctx.ModuleForTests("libfoo",
+ "android_arm64_armv8-a_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String()
+ install_path_lib32 := ctx.ModuleForTests("libfoo",
+ "android_arm_armv7-a-neon_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String()
+ install_path_bin := ctx.ModuleForTests("fizzbuzz",
+ "android_arm64_armv8-a").Module().(*Module).compiler.(*binaryDecorator).path.String()
+
+ if !strings.HasSuffix(install_path_lib64, "system/lib64/libfoo.dylib.so") {
+ t.Fatalf("unexpected install path for 64-bit library: %#v", install_path_lib64)
+ }
+ if !strings.HasSuffix(install_path_lib32, "system/lib/libfoo.dylib.so") {
+ t.Fatalf("unexpected install path for 32-bit library: %#v", install_path_lib32)
+ }
+ if !strings.HasSuffix(install_path_bin, "system/bin/fizzbuzz") {
+ t.Fatalf("unexpected install path for binary: %#v", install_path_bin)
+ }
+}
+
+func TestLints(t *testing.T) {
+
+ bp := `
+ // foo uses the default value of lints
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ // bar forces the use of the "android" lint set
+ rust_library {
+ name: "libbar",
+ srcs: ["foo.rs"],
+ crate_name: "bar",
+ lints: "android",
+ }
+ // foobar explicitly disable all lints
+ rust_library {
+ name: "libfoobar",
+ srcs: ["foo.rs"],
+ crate_name: "foobar",
+ lints: "none",
+ }`
+
+ bp = bp + GatherRequiredDepsForTest()
+
+ fs := map[string][]byte{
+ // Reuse the same blueprint file for subdirectories.
+ "external/Android.bp": []byte(bp),
+ "hardware/Android.bp": []byte(bp),
+ }
+
+ var lintTests = []struct {
+ modulePath string
+ fooFlags string
+ }{
+ {"", "${config.RustDefaultLints}"},
+ {"external/", "${config.RustAllowAllLints}"},
+ {"hardware/", "${config.RustVendorLints}"},
+ }
+
+ for _, tc := range lintTests {
+ t.Run("path="+tc.modulePath, func(t *testing.T) {
+
+ config := android.TestArchConfig(buildDir, nil, bp, fs)
+ ctx := CreateTestContext()
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
+ if !strings.Contains(r.Args["rustcFlags"], tc.fooFlags) {
+ t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["rustcFlags"], tc.fooFlags)
+ }
+
+ r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
+ if !strings.Contains(r.Args["rustcFlags"], "${config.RustDefaultLints}") {
+ t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["rustcFlags"], "${config.RustDefaultLints}")
+ }
+
+ r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc")
+ if !strings.Contains(r.Args["rustcFlags"], "${config.RustAllowAllLints}") {
+ t.Errorf("Incorrect flags for libfoobar: %q, want %q", r.Args["rustcFlags"], "${config.RustAllowAllLints}")
+ }
+
+ })
+ }
+}
+
+// Test that devices are linking the stdlib dynamically
+func TestStdDeviceLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz",
+ srcs: ["foo.rs"],
+ }
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+ fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
+ fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module)
+ fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
+
+ if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for device binaries")
+ }
+ if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for rlibs")
+ }
+ if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for dylibs")
+ }
+}
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 5026da3..e0cc4ce 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -9,11 +9,13 @@
"arm_device.go",
"arm64_device.go",
"global.go",
+ "lints.go",
"toolchain.go",
"allowed_list.go",
"x86_darwin_host.go",
"x86_linux_host.go",
"x86_device.go",
"x86_64_device.go",
+ "arm64_linux_host.go",
],
}
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index a339050..62d469e 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -6,7 +6,11 @@
"external/rust",
"external/crosvm",
"external/adhd",
+ "frameworks/native/libs/binder/rust",
"prebuilts/rust",
+ "system/extras/profcollectd",
+ "system/security",
+ "system/tools/aidl",
}
RustModuleTypes = []string{
@@ -15,13 +19,15 @@
"rust_library",
"rust_library_dylib",
"rust_library_rlib",
- "rust_library_shared",
- "rust_library_static",
+ "rust_ffi",
+ "rust_ffi_shared",
+ "rust_ffi_static",
"rust_library_host",
"rust_library_host_dylib",
"rust_library_host_rlib",
- "rust_library_host_shared",
- "rust_library_host_static",
+ "rust_ffi_host",
+ "rust_ffi_host_shared",
+ "rust_ffi_host_static",
"rust_proc_macro",
"rust_test",
"rust_test_host",
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 60796d8..7d13c42 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -23,13 +23,7 @@
var (
Arm64RustFlags = []string{}
Arm64ArchFeatureRustFlags = map[string][]string{}
- Arm64LinkFlags = []string{
- "-Wl,--icf=safe",
- "-Wl,-z,max-page-size=4096",
-
- "-Wl,--execute-only",
- "-Wl,-z,separate-code",
- }
+ Arm64LinkFlags = []string{}
Arm64ArchVariantRustFlags = map[string][]string{
"armv8-a": []string{},
@@ -60,7 +54,8 @@
}
func (t *toolchainArm64) ToolchainLinkFlags() string {
- return "${config.DeviceGlobalLinkFlags} ${config.Arm64ToolchainLinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${config.DeviceGlobalLinkFlags} ${cc_config.Arm64Lldflags} ${config.Arm64ToolchainLinkFlags}"
}
func (t *toolchainArm64) ToolchainRustFlags() string {
@@ -76,9 +71,16 @@
}
func Arm64ToolchainFactory(arch android.Arch) Toolchain {
+ archVariant := arch.ArchVariant
+ if archVariant == "" {
+ // arch variants defaults to armv8-a. This is mostly for
+ // the host target which borrows toolchain configs from here.
+ archVariant = "armv8-a"
+ }
+
toolchainRustFlags := []string{
"${config.Arm64ToolchainRustFlags}",
- "${config.Arm64" + arch.ArchVariant + "VariantRustFlags}",
+ "${config.Arm64" + archVariant + "VariantRustFlags}",
}
toolchainRustFlags = append(toolchainRustFlags, deviceGlobalRustFlags...)
diff --git a/rust/config/arm64_linux_host.go b/rust/config/arm64_linux_host.go
new file mode 100644
index 0000000..baf9cf8
--- /dev/null
+++ b/rust/config/arm64_linux_host.go
@@ -0,0 +1,24 @@
+// Copyright 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+ "android/soong/android"
+)
+
+func init() {
+ // Linux_cross-arm64 uses the same rust toolchain as the Android-arm64
+ registerToolchainFactory(android.LinuxBionic, android.Arm64, Arm64ToolchainFactory)
+}
diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go
index aedb42b..ac4f1c6 100644
--- a/rust/config/arm_device.go
+++ b/rust/config/arm_device.go
@@ -23,10 +23,7 @@
var (
ArmRustFlags = []string{}
ArmArchFeatureRustFlags = map[string][]string{}
- ArmLinkFlags = []string{
- "-Wl,--icf=safe",
- "-Wl,-m,armelf",
- }
+ ArmLinkFlags = []string{}
ArmArchVariantRustFlags = map[string][]string{
"armv7-a": []string{},
@@ -50,7 +47,7 @@
}
type toolchainArm struct {
- toolchain64Bit
+ toolchain32Bit
toolchainRustFlags string
}
@@ -59,7 +56,8 @@
}
func (t *toolchainArm) ToolchainLinkFlags() string {
- return "${config.DeviceGlobalLinkFlags} ${config.ArmToolchainLinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${config.DeviceGlobalLinkFlags} ${cc_config.ArmLldflags} ${config.ArmToolchainLinkFlags}"
}
func (t *toolchainArm) ToolchainRustFlags() string {
diff --git a/rust/config/global.go b/rust/config/global.go
index 690d83e..6a5251b 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.40.0"
+ RustDefaultVersion = "1.45.2"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
@@ -32,8 +32,6 @@
"libtest",
}
- DefaultDenyWarnings = true
-
GlobalRustFlags = []string{
"--remap-path-prefix $$(pwd)=",
"-C codegen-units=1",
@@ -44,18 +42,18 @@
deviceGlobalRustFlags = []string{}
deviceGlobalLinkFlags = []string{
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ "${cc_config.DeviceGlobalLldflags}",
+
+ // Override cc's --no-undefined-version to allow rustc's generated alloc functions
+ "-Wl,--undefined-version",
+
"-Bdynamic",
"-nostdlib",
- "-Wl,-z,noexecstack",
- "-Wl,-z,relro",
- "-Wl,-z,now",
- "-Wl,--build-id=md5",
- "-Wl,--warn-shared-textrel",
- "-Wl,--fatal-warnings",
-
"-Wl,--pack-dyn-relocs=android+relr",
+ "-Wl,--use-android-relr-tags",
"-Wl,--no-undefined",
- "-Wl,--hash-style=gnu",
+ "-B${cc_config.ClangBin}",
}
)
@@ -80,9 +78,9 @@
pctx.StaticVariable("RustPath", "${RustBase}/${HostPrebuiltTag}/${RustVersion}")
pctx.StaticVariable("RustBin", "${RustPath}/bin")
- pctx.ImportAs("ccConfig", "android/soong/cc/config")
- pctx.StaticVariable("RustLinker", "${ccConfig.ClangBin}/clang++")
- pctx.StaticVariable("RustLinkerArgs", "-B ${ccConfig.ClangBin} -fuse-ld=lld")
+ pctx.ImportAs("cc_config", "android/soong/cc/config")
+ pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++")
+ pctx.StaticVariable("RustLinkerArgs", "")
pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " "))
diff --git a/rust/config/lints.go b/rust/config/lints.go
new file mode 100644
index 0000000..06bb668
--- /dev/null
+++ b/rust/config/lints.go
@@ -0,0 +1,190 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+ "fmt"
+ "strings"
+
+ "android/soong/android"
+)
+
+// Overarching principles for Rust lints on Android:
+// The Android build system tries to avoid reporting warnings during the build.
+// Therefore, by default, we upgrade warnings to denials. For some of these
+// lints, an allow exception is setup, using the variables below.
+//
+// The lints are split into two categories. The first one contains the built-in
+// lints (https://doc.rust-lang.org/rustc/lints/index.html). The second is
+// specific to Clippy lints (https://rust-lang.github.io/rust-clippy/master/).
+//
+// For both categories, there are 3 levels of linting possible:
+// - "android", for the strictest lints that applies to all Android platform code.
+// - "vendor", for relaxed rules.
+// - "none", to disable the linting.
+// There is a fourth option ("default") which automatically selects the linting level
+// based on the module's location. See defaultLintSetForPath.
+//
+// When developing a module, you may set `lints = "none"` and `clippy_lints =
+// "none"` to disable all the linting. Expect some questioning during code review
+// if you enable one of these options.
+var (
+ // Default Rust lints that applies to Google-authored modules.
+ defaultRustcLints = []string{
+ "-A deprecated",
+ "-D missing-docs",
+ "-D warnings",
+ }
+ // Default Clippy lints. These are applied on top of defaultRustcLints.
+ // It should be assumed that any warning lint will be promoted to a
+ // deny.
+ defaultClippyLints = []string{
+ "-A clippy::type-complexity",
+ }
+
+ // Rust lints for vendor code.
+ defaultRustcVendorLints = []string{
+ "-A deprecated",
+ "-D warnings",
+ }
+ // Clippy lints for vendor source. These are applied on top of
+ // defaultRustcVendorLints. It should be assumed that any warning lint
+ // will be promoted to a deny.
+ defaultClippyVendorLints = []string{
+ "-A clippy::complexity",
+ "-A clippy::perf",
+ "-A clippy::style",
+ }
+
+ // For prebuilts/ and external/, no linting is expected. If a warning
+ // or a deny is reported, it should be fixed upstream.
+ allowAllLints = []string{
+ "--cap-lints allow",
+ }
+)
+
+func init() {
+ // Default Rust lints. These apply to all Google-authored modules.
+ pctx.VariableFunc("RustDefaultLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_DEFAULT_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultRustcLints, " ")
+ })
+ pctx.VariableFunc("ClippyDefaultLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_DEFAULT_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultClippyLints, " ")
+ })
+
+ // Rust lints that only applies to external code.
+ pctx.VariableFunc("RustVendorLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("RUST_VENDOR_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultRustcVendorLints, " ")
+ })
+ pctx.VariableFunc("ClippyVendorLints", func(ctx android.PackageVarContext) string {
+ if override := ctx.Config().Getenv("CLIPPY_VENDOR_LINTS"); override != "" {
+ return override
+ }
+ return strings.Join(defaultClippyVendorLints, " ")
+ })
+ pctx.StaticVariable("RustAllowAllLints", strings.Join(allowAllLints, " "))
+}
+
+const noLint = ""
+const rustcDefault = "${config.RustDefaultLints}"
+const rustcVendor = "${config.RustVendorLints}"
+const rustcAllowAll = "${config.RustAllowAllLints}"
+const clippyDefault = "${config.ClippyDefaultLints}"
+const clippyVendor = "${config.ClippyVendorLints}"
+
+// lintConfig defines a set of lints and clippy configuration.
+type lintConfig struct {
+ rustcConfig string // for the lints to apply to rustc.
+ clippyEnabled bool // to indicate if clippy should be executed.
+ clippyConfig string // for the lints to apply to clippy.
+}
+
+const (
+ androidLints = "android"
+ vendorLints = "vendor"
+ noneLints = "none"
+)
+
+// lintSets defines the categories of linting for Android and their mapping to lintConfigs.
+var lintSets = map[string]lintConfig{
+ androidLints: {rustcDefault, true, clippyDefault},
+ vendorLints: {rustcVendor, true, clippyVendor},
+ noneLints: {rustcAllowAll, false, noLint},
+}
+
+type pathLintSet struct {
+ prefix string
+ set string
+}
+
+// This is a map of local path prefixes to a lint set. The first entry
+// matching will be used. If no entry matches, androidLints ("android") will be
+// used.
+var defaultLintSetForPath = []pathLintSet{
+ {"external", noneLints},
+ {"hardware", vendorLints},
+ {"prebuilts", noneLints},
+ {"vendor/google", androidLints},
+ {"vendor", vendorLints},
+}
+
+// ClippyLintsForDir returns a boolean if Clippy should be executed and if so, the lints to be used.
+func ClippyLintsForDir(dir string, clippyLintsProperty *string) (bool, string, error) {
+ if clippyLintsProperty != nil {
+ set, ok := lintSets[*clippyLintsProperty]
+ if ok {
+ return set.clippyEnabled, set.clippyConfig, nil
+ }
+ if *clippyLintsProperty != "default" {
+ return false, "", fmt.Errorf("unknown value for `clippy_lints`: %v, valid options are: default, android, vendor or none", *clippyLintsProperty)
+ }
+ }
+ for _, p := range defaultLintSetForPath {
+ if strings.HasPrefix(dir, p.prefix) {
+ setConfig := lintSets[p.set]
+ return setConfig.clippyEnabled, setConfig.clippyConfig, nil
+ }
+ }
+ return true, clippyDefault, nil
+}
+
+// RustcLintsForDir returns the standard lints to be used for a repository.
+func RustcLintsForDir(dir string, lintProperty *string) (string, error) {
+ if lintProperty != nil {
+ set, ok := lintSets[*lintProperty]
+ if ok {
+ return set.rustcConfig, nil
+ }
+ if *lintProperty != "default" {
+ return "", fmt.Errorf("unknown value for `lints`: %v, valid options are: default, android, vendor or none", *lintProperty)
+ }
+
+ }
+ for _, p := range defaultLintSetForPath {
+ if strings.HasPrefix(dir, p.prefix) {
+ return lintSets[p.set].rustcConfig, nil
+ }
+ }
+ return rustcDefault, nil
+}
diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go
index 9a6c00b..5f6e85a 100644
--- a/rust/config/x86_64_device.go
+++ b/rust/config/x86_64_device.go
@@ -61,7 +61,8 @@
}
func (t *toolchainX86_64) ToolchainLinkFlags() string {
- return "${config.DeviceGlobalLinkFlags} ${config.X86_64ToolchainLinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${config.DeviceGlobalLinkFlags} ${cc_config.X86_64Lldflags} ${config.X86_64ToolchainLinkFlags}"
}
func (t *toolchainX86_64) ToolchainRustFlags() string {
diff --git a/rust/config/x86_darwin_host.go b/rust/config/x86_darwin_host.go
index 7cfc59c..ddd93e8 100644
--- a/rust/config/x86_darwin_host.go
+++ b/rust/config/x86_darwin_host.go
@@ -21,8 +21,10 @@
)
var (
- DarwinRustFlags = []string{}
- DarwinRustLinkFlags = []string{}
+ DarwinRustFlags = []string{}
+ DarwinRustLinkFlags = []string{
+ "-B${cc_config.MacToolPath}",
+ }
darwinX8664Rustflags = []string{}
darwinX8664Linkflags = []string{}
)
@@ -62,12 +64,21 @@
return "x86_64-apple-darwin"
}
-func (t *toolchainDarwin) ShlibSuffix() string {
+func (t *toolchainDarwin) SharedLibSuffix() string {
+ return ".dylib"
+}
+
+func (t *toolchainDarwin) DylibSuffix() string {
+ return ".rustlib.dylib"
+}
+
+func (t *toolchainDarwin) ProcMacroSuffix() string {
return ".dylib"
}
func (t *toolchainDarwinX8664) ToolchainLinkFlags() string {
- return "${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.DarwinClangLldflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}"
}
func (t *toolchainDarwinX8664) ToolchainRustFlags() string {
diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go
index ec19b3c..daeeb14 100644
--- a/rust/config/x86_device.go
+++ b/rust/config/x86_device.go
@@ -64,7 +64,8 @@
}
func (t *toolchainX86) ToolchainLinkFlags() string {
- return "${config.DeviceGlobalLinkFlags} ${config.X86ToolchainLinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${config.DeviceGlobalLinkFlags} ${cc_config.X86ClangLldflags} ${config.X86ToolchainLinkFlags}"
}
func (t *toolchainX86) ToolchainRustFlags() string {
diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go
index 5376e5b..e7f26ce 100644
--- a/rust/config/x86_linux_host.go
+++ b/rust/config/x86_linux_host.go
@@ -21,8 +21,12 @@
)
var (
- LinuxRustFlags = []string{}
- LinuxRustLinkFlags = []string{}
+ LinuxRustFlags = []string{}
+ LinuxRustLinkFlags = []string{
+ "-B${cc_config.ClangBin}",
+ "-fuse-ld=lld",
+ "-Wl,--undefined-version",
+ }
linuxX86Rustflags = []string{}
linuxX86Linkflags = []string{}
linuxX8664Rustflags = []string{}
@@ -74,7 +78,9 @@
}
func (t *toolchainLinuxX8664) ToolchainLinkFlags() string {
- return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX8664ClangLldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}"
}
func (t *toolchainLinuxX8664) ToolchainRustFlags() string {
@@ -102,7 +108,9 @@
}
func (t *toolchainLinuxX86) ToolchainLinkFlags() string {
- return "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
+ // Prepend the lld flags from cc_config so we stay in sync with cc
+ return "${cc_config.LinuxClangLldflags} ${cc_config.LinuxX86ClangLldflags} " +
+ "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}"
}
func (t *toolchainLinuxX86) ToolchainRustFlags() string {
diff --git a/rust/coverage.go b/rust/coverage.go
new file mode 100644
index 0000000..26375f5
--- /dev/null
+++ b/rust/coverage.go
@@ -0,0 +1,72 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "github.com/google/blueprint"
+
+ "android/soong/cc"
+)
+
+var CovLibraryName = "libprofile-extras"
+
+type coverage struct {
+ Properties cc.CoverageProperties
+
+ // Whether binaries containing this module need --coverage added to their ldflags
+ linkCoverage bool
+}
+
+func (cov *coverage) props() []interface{} {
+ return []interface{}{&cov.Properties}
+}
+
+func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps {
+ if cov.Properties.NeedCoverageVariant {
+ ctx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "static"},
+ }, cc.CoverageDepTag, CovLibraryName)
+ }
+
+ return deps
+}
+
+func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
+
+ if !ctx.DeviceConfig().NativeCoverageEnabled() {
+ return flags, deps
+ }
+
+ if cov.Properties.CoverageEnabled {
+ flags.Coverage = true
+ coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
+ flags.RustFlags = append(flags.RustFlags,
+ "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code")
+ flags.LinkFlags = append(flags.LinkFlags,
+ "--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
+ deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+ }
+
+ return flags, deps
+}
+
+func (cov *coverage) begin(ctx BaseModuleContext) {
+ if ctx.Host() {
+ // Host coverage not yet supported.
+ } else {
+ // Update useSdk and sdkVersion args if Rust modules become SDK aware.
+ cov.Properties = cc.SetCoverageProperties(ctx, cov.Properties, ctx.RustModule().nativeCoverage(), false, "")
+ }
+}
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
new file mode 100644
index 0000000..73673d0
--- /dev/null
+++ b/rust/coverage_test.go
@@ -0,0 +1,187 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "strings"
+ "testing"
+
+ "android/soong/android"
+)
+
+// Test that coverage flags are being correctly generated.
+func TestCoverageFlags(t *testing.T) {
+ ctx := testRustCov(t, `
+ rust_library {
+ name: "libfoo_cov",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }
+ rust_binary {
+ name: "fizz_cov",
+ srcs: ["foo.rs"],
+ }
+ rust_binary {
+ name: "buzzNoCov",
+ srcs: ["foo.rs"],
+ native_coverage: false,
+ }
+ rust_library {
+ name: "libbar_nocov",
+ srcs: ["foo.rs"],
+ crate_name: "bar",
+ native_coverage: false,
+ }`)
+
+ // Make sure native_coverage: false isn't creating a coverage variant.
+ if android.InList("android_arm64_armv8-a_dylib_cov", ctx.ModuleVariantsForTests("libbar_nocov")) {
+ t.Fatalf("coverage variant created for module 'libbar_nocov' with native coverage disabled")
+ }
+
+ // Just test the dylib variants unless the library coverage logic changes to distinguish between the types.
+ libfooCov := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc")
+ libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc")
+ fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
+ buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
+
+ rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"}
+ for _, flag := range rustcCoverageFlags {
+ missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
+ containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
+
+ if !strings.Contains(fizzCov.Args["rustcFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["rustcFlags"])
+ }
+ if !strings.Contains(libfooCov.Args["rustcFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["rustcFlags"])
+ }
+ if strings.Contains(buzzNoCov.Args["rustcFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["rustcFlags"])
+ }
+ if strings.Contains(libbarNoCov.Args["rustcFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["rustcFlags"])
+ }
+ }
+
+ linkCoverageFlags := []string{"--coverage", " -g "}
+ for _, flag := range linkCoverageFlags {
+ missingErrorStr := "missing rust linker flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
+ containsErrorStr := "contains rust linker flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
+
+ if !strings.Contains(fizzCov.Args["linkFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "fizz_cov", fizzCov.Args["linkFlags"])
+ }
+ if !strings.Contains(libfooCov.Args["linkFlags"], flag) {
+ t.Fatalf(missingErrorStr, flag, "libfoo_cov dylib", libfooCov.Args["linkFlags"])
+ }
+ if strings.Contains(buzzNoCov.Args["linkFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "buzzNoCov", buzzNoCov.Args["linkFlags"])
+ }
+ if strings.Contains(libbarNoCov.Args["linkFlags"], flag) {
+ t.Fatalf(containsErrorStr, flag, "libbar_cov", libbarNoCov.Args["linkFlags"])
+ }
+ }
+
+}
+
+// Test coverage files are included correctly
+func TestCoverageZip(t *testing.T) {
+ ctx := testRustCov(t, `
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ rlibs: ["librlib"],
+ crate_name: "foo",
+ }
+ rust_ffi_static {
+ name: "libbaz",
+ srcs: ["foo.rs"],
+ rlibs: ["librlib"],
+ crate_name: "baz",
+ }
+ rust_library_rlib {
+ name: "librlib",
+ srcs: ["foo.rs"],
+ crate_name: "rlib",
+ }
+ rust_binary {
+ name: "fizz",
+ rlibs: ["librlib"],
+ static_libs: ["libbaz"],
+ srcs: ["foo.rs"],
+ }
+ cc_binary {
+ name: "buzz",
+ static_libs: ["libbaz"],
+ srcs: ["foo.c"],
+ }
+ cc_library {
+ name: "libbar",
+ static_libs: ["libbaz"],
+ compile_multilib: "64",
+ srcs: ["foo.c"],
+ }`)
+
+ fizzZipInputs := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
+ libfooZipInputs := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib_cov").Rule("zip").Inputs.Strings()
+ buzzZipInputs := ctx.ModuleForTests("buzz", "android_arm64_armv8-a_cov").Rule("zip").Inputs.Strings()
+ libbarZipInputs := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared_cov").Rule("zip").Inputs.Strings()
+
+ // Make sure the expected number of input files are included.
+ if len(fizzZipInputs) != 3 {
+ t.Fatalf("expected only 3 coverage inputs for rust 'fizz' binary, got %#v: %#v", len(fizzZipInputs), fizzZipInputs)
+ }
+ if len(libfooZipInputs) != 2 {
+ t.Fatalf("expected only 2 coverage inputs for rust 'libfoo' library, got %#v: %#v", len(libfooZipInputs), libfooZipInputs)
+ }
+ if len(buzzZipInputs) != 2 {
+ t.Fatalf("expected only 2 coverage inputs for cc 'buzz' binary, got %#v: %#v", len(buzzZipInputs), buzzZipInputs)
+ }
+ if len(libbarZipInputs) != 2 {
+ t.Fatalf("expected only 2 coverage inputs for cc 'libbar' library, got %#v: %#v", len(libbarZipInputs), libbarZipInputs)
+ }
+
+ // Make sure the expected inputs are provided to the zip rule.
+ if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+ !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") ||
+ !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_cov/fizz.gcno") {
+ t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", fizzZipInputs)
+ }
+ if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") ||
+ !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_dylib_cov/libfoo.dylib.gcno") {
+ t.Fatalf("missing expected coverage files for rust 'fizz' binary: %#v", libfooZipInputs)
+ }
+ if !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_cov/obj/foo.gcno") ||
+ !android.SuffixInList(buzzZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
+ t.Fatalf("missing expected coverage files for cc 'buzz' binary: %#v", buzzZipInputs)
+ }
+ if !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/obj/foo.gcno") ||
+ !android.SuffixInList(libbarZipInputs, "android_arm64_armv8-a_static_cov/libbaz.gcno") {
+ t.Fatalf("missing expected coverage files for cc 'libbar' library: %#v", libbarZipInputs)
+ }
+}
+
+func TestCoverageDeps(t *testing.T) {
+ ctx := testRustCov(t, `
+ rust_binary {
+ name: "fizz",
+ srcs: ["foo.rs"],
+ }`)
+
+ fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc")
+ if !strings.Contains(fizz.Args["linkFlags"], "libprofile-extras.a") {
+ t.Fatalf("missing expected coverage 'libprofile-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"])
+ }
+}
diff --git a/rust/library.go b/rust/library.go
index 0cf2dd0..a442933 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -19,7 +19,6 @@
"strings"
"android/soong/android"
- "android/soong/rust/config"
)
func init() {
@@ -29,14 +28,17 @@
android.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
android.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
- android.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
- android.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
- android.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
- android.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
+ android.RegisterModuleType("rust_ffi", RustFFIFactory)
+ android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
+ android.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
+ android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
+ android.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
}
type VariantLibraryProperties struct {
- Enabled *bool `android:"arch_variant"`
+ Enabled *bool `android:"arch_variant"`
+ Srcs []string `android:"path,arch_variant"`
}
type LibraryCompilerProperties struct {
@@ -45,9 +47,6 @@
Shared VariantLibraryProperties `android:"arch_variant"`
Static VariantLibraryProperties `android:"arch_variant"`
- // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
- Srcs []string `android:"path,arch_variant"`
-
// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
Include_dirs []string `android:"path,arch_variant"`
}
@@ -70,16 +69,21 @@
VariantIsShared bool `blueprint:"mutated"`
// This variant is a static library
VariantIsStatic bool `blueprint:"mutated"`
+
+ // This variant is disabled and should not be compiled
+ // (used for SourceProvider variants that produce only source)
+ VariantIsDisabled bool `blueprint:"mutated"`
}
type libraryDecorator struct {
*baseCompiler
+ *flagExporter
+ stripper Stripper
- Properties LibraryCompilerProperties
- MutatedProperties LibraryMutatedProperties
- distFile android.OptionalPath
- unstrippedOutputFile android.Path
- includeDirs android.Paths
+ Properties LibraryCompilerProperties
+ MutatedProperties LibraryMutatedProperties
+ includeDirs android.Paths
+ sourceProvider SourceProvider
}
type libraryInterface interface {
@@ -101,26 +105,16 @@
setStatic()
// Build a specific library variant
+ BuildOnlyFFI()
+ BuildOnlyRust()
BuildOnlyRlib()
BuildOnlyDylib()
BuildOnlyStatic()
BuildOnlyShared()
}
-func (library *libraryDecorator) exportedDirs() []string {
- return library.linkDirs
-}
-
-func (library *libraryDecorator) exportedDepFlags() []string {
- return library.depFlags
-}
-
-func (library *libraryDecorator) reexportDirs(dirs ...string) {
- library.linkDirs = android.FirstUniqueStrings(append(library.linkDirs, dirs...))
-}
-
-func (library *libraryDecorator) reexportDepFlags(flags ...string) {
- library.depFlags = android.FirstUniqueStrings(append(library.depFlags, flags...))
+func (library *libraryDecorator) nativeCoverage() bool {
+ return true
}
func (library *libraryDecorator) rlib() bool {
@@ -183,12 +177,31 @@
library.MutatedProperties.VariantIsDylib = false
}
+func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+ if library.rlib() || library.static() {
+ return rlibAutoDep
+ } else if library.dylib() || library.shared() {
+ return dylibAutoDep
+ } else {
+ panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.")
+ }
+}
+
var _ compiler = (*libraryDecorator)(nil)
var _ libraryInterface = (*libraryDecorator)(nil)
+var _ exportedFlagsProducer = (*libraryDecorator)(nil)
-// rust_library produces all variants.
+// rust_library produces all rust variants.
func RustLibraryFactory() android.Module {
- module, _ := NewRustLibrary(android.HostAndDeviceSupported)
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyRust()
+ return module.Init()
+}
+
+// rust_ffi produces all ffi variants.
+func RustFFIFactory() android.Module {
+ module, library := NewRustLibrary(android.HostAndDeviceSupported)
+ library.BuildOnlyFFI()
return module.Init()
}
@@ -206,23 +219,31 @@
return module.Init()
}
-// rust_library_shared produces a shared library.
-func RustLibrarySharedFactory() android.Module {
+// rust_ffi_shared produces a shared library.
+func RustFFISharedFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyShared()
return module.Init()
}
-// rust_library_static produces a static library.
-func RustLibraryStaticFactory() android.Module {
+// rust_ffi_static produces a static library.
+func RustFFIStaticFactory() android.Module {
module, library := NewRustLibrary(android.HostAndDeviceSupported)
library.BuildOnlyStatic()
return module.Init()
}
-// rust_library_host produces all variants.
+// rust_library_host produces all rust variants.
func RustLibraryHostFactory() android.Module {
- module, _ := NewRustLibrary(android.HostSupported)
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyRust()
+ return module.Init()
+}
+
+// rust_ffi_host produces all FFI variants.
+func RustFFIHostFactory() android.Module {
+ module, library := NewRustLibrary(android.HostSupported)
+ library.BuildOnlyFFI()
return module.Init()
}
@@ -240,57 +261,74 @@
return module.Init()
}
-// rust_library_static_host produces a static library.
-func RustLibraryStaticHostFactory() android.Module {
+// rust_ffi_static_host produces a static library.
+func RustFFIStaticHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyStatic()
return module.Init()
}
-// rust_library_shared_host produces an shared library.
-func RustLibrarySharedHostFactory() android.Module {
+// rust_ffi_shared_host produces an shared library.
+func RustFFISharedHostFactory() android.Module {
module, library := NewRustLibrary(android.HostSupported)
library.BuildOnlyShared()
return module.Init()
}
+func (library *libraryDecorator) BuildOnlyFFI() {
+ library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildRlib = false
+ library.MutatedProperties.BuildShared = true
+ library.MutatedProperties.BuildStatic = true
+}
+
+func (library *libraryDecorator) BuildOnlyRust() {
+ library.MutatedProperties.BuildDylib = true
+ library.MutatedProperties.BuildRlib = true
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = false
+}
+
func (library *libraryDecorator) BuildOnlyDylib() {
+ library.MutatedProperties.BuildDylib = true
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = false
-
}
func (library *libraryDecorator) BuildOnlyRlib() {
library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildRlib = true
library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildStatic = false
}
func (library *libraryDecorator) BuildOnlyStatic() {
- library.MutatedProperties.BuildShared = false
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
-
+ library.MutatedProperties.BuildShared = false
+ library.MutatedProperties.BuildStatic = true
}
func (library *libraryDecorator) BuildOnlyShared() {
- library.MutatedProperties.BuildStatic = false
library.MutatedProperties.BuildRlib = false
library.MutatedProperties.BuildDylib = false
+ library.MutatedProperties.BuildStatic = false
+ library.MutatedProperties.BuildShared = true
}
func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) {
- module := newModule(hod, android.MultilibFirst)
+ module := newModule(hod, android.MultilibBoth)
library := &libraryDecorator{
MutatedProperties: LibraryMutatedProperties{
- BuildDylib: true,
- BuildRlib: true,
- BuildShared: true,
- BuildStatic: true,
+ BuildDylib: false,
+ BuildRlib: false,
+ BuildShared: false,
+ BuildStatic: false,
},
baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
+ flagExporter: NewFlagExporter(),
}
module.compiler = library
@@ -301,42 +339,52 @@
func (library *libraryDecorator) compilerProps() []interface{} {
return append(library.baseCompiler.compilerProps(),
&library.Properties,
- &library.MutatedProperties)
+ &library.MutatedProperties,
+ &library.stripper.StripProperties)
}
func (library *libraryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps {
-
- // TODO(b/144861059) Remove if C libraries support dylib linkage in the future.
- if !ctx.Host() && (library.static() || library.shared()) {
- library.setNoStdlibs()
- for _, stdlib := range config.Stdlibs {
- deps.Rlibs = append(deps.Rlibs, stdlib+".static")
- }
- }
-
deps = library.baseCompiler.compilerDeps(ctx, deps)
if ctx.toolchain().Bionic() && (library.dylib() || library.shared()) {
- deps = library.baseCompiler.bionicDeps(ctx, deps)
+ deps = bionicDeps(deps)
+ deps.CrtBegin = "crtbegin_so"
+ deps.CrtEnd = "crtend_so"
}
return deps
}
+
+func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
+ return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+}
+
func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
- flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName())
+ flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName())
flags = library.baseCompiler.compilerFlags(ctx, flags)
if library.shared() || library.static() {
library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
}
+ if library.shared() {
+ flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+ }
+
return flags
}
func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
- var outputFile android.WritablePath
+ var outputFile android.ModuleOutPath
+ var fileName string
+ var srcPath android.Path
- srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+ if library.sourceProvider != nil {
+ srcPath = library.sourceProvider.Srcs()[0]
+ } else {
+ srcPath, _ = srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
+ }
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
if library.dylib() {
// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -346,32 +394,51 @@
}
if library.rlib() {
- fileName := library.getStem(ctx) + ctx.toolchain().RlibSuffix()
+ fileName = library.getStem(ctx) + ctx.toolchain().RlibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ outputs := TransformSrctoRlib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ library.coverageFile = outputs.coverageFile
} else if library.dylib() {
- fileName := library.getStem(ctx) + ctx.toolchain().DylibSuffix()
+ fileName = library.getStem(ctx) + ctx.toolchain().DylibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ outputs := TransformSrctoDylib(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ library.coverageFile = outputs.coverageFile
} else if library.static() {
- fileName := library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
+ fileName = library.getStem(ctx) + ctx.toolchain().StaticLibSuffix()
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ library.coverageFile = outputs.coverageFile
} else if library.shared() {
- fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+ fileName = library.sharedLibFilename(ctx)
outputFile = android.PathForModuleOut(ctx, fileName)
- TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
+ library.coverageFile = outputs.coverageFile
}
+ if !library.rlib() && library.stripper.NeedsStrip(ctx) {
+ strippedOutputFile := android.PathForModuleOut(ctx, "stripped", fileName)
+ library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile)
+ library.strippedOutputFile = android.OptionalPathForPath(strippedOutputFile)
+ }
+
+ var coverageFiles android.Paths
+ if library.coverageFile != nil {
+ coverageFiles = append(coverageFiles, library.coverageFile)
+ }
+ if len(deps.coverageFiles) > 0 {
+ coverageFiles = append(coverageFiles, deps.coverageFiles...)
+ }
+ library.coverageOutputZipFile = TransformCoverageFilesToZip(ctx, coverageFiles, library.getStem(ctx))
+
if library.rlib() || library.dylib() {
- library.reexportDirs(deps.linkDirs...)
- library.reexportDepFlags(deps.depFlags...)
+ library.exportLinkDirs(deps.linkDirs...)
+ library.exportDepFlags(deps.depFlags...)
+ library.exportLinkObjects(deps.linkObjects...)
}
- library.unstrippedOutputFile = outputFile
return outputFile
}
@@ -383,6 +450,14 @@
return stem + String(library.baseCompiler.Properties.Suffix)
}
+func (library *libraryDecorator) Disabled() bool {
+ return library.MutatedProperties.VariantIsDisabled
+}
+
+func (library *libraryDecorator) SetDisabled() {
+ library.MutatedProperties.VariantIsDisabled = true
+}
+
var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+")
func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) {
@@ -407,25 +482,35 @@
if m, ok := mctx.Module().(*Module); ok && m.compiler != nil {
switch library := m.compiler.(type) {
case libraryInterface:
-
- // We only build the rust library variants here. This assumes that
- // LinkageMutator runs first and there's an empty variant
- // if rust variants are required.
- if !library.static() && !library.shared() {
- if library.buildRlib() && library.buildDylib() {
- modules := mctx.CreateLocalVariations("rlib", "dylib")
- rlib := modules[0].(*Module)
- dylib := modules[1].(*Module)
-
- rlib.compiler.(libraryInterface).setRlib()
- dylib.compiler.(libraryInterface).setDylib()
- } else if library.buildRlib() {
- modules := mctx.CreateLocalVariations("rlib")
- modules[0].(*Module).compiler.(libraryInterface).setRlib()
- } else if library.buildDylib() {
- modules := mctx.CreateLocalVariations("dylib")
- modules[0].(*Module).compiler.(libraryInterface).setDylib()
+ if library.buildRlib() && library.buildDylib() {
+ variants := []string{"rlib", "dylib"}
+ if m.sourceProvider != nil {
+ variants = append(variants, "")
}
+ modules := mctx.CreateLocalVariations(variants...)
+
+ rlib := modules[0].(*Module)
+ dylib := modules[1].(*Module)
+ rlib.compiler.(libraryInterface).setRlib()
+ dylib.compiler.(libraryInterface).setDylib()
+
+ if m.sourceProvider != nil {
+ // This library is SourceProvider generated, so the non-library-producing
+ // variant needs to disable it's compiler and skip installation.
+ sourceProvider := modules[2].(*Module)
+ sourceProvider.compiler.SetDisabled()
+ }
+ } else if library.buildRlib() {
+ modules := mctx.CreateLocalVariations("rlib")
+ modules[0].(*Module).compiler.(libraryInterface).setRlib()
+ } else if library.buildDylib() {
+ modules := mctx.CreateLocalVariations("dylib")
+ modules[0].(*Module).compiler.(libraryInterface).setDylib()
+ }
+
+ if m.sourceProvider != nil {
+ // Alias the non-library variant to the empty-string variant.
+ mctx.AliasVariation("")
}
}
}
diff --git a/rust/library_test.go b/rust/library_test.go
index 9f9f374..f1bc050 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -17,6 +17,8 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
// Test that variants are being generated correctly, and that crate-types are correct.
@@ -27,13 +29,18 @@
name: "libfoo",
srcs: ["foo.rs"],
crate_name: "foo",
- }`)
+ }
+ rust_ffi_host {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo"
+ }`)
// Test all variants are being built.
libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib")
libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.so")
- libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Output("libfoo.a")
- libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static").Output("libfoo.ffi.a")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Output("libfoo.ffi.so")
rlibCrateType := "rlib"
dylibCrateType := "dylib"
@@ -114,3 +121,120 @@
}`)
}
+
+func TestSharedLibrary(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_shared {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared")
+
+ libfooOutput := libfoo.Output("libfoo.so")
+ if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
+ t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v",
+ libfooOutput.Args["linkFlags"])
+ }
+
+ if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("Non-static libstd dylib expected to be a dependency of Rust shared libraries. Dylib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+ }
+}
+
+func TestStaticLibraryLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_static {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+
+ if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+ }
+}
+
+// Test that variants pull in the right type of rustlib autodep
+func TestAutoDeps(t *testing.T) {
+
+ ctx := testRust(t, `
+ rust_library_host {
+ name: "libbar",
+ srcs: ["bar.rs"],
+ crate_name: "bar",
+ }
+ rust_library_host {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ rustlibs: ["libbar"],
+ }
+ rust_ffi_host {
+ name: "libfoo.ffi",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ rustlibs: ["libbar"],
+ }`)
+
+ libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib")
+ libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib")
+ libfooStatic := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_static")
+ libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared")
+
+ for _, static := range []android.TestingModule{libfooRlib, libfooStatic} {
+ if !android.InList("libbar", static.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("libbar not present as static dependency in static lib")
+ }
+ if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("libbar present as dynamic dependency in static lib")
+ }
+ }
+
+ for _, dyn := range []android.TestingModule{libfooDylib, libfooShared} {
+ if !android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkDylibs) {
+ t.Errorf("libbar not present as dynamic dependency in dynamic lib")
+ }
+ if android.InList("libbar", dyn.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("libbar present as static dependency in dynamic lib")
+ }
+
+ }
+}
+
+// Test that stripped versions are correctly generated and used.
+func TestStrippedLibrary(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_dylib {
+ name: "libfoo",
+ crate_name: "foo",
+ srcs: ["foo.rs"],
+ }
+ rust_library_dylib {
+ name: "libbar",
+ crate_name: "bar",
+ srcs: ["foo.rs"],
+ strip: {
+ none: true
+ }
+ }
+ `)
+
+ foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib")
+ foo.Output("stripped/libfoo.dylib.so")
+ // Check that the `cp` rule is using the stripped version as input.
+ cp := foo.Rule("android.Cp")
+ if !strings.HasSuffix(cp.Input.String(), "stripped/libfoo.dylib.so") {
+ t.Errorf("installed binary not based on stripped version: %v", cp.Input)
+ }
+
+ fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("stripped/libbar.dylib.so")
+ if fizzBar.Rule != nil {
+ t.Errorf("stripped version of bar has been generated")
+ }
+}
diff --git a/rust/prebuilt.go b/rust/prebuilt.go
index 45bef9e..f9c8934 100644
--- a/rust/prebuilt.go
+++ b/rust/prebuilt.go
@@ -19,12 +19,16 @@
)
func init() {
+ android.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
android.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+ android.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
}
type PrebuiltProperties struct {
// path to the prebuilt file
Srcs []string `android:"path,arch_variant"`
+ // directories containing associated rlib dependencies
+ Link_dirs []string `android:"path,arch_variant"`
}
type prebuiltLibraryDecorator struct {
@@ -33,35 +37,68 @@
}
var _ compiler = (*prebuiltLibraryDecorator)(nil)
+var _ exportedFlagsProducer = (*prebuiltLibraryDecorator)(nil)
+
+func PrebuiltLibraryFactory() android.Module {
+ module, _ := NewPrebuiltLibrary(android.HostAndDeviceSupported)
+ return module.Init()
+}
func PrebuiltDylibFactory() android.Module {
module, _ := NewPrebuiltDylib(android.HostAndDeviceSupported)
return module.Init()
}
-func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+func PrebuiltRlibFactory() android.Module {
+ module, _ := NewPrebuiltRlib(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+func NewPrebuiltLibrary(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
module, library := NewRustLibrary(hod)
- library.BuildOnlyDylib()
+ library.BuildOnlyRust()
library.setNoStdlibs()
- library.setDylib()
prebuilt := &prebuiltLibraryDecorator{
libraryDecorator: library,
}
module.compiler = prebuilt
- module.AddProperties(&library.Properties)
+ return module, prebuilt
+}
+
+func NewPrebuiltDylib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyDylib()
+ library.setNoStdlibs()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
+ return module, prebuilt
+}
+
+func NewPrebuiltRlib(hod android.HostOrDeviceSupported) (*Module, *prebuiltLibraryDecorator) {
+ module, library := NewRustLibrary(hod)
+ library.BuildOnlyRlib()
+ library.setNoStdlibs()
+ prebuilt := &prebuiltLibraryDecorator{
+ libraryDecorator: library,
+ }
+ module.compiler = prebuilt
return module, prebuilt
}
func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} {
- return append(prebuilt.baseCompiler.compilerProps(),
+ return append(prebuilt.libraryDecorator.compilerProps(),
&prebuilt.Properties)
}
func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
- srcPath := srcPathFromModuleSrcs(ctx, prebuilt.Properties.Srcs)
+ prebuilt.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...)
- prebuilt.unstrippedOutputFile = srcPath
-
+ srcPath, paths := srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs())
+ if len(paths) > 0 {
+ ctx.PropertyErrorf("srcs", "prebuilt libraries can only have one entry in srcs (the prebuilt path)")
+ }
return srcPath
}
@@ -69,3 +106,19 @@
deps = prebuilt.baseCompiler.compilerDeps(ctx, deps)
return deps
}
+
+func (prebuilt *prebuiltLibraryDecorator) nativeCoverage() bool {
+ return false
+}
+
+func (prebuilt *prebuiltLibraryDecorator) prebuiltSrcs() []string {
+ srcs := prebuilt.Properties.Srcs
+ if prebuilt.rlib() {
+ srcs = append(srcs, prebuilt.libraryDecorator.Properties.Rlib.Srcs...)
+ }
+ if prebuilt.dylib() {
+ srcs = append(srcs, prebuilt.libraryDecorator.Properties.Dylib.Srcs...)
+ }
+
+ return srcs
+}
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 10ea1e3..0c6ec99 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -23,26 +23,20 @@
}
type ProcMacroCompilerProperties struct {
- // path to the source file that is the main entry point of the program (e.g. src/lib.rs)
- Srcs []string `android:"path,arch_variant"`
-
- // set name of the procMacro
- Stem *string `android:"arch_variant"`
- Suffix *string `android:"arch_variant"`
}
type procMacroDecorator struct {
*baseCompiler
+ *flagExporter
- Properties ProcMacroCompilerProperties
- distFile android.OptionalPath
- unstrippedOutputFile android.Path
+ Properties ProcMacroCompilerProperties
}
type procMacroInterface interface {
}
var _ compiler = (*procMacroDecorator)(nil)
+var _ exportedFlagsProducer = (*procMacroDecorator)(nil)
func ProcMacroFactory() android.Module {
module, _ := NewProcMacro(android.HostSupportedNoCross)
@@ -54,6 +48,7 @@
procMacro := &procMacroDecorator{
baseCompiler: NewBaseCompiler("lib", "lib64", InstallInSystem),
+ flagExporter: NewFlagExporter(),
}
module.compiler = procMacro
@@ -70,10 +65,7 @@
fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
outputFile := android.PathForModuleOut(ctx, fileName)
- srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
-
- procMacro.unstrippedOutputFile = outputFile
-
+ srcPath, _ := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
return outputFile
}
@@ -84,3 +76,7 @@
return stem + String(procMacro.baseCompiler.Properties.Suffix)
}
+
+func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep {
+ return rlibAutoDep
+}
diff --git a/rust/project_json.go b/rust/project_json.go
new file mode 100644
index 0000000..8310479
--- /dev/null
+++ b/rust/project_json.go
@@ -0,0 +1,165 @@
+// Copyright 2020 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 rust
+
+import (
+ "encoding/json"
+ "fmt"
+ "path"
+
+ "android/soong/android"
+)
+
+// This singleton collects Rust crate definitions and generates a JSON file
+// (${OUT_DIR}/soong/rust-project.json) which can be use by external tools,
+// such as rust-analyzer. It does so when either make, mm, mma, mmm or mmma is
+// called. This singleton is enabled only if SOONG_GEN_RUST_PROJECT is set.
+// For example,
+//
+// $ SOONG_GEN_RUST_PROJECT=1 m nothing
+
+func init() {
+ android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+}
+
+func rustProjectGeneratorSingleton() android.Singleton {
+ return &projectGeneratorSingleton{}
+}
+
+type projectGeneratorSingleton struct{}
+
+const (
+ // Environment variables used to control the behavior of this singleton.
+ envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT"
+ rustProjectJsonFileName = "rust-project.json"
+)
+
+// The format of rust-project.json is not yet finalized. A current description is available at:
+// https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc#non-cargo-based-projects
+type rustProjectDep struct {
+ Crate int `json:"crate"`
+ Name string `json:"name"`
+}
+
+type rustProjectCrate struct {
+ RootModule string `json:"root_module"`
+ Edition string `json:"edition,omitempty"`
+ Deps []rustProjectDep `json:"deps"`
+ Cfgs []string `json:"cfgs"`
+}
+
+type rustProjectJson struct {
+ Roots []string `json:"roots"`
+ Crates []rustProjectCrate `json:"crates"`
+}
+
+// crateInfo is used during the processing to keep track of the known crates.
+type crateInfo struct {
+ ID int
+ Deps map[string]int
+}
+
+func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson,
+ knownCrates map[string]crateInfo, module android.Module,
+ crate *rustProjectCrate, deps map[string]int) {
+
+ ctx.VisitDirectDeps(module, func(child android.Module) {
+ childId, childCrateName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
+ if !ok {
+ return
+ }
+ if _, ok = deps[ctx.ModuleName(child)]; ok {
+ return
+ }
+ crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childCrateName})
+ deps[ctx.ModuleName(child)] = childId
+ })
+}
+
+// appendLibraryAndDeps creates a rustProjectCrate for the module argument and
+// appends it to the rustProjectJson struct. It visits the dependencies of the
+// module depth-first. If the current module is already in knownCrates, its
+// dependencies are merged. Returns a tuple (id, crate_name, ok).
+func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson,
+ knownCrates map[string]crateInfo, module android.Module) (int, string, bool) {
+ rModule, ok := module.(*Module)
+ if !ok {
+ return 0, "", false
+ }
+ if rModule.compiler == nil {
+ return 0, "", false
+ }
+ rustLib, ok := rModule.compiler.(*libraryDecorator)
+ if !ok {
+ return 0, "", false
+ }
+ moduleName := ctx.ModuleName(module)
+ crateName := rModule.CrateName()
+ if cInfo, ok := knownCrates[moduleName]; ok {
+ // We have seen this crate already; merge any new dependencies.
+ crate := project.Crates[cInfo.ID]
+ mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps)
+ project.Crates[cInfo.ID] = crate
+ return cInfo.ID, crateName, true
+ }
+ crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
+ srcs := rustLib.baseCompiler.Properties.Srcs
+ if len(srcs) == 0 {
+ return 0, "", false
+ }
+ crate.RootModule = path.Join(ctx.ModuleDir(rModule), srcs[0])
+ crate.Edition = rustLib.baseCompiler.edition()
+
+ deps := make(map[string]int)
+ mergeDependencies(ctx, project, knownCrates, module, &crate, deps)
+
+ id := len(project.Crates)
+ knownCrates[moduleName] = crateInfo{ID: id, Deps: deps}
+ project.Crates = append(project.Crates, crate)
+ // rust-analyzer requires that all crates belong to at least one root:
+ // https://github.com/rust-analyzer/rust-analyzer/issues/4735.
+ project.Roots = append(project.Roots, path.Dir(crate.RootModule))
+ return id, crateName, true
+}
+
+func (r *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) {
+ return
+ }
+
+ project := rustProjectJson{}
+ knownCrates := make(map[string]crateInfo)
+ ctx.VisitAllModules(func(module android.Module) {
+ appendLibraryAndDeps(ctx, &project, knownCrates, module)
+ })
+
+ path := android.PathForOutput(ctx, rustProjectJsonFileName)
+ err := createJsonFile(project, path)
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+}
+
+func createJsonFile(project rustProjectJson, rustProjectPath android.WritablePath) error {
+ buf, err := json.MarshalIndent(project, "", " ")
+ if err != nil {
+ return fmt.Errorf("JSON marshal of rustProjectJson failed: %s", err)
+ }
+ err = android.WriteFileToOutputDir(rustProjectPath, buf, 0666)
+ if err != nil {
+ return fmt.Errorf("Writing rust-project to %s failed: %s", rustProjectPath.String(), err)
+ }
+ return nil
+}
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
new file mode 100644
index 0000000..8521940
--- /dev/null
+++ b/rust/project_json_test.go
@@ -0,0 +1,171 @@
+// Copyright 2020 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 rust
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+// testProjectJson run the generation of rust-project.json. It returns the raw
+// content of the generated file.
+func testProjectJson(t *testing.T, bp string, fs map[string][]byte) []byte {
+ cc.GatherRequiredFilesForTest(fs)
+
+ env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
+ config := android.TestArchConfig(buildDir, env, bp, fs)
+ ctx := CreateTestContext()
+ ctx.Register(config)
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ // The JSON file is generated via WriteFileToOutputDir. Therefore, it
+ // won't appear in the Output of the TestingSingleton. Manually verify
+ // it exists.
+ content, err := ioutil.ReadFile(filepath.Join(buildDir, rustProjectJsonFileName))
+ if err != nil {
+ t.Errorf("rust-project.json has not been generated")
+ }
+ return content
+}
+
+// validateJsonCrates validates that content follows the basic structure of
+// rust-project.json. It returns the crates attribute if the validation
+// succeeded.
+// It uses an empty interface instead of relying on a defined structure to
+// avoid a strong dependency on our implementation.
+func validateJsonCrates(t *testing.T, rawContent []byte) []interface{} {
+ var content interface{}
+ err := json.Unmarshal(rawContent, &content)
+ if err != nil {
+ t.Errorf("Unable to parse the rust-project.json as JSON: %v", err)
+ }
+ root, ok := content.(map[string]interface{})
+ if !ok {
+ t.Errorf("Unexpected JSON format: %v", content)
+ }
+ if _, ok = root["crates"]; !ok {
+ t.Errorf("No crates attribute in rust-project.json: %v", root)
+ }
+ crates, ok := root["crates"].([]interface{})
+ if !ok {
+ t.Errorf("Unexpected crates format: %v", root["crates"])
+ }
+ return crates
+}
+
+func TestProjectJsonDep(t *testing.T) {
+ bp := `
+ rust_library {
+ name: "liba",
+ srcs: ["a/src/lib.rs"],
+ crate_name: "a"
+ }
+ rust_library {
+ name: "libb",
+ srcs: ["b/src/lib.rs"],
+ crate_name: "b",
+ rlibs: ["liba"],
+ }
+ ` + GatherRequiredDepsForTest()
+ fs := map[string][]byte{
+ "a/src/lib.rs": nil,
+ "b/src/lib.rs": nil,
+ }
+ jsonContent := testProjectJson(t, bp, fs)
+ validateJsonCrates(t, jsonContent)
+}
+
+func TestProjectJsonBindGen(t *testing.T) {
+ bp := `
+ rust_library {
+ name: "liba",
+ srcs: ["src/lib.rs"],
+ rlibs: ["libbindings"],
+ crate_name: "a"
+ }
+ rust_bindgen {
+ name: "libbindings",
+ crate_name: "bindings",
+ source_stem: "bindings",
+ host_supported: true,
+ wrapper_src: "src/any.h",
+ }
+ ` + GatherRequiredDepsForTest()
+ fs := map[string][]byte{
+ "src/lib.rs": nil,
+ }
+ jsonContent := testProjectJson(t, bp, fs)
+ validateJsonCrates(t, jsonContent)
+}
+
+func TestProjectJsonMultiVersion(t *testing.T) {
+ bp := `
+ rust_library {
+ name: "liba1",
+ srcs: ["a1/src/lib.rs"],
+ crate_name: "a"
+ }
+ rust_library {
+ name: "liba2",
+ srcs: ["a2/src/lib.rs"],
+ crate_name: "a",
+ }
+ rust_library {
+ name: "libb",
+ srcs: ["b/src/lib.rs"],
+ crate_name: "b",
+ rustlibs: ["liba1", "liba2"],
+ }
+ ` + GatherRequiredDepsForTest()
+ fs := map[string][]byte{
+ "a1/src/lib.rs": nil,
+ "a2/src/lib.rs": nil,
+ "b/src/lib.rs": nil,
+ }
+ jsonContent := testProjectJson(t, bp, fs)
+ crates := validateJsonCrates(t, jsonContent)
+ for _, crate := range crates {
+ c := crate.(map[string]interface{})
+ if c["root_module"] == "b/src/lib.rs" {
+ deps, ok := c["deps"].([]interface{})
+ if !ok {
+ t.Errorf("Unexpected format for deps: %v", c["deps"])
+ }
+ aCount := 0
+ for _, dep := range deps {
+ d, ok := dep.(map[string]interface{})
+ if !ok {
+ t.Errorf("Unexpected format for dep: %v", dep)
+ }
+ if d["name"] == "a" {
+ aCount++
+ }
+ }
+ if aCount != 2 {
+ t.Errorf("Unexpected number of liba dependencies want %v, got %v: %v", 2, aCount, deps)
+ }
+ return
+ }
+ }
+ t.Errorf("libb crate has not been found: %v", crates)
+}
diff --git a/rust/protobuf.go b/rust/protobuf.go
new file mode 100644
index 0000000..897300f
--- /dev/null
+++ b/rust/protobuf.go
@@ -0,0 +1,109 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+var (
+ defaultProtobufFlags = []string{""}
+)
+
+func init() {
+ android.RegisterModuleType("rust_protobuf", RustProtobufFactory)
+ android.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
+}
+
+var _ SourceProvider = (*protobufDecorator)(nil)
+
+type ProtobufProperties struct {
+ // Path to the proto file that will be used to generate the source
+ Proto *string `android:"path,arch_variant"`
+
+ // List of additional flags to pass to aprotoc
+ Proto_flags []string `android:"arch_variant"`
+}
+
+type protobufDecorator struct {
+ *BaseSourceProvider
+
+ Properties ProtobufProperties
+}
+
+func (proto *protobufDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
+ var protoFlags android.ProtoFlags
+ pluginPath := ctx.Config().HostToolPath(ctx, "protoc-gen-rust")
+
+ protoFlags.OutTypeFlag = "--rust_out"
+
+ protoFlags.Flags = append(protoFlags.Flags, " --plugin="+pluginPath.String())
+ protoFlags.Flags = append(protoFlags.Flags, defaultProtobufFlags...)
+ protoFlags.Flags = append(protoFlags.Flags, proto.Properties.Proto_flags...)
+
+ protoFlags.Deps = append(protoFlags.Deps, pluginPath)
+
+ protoFile := android.OptionalPathForModuleSrc(ctx, proto.Properties.Proto)
+ if !protoFile.Valid() {
+ ctx.PropertyErrorf("proto", "invalid path to proto file")
+ }
+
+ outDir := android.PathForModuleOut(ctx)
+ depFile := android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".d")
+ outputs := android.WritablePaths{android.PathForModuleOut(ctx, proto.BaseSourceProvider.getStem(ctx)+".rs")}
+
+ rule := android.NewRuleBuilder()
+ android.ProtoRule(ctx, rule, protoFile.Path(), protoFlags, protoFlags.Deps, outDir, depFile, outputs)
+ rule.Build(pctx, ctx, "protoc_"+protoFile.Path().Rel(), "protoc "+protoFile.Path().Rel())
+
+ proto.BaseSourceProvider.OutputFile = outputs[0]
+ return outputs[0]
+}
+
+func (proto *protobufDecorator) SourceProviderProps() []interface{} {
+ return append(proto.BaseSourceProvider.SourceProviderProps(), &proto.Properties)
+}
+
+func (proto *protobufDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+ deps = proto.BaseSourceProvider.SourceProviderDeps(ctx, deps)
+ deps.Rustlibs = append(deps.Rustlibs, "libprotobuf")
+ return deps
+}
+
+// rust_protobuf generates protobuf rust code from the provided proto file. This uses the protoc-gen-rust plugin for
+// protoc. Additional flags to the protoc command can be passed via the proto_flags property. This module type will
+// create library variants that can be used as a crate dependency by adding it to the rlibs, dylibs, and rustlibs
+// properties of other modules.
+func RustProtobufFactory() android.Module {
+ module, _ := NewRustProtobuf(android.HostAndDeviceSupported)
+ return module.Init()
+}
+
+// A host-only variant of rust_protobuf. Refer to rust_protobuf for more details.
+func RustProtobufHostFactory() android.Module {
+ module, _ := NewRustProtobuf(android.HostSupported)
+ return module.Init()
+}
+
+func NewRustProtobuf(hod android.HostOrDeviceSupported) (*Module, *protobufDecorator) {
+ protobuf := &protobufDecorator{
+ BaseSourceProvider: NewSourceProvider(),
+ Properties: ProtobufProperties{},
+ }
+
+ module := NewSourceProviderModule(hod, protobuf, false)
+
+ return module, protobuf
+}
diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go
new file mode 100644
index 0000000..a9dbf39
--- /dev/null
+++ b/rust/protobuf_test.go
@@ -0,0 +1,39 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "android/soong/android"
+ "testing"
+)
+
+func TestRustProtobuf(t *testing.T) {
+ ctx := testRust(t, `
+ rust_protobuf {
+ name: "librust_proto",
+ proto: "buf.proto",
+ crate_name: "rust_proto",
+ source_stem: "buf",
+ }
+ `)
+ // Check that there's a rule to generate the expected output
+ _ = ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Output("buf.rs")
+
+ // Check that libprotobuf is added as a dependency.
+ librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module)
+ if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) {
+ t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)")
+ }
+}
diff --git a/rust/rust.go b/rust/rust.go
index 5cc8845..b98992c 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -23,6 +23,7 @@
"android/soong/android"
"android/soong/cc"
+ cc_config "android/soong/cc/config"
"android/soong/rust/config"
)
@@ -39,18 +40,21 @@
android.RegisterModuleType("rust_defaults", defaultsFactory)
android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
- ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
+ ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
pctx.Import("android/soong/rust/config")
+ pctx.ImportAs("cc_config", "android/soong/cc/config")
}
type Flags struct {
- GlobalRustFlags []string // Flags that apply globally to rust
- GlobalLinkFlags []string // Flags that apply globally to linker
- RustFlags []string // Flags that apply to rust
- LinkFlags []string // Flags that apply to linker
- RustFlagsDeps android.Paths // Files depended on by compiler flags
+ GlobalRustFlags []string // Flags that apply globally to rust
+ GlobalLinkFlags []string // Flags that apply globally to linker
+ RustFlags []string // Flags that apply to rust
+ LinkFlags []string // Flags that apply to linker
+ ClippyFlags []string // Flags that apply to clippy-driver, during the linting
Toolchain config.Toolchain
+ Coverage bool
+ Clippy bool
}
type BaseProperties struct {
@@ -59,7 +63,11 @@
AndroidMkProcMacroLibs []string
AndroidMkSharedLibs []string
AndroidMkStaticLibs []string
- SubName string `blueprint:"mutated"`
+
+ SubName string `blueprint:"mutated"`
+
+ PreventInstall bool
+ HideFromMake bool
}
type Module struct {
@@ -72,9 +80,30 @@
multilib android.Multilib
compiler compiler
+ coverage *coverage
+ clippy *clippy
cachedToolchain config.Toolchain
- subAndroidMkOnce map[subAndroidMkProvider]bool
- outputFile android.OptionalPath
+ sourceProvider SourceProvider
+ subAndroidMkOnce map[SubAndroidMkProvider]bool
+
+ outputFile android.OptionalPath
+ generatedFile android.OptionalPath
+}
+
+func (mod *Module) OutputFiles(tag string) (android.Paths, error) {
+ switch tag {
+ case "":
+ if mod.sourceProvider != nil && (mod.compiler == nil || mod.compiler.Disabled()) {
+ return mod.sourceProvider.Srcs(), nil
+ } else {
+ if mod.outputFile.Valid() {
+ return android.Paths{mod.outputFile.Path()}, nil
+ }
+ return android.Paths{}, nil
+ }
+ default:
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+ }
}
var _ android.ImageInterface = (*Module)(nil)
@@ -114,12 +143,8 @@
func (mod *Module) NonCcVariants() bool {
if mod.compiler != nil {
- if library, ok := mod.compiler.(libraryInterface); ok {
- if library.buildRlib() || library.buildDylib() {
- return true
- } else {
- return false
- }
+ if _, ok := mod.compiler.(libraryInterface); ok {
+ return false
}
}
panic(fmt.Errorf("NonCcVariants called on non-library module: %q", mod.BaseModuleName()))
@@ -135,16 +160,16 @@
return library.static()
}
}
- panic(fmt.Errorf("Static called on non-library module: %q", mod.BaseModuleName()))
+ return false
}
func (mod *Module) Shared() bool {
if mod.compiler != nil {
if library, ok := mod.compiler.(libraryInterface); ok {
- return library.static()
+ return library.shared()
}
}
- panic(fmt.Errorf("Shared called on non-library module: %q", mod.BaseModuleName()))
+ return false
}
func (mod *Module) Toc() android.OptionalPath {
@@ -192,6 +217,10 @@
return false
}
+func (mod *Module) IsSdkVariant() bool {
+ return false
+}
+
func (mod *Module) ToolchainLibrary() bool {
return false
}
@@ -207,6 +236,7 @@
type Deps struct {
Dylibs []string
Rlibs []string
+ Rustlibs []string
ProcMacros []string
SharedLibs []string
StaticLibs []string
@@ -215,17 +245,29 @@
}
type PathDeps struct {
- DyLibs RustLibraries
- RLibs RustLibraries
- SharedLibs android.Paths
- StaticLibs android.Paths
- ProcMacros RustLibraries
- linkDirs []string
- depFlags []string
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ SharedLibs android.Paths
+ StaticLibs android.Paths
+ ProcMacros RustLibraries
+ linkDirs []string
+ depFlags []string
+ linkObjects []string
//ReexportedDeps android.Paths
+ // Used by bindgen modules which call clang
+ depClangFlags []string
+ depIncludePaths android.Paths
+ depGeneratedHeaders android.Paths
+ depSystemIncludePaths android.Paths
+
+ coverageFiles android.Paths
+
CrtBegin android.OptionalPath
CrtEnd android.OptionalPath
+
+ // Paths to generated source files
+ SrcDeps android.Paths
}
type RustLibraries []RustLibrary
@@ -243,8 +285,90 @@
crateName() string
inData() bool
- install(ctx ModuleContext, path android.Path)
+ install(ctx ModuleContext)
relativeInstallPath() string
+
+ nativeCoverage() bool
+
+ Disabled() bool
+ SetDisabled()
+
+ static() bool
+}
+
+type exportedFlagsProducer interface {
+ exportedLinkDirs() []string
+ exportedDepFlags() []string
+ exportedLinkObjects() []string
+ exportLinkDirs(...string)
+ exportDepFlags(...string)
+ exportLinkObjects(...string)
+}
+
+type flagExporter struct {
+ depFlags []string
+ linkDirs []string
+ linkObjects []string
+}
+
+func (flagExporter *flagExporter) exportedLinkDirs() []string {
+ return flagExporter.linkDirs
+}
+
+func (flagExporter *flagExporter) exportedDepFlags() []string {
+ return flagExporter.depFlags
+}
+
+func (flagExporter *flagExporter) exportedLinkObjects() []string {
+ return flagExporter.linkObjects
+}
+
+func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
+ flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
+}
+
+func (flagExporter *flagExporter) exportDepFlags(flags ...string) {
+ flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...))
+}
+
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+ flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
+}
+
+var _ exportedFlagsProducer = (*flagExporter)(nil)
+
+func NewFlagExporter() *flagExporter {
+ return &flagExporter{
+ depFlags: []string{},
+ linkDirs: []string{},
+ linkObjects: []string{},
+ }
+}
+
+func (mod *Module) isCoverageVariant() bool {
+ return mod.coverage.Properties.IsCoverageVariant
+}
+
+var _ cc.Coverage = (*Module)(nil)
+
+func (mod *Module) IsNativeCoverageNeeded(ctx android.BaseModuleContext) bool {
+ return mod.coverage != nil && mod.coverage.Properties.NeedCoverageVariant
+}
+
+func (mod *Module) PreventInstall() {
+ mod.Properties.PreventInstall = true
+}
+
+func (mod *Module) HideFromMake() {
+ mod.Properties.HideFromMake = true
+}
+
+func (mod *Module) MarkAsCoverageVariant(coverage bool) {
+ mod.coverage.Properties.IsCoverageVariant = coverage
+}
+
+func (mod *Module) EnableCoverageIfNeeded() {
+ mod.coverage.Properties.CoverageEnabled = mod.coverage.Properties.NeedCoverageBuild
}
func defaultsFactory() android.Module {
@@ -267,7 +391,10 @@
&LibraryCompilerProperties{},
&ProcMacroCompilerProperties{},
&PrebuiltProperties{},
+ &SourceProviderProperties{},
&TestProperties{},
+ &cc.CoverageProperties{},
+ &ClippyProperties{},
)
android.InitDefaultsModule(module)
@@ -289,7 +416,9 @@
func (mod *Module) CcLibraryInterface() bool {
if mod.compiler != nil {
- if _, ok := mod.compiler.(libraryInterface); ok {
+ // use build{Static,Shared}() instead of {static,shared}() here because this might be called before
+ // VariantIs{Static,Shared} is set.
+ if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic()) {
return true
}
}
@@ -373,7 +502,7 @@
func (mod *Module) StubsVersions() []string {
// For now, Rust has no stubs versions.
if mod.compiler != nil {
- if _, ok := mod.compiler.(*libraryDecorator); ok {
+ if _, ok := mod.compiler.(libraryInterface); ok {
return []string{}
}
}
@@ -395,6 +524,21 @@
return false
}
+func (mod *Module) CoverageFiles() android.Paths {
+ if mod.compiler != nil {
+ if !mod.compiler.nativeCoverage() {
+ return android.Paths{}
+ }
+ if library, ok := mod.compiler.(*libraryDecorator); ok {
+ if library.coverageFile != nil {
+ return android.Paths{library.coverageFile}
+ }
+ return android.Paths{}
+ }
+ }
+ panic(fmt.Errorf("CoverageFiles called on non-library module: %q", mod.BaseModuleName()))
+}
+
var _ cc.LinkableInterface = (*Module)(nil)
func (mod *Module) Init() android.Module {
@@ -403,24 +547,19 @@
if mod.compiler != nil {
mod.AddProperties(mod.compiler.compilerProps()...)
}
+ if mod.coverage != nil {
+ mod.AddProperties(mod.coverage.props()...)
+ }
+ if mod.clippy != nil {
+ mod.AddProperties(mod.clippy.props()...)
+ }
+ if mod.sourceProvider != nil {
+ mod.AddProperties(mod.sourceProvider.SourceProviderProps()...)
+ }
+
android.InitAndroidArchModule(mod, mod.hod, mod.multilib)
android.InitDefaultableModule(mod)
-
- // Explicitly disable unsupported targets.
- android.AddLoadHook(mod, func(ctx android.LoadHookContext) {
- disableTargets := struct {
- Target struct {
- Linux_bionic struct {
- Enabled *bool
- }
- }
- }{}
- disableTargets.Target.Linux_bionic.Enabled = proptools.BoolPtr(false)
-
- ctx.AppendProperties(&disableTargets)
- })
-
return mod
}
@@ -432,6 +571,8 @@
}
func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
module := newBaseModule(hod, multilib)
+ module.coverage = &coverage{}
+ module.clippy = &clippy{}
return module
}
@@ -451,28 +592,48 @@
}
type ModuleContextIntf interface {
+ RustModule() *Module
toolchain() config.Toolchain
- baseModuleName() string
- CrateName() string
}
type depsContext struct {
android.BottomUpMutatorContext
- moduleContextImpl
}
type moduleContext struct {
android.ModuleContext
- moduleContextImpl
}
-type moduleContextImpl struct {
- mod *Module
- ctx BaseModuleContext
+type baseModuleContext struct {
+ android.BaseModuleContext
}
-func (ctx *moduleContextImpl) toolchain() config.Toolchain {
- return ctx.mod.toolchain(ctx.ctx)
+func (ctx *moduleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *moduleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *depsContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *depsContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (ctx *baseModuleContext) RustModule() *Module {
+ return ctx.Module().(*Module)
+}
+
+func (ctx *baseModuleContext) toolchain() config.Toolchain {
+ return ctx.RustModule().toolchain(ctx)
+}
+
+func (mod *Module) nativeCoverage() bool {
+ return mod.compiler != nil && mod.compiler.nativeCoverage()
}
func (mod *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
@@ -482,17 +643,17 @@
return mod.cachedToolchain
}
+func (mod *Module) ccToolchain(ctx android.BaseModuleContext) cc_config.Toolchain {
+ return cc_config.FindToolchain(ctx.Os(), ctx.Arch())
+}
+
func (d *Defaults) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
ctx := &moduleContext{
ModuleContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
toolchain := mod.toolchain(ctx)
@@ -508,9 +669,29 @@
if mod.compiler != nil {
flags = mod.compiler.compilerFlags(ctx, flags)
+ }
+ if mod.coverage != nil {
+ flags, deps = mod.coverage.flags(ctx, flags, deps)
+ }
+ if mod.clippy != nil {
+ flags, deps = mod.clippy.flags(ctx, flags, deps)
+ }
+
+ // SourceProvider needs to call GenerateSource() before compiler calls compile() so it can provide the source.
+ // TODO(b/162588681) This shouldn't have to run for every variant.
+ if mod.sourceProvider != nil {
+ generatedFile := mod.sourceProvider.GenerateSource(ctx, deps)
+ mod.generatedFile = android.OptionalPathForPath(generatedFile)
+ mod.sourceProvider.setSubName(ctx.ModuleSubDir())
+ }
+
+ if mod.compiler != nil && !mod.compiler.Disabled() {
outputFile := mod.compiler.compile(ctx, flags, deps)
+
mod.outputFile = android.OptionalPathForPath(outputFile)
- mod.compiler.install(ctx, mod.outputFile.Path())
+ if mod.outputFile.Valid() && !mod.Properties.PreventInstall {
+ mod.compiler.install(ctx)
+ }
}
}
@@ -520,9 +701,17 @@
if mod.compiler != nil {
deps = mod.compiler.compilerDeps(ctx, deps)
}
+ if mod.sourceProvider != nil {
+ deps = mod.sourceProvider.SourceProviderDeps(ctx, deps)
+ }
+
+ if mod.coverage != nil {
+ deps = mod.coverage.deps(ctx, deps)
+ }
deps.Rlibs = android.LastUniqueStrings(deps.Rlibs)
deps.Dylibs = android.LastUniqueStrings(deps.Dylibs)
+ deps.Rustlibs = android.LastUniqueStrings(deps.Rustlibs)
deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
@@ -531,14 +720,6 @@
}
-func (ctx *moduleContextImpl) baseModuleName() string {
- return ctx.mod.ModuleBase.BaseModuleName()
-}
-
-func (ctx *moduleContextImpl) CrateName() string {
- return ctx.mod.CrateName()
-}
-
type dependencyTag struct {
blueprint.BaseDependencyTag
name string
@@ -547,12 +728,33 @@
}
var (
- rlibDepTag = dependencyTag{name: "rlibTag", library: true}
- dylibDepTag = dependencyTag{name: "dylib", library: true}
- procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
- testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
+ customBindgenDepTag = dependencyTag{name: "customBindgenTag"}
+ rlibDepTag = dependencyTag{name: "rlibTag", library: true}
+ dylibDepTag = dependencyTag{name: "dylib", library: true}
+ procMacroDepTag = dependencyTag{name: "procMacro", proc_macro: true}
+ testPerSrcDepTag = dependencyTag{name: "rust_unit_tests"}
)
+type autoDep struct {
+ variation string
+ depTag dependencyTag
+}
+
+var (
+ rlibAutoDep = autoDep{variation: "rlib", depTag: rlibDepTag}
+ dylibAutoDep = autoDep{variation: "dylib", depTag: dylibDepTag}
+)
+
+type autoDeppable interface {
+ autoDep(ctx BaseModuleContext) autoDep
+}
+
+func (mod *Module) begin(ctx BaseModuleContext) {
+ if mod.coverage != nil {
+ mod.coverage.begin(ctx)
+ }
+}
+
func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
var depPaths PathDeps
@@ -561,18 +763,15 @@
directProcMacroDeps := []*Module{}
directSharedLibDeps := [](cc.LinkableInterface){}
directStaticLibDeps := [](cc.LinkableInterface){}
+ directSrcProvidersDeps := []*Module{}
+ directSrcDeps := [](android.SourceFileProducer){}
ctx.VisitDirectDeps(func(dep android.Module) {
depName := ctx.OtherModuleName(dep)
depTag := ctx.OtherModuleDependencyTag(dep)
- if rustDep, ok := dep.(*Module); ok {
+ if rustDep, ok := dep.(*Module); ok && !rustDep.CcLibraryInterface() {
//Handle Rust Modules
- linkFile := rustDep.outputFile
- if !linkFile.Valid() {
- ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
- }
-
switch depTag {
case dylibDepTag:
dylib, ok := rustDep.compiler.(libraryInterface)
@@ -588,33 +787,53 @@
ctx.ModuleErrorf("mod %q not an rlib library", depName)
return
}
+ depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...)
directRlibDeps = append(directRlibDeps, rustDep)
mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName)
case procMacroDepTag:
directProcMacroDeps = append(directProcMacroDeps, rustDep)
mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName)
+ case android.SourceDepTag:
+ // Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct
+ // OS/Arch variant is used.
+ var helper string
+ if ctx.Host() {
+ helper = "missing 'host_supported'?"
+ } else {
+ helper = "device module defined?"
+ }
+
+ if dep.Target().Os != ctx.Os() {
+ ctx.ModuleErrorf("OS mismatch on dependency %q (%s)", dep.Name(), helper)
+ return
+ } else if dep.Target().Arch.ArchType != ctx.Arch().ArchType {
+ ctx.ModuleErrorf("Arch mismatch on dependency %q (%s)", dep.Name(), helper)
+ return
+ }
+ directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep)
}
- //Append the dependencies exportedDirs
- if lib, ok := rustDep.compiler.(*libraryDecorator); ok {
- depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedDirs()...)
+ //Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS
+ if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok && depTag != procMacroDepTag {
+ depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...)
depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
+ depPaths.linkObjects = append(depPaths.linkObjects, lib.exportedLinkObjects()...)
}
- // Append this dependencies output to this mod's linkDirs so they can be exported to dependencies
- // This can be probably be refactored by defining a common exporter interface similar to cc's
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
+ linkFile := rustDep.outputFile
+ if !linkFile.Valid() {
+ ctx.ModuleErrorf("Invalid output file when adding dep %q to %q",
+ depName, ctx.ModuleName())
+ return
+ }
linkDir := linkPathFromFilePath(linkFile.Path())
- if lib, ok := mod.compiler.(*libraryDecorator); ok {
- lib.linkDirs = append(lib.linkDirs, linkDir)
- } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok {
- procMacro.linkDirs = append(procMacro.linkDirs, linkDir)
+ if lib, ok := mod.compiler.(exportedFlagsProducer); ok {
+ lib.exportLinkDirs(linkDir)
}
}
- }
-
- if ccDep, ok := dep.(cc.LinkableInterface); ok {
+ } else if ccDep, ok := dep.(cc.LinkableInterface); ok {
//Handle C dependencies
if _, ok := ccDep.(*Module); !ok {
if ccDep.Module().Target().Os != ctx.Os() {
@@ -626,46 +845,58 @@
return
}
}
+ linkObject := ccDep.OutputFile()
+ linkPath := linkPathFromFilePath(linkObject.Path())
- linkFile := ccDep.OutputFile()
- linkPath := linkPathFromFilePath(linkFile.Path())
- libName := libNameFromFilePath(linkFile.Path())
- depFlag := "-l" + libName
-
- if !linkFile.Valid() {
+ if !linkObject.Valid() {
ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
}
exportDep := false
- switch depTag {
- case cc.StaticDepTag:
- depFlag = "-lstatic=" + libName
+ switch {
+ case cc.IsStaticDepTag(depTag):
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, depFlag)
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
+ depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
+ if mod, ok := ccDep.(*cc.Module); ok {
+ depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
+ depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...)
+ depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...)
+ }
+ depPaths.coverageFiles = append(depPaths.coverageFiles, ccDep.CoverageFiles()...)
directStaticLibDeps = append(directStaticLibDeps, ccDep)
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
- case cc.SharedDepTag:
- depFlag = "-ldylib=" + libName
+ case cc.IsSharedDepTag(depTag):
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, depFlag)
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
+ depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
+ if mod, ok := ccDep.(*cc.Module); ok {
+ depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
+ depPaths.depClangFlags = append(depPaths.depClangFlags, mod.ExportedFlags()...)
+ depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, mod.ExportedGeneratedHeaders()...)
+ }
directSharedLibDeps = append(directSharedLibDeps, ccDep)
mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
exportDep = true
- case cc.CrtBeginDepTag:
- depPaths.CrtBegin = linkFile
- case cc.CrtEndDepTag:
- depPaths.CrtEnd = linkFile
+ case depTag == cc.CrtBeginDepTag:
+ depPaths.CrtBegin = linkObject
+ case depTag == cc.CrtEndDepTag:
+ depPaths.CrtEnd = linkObject
}
// Make sure these dependencies are propagated
- if lib, ok := mod.compiler.(*libraryDecorator); ok && exportDep {
- lib.linkDirs = append(lib.linkDirs, linkPath)
- lib.depFlags = append(lib.depFlags, depFlag)
- } else if procMacro, ok := mod.compiler.(*procMacroDecorator); ok && exportDep {
- procMacro.linkDirs = append(procMacro.linkDirs, linkPath)
- procMacro.depFlags = append(procMacro.depFlags, depFlag)
+ if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
+ lib.exportLinkDirs(linkPath)
+ lib.exportLinkObjects(linkObject.String())
}
+ }
+ if srcDep, ok := dep.(android.SourceFileProducer); ok {
+ switch depTag {
+ case android.SourceDepTag:
+ // These are usually genrules which don't have per-target variants.
+ directSrcDeps = append(directSrcDeps, srcDep)
+ }
}
})
@@ -692,15 +923,29 @@
sharedLibDepFiles = append(sharedLibDepFiles, dep.OutputFile().Path())
}
+ var srcProviderDepFiles android.Paths
+ for _, dep := range directSrcProvidersDeps {
+ srcs, _ := dep.OutputFiles("")
+ srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
+ }
+ for _, dep := range directSrcDeps {
+ srcs := dep.Srcs()
+ srcProviderDepFiles = append(srcProviderDepFiles, srcs...)
+ }
+
depPaths.RLibs = append(depPaths.RLibs, rlibDepFiles...)
depPaths.DyLibs = append(depPaths.DyLibs, dylibDepFiles...)
depPaths.SharedLibs = append(depPaths.SharedLibs, sharedLibDepFiles...)
depPaths.StaticLibs = append(depPaths.StaticLibs, staticLibDepFiles...)
depPaths.ProcMacros = append(depPaths.ProcMacros, procMacroDepFiles...)
+ depPaths.SrcDeps = append(depPaths.SrcDeps, srcProviderDepFiles...)
// Dedup exported flags from dependencies
depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs)
depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags)
+ depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags)
+ depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths)
+ depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths)
return depPaths
}
@@ -716,22 +961,10 @@
return strings.Split(filepath.String(), filepath.Base())[0]
}
-func libNameFromFilePath(filepath android.Path) string {
- libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
- if strings.HasPrefix(libName, "lib") {
- libName = libName[3:]
- }
- return libName
-}
-
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
- moduleContextImpl: moduleContextImpl{
- mod: mod,
- },
}
- ctx.ctx = ctx
deps := mod.deps(ctx)
commonDepVariations := []blueprint.Variation{}
@@ -745,33 +978,61 @@
}
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
- {Mutator: "rust_libraries", Variation: "rlib"},
- {Mutator: "link", Variation: ""}}...),
+ {Mutator: "rust_libraries", Variation: "rlib"}}...),
rlibDepTag, deps.Rlibs...)
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
- {Mutator: "rust_libraries", Variation: "dylib"},
- {Mutator: "link", Variation: ""}}...),
+ {Mutator: "rust_libraries", Variation: "dylib"}}...),
dylibDepTag, deps.Dylibs...)
+ if deps.Rustlibs != nil && !mod.compiler.Disabled() {
+ autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
+ actx.AddVariationDependencies(
+ append(commonDepVariations, []blueprint.Variation{
+ {Mutator: "rust_libraries", Variation: autoDep.variation}}...),
+ autoDep.depTag, deps.Rustlibs...)
+ }
+
actx.AddVariationDependencies(append(commonDepVariations,
blueprint.Variation{Mutator: "link", Variation: "shared"}),
- cc.SharedDepTag, deps.SharedLibs...)
+ cc.SharedDepTag(), deps.SharedLibs...)
actx.AddVariationDependencies(append(commonDepVariations,
blueprint.Variation{Mutator: "link", Variation: "static"}),
- cc.StaticDepTag, deps.StaticLibs...)
+ cc.StaticDepTag(), deps.StaticLibs...)
+ crtVariations := append(cc.GetCrtVariations(ctx, mod), commonDepVariations...)
if deps.CrtBegin != "" {
- actx.AddVariationDependencies(commonDepVariations, cc.CrtBeginDepTag, deps.CrtBegin)
+ actx.AddVariationDependencies(crtVariations, cc.CrtBeginDepTag, deps.CrtBegin)
}
if deps.CrtEnd != "" {
- actx.AddVariationDependencies(commonDepVariations, cc.CrtEndDepTag, deps.CrtEnd)
+ actx.AddVariationDependencies(crtVariations, cc.CrtEndDepTag, deps.CrtEnd)
}
+ if mod.sourceProvider != nil {
+ if bindgen, ok := mod.sourceProvider.(*bindgenDecorator); ok &&
+ bindgen.Properties.Custom_bindgen != "" {
+ actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), customBindgenDepTag,
+ bindgen.Properties.Custom_bindgen)
+ }
+ }
// proc_macros are compiler plugins, and so we need the host arch variant as a dependendcy.
actx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), procMacroDepTag, deps.ProcMacros...)
}
+func BeginMutator(ctx android.BottomUpMutatorContext) {
+ if mod, ok := ctx.Module().(*Module); ok && mod.Enabled() {
+ mod.beginMutator(ctx)
+ }
+}
+
+func (mod *Module) beginMutator(actx android.BottomUpMutatorContext) {
+ ctx := &baseModuleContext{
+ BaseModuleContext: actx,
+ }
+
+ mod.begin(ctx)
+}
+
func (mod *Module) Name() string {
name := mod.ModuleBase.Name()
if p, ok := mod.compiler.(interface {
@@ -782,7 +1043,27 @@
return name
}
+func (mod *Module) disableClippy() {
+ if mod.clippy != nil {
+ mod.clippy.Properties.Clippy_lints = proptools.StringPtr("none")
+ }
+}
+
+var _ android.HostToolProvider = (*Module)(nil)
+
+func (mod *Module) HostToolPath() android.OptionalPath {
+ if !mod.Host() {
+ return android.OptionalPath{}
+ }
+ if binary, ok := mod.compiler.(*binaryDecorator); ok {
+ return android.OptionalPathForPath(binary.baseCompiler.path)
+ }
+ return android.OptionalPath{}
+}
+
var Bool = proptools.Bool
var BoolDefault = proptools.BoolDefault
var String = proptools.String
var StringPtr = proptools.StringPtr
+
+var _ android.OutputFileProducer = (*Module)(nil)
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 020581d..89ce359 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -21,6 +21,8 @@
"strings"
"testing"
+ "github.com/google/blueprint/proptools"
+
"android/soong/android"
"android/soong/cc"
)
@@ -57,7 +59,10 @@
fs := map[string][]byte{
"foo.rs": nil,
+ "foo.c": nil,
"src/bar.rs": nil,
+ "src/any.h": nil,
+ "buf.proto": nil,
"liby.so": nil,
"libz.so": nil,
}
@@ -68,6 +73,14 @@
}
func testRust(t *testing.T, bp string) *android.TestContext {
+ return testRustContext(t, bp, false)
+}
+
+func testRustCov(t *testing.T, bp string) *android.TestContext {
+ return testRustContext(t, bp, true)
+}
+
+func testRustContext(t *testing.T, bp string, coverage bool) *android.TestContext {
// TODO (b/140435149)
if runtime.GOOS != "linux" {
t.Skip("Only the Linux toolchain is supported for Rust")
@@ -76,7 +89,12 @@
t.Helper()
config := testConfig(bp)
- t.Helper()
+ if coverage {
+ config.TestProductVariables.GcovCoverage = proptools.BoolPtr(true)
+ config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
+ config.TestProductVariables.NativeCoveragePaths = []string{"*"}
+ }
+
ctx := CreateTestContext()
ctx.Register(config)
@@ -115,25 +133,6 @@
t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
}
-// Test that we can extract the lib name from a lib path.
-func TestLibNameFromFilePath(t *testing.T) {
- libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
- libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
-
- libBarName := libNameFromFilePath(libBarPath)
- libLibName := libNameFromFilePath(libLibPath)
-
- expectedResult := "bar.so"
- if libBarName != expectedResult {
- t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
- }
-
- expectedResult = "lib.dylib"
- if libLibName != expectedResult {
- t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
- }
-}
-
// Test that we can extract the link path from a lib path.
func TestLinkPathFromFilePath(t *testing.T) {
barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
@@ -148,12 +147,12 @@
// Test to make sure dependencies are being picked up correctly.
func TestDepsTracking(t *testing.T) {
ctx := testRust(t, `
- rust_library_host_static {
+ rust_ffi_host_static {
name: "libstatic",
srcs: ["foo.rs"],
crate_name: "static",
}
- rust_library_host_shared {
+ rust_ffi_host_shared {
name: "libshared",
srcs: ["foo.rs"],
crate_name: "shared",
@@ -207,6 +206,114 @@
}
}
+func TestSourceProviderDeps(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz-buzz-dep",
+ srcs: [
+ "foo.rs",
+ ":my_generator",
+ ":libbindings",
+ ],
+ rlibs: ["libbindings"],
+ }
+ rust_proc_macro {
+ name: "libprocmacro",
+ srcs: [
+ "foo.rs",
+ ":my_generator",
+ ":libbindings",
+ ],
+ rlibs: ["libbindings"],
+ crate_name: "procmacro",
+ }
+ rust_library {
+ name: "libfoo",
+ srcs: [
+ "foo.rs",
+ ":my_generator",
+ ":libbindings",
+ ],
+ rlibs: ["libbindings"],
+ crate_name: "foo",
+ }
+ genrule {
+ name: "my_generator",
+ tools: ["any_rust_binary"],
+ cmd: "$(location) -o $(out) $(in)",
+ srcs: ["src/any.h"],
+ out: ["src/any.rs"],
+ }
+ rust_bindgen {
+ name: "libbindings",
+ crate_name: "bindings",
+ source_stem: "bindings",
+ host_supported: true,
+ wrapper_src: "src/any.h",
+ }
+ `)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc")
+ if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") {
+ t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
+ }
+ if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/any.rs") {
+ t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings())
+ }
+
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc")
+ if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") {
+ t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
+ }
+ if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/any.rs") {
+ t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings())
+ }
+
+ libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc")
+ if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") {
+ t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
+ }
+ if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/any.rs") {
+ t.Errorf("genrule generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings())
+ }
+
+ // Check that our bindings are picked up as crate dependencies as well
+ libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
+ if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) {
+ t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
+ }
+ fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module)
+ if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) {
+ t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
+ }
+ libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module)
+ if !android.InList("libbindings", libprocmacroMod.Properties.AndroidMkRlibs) {
+ t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)")
+ }
+
+}
+
+func TestSourceProviderTargetMismatch(t *testing.T) {
+ // This might error while building the dependency tree or when calling depsToPaths() depending on the lunched
+ // target, which results in two different errors. So don't check the error, just confirm there is one.
+ testRustError(t, ".*", `
+ rust_proc_macro {
+ name: "libprocmacro",
+ srcs: [
+ "foo.rs",
+ ":libbindings",
+ ],
+ crate_name: "procmacro",
+ }
+ rust_bindgen {
+ name: "libbindings",
+ crate_name: "bindings",
+ source_stem: "bindings",
+ wrapper_src: "src/any.h",
+ }
+ `)
+}
+
// Test to make sure proc_macros use host variants when building device modules.
func TestProcMacroDeviceDeps(t *testing.T) {
ctx := testRust(t, `
@@ -215,25 +322,6 @@
srcs: ["foo.rs"],
crate_name: "bar",
}
- // Make a dummy libstd to let resolution go through
- rust_library_dylib {
- name: "libstd",
- crate_name: "std",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
- rust_library_dylib {
- name: "libterm",
- crate_name: "term",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
- rust_library_dylib {
- name: "libtest",
- crate_name: "test",
- srcs: ["foo.rs"],
- no_stdlibs: true,
- }
rust_proc_macro {
name: "libpm",
rlibs: ["libbar"],
@@ -259,7 +347,7 @@
rust_binary {
name: "fizz-buzz",
srcs: ["foo.rs"],
- no_stdlibs: true,
+ no_stdlibs: true,
}`)
module := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
@@ -267,3 +355,16 @@
t.Errorf("no_stdlibs did not suppress dependency on libstd")
}
}
+
+// Test that libraries provide both 32-bit and 64-bit variants.
+func TestMultilib(t *testing.T) {
+ ctx := testRust(t, `
+ rust_library_rlib {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib")
+ _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib")
+}
diff --git a/rust/source_provider.go b/rust/source_provider.go
new file mode 100644
index 0000000..755a369
--- /dev/null
+++ b/rust/source_provider.go
@@ -0,0 +1,97 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "android/soong/android"
+)
+
+type SourceProviderProperties struct {
+ // filename for the generated source file (<source_stem>.rs). This field is required.
+ // The inherited "stem" property sets the output filename for the generated library variants only.
+ Source_stem *string `android:"arch_variant"`
+
+ // crate name, used for the library variant of this source provider. See additional details in rust_library.
+ Crate_name string `android:"arch_variant"`
+}
+
+type BaseSourceProvider struct {
+ Properties SourceProviderProperties
+
+ OutputFile android.Path
+ subAndroidMkOnce map[SubAndroidMkProvider]bool
+ subName string
+}
+
+var _ SourceProvider = (*BaseSourceProvider)(nil)
+
+type SourceProvider interface {
+ GenerateSource(ctx ModuleContext, deps PathDeps) android.Path
+ Srcs() android.Paths
+ SourceProviderProps() []interface{}
+ SourceProviderDeps(ctx DepsContext, deps Deps) Deps
+ setSubName(subName string)
+}
+
+func (sp *BaseSourceProvider) Srcs() android.Paths {
+ return android.Paths{sp.OutputFile}
+}
+
+func (sp *BaseSourceProvider) GenerateSource(ctx ModuleContext, deps PathDeps) android.Path {
+ panic("BaseSourceProviderModule does not implement GenerateSource()")
+}
+
+func (sp *BaseSourceProvider) SourceProviderProps() []interface{} {
+ return []interface{}{&sp.Properties}
+}
+
+func NewSourceProvider() *BaseSourceProvider {
+ return &BaseSourceProvider{
+ Properties: SourceProviderProperties{},
+ }
+}
+
+func NewSourceProviderModule(hod android.HostOrDeviceSupported, sourceProvider SourceProvider, enableLints bool) *Module {
+ _, library := NewRustLibrary(hod)
+ library.BuildOnlyRust()
+ library.sourceProvider = sourceProvider
+
+ module := newModule(hod, android.MultilibBoth)
+ module.sourceProvider = sourceProvider
+ module.compiler = library
+
+ if !enableLints {
+ library.disableLints()
+ module.disableClippy()
+ }
+
+ return module
+}
+
+func (sp *BaseSourceProvider) getStem(ctx android.ModuleContext) string {
+ if String(sp.Properties.Source_stem) == "" {
+ ctx.PropertyErrorf("source_stem",
+ "source_stem property is undefined but required for rust_bindgen modules")
+ }
+ return String(sp.Properties.Source_stem)
+}
+
+func (sp *BaseSourceProvider) SourceProviderDeps(ctx DepsContext, deps Deps) Deps {
+ return deps
+}
+
+func (sp *BaseSourceProvider) setSubName(subName string) {
+ sp.subName = subName
+}
diff --git a/rust/source_provider_test.go b/rust/source_provider_test.go
new file mode 100644
index 0000000..6e68ae6
--- /dev/null
+++ b/rust/source_provider_test.go
@@ -0,0 +1,31 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+ "testing"
+)
+
+var stemRequiredError = "source_stem property is undefined but required for rust_bindgen modules"
+
+func TestSourceProviderRequiredFields(t *testing.T) {
+ testRustError(t, stemRequiredError, `
+ rust_bindgen {
+ name: "libbindgen",
+ wrapper_src: "src/any.h",
+ crate_name: "bindgen",
+ }
+ `)
+}
diff --git a/rust/strip.go b/rust/strip.go
new file mode 100644
index 0000000..d1bbba6
--- /dev/null
+++ b/rust/strip.go
@@ -0,0 +1,30 @@
+// Copyright 2020 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 rust
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+)
+
+// Stripper encapsulates cc.Stripper.
+type Stripper struct {
+ cc.Stripper
+}
+
+func (s *Stripper) StripExecutableOrSharedLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath) {
+ ccFlags := cc.StripFlags{Toolchain: ctx.RustModule().ccToolchain(ctx)}
+ s.Stripper.StripExecutableOrSharedLib(ctx, in, out, ccFlags)
+}
diff --git a/rust/test.go b/rust/test.go
index 469bec6..d93fc31 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -15,14 +15,16 @@
package rust
import (
- "path/filepath"
- "strings"
-
"android/soong/android"
"android/soong/tradefed"
)
type TestProperties struct {
+ // Disables the creation of a test-specific directory when used with
+ // relative_install_path. Useful if several tests need to be in the same
+ // directory, but test_per_src doesn't work.
+ No_named_install_directory *bool
+
// the name of the test configuration (for example "AndroidTest.xml") that should be
// installed with the module.
Test_config *string `android:"path,arch_variant"`
@@ -39,6 +41,9 @@
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // if set, build with the standard Rust test harness. Defaults to true.
+ Test_harness *bool
}
// A test module is a binary module with extra --test compiler flag
@@ -50,8 +55,23 @@
testConfig android.Path
}
+func (test *testDecorator) nativeCoverage() bool {
+ return true
+}
+
+func (test *testDecorator) testHarness() bool {
+ return BoolDefault(test.Properties.Test_harness, true)
+}
+
func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
- module := newModule(hod, android.MultilibFirst)
+ // Build both 32 and 64 targets for device tests.
+ // Cannot build both for host tests yet if the test depends on
+ // something like proc-macro2 that cannot be built for both.
+ multilib := android.MultilibBoth
+ if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+ multilib = android.MultilibFirst
+ }
+ module := newModule(hod, multilib)
test := &testDecorator{
binaryDecorator: &binaryDecorator{
@@ -60,7 +80,7 @@
}
module.compiler = test
-
+ module.AddProperties(&test.Properties)
return module, test
}
@@ -68,45 +88,36 @@
return append(test.binaryDecorator.compilerProps(), &test.Properties)
}
-func (test *testDecorator) getMutatedModuleSubName(moduleName string) string {
- stem := String(test.baseCompiler.Properties.Stem)
- if stem != "" && !strings.HasSuffix(moduleName, "_"+stem) {
- // Avoid repeated suffix in the module name.
- return "_" + stem
- }
- return ""
-}
-
-func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
- name := ctx.ModuleName()
- path := test.baseCompiler.relativeInstallPath()
- // on device, use mutated module name
- name = name + test.getMutatedModuleSubName(name)
- if !ctx.Device() { // on host, use mutated module name + arch type + stem name
- stem := String(test.baseCompiler.Properties.Stem)
- if stem == "" {
- stem = name
- }
- name = filepath.Join(name, ctx.Arch().ArchType.String(), stem)
- }
- test.testConfig = tradefed.AutoGenRustTestConfig(ctx, name,
+func (test *testDecorator) install(ctx ModuleContext) {
+ test.testConfig = tradefed.AutoGenRustTestConfig(ctx,
test.Properties.Test_config,
test.Properties.Test_config_template,
test.Properties.Test_suites,
+ nil,
test.Properties.Auto_gen_config)
+
// default relative install path is module name
- if path == "" {
+ if !Bool(test.Properties.No_named_install_directory) {
test.baseCompiler.relative = ctx.ModuleName()
+ } else if String(test.baseCompiler.Properties.Relative_install_path) == "" {
+ ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
}
- test.binaryDecorator.install(ctx, file)
+
+ test.binaryDecorator.install(ctx)
}
func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = test.binaryDecorator.compilerFlags(ctx, flags)
- flags.RustFlags = append(flags.RustFlags, "--test")
+ if test.testHarness() {
+ flags.RustFlags = append(flags.RustFlags, "--test")
+ }
return flags
}
+func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep {
+ return rlibAutoDep
+}
+
func init() {
// Rust tests are binary files built with --test.
android.RegisterModuleType("rust_test", RustTestFactory)
@@ -122,64 +133,3 @@
module, _ := NewRustTest(android.HostSupported)
return module.Init()
}
-
-func (test *testDecorator) testPerSrc() bool {
- return true
-}
-
-func (test *testDecorator) srcs() []string {
- return test.binaryDecorator.Properties.Srcs
-}
-
-func (test *testDecorator) setSrc(name, src string) {
- test.binaryDecorator.Properties.Srcs = []string{src}
- test.baseCompiler.Properties.Stem = StringPtr(name)
-}
-
-func (test *testDecorator) unsetSrc() {
- test.binaryDecorator.Properties.Srcs = nil
- test.baseCompiler.Properties.Stem = StringPtr("")
-}
-
-type testPerSrc interface {
- testPerSrc() bool
- srcs() []string
- setSrc(string, string)
- unsetSrc()
-}
-
-var _ testPerSrc = (*testDecorator)(nil)
-
-func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(*Module); ok {
- if test, ok := m.compiler.(testPerSrc); ok {
- numTests := len(test.srcs())
- if test.testPerSrc() && numTests > 0 {
- if duplicate, found := android.CheckDuplicate(test.srcs()); found {
- mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
- return
- }
- // Rust compiler always compiles one source file at a time and
- // uses the crate name as output file name.
- // Cargo uses the test source file name as default crate name,
- // but that can be redefined.
- // So when there are multiple source files, the source file names will
- // be the output file names, but when there is only one test file,
- // use the crate name.
- testNames := make([]string, numTests)
- for i, src := range test.srcs() {
- testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
- }
- crateName := m.compiler.crateName()
- if numTests == 1 && crateName != "" {
- testNames[0] = crateName
- }
- // TODO(chh): Add an "all tests" variation like cc/test.go?
- tests := mctx.CreateLocalVariations(testNames...)
- for i, src := range test.srcs() {
- tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
- }
- }
- }
- }
-}
diff --git a/rust/test_test.go b/rust/test_test.go
index f131c6e..2382b18 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -19,45 +19,17 @@
"testing"
)
-// Check if rust_test_host accepts multiple source files and applies --test flag.
func TestRustTest(t *testing.T) {
ctx := testRust(t, `
rust_test_host {
name: "my_test",
- srcs: ["foo.rs", "src/bar.rs"],
- crate_name: "new_test", // not used for multiple source files
- relative_install_path: "rust/my-test",
- }`)
-
- for _, name := range []string{"foo", "bar"} {
- testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64_"+name)
- testingBuildParams := testingModule.Output(name)
- rustcFlags := testingBuildParams.Args["rustcFlags"]
- if !strings.Contains(rustcFlags, "--test") {
- t.Errorf("%v missing --test flag, rustcFlags: %#v", name, rustcFlags)
- }
- outPath := "/my_test/linux_glibc_x86_64_" + name + "/" + name
- if !strings.Contains(testingBuildParams.Output.String(), outPath) {
- t.Errorf("wrong output: %v expect: %v", testingBuildParams.Output, outPath)
- }
- }
-}
-
-// crate_name is output file name, when there is only one source file.
-func TestRustTestSingleFile(t *testing.T) {
- ctx := testRust(t, `
- rust_test_host {
- name: "my-test",
srcs: ["foo.rs"],
- crate_name: "new_test",
- relative_install_path: "my-pkg",
}`)
- name := "new_test"
- testingModule := ctx.ModuleForTests("my-test", "linux_glibc_x86_64_"+name)
- outPath := "/my-test/linux_glibc_x86_64_" + name + "/" + name
- testingBuildParams := testingModule.Output(name)
- if !strings.Contains(testingBuildParams.Output.String(), outPath) {
- t.Errorf("wrong output: %v expect: %v", testingBuildParams.Output, outPath)
+ testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64")
+ expectedOut := "my_test/linux_glibc_x86_64/my_test"
+ outPath := testingModule.Output("my_test").Output.String()
+ if !strings.Contains(outPath, expectedOut) {
+ t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut)
}
}
diff --git a/rust/testing.go b/rust/testing.go
index f9adec8..0144c82 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -17,61 +17,55 @@
import (
"android/soong/android"
"android/soong/cc"
+ "android/soong/genrule"
)
func GatherRequiredDepsForTest() string {
bp := `
- rust_prebuilt_dylib {
- name: "libarena_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libfmt_macros_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libgraphviz_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libserialize_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
+ rust_prebuilt_library {
name: "libstd_x86_64-unknown-linux-gnu",
- srcs: [""],
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd.so"],
+ },
host_supported: true,
}
- rust_prebuilt_dylib {
- name: "libsyntax_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libsyntax_ext_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libsyntax_pos_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
- name: "libterm_x86_64-unknown-linux-gnu",
- srcs: [""],
- host_supported: true,
- }
- rust_prebuilt_dylib {
+ rust_prebuilt_library {
name: "libtest_x86_64-unknown-linux-gnu",
- srcs: [""],
+ crate_name: "test",
+ rlib: {
+ srcs: ["libtest.rlib"],
+ },
+ dylib: {
+ srcs: ["libtest.so"],
+ },
host_supported: true,
}
-
+ rust_prebuilt_library {
+ name: "libstd_x86_64-apple-darwin",
+ crate_name: "std",
+ rlib: {
+ srcs: ["libstd.rlib"],
+ },
+ dylib: {
+ srcs: ["libstd.so"],
+ },
+ host_supported: true,
+ }
+ rust_prebuilt_library {
+ name: "libtest_x86_64-apple-darwin",
+ crate_name: "test",
+ rlib: {
+ srcs: ["libtest.rlib"],
+ },
+ dylib: {
+ srcs: ["libtest.so"],
+ },
+ host_supported: true,
+ }
//////////////////////////////
// Device module requirements
@@ -81,34 +75,68 @@
nocrt: true,
system_shared_libs: [],
}
+ rust_library {
+ name: "libstd",
+ crate_name: "std",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ host_supported: true,
+ native_coverage: false,
+ }
+ rust_library {
+ name: "libtest",
+ crate_name: "test",
+ srcs: ["foo.rs"],
+ no_stdlibs: true,
+ host_supported: true,
+ native_coverage: false,
+ }
+ rust_library {
+ name: "libprotobuf",
+ crate_name: "protobuf",
+ srcs: ["foo.rs"],
+ host_supported: true,
+ }
+
` + cc.GatherRequiredDepsForTest(android.NoOsType)
return bp
}
func CreateTestContext() *android.TestContext {
ctx := android.NewTestArchContext()
+ android.RegisterPrebuiltMutators(ctx)
+ ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
cc.RegisterRequiredBuildComponentsForTest(ctx)
+ ctx.RegisterModuleType("genrule", genrule.GenRuleFactory)
ctx.RegisterModuleType("rust_binary", RustBinaryFactory)
ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory)
+ ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory)
ctx.RegisterModuleType("rust_test", RustTestFactory)
ctx.RegisterModuleType("rust_test_host", RustTestHostFactory)
ctx.RegisterModuleType("rust_library", RustLibraryFactory)
- ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
- ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
- ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
- ctx.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
ctx.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory)
- ctx.RegisterModuleType("rust_library_shared", RustLibrarySharedFactory)
- ctx.RegisterModuleType("rust_library_static", RustLibraryStaticFactory)
- ctx.RegisterModuleType("rust_library_host_shared", RustLibrarySharedHostFactory)
- ctx.RegisterModuleType("rust_library_host_static", RustLibraryStaticHostFactory)
+ ctx.RegisterModuleType("rust_library_rlib", RustLibraryRlibFactory)
+ ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory)
+ ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory)
+ ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory)
+ ctx.RegisterModuleType("rust_ffi", RustFFIFactory)
+ ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory)
+ ctx.RegisterModuleType("rust_ffi_static", RustFFIStaticFactory)
+ ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory)
+ ctx.RegisterModuleType("rust_ffi_host_static", RustFFIStaticHostFactory)
ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory)
+ ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory)
+ ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory)
+ ctx.RegisterModuleType("rust_prebuilt_library", PrebuiltLibraryFactory)
ctx.RegisterModuleType("rust_prebuilt_dylib", PrebuiltDylibFactory)
+ ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
// rust mutators
ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
- ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
+ ctx.BottomUp("rust_begin", BeginMutator).Parallel()
})
+ ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
return ctx
}
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 1f55030..7782c68 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -106,7 +106,7 @@
py3: {
enabled: false,
},
- }
+ },
}
python_binary_host {
@@ -150,7 +150,59 @@
}
python_binary_host {
+ name: "construct_context",
+ main: "construct_context.py",
+ srcs: [
+ "construct_context.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+ libs: [
+ "manifest_utils",
+ ],
+}
+
+python_test_host {
+ name: "construct_context_test",
+ main: "construct_context_test.py",
+ srcs: [
+ "construct_context_test.py",
+ "construct_context.py",
+ ],
+ version: {
+ py2: {
+ enabled: true,
+ },
+ py3: {
+ enabled: false,
+ },
+ },
+ libs: [
+ "manifest_utils",
+ ],
+ test_suites: ["general-tests"],
+}
+
+python_binary_host {
name: "lint-project-xml",
main: "lint-project-xml.py",
- srcs: ["lint-project-xml.py"],
+ srcs: [
+ "lint-project-xml.py",
+ "ninja_rsp.py",
+ ],
+}
+
+python_binary_host {
+ name: "gen-kotlin-build-file.py",
+ main: "gen-kotlin-build-file.py",
+ srcs: [
+ "gen-kotlin-build-file.py",
+ "ninja_rsp.py",
+ ],
}
diff --git a/scripts/OWNERS b/scripts/OWNERS
index 9e97a60..8c64424 100644
--- a/scripts/OWNERS
+++ b/scripts/OWNERS
@@ -1,2 +1,4 @@
per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com
+per-file construct_context.py = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com
diff --git a/scripts/build-aml-prebuilts.sh b/scripts/build-aml-prebuilts.sh
index c60eaa1..ef5565d 100755
--- a/scripts/build-aml-prebuilts.sh
+++ b/scripts/build-aml-prebuilts.sh
@@ -84,6 +84,8 @@
"CrossHostArch": "x86_64",
"Aml_abis": true,
+ "Allow_missing_dependencies": ${SOONG_ALLOW_MISSING_DEPENDENCIES:-false},
+ "Unbundled_build": ${TARGET_BUILD_UNBUNDLED:-false},
"UseGoma": ${USE_GOMA}
}
EOF
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index f836ea9..c5ec8d1 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -20,6 +20,18 @@
conscrypt-module-test-exports
conscrypt-module-host-exports
runtime-module-sdk
+ runtime-module-host-exports
+ i18n-module-test-exports
+ i18n-module-sdk
+ platform-mainline-sdk
+ platform-mainline-test-exports
+)
+
+# List of libraries installed on the platform that are needed for ART chroot
+# testing.
+PLATFORM_LIBRARIES=(
+ liblog
+ libartpalette-system
)
# We want to create apex modules for all supported architectures.
@@ -40,13 +52,21 @@
"$@"
}
+lib_dir() {
+ case $1 in
+ (aosp_arm|aosp_x86) echo "lib";;
+ (aosp_arm64|aosp_x86_64) echo "lib64";;
+ esac
+}
+
OUT_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var OUT_DIR)
DIST_DIR=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT= get_build_var DIST_DIR)
for product in "${PRODUCTS[@]}"; do
echo_and_run build/soong/soong_ui.bash --make-mode $@ \
TARGET_PRODUCT=${product} \
- ${MAINLINE_MODULES[@]}
+ ${MAINLINE_MODULES[@]} \
+ ${PLATFORM_LIBRARIES[@]}
PRODUCT_OUT=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var PRODUCT_OUT)
TARGET_ARCH=$(source build/envsetup.sh > /dev/null; TARGET_PRODUCT=${product} get_build_var TARGET_ARCH)
@@ -55,9 +75,12 @@
for module in "${MAINLINE_MODULES[@]}"; do
echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/apex/${module}.apex ${DIST_DIR}/${TARGET_ARCH}/
done
+ for library in "${PLATFORM_LIBRARIES[@]}"; do
+ libdir=$(lib_dir $product)
+ echo_and_run cp ${PWD}/${PRODUCT_OUT}/system/${libdir}/${library}.so ${DIST_DIR}/${TARGET_ARCH}/
+ done
done
-
# Create multi-archs SDKs in a different out directory. The multi-arch script
# uses Soong in --skip-make mode which cannot use the same directory as normal
# mode with make.
diff --git a/scripts/build_broken_logs.go b/scripts/build_broken_logs.go
index 8021e55..82ba749 100644
--- a/scripts/build_broken_logs.go
+++ b/scripts/build_broken_logs.go
@@ -54,11 +54,13 @@
DefaultDeprecated
)
-var buildBrokenSettings = []struct {
+type Setting struct {
name string
behavior BuildBrokenBehavior
warnings []string
-}{
+}
+
+var buildBrokenSettings = []Setting{
{
name: "BUILD_BROKEN_DUP_RULES",
behavior: DefaultFalse,
@@ -68,6 +70,19 @@
name: "BUILD_BROKEN_USES_NETWORK",
behavior: DefaultDeprecated,
},
+ {
+ name: "BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
+ behavior: DefaultTrue,
+ warnings: []string{
+ "COPY_HEADERS has been deprecated",
+ "COPY_HEADERS is deprecated",
+ },
+ },
+}
+
+type Branch struct {
+ Settings []Setting
+ Logs []ProductLog
}
type ProductBranch struct {
@@ -82,35 +97,48 @@
}
type Log struct {
- BuildBroken []*bool
- HasBroken []bool
+ WarningModuleTypes []string
+ ErrorModuleTypes []string
+
+ BuildBroken map[string]*bool
+ HasBroken map[string]int
}
func Merge(l, l2 Log) Log {
- if len(l.BuildBroken) == 0 {
- l.BuildBroken = make([]*bool, len(buildBrokenSettings))
+ if l.BuildBroken == nil {
+ l.BuildBroken = map[string]*bool{}
}
- if len(l.HasBroken) == 0 {
- l.HasBroken = make([]bool, len(buildBrokenSettings))
+ if l.HasBroken == nil {
+ l.HasBroken = map[string]int{}
}
- if len(l.BuildBroken) != len(l2.BuildBroken) || len(l.HasBroken) != len(l2.HasBroken) {
- panic("mis-matched logs")
- }
-
- for i, v := range l.BuildBroken {
+ for n, v := range l.BuildBroken {
if v == nil {
- l.BuildBroken[i] = l2.BuildBroken[i]
+ l.BuildBroken[n] = l2.BuildBroken[n]
}
}
- for i := range l.HasBroken {
- l.HasBroken[i] = l.HasBroken[i] || l2.HasBroken[i]
+ for n, v := range l2.BuildBroken {
+ if _, ok := l.BuildBroken[n]; !ok {
+ l.BuildBroken[n] = v
+ }
+ }
+
+ for n := range l.HasBroken {
+ if l.HasBroken[n] < l2.HasBroken[n] {
+ l.HasBroken[n] = l2.HasBroken[n]
+ }
+ }
+ for n := range l2.HasBroken {
+ if _, ok := l.HasBroken[n]; !ok {
+ l.HasBroken[n] = l2.HasBroken[n]
+ }
}
return l
}
-func PrintResults(products []ProductLog) {
+func PrintResults(branch Branch) {
+ products := branch.Logs
devices := map[string]Log{}
deviceNames := []string{}
@@ -124,39 +152,48 @@
sort.Strings(deviceNames)
- for i, setting := range buildBrokenSettings {
+ for _, setting := range branch.Settings {
printed := false
+ n := setting.name
for _, device := range deviceNames {
log := devices[device]
if setting.behavior == DefaultTrue {
- if log.BuildBroken[i] == nil || *log.BuildBroken[i] == false {
- if log.HasBroken[i] {
+ if log.BuildBroken[n] == nil || *log.BuildBroken[n] == false {
+ if log.HasBroken[n] > 0 {
printed = true
- fmt.Printf(" %s needs to set %s := true\n", device, setting.name)
+ plural := ""
+ if log.HasBroken[n] > 1 {
+ plural = "s"
+ }
+ fmt.Printf(" %s needs to set %s := true (%d instance%s)\n", device, setting.name, log.HasBroken[n], plural)
}
- } else if !log.HasBroken[i] {
+ } else if log.HasBroken[n] == 0 {
printed = true
fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
}
} else if setting.behavior == DefaultFalse {
- if log.BuildBroken[i] == nil {
+ if log.BuildBroken[n] == nil {
// Nothing to be done
- } else if *log.BuildBroken[i] == false {
+ } else if *log.BuildBroken[n] == false {
printed = true
fmt.Printf(" %s sets %s := false, which is the default and can be removed\n", device, setting.name)
- } else if !log.HasBroken[i] {
+ } else if log.HasBroken[n] == 0 {
printed = true
fmt.Printf(" %s sets %s := true, but does not need it\n", device, setting.name)
}
} else if setting.behavior == DefaultDeprecated {
- if log.BuildBroken[i] != nil {
+ if log.BuildBroken[n] != nil {
printed = true
- if log.HasBroken[i] {
- fmt.Printf(" %s sets %s := %v, which is deprecated, but has failures\n", device, setting.name, *log.BuildBroken[i])
+ if log.HasBroken[n] > 0 {
+ plural := ""
+ if log.HasBroken[n] > 1 {
+ plural = "s"
+ }
+ fmt.Printf(" %s sets %s := %v, which is deprecated, but has %d failure%s\n", device, setting.name, *log.BuildBroken[n], log.HasBroken[n], plural)
} else {
- fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[i])
+ fmt.Printf(" %s sets %s := %v, which is deprecated and can be removed\n", device, setting.name, *log.BuildBroken[n])
}
}
}
@@ -168,17 +205,45 @@
}
}
-func ParseBranch(name string) []ProductLog {
+func ParseBranch(name string) Branch {
products, err := filepath.Glob(filepath.Join(name, "*"))
if err != nil {
log.Fatal(err)
}
- ret := []ProductLog{}
+ ret := Branch{Logs: []ProductLog{}}
for _, product := range products {
product = filepath.Base(product)
- ret = append(ret, ParseProduct(ProductBranch{Branch: name, Name: product}))
+ ret.Logs = append(ret.Logs, ParseProduct(ProductBranch{Branch: name, Name: product}))
+ }
+
+ ret.Settings = append(ret.Settings, buildBrokenSettings...)
+ if len(ret.Logs) > 0 {
+ for _, mtype := range ret.Logs[0].WarningModuleTypes {
+ if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
+ continue
+ }
+ ret.Settings = append(ret.Settings, Setting{
+ name: "BUILD_BROKEN_USES_" + mtype,
+ behavior: DefaultTrue,
+ warnings: []string{mtype + " has been deprecated"},
+ })
+ }
+ for _, mtype := range ret.Logs[0].ErrorModuleTypes {
+ if mtype == "BUILD_COPY_HEADERS" || mtype == "" {
+ continue
+ }
+ ret.Settings = append(ret.Settings, Setting{
+ name: "BUILD_BROKEN_USES_" + mtype,
+ behavior: DefaultFalse,
+ warnings: []string{mtype + " has been deprecated"},
+ })
+ }
+ }
+
+ for _, productLog := range ret.Logs {
+ ScanProduct(ret.Settings, productLog)
}
return ret
}
@@ -192,15 +257,15 @@
ret := ProductLog{
ProductBranch: p,
Log: Log{
- BuildBroken: make([]*bool, len(buildBrokenSettings)),
- HasBroken: make([]bool, len(buildBrokenSettings)),
+ BuildBroken: map[string]*bool{},
+ HasBroken: map[string]int{},
},
}
lines := strings.Split(string(soongLog), "\n")
for _, line := range lines {
fields := strings.Split(line, " ")
- if len(fields) != 5 {
+ if len(fields) < 5 {
continue
}
@@ -208,30 +273,35 @@
ret.Device = fields[4]
}
+ if fields[3] == "DEFAULT_WARNING_BUILD_MODULE_TYPES" {
+ ret.WarningModuleTypes = fields[4:]
+ }
+ if fields[3] == "DEFAULT_ERROR_BUILD_MODULE_TYPES" {
+ ret.ErrorModuleTypes = fields[4:]
+ }
+
if strings.HasPrefix(fields[3], "BUILD_BROKEN_") {
- for i, setting := range buildBrokenSettings {
- if setting.name == fields[3] {
- ret.BuildBroken[i] = ParseBoolPtr(fields[4])
- }
- }
+ ret.BuildBroken[fields[3]] = ParseBoolPtr(fields[4])
}
}
- stdLog, err := ioutil.ReadFile(filepath.Join(p.Branch, p.Name, "std_full.log"))
+ return ret
+}
+
+func ScanProduct(settings []Setting, l ProductLog) {
+ stdLog, err := ioutil.ReadFile(filepath.Join(l.Branch, l.Name, "std_full.log"))
if err != nil {
log.Fatal(err)
}
stdStr := string(stdLog)
- for i, setting := range buildBrokenSettings {
+ for _, setting := range settings {
for _, warning := range setting.warnings {
if strings.Contains(stdStr, warning) {
- ret.HasBroken[i] = true
+ l.HasBroken[setting.name] += strings.Count(stdStr, warning)
}
}
}
-
- return ret
}
func ParseBoolPtr(str string) *bool {
diff --git a/scripts/construct_context.py b/scripts/construct_context.py
new file mode 100755
index 0000000..8717fe3
--- /dev/null
+++ b/scripts/construct_context.py
@@ -0,0 +1,90 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""A tool for constructing class loader context."""
+
+from __future__ import print_function
+
+import argparse
+import sys
+
+from manifest import compare_version_gt
+
+
+def parse_args(args):
+ """Parse commandline arguments."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--target-sdk-version', default='', dest='sdk',
+ help='specify target SDK version (as it appears in the manifest)')
+ parser.add_argument('--host-classpath-for-sdk', dest='host_classpaths',
+ action='append', nargs=2, metavar=('sdk','classpath'),
+ help='specify classpath on host for a given SDK version or "any" version')
+ parser.add_argument('--target-classpath-for-sdk', dest='target_classpaths',
+ action='append', nargs=2, metavar=('sdk','classpath'),
+ help='specify classpath on target for a given SDK version or "any" version')
+ return parser.parse_args(args)
+
+# The hidl.manager shared library has a dependency on hidl.base. We manually
+# add that information to the class loader context if we see those libraries.
+HIDL_MANAGER = 'android.hidl.manager-V1.0-java'
+HIDL_BASE = 'android.hidl.base-V1.0-java'
+
+# Special keyword that means that the classpath should be added to class loader
+# context regardless of the target SDK version.
+any_sdk = 'any'
+
+# We assume that the order of classpath arguments passed to this script is
+# correct (matches the order computed by package manager). It is possible to
+# sort them here, but Soong needs to use deterministic order anyway, so it can
+# as well use the correct order.
+def construct_context(versioned_classpaths, target_sdk):
+ context = []
+ for [sdk, classpath] in versioned_classpaths:
+ if sdk == any_sdk or compare_version_gt(sdk, target_sdk):
+ for jar in classpath.split(':'):
+ pcl = 'PCL[%s]' % jar
+ if HIDL_MANAGER in jar:
+ pcl += '{PCL[%s]}' % jar.replace(HIDL_MANAGER, HIDL_BASE, 1)
+ context.append(pcl)
+ return context
+
+def construct_contexts(args):
+ host_context = construct_context(args.host_classpaths, args.sdk)
+ target_context = construct_context(args.target_classpaths, args.sdk)
+ context_sep = '#'
+ return ('class_loader_context_arg=--class-loader-context=PCL[]{%s} ; ' % context_sep.join(host_context) +
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{%s}' % context_sep.join(target_context))
+
+def main():
+ """Program entry point."""
+ try:
+ args = parse_args(sys.argv[1:])
+ if not args.sdk:
+ raise SystemExit('target sdk version is not set')
+ if not args.host_classpaths:
+ raise SystemExit('host classpath is not set')
+ if not args.target_classpaths:
+ raise SystemExit('target classpath is not set')
+
+ print(construct_contexts(args))
+
+ # pylint: disable=broad-except
+ except Exception as err:
+ print('error: ' + str(err), file=sys.stderr)
+ sys.exit(-1)
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/construct_context_test.py b/scripts/construct_context_test.py
new file mode 100755
index 0000000..0b0b0a3
--- /dev/null
+++ b/scripts/construct_context_test.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Unit tests for construct_context.py."""
+
+import sys
+import unittest
+
+import construct_context as cc
+
+sys.dont_write_bytecode = True
+
+def construct_contexts(arglist):
+ args = cc.parse_args(arglist)
+ return cc.construct_contexts(args)
+
+classpaths = [
+ '--host-classpath-for-sdk', '28', 'out/zdir/z.jar',
+ '--target-classpath-for-sdk', '28', '/system/z.jar',
+ '--host-classpath-for-sdk', '29', 'out/xdir/x.jar:out/ydir/y.jar',
+ '--target-classpath-for-sdk', '29', '/system/x.jar:/product/y.jar',
+ '--host-classpath-for-sdk', 'any', 'out/adir/a.jar:out/android.hidl.manager-V1.0-java.jar:out/bdir/b.jar',
+ '--target-classpath-for-sdk', 'any', '/system/a.jar:/system/android.hidl.manager-V1.0-java.jar:/product/b.jar',
+]
+
+class ConstructContextTest(unittest.TestCase):
+ def test_construct_context_28(self):
+ args = ['--target-sdk-version', '28'] + classpaths
+ result = construct_contexts(args)
+ expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/xdir/x.jar]'
+ '#PCL[out/ydir/y.jar]'
+ '#PCL[out/adir/a.jar]'
+ '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/x.jar]'
+ '#PCL[/product/y.jar]'
+ '#PCL[/system/a.jar]'
+ '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
+
+ def test_construct_context_29(self):
+ args = ['--target-sdk-version', '29'] + classpaths
+ result = construct_contexts(args)
+ expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
+ '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
+ '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
+
+ def test_construct_context_S(self):
+ args = ['--target-sdk-version', 'S'] + classpaths
+ result = construct_contexts(args)
+ expect = ('class_loader_context_arg=--class-loader-context=PCL[]{PCL[out/adir/a.jar]'
+ '#PCL[out/android.hidl.manager-V1.0-java.jar]{PCL[out/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[out/bdir/b.jar]}'
+ ' ; '
+ 'stored_class_loader_context_arg=--stored-class-loader-context=PCL[]{PCL[/system/a.jar]'
+ '#PCL[/system/android.hidl.manager-V1.0-java.jar]{PCL[/system/android.hidl.base-V1.0-java.jar]}'
+ '#PCL[/product/b.jar]}')
+ self.assertEqual(result, expect)
+
+if __name__ == '__main__':
+ unittest.main(verbosity=2)
diff --git a/scripts/gen-kotlin-build-file.py b/scripts/gen-kotlin-build-file.py
new file mode 100644
index 0000000..83b4cd8
--- /dev/null
+++ b/scripts/gen-kotlin-build-file.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018 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.
+
+# Generates kotlinc module xml file to drive kotlinc
+
+import argparse
+import os
+
+from ninja_rsp import NinjaRspFileReader
+
+def parse_args():
+ """Parse commandline arguments."""
+
+ def convert_arg_line_to_args(arg_line):
+ for arg in arg_line.split():
+ if arg.startswith('#'):
+ return
+ if not arg.strip():
+ continue
+ yield arg
+
+ parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+ parser.convert_arg_line_to_args = convert_arg_line_to_args
+ parser.add_argument('--out', dest='out',
+ help='file to which the module.xml contents will be written.')
+ parser.add_argument('--classpath', dest='classpath', action='append', default=[],
+ help='classpath to pass to kotlinc.')
+ parser.add_argument('--name', dest='name',
+ help='name of the module.')
+ parser.add_argument('--out_dir', dest='out_dir',
+ help='directory to which kotlinc will write output files.')
+ parser.add_argument('--srcs', dest='srcs', action='append', default=[],
+ help='file containing whitespace separated list of source files.')
+ parser.add_argument('--common_srcs', dest='common_srcs', action='append', default=[],
+ help='file containing whitespace separated list of common multiplatform source files.')
+
+ return parser.parse_args()
+
+def main():
+ """Program entry point."""
+ args = parse_args()
+
+ if not args.out:
+ raise RuntimeError('--out argument is required')
+
+ if not args.name:
+ raise RuntimeError('--name argument is required')
+
+ with open(args.out, 'w') as f:
+ # Print preamble
+ f.write('<modules>\n')
+ f.write(' <module name="%s" type="java-production" outputDir="%s">\n' % (args.name, args.out_dir or ''))
+
+ # Print classpath entries
+ for c in args.classpath:
+ for entry in c.split(':'):
+ path = os.path.abspath(entry)
+ f.write(' <classpath path="%s"/>\n' % path)
+
+ # For each rsp file, print source entries
+ for rsp_file in args.srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ if src.endswith('.java'):
+ f.write(' <javaSourceRoots path="%s"/>\n' % path)
+ elif src.endswith('.kt'):
+ f.write(' <sources path="%s"/>\n' % path)
+ else:
+ raise RuntimeError('unknown source file type %s' % file)
+
+ for rsp_file in args.common_srcs:
+ for src in NinjaRspFileReader(rsp_file):
+ path = os.path.abspath(src)
+ f.write(' <sources path="%s"/>\n' % path)
+ f.write(' <commonSources path="%s"/>\n' % path)
+
+ f.write(' </module>\n')
+ f.write('</modules>\n')
+
+if __name__ == '__main__':
+ main()
diff --git a/scripts/gen-kotlin-build-file.sh b/scripts/gen-kotlin-build-file.sh
deleted file mode 100755
index 177ca1b..0000000
--- a/scripts/gen-kotlin-build-file.sh
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/bin/bash -e
-
-# Copyright 2018 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.
-
-# Generates kotlinc module xml file to standard output based on rsp files
-
-if [[ -z "$1" ]]; then
- echo "usage: $0 <classpath> <name> <outDir> <rspFiles>..." >&2
- exit 1
-fi
-
-# Classpath variable has a tendency to be prefixed by "-classpath", remove it.
-if [[ $1 == "-classpath" ]]; then
- shift
-fi;
-
-classpath=$1
-name=$2
-out_dir=$3
-shift 3
-
-# Path in the build file may be relative to the build file, we need to make them
-# absolute
-prefix="$(pwd)"
-
-get_abs_path () {
- local file="$1"
- if [[ "${file:0:1}" == '/' ]] ; then
- echo "${file}"
- else
- echo "${prefix}/${file}"
- fi
-}
-
-# Print preamble
-echo "<modules><module name=\"${name}\" type=\"java-production\" outputDir=\"${out_dir}\">"
-
-# Print classpath entries
-for file in $(echo "$classpath" | tr ":" "\n"); do
- path="$(get_abs_path "$file")"
- echo " <classpath path=\"${path}\"/>"
-done
-
-# For each rsp file, print source entries
-while (( "$#" )); do
- for file in $(cat "$1"); do
- path="$(get_abs_path "$file")"
- if [[ $file == *.java ]]; then
- echo " <javaSourceRoots path=\"${path}\"/>"
- elif [[ $file == *.kt ]]; then
- echo " <sources path=\"${path}\"/>"
- else
- echo "Unknown source file type ${file}"
- exit 1
- fi
- done
-
- shift
-done
-
-echo "</module></modules>"
diff --git a/scripts/generate-notice-files.py b/scripts/generate-notice-files.py
new file mode 100755
index 0000000..49011b2
--- /dev/null
+++ b/scripts/generate-notice-files.py
@@ -0,0 +1,267 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2012 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+Usage: generate-notice-files --text-output [plain text output file] \
+ --html-output [html output file] \
+ --xml-output [xml output file] \
+ -t [file title] -s [directory of notices]
+
+Generate the Android notice files, including both text and html files.
+
+-h to display this usage message and exit.
+"""
+from collections import defaultdict
+import argparse
+import hashlib
+import itertools
+import os
+import os.path
+import re
+import sys
+
+MD5_BLOCKSIZE = 1024 * 1024
+HTML_ESCAPE_TABLE = {
+ "&": "&",
+ '"': """,
+ "'": "'",
+ ">": ">",
+ "<": "<",
+ }
+
+def hexify(s):
+ return ("%02x"*len(s)) % tuple(map(ord, s))
+
+def md5sum(filename):
+ """Calculate an MD5 of the file given by FILENAME,
+ and return hex digest as a string.
+ Output should be compatible with md5sum command"""
+
+ f = open(filename, "rb")
+ sum = hashlib.md5()
+ while 1:
+ block = f.read(MD5_BLOCKSIZE)
+ if not block:
+ break
+ sum.update(block)
+ f.close()
+ return hexify(sum.digest())
+
+
+def html_escape(text):
+ """Produce entities within text."""
+ return "".join(HTML_ESCAPE_TABLE.get(c,c) for c in text)
+
+HTML_OUTPUT_CSS="""
+<style type="text/css">
+body { padding: 0; font-family: sans-serif; }
+.same-license { background-color: #eeeeee; border-top: 20px solid white; padding: 10px; }
+.label { font-weight: bold; }
+.file-list { margin-left: 1em; color: blue; }
+</style>
+"""
+
+def combine_notice_files_html(file_hash, input_dir, output_filename):
+ """Combine notice files in FILE_HASH and output a HTML version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+
+ # Set up a filename to row id table (anchors inside tables don't work in
+ # most browsers, but href's to table row ids do)
+ id_table = {}
+ id_count = 0
+ for value in file_hash:
+ for filename in value:
+ id_table[filename] = id_count
+ id_count += 1
+
+ # Open the output file, and output the header pieces
+ output_file = open(output_filename, "wb")
+
+ print >> output_file, "<html><head>"
+ print >> output_file, HTML_OUTPUT_CSS
+ print >> output_file, '</head><body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">'
+
+ # Output our table of contents
+ print >> output_file, '<div class="toc">'
+ print >> output_file, "<ul>"
+
+ # Flatten the list of lists into a single list of filenames
+ sorted_filenames = sorted(itertools.chain.from_iterable(file_hash))
+
+ # Print out a nice table of contents
+ for filename in sorted_filenames:
+ stripped_filename = SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, '<li><a href="#id%d">%s</a></li>' % (id_table.get(filename), stripped_filename)
+
+ print >> output_file, "</ul>"
+ print >> output_file, "</div><!-- table of contents -->"
+ # Output the individual notice file lists
+ print >>output_file, '<table cellpadding="0" cellspacing="0" border="0">'
+ for value in file_hash:
+ print >> output_file, '<tr id="id%d"><td class="same-license">' % id_table.get(value[0])
+ print >> output_file, '<div class="label">Notices for file(s):</div>'
+ print >> output_file, '<div class="file-list">'
+ for filename in value:
+ print >> output_file, "%s <br/>" % (SRC_DIR_STRIP_RE.sub(r"\1", filename))
+ print >> output_file, "</div><!-- file-list -->"
+ print >> output_file
+ print >> output_file, '<pre class="license-text">'
+ print >> output_file, html_escape(open(value[0]).read())
+ print >> output_file, "</pre><!-- license-text -->"
+ print >> output_file, "</td></tr><!-- same-license -->"
+ print >> output_file
+ print >> output_file
+ print >> output_file
+
+ # Finish off the file output
+ print >> output_file, "</table>"
+ print >> output_file, "</body></html>"
+ output_file.close()
+
+def combine_notice_files_text(file_hash, input_dir, output_filename, file_title):
+ """Combine notice files in FILE_HASH and output a text version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+ output_file = open(output_filename, "wb")
+ print >> output_file, file_title
+ for value in file_hash:
+ print >> output_file, "============================================================"
+ print >> output_file, "Notices for file(s):"
+ for filename in value:
+ print >> output_file, SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, "------------------------------------------------------------"
+ print >> output_file, open(value[0]).read()
+ output_file.close()
+
+def combine_notice_files_xml(files_with_same_hash, input_dir, output_filename):
+ """Combine notice files in FILE_HASH and output a XML version to OUTPUT_FILENAME."""
+
+ SRC_DIR_STRIP_RE = re.compile(input_dir + "(/.*).txt")
+
+ # Set up a filename to row id table (anchors inside tables don't work in
+ # most browsers, but href's to table row ids do)
+ id_table = {}
+ for file_key in files_with_same_hash.keys():
+ for filename in files_with_same_hash[file_key]:
+ id_table[filename] = file_key
+
+ # Open the output file, and output the header pieces
+ output_file = open(output_filename, "wb")
+
+ print >> output_file, '<?xml version="1.0" encoding="utf-8"?>'
+ print >> output_file, "<licenses>"
+
+ # Flatten the list of lists into a single list of filenames
+ sorted_filenames = sorted(id_table.keys())
+
+ # Print out a nice table of contents
+ for filename in sorted_filenames:
+ stripped_filename = SRC_DIR_STRIP_RE.sub(r"\1", filename)
+ print >> output_file, '<file-name contentId="%s">%s</file-name>' % (id_table.get(filename), stripped_filename)
+
+ print >> output_file
+ print >> output_file
+
+ processed_file_keys = []
+ # Output the individual notice file lists
+ for filename in sorted_filenames:
+ file_key = id_table.get(filename)
+ if file_key in processed_file_keys:
+ continue
+ processed_file_keys.append(file_key)
+
+ print >> output_file, '<file-content contentId="%s"><![CDATA[%s]]></file-content>' % (file_key, html_escape(open(filename).read()))
+ print >> output_file
+
+ # Finish off the file output
+ print >> output_file, "</licenses>"
+ output_file.close()
+
+def get_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--text-output', required=True,
+ help='The text output file path.')
+ parser.add_argument(
+ '--html-output',
+ help='The html output file path.')
+ parser.add_argument(
+ '--xml-output',
+ help='The xml output file path.')
+ parser.add_argument(
+ '-t', '--title', required=True,
+ help='The file title.')
+ parser.add_argument(
+ '-s', '--source-dir', required=True,
+ help='The directory containing notices.')
+ parser.add_argument(
+ '-i', '--included-subdirs', action='append',
+ help='The sub directories which should be included.')
+ parser.add_argument(
+ '-e', '--excluded-subdirs', action='append',
+ help='The sub directories which should be excluded.')
+ return parser.parse_args()
+
+def main(argv):
+ args = get_args()
+
+ txt_output_file = args.text_output
+ html_output_file = args.html_output
+ xml_output_file = args.xml_output
+ file_title = args.title
+ included_subdirs = []
+ excluded_subdirs = []
+ if args.included_subdirs is not None:
+ included_subdirs = args.included_subdirs
+ if args.excluded_subdirs is not None:
+ excluded_subdirs = args.excluded_subdirs
+
+ # Find all the notice files and md5 them
+ input_dir = os.path.normpath(args.source_dir)
+ files_with_same_hash = defaultdict(list)
+ for root, dir, files in os.walk(input_dir):
+ for file in files:
+ matched = True
+ if len(included_subdirs) > 0:
+ matched = False
+ for subdir in included_subdirs:
+ if (root == (input_dir + '/' + subdir) or
+ root.startswith(input_dir + '/' + subdir + '/')):
+ matched = True
+ break
+ elif len(excluded_subdirs) > 0:
+ for subdir in excluded_subdirs:
+ if (root == (input_dir + '/' + subdir) or
+ root.startswith(input_dir + '/' + subdir + '/')):
+ matched = False
+ break
+ if matched and file.endswith(".txt"):
+ filename = os.path.join(root, file)
+ file_md5sum = md5sum(filename)
+ files_with_same_hash[file_md5sum].append(filename)
+
+ filesets = [sorted(files_with_same_hash[md5]) for md5 in sorted(files_with_same_hash.keys())]
+
+ combine_notice_files_text(filesets, input_dir, txt_output_file, file_title)
+
+ if html_output_file is not None:
+ combine_notice_files_html(filesets, input_dir, html_output_file)
+
+ if xml_output_file is not None:
+ combine_notice_files_xml(files_with_same_hash, input_dir, xml_output_file)
+
+if __name__ == "__main__":
+ main(sys.argv)
diff --git a/scripts/jsonmodify.py b/scripts/jsonmodify.py
index 4b2c3c2..ba1109e 100755
--- a/scripts/jsonmodify.py
+++ b/scripts/jsonmodify.py
@@ -112,9 +112,10 @@
if args.out:
with open(args.out, "w") as f:
- json.dump(obj, f, indent=2)
+ json.dump(obj, f, indent=2, separators=(',', ': '))
+ f.write('\n')
else:
- print(json.dumps(obj, indent=2))
+ print(json.dumps(obj, indent=2, separators=(',', ': ')))
if __name__ == '__main__':
diff --git a/scripts/lint-project-xml.py b/scripts/lint-project-xml.py
index 38c57ca..f1ef85d 100755
--- a/scripts/lint-project-xml.py
+++ b/scripts/lint-project-xml.py
@@ -19,6 +19,8 @@
import argparse
+from ninja_rsp import NinjaRspFileReader
+
def check_action(check_type):
"""
@@ -91,74 +93,6 @@
return parser.parse_args()
-class NinjaRspFileReader:
- """
- Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
- non-standard character by surrounding the whole entry with single quotes, and then replacing
- any single quotes in the entry with the escape sequence '\''.
- """
-
- def __init__(self, filename):
- self.f = open(filename, 'r')
- self.r = self.character_reader(self.f)
-
- def __iter__(self):
- return self
-
- def character_reader(self, f):
- """Turns a file into a generator that returns one character at a time."""
- while True:
- c = f.read(1)
- if c:
- yield c
- else:
- return
-
- def __next__(self):
- entry = self.read_entry()
- if entry:
- return entry
- else:
- raise StopIteration
-
- def read_entry(self):
- c = next(self.r, "")
- if not c:
- return ""
- elif c == "'":
- return self.read_quoted_entry()
- else:
- entry = c
- for c in self.r:
- if c == " " or c == "\n":
- break
- entry += c
- return entry
-
- def read_quoted_entry(self):
- entry = ""
- for c in self.r:
- if c == "'":
- # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
- # character to find out.
- c = next(self.r)
- if not c or c == " " or c == "\n":
- # End of the item
- return entry
- elif c == "\\":
- # Escape sequence, expect a '
- c = next(self.r)
- if c != "'":
- # Malformed escape sequence
- raise "malformed escape sequence %s'\\%s" % (entry, c)
- entry += "'"
- else:
- raise "malformed escape sequence %s'%s" % (entry, c)
- else:
- entry += c
- raise "unterminated quoted entry %s" % entry
-
-
def write_project_xml(f, args):
test_attr = "test='true' " if args.test else ""
diff --git a/scripts/mergenotice.py b/scripts/mergenotice.py
index 407ae8c..fe99073 100755
--- a/scripts/mergenotice.py
+++ b/scripts/mergenotice.py
@@ -16,7 +16,7 @@
#
"""
Merges input notice files to the output file while ignoring duplicated files
-This script shouldn't be confused with build/make/tools/generate-notice-files.py
+This script shouldn't be confused with build/soong/scripts/generate-notice-files.py
which is responsible for creating the final notice file for all artifacts
installed. This script has rather limited scope; it is meant to create a merged
notice file for a set of modules that are packaged together, e.g. in an APEX.
diff --git a/scripts/ninja_rsp.py b/scripts/ninja_rsp.py
new file mode 100644
index 0000000..004ce47
--- /dev/null
+++ b/scripts/ninja_rsp.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""This file reads entries from a Ninja rsp file."""
+
+class NinjaRspFileReader:
+ """
+ Reads entries from a Ninja rsp file. Ninja escapes any entries in the file that contain a
+ non-standard character by surrounding the whole entry with single quotes, and then replacing
+ any single quotes in the entry with the escape sequence '\''.
+ """
+
+ def __init__(self, filename):
+ self.f = open(filename, 'r')
+ self.r = self.character_reader(self.f)
+
+ def __iter__(self):
+ return self
+
+ def character_reader(self, f):
+ """Turns a file into a generator that returns one character at a time."""
+ while True:
+ c = f.read(1)
+ if c:
+ yield c
+ else:
+ return
+
+ def __next__(self):
+ entry = self.read_entry()
+ if entry:
+ return entry
+ else:
+ raise StopIteration
+
+ def read_entry(self):
+ c = next(self.r, "")
+ if not c:
+ return ""
+ elif c == "'":
+ return self.read_quoted_entry()
+ else:
+ entry = c
+ for c in self.r:
+ if c == " " or c == "\n":
+ break
+ entry += c
+ return entry
+
+ def read_quoted_entry(self):
+ entry = ""
+ for c in self.r:
+ if c == "'":
+ # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
+ # character to find out.
+ c = next(self.r)
+ if not c or c == " " or c == "\n":
+ # End of the item
+ return entry
+ elif c == "\\":
+ # Escape sequence, expect a '
+ c = next(self.r)
+ if c != "'":
+ # Malformed escape sequence
+ raise "malformed escape sequence %s'\\%s" % (entry, c)
+ entry += "'"
+ else:
+ raise "malformed escape sequence %s'%s" % (entry, c)
+ else:
+ entry += c
+ raise "unterminated quoted entry %s" % entry
diff --git a/scripts/reverse-deps.sh b/scripts/reverse-deps.sh
new file mode 100755
index 0000000..02b7dcb
--- /dev/null
+++ b/scripts/reverse-deps.sh
@@ -0,0 +1,246 @@
+#!/bin/bash
+
+set -eu
+
+# Copyright 2020 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets depending on a given target.
+#
+# i.e. the list of things that could change after changing a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the reverse transitive closure of ninja targets depending on one or
+more targets.
+
+Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+#
+# only argument is the dependency depth indicator
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v depth="${1}" '
+ BEGIN {
+ inoutput = 0
+ }
+ $0 ~ /^\S\S*:$/ {
+ inoutput = 0
+ }
+ inoutput != 0 {
+ print gensub(/^\s*/, "", "g")" "depth
+ }
+ $1 == "outputs:" {
+ inoutput = 1
+ }
+ '
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+quiet=false # whether to suppress progress
+
+sep=" " # output separator between depth and target
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=*)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$';;
+ *)
+ die "Unknown flag ${1}"
+ ;;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target `target` is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))" "0
+ }
+ ' >"${newDeps}"
+else # start with no deps by clearing file
+ : >"${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ echo "${targets[${idx}]} 0" >>"${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u <"${newDeps}" >"${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ fi
+ depth=$(expr ${depth} + 1)
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ cut -d\ -f1 "${newDeps}" | getDeps "${depth}"
+ cat "${oldDeps}"
+ ) | sort -n | awk '
+ BEGIN {
+ prev = ""
+ }
+ {
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ if ($0 != prev) {
+ print gensub(/\s*$/, "", "g")" "depth
+ }
+ prev = $0
+ }
+ ' >"${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' \
+ --new-line-format='%L' --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+awk -v sep="${sep}" '{
+ depth = $NF
+ $NF = ""
+ gsub(/\s*$/, "")
+ print depth sep $0
+}' "${allDeps}" | sort -n
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/scripts/rustfmt.toml b/scripts/rustfmt.toml
new file mode 100644
index 0000000..617d425
--- /dev/null
+++ b/scripts/rustfmt.toml
@@ -0,0 +1,5 @@
+# Android Format Style
+
+edition = "2018"
+use_small_heuristics = "Max"
+newline_style = "Unix"
diff --git a/scripts/transitive-deps.sh b/scripts/transitive-deps.sh
new file mode 100755
index 0000000..ba36ba4
--- /dev/null
+++ b/scripts/transitive-deps.sh
@@ -0,0 +1,491 @@
+#!/bin/bash
+
+set -eu
+
+# Copyright 2020 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.
+
+# Tool to evaluate the transitive closure of the ninja dependency graph of the
+# files and targets a given target depends on.
+#
+# i.e. the list of things that, if changed, could cause a change to a target.
+
+readonly me=$(basename "${0}")
+
+readonly usage="usage: ${me} {options} target [target...]
+
+Evaluate the transitive closure of files and ninja targets that one or more
+targets depend on.
+
+Dependency Options:
+
+ -(no)order_deps Whether to include order-only dependencies. (Default false)
+ -(no)implicit Whether to include implicit dependencies. (Default true)
+ -(no)explicit Whether to include regular / explicit deps. (Default true)
+
+ -nofollow Unanchored regular expression. Matching paths and targets
+ always get reported. Their dependencies do not get reported
+ unless first encountered in a 'container' file type.
+ Multiple allowed and combined using '|'.
+ e.g. -nofollow='*.so' not -nofollow='.so$'
+ -nofollow='*.so|*.dex' or -nofollow='*.so' -nofollow='.dex'
+ (Defaults to no matches)
+ -container Unanchored regular expression. Matching file extensions get
+ treated as 'container' files for -nofollow option.
+ Multiple allowed and combines using '|'
+ (Default 'apex|apk|zip|jar|tar|tgz')
+
+Output Options:
+
+ -(no)quiet Suppresses progress output to stderr and interactive
+ alias -(no)q prompts. By default, when stderr is a tty, progress gets
+ reported to stderr; when both stderr and stdin are tty,
+ the script asks user whether to delete intermediate files.
+ When suppressed or not prompted, script always deletes the
+ temporary / intermediate files.
+ -sep=<delim> Use 'delim' as output field separator between notice
+ checksum and notice filename in notice output.
+ e.g. sep='\\t'
+ (Default space)
+ -csv Shorthand for -sep=','
+ -directories=<f> Output directory names of dependencies to 'f'.
+ alias -d User '/dev/stdout' to send directories to stdout. Defaults
+ to no directory output.
+ -notices=<file> Output license and notice file paths to 'file'.
+ alias -n Use '/dev/stdout' to send notices to stdout. Defaults to no
+ license/notice output.
+ -projects=<file> Output git project names to 'file'. Use '/dev/stdout' to
+ alias -p send projects to stdout. Defaults to no project output.
+ -targets=<fils> Output target dependencies to 'file'. Use '/dev/stdout' to
+ alias -t send targets to stdout.
+ When no directory, notice, project or target output options
+ given, defaults to stdout. Otherwise, defaults to no target
+ output.
+
+At minimum, before running this script, you must first run:
+$ source build/envsetup.sh
+$ lunch
+$ m nothing
+to setup the build environment, choose a target platform, and build the ninja
+dependency graph.
+"
+
+function die() { echo -e "${*}" >&2; exit 2; }
+
+# Reads one input target per line from stdin; outputs (isnotice target) tuples.
+#
+# output target is a ninja target that the input target depends on
+# isnotice in {0,1} with 1 for output targets believed to be license or notice
+function getDeps() {
+ (tr '\n' '\0' | xargs -0 -r "${ninja_bin}" -f "${ninja_file}" -t query) \
+ | awk -v include_order="${include_order_deps}" \
+ -v include_implicit="${include_implicit_deps}" \
+ -v include_explicit="${include_deps}" \
+ -v containers="${container_types}" \
+ '
+ BEGIN {
+ ininput = 0
+ isnotice = 0
+ currFileName = ""
+ currExt = ""
+ }
+ $1 == "outputs:" {
+ ininput = 0
+ }
+ ininput == 0 && $0 ~ /^\S\S*:$/ {
+ isnotice = ($0 ~ /.*NOTICE.*[.]txt:$/)
+ currFileName = gensub(/^.*[/]([^/]*)[:]$/, "\\1", "g")
+ currExt = gensub(/^.*[.]([^./]*)[:]$/, "\\1", "g")
+ }
+ ininput != 0 && $1 !~ /^[|][|]?/ {
+ if (include_explicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "|" {
+ if (include_implicit == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ ininput != 0 && $1 == "||" {
+ if (include_order == "true") {
+ fileName = gensub(/^.*[/]([^/]*)$/, "\\1", "g")
+ $1 = ""
+ print ( \
+ (isnotice && $0 !~ /^\s*build[/]soong[/]scripts[/]/) \
+ || $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "(fileName == currFileName||currExt ~ "^(" containers ")$")" "gensub(/^\s*/, "", "g")
+ }
+ }
+ $1 == "input:" {
+ ininput = 1
+ }
+ '
+}
+
+# Reads one input directory per line from stdin; outputs unique git projects.
+function getProjects() {
+ while read d; do
+ while [ "${d}" != '.' ] && [ "${d}" != '/' ]; do
+ if [ -d "${d}/.git/" ]; then
+ echo "${d}"
+ break
+ fi
+ d=$(dirname "${d}")
+ done
+ done | sort -u
+}
+
+
+if [ -z "${ANDROID_BUILD_TOP}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+if [ -z "${TARGET_PRODUCT}" ]; then
+ die "${me}: Run 'lunch' to configure the build environment"
+fi
+
+readonly ninja_file="${ANDROID_BUILD_TOP}/out/combined-${TARGET_PRODUCT}.ninja"
+if [ ! -f "${ninja_file}" ]; then
+ die "${me}: Run 'm nothing' to build the dependency graph"
+fi
+
+readonly ninja_bin="${ANDROID_BUILD_TOP}/prebuilts/build-tools/linux-x86/bin/ninja"
+if [ ! -x "${ninja_bin}" ]; then
+ die "${me}: Cannot find ninja executable expected at ${ninja_bin}"
+fi
+
+
+# parse the command-line
+
+declare -a targets # one or more targets to evaluate
+
+include_order_deps=false # whether to trace through || "order dependencies"
+include_implicit_deps=true # whether to trace through | "implicit deps"
+include_deps=true # whether to trace through regular explicit deps
+quiet=false # whether to suppress progress
+
+projects_out='' # where to output the list of projects
+directories_out='' # where to output the list of directories
+targets_out='' # where to output the list of targets/source files
+notices_out='' # where to output the list of license/notice files
+
+sep=" " # separator between md5sum and notice filename
+
+nofollow='' # regularexp must fully match targets to skip
+
+container_types='' # regularexp must full match file extension
+ # defaults to 'apex|apk|zip|jar|tar|tgz' below.
+
+use_stdin=false # whether to read targets from stdin i.e. target -
+
+while [ $# -gt 0 ]; do
+ case "${1:-}" in
+ -)
+ use_stdin=true
+ ;;
+ -*)
+ flag=$(expr "${1}" : '^-*\(.*\)$')
+ case "${flag:-}" in
+ order_deps)
+ include_order_deps=true;;
+ noorder_deps)
+ include_order_deps=false;;
+ implicit)
+ include_implicit_deps=true;;
+ noimplicit)
+ include_implicit_deps=false;;
+ explicit)
+ include_deps=true;;
+ noexplicit)
+ include_deps=false;;
+ csv)
+ sep=",";;
+ sep)
+ sep="${2?"${usage}"}"; shift;;
+ sep=)
+ sep=$(expr "${flag}" : '^sep=\(.*\)$');;
+ q) ;&
+ quiet)
+ quiet=true;;
+ noq) ;&
+ noquiet)
+ quiet=false;;
+ nofollow)
+ case "${nofollow}" in
+ '')
+ nofollow="${2?"${usage}"}";;
+ *)
+ nofollow="${nofollow}|${2?"${usage}"}";;
+ esac
+ shift
+ ;;
+ nofollow=*)
+ case "${nofollow}" in
+ '')
+ nofollow=$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ *)
+ nofollow="${nofollow}|"$(expr "${flag}" : '^nofollow=\(.*\)$');;
+ esac
+ ;;
+ container)
+ container_types="${container_types}|${2?"${usage}"}";;
+ container=*)
+ container_types="${container_types}|"$(expr "${flag}" : '^container=\(.*\)$');;
+ p) ;&
+ projects)
+ projects_out="${2?"${usage}"}"; shift;;
+ p=*) ;&
+ projects=*)
+ projects_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ d) ;&
+ directores)
+ directories_out="${2?"${usage}"}"; shift;;
+ d=*) ;&
+ directories=*)
+ directories_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ t) ;&
+ targets)
+ targets_out="${2?"${usage}"}"; shift;;
+ t=*) ;&
+ targets=)
+ targets_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ n) ;&
+ notices)
+ notices_out="${2?"${usage}"}"; shift;;
+ n=*) ;&
+ notices=)
+ notices_out=$(expr "${flag}" : '^.*=\(.*\)$');;
+ *)
+ die "${usage}\n\nUnknown flag ${1}";;
+ esac
+ ;;
+ *)
+ targets+=("${1:-}")
+ ;;
+ esac
+ shift
+done
+
+
+# fail fast if command-line arguments are invalid
+
+if [ ! -v targets[0] ] && ! ${use_stdin}; then
+ die "${usage}\n\nNo target specified."
+fi
+
+if [ -z "${projects_out}" ] \
+ && [ -z "${directories_out}" ] \
+ && [ -z "${targets_out}" ] \
+ && [ -z "${notices_out}" ]
+then
+ targets_out='/dev/stdout'
+fi
+
+if [ -z "${container_types}" ]; then
+ container_types='apex|apk|zip|jar|tar|tgz'
+fi
+
+# showProgress when stderr is a tty
+if [ -t 2 ] && ! ${quiet}; then
+ showProgress=true
+else
+ showProgress=false
+fi
+
+# interactive when both stderr and stdin are tty
+if ${showProgress} && [ -t 0 ]; then
+ interactive=true
+else
+ interactive=false
+fi
+
+
+readonly tmpFiles=$(mktemp -d "${TMPDIR}.tdeps.XXXXXXXXX")
+if [ -z "${tmpFiles}" ]; then
+ die "${me}: unable to create temporary directory"
+fi
+
+# The deps files contain unique (isnotice target) tuples where
+# isnotice in {0,1} with 1 when ninja target 'target' is a license or notice.
+readonly oldDeps="${tmpFiles}/old"
+readonly newDeps="${tmpFiles}/new"
+readonly allDeps="${tmpFiles}/all"
+
+if ${use_stdin}; then # start deps by reading 1 target per line from stdin
+ awk '
+ NF > 0 {
+ print ( \
+ $0 ~ /NOTICE|LICEN[CS]E/ \
+ || $0 ~ /(notice|licen[cs]e)[.]txt/ \
+ )" "gensub(/\s*$/, "", "g", gensub(/^\s*/, "", "g"))
+ }
+ ' > "${newDeps}"
+else # start with no deps by clearing file
+ : > "${newDeps}"
+fi
+
+# extend deps by appending targets from command-line
+for idx in "${!targets[*]}"; do
+ isnotice='0'
+ case "${targets[${idx}]}" in
+ *NOTICE*) ;&
+ *LICEN[CS]E*) ;&
+ *notice.txt) ;&
+ *licen[cs]e.txt)
+ isnotice='1';;
+ esac
+ echo "${isnotice} 1 ${targets[${idx}]}" >> "${newDeps}"
+done
+
+# remove duplicates and start with new, old and all the same
+sort -u < "${newDeps}" > "${allDeps}"
+cp "${allDeps}" "${newDeps}"
+cp "${allDeps}" "${oldDeps}"
+
+# report depth of dependenciens when showProgress
+depth=0
+
+# 1st iteration always unfiltered
+filter='cat'
+while [ $(wc -l < "${newDeps}") -gt 0 ]; do
+ if ${showProgress}; then
+ echo "depth ${depth} has "$(wc -l < "${newDeps}")" targets" >&2
+ depth=$(expr ${depth} + 1)
+ fi
+ ( # recalculate dependencies by combining unique inputs of new deps w. old
+ set +e
+ sh -c "${filter}" < "${newDeps}" | cut -d\ -f3- | getDeps
+ set -e
+ cat "${oldDeps}"
+ ) | sort -u > "${allDeps}"
+ # recalculate new dependencies as net additions to old dependencies
+ set +e
+ diff "${oldDeps}" "${allDeps}" --old-line-format='' --new-line-format='%L' \
+ --unchanged-line-format='' > "${newDeps}"
+ set -e
+ # apply filters on subsequent iterations
+ case "${nofollow}" in
+ '')
+ filter='cat';;
+ *)
+ filter="egrep -v '^[01] 0 (${nofollow})$'"
+ ;;
+ esac
+ # recalculate old dependencies for next iteration
+ cp "${allDeps}" "${oldDeps}"
+done
+
+# found all deps -- clean up last iteration of old and new
+rm -f "${oldDeps}"
+rm -f "${newDeps}"
+
+if ${showProgress}; then
+ echo $(wc -l < "${allDeps}")" targets" >&2
+fi
+
+if [ -n "${targets_out}" ]; then
+ cut -d\ -f3- "${allDeps}" | sort -u > "${targets_out}"
+fi
+
+if [ -n "${directories_out}" ] \
+ || [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allDirs="${tmpFiles}/dirs"
+ (
+ cut -d\ -f3- "${allDeps}" | tr '\n' '\0' | xargs -0 dirname
+ ) | sort -u > "${allDirs}"
+ if ${showProgress}; then
+ echo $(wc -l < "${allDirs}")" directories" >&2
+ fi
+
+ case "${directories_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allDirs}" > "${directories_out}"
+ ;;
+ esac
+fi
+
+if [ -n "${projects_out}" ] \
+ || [ -n "${notices_out}" ]
+then
+ readonly allProj="${tmpFiles}/projects"
+ set +e
+ egrep -v '^out[/]' "${allDirs}" | getProjects > "${allProj}"
+ set -e
+ if ${showProgress}; then
+ echo $(wc -l < "${allProj}")" projects" >&2
+ fi
+
+ case "${projects_out}" in
+ '') : do nothing;;
+ *)
+ cat "${allProj}" > "${projects_out}"
+ ;;
+ esac
+fi
+
+case "${notices_out}" in
+ '') : do nothing;;
+ *)
+ readonly allNotice="${tmpFiles}/notices"
+ set +e
+ egrep '^1' "${allDeps}" | cut -d\ -f3- | egrep -v '^out/' > "${allNotice}"
+ set -e
+ cat "${allProj}" | while read proj; do
+ for f in LICENSE LICENCE NOTICE license.txt notice.txt; do
+ if [ -f "${proj}/${f}" ]; then
+ echo "${proj}/${f}"
+ fi
+ done
+ done >> "${allNotice}"
+ if ${showProgress}; then
+ echo $(cat "${allNotice}" | sort -u | wc -l)" notice targets" >&2
+ fi
+ readonly hashedNotice="${tmpFiles}/hashednotices"
+ ( # md5sum outputs checksum space indicator(space or *) filename newline
+ set +e
+ sort -u "${allNotice}" | tr '\n' '\0' | xargs -0 -r md5sum 2>/dev/null
+ set -e
+ # use sed to replace space and indicator with separator
+ ) > "${hashedNotice}"
+ if ${showProgress}; then
+ echo $(cut -d\ -f2- "${hashedNotice}" | sort -u | wc -l)" notice files" >&2
+ echo $(cut -d\ -f1 "${hashedNotice}" | sort -u | wc -l)" distinct notices" >&2
+ fi
+ sed 's/^\([^ ]*\) [* ]/\1'"${sep}"'/g' "${hashedNotice}" | sort > "${notices_out}"
+ ;;
+esac
+
+if ${interactive}; then
+ echo -n "$(date '+%F %-k:%M:%S') Delete ${tmpFiles} ? [n] " >&2
+ read answer
+ case "${answer}" in [yY]*) rm -fr "${tmpFiles}";; esac
+else
+ rm -fr "${tmpFiles}"
+fi
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index dded153..8c9e228 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -21,24 +21,38 @@
"android/soong/cc"
)
+var ccTestFs = map[string][]byte{
+ "Test.cpp": nil,
+ "include/Test.h": nil,
+ "include-android/AndroidTest.h": nil,
+ "include-host/HostTest.h": nil,
+ "arm64/include/Arm64Test.h": nil,
+ "libfoo.so": nil,
+ "aidl/foo/bar/Test.aidl": nil,
+ "some/where/stubslib.map.txt": nil,
+}
+
func testSdkWithCc(t *testing.T, bp string) *testSdkResult {
t.Helper()
-
- fs := map[string][]byte{
- "Test.cpp": nil,
- "include/Test.h": nil,
- "include-android/AndroidTest.h": nil,
- "include-host/HostTest.h": nil,
- "arm64/include/Arm64Test.h": nil,
- "libfoo.so": nil,
- "aidl/foo/bar/Test.aidl": nil,
- "some/where/stubslib.map.txt": nil,
- }
- return testSdkWithFs(t, bp, fs)
+ return testSdkWithFs(t, bp, ccTestFs)
}
// Contains tests for SDK members provided by the cc package.
+func TestSingleDeviceOsAssumption(t *testing.T) {
+ // Mock a module with DeviceSupported() == true.
+ s := &sdk{}
+ android.InitAndroidArchModule(s, android.DeviceSupported, android.MultilibCommon)
+
+ osTypes := s.getPossibleOsTypes()
+ if len(osTypes) != 1 {
+ // The snapshot generation assumes there is a single device OS. If more are
+ // added it might need to disable them by default, like it does for host
+ // OS'es.
+ t.Errorf("expected a single device OS, got %v", osTypes)
+ }
+}
+
func TestSdkIsCompileMultilibBoth(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -69,6 +83,94 @@
ensureListContains(t, inputs, arm64Output.String())
}
+func TestSdkCompileMultilibOverride(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_shared_libs: ["sdkmember"],
+ compile_multilib: "64",
+ }
+
+ cc_library_shared {
+ name: "sdkmember",
+ host_supported: true,
+ srcs: ["Test.cpp"],
+ stl: "none",
+ compile_multilib: "64",
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_sdkmember@current",
+ sdk_member_name: "sdkmember",
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/sdkmember.so"],
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/sdkmember.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "sdkmember",
+ prefer: false,
+ host_supported: true,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/sdkmember.so"],
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/sdkmember.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_shared_libs: ["mysdk_sdkmember@current"],
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/sdkmember/android_arm64_armv8-a_shared/sdkmember.so -> android/arm64/lib/sdkmember.so
+.intermediates/sdkmember/linux_glibc_x86_64_shared/sdkmember.so -> linux_glibc/x86_64/lib/sdkmember.so
+`))
+}
+
func TestBasicSdkWithCc(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -79,6 +181,8 @@
cc_library_shared {
name: "sdkmember",
system_shared_libs: [],
+ stl: "none",
+ apex_available: ["mysdkapex"],
}
sdk_snapshot {
@@ -152,13 +256,20 @@
key: "myapex.key",
certificate: ":myapex.cert",
}
+
+ apex {
+ name: "mysdkapex",
+ native_shared_libs: ["sdkmember"],
+ key: "myapex.key",
+ certificate: ":myapex.cert",
+ }
`)
- sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output
- sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_myapex2").Rule("toc").Output
+ sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output
+ sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output
- cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex")
- cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex2")
+ cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_1")
+ cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_2")
// Depending on the uses_sdks value, different libs are linked
ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
@@ -229,6 +340,9 @@
cc_object {
name: "crtobj",
stl: "none",
+ sanitize: {
+ never: true,
+ },
}
`)
@@ -240,6 +354,10 @@
name: "mysdk_crtobj@current",
sdk_member_name: "crtobj",
stl: "none",
+ compile_multilib: "both",
+ sanitize: {
+ never: true,
+ },
arch: {
arm64: {
srcs: ["arm64/lib/crtobj.o"],
@@ -254,6 +372,10 @@
name: "crtobj",
prefer: false,
stl: "none",
+ compile_multilib: "both",
+ sanitize: {
+ never: true,
+ },
arch: {
arm64: {
srcs: ["arm64/lib/crtobj.o"],
@@ -347,6 +469,7 @@
sdk_member_name: "mynativelib",
installable: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -363,6 +486,7 @@
name: "mynativelib",
prefer: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -401,7 +525,6 @@
"Test.cpp",
],
compile_multilib: "both",
- stl: "none",
}
`)
@@ -451,9 +574,6 @@
}
func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
module_exports {
name: "myexports",
@@ -494,8 +614,13 @@
device_supported: false,
host_supported: true,
installable: false,
+ stl: "none",
target: {
+ host: {
+ enabled: false,
+ },
linux_glibc: {
+ enabled: true,
compile_multilib: "both",
},
linux_glibc_x86_64: {
@@ -505,6 +630,7 @@
srcs: ["linux_glibc/x86/bin/mynativebinary"],
},
windows: {
+ enabled: true,
compile_multilib: "64",
},
windows_x86_64: {
@@ -518,8 +644,13 @@
prefer: false,
device_supported: false,
host_supported: true,
+ stl: "none",
target: {
+ host: {
+ enabled: false,
+ },
linux_glibc: {
+ enabled: true,
compile_multilib: "both",
},
linux_glibc_x86_64: {
@@ -529,6 +660,7 @@
srcs: ["linux_glibc/x86/bin/mynativebinary"],
},
windows: {
+ enabled: true,
compile_multilib: "64",
},
windows_x86_64: {
@@ -543,7 +675,14 @@
host_supported: true,
native_binaries: ["myexports_mynativebinary@current"],
target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
windows: {
+ enabled: true,
compile_multilib: "64",
},
},
@@ -557,6 +696,263 @@
)
}
+func TestSnapshotWithSingleHostOsType(t *testing.T) {
+ ctx, config := testSdkContext(`
+ cc_defaults {
+ name: "mydefaults",
+ device_supported: false,
+ host_supported: true,
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+ }
+
+ module_exports {
+ name: "myexports",
+ defaults: ["mydefaults"],
+ native_shared_libs: ["mynativelib"],
+ native_binaries: ["mynativebinary"],
+ compile_multilib: "64", // The built-in default in sdk.go overrides mydefaults.
+ }
+
+ cc_library {
+ name: "mynativelib",
+ defaults: ["mydefaults"],
+ srcs: [
+ "Test.cpp",
+ ],
+ stl: "none",
+ }
+
+ cc_binary {
+ name: "mynativebinary",
+ defaults: ["mydefaults"],
+ srcs: [
+ "Test.cpp",
+ ],
+ stl: "none",
+ }
+ `, ccTestFs, []android.OsType{android.LinuxBionic})
+
+ result := runTests(t, ctx, config)
+
+ result.CheckSnapshot("myexports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "myexports_mynativebinary@current",
+ sdk_member_name: "mynativebinary",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ linux_bionic_x86_64: {
+ srcs: ["x86_64/bin/mynativebinary"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "mynativebinary",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ linux_bionic_x86_64: {
+ srcs: ["x86_64/bin/mynativebinary"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "myexports_mynativelib@current",
+ sdk_member_name: "mynativelib",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ linux_bionic_x86_64: {
+ srcs: ["x86_64/lib/mynativelib.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mynativelib",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ linux_bionic_x86_64: {
+ srcs: ["x86_64/lib/mynativelib.so"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "myexports@current",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["myexports_mynativebinary@current"],
+ native_shared_libs: ["myexports_mynativelib@current"],
+ compile_multilib: "64",
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_bionic: {
+ enabled: true,
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mynativebinary/linux_bionic_x86_64/mynativebinary -> x86_64/bin/mynativebinary
+.intermediates/mynativelib/linux_bionic_x86_64_shared/mynativelib.so -> x86_64/lib/mynativelib.so
+`),
+ )
+}
+
+// Test that we support the necessary flags for the linker binary, which is
+// special in several ways.
+func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) {
+ result := testSdkWithCc(t, `
+ module_exports {
+ name: "mymodule_exports",
+ host_supported: true,
+ device_supported: false,
+ native_binaries: ["linker"],
+ }
+
+ cc_binary {
+ name: "linker",
+ host_supported: true,
+ static_executable: true,
+ nocrt: true,
+ stl: "none",
+ srcs: [
+ "Test.cpp",
+ ],
+ compile_multilib: "both",
+ }
+ `)
+
+ result.CheckSnapshot("mymodule_exports", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_binary {
+ name: "mymodule_exports_linker@current",
+ sdk_member_name: "linker",
+ device_supported: false,
+ host_supported: true,
+ installable: false,
+ stl: "none",
+ compile_multilib: "both",
+ static_executable: true,
+ nocrt: true,
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["x86_64/bin/linker"],
+ },
+ linux_glibc_x86: {
+ srcs: ["x86/bin/linker"],
+ },
+ },
+}
+
+cc_prebuilt_binary {
+ name: "linker",
+ prefer: false,
+ device_supported: false,
+ host_supported: true,
+ stl: "none",
+ compile_multilib: "both",
+ static_executable: true,
+ nocrt: true,
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["x86_64/bin/linker"],
+ },
+ linux_glibc_x86: {
+ srcs: ["x86/bin/linker"],
+ },
+ },
+}
+
+module_exports_snapshot {
+ name: "mymodule_exports@current",
+ device_supported: false,
+ host_supported: true,
+ native_binaries: ["mymodule_exports_linker@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/linker/linux_glibc_x86_64/linker -> x86_64/bin/linker
+.intermediates/linker/linux_glibc_x86/linker -> x86/bin/linker
+`),
+ )
+}
+
func TestSnapshotWithCcSharedLibrary(t *testing.T) {
result := testSdkWithCc(t, `
sdk {
@@ -592,6 +988,7 @@
],
installable: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -613,6 +1010,7 @@
"apex2",
],
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -714,6 +1112,7 @@
sdk_member_name: "mynativelib",
installable: false,
stl: "none",
+ compile_multilib: "both",
shared_libs: [
"mysdk_myothernativelib@current",
"libc",
@@ -732,6 +1131,7 @@
name: "mynativelib",
prefer: false,
stl: "none",
+ compile_multilib: "both",
shared_libs: [
"myothernativelib",
"libc",
@@ -751,6 +1151,7 @@
sdk_member_name: "myothernativelib",
installable: false,
stl: "none",
+ compile_multilib: "both",
system_shared_libs: ["libm"],
arch: {
arm64: {
@@ -766,6 +1167,7 @@
name: "myothernativelib",
prefer: false,
stl: "none",
+ compile_multilib: "both",
system_shared_libs: ["libm"],
arch: {
arm64: {
@@ -782,6 +1184,7 @@
sdk_member_name: "mysystemnativelib",
installable: false,
stl: "none",
+ compile_multilib: "both",
arch: {
arm64: {
srcs: ["arm64/lib/mysystemnativelib.so"],
@@ -796,6 +1199,7 @@
name: "mysystemnativelib",
prefer: false,
stl: "none",
+ compile_multilib: "both",
arch: {
arm64: {
srcs: ["arm64/lib/mysystemnativelib.so"],
@@ -827,9 +1231,6 @@
}
func TestHostSnapshotWithCcSharedLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -867,13 +1268,20 @@
installable: false,
sdk_version: "minimum",
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.so"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
- x86: {
+ linux_glibc_x86: {
srcs: ["x86/lib/mynativelib.so"],
export_include_dirs: ["x86/include_gen/mynativelib"],
},
@@ -887,13 +1295,20 @@
host_supported: true,
sdk_version: "minimum",
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.so"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
- x86: {
+ linux_glibc_x86: {
srcs: ["x86/lib/mynativelib.so"],
export_include_dirs: ["x86/include_gen/mynativelib"],
},
@@ -905,6 +1320,14 @@
device_supported: false,
host_supported: true,
native_shared_libs: ["mysdk_mynativelib@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`),
checkAllCopyRules(`
@@ -922,9 +1345,6 @@
}
func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -966,12 +1386,23 @@
installable: false,
stl: "none",
target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ compile_multilib: "both",
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
},
linux_glibc_x86: {
srcs: ["linux_glibc/x86/lib/mynativelib.so"],
},
+ windows: {
+ enabled: true,
+ compile_multilib: "64",
+ },
windows_x86_64: {
srcs: ["windows/x86_64/lib/mynativelib.dll"],
},
@@ -985,12 +1416,23 @@
host_supported: true,
stl: "none",
target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ compile_multilib: "both",
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/mynativelib.so"],
},
linux_glibc_x86: {
srcs: ["linux_glibc/x86/lib/mynativelib.so"],
},
+ windows: {
+ enabled: true,
+ compile_multilib: "64",
+ },
windows_x86_64: {
srcs: ["windows/x86_64/lib/mynativelib.dll"],
},
@@ -1003,7 +1445,14 @@
host_supported: true,
native_shared_libs: ["mysdk_mynativelib@current"],
target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
windows: {
+ enabled: true,
compile_multilib: "64",
},
},
@@ -1047,6 +1496,7 @@
sdk_member_name: "mynativelib",
installable: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -1064,6 +1514,7 @@
name: "mynativelib",
prefer: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -1097,9 +1548,6 @@
}
func TestHostSnapshotWithCcStaticLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
module_exports {
name: "myexports",
@@ -1135,13 +1583,20 @@
host_supported: true,
installable: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.a"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
- x86: {
+ linux_glibc_x86: {
srcs: ["x86/lib/mynativelib.a"],
export_include_dirs: ["x86/include_gen/mynativelib"],
},
@@ -1154,13 +1609,20 @@
device_supported: false,
host_supported: true,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.a"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
- x86: {
+ linux_glibc_x86: {
srcs: ["x86/lib/mynativelib.a"],
export_include_dirs: ["x86/include_gen/mynativelib"],
},
@@ -1172,6 +1634,14 @@
device_supported: false,
host_supported: true,
native_static_libs: ["myexports_mynativelib@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`),
checkAllCopyRules(`
@@ -1202,6 +1672,8 @@
],
export_include_dirs: ["include"],
stl: "none",
+ recovery_available: true,
+ vendor_available: true,
}
`)
@@ -1213,7 +1685,10 @@
name: "myexports_mynativelib@current",
sdk_member_name: "mynativelib",
installable: false,
+ recovery_available: true,
+ vendor_available: true,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -1238,7 +1713,10 @@
cc_prebuilt_library {
name: "mynativelib",
prefer: false,
+ recovery_available: true,
+ vendor_available: true,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
arch: {
arm64: {
@@ -1275,9 +1753,6 @@
}
func TestHostSnapshotWithMultiLib64(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
module_exports {
name: "myexports",
@@ -1318,9 +1793,16 @@
host_supported: true,
installable: false,
stl: "none",
+ compile_multilib: "64",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.a"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
@@ -1333,9 +1815,16 @@
device_supported: false,
host_supported: true,
stl: "none",
+ compile_multilib: "64",
export_include_dirs: ["include/include"],
- arch: {
- x86_64: {
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
srcs: ["x86_64/lib/mynativelib.a"],
export_include_dirs: ["x86_64/include_gen/mynativelib"],
},
@@ -1347,9 +1836,13 @@
device_supported: false,
host_supported: true,
native_static_libs: ["myexports_mynativelib@current"],
+ compile_multilib: "64",
target: {
+ host: {
+ enabled: false,
+ },
linux_glibc: {
- compile_multilib: "64",
+ enabled: true,
},
},
}`),
@@ -1385,6 +1878,7 @@
name: "mysdk_mynativeheaders@current",
sdk_member_name: "mynativeheaders",
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
}
@@ -1392,6 +1886,7 @@
name: "mynativeheaders",
prefer: false,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
}
@@ -1407,9 +1902,6 @@
}
func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -1437,7 +1929,16 @@
device_supported: false,
host_supported: true,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
cc_prebuilt_library_headers {
@@ -1446,7 +1947,16 @@
device_supported: false,
host_supported: true,
stl: "none",
+ compile_multilib: "both",
export_include_dirs: ["include/include"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
sdk_snapshot {
@@ -1454,6 +1964,14 @@
device_supported: false,
host_supported: true,
native_header_libs: ["mysdk_mynativeheaders@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`),
checkAllCopyRules(`
@@ -1463,9 +1981,6 @@
}
func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -1498,13 +2013,18 @@
sdk_member_name: "mynativeheaders",
host_supported: true,
stl: "none",
- export_system_include_dirs: ["include/include"],
+ compile_multilib: "both",
+ export_system_include_dirs: ["common_os/include/include"],
target: {
+ host: {
+ enabled: false,
+ },
android: {
- export_include_dirs: ["include/include-android"],
+ export_include_dirs: ["android/include/include-android"],
},
linux_glibc: {
- export_include_dirs: ["include/include-host"],
+ enabled: true,
+ export_include_dirs: ["linux_glibc/include/include-host"],
},
},
}
@@ -1514,13 +2034,18 @@
prefer: false,
host_supported: true,
stl: "none",
- export_system_include_dirs: ["include/include"],
+ compile_multilib: "both",
+ export_system_include_dirs: ["common_os/include/include"],
target: {
+ host: {
+ enabled: false,
+ },
android: {
- export_include_dirs: ["include/include-android"],
+ export_include_dirs: ["android/include/include-android"],
},
linux_glibc: {
- export_include_dirs: ["include/include-host"],
+ enabled: true,
+ export_include_dirs: ["linux_glibc/include/include-host"],
},
},
}
@@ -1529,20 +2054,25 @@
name: "mysdk@current",
host_supported: true,
native_header_libs: ["mysdk_mynativeheaders@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`),
checkAllCopyRules(`
-include/Test.h -> include/include/Test.h
-include-android/AndroidTest.h -> include/include-android/AndroidTest.h
-include-host/HostTest.h -> include/include-host/HostTest.h
+include/Test.h -> common_os/include/include/Test.h
+include-android/AndroidTest.h -> android/include/include-android/AndroidTest.h
+include-host/HostTest.h -> linux_glibc/include/include-host/HostTest.h
`),
)
}
func TestSystemSharedLibPropagation(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -1573,6 +2103,7 @@
name: "mysdk_sslnil@current",
sdk_member_name: "sslnil",
installable: false,
+ compile_multilib: "both",
arch: {
arm64: {
srcs: ["arm64/lib/sslnil.so"],
@@ -1586,6 +2117,7 @@
cc_prebuilt_library_shared {
name: "sslnil",
prefer: false,
+ compile_multilib: "both",
arch: {
arm64: {
srcs: ["arm64/lib/sslnil.so"],
@@ -1600,6 +2132,7 @@
name: "mysdk_sslempty@current",
sdk_member_name: "sslempty",
installable: false,
+ compile_multilib: "both",
system_shared_libs: [],
arch: {
arm64: {
@@ -1614,6 +2147,7 @@
cc_prebuilt_library_shared {
name: "sslempty",
prefer: false,
+ compile_multilib: "both",
system_shared_libs: [],
arch: {
arm64: {
@@ -1629,6 +2163,7 @@
name: "mysdk_sslnonempty@current",
sdk_member_name: "sslnonempty",
installable: false,
+ compile_multilib: "both",
system_shared_libs: ["mysdk_sslnil@current"],
arch: {
arm64: {
@@ -1643,6 +2178,7 @@
cc_prebuilt_library_shared {
name: "sslnonempty",
prefer: false,
+ compile_multilib: "both",
system_shared_libs: ["sslnil"],
arch: {
arm64: {
@@ -1691,7 +2227,11 @@
sdk_member_name: "sslvariants",
host_supported: true,
installable: false,
+ compile_multilib: "both",
target: {
+ host: {
+ enabled: false,
+ },
android: {
system_shared_libs: [],
},
@@ -1701,6 +2241,9 @@
android_arm: {
srcs: ["android/arm/lib/sslvariants.so"],
},
+ linux_glibc: {
+ enabled: true,
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
},
@@ -1714,7 +2257,11 @@
name: "sslvariants",
prefer: false,
host_supported: true,
+ compile_multilib: "both",
target: {
+ host: {
+ enabled: false,
+ },
android: {
system_shared_libs: [],
},
@@ -1724,6 +2271,9 @@
android_arm: {
srcs: ["android/arm/lib/sslvariants.so"],
},
+ linux_glibc: {
+ enabled: true,
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/sslvariants.so"],
},
@@ -1737,6 +2287,14 @@
name: "mysdk@current",
host_supported: true,
native_shared_libs: ["mysdk_sslvariants@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`))
}
@@ -1770,6 +2328,7 @@
name: "mysdk_stubslib@current",
sdk_member_name: "stubslib",
installable: false,
+ compile_multilib: "both",
stubs: {
versions: ["3"],
},
@@ -1786,6 +2345,7 @@
cc_prebuilt_library_shared {
name: "stubslib",
prefer: false,
+ compile_multilib: "both",
stubs: {
versions: ["3"],
},
@@ -1807,9 +2367,6 @@
}
func TestDeviceAndHostSnapshotWithStubsLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithCc(t, `
sdk {
name: "mysdk",
@@ -1842,16 +2399,23 @@
sdk_member_name: "stubslib",
host_supported: true,
installable: false,
+ compile_multilib: "both",
stubs: {
versions: ["3"],
},
target: {
+ host: {
+ enabled: false,
+ },
android_arm64: {
srcs: ["android/arm64/lib/stubslib.so"],
},
android_arm: {
srcs: ["android/arm/lib/stubslib.so"],
},
+ linux_glibc: {
+ enabled: true,
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
},
@@ -1865,16 +2429,23 @@
name: "stubslib",
prefer: false,
host_supported: true,
+ compile_multilib: "both",
stubs: {
versions: ["3"],
},
target: {
+ host: {
+ enabled: false,
+ },
android_arm64: {
srcs: ["android/arm64/lib/stubslib.so"],
},
android_arm: {
srcs: ["android/arm/lib/stubslib.so"],
},
+ linux_glibc: {
+ enabled: true,
+ },
linux_glibc_x86_64: {
srcs: ["linux_glibc/x86_64/lib/stubslib.so"],
},
@@ -1888,6 +2459,113 @@
name: "mysdk@current",
host_supported: true,
native_shared_libs: ["mysdk_stubslib@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
}
`))
}
+
+func TestUniqueHostSoname(t *testing.T) {
+ result := testSdkWithCc(t, `
+ sdk {
+ name: "mysdk",
+ host_supported: true,
+ native_shared_libs: ["mylib"],
+ }
+
+ cc_library {
+ name: "mylib",
+ host_supported: true,
+ unique_host_soname: true,
+ }
+ `)
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+ name: "mysdk_mylib@current",
+ sdk_member_name: "mylib",
+ host_supported: true,
+ installable: false,
+ unique_host_soname: true,
+ compile_multilib: "both",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/mylib.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/mylib.so"],
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+ },
+ },
+}
+
+cc_prebuilt_library_shared {
+ name: "mylib",
+ prefer: false,
+ host_supported: true,
+ unique_host_soname: true,
+ compile_multilib: "both",
+ target: {
+ host: {
+ enabled: false,
+ },
+ android_arm64: {
+ srcs: ["android/arm64/lib/mylib.so"],
+ },
+ android_arm: {
+ srcs: ["android/arm/lib/mylib.so"],
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ linux_glibc_x86_64: {
+ srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+ },
+ linux_glibc_x86: {
+ srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+ },
+ },
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ host_supported: true,
+ native_shared_libs: ["mysdk_mylib@current"],
+ target: {
+ host: {
+ enabled: false,
+ },
+ linux_glibc: {
+ enabled: true,
+ },
+ },
+}
+`),
+ checkAllCopyRules(`
+.intermediates/mylib/android_arm64_armv8-a_shared/mylib.so -> android/arm64/lib/mylib.so
+.intermediates/mylib/android_arm_armv7-a-neon_shared/mylib.so -> android/arm/lib/mylib.so
+.intermediates/mylib/linux_glibc_x86_64_shared/mylib-host.so -> linux_glibc/x86_64/lib/mylib-host.so
+.intermediates/mylib/linux_glibc_x86_shared/mylib-host.so -> linux_glibc/x86/lib/mylib-host.so
+`),
+ )
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index db395c5..a7ee8d1 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -16,6 +16,8 @@
import (
"testing"
+
+ "android/soong/java"
)
func testSdkWithJava(t *testing.T, bp string) *testSdkResult {
@@ -23,8 +25,12 @@
fs := map[string][]byte{
"Test.java": nil,
+ "resource.test": nil,
"aidl/foo/bar/Test.aidl": nil,
+ // For java_import
+ "prebuilt.jar": nil,
+
// For java_sdk_library
"api/current.txt": nil,
"api/removed.txt": nil,
@@ -45,10 +51,10 @@
name: "core-current-stubs-system-modules",
}
java_system_modules_import {
- name: "core-platform-api-stubs-system-modules",
+ name: "stable-core-platform-api-stubs-system-modules",
}
java_import {
- name: "core.platform.api.stubs",
+ name: "stable.core.platform.api.stubs",
}
java_import {
name: "android_stubs_current",
@@ -84,6 +90,52 @@
// Contains tests for SDK members provided by the java package.
+func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ java_header_libs: ["sdkmember"],
+ }
+
+ java_library {
+ name: "sdkmember",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ }
+
+ java_import {
+ name: "sdkmember",
+ prefer: true,
+ jars: ["prebuilt.jar"],
+ }
+ `)
+
+ // Make sure that the mysdk module depends on "sdkmember" and not "prebuilt_sdkmember".
+ java.CheckModuleDependencies(t, result.ctx, "mysdk", "android_common", []string{"sdkmember"})
+
+ result.CheckSnapshot("mysdk", "",
+ checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.
+
+java_import {
+ name: "mysdk_sdkmember@current",
+ sdk_member_name: "sdkmember",
+ jars: ["java/sdkmember.jar"],
+}
+
+java_import {
+ name: "sdkmember",
+ prefer: false,
+ jars: ["java/sdkmember.jar"],
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ java_header_libs: ["mysdk_sdkmember@current"],
+}
+`))
+}
+
func TestBasicSdkWithJavaLibrary(t *testing.T) {
result := testSdkWithJava(t, `
sdk {
@@ -152,11 +204,11 @@
}
`)
- sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common_myapex").Rule("combineJar").Output
- sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common_myapex2").Rule("combineJar").Output
+ sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output
+ sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output
- javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex")
- javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2")
+ javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1")
+ javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2")
// Depending on the uses_sdks value, different libs are linked
ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
@@ -213,9 +265,6 @@
}
func TestHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
sdk {
name: "mysdk",
@@ -273,9 +322,6 @@
}
func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
sdk {
name: "mysdk",
@@ -348,6 +394,7 @@
java_library {
name: "myjavalib",
srcs: ["Test.java"],
+ java_resources: ["resource.txt"],
aidl: {
export_include_dirs: ["aidl"],
},
@@ -381,16 +428,13 @@
`),
checkAllCopyRules(`
-.intermediates/myjavalib/android_common/javac/myjavalib.jar -> java/myjavalib.jar
+.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar
aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl
`),
)
}
func TestHostSnapshotWithJavaImplLibrary(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
module_exports {
name: "myexports",
@@ -495,9 +539,6 @@
}
func TestHostSnapshotWithJavaTest(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
module_exports {
name: "myexports",
@@ -639,9 +680,6 @@
}
func TestHostSnapshotWithDroidstubs(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithDroidstubs(t, `
module_exports {
name: "myexports",
@@ -782,9 +820,6 @@
}
func TestHostSnapshotWithJavaSystemModules(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
sdk {
name: "mysdk",
@@ -860,9 +895,6 @@
}
func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) {
- // b/145598135 - Generating host snapshots for anything other than linux is not supported.
- SkipIfNotLinux(t)
-
result := testSdkWithJava(t, `
module_exports {
name: "myexports",
@@ -1392,8 +1424,8 @@
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
.intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
-.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
-.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
+.intermediates/myjavalib.stubs.source.module_lib/android_common/myjavalib.stubs.source.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
`),
checkMergeZips(
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1502,7 +1534,7 @@
apex_available: ["//apex_available:anyapex"],
srcs: ["Test.java"],
sdk_version: "current",
- naming_scheme: "framework-modules",
+ naming_scheme: "default",
public: {
enabled: true,
},
@@ -1517,7 +1549,7 @@
name: "mysdk_myjavalib@current",
sdk_member_name: "myjavalib",
apex_available: ["//apex_available:anyapex"],
- naming_scheme: "framework-modules",
+ naming_scheme: "default",
shared_library: true,
public: {
jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1532,7 +1564,7 @@
name: "myjavalib",
prefer: false,
apex_available: ["//apex_available:anyapex"],
- naming_scheme: "framework-modules",
+ naming_scheme: "default",
shared_library: true,
public: {
jars: ["sdk_library/public/myjavalib-stubs.jar"],
@@ -1549,9 +1581,9 @@
}
`),
checkAllCopyRules(`
-.intermediates/myjavalib-stubs-publicapi/android_common/javac/myjavalib-stubs-publicapi.jar -> sdk_library/public/myjavalib-stubs.jar
-.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
`),
checkMergeZips(
".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
diff --git a/sdk/sdk.go b/sdk/sdk.go
index b9b8199..7591020 100644
--- a/sdk/sdk.go
+++ b/sdk/sdk.go
@@ -218,7 +218,7 @@
Compile_multilib *string
}
p := &props{Compile_multilib: proptools.StringPtr("both")}
- ctx.AppendProperties(p)
+ ctx.PrependProperties(p)
})
return s
}
@@ -330,6 +330,11 @@
blueprint.BaseDependencyTag
}
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t dependencyTag) ExcludeFromApexContents() {}
+
+var _ android.ExcludeFromApexContentsTag = dependencyTag{}
+
// For dependencies from an in-development version of an SDK member to frozen versions of the same member
// e.g. libfoo -> libfoo.mysdk.11 and libfoo.mysdk.12
type sdkMemberVersionedDepTag struct {
@@ -401,13 +406,17 @@
// Step 4: transitively ripple down the SDK requirements from the root modules like APEX to its
// descendants
func sdkDepsMutator(mctx android.TopDownMutatorContext) {
- if m, ok := mctx.Module().(android.SdkAware); ok {
+ if parent, ok := mctx.Module().(interface {
+ android.DepIsInSameApex
+ android.RequiredSdks
+ }); ok {
// Module types for Mainline modules (e.g. APEX) are expected to implement RequiredSdks()
// by reading its own properties like `uses_sdks`.
- requiredSdks := m.RequiredSdks()
+ requiredSdks := parent.RequiredSdks()
if len(requiredSdks) > 0 {
mctx.VisitDirectDeps(func(m android.Module) {
- if dep, ok := m.(android.SdkAware); ok {
+ // Only propagate required sdks from the apex onto its contents.
+ if dep, ok := m.(android.SdkAware); ok && parent.DepIsInSameApex(mctx, dep) {
dep.BuildWithSdks(requiredSdks)
}
})
@@ -418,15 +427,28 @@
// Step 5: if libfoo.mysdk.11 is in the context where version 11 of mysdk is requested, the
// versioned module is used instead of the un-versioned (in-development) module libfoo
func sdkDepsReplaceMutator(mctx android.BottomUpMutatorContext) {
- if m, ok := mctx.Module().(android.SdkAware); ok && m.IsInAnySdk() {
- if sdk := m.ContainingSdk(); !sdk.Unversioned() {
- if m.RequiredSdks().Contains(sdk) {
- // Note that this replacement is done only for the modules that have the same
- // variations as the current module. Since current module is already mutated for
- // apex references in other APEXes are not affected by this replacement.
- memberName := m.MemberName()
- mctx.ReplaceDependencies(memberName)
- }
+ if versionedSdkMember, ok := mctx.Module().(android.SdkAware); ok && versionedSdkMember.IsInAnySdk() {
+ if sdk := versionedSdkMember.ContainingSdk(); !sdk.Unversioned() {
+ // Only replace dependencies to <sdkmember> with <sdkmember@required-version>
+ // if the depending module requires it. e.g.
+ // foo -> sdkmember
+ // will be transformed to:
+ // foo -> sdkmember@1
+ // if and only if foo is a member of an APEX that requires version 1 of the
+ // sdk containing sdkmember.
+ memberName := versionedSdkMember.MemberName()
+
+ // Replace dependencies on sdkmember with a dependency on the current module which
+ // is a versioned prebuilt of the sdkmember if required.
+ mctx.ReplaceDependenciesIf(memberName, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
+ // from - foo
+ // to - sdkmember
+ replace := false
+ if parent, ok := from.(android.RequiredSdks); ok {
+ replace = parent.RequiredSdks().Contains(sdk)
+ }
+ return replace
+ })
}
}
}
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 56be741..ef62b79 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -15,6 +15,9 @@
package sdk
import (
+ "android/soong/android"
+ "log"
+ "os"
"testing"
"github.com/google/blueprint/proptools"
@@ -22,6 +25,12 @@
// Needed in an _test.go file in this package to ensure tests run correctly, particularly in IDE.
func TestMain(m *testing.M) {
+ if android.BuildOs != android.Linux {
+ // b/145598135 - Generating host snapshots for anything other than linux is not supported.
+ log.Printf("Skipping as sdk snapshot generation is only supported on %s not %s", android.Linux, android.BuildOs)
+ os.Exit(0)
+ }
+
runTestWithBuildDir(m)
}
diff --git a/sdk/testing.go b/sdk/testing.go
index 4361754..b53558d 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -29,7 +29,9 @@
"android/soong/java"
)
-func testSdkContext(bp string, fs map[string][]byte) (*android.TestContext, android.Config) {
+func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsType) (*android.TestContext, android.Config) {
+ extraOsTypes = append(extraOsTypes, android.Android, android.Windows)
+
bp = bp + `
apex_key {
name: "myapex.key",
@@ -41,17 +43,18 @@
name: "myapex.cert",
certificate: "myapex",
}
- ` + cc.GatherRequiredDepsForTest(android.Android, android.Windows)
+ ` + cc.GatherRequiredDepsForTest(extraOsTypes...)
mockFS := map[string][]byte{
- "build/make/target/product/security": nil,
- "apex_manifest.json": nil,
- "system/sepolicy/apex/myapex-file_contexts": nil,
- "system/sepolicy/apex/myapex2-file_contexts": nil,
- "myapex.avbpubkey": nil,
- "myapex.pem": nil,
- "myapex.x509.pem": nil,
- "myapex.pk8": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex2-file_contexts": nil,
+ "system/sepolicy/apex/mysdkapex-file_contexts": nil,
+ "myapex.avbpubkey": nil,
+ "myapex.pem": nil,
+ "myapex.x509.pem": nil,
+ "myapex.pk8": nil,
}
cc.GatherRequiredFilesForTest(mockFS)
@@ -68,6 +71,15 @@
{android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
}
+ for _, extraOsType := range extraOsTypes {
+ switch extraOsType {
+ case android.LinuxBionic:
+ config.Targets[android.LinuxBionic] = []android.Target{
+ {android.LinuxBionic, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", ""},
+ }
+ }
+ }
+
ctx := android.NewTestArchContext()
// Enable androidmk support.
@@ -84,6 +96,12 @@
android.RegisterPackageBuildComponents(ctx)
ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
+ ctx.PreArchMutators(android.RegisterComponentsMutator)
+
+ android.RegisterPrebuiltMutators(ctx)
+
+ // Register these after the prebuilt mutators have been registered to match what
+ // happens at runtime.
ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
@@ -115,9 +133,8 @@
return ctx, config
}
-func testSdkWithFs(t *testing.T, bp string, fs map[string][]byte) *testSdkResult {
+func runTests(t *testing.T, ctx *android.TestContext, config android.Config) *testSdkResult {
t.Helper()
- ctx, config := testSdkContext(bp, fs)
_, errs := ctx.ParseBlueprintsFiles(".")
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -129,9 +146,15 @@
}
}
+func testSdkWithFs(t *testing.T, bp string, fs map[string][]byte) *testSdkResult {
+ t.Helper()
+ ctx, config := testSdkContext(bp, fs, nil)
+ return runTests(t, ctx, config)
+}
+
func testSdkError(t *testing.T, pattern, bp string) {
t.Helper()
- ctx, config := testSdkContext(bp, nil)
+ ctx, config := testSdkContext(bp, nil, nil)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
if len(errs) > 0 {
android.FailIfNoMatchingErrors(t, pattern, errs)
@@ -420,10 +443,3 @@
os.Exit(run())
}
-
-func SkipIfNotLinux(t *testing.T) {
- t.Helper()
- if android.BuildOs != android.Linux {
- t.Skipf("Skipping as sdk snapshot generation is only supported on %s not %s", android.Linux, android.BuildOs)
- }
-}
diff --git a/sdk/update.go b/sdk/update.go
index 59a7640..537ab13 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -43,7 +43,7 @@
zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
blueprint.RuleParams{
- Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`,
+ Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`,
CommandDeps: []string{
"${config.SoongZipCmd}",
},
@@ -262,7 +262,7 @@
memberCtx := &memberContext{ctx, builder, memberType, member.name}
prebuiltModule := memberType.AddPrebuiltModule(memberCtx, member)
- s.createMemberSnapshot(memberCtx, member, prebuiltModule)
+ s.createMemberSnapshot(memberCtx, member, prebuiltModule.(*bpModule))
}
// Create a transformer that will transform an unversioned module into a versioned module.
@@ -323,19 +323,62 @@
// Add properties common to all os types.
s.addMemberPropertiesToPropertySet(builder, snapshotModule, commonDynamicMemberProperties)
- // Iterate over the os types in a fixed order.
+ // Optimize other per-variant properties, besides the dynamic member lists.
+ type variantProperties struct {
+ Compile_multilib string `android:"arch_variant"`
+ }
+ var variantPropertiesContainers []propertiesContainer
+ variantToProperties := make(map[*sdk]*variantProperties)
+ for _, sdkVariant := range sdkVariants {
+ props := &variantProperties{
+ Compile_multilib: sdkVariant.multilibUsages.String(),
+ }
+ variantPropertiesContainers = append(variantPropertiesContainers, &dynamicMemberPropertiesContainer{sdkVariant, props})
+ variantToProperties[sdkVariant] = props
+ }
+ commonVariantProperties := variantProperties{}
+ extractor = newCommonValueExtractor(commonVariantProperties)
+ extractCommonProperties(ctx, extractor, &commonVariantProperties, variantPropertiesContainers)
+ if commonVariantProperties.Compile_multilib != "" && commonVariantProperties.Compile_multilib != "both" {
+ // Compile_multilib defaults to both so only needs to be set when it's
+ // specified and not both.
+ snapshotModule.AddProperty("compile_multilib", commonVariantProperties.Compile_multilib)
+ }
+
targetPropertySet := snapshotModule.AddPropertySet("target")
+
+ // If host is supported and any member is host OS dependent then disable host
+ // by default, so that we can enable each host OS variant explicitly. This
+ // avoids problems with implicitly enabled OS variants when the snapshot is
+ // used, which might be different from this run (e.g. different build OS).
+ hasHostOsDependentMember := false
+ if s.HostSupported() {
+ for _, memberRef := range memberRefs {
+ if memberRef.memberType.IsHostOsDependent() {
+ hasHostOsDependentMember = true
+ break
+ }
+ }
+ if hasHostOsDependentMember {
+ hostPropertySet := targetPropertySet.AddPropertySet("host")
+ hostPropertySet.AddProperty("enabled", false)
+ }
+ }
+
+ // Iterate over the os types in a fixed order.
for _, osType := range s.getPossibleOsTypes() {
if sdkVariant, ok := osTypeToMemberProperties[osType]; ok {
osPropertySet := targetPropertySet.AddPropertySet(sdkVariant.Target().Os.Name)
- // Compile_multilib defaults to both and must always be set to both on the
- // device and so only needs to be set when targeted at the host and is neither
- // unspecified or both.
- multilib := sdkVariant.multilibUsages
- if (osType.Class == android.Host || osType.Class == android.HostCross) &&
- multilib != multilibNone && multilib != multilibBoth {
- osPropertySet.AddProperty("compile_multilib", multilib.String())
+ // Enable the variant explicitly when we've disabled it by default on host.
+ if hasHostOsDependentMember &&
+ (osType.Class == android.Host || osType.Class == android.HostCross) {
+ osPropertySet.AddProperty("enabled", true)
+ }
+
+ variantProps := variantToProperties[sdkVariant]
+ if variantProps.Compile_multilib != "" && variantProps.Compile_multilib != "both" {
+ osPropertySet.AddProperty("compile_multilib", variantProps.Compile_multilib)
}
s.addMemberPropertiesToPropertySet(builder, osPropertySet, sdkVariant.dynamicMemberTypeListProperties)
@@ -351,6 +394,9 @@
bp = newGeneratedFile(ctx, "snapshot", "Android.bp")
generateBpContents(&bp.generatedContents, bpFile)
+ contents := bp.content.String()
+ syntaxCheckSnapshotBpFile(ctx, contents)
+
bp.build(pctx, ctx, nil)
filesToZip := builder.filesToZip
@@ -395,6 +441,36 @@
return outputZipFile
}
+// Check the syntax of the generated Android.bp file contents and if they are
+// invalid then log an error with the contents (tagged with line numbers) and the
+// errors that were found so that it is easy to see where the problem lies.
+func syntaxCheckSnapshotBpFile(ctx android.ModuleContext, contents string) {
+ errs := android.CheckBlueprintSyntax(ctx, "Android.bp", contents)
+ if len(errs) != 0 {
+ message := &strings.Builder{}
+ _, _ = fmt.Fprint(message, `errors in generated Android.bp snapshot:
+
+Generated Android.bp contents
+========================================================================
+`)
+ for i, line := range strings.Split(contents, "\n") {
+ _, _ = fmt.Fprintf(message, "%6d: %s\n", i+1, line)
+ }
+
+ _, _ = fmt.Fprint(message, `
+========================================================================
+
+Errors found:
+`)
+
+ for _, err := range errs {
+ _, _ = fmt.Fprintf(message, "%s\n", err.Error())
+ }
+
+ ctx.ModuleErrorf("%s", message.String())
+ }
+}
+
func extractCommonProperties(ctx android.ModuleContext, extractor *commonValueExtractor, commonProperties interface{}, inputPropertiesSlice interface{}) {
err := extractor.extractCommonProperties(commonProperties, inputPropertiesSlice)
if err != nil {
@@ -761,6 +837,17 @@
return !ok
}
+// Add the properties from the given SdkMemberProperties to the blueprint
+// property set. This handles common properties in SdkMemberPropertiesBase and
+// calls the member-specific AddToPropertySet for the rest.
+func addSdkMemberPropertiesToSet(ctx *memberContext, memberProperties android.SdkMemberProperties, targetPropertySet android.BpPropertySet) {
+ if memberProperties.Base().Compile_multilib != "" {
+ targetPropertySet.AddProperty("compile_multilib", memberProperties.Base().Compile_multilib)
+ }
+
+ memberProperties.AddToPropertySet(ctx, targetPropertySet)
+}
+
type sdkMemberRef struct {
memberType android.SdkMemberType
variant android.SdkAware
@@ -878,7 +965,7 @@
if commonVariants, ok := variantsByArchName["common"]; ok {
if len(osTypeVariants) != 1 {
- panic("Expected to only have 1 variant when arch type is common but found " + string(len(osTypeVariants)))
+ panic(fmt.Errorf("Expected to only have 1 variant when arch type is common but found %d", len(osTypeVariants)))
}
// A common arch type only has one variant and its properties should be treated
@@ -931,9 +1018,12 @@
var osPropertySet android.BpPropertySet
var archPropertySet android.BpPropertySet
var archOsPrefix string
- if osInfo.Properties.Base().Os_count == 1 {
- // There is only one os type present in the variants so don't bother
- // with adding target specific properties.
+ if osInfo.Properties.Base().Os_count == 1 &&
+ (osInfo.osType.Class == android.Device || !ctx.memberType.IsHostOsDependent()) {
+ // There is only one OS type present in the variants and it shouldn't have a
+ // variant-specific target. The latter is the case if it's either for device
+ // where there is only one OS (android), or for host and the member type
+ // isn't host OS dependent.
// Create a structure that looks like:
// module_type {
@@ -970,13 +1060,19 @@
osPropertySet = targetPropertySet.AddPropertySet(osType.Name)
archPropertySet = targetPropertySet
+ // Enable the variant explicitly when we've disabled it by default on host.
+ if ctx.memberType.IsHostOsDependent() &&
+ (osType.Class == android.Host || osType.Class == android.HostCross) {
+ osPropertySet.AddProperty("enabled", true)
+ }
+
// Arch specific properties need to be added to an os and arch specific
// section prefixed with <os>_.
archOsPrefix = osType.Name + "_"
}
// Add the os specific but arch independent properties to the module.
- osInfo.Properties.AddToPropertySet(ctx, osPropertySet)
+ addSdkMemberPropertiesToSet(ctx, osInfo.Properties, osPropertySet)
// Add arch (and possibly os) specific sections for each set of arch (and possibly
// os) specific properties.
@@ -1078,11 +1174,11 @@
func (archInfo *archTypeSpecificInfo) addToPropertySet(ctx *memberContext, archPropertySet android.BpPropertySet, archOsPrefix string) {
archTypeName := archInfo.archType.Name
archTypePropertySet := archPropertySet.AddPropertySet(archOsPrefix + archTypeName)
- archInfo.Properties.AddToPropertySet(ctx, archTypePropertySet)
+ addSdkMemberPropertiesToSet(ctx, archInfo.Properties, archTypePropertySet)
for _, linkInfo := range archInfo.linkInfos {
linkPropertySet := archTypePropertySet.AddPropertySet(linkInfo.linkType)
- linkInfo.Properties.AddToPropertySet(ctx, linkPropertySet)
+ addSdkMemberPropertiesToSet(ctx, linkInfo.Properties, linkPropertySet)
}
}
@@ -1140,7 +1236,7 @@
return m.name
}
-func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule android.BpModule) {
+func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModule *bpModule) {
memberType := member.memberType
@@ -1188,12 +1284,24 @@
extractCommonProperties(ctx.sdkMemberContext, commonValueExtractor, commonProperties, osSpecificPropertiesContainers)
// Add the common properties to the module.
- commonProperties.AddToPropertySet(ctx, bpModule)
+ addSdkMemberPropertiesToSet(ctx, commonProperties, bpModule)
// Create a target property set into which target specific properties can be
// added.
targetPropertySet := bpModule.AddPropertySet("target")
+ // If the member is host OS dependent and has host_supported then disable by
+ // default and enable each host OS variant explicitly. This avoids problems
+ // with implicitly enabled OS variants when the snapshot is used, which might
+ // be different from this run (e.g. different build OS).
+ if ctx.memberType.IsHostOsDependent() {
+ hostSupported := bpModule.getValue("host_supported") == true // Missing means false.
+ if hostSupported {
+ hostPropertySet := targetPropertySet.AddPropertySet("host")
+ hostPropertySet.AddProperty("enabled", false)
+ }
+ }
+
// Iterate over the os types in a fixed order.
for _, osType := range s.getPossibleOsTypes() {
osInfo := osTypeToInfo[osType]
diff --git a/sh/Android.bp b/sh/Android.bp
index 0f40c5f..e5ffeef 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -5,6 +5,7 @@
"blueprint",
"soong",
"soong-android",
+ "soong-cc",
"soong-tradefed",
],
srcs: [
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index ab0490a..f3f4a4a 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -17,11 +17,14 @@
import (
"fmt"
"path/filepath"
+ "sort"
"strings"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/cc"
"android/soong/tradefed"
)
@@ -61,6 +64,12 @@
// install symlinks to the binary
Symlinks []string `android:"arch_variant"`
+
+ // Make this module available when building for ramdisk.
+ Ramdisk_available *bool
+
+ // Make this module available when building for recovery.
+ Recovery_available *bool
}
type TestProperties struct {
@@ -88,6 +97,20 @@
// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
// explicitly.
Auto_gen_config *bool
+
+ // list of binary modules that should be installed alongside the test
+ Data_bins []string `android:"path,arch_variant"`
+
+ // list of library modules that should be installed alongside the test
+ Data_libs []string `android:"path,arch_variant"`
+
+ // list of device binary modules that should be installed alongside the test.
+ // Only available for host sh_test modules.
+ Data_device_bins []string `android:"path,arch_variant"`
+
+ // list of device library modules that should be installed alongside the test.
+ // Only available for host sh_test modules.
+ Data_device_libs []string `android:"path,arch_variant"`
}
type ShBinary struct {
@@ -107,8 +130,12 @@
testProperties TestProperties
+ installDir android.InstallPath
+
data android.Paths
testConfig android.Path
+
+ dataModules map[string]android.Path
}
func (s *ShBinary) HostToolPath() android.OptionalPath {
@@ -137,6 +164,29 @@
return s.properties.Symlinks
}
+var _ android.ImageInterface = (*ShBinary)(nil)
+
+func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+ return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
+}
+
+func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+ return nil
+}
+
+func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
+
func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
filename := proptools.String(s.properties.Filename)
@@ -176,13 +226,13 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
+ entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
},
},
}}
}
func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) {
- entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
entries.SetString("LOCAL_MODULE_SUFFIX", "")
entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
if len(s.properties.Symlinks) > 0 {
@@ -190,6 +240,50 @@
}
}
+type dependencyTag struct {
+ blueprint.BaseDependencyTag
+ name string
+}
+
+var (
+ shTestDataBinsTag = dependencyTag{name: "dataBins"}
+ shTestDataLibsTag = dependencyTag{name: "dataLibs"}
+ shTestDataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"}
+ shTestDataDeviceLibsTag = dependencyTag{name: "dataDeviceLibs"}
+)
+
+var sharedLibVariations = []blueprint.Variation{{Mutator: "link", Variation: "shared"}}
+
+func (s *ShTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+ s.ShBinary.DepsMutator(ctx)
+
+ ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...)
+ ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...),
+ shTestDataLibsTag, s.testProperties.Data_libs...)
+ if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 {
+ deviceVariations := ctx.Config().Targets[android.Android][0].Variations()
+ ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
+ ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
+ shTestDataDeviceLibsTag, s.testProperties.Data_device_libs...)
+ } else if ctx.Target().Os.Class != android.Host {
+ if len(s.testProperties.Data_device_bins) > 0 {
+ ctx.PropertyErrorf("data_device_bins", "only available for host modules")
+ }
+ if len(s.testProperties.Data_device_libs) > 0 {
+ ctx.PropertyErrorf("data_device_libs", "only available for host modules")
+ }
+ }
+}
+
+func (s *ShTest) addToDataModules(ctx android.ModuleContext, relPath string, path android.Path) {
+ if _, exists := s.dataModules[relPath]; exists {
+ ctx.ModuleErrorf("data modules have a conflicting installation path, %v - %s, %s",
+ relPath, s.dataModules[relPath].String(), path.String())
+ return
+ }
+ s.dataModules[relPath] = path
+}
+
func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
s.ShBinary.generateAndroidBuildActions(ctx)
testDir := "nativetest"
@@ -201,8 +295,14 @@
} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
}
- installDir := android.PathForModuleInstall(ctx, testDir, proptools.String(s.properties.Sub_dir))
- s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+ if s.SubDir() != "" {
+ // Don't add the module name to the installation path if sub_dir is specified for backward
+ // compatibility.
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.SubDir())
+ } else {
+ s.installDir = android.PathForModuleInstall(ctx, testDir, s.Name())
+ }
+ s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath)
s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
@@ -215,6 +315,50 @@
}
s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config,
s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base())
+
+ s.dataModules = make(map[string]android.Path)
+ ctx.VisitDirectDeps(func(dep android.Module) {
+ depTag := ctx.OtherModuleDependencyTag(dep)
+ switch depTag {
+ case shTestDataBinsTag, shTestDataDeviceBinsTag:
+ if cc, isCc := dep.(*cc.Module); isCc {
+ s.addToDataModules(ctx, cc.OutputFile().Path().Base(), cc.OutputFile().Path())
+ return
+ }
+ property := "data_bins"
+ if depTag == shTestDataDeviceBinsTag {
+ property = "data_device_bins"
+ }
+ ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+ case shTestDataLibsTag, shTestDataDeviceLibsTag:
+ if cc, isCc := dep.(*cc.Module); isCc {
+ // Copy to an intermediate output directory to append "lib[64]" to the path,
+ // so that it's compatible with the default rpath values.
+ var relPath string
+ if cc.Arch().ArchType.Multilib == "lib64" {
+ relPath = filepath.Join("lib64", cc.OutputFile().Path().Base())
+ } else {
+ relPath = filepath.Join("lib", cc.OutputFile().Path().Base())
+ }
+ if _, exist := s.dataModules[relPath]; exist {
+ return
+ }
+ relocatedLib := android.PathForModuleOut(ctx, "relocated", relPath)
+ ctx.Build(pctx, android.BuildParams{
+ Rule: android.Cp,
+ Input: cc.OutputFile().Path(),
+ Output: relocatedLib,
+ })
+ s.addToDataModules(ctx, relPath, relocatedLib)
+ return
+ }
+ property := "data_libs"
+ if depTag == shTestDataDeviceBinsTag {
+ property = "data_device_libs"
+ }
+ ctx.PropertyErrorf(property, "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep))
+ }
+ })
}
func (s *ShTest) InstallInData() bool {
@@ -229,7 +373,7 @@
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
func(entries *android.AndroidMkEntries) {
s.customAndroidMkEntries(entries)
-
+ entries.SetPath("LOCAL_MODULE_PATH", s.installDir.ToMakePath())
entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
if s.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
@@ -243,6 +387,15 @@
path = strings.TrimSuffix(path, rel)
entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
}
+ relPaths := make([]string, 0)
+ for relPath, _ := range s.dataModules {
+ relPaths = append(relPaths, relPath)
+ }
+ sort.Strings(relPaths)
+ for _, relPath := range relPaths {
+ dir := strings.TrimSuffix(s.dataModules[relPath].String(), relPath)
+ entries.AddStrings("LOCAL_TEST_DATA", dir+":"+relPath)
+ }
},
},
}}
@@ -256,9 +409,6 @@
// executable binary to <partition>/bin.
func ShBinaryFactory() android.Module {
module := &ShBinary{}
- module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
- return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
- })
InitShBinaryModule(module)
android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
return module
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 6c0d96a..0aa607b 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -3,10 +3,12 @@
import (
"io/ioutil"
"os"
+ "path/filepath"
"reflect"
"testing"
"android/soong/android"
+ "android/soong/cc"
)
var buildDir string
@@ -46,6 +48,9 @@
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("sh_test", ShTestFactory)
ctx.RegisterModuleType("sh_test_host", ShTestHostFactory)
+
+ cc.RegisterRequiredBuildComponentsForTest(ctx)
+
ctx.Register(config)
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
android.FailIfErrored(t, errs)
@@ -55,7 +60,27 @@
return ctx, config
}
-func TestShTestTestData(t *testing.T) {
+func TestShTestSubDir(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_test {
+ name: "foo",
+ src: "test.sh",
+ sub_dir: "foo_test"
+ }
+ `)
+
+ mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
+
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo_test"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+}
+
+func TestShTest(t *testing.T) {
ctx, config := testShBinary(t, `
sh_test {
name: "foo",
@@ -71,10 +96,76 @@
mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
- expected := []string{":testdata/data1", ":testdata/sub/data2"}
- actual := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expected, actual) {
- t.Errorf("Unexpected test data expected: %q, actual: %q", expected, actual)
+
+ expectedPath := "/tmp/target/product/test_device/data/nativetest64/foo"
+ actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
+ if expectedPath != actualPath {
+ t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
+ }
+
+ expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ if !reflect.DeepEqual(expectedData, actualData) {
+ t.Errorf("Unexpected test data expected: %q, actual: %q", expectedData, actualData)
+ }
+}
+
+func TestShTest_dataModules(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_test {
+ name: "foo",
+ src: "test.sh",
+ host_supported: true,
+ data_bins: ["bar"],
+ data_libs: ["libbar"],
+ }
+
+ cc_binary {
+ name: "bar",
+ host_supported: true,
+ shared_libs: ["libbar"],
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libbar",
+ host_supported: true,
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+ arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"}
+ for _, arch := range arches {
+ variant := ctx.ModuleForTests("foo", arch)
+
+ libExt := ".so"
+ if arch == "darwin_x86_64" {
+ libExt = ".dylib"
+ }
+ relocated := variant.Output("relocated/lib64/libbar" + libExt)
+ expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt)
+ if relocated.Input.String() != expectedInput {
+ t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+ expectedInput, relocated.Input.String())
+ }
+
+ mod := variant.Module().(*ShTest)
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+ expectedData := []string{
+ filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"),
+ filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
+ }
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ if !reflect.DeepEqual(expectedData, actualData) {
+ t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+ }
}
}
@@ -97,3 +188,53 @@
t.Errorf("host bit is not set for a sh_test_host module.")
}
}
+
+func TestShTestHost_dataDeviceModules(t *testing.T) {
+ ctx, config := testShBinary(t, `
+ sh_test_host {
+ name: "foo",
+ src: "test.sh",
+ data_device_bins: ["bar"],
+ data_device_libs: ["libbar"],
+ }
+
+ cc_binary {
+ name: "bar",
+ shared_libs: ["libbar"],
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libbar",
+ no_libcrt: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ buildOS := android.BuildOs.String()
+ variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
+
+ relocated := variant.Output("relocated/lib64/libbar.so")
+ expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
+ if relocated.Input.String() != expectedInput {
+ t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
+ expectedInput, relocated.Input.String())
+ }
+
+ mod := variant.Module().(*ShTest)
+ entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+ expectedData := []string{
+ filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"),
+ // libbar has been relocated, and so has a variant that matches the host arch.
+ filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"),
+ }
+ actualData := entries.EntryMap["LOCAL_TEST_DATA"]
+ if !reflect.DeepEqual(expectedData, actualData) {
+ t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
+ }
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 14fab68..768c8e5 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -18,6 +18,7 @@
"fmt"
"io"
"path"
+ "sync"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -161,8 +162,21 @@
var (
pctx = android.NewPackageContext("android/soong/sysprop")
syspropCcTag = dependencyTag{name: "syspropCc"}
+
+ syspropLibrariesKey = android.NewOnceKey("syspropLibraries")
+ syspropLibrariesLock sync.Mutex
)
+func syspropLibraries(config android.Config) *[]string {
+ return config.Once(syspropLibrariesKey, func() interface{} {
+ return &[]string{}
+ }).(*[]string)
+}
+
+func SyspropLibraries(config android.Config) []string {
+ return append([]string{}, *syspropLibraries(config)...)
+}
+
func init() {
android.RegisterModuleType("sysprop_library", syspropLibraryFactory)
}
@@ -202,6 +216,10 @@
return proptools.Bool(m.properties.Public_stub)
}
+func (m *syspropLibrary) CurrentSyspropApiFile() android.Path {
+ return m.currentApiFile
+}
+
func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
baseModuleName := m.BaseModuleName()
@@ -292,6 +310,10 @@
}}
}
+func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion int) error {
+ return fmt.Errorf("sysprop_library is not supposed to be part of apex modules")
+}
+
// sysprop_library creates schematized APIs from sysprop description files (.sysprop).
// Both Java and C++ modules can link against sysprop_library, and API stability check
// against latest APIs (see build/soong/scripts/freeze-sysprop-api-files.sh)
@@ -475,6 +497,14 @@
Stem: proptools.StringPtr(m.BaseModuleName()),
})
}
+
+ if m.ExportedToMake() {
+ syspropLibrariesLock.Lock()
+ defer syspropLibrariesLock.Unlock()
+
+ libraries := syspropLibraries(ctx.Config())
+ *libraries = append(*libraries, "//"+ctx.ModuleDir()+":"+ctx.ModuleName())
+ }
}
func syspropDepsMutator(ctx android.BottomUpMutatorContext) {
diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go
index 8503386..711129c 100644
--- a/sysprop/sysprop_test.go
+++ b/sysprop/sysprop_test.go
@@ -67,6 +67,8 @@
ctx.BottomUp("sysprop_deps", syspropDepsMutator).Parallel()
})
+ android.RegisterPrebuiltMutators(ctx)
+
cc.RegisterRequiredBuildComponentsForTest(ctx)
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("sysprop_java", java.SyspropMutator).Parallel()
diff --git a/third_party/zip/android.go b/third_party/zip/android.go
index 8d387cc..f8e45c5 100644
--- a/third_party/zip/android.go
+++ b/third_party/zip/android.go
@@ -43,6 +43,15 @@
offset: uint64(w.cw.count),
}
w.dir = append(w.dir, h)
+ if !fh.isZip64() {
+ // Some writers will generate 64 bit sizes and set 32 bit fields to
+ // uint32max even if the actual size fits in 32 bit. So we should
+ // make sure CompressedSize contains the correct value in such
+ // cases. With out the two lines below we would be writing invalid(-1)
+ // sizes in such case.
+ fh.CompressedSize = uint32(fh.CompressedSize64)
+ fh.UncompressedSize = uint32(fh.UncompressedSize64)
+ }
if err := writeHeader(w.cw, fh); err != nil {
return err
diff --git a/third_party/zip/zip_test.go b/third_party/zip/zip_test.go
index 7373660..559c914 100644
--- a/third_party/zip/zip_test.go
+++ b/third_party/zip/zip_test.go
@@ -219,7 +219,7 @@
}
}
-// fakeHash32 is a dummy Hash32 that always returns 0.
+// fakeHash32 is a fake Hash32 that always returns 0.
type fakeHash32 struct {
hash.Hash32
}
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 2829146..b35f831 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -40,9 +40,9 @@
}
var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
- Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g' $template > $out",
+ Command: "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g;s&{TEST_INSTALL_BASE}&'${testInstallBase}'&g' $template > $out",
CommandDeps: []string{"$template"},
-}, "name", "template", "extraConfigs", "outputFileName")
+}, "name", "template", "extraConfigs", "outputFileName", "testInstallBase")
func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
p := getTestConfig(ctx, prop)
@@ -107,15 +107,15 @@
}
-func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "")
+func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config, testInstallBase string) {
+ autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "", testInstallBase)
}
-func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config) {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "")
+func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testInstallBase string) {
+ autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "", testInstallBase)
}
-func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string) {
+func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
var configStrings []string
for _, config := range configs {
configStrings = append(configStrings, config.Config())
@@ -128,26 +128,28 @@
Description: "test config",
Output: output,
Args: map[string]string{
- "name": name,
- "template": template,
- "extraConfigs": extraConfigs,
- "outputFileName": outputFileName,
+ "name": name,
+ "template": template,
+ "extraConfigs": extraConfigs,
+ "outputFileName": outputFileName,
+ "testInstallBase": testInstallBase,
},
})
}
func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path {
+
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), config)
+ autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase)
} else {
if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config)
+ autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config, testInstallBase)
} else {
- autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config)
+ autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config, testInstallBase)
}
}
return autogenPath
@@ -161,9 +163,9 @@
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName)
+ autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName, "")
} else {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName)
+ autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName, "")
}
return autogenPath
}
@@ -176,9 +178,9 @@
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), configs)
+ autogenTemplate(ctx, autogenPath, templatePath.String(), configs, "")
} else {
- autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs)
+ autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs, "")
}
return autogenPath
}
@@ -191,12 +193,12 @@
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+ autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
} else {
if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil)
+ autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", nil, "")
} else {
- autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil)
+ autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", nil, "")
}
}
return autogenPath
@@ -211,28 +213,44 @@
if autogenPath != nil {
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), nil)
+ autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
} else {
- autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil)
+ autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil, "")
}
return autogenPath
}
return path
}
-func AutoGenRustTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
+func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string,
+ testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
if autogenPath != nil {
- templatePathString := "${RustHostTestConfigTemplate}"
- if ctx.Device() {
- templatePathString = "${RustDeviceTestConfigTemplate}"
- }
templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
if templatePath.Valid() {
- templatePathString = templatePath.String()
+ autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
+ } else {
+ if ctx.Device() {
+ autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, "")
+ } else {
+ autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, "")
+ }
}
- autogenTemplateWithName(ctx, name, autogenPath, templatePathString, nil)
+ return autogenPath
+ }
+ return path
+}
+
+func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
+ testSuites []string, autoGenConfig *bool) android.Path {
+ path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+ if autogenPath != nil {
+ templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+ if templatePath.Valid() {
+ autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
+ } else {
+ autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil, "")
+ }
return autogenPath
}
return path
diff --git a/tradefed/config.go b/tradefed/config.go
index 34195c3..f7e8349 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -33,6 +33,7 @@
pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+ pctx.SourcePathVariable("RobolectricTestConfigTemplate", "build/make/core/robolectric_test_config_template.xml")
pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml")
diff --git a/ui/build/build.go b/ui/build/build.go
index 349a7de..396f54c 100644
--- a/ui/build/build.go
+++ b/ui/build/build.go
@@ -53,7 +53,6 @@
{{end -}}
pool highmem_pool
depth = {{.HighmemParallel}}
-build _kati_always_build_: phony
{{if .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}}
subninja {{.KatiPackageNinjaFile}}
{{end -}}
@@ -244,6 +243,8 @@
// Write combined ninja file
createCombinedBuildNinjaFile(ctx, config)
+ distGzipFile(ctx, config, config.CombinedNinjaFile())
+
if what&RunBuildTests != 0 {
testForDanglingRules(ctx, config)
}
@@ -257,3 +258,47 @@
runNinja(ctx, config)
}
}
+
+// distGzipFile writes a compressed copy of src to the distDir if dist is enabled. Failures
+// are printed but non-fatal.
+func distGzipFile(ctx Context, config Config, src string, subDirs ...string) {
+ if !config.Dist() {
+ return
+ }
+
+ subDir := filepath.Join(subDirs...)
+ destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+
+ err := os.MkdirAll(destDir, 0777)
+ if err != nil {
+ ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
+
+ }
+
+ err = gzipFileToDir(src, destDir)
+ if err != nil {
+ ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
+ }
+}
+
+// distFile writes a copy of src to the distDir if dist is enabled. Failures are printed but
+// non-fatal.
+func distFile(ctx Context, config Config, src string, subDirs ...string) {
+ if !config.Dist() {
+ return
+ }
+
+ subDir := filepath.Join(subDirs...)
+ destDir := filepath.Join(config.DistDir(), "soong_ui", subDir)
+
+ err := os.MkdirAll(destDir, 0777)
+ if err != nil {
+ ctx.Printf("failed to mkdir %s: %s", destDir, err.Error())
+
+ }
+
+ _, err = copyFile(src, filepath.Join(destDir, filepath.Base(src)))
+ if err != nil {
+ ctx.Printf("failed to dist %s: %s", filepath.Base(src), err.Error())
+ }
+}
diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go
index 0bcdccb..e1123e0 100644
--- a/ui/build/cleanbuild.go
+++ b/ui/build/cleanbuild.go
@@ -104,6 +104,7 @@
productOut("*.img"),
productOut("*.zip"),
productOut("android-info.txt"),
+ productOut("misc_info.txt"),
productOut("apex"),
productOut("kernel"),
productOut("data"),
diff --git a/ui/build/config.go b/ui/build/config.go
index 5bf4baf..e9a8fc9 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -57,8 +57,6 @@
// Autodetected
totalRAM uint64
- pdkBuild bool
-
brokenDupRules bool
brokenUsesNetwork bool
brokenNinjaEnvVars []string
@@ -100,7 +98,7 @@
environ: OsEnvironment(),
}
- // Sane default matching ninja
+ // Default matching ninja
ret.parallel = runtime.NumCPU() + 2
ret.keepGoing = 1
@@ -541,6 +539,9 @@
ctx.Fatalln("Unknown option:", arg)
}
} else if k, v, ok := decodeKeyValue(arg); ok && len(k) > 0 {
+ if k == "OUT_DIR" {
+ ctx.Fatalln("OUT_DIR may only be set in the environment, not as a command line option.")
+ }
c.environ.Set(k, v)
} else if arg == "dist" {
c.dist = true
@@ -613,6 +614,7 @@
c.environ.Set("TARGET_BUILD_VARIANT", variant)
c.environ.Set("TARGET_BUILD_TYPE", "release")
c.environ.Unset("TARGET_BUILD_APPS")
+ c.environ.Unset("TARGET_BUILD_UNBUNDLED")
}
// Tapas configures the environment to build one or more unbundled apps,
@@ -635,10 +637,6 @@
product = "aosp_arm"
case "arm64":
product = "aosm_arm64"
- case "mips":
- product = "aosp_mips"
- case "mips64":
- product = "aosp_mips64"
case "x86":
product = "aosp_x86"
case "x86_64":
@@ -1048,14 +1046,6 @@
return c.targetDeviceDir
}
-func (c *configImpl) SetPdkBuild(pdk bool) {
- c.pdkBuild = pdk
-}
-
-func (c *configImpl) IsPdkBuild() bool {
- return c.pdkBuild
-}
-
func (c *configImpl) BuildDateTime() string {
return c.buildDateTime
}
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index bd073e5..999af07 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -143,6 +143,7 @@
"TARGET_BUILD_VARIANT",
"TARGET_BUILD_TYPE",
"TARGET_BUILD_APPS",
+ "TARGET_BUILD_UNBUNDLED",
"TARGET_ARCH",
"TARGET_ARCH_VARIANT",
"TARGET_CPU_VARIANT",
@@ -160,8 +161,6 @@
"BUILD_ID",
"OUT_DIR",
"AUX_OS_VARIANT_LIST",
- "TARGET_BUILD_PDK",
- "PDK_FUSION_PLATFORM_ZIP",
"PRODUCT_SOONG_NAMESPACES",
}
@@ -187,6 +186,7 @@
"TARGET_PRODUCT",
"TARGET_BUILD_VARIANT",
"TARGET_BUILD_APPS",
+ "TARGET_BUILD_UNBUNDLED",
// compiler wrappers set up by make
"CC_WRAPPER",
@@ -230,8 +230,6 @@
"DEFAULT_ERROR_BUILD_MODULE_TYPES",
"BUILD_BROKEN_PREBUILT_ELF_FILES",
"BUILD_BROKEN_TREBLE_SYSPROP_NEVERALLOW",
- "BUILD_BROKEN_USES_BUILD_AUX_EXECUTABLE",
- "BUILD_BROKEN_USES_BUILD_AUX_STATIC_LIBRARY",
"BUILD_BROKEN_USES_BUILD_COPY_HEADERS",
"BUILD_BROKEN_USES_BUILD_EXECUTABLE",
"BUILD_BROKEN_USES_BUILD_FUZZ_TEST",
@@ -239,17 +237,12 @@
"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_EXECUTABLE",
- "BUILD_BROKEN_USES_BUILD_HOST_FUZZ_TEST",
"BUILD_BROKEN_USES_BUILD_HOST_JAVA_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_NATIVE_TEST",
"BUILD_BROKEN_USES_BUILD_HOST_PREBUILT",
"BUILD_BROKEN_USES_BUILD_HOST_SHARED_LIBRARY",
"BUILD_BROKEN_USES_BUILD_HOST_STATIC_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_STATIC_TEST_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_HOST_TEST_CONFIG",
"BUILD_BROKEN_USES_BUILD_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_MULTI_PREBUILT",
- "BUILD_BROKEN_USES_BUILD_NATIVE_BENCHMARK",
"BUILD_BROKEN_USES_BUILD_NATIVE_TEST",
"BUILD_BROKEN_USES_BUILD_NOTICE_FILE",
"BUILD_BROKEN_USES_BUILD_PACKAGE",
@@ -259,8 +252,6 @@
"BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY",
"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_STATIC_TEST_LIBRARY",
- "BUILD_BROKEN_USES_BUILD_TARGET_TEST_CONFIG",
}, exportEnvVars...), BannerVars...)
make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
@@ -288,7 +279,6 @@
config.SetTargetDevice(make_vars["TARGET_DEVICE"])
config.SetTargetDeviceDir(make_vars["TARGET_DEVICE_DIR"])
- config.SetPdkBuild(make_vars["TARGET_BUILD_PDK"] == "true")
config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true")
config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true")
config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(make_vars["BUILD_BROKEN_NINJA_USES_ENV_VARS"]))
diff --git a/ui/build/exec.go b/ui/build/exec.go
index e435c53..053bbae 100644
--- a/ui/build/exec.go
+++ b/ui/build/exec.go
@@ -19,6 +19,8 @@
"io"
"os/exec"
"strings"
+ "syscall"
+ "time"
)
// Cmd is a wrapper of os/exec.Cmd that integrates with the build context for
@@ -33,6 +35,8 @@
ctx Context
config Config
name string
+
+ started time.Time
}
func Command(ctx Context, config Config, name string, executable string, args ...string) *Cmd {
@@ -57,7 +61,20 @@
c.wrapSandbox()
}
- c.ctx.Verboseln(c.Path, c.Args)
+ c.ctx.Verbosef("%q executing %q %v\n", c.name, c.Path, c.Args)
+ c.started = time.Now()
+}
+
+func (c *Cmd) report() {
+ if c.Cmd.ProcessState != nil {
+ rusage := c.Cmd.ProcessState.SysUsage().(*syscall.Rusage)
+ c.ctx.Verbosef("%q finished with exit code %d (%s real, %s user, %s system, %dMB maxrss)",
+ c.name, c.Cmd.ProcessState.ExitCode(),
+ time.Since(c.started).Round(time.Millisecond),
+ c.Cmd.ProcessState.UserTime().Round(time.Millisecond),
+ c.Cmd.ProcessState.SystemTime().Round(time.Millisecond),
+ rusage.Maxrss/1024)
+ }
}
func (c *Cmd) Start() error {
@@ -68,21 +85,30 @@
func (c *Cmd) Run() error {
c.prepare()
err := c.Cmd.Run()
+ c.report()
return err
}
func (c *Cmd) Output() ([]byte, error) {
c.prepare()
bytes, err := c.Cmd.Output()
+ c.report()
return bytes, err
}
func (c *Cmd) CombinedOutput() ([]byte, error) {
c.prepare()
bytes, err := c.Cmd.CombinedOutput()
+ c.report()
return bytes, err
}
+func (c *Cmd) Wait() error {
+ err := c.Cmd.Wait()
+ c.report()
+ return err
+}
+
// StartOrFatal is equivalent to Start, but handles the error with a call to ctx.Fatal
func (c *Cmd) StartOrFatal() {
if err := c.Start(); err != nil {
diff --git a/ui/build/finder.go b/ui/build/finder.go
index 0f34b5e..c019ea2 100644
--- a/ui/build/finder.go
+++ b/ui/build/finder.go
@@ -86,7 +86,7 @@
os.MkdirAll(dumpDir, 0777)
androidMks := f.FindFirstNamedAt(".", "Android.mk")
- err := dumpListToFile(androidMks, filepath.Join(dumpDir, "Android.mk.list"))
+ err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
}
@@ -94,25 +94,25 @@
androidProductsMks := f.FindNamedAt("device", "AndroidProducts.mk")
androidProductsMks = append(androidProductsMks, f.FindNamedAt("vendor", "AndroidProducts.mk")...)
androidProductsMks = append(androidProductsMks, f.FindNamedAt("product", "AndroidProducts.mk")...)
- err = dumpListToFile(androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list"))
+ err = dumpListToFile(ctx, config, androidProductsMks, filepath.Join(dumpDir, "AndroidProducts.mk.list"))
if err != nil {
ctx.Fatalf("Could not export product list: %v", err)
}
cleanSpecs := f.FindFirstNamedAt(".", "CleanSpec.mk")
- err = dumpListToFile(cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
+ err = dumpListToFile(ctx, config, cleanSpecs, filepath.Join(dumpDir, "CleanSpec.mk.list"))
if err != nil {
ctx.Fatalf("Could not export module list: %v", err)
}
owners := f.FindNamedAt(".", "OWNERS")
- err = dumpListToFile(owners, filepath.Join(dumpDir, "OWNERS.list"))
+ err = dumpListToFile(ctx, config, owners, filepath.Join(dumpDir, "OWNERS.list"))
if err != nil {
ctx.Fatalf("Could not find OWNERS: %v", err)
}
testMappings := f.FindNamedAt(".", "TEST_MAPPING")
- err = dumpListToFile(testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
+ err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list"))
if err != nil {
ctx.Fatalf("Could not find TEST_MAPPING: %v", err)
}
@@ -122,18 +122,29 @@
if len(androidBps) == 0 {
ctx.Fatalf("No Android.bp found")
}
- err = dumpListToFile(androidBps, filepath.Join(dumpDir, "Android.bp.list"))
+ err = dumpListToFile(ctx, config, androidBps, filepath.Join(dumpDir, "Android.bp.list"))
if err != nil {
ctx.Fatalf("Could not find modules: %v", err)
}
+
+ if config.Dist() {
+ f.WaitForDbDump()
+ distFile(ctx, config, f.DbPath, "module_paths")
+ }
}
-func dumpListToFile(list []string, filePath string) (err error) {
+func dumpListToFile(ctx Context, config Config, list []string, filePath string) (err error) {
desiredText := strings.Join(list, "\n")
desiredBytes := []byte(desiredText)
actualBytes, readErr := ioutil.ReadFile(filePath)
if readErr != nil || !bytes.Equal(desiredBytes, actualBytes) {
err = ioutil.WriteFile(filePath, desiredBytes, 0777)
+ if err != nil {
+ return err
+ }
}
- return err
+
+ distFile(ctx, config, filePath, "module_paths")
+
+ return nil
}
diff --git a/ui/build/kati.go b/ui/build/kati.go
index a845c5b..f6d3a57 100644
--- a/ui/build/kati.go
+++ b/ui/build/kati.go
@@ -67,6 +67,7 @@
"--ninja_dir=" + config.OutDir(),
"--ninja_suffix=" + config.KatiSuffix() + extraSuffix,
"--no_ninja_prelude",
+ "--use_ninja_phony_output",
"--regen",
"--ignore_optional_include=" + filepath.Join(config.OutDir(), "%.P"),
"--detect_android_echo",
@@ -104,17 +105,20 @@
envFunc(cmd.Environment)
if _, ok := cmd.Environment.Get("BUILD_USERNAME"); !ok {
- u, err := user.Current()
- if err != nil {
- ctx.Println("Failed to get current user")
+ username := "unknown"
+ if u, err := user.Current(); err == nil {
+ username = u.Username
+ } else {
+ ctx.Println("Failed to get current user:", err)
}
- cmd.Environment.Set("BUILD_USERNAME", u.Username)
+ cmd.Environment.Set("BUILD_USERNAME", username)
}
if _, ok := cmd.Environment.Get("BUILD_HOSTNAME"); !ok {
hostname, err := os.Hostname()
if err != nil {
- ctx.Println("Failed to read hostname")
+ ctx.Println("Failed to read hostname:", err)
+ hostname = "unknown"
}
cmd.Environment.Set("BUILD_HOSTNAME", hostname)
}
@@ -130,14 +134,10 @@
args := []string{
"--writable", config.OutDir() + "/",
+ "--werror_implicit_rules",
"-f", "build/make/core/main.mk",
}
- // PDK builds still uses a few implicit rules
- if !config.IsPdkBuild() {
- args = append(args, "--werror_implicit_rules")
- }
-
if !config.BuildBrokenDupRules() {
args = append(args, "--werror_overriding_commands")
}
@@ -152,6 +152,8 @@
runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {})
+ distGzipFile(ctx, config, config.KatiBuildNinjaFile())
+
cleanCopyHeaders(ctx, config)
cleanOldInstalledFiles(ctx, config)
}
@@ -247,6 +249,8 @@
env.Set("DIST_DIR", config.DistDir())
}
})
+
+ distGzipFile(ctx, config, config.KatiPackageNinjaFile())
}
func runKatiCleanSpec(ctx Context, config Config) {
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index dfc3be1..fa44cb1 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -39,6 +39,7 @@
args := []string{
"-d", "keepdepfile",
"-d", "keeprsp",
+ "-d", "stats",
"--frontend_file", fifo,
}
@@ -58,6 +59,7 @@
args = append(args, "-f", config.CombinedNinjaFile())
args = append(args,
+ "-o", "usesphonyoutputs=yes",
"-w", "dupbuild=err",
"-w", "missingdepfile=err")
diff --git a/ui/build/path.go b/ui/build/path.go
index f515775..6f5cf78 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -181,9 +181,12 @@
execs = append(execs, parsePathDir(pathEntry)...)
}
- allowAllSymlinks := config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS")
+ if config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS") {
+ ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.")
+ }
+
for _, name := range execs {
- if !paths.GetConfig(name).Symlink && !allowAllSymlinks {
+ if !paths.GetConfig(name).Symlink {
continue
}
diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go
index 5717401..81c500d 100644
--- a/ui/build/paths/config.go
+++ b/ui/build/paths/config.go
@@ -88,7 +88,6 @@
"javap": Allowed,
"lsof": Allowed,
"openssl": Allowed,
- "patch": Allowed,
"pstree": Allowed,
"rsync": Allowed,
"sh": Allowed,
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 67bcebb..c4b829d 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -19,6 +19,7 @@
"math/rand"
"os"
"path/filepath"
+ "syscall"
"time"
"android/soong/ui/metrics"
@@ -50,8 +51,25 @@
return cmdPath
}
-func getRBEVars(ctx Context, config Config) map[string]string {
+func sockAddr(dir string) (string, error) {
+ maxNameLen := len(syscall.RawSockaddrUnix{}.Path)
rand.Seed(time.Now().UnixNano())
+ base := fmt.Sprintf("reproxy_%v.sock", rand.Intn(1000))
+
+ name := filepath.Join(dir, base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ name = filepath.Join("/tmp", base)
+ if len(name) < maxNameLen {
+ return name, nil
+ }
+
+ return "", fmt.Errorf("cannot generate a proxy socket address shorter than the limit of %v", maxNameLen)
+}
+
+func getRBEVars(ctx Context, config Config) map[string]string {
vars := map[string]string{
"RBE_log_path": config.rbeLogPath(),
"RBE_log_dir": config.logDir(),
@@ -60,7 +78,12 @@
"RBE_output_dir": config.rbeStatsOutputDir(),
}
if config.StartRBE() {
- vars["RBE_server_address"] = fmt.Sprintf("unix://%v/reproxy_%v.sock", absPath(ctx, config.TempDir()), rand.Intn(1000))
+ name, err := sockAddr(absPath(ctx, config.TempDir()))
+ if err != nil {
+ ctx.Fatalf("Error retrieving socket address: %v", err)
+ return nil
+ }
+ vars["RBE_server_address"] = fmt.Sprintf("unix://%v", name)
}
k, v := config.rbeAuth()
vars[k] = v
diff --git a/ui/build/rbe_test.go b/ui/build/rbe_test.go
index c56a33c..8ff96bc 100644
--- a/ui/build/rbe_test.go
+++ b/ui/build/rbe_test.go
@@ -46,11 +46,7 @@
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
- tmpDir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatalf("failed to create a temp directory: %v", err)
- }
- defer os.RemoveAll(tmpDir)
+ tmpDir := t.TempDir()
rbeBootstrapCmd := filepath.Join(tmpDir, bootstrapCmd)
if err := ioutil.WriteFile(rbeBootstrapCmd, []byte(rbeBootstrapProgram), 0755); err != nil {
@@ -60,14 +56,7 @@
env := Environment(tt.env)
env.Set("OUT_DIR", tmpDir)
env.Set("RBE_DIR", tmpDir)
-
- tmpRBEDir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatalf("failed to create a temp directory for RBE: %v", err)
- }
- defer os.RemoveAll(tmpRBEDir)
- env.Set("RBE_output_dir", tmpRBEDir)
-
+ env.Set("RBE_output_dir", t.TempDir())
config := Config{&configImpl{
environ: &env,
}}
@@ -112,11 +101,7 @@
}
})
- tmpDir, err := ioutil.TempDir("", "")
- if err != nil {
- t.Fatalf("failed to create a temp directory: %v", err)
- }
- defer os.RemoveAll(tmpDir)
+ tmpDir := t.TempDir()
rbeBootstrapCmd := filepath.Join(tmpDir, bootstrapCmd)
if err := ioutil.WriteFile(rbeBootstrapCmd, []byte(tt.bootstrapProgram), 0755); err != nil {
diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go
index 2de772b..dab0e75 100644
--- a/ui/build/sandbox_linux.go
+++ b/ui/build/sandbox_linux.go
@@ -19,6 +19,7 @@
"os"
"os/exec"
"os/user"
+ "path/filepath"
"strings"
"sync"
)
@@ -54,6 +55,9 @@
working bool
group string
+ srcDir string
+ outDir string
+ distDir string
}
func (c *Cmd) sandboxSupported() bool {
@@ -72,15 +76,45 @@
sandboxConfig.group = "nobody"
}
- cmd := exec.CommandContext(c.ctx.Context, nsjailPath,
+ // These directories will be bind mounted
+ // so we need full non-symlink paths
+ sandboxConfig.srcDir = absPath(c.ctx, ".")
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.srcDir); err == nil {
+ sandboxConfig.srcDir = absPath(c.ctx, derefPath)
+ }
+ sandboxConfig.outDir = absPath(c.ctx, c.config.OutDir())
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.outDir); err == nil {
+ sandboxConfig.outDir = absPath(c.ctx, derefPath)
+ }
+ sandboxConfig.distDir = absPath(c.ctx, c.config.DistDir())
+ if derefPath, err := filepath.EvalSymlinks(sandboxConfig.distDir); err == nil {
+ sandboxConfig.distDir = absPath(c.ctx, derefPath)
+ }
+
+ sandboxArgs := []string{
"-H", "android-build",
"-e",
"-u", "nobody",
"-g", sandboxConfig.group,
- "-B", "/",
+ "-R", "/",
+ "-B", sandboxConfig.srcDir,
+ "-B", "/tmp",
+ "-B", sandboxConfig.outDir,
+ }
+
+ if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+ //Mount dist dir as read-write if it already exists
+ sandboxArgs = append(sandboxArgs, "-B",
+ sandboxConfig.distDir)
+ }
+
+ sandboxArgs = append(sandboxArgs,
"--disable_clone_newcgroup",
"--",
"/bin/bash", "-c", `if [ $(hostname) == "android-build" ]; then echo "Android" "Success"; else echo Failure; fi`)
+
+ cmd := exec.CommandContext(c.ctx.Context, nsjailPath, sandboxArgs...)
+
cmd.Env = c.config.Environment().Environ()
c.ctx.Verboseln(cmd.Args)
@@ -144,8 +178,17 @@
"--rlimit_fsize", "soft",
"--rlimit_nofile", "soft",
- // For now, just map everything. Eventually we should limit this, especially to make most things readonly.
- "-B", "/",
+ // For now, just map everything. Make most things readonly.
+ "-R", "/",
+
+ // Mount a writable tmp dir
+ "-B", "/tmp",
+
+ // Mount source are read-write
+ "-B", sandboxConfig.srcDir,
+
+ //Mount out dir as read-write
+ "-B", sandboxConfig.outDir,
// Disable newcgroup for now, since it may require newer kernels
// TODO: try out cgroups
@@ -155,6 +198,11 @@
"-q",
}
+ if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) {
+ //Mount dist dir as read-write if it already exists
+ sandboxArgs = append(sandboxArgs, "-B", sandboxConfig.distDir)
+ }
+
if c.Sandbox.AllowBuildBrokenUsesNetwork && c.config.BuildBrokenUsesNetwork() {
c.ctx.Printf("AllowBuildBrokenUsesNetwork: %v", c.Sandbox.AllowBuildBrokenUsesNetwork)
c.ctx.Printf("BuildBrokenUsesNetwork: %v", c.config.BuildBrokenUsesNetwork())
diff --git a/ui/build/soong.go b/ui/build/soong.go
index afbc073..fb21430 100644
--- a/ui/build/soong.go
+++ b/ui/build/soong.go
@@ -15,11 +15,15 @@
package build
import (
+ "io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
+ soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
+
+ "github.com/golang/protobuf/proto"
"github.com/google/blueprint/microfactory"
"android/soong/ui/metrics"
@@ -34,7 +38,7 @@
ctx.BeginTrace(metrics.RunSoong, "blueprint bootstrap")
defer ctx.EndTrace()
- cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", "-t")
+ cmd := Command(ctx, config, "blueprint bootstrap", "build/blueprint/bootstrap.bash", "-t", "-n")
cmd.Environment.Set("BLUEPRINTDIR", "./build/blueprint")
cmd.Environment.Set("BOOTSTRAP", "./build/blueprint/bootstrap.bash")
cmd.Environment.Set("BUILDDIR", config.SoongOutDir())
@@ -115,7 +119,12 @@
cmd := Command(ctx, config, "soong "+name,
config.PrebuiltBuildTool("ninja"),
"-d", "keepdepfile",
+ "-d", "stats",
+ "-o", "usesphonyoutputs=yes",
+ "-o", "preremoveoutputs=yes",
"-w", "dupbuild=err",
+ "-w", "outputdir=err",
+ "-w", "missingoutfile=err",
"-j", strconv.Itoa(config.Parallel()),
"--frontend_file", fifo,
"-f", filepath.Join(config.SoongOutDir(), file))
@@ -126,4 +135,42 @@
ninja("minibootstrap", ".minibootstrap/build.ninja")
ninja("bootstrap", ".bootstrap/build.ninja")
+
+ soongBuildMetrics := loadSoongBuildMetrics(ctx, config)
+ logSoongBuildMetrics(ctx, soongBuildMetrics)
+
+ distGzipFile(ctx, config, config.SoongNinjaFile(), "soong")
+
+ if !config.SkipMake() {
+ distGzipFile(ctx, config, config.SoongAndroidMk(), "soong")
+ distGzipFile(ctx, config, config.SoongMakeVarsMk(), "soong")
+ }
+
+ if ctx.Metrics != nil {
+ ctx.Metrics.SetSoongBuildMetrics(soongBuildMetrics)
+ }
+}
+
+func loadSoongBuildMetrics(ctx Context, config Config) *soong_metrics_proto.SoongBuildMetrics {
+ soongBuildMetricsFile := filepath.Join(config.OutDir(), "soong", "soong_build_metrics.pb")
+ buf, err := ioutil.ReadFile(soongBuildMetricsFile)
+ if err != nil {
+ ctx.Fatalf("Failed to load %s: %s", soongBuildMetricsFile, err)
+ }
+ soongBuildMetrics := &soong_metrics_proto.SoongBuildMetrics{}
+ err = proto.Unmarshal(buf, soongBuildMetrics)
+ if err != nil {
+ ctx.Fatalf("Failed to unmarshal %s: %s", soongBuildMetricsFile, err)
+ }
+ return soongBuildMetrics
+}
+
+func logSoongBuildMetrics(ctx Context, metrics *soong_metrics_proto.SoongBuildMetrics) {
+ ctx.Verbosef("soong_build metrics:")
+ ctx.Verbosef(" modules: %v", metrics.GetModules())
+ ctx.Verbosef(" variants: %v", metrics.GetVariants())
+ ctx.Verbosef(" max heap size: %v MB", metrics.GetMaxHeapSize()/1e6)
+ ctx.Verbosef(" total allocation count: %v", metrics.GetTotalAllocCount())
+ ctx.Verbosef(" total allocation size: %v MB", metrics.GetTotalAllocSize()/1e6)
+
}
diff --git a/ui/build/test_build.go b/ui/build/test_build.go
index 5109465..83b3807 100644
--- a/ui/build/test_build.go
+++ b/ui/build/test_build.go
@@ -50,10 +50,10 @@
// Get a list of leaf nodes in the dependency graph from ninja
executable := config.PrebuiltBuildTool("ninja")
- args := []string{}
- args = append(args, config.NinjaArgs()...)
- args = append(args, "-f", config.CombinedNinjaFile())
- args = append(args, "-t", "targets", "rule")
+ common_args := []string{}
+ common_args = append(common_args, config.NinjaArgs()...)
+ common_args = append(common_args, "-f", config.CombinedNinjaFile())
+ args := append(common_args, "-t", "targets", "rule")
cmd := Command(ctx, config, "ninja", executable, args...)
stdout, err := cmd.StdoutPipe()
@@ -66,6 +66,8 @@
outDir := config.OutDir()
bootstrapDir := filepath.Join(outDir, "soong", ".bootstrap")
miniBootstrapDir := filepath.Join(outDir, "soong", ".minibootstrap")
+ modulePathsDir := filepath.Join(outDir, ".module_paths")
+ variablesFilePath := filepath.Join(outDir, "soong", "soong.variables")
danglingRules := make(map[string]bool)
@@ -76,7 +78,10 @@
// Leaf node is not in the out directory.
continue
}
- if strings.HasPrefix(line, bootstrapDir) || strings.HasPrefix(line, miniBootstrapDir) {
+ if strings.HasPrefix(line, bootstrapDir) ||
+ strings.HasPrefix(line, miniBootstrapDir) ||
+ strings.HasPrefix(line, modulePathsDir) ||
+ line == variablesFilePath {
// Leaf node is in one of Soong's bootstrap directories, which do not have
// full build rules in the primary build.ninja file.
continue
@@ -96,9 +101,31 @@
sb := &strings.Builder{}
title := "Dependencies in out found with no rule to create them:"
fmt.Fprintln(sb, title)
- for _, dep := range danglingRulesList {
- fmt.Fprintln(sb, " ", dep)
+
+ report_lines := 1
+ for i, dep := range danglingRulesList {
+ if report_lines > 20 {
+ fmt.Fprintf(sb, " ... and %d more\n", len(danglingRulesList)-i)
+ break
+ }
+ // It's helpful to see the reverse dependencies. ninja -t query is the
+ // best tool we got for that. Its output starts with the dependency
+ // itself.
+ query_cmd := Command(ctx, config, "ninja", executable,
+ append(common_args, "-t", "query", dep)...)
+ query_stdout, err := query_cmd.StdoutPipe()
+ if err != nil {
+ ctx.Fatal(err)
+ }
+ query_cmd.StartOrFatal()
+ scanner := bufio.NewScanner(query_stdout)
+ for scanner.Scan() {
+ report_lines++
+ fmt.Fprintln(sb, " ", scanner.Text())
+ }
+ query_cmd.WaitOrFatal()
}
+
ts.FinishAction(status.ActionResult{
Action: action,
Error: fmt.Errorf(title),
diff --git a/ui/build/upload.go b/ui/build/upload.go
index 1cc2e94..a9346e0 100644
--- a/ui/build/upload.go
+++ b/ui/build/upload.go
@@ -44,7 +44,7 @@
// environment variable. The metrics files are copied to a temporary directory
// and the uploader is then executed in the background to allow the user to continue
// working.
-func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStarted time.Time, files ...string) {
+func UploadMetrics(ctx Context, config Config, simpleOutput bool, buildStarted time.Time, files ...string) {
ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
defer ctx.EndTrace()
@@ -105,7 +105,7 @@
// Start the uploader in the background as it takes several milliseconds to start the uploader
// and prepare the metrics for upload. This affects small commands like "lunch".
cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
- if forceDumbOutput {
+ if simpleOutput {
cmd.RunOrFatal()
} else {
cmd.RunAndStreamOrFatal()
diff --git a/ui/build/util.go b/ui/build/util.go
index d44cd6d..d4c3431 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -15,6 +15,8 @@
package build
import (
+ "compress/gzip"
+ "fmt"
"io"
"os"
"path/filepath"
@@ -142,3 +144,29 @@
return io.Copy(destination, source)
}
+
+// gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz".
+func gzipFileToDir(src, destDir string) error {
+ in, err := os.Open(src)
+ if err != nil {
+ return fmt.Errorf("failed to open %s: %s", src, err.Error())
+ }
+ defer in.Close()
+
+ dest := filepath.Join(destDir, filepath.Base(src)+".gz")
+
+ out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666)
+ if err != nil {
+ return fmt.Errorf("failed to open %s: %s", dest, err.Error())
+ }
+ defer out.Close()
+ gz := gzip.NewWriter(out)
+ defer gz.Close()
+
+ _, err = io.Copy(gz, in)
+ if err != nil {
+ return fmt.Errorf("failed to gzip %s: %s", dest, err.Error())
+ }
+
+ return nil
+}
diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go
index 65cae4a..f5552a3 100644
--- a/ui/metrics/metrics.go
+++ b/ui/metrics/metrics.go
@@ -144,6 +144,10 @@
return writeMessageToFile(&m.metrics, outputPath)
}
+func (m *Metrics) SetSoongBuildMetrics(metrics *soong_metrics_proto.SoongBuildMetrics) {
+ m.metrics.SoongBuildMetrics = metrics
+}
+
type CriticalUserJourneysMetrics struct {
cujs soong_metrics_proto.CriticalUserJourneysMetrics
}
diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go
index aaa8587..d7c53ec 100644
--- a/ui/metrics/metrics_proto/metrics.pb.go
+++ b/ui/metrics/metrics_proto/metrics.pb.go
@@ -197,11 +197,12 @@
// The metrics for calling Ninja.
NinjaRuns []*PerfInfo `protobuf:"bytes,20,rep,name=ninja_runs,json=ninjaRuns" json:"ninja_runs,omitempty"`
// The metrics for the whole build
- Total *PerfInfo `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
- BuildConfig *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
- XXX_NoUnkeyedLiteral struct{} `json:"-"`
- XXX_unrecognized []byte `json:"-"`
- XXX_sizecache int32 `json:"-"`
+ Total *PerfInfo `protobuf:"bytes,21,opt,name=total" json:"total,omitempty"`
+ SoongBuildMetrics *SoongBuildMetrics `protobuf:"bytes,22,opt,name=soong_build_metrics,json=soongBuildMetrics" json:"soong_build_metrics,omitempty"`
+ BuildConfig *BuildConfig `protobuf:"bytes,23,opt,name=build_config,json=buildConfig" json:"build_config,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
}
func (m *MetricsBase) Reset() { *m = MetricsBase{} }
@@ -381,6 +382,13 @@
return nil
}
+func (m *MetricsBase) GetSoongBuildMetrics() *SoongBuildMetrics {
+ if m != nil {
+ return m.SoongBuildMetrics
+ }
+ return nil
+}
+
func (m *MetricsBase) GetBuildConfig() *BuildConfig {
if m != nil {
return m.BuildConfig
@@ -662,6 +670,82 @@
return nil
}
+type SoongBuildMetrics struct {
+ // The number of modules handled by soong_build.
+ Modules *uint32 `protobuf:"varint,1,opt,name=modules" json:"modules,omitempty"`
+ // The total number of variants handled by soong_build.
+ Variants *uint32 `protobuf:"varint,2,opt,name=variants" json:"variants,omitempty"`
+ // The total number of allocations in soong_build.
+ TotalAllocCount *uint64 `protobuf:"varint,3,opt,name=total_alloc_count,json=totalAllocCount" json:"total_alloc_count,omitempty"`
+ // The total size of allocations in soong_build in bytes.
+ TotalAllocSize *uint64 `protobuf:"varint,4,opt,name=total_alloc_size,json=totalAllocSize" json:"total_alloc_size,omitempty"`
+ // The approximate maximum size of the heap in soong_build in bytes.
+ MaxHeapSize *uint64 `protobuf:"varint,5,opt,name=max_heap_size,json=maxHeapSize" json:"max_heap_size,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *SoongBuildMetrics) Reset() { *m = SoongBuildMetrics{} }
+func (m *SoongBuildMetrics) String() string { return proto.CompactTextString(m) }
+func (*SoongBuildMetrics) ProtoMessage() {}
+func (*SoongBuildMetrics) Descriptor() ([]byte, []int) {
+ return fileDescriptor_6039342a2ba47b72, []int{6}
+}
+
+func (m *SoongBuildMetrics) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_SoongBuildMetrics.Unmarshal(m, b)
+}
+func (m *SoongBuildMetrics) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_SoongBuildMetrics.Marshal(b, m, deterministic)
+}
+func (m *SoongBuildMetrics) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_SoongBuildMetrics.Merge(m, src)
+}
+func (m *SoongBuildMetrics) XXX_Size() int {
+ return xxx_messageInfo_SoongBuildMetrics.Size(m)
+}
+func (m *SoongBuildMetrics) XXX_DiscardUnknown() {
+ xxx_messageInfo_SoongBuildMetrics.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_SoongBuildMetrics proto.InternalMessageInfo
+
+func (m *SoongBuildMetrics) GetModules() uint32 {
+ if m != nil && m.Modules != nil {
+ return *m.Modules
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetVariants() uint32 {
+ if m != nil && m.Variants != nil {
+ return *m.Variants
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetTotalAllocCount() uint64 {
+ if m != nil && m.TotalAllocCount != nil {
+ return *m.TotalAllocCount
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetTotalAllocSize() uint64 {
+ if m != nil && m.TotalAllocSize != nil {
+ return *m.TotalAllocSize
+ }
+ return 0
+}
+
+func (m *SoongBuildMetrics) GetMaxHeapSize() uint64 {
+ if m != nil && m.MaxHeapSize != nil {
+ return *m.MaxHeapSize
+ }
+ return 0
+}
+
func init() {
proto.RegisterEnum("soong_build_metrics.MetricsBase_BuildVariant", MetricsBase_BuildVariant_name, MetricsBase_BuildVariant_value)
proto.RegisterEnum("soong_build_metrics.MetricsBase_Arch", MetricsBase_Arch_name, MetricsBase_Arch_value)
@@ -672,67 +756,77 @@
proto.RegisterType((*ModuleTypeInfo)(nil), "soong_build_metrics.ModuleTypeInfo")
proto.RegisterType((*CriticalUserJourneyMetrics)(nil), "soong_build_metrics.CriticalUserJourneyMetrics")
proto.RegisterType((*CriticalUserJourneysMetrics)(nil), "soong_build_metrics.CriticalUserJourneysMetrics")
+ proto.RegisterType((*SoongBuildMetrics)(nil), "soong_build_metrics.SoongBuildMetrics")
}
-func init() { proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72) }
+func init() {
+ proto.RegisterFile("metrics.proto", fileDescriptor_6039342a2ba47b72)
+}
var fileDescriptor_6039342a2ba47b72 = []byte{
- // 910 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x55, 0xdf, 0x6e, 0xdb, 0x36,
- 0x17, 0xaf, 0x12, 0x25, 0x96, 0x8e, 0x62, 0x57, 0x65, 0x52, 0x44, 0xfd, 0x8a, 0xe0, 0x33, 0x84,
- 0x75, 0xc8, 0xc5, 0x9a, 0x16, 0x59, 0x11, 0x14, 0x41, 0x31, 0xc0, 0x71, 0x8c, 0xa0, 0x0b, 0x6c,
- 0x17, 0x4c, 0xdc, 0x15, 0xdb, 0x85, 0x20, 0x4b, 0x74, 0xa2, 0xce, 0x12, 0x0d, 0x92, 0x2a, 0xe6,
- 0x87, 0xd8, 0x6b, 0xec, 0xcd, 0xf6, 0x1e, 0x03, 0x0f, 0x25, 0x47, 0x01, 0x5c, 0x34, 0xe8, 0x9d,
- 0x74, 0x7e, 0x7f, 0xf8, 0x3b, 0xa4, 0x78, 0x04, 0xed, 0x9c, 0x29, 0x91, 0x25, 0xf2, 0x68, 0x21,
- 0xb8, 0xe2, 0x64, 0x57, 0x72, 0x5e, 0xdc, 0x44, 0xd3, 0x32, 0x9b, 0xa7, 0x51, 0x05, 0x85, 0xff,
- 0x00, 0x78, 0x43, 0xf3, 0x7c, 0x16, 0x4b, 0x46, 0x5e, 0xc3, 0x9e, 0x21, 0xa4, 0xb1, 0x62, 0x91,
- 0xca, 0x72, 0x26, 0x55, 0x9c, 0x2f, 0x02, 0xab, 0x6b, 0x1d, 0x6e, 0x52, 0x82, 0xd8, 0x79, 0xac,
- 0xd8, 0x75, 0x8d, 0x90, 0x67, 0xe0, 0x18, 0x45, 0x96, 0x06, 0x1b, 0x5d, 0xeb, 0xd0, 0xa5, 0x2d,
- 0x7c, 0x7f, 0x9f, 0x92, 0x53, 0x78, 0xb6, 0x98, 0xc7, 0x6a, 0xc6, 0x45, 0x1e, 0x7d, 0x61, 0x42,
- 0x66, 0xbc, 0x88, 0x12, 0x9e, 0xb2, 0x22, 0xce, 0x59, 0xb0, 0x89, 0xdc, 0xfd, 0x9a, 0xf0, 0xd1,
- 0xe0, 0xfd, 0x0a, 0x26, 0x2f, 0xa0, 0xa3, 0x62, 0x71, 0xc3, 0x54, 0xb4, 0x10, 0x3c, 0x2d, 0x13,
- 0x15, 0xd8, 0x28, 0x68, 0x9b, 0xea, 0x07, 0x53, 0x24, 0x29, 0xec, 0x55, 0x34, 0x13, 0xe2, 0x4b,
- 0x2c, 0xb2, 0xb8, 0x50, 0xc1, 0x56, 0xd7, 0x3a, 0xec, 0x1c, 0xbf, 0x3c, 0x5a, 0xd3, 0xf3, 0x51,
- 0xa3, 0xdf, 0xa3, 0x33, 0x8d, 0x7c, 0x34, 0xa2, 0xd3, 0xcd, 0xc1, 0xe8, 0x82, 0x12, 0xe3, 0xd7,
- 0x04, 0xc8, 0x18, 0xbc, 0x6a, 0x95, 0x58, 0x24, 0xb7, 0xc1, 0x36, 0x9a, 0xbf, 0xf8, 0xa6, 0x79,
- 0x4f, 0x24, 0xb7, 0xa7, 0xad, 0xc9, 0xe8, 0x72, 0x34, 0xfe, 0x6d, 0x44, 0xc1, 0x58, 0xe8, 0x22,
- 0x39, 0x82, 0xdd, 0x86, 0xe1, 0x2a, 0x75, 0x0b, 0x5b, 0x7c, 0x72, 0x47, 0xac, 0x03, 0xfc, 0x04,
- 0x55, 0xac, 0x28, 0x59, 0x94, 0x2b, 0xba, 0x83, 0x74, 0xdf, 0x20, 0xfd, 0x45, 0x59, 0xb3, 0x2f,
- 0xc1, 0xbd, 0xe5, 0xb2, 0x0a, 0xeb, 0x7e, 0x57, 0x58, 0x47, 0x1b, 0x60, 0x54, 0x0a, 0x6d, 0x34,
- 0x3b, 0x2e, 0x52, 0x63, 0x08, 0xdf, 0x65, 0xe8, 0x69, 0x93, 0xe3, 0x22, 0x45, 0xcf, 0x7d, 0x68,
- 0xa1, 0x27, 0x97, 0x81, 0x87, 0x3d, 0x6c, 0xeb, 0xd7, 0xb1, 0x24, 0x61, 0xb5, 0x18, 0x97, 0x11,
- 0xfb, 0x4b, 0x89, 0x38, 0xd8, 0x41, 0xd8, 0x33, 0xf0, 0x40, 0x97, 0x56, 0x9c, 0x44, 0x70, 0x29,
- 0xb5, 0x45, 0xfb, 0x8e, 0xd3, 0xd7, 0xb5, 0xb1, 0x24, 0x3f, 0xc2, 0xe3, 0x06, 0x07, 0x63, 0x77,
- 0xcc, 0xe7, 0xb3, 0x62, 0x61, 0x90, 0x97, 0xb0, 0xdb, 0xe0, 0xad, 0x5a, 0x7c, 0x6c, 0x36, 0x76,
- 0xc5, 0x6d, 0xe4, 0xe6, 0xa5, 0x8a, 0xd2, 0x4c, 0x04, 0xbe, 0xc9, 0xcd, 0x4b, 0x75, 0x9e, 0x09,
- 0xf2, 0x0b, 0x78, 0x92, 0xa9, 0x72, 0x11, 0x29, 0xce, 0xe7, 0x32, 0x78, 0xd2, 0xdd, 0x3c, 0xf4,
- 0x8e, 0x0f, 0xd6, 0x6e, 0xd1, 0x07, 0x26, 0x66, 0xef, 0x8b, 0x19, 0xa7, 0x80, 0x8a, 0x6b, 0x2d,
- 0x20, 0xa7, 0xe0, 0xfe, 0x19, 0xab, 0x2c, 0x12, 0x65, 0x21, 0x03, 0xf2, 0x10, 0xb5, 0xa3, 0xf9,
- 0xb4, 0x2c, 0x24, 0x79, 0x07, 0x60, 0x98, 0x28, 0xde, 0x7d, 0x88, 0xd8, 0x45, 0xb4, 0x56, 0x17,
- 0x59, 0xf1, 0x39, 0x36, 0xea, 0xbd, 0x07, 0xa9, 0x51, 0x80, 0xea, 0x9f, 0x61, 0x4b, 0x71, 0x15,
- 0xcf, 0x83, 0xa7, 0x5d, 0xeb, 0xdb, 0x42, 0xc3, 0x25, 0x7d, 0xd8, 0x31, 0x84, 0x84, 0x17, 0xb3,
- 0xec, 0x26, 0xd8, 0x47, 0x6d, 0x77, 0xad, 0x16, 0xaf, 0x61, 0x1f, 0x79, 0xd4, 0x9b, 0xde, 0xbd,
- 0x84, 0xaf, 0x61, 0xe7, 0xde, 0x15, 0x75, 0xc0, 0x9e, 0x5c, 0x0d, 0xa8, 0xff, 0x88, 0xb4, 0xc1,
- 0xd5, 0x4f, 0xe7, 0x83, 0xb3, 0xc9, 0x85, 0x6f, 0x91, 0x16, 0xe8, 0x6b, 0xed, 0x6f, 0x84, 0xef,
- 0xc0, 0xc6, 0x43, 0xf4, 0xa0, 0xfe, 0x28, 0xfd, 0x47, 0x1a, 0xed, 0xd1, 0xa1, 0x6f, 0x11, 0x17,
- 0xb6, 0x7a, 0x74, 0x78, 0xf2, 0xc6, 0xdf, 0xd0, 0xb5, 0x4f, 0x6f, 0x4f, 0xfc, 0x4d, 0x02, 0xb0,
- 0xfd, 0xe9, 0xed, 0x49, 0x74, 0xf2, 0xc6, 0xb7, 0xc3, 0x1e, 0x78, 0x8d, 0x2c, 0x7a, 0xea, 0x95,
- 0x92, 0x45, 0x37, 0x3c, 0x8f, 0x71, 0x36, 0x3a, 0xb4, 0x55, 0x4a, 0x76, 0xc1, 0xf3, 0x58, 0x7f,
- 0x24, 0x1a, 0x12, 0x53, 0x86, 0xf3, 0xd0, 0xa1, 0xdb, 0xa5, 0x64, 0x74, 0xca, 0xc2, 0xbf, 0x2d,
- 0x70, 0xea, 0xbd, 0x20, 0x04, 0xec, 0x94, 0xc9, 0x04, 0xc5, 0x2e, 0xc5, 0x67, 0x5d, 0xc3, 0xd1,
- 0x68, 0xc6, 0x28, 0x3e, 0x93, 0x03, 0x00, 0xa9, 0x62, 0xa1, 0x70, 0x16, 0xe3, 0xd0, 0xb4, 0xa9,
- 0x8b, 0x15, 0x3d, 0x82, 0xc9, 0x73, 0x70, 0x05, 0x8b, 0xe7, 0x06, 0xb5, 0x11, 0x75, 0x74, 0x01,
- 0xc1, 0x03, 0x80, 0x9c, 0xe5, 0x5c, 0x2c, 0xa3, 0x52, 0x32, 0x1c, 0x89, 0x36, 0x75, 0x4d, 0x65,
- 0x22, 0x59, 0xf8, 0xaf, 0x05, 0x9d, 0x21, 0x4f, 0xcb, 0x39, 0xbb, 0x5e, 0x2e, 0x18, 0xa6, 0xfa,
- 0xa3, 0x3e, 0x1a, 0xb9, 0x94, 0x8a, 0xe5, 0x98, 0xae, 0x73, 0xfc, 0x6a, 0xfd, 0x5d, 0xbf, 0x27,
- 0x35, 0x27, 0x75, 0x85, 0xb2, 0xc6, 0xad, 0x9f, 0xde, 0x55, 0xc9, 0xff, 0xc1, 0xcb, 0x51, 0x13,
- 0xa9, 0xe5, 0xa2, 0xee, 0x12, 0xf2, 0x95, 0x0d, 0xf9, 0x01, 0x3a, 0x45, 0x99, 0x47, 0x7c, 0x16,
- 0x99, 0xa2, 0xc4, 0x7e, 0xdb, 0x74, 0xa7, 0x28, 0xf3, 0xf1, 0xcc, 0xac, 0x27, 0xc3, 0x57, 0xd5,
- 0x49, 0x54, 0xae, 0xf7, 0x8e, 0xd3, 0x85, 0xad, 0xab, 0xf1, 0x78, 0xa4, 0xcf, 0xdd, 0x01, 0x7b,
- 0xd8, 0xbb, 0x1c, 0xf8, 0x1b, 0xe1, 0x1c, 0xfe, 0xd7, 0x17, 0x99, 0xca, 0x92, 0x78, 0x3e, 0x91,
- 0x4c, 0xfc, 0xca, 0x4b, 0x51, 0xb0, 0x65, 0x35, 0xaa, 0x56, 0x9b, 0x6e, 0x35, 0x36, 0xfd, 0x14,
- 0x5a, 0x55, 0x97, 0x98, 0xf2, 0x6b, 0x1f, 0x67, 0x63, 0xda, 0xd1, 0x5a, 0x10, 0x4e, 0xe1, 0xf9,
- 0x9a, 0xd5, 0x64, 0xbd, 0x5c, 0x1f, 0xec, 0xa4, 0xfc, 0x2c, 0x03, 0x0b, 0x6f, 0xda, 0xfa, 0x9d,
- 0xfd, 0x7a, 0x5a, 0x8a, 0xe2, 0xb3, 0xa7, 0xbf, 0x57, 0x3f, 0xf3, 0x4a, 0x11, 0xe1, 0x1f, 0xfe,
- 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x51, 0x32, 0x87, 0x13, 0xf1, 0x07, 0x00, 0x00,
+ // 1021 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xef, 0x6e, 0xdb, 0x36,
+ 0x10, 0xaf, 0x12, 0x27, 0xb6, 0x4e, 0xb1, 0xab, 0x30, 0xed, 0xa2, 0xb6, 0x08, 0x66, 0x18, 0x6b,
+ 0x11, 0x0c, 0x6b, 0x5a, 0x64, 0x45, 0x50, 0x04, 0xc5, 0x00, 0xc7, 0x09, 0xb2, 0x2e, 0x48, 0x5c,
+ 0x30, 0x7f, 0x56, 0x6c, 0x1f, 0x04, 0x5a, 0xa2, 0x13, 0x75, 0x96, 0x28, 0x90, 0x54, 0x91, 0xf4,
+ 0x1d, 0xf6, 0x54, 0x7b, 0x96, 0xbd, 0xc6, 0x30, 0xf0, 0x28, 0xd9, 0xca, 0xe6, 0xad, 0x41, 0xbf,
+ 0x89, 0xf7, 0xfb, 0xc3, 0x3b, 0xf2, 0x78, 0x36, 0xb4, 0x53, 0xae, 0x65, 0x12, 0xa9, 0xad, 0x5c,
+ 0x0a, 0x2d, 0xc8, 0x9a, 0x12, 0x22, 0xbb, 0x0c, 0x47, 0x45, 0x32, 0x89, 0xc3, 0x12, 0xea, 0xfd,
+ 0x05, 0xe0, 0x1d, 0xdb, 0xef, 0x3d, 0xa6, 0x38, 0x79, 0x09, 0x0f, 0x2c, 0x21, 0x66, 0x9a, 0x87,
+ 0x3a, 0x49, 0xb9, 0xd2, 0x2c, 0xcd, 0x03, 0xa7, 0xeb, 0x6c, 0x2e, 0x52, 0x82, 0xd8, 0x3e, 0xd3,
+ 0xfc, 0xac, 0x42, 0xc8, 0x23, 0x68, 0x59, 0x45, 0x12, 0x07, 0x0b, 0x5d, 0x67, 0xd3, 0xa5, 0x4d,
+ 0x5c, 0xbf, 0x8d, 0xc9, 0x2e, 0x3c, 0xca, 0x27, 0x4c, 0x8f, 0x85, 0x4c, 0xc3, 0x8f, 0x5c, 0xaa,
+ 0x44, 0x64, 0x61, 0x24, 0x62, 0x9e, 0xb1, 0x94, 0x07, 0x8b, 0xc8, 0x5d, 0xaf, 0x08, 0x17, 0x16,
+ 0x1f, 0x94, 0x30, 0x79, 0x0a, 0x1d, 0xcd, 0xe4, 0x25, 0xd7, 0x61, 0x2e, 0x45, 0x5c, 0x44, 0x3a,
+ 0x68, 0xa0, 0xa0, 0x6d, 0xa3, 0xef, 0x6c, 0x90, 0xc4, 0xf0, 0xa0, 0xa4, 0xd9, 0x24, 0x3e, 0x32,
+ 0x99, 0xb0, 0x4c, 0x07, 0x4b, 0x5d, 0x67, 0xb3, 0xb3, 0xfd, 0x7c, 0x6b, 0x4e, 0xcd, 0x5b, 0xb5,
+ 0x7a, 0xb7, 0xf6, 0x0c, 0x72, 0x61, 0x45, 0xbb, 0x8b, 0x07, 0x27, 0x87, 0x94, 0x58, 0xbf, 0x3a,
+ 0x40, 0x86, 0xe0, 0x95, 0xbb, 0x30, 0x19, 0x5d, 0x05, 0xcb, 0x68, 0xfe, 0xf4, 0xb3, 0xe6, 0x7d,
+ 0x19, 0x5d, 0xed, 0x36, 0xcf, 0x4f, 0x8e, 0x4e, 0x86, 0x3f, 0x9f, 0x50, 0xb0, 0x16, 0x26, 0x48,
+ 0xb6, 0x60, 0xad, 0x66, 0x38, 0xcd, 0xba, 0x89, 0x25, 0xae, 0xce, 0x88, 0x55, 0x02, 0xdf, 0x41,
+ 0x99, 0x56, 0x18, 0xe5, 0xc5, 0x94, 0xde, 0x42, 0xba, 0x6f, 0x91, 0x41, 0x5e, 0x54, 0xec, 0x23,
+ 0x70, 0xaf, 0x84, 0x2a, 0x93, 0x75, 0xbf, 0x28, 0xd9, 0x96, 0x31, 0xc0, 0x54, 0x29, 0xb4, 0xd1,
+ 0x6c, 0x3b, 0x8b, 0xad, 0x21, 0x7c, 0x91, 0xa1, 0x67, 0x4c, 0xb6, 0xb3, 0x18, 0x3d, 0xd7, 0xa1,
+ 0x89, 0x9e, 0x42, 0x05, 0x1e, 0xd6, 0xb0, 0x6c, 0x96, 0x43, 0x45, 0x7a, 0xe5, 0x66, 0x42, 0x85,
+ 0xfc, 0x5a, 0x4b, 0x16, 0xac, 0x20, 0xec, 0x59, 0xf8, 0xc0, 0x84, 0xa6, 0x9c, 0x48, 0x0a, 0xa5,
+ 0x8c, 0x45, 0x7b, 0xc6, 0x19, 0x98, 0xd8, 0x50, 0x91, 0x67, 0x70, 0xbf, 0xc6, 0xc1, 0xb4, 0x3b,
+ 0xb6, 0x7d, 0xa6, 0x2c, 0x4c, 0xe4, 0x39, 0xac, 0xd5, 0x78, 0xd3, 0x12, 0xef, 0xdb, 0x83, 0x9d,
+ 0x72, 0x6b, 0x79, 0x8b, 0x42, 0x87, 0x71, 0x22, 0x03, 0xdf, 0xe6, 0x2d, 0x0a, 0xbd, 0x9f, 0x48,
+ 0xf2, 0x03, 0x78, 0x8a, 0xeb, 0x22, 0x0f, 0xb5, 0x10, 0x13, 0x15, 0xac, 0x76, 0x17, 0x37, 0xbd,
+ 0xed, 0x8d, 0xb9, 0x47, 0xf4, 0x8e, 0xcb, 0xf1, 0xdb, 0x6c, 0x2c, 0x28, 0xa0, 0xe2, 0xcc, 0x08,
+ 0xc8, 0x2e, 0xb8, 0xbf, 0x31, 0x9d, 0x84, 0xb2, 0xc8, 0x54, 0x40, 0xee, 0xa2, 0x6e, 0x19, 0x3e,
+ 0x2d, 0x32, 0x45, 0xde, 0x00, 0x58, 0x26, 0x8a, 0xd7, 0xee, 0x22, 0x76, 0x11, 0xad, 0xd4, 0x59,
+ 0x92, 0x7d, 0x60, 0x56, 0xfd, 0xe0, 0x4e, 0x6a, 0x14, 0xa0, 0xfa, 0x7b, 0x58, 0xd2, 0x42, 0xb3,
+ 0x49, 0xf0, 0xb0, 0xeb, 0x7c, 0x5e, 0x68, 0xb9, 0xe4, 0x02, 0xe6, 0x8d, 0xa2, 0xe0, 0x2b, 0xb4,
+ 0x78, 0x36, 0xd7, 0xe2, 0xd4, 0xc4, 0xf0, 0x49, 0x96, 0x1d, 0x46, 0x57, 0xd5, 0x3f, 0x43, 0x64,
+ 0x00, 0x2b, 0x56, 0x15, 0x89, 0x6c, 0x9c, 0x5c, 0x06, 0xeb, 0x68, 0xd8, 0x9d, 0x6b, 0x88, 0xc2,
+ 0x01, 0xf2, 0xa8, 0x37, 0x9a, 0x2d, 0x7a, 0x2f, 0x61, 0xe5, 0xd6, 0xd3, 0x6f, 0x41, 0xe3, 0xfc,
+ 0xf4, 0x80, 0xfa, 0xf7, 0x48, 0x1b, 0x5c, 0xf3, 0xb5, 0x7f, 0xb0, 0x77, 0x7e, 0xe8, 0x3b, 0xa4,
+ 0x09, 0x66, 0x5c, 0xf8, 0x0b, 0xbd, 0x37, 0xd0, 0xc0, 0xe6, 0xf0, 0xa0, 0x6a, 0x76, 0xff, 0x9e,
+ 0x41, 0xfb, 0xf4, 0xd8, 0x77, 0x88, 0x0b, 0x4b, 0x7d, 0x7a, 0xbc, 0xf3, 0xca, 0x5f, 0x30, 0xb1,
+ 0xf7, 0xaf, 0x77, 0xfc, 0x45, 0x02, 0xb0, 0xfc, 0xfe, 0xf5, 0x4e, 0xb8, 0xf3, 0xca, 0x6f, 0xf4,
+ 0xfa, 0xe0, 0xd5, 0x72, 0x31, 0xd3, 0xb4, 0x50, 0x3c, 0xbc, 0x14, 0x29, 0xc3, 0x99, 0xdb, 0xa2,
+ 0xcd, 0x42, 0xf1, 0x43, 0x91, 0x32, 0xd3, 0x7c, 0x06, 0x92, 0x23, 0x8e, 0x73, 0xb6, 0x45, 0x97,
+ 0x0b, 0xc5, 0xe9, 0x88, 0xf7, 0x7e, 0x77, 0xa0, 0x55, 0x9d, 0x31, 0x21, 0xd0, 0x88, 0xb9, 0x8a,
+ 0x50, 0xec, 0x52, 0xfc, 0x36, 0x31, 0x1c, 0xb9, 0x76, 0x3c, 0xe3, 0x37, 0xd9, 0x00, 0x50, 0x9a,
+ 0x49, 0x8d, 0x33, 0x1e, 0x87, 0x71, 0x83, 0xba, 0x18, 0x31, 0xa3, 0x9d, 0x3c, 0x01, 0x57, 0x72,
+ 0x36, 0xb1, 0x68, 0x03, 0xd1, 0x96, 0x09, 0x20, 0xb8, 0x01, 0x90, 0xf2, 0x54, 0xc8, 0x9b, 0xb0,
+ 0x50, 0x1c, 0x47, 0x6d, 0x83, 0xba, 0x36, 0x72, 0xae, 0x78, 0xef, 0x4f, 0x07, 0x3a, 0xc7, 0x22,
+ 0x2e, 0x26, 0xfc, 0xec, 0x26, 0xe7, 0x98, 0xd5, 0xaf, 0xd5, 0xd5, 0xa8, 0x1b, 0xa5, 0x79, 0x8a,
+ 0xd9, 0x75, 0xb6, 0x5f, 0xcc, 0x9f, 0x21, 0xb7, 0xa4, 0xf6, 0xa6, 0x4e, 0x51, 0x56, 0x9b, 0x26,
+ 0xa3, 0x59, 0x94, 0x7c, 0x0d, 0x5e, 0x8a, 0x9a, 0x50, 0xdf, 0xe4, 0x55, 0x95, 0x90, 0x4e, 0x6d,
+ 0xc8, 0x37, 0xd0, 0xc9, 0x8a, 0x34, 0x14, 0xe3, 0xd0, 0x06, 0x15, 0xd6, 0xdb, 0xa6, 0x2b, 0x59,
+ 0x91, 0x0e, 0xc7, 0x76, 0x3f, 0xd5, 0x7b, 0x51, 0xde, 0x44, 0xe9, 0x7a, 0xeb, 0x3a, 0x5d, 0x58,
+ 0x3a, 0x1d, 0x0e, 0x4f, 0xcc, 0xbd, 0xb7, 0xa0, 0x71, 0xdc, 0x3f, 0x3a, 0xf0, 0x17, 0x7a, 0x13,
+ 0x78, 0x3c, 0x90, 0x89, 0x4e, 0x22, 0x36, 0x39, 0x57, 0x5c, 0xfe, 0x24, 0x0a, 0x99, 0xf1, 0x9b,
+ 0xaa, 0x1b, 0xab, 0x43, 0x77, 0x6a, 0x87, 0xbe, 0x0b, 0xcd, 0xaa, 0xdb, 0x17, 0xfe, 0xa7, 0x39,
+ 0x6b, 0x53, 0x94, 0x56, 0x82, 0xde, 0x08, 0x9e, 0xcc, 0xd9, 0x4d, 0xcd, 0x9a, 0xbf, 0x11, 0x15,
+ 0x1f, 0x54, 0xe0, 0xe0, 0x0b, 0x9e, 0x7f, 0xb2, 0xff, 0x9d, 0x2d, 0x45, 0x71, 0xef, 0x0f, 0x07,
+ 0x56, 0xff, 0xf5, 0xd4, 0x48, 0x00, 0xcd, 0xea, 0xdc, 0x1c, 0x3c, 0xb7, 0x6a, 0x49, 0x1e, 0x43,
+ 0xab, 0xfc, 0x2d, 0xb2, 0x05, 0xb5, 0xe9, 0x74, 0x4d, 0xbe, 0x85, 0x55, 0x7c, 0xee, 0x21, 0x9b,
+ 0x4c, 0x44, 0x14, 0x46, 0xa2, 0xc8, 0x74, 0xd9, 0x67, 0xf7, 0x11, 0xe8, 0x9b, 0xf8, 0xc0, 0x84,
+ 0xc9, 0x26, 0xf8, 0x75, 0xae, 0x4a, 0x3e, 0x55, 0x4d, 0xd7, 0x99, 0x51, 0x4f, 0x93, 0x4f, 0xdc,
+ 0x0c, 0xff, 0x94, 0x5d, 0x87, 0x57, 0x9c, 0xe5, 0x96, 0x66, 0xbb, 0xcf, 0x4b, 0xd9, 0xf5, 0x8f,
+ 0x9c, 0xe5, 0x86, 0xb3, 0xf7, 0xf0, 0x97, 0x72, 0xbe, 0x94, 0x75, 0x87, 0xf8, 0xff, 0xe7, 0xef,
+ 0x00, 0x00, 0x00, 0xff, 0xff, 0x0a, 0x03, 0x26, 0x59, 0x0f, 0x09, 0x00, 0x00,
}
diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto
index 62cb4b8..6559ba3 100644
--- a/ui/metrics/metrics_proto/metrics.proto
+++ b/ui/metrics/metrics_proto/metrics.proto
@@ -93,6 +93,8 @@
// The metrics for the whole build
optional PerfInfo total = 21;
+ optional SoongBuildMetrics soong_build_metrics = 22;
+
optional BuildConfig build_config = 23;
}
@@ -148,4 +150,21 @@
message CriticalUserJourneysMetrics {
// A set of metrics from a run of the critical user journey tests.
repeated CriticalUserJourneyMetrics cujs = 1;
-}
\ No newline at end of file
+}
+
+message SoongBuildMetrics {
+ // The number of modules handled by soong_build.
+ optional uint32 modules = 1;
+
+ // The total number of variants handled by soong_build.
+ optional uint32 variants = 2;
+
+ // The total number of allocations in soong_build.
+ optional uint64 total_alloc_count = 3;
+
+ // The total size of allocations in soong_build in bytes.
+ optional uint64 total_alloc_size = 4;
+
+ // The approximate maximum size of the heap in soong_build in bytes.
+ optional uint64 max_heap_size = 5;
+}
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index ec929b3..19e5a2a 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -20,6 +20,7 @@
"soong-ui-logger",
"soong-ui-status-ninja_frontend",
"soong-ui-status-build_error_proto",
+ "soong-ui-status-build_progress_proto",
],
srcs: [
"critical_path.go",
@@ -53,3 +54,12 @@
"build_error_proto/build_error.pb.go",
],
}
+
+bootstrap_go_package {
+ name: "soong-ui-status-build_progress_proto",
+ pkgPath: "android/soong/ui/status/build_progress_proto",
+ deps: ["golang-protobuf-proto"],
+ srcs: [
+ "build_progress_proto/build_progress.pb.go",
+ ],
+}
diff --git a/ui/status/build_progress_proto/build_progress.pb.go b/ui/status/build_progress_proto/build_progress.pb.go
new file mode 100644
index 0000000..f63c157
--- /dev/null
+++ b/ui/status/build_progress_proto/build_progress.pb.go
@@ -0,0 +1,115 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// source: build_progress.proto
+
+package soong_build_progress_proto
+
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
+
+// Reference imports to suppress errors if they are not otherwise used.
+var _ = proto.Marshal
+var _ = fmt.Errorf
+var _ = math.Inf
+
+// This is a compile-time assertion to ensure that this generated file
+// is compatible with the proto package it is being compiled against.
+// A compilation error at this line likely means your copy of the
+// proto package needs to be updated.
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
+
+type BuildProgress struct {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ TotalActions *uint64 `protobuf:"varint,1,opt,name=total_actions,json=totalActions" json:"total_actions,omitempty"`
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ FinishedActions *uint64 `protobuf:"varint,2,opt,name=finished_actions,json=finishedActions" json:"finished_actions,omitempty"`
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ CurrentActions *uint64 `protobuf:"varint,3,opt,name=current_actions,json=currentActions" json:"current_actions,omitempty"`
+ // Total number of actions that reported as a failure.
+ FailedActions *uint64 `protobuf:"varint,4,opt,name=failed_actions,json=failedActions" json:"failed_actions,omitempty"`
+ XXX_NoUnkeyedLiteral struct{} `json:"-"`
+ XXX_unrecognized []byte `json:"-"`
+ XXX_sizecache int32 `json:"-"`
+}
+
+func (m *BuildProgress) Reset() { *m = BuildProgress{} }
+func (m *BuildProgress) String() string { return proto.CompactTextString(m) }
+func (*BuildProgress) ProtoMessage() {}
+func (*BuildProgress) Descriptor() ([]byte, []int) {
+ return fileDescriptor_a8a463f8e30dab2e, []int{0}
+}
+
+func (m *BuildProgress) XXX_Unmarshal(b []byte) error {
+ return xxx_messageInfo_BuildProgress.Unmarshal(m, b)
+}
+func (m *BuildProgress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+ return xxx_messageInfo_BuildProgress.Marshal(b, m, deterministic)
+}
+func (m *BuildProgress) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_BuildProgress.Merge(m, src)
+}
+func (m *BuildProgress) XXX_Size() int {
+ return xxx_messageInfo_BuildProgress.Size(m)
+}
+func (m *BuildProgress) XXX_DiscardUnknown() {
+ xxx_messageInfo_BuildProgress.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_BuildProgress proto.InternalMessageInfo
+
+func (m *BuildProgress) GetTotalActions() uint64 {
+ if m != nil && m.TotalActions != nil {
+ return *m.TotalActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetFinishedActions() uint64 {
+ if m != nil && m.FinishedActions != nil {
+ return *m.FinishedActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetCurrentActions() uint64 {
+ if m != nil && m.CurrentActions != nil {
+ return *m.CurrentActions
+ }
+ return 0
+}
+
+func (m *BuildProgress) GetFailedActions() uint64 {
+ if m != nil && m.FailedActions != nil {
+ return *m.FailedActions
+ }
+ return 0
+}
+
+func init() {
+ proto.RegisterType((*BuildProgress)(nil), "soong_build_progress.BuildProgress")
+}
+
+func init() { proto.RegisterFile("build_progress.proto", fileDescriptor_a8a463f8e30dab2e) }
+
+var fileDescriptor_a8a463f8e30dab2e = []byte{
+ // 165 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x12, 0x49, 0x2a, 0xcd, 0xcc,
+ 0x49, 0x89, 0x2f, 0x28, 0xca, 0x4f, 0x2f, 0x4a, 0x2d, 0x2e, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9,
+ 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f, 0x47, 0x95, 0x53, 0x5a, 0xcf, 0xc8, 0xc5, 0xeb,
+ 0x04, 0x12, 0x0a, 0x80, 0x8a, 0x08, 0x29, 0x73, 0xf1, 0x96, 0xe4, 0x97, 0x24, 0xe6, 0xc4, 0x27,
+ 0x26, 0x97, 0x64, 0xe6, 0xe7, 0x15, 0x4b, 0x30, 0x2a, 0x30, 0x6a, 0xb0, 0x04, 0xf1, 0x80, 0x05,
+ 0x1d, 0x21, 0x62, 0x42, 0x9a, 0x5c, 0x02, 0x69, 0x99, 0x79, 0x99, 0xc5, 0x19, 0xa9, 0x29, 0x70,
+ 0x75, 0x4c, 0x60, 0x75, 0xfc, 0x30, 0x71, 0x98, 0x52, 0x75, 0x2e, 0xfe, 0xe4, 0xd2, 0xa2, 0xa2,
+ 0xd4, 0xbc, 0x12, 0xb8, 0x4a, 0x66, 0xb0, 0x4a, 0x3e, 0xa8, 0x30, 0x4c, 0xa1, 0x2a, 0x17, 0x5f,
+ 0x5a, 0x62, 0x66, 0x0e, 0x92, 0x89, 0x2c, 0x60, 0x75, 0xbc, 0x10, 0x51, 0xa8, 0x32, 0x27, 0x99,
+ 0x28, 0x29, 0x6c, 0x3e, 0x89, 0x07, 0xfb, 0x12, 0x10, 0x00, 0x00, 0xff, 0xff, 0x3f, 0x6e, 0xc1,
+ 0xef, 0xfc, 0x00, 0x00, 0x00,
+}
diff --git a/ui/status/build_progress_proto/build_progress.proto b/ui/status/build_progress_proto/build_progress.proto
new file mode 100644
index 0000000..d78060a
--- /dev/null
+++ b/ui/status/build_progress_proto/build_progress.proto
@@ -0,0 +1,38 @@
+// Copyright 2020 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.
+
+syntax = "proto2";
+
+package soong_build_progress;
+option go_package = "soong_build_progress_proto";
+
+message BuildProgress {
+ // Total number of actions in a build. The total actions will increase
+ // and might decrease during the course of a build.
+ optional uint64 total_actions = 1;
+
+ // Total number of completed build actions. This value will never decrease
+ // and finished_actions <= total_actions. At one point of the build, the
+ // finished_actions will be equal to total_actions. This may not represent
+ // that the build is completed as the total_actions may be increased for
+ // additional counted work or is doing non-counted work.
+ optional uint64 finished_actions = 2;
+
+ // Total number of current actions being executed during a course of a
+ // build and current_actions + finished_actions <= total_actions.
+ optional uint64 current_actions = 3;
+
+ // Total number of actions that reported as a failure.
+ optional uint64 failed_actions = 4;
+}
diff --git a/ui/status/build_progress_proto/regen.sh b/ui/status/build_progress_proto/regen.sh
new file mode 100755
index 0000000..572785d
--- /dev/null
+++ b/ui/status/build_progress_proto/regen.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Generates the golang source file of build_completion.proto file.
+
+set -e
+
+function die() { echo "ERROR: $1" >&2; exit 1; }
+
+readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?"
+
+if ! hash aprotoc &>/dev/null; then
+ die "could not find aprotoc. ${error_msg}"
+fi
+
+if ! aprotoc --go_out=paths=source_relative:. build_progress.proto; then
+ die "build failed. ${error_msg}"
+fi
diff --git a/ui/status/log.go b/ui/status/log.go
index d407248..4a08acb 100644
--- a/ui/status/log.go
+++ b/ui/status/log.go
@@ -20,12 +20,14 @@
"fmt"
"io"
"io/ioutil"
+ "os"
"strings"
"github.com/golang/protobuf/proto"
"android/soong/ui/logger"
"android/soong/ui/status/build_error_proto"
+ "android/soong/ui/status/build_progress_proto"
)
type verboseLog struct {
@@ -154,6 +156,7 @@
}
func NewProtoErrorLog(log logger.Logger, filename string) StatusOutput {
+ os.Remove(filename)
return &errorProtoLog{
errorProto: soong_build_error_proto.BuildError{},
filename: filename,
@@ -175,20 +178,17 @@
Artifacts: result.Outputs,
Error: proto.String(result.Error.Error()),
})
-}
-func (e *errorProtoLog) Flush() {
- data, err := proto.Marshal(&e.errorProto)
- if err != nil {
- e.log.Printf("Failed to marshal build status proto: %v\n", err)
- return
- }
- err = ioutil.WriteFile(e.filename, []byte(data), 0644)
+ err := writeToFile(&e.errorProto, e.filename)
if err != nil {
e.log.Printf("Failed to write file %s: %v\n", e.filename, err)
}
}
+func (e *errorProtoLog) Flush() {
+ //Not required.
+}
+
func (e *errorProtoLog) Message(level MsgLevel, message string) {
if level > ErrorLvl {
e.errorProto.ErrorMessages = append(e.errorProto.ErrorMessages, message)
@@ -198,3 +198,75 @@
func (e *errorProtoLog) Write(p []byte) (int, error) {
return 0, errors.New("not supported")
}
+
+type buildProgressLog struct {
+ filename string
+ log logger.Logger
+ failedActions uint64
+}
+
+func NewBuildProgressLog(log logger.Logger, filename string) StatusOutput {
+ return &buildProgressLog{
+ filename: filename,
+ log: log,
+ failedActions: 0,
+ }
+}
+
+func (b *buildProgressLog) StartAction(action *Action, counts Counts) {
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) FinishAction(result ActionResult, counts Counts) {
+ if result.Error != nil {
+ b.failedActions++
+ }
+ b.updateCounters(counts)
+}
+
+func (b *buildProgressLog) Flush() {
+ //Not required.
+}
+
+func (b *buildProgressLog) Message(level MsgLevel, message string) {
+ // Not required.
+}
+
+func (b *buildProgressLog) Write(p []byte) (int, error) {
+ return 0, errors.New("not supported")
+}
+
+func (b *buildProgressLog) updateCounters(counts Counts) {
+ err := writeToFile(
+ &soong_build_progress_proto.BuildProgress{
+ CurrentActions: proto.Uint64(uint64(counts.RunningActions)),
+ FinishedActions: proto.Uint64(uint64(counts.FinishedActions)),
+ TotalActions: proto.Uint64(uint64(counts.TotalActions)),
+ FailedActions: proto.Uint64(b.failedActions),
+ },
+ b.filename,
+ )
+ if err != nil {
+ b.log.Printf("Failed to write file %s: %v\n", b.filename, err)
+ }
+}
+
+func writeToFile(pb proto.Message, outputPath string) (err error) {
+ data, err := proto.Marshal(pb)
+ if err != nil {
+ return err
+ }
+
+ tempPath := outputPath + ".tmp"
+ err = ioutil.WriteFile(tempPath, []byte(data), 0644)
+ if err != nil {
+ return err
+ }
+
+ err = os.Rename(tempPath, outputPath)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/ui/status/ninja.go b/ui/status/ninja.go
index 9cf2f6a..a11774c 100644
--- a/ui/status/ninja.go
+++ b/ui/status/ninja.go
@@ -174,6 +174,8 @@
n.status.Print("warning: " + message)
case ninja_frontend.Status_Message_ERROR:
n.status.Error(message)
+ case ninja_frontend.Status_Message_DEBUG:
+ n.status.Verbose(message)
default:
n.status.Print(message)
}
diff --git a/ui/status/ninja_frontend/frontend.pb.go b/ui/status/ninja_frontend/frontend.pb.go
index 7c05eed..7ba9de2 100644
--- a/ui/status/ninja_frontend/frontend.pb.go
+++ b/ui/status/ninja_frontend/frontend.pb.go
@@ -3,9 +3,11 @@
package ninja_frontend
-import proto "github.com/golang/protobuf/proto"
-import fmt "fmt"
-import math "math"
+import (
+ fmt "fmt"
+ proto "github.com/golang/protobuf/proto"
+ math "math"
+)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@@ -16,7 +18,7 @@
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
-const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package
+const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type Status_Message_Level int32
@@ -24,17 +26,21 @@
Status_Message_INFO Status_Message_Level = 0
Status_Message_WARNING Status_Message_Level = 1
Status_Message_ERROR Status_Message_Level = 2
+ Status_Message_DEBUG Status_Message_Level = 3
)
var Status_Message_Level_name = map[int32]string{
0: "INFO",
1: "WARNING",
2: "ERROR",
+ 3: "DEBUG",
}
+
var Status_Message_Level_value = map[string]int32{
"INFO": 0,
"WARNING": 1,
"ERROR": 2,
+ "DEBUG": 3,
}
func (x Status_Message_Level) Enum() *Status_Message_Level {
@@ -42,9 +48,11 @@
*p = x
return p
}
+
func (x Status_Message_Level) String() string {
return proto.EnumName(Status_Message_Level_name, int32(x))
}
+
func (x *Status_Message_Level) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(Status_Message_Level_value, data, "Status_Message_Level")
if err != nil {
@@ -53,8 +61,9 @@
*x = Status_Message_Level(value)
return nil
}
+
func (Status_Message_Level) EnumDescriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 5, 0}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 5, 0}
}
type Status struct {
@@ -73,16 +82,17 @@
func (m *Status) String() string { return proto.CompactTextString(m) }
func (*Status) ProtoMessage() {}
func (*Status) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0}
+ return fileDescriptor_eca3873955a29cfe, []int{0}
}
+
func (m *Status) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status.Unmarshal(m, b)
}
func (m *Status) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status.Marshal(b, m, deterministic)
}
-func (dst *Status) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status.Merge(dst, src)
+func (m *Status) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status.Merge(m, src)
}
func (m *Status) XXX_Size() int {
return xxx_messageInfo_Status.Size(m)
@@ -147,16 +157,17 @@
func (m *Status_TotalEdges) String() string { return proto.CompactTextString(m) }
func (*Status_TotalEdges) ProtoMessage() {}
func (*Status_TotalEdges) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 0}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 0}
}
+
func (m *Status_TotalEdges) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_TotalEdges.Unmarshal(m, b)
}
func (m *Status_TotalEdges) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_TotalEdges.Marshal(b, m, deterministic)
}
-func (dst *Status_TotalEdges) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_TotalEdges.Merge(dst, src)
+func (m *Status_TotalEdges) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_TotalEdges.Merge(m, src)
}
func (m *Status_TotalEdges) XXX_Size() int {
return xxx_messageInfo_Status_TotalEdges.Size(m)
@@ -188,16 +199,17 @@
func (m *Status_BuildStarted) String() string { return proto.CompactTextString(m) }
func (*Status_BuildStarted) ProtoMessage() {}
func (*Status_BuildStarted) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 1}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 1}
}
+
func (m *Status_BuildStarted) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_BuildStarted.Unmarshal(m, b)
}
func (m *Status_BuildStarted) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_BuildStarted.Marshal(b, m, deterministic)
}
-func (dst *Status_BuildStarted) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_BuildStarted.Merge(dst, src)
+func (m *Status_BuildStarted) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_BuildStarted.Merge(m, src)
}
func (m *Status_BuildStarted) XXX_Size() int {
return xxx_messageInfo_Status_BuildStarted.Size(m)
@@ -232,16 +244,17 @@
func (m *Status_BuildFinished) String() string { return proto.CompactTextString(m) }
func (*Status_BuildFinished) ProtoMessage() {}
func (*Status_BuildFinished) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 2}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 2}
}
+
func (m *Status_BuildFinished) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_BuildFinished.Unmarshal(m, b)
}
func (m *Status_BuildFinished) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_BuildFinished.Marshal(b, m, deterministic)
}
-func (dst *Status_BuildFinished) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_BuildFinished.Merge(dst, src)
+func (m *Status_BuildFinished) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_BuildFinished.Merge(m, src)
}
func (m *Status_BuildFinished) XXX_Size() int {
return xxx_messageInfo_Status_BuildFinished.Size(m)
@@ -276,16 +289,17 @@
func (m *Status_EdgeStarted) String() string { return proto.CompactTextString(m) }
func (*Status_EdgeStarted) ProtoMessage() {}
func (*Status_EdgeStarted) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 3}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 3}
}
+
func (m *Status_EdgeStarted) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_EdgeStarted.Unmarshal(m, b)
}
func (m *Status_EdgeStarted) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_EdgeStarted.Marshal(b, m, deterministic)
}
-func (dst *Status_EdgeStarted) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_EdgeStarted.Merge(dst, src)
+func (m *Status_EdgeStarted) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_EdgeStarted.Merge(m, src)
}
func (m *Status_EdgeStarted) XXX_Size() int {
return xxx_messageInfo_Status_EdgeStarted.Size(m)
@@ -353,7 +367,11 @@
// Exit status (0 for success).
Status *int32 `protobuf:"zigzag32,3,opt,name=status" json:"status,omitempty"`
// Edge output, may contain ANSI codes.
- Output *string `protobuf:"bytes,4,opt,name=output" json:"output,omitempty"`
+ Output *string `protobuf:"bytes,4,opt,name=output" json:"output,omitempty"`
+ // Number of milliseconds spent executing in user mode
+ UserTime *uint32 `protobuf:"varint,5,opt,name=user_time,json=userTime" json:"user_time,omitempty"`
+ // Number of milliseconds spent executing in kernel mode
+ SystemTime *uint32 `protobuf:"varint,6,opt,name=system_time,json=systemTime" json:"system_time,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@@ -363,16 +381,17 @@
func (m *Status_EdgeFinished) String() string { return proto.CompactTextString(m) }
func (*Status_EdgeFinished) ProtoMessage() {}
func (*Status_EdgeFinished) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 4}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 4}
}
+
func (m *Status_EdgeFinished) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_EdgeFinished.Unmarshal(m, b)
}
func (m *Status_EdgeFinished) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_EdgeFinished.Marshal(b, m, deterministic)
}
-func (dst *Status_EdgeFinished) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_EdgeFinished.Merge(dst, src)
+func (m *Status_EdgeFinished) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_EdgeFinished.Merge(m, src)
}
func (m *Status_EdgeFinished) XXX_Size() int {
return xxx_messageInfo_Status_EdgeFinished.Size(m)
@@ -411,8 +430,22 @@
return ""
}
+func (m *Status_EdgeFinished) GetUserTime() uint32 {
+ if m != nil && m.UserTime != nil {
+ return *m.UserTime
+ }
+ return 0
+}
+
+func (m *Status_EdgeFinished) GetSystemTime() uint32 {
+ if m != nil && m.SystemTime != nil {
+ return *m.SystemTime
+ }
+ return 0
+}
+
type Status_Message struct {
- // Message priority level (INFO, WARNING, or ERROR).
+ // Message priority level (DEBUG, INFO, WARNING, ERROR).
Level *Status_Message_Level `protobuf:"varint,1,opt,name=level,enum=ninja.Status_Message_Level,def=0" json:"level,omitempty"`
// Info/warning/error message from Ninja.
Message *string `protobuf:"bytes,2,opt,name=message" json:"message,omitempty"`
@@ -425,16 +458,17 @@
func (m *Status_Message) String() string { return proto.CompactTextString(m) }
func (*Status_Message) ProtoMessage() {}
func (*Status_Message) Descriptor() ([]byte, []int) {
- return fileDescriptor_frontend_5a49d9b15a642005, []int{0, 5}
+ return fileDescriptor_eca3873955a29cfe, []int{0, 5}
}
+
func (m *Status_Message) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_Status_Message.Unmarshal(m, b)
}
func (m *Status_Message) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_Status_Message.Marshal(b, m, deterministic)
}
-func (dst *Status_Message) XXX_Merge(src proto.Message) {
- xxx_messageInfo_Status_Message.Merge(dst, src)
+func (m *Status_Message) XXX_Merge(src proto.Message) {
+ xxx_messageInfo_Status_Message.Merge(m, src)
}
func (m *Status_Message) XXX_Size() int {
return xxx_messageInfo_Status_Message.Size(m)
@@ -462,6 +496,7 @@
}
func init() {
+ proto.RegisterEnum("ninja.Status_Message_Level", Status_Message_Level_name, Status_Message_Level_value)
proto.RegisterType((*Status)(nil), "ninja.Status")
proto.RegisterType((*Status_TotalEdges)(nil), "ninja.Status.TotalEdges")
proto.RegisterType((*Status_BuildStarted)(nil), "ninja.Status.BuildStarted")
@@ -469,42 +504,46 @@
proto.RegisterType((*Status_EdgeStarted)(nil), "ninja.Status.EdgeStarted")
proto.RegisterType((*Status_EdgeFinished)(nil), "ninja.Status.EdgeFinished")
proto.RegisterType((*Status_Message)(nil), "ninja.Status.Message")
- proto.RegisterEnum("ninja.Status_Message_Level", Status_Message_Level_name, Status_Message_Level_value)
}
-func init() { proto.RegisterFile("frontend.proto", fileDescriptor_frontend_5a49d9b15a642005) }
+func init() {
+ proto.RegisterFile("frontend.proto", fileDescriptor_eca3873955a29cfe)
+}
-var fileDescriptor_frontend_5a49d9b15a642005 = []byte{
- // 496 bytes of a gzipped FileDescriptorProto
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x53, 0xd1, 0x6e, 0xd3, 0x30,
- 0x14, 0xa5, 0x69, 0xd3, 0x34, 0x37, 0x6d, 0x28, 0x96, 0x40, 0x59, 0x10, 0xa2, 0xda, 0xd3, 0x78,
- 0x20, 0x48, 0xbc, 0x20, 0x10, 0x12, 0xa2, 0xd2, 0x06, 0x43, 0xd0, 0x49, 0xde, 0x24, 0x24, 0x5e,
- 0xaa, 0x74, 0xf6, 0x86, 0x51, 0xe2, 0x54, 0xb1, 0xbb, 0x5f, 0xe0, 0x7f, 0x78, 0xe0, 0xfb, 0x90,
- 0xaf, 0xed, 0x2c, 0x65, 0x7b, 0xcb, 0xf1, 0x3d, 0xe7, 0xde, 0x73, 0x8f, 0x1d, 0x48, 0xaf, 0xda,
- 0x46, 0x6a, 0x2e, 0x59, 0xb1, 0x6d, 0x1b, 0xdd, 0x90, 0x50, 0x0a, 0xf9, 0xab, 0x3c, 0xfc, 0x13,
- 0xc1, 0xf8, 0x5c, 0x97, 0x7a, 0xa7, 0xc8, 0x5b, 0x48, 0x74, 0xa3, 0xcb, 0x6a, 0xcd, 0xd9, 0x35,
- 0x57, 0xd9, 0x60, 0x31, 0x38, 0x4a, 0x5e, 0x67, 0x05, 0xf2, 0x0a, 0xcb, 0x29, 0x2e, 0x0c, 0xe1,
- 0xd8, 0xd4, 0x29, 0xe8, 0xee, 0x9b, 0x7c, 0x80, 0xd9, 0x66, 0x27, 0x2a, 0xb6, 0x56, 0xba, 0x6c,
- 0x35, 0x67, 0x59, 0x80, 0xe2, 0x7c, 0x5f, 0xbc, 0x34, 0x94, 0x73, 0xcb, 0xa0, 0xd3, 0x4d, 0x0f,
- 0x91, 0x25, 0xa4, 0xb6, 0xc1, 0x95, 0x90, 0x42, 0xfd, 0xe4, 0x2c, 0x1b, 0x62, 0x87, 0xa7, 0xf7,
- 0x74, 0x38, 0x71, 0x14, 0x6a, 0x67, 0x7a, 0x48, 0xde, 0xc3, 0xd4, 0x38, 0xef, 0x3c, 0x8c, 0xb0,
- 0xc3, 0xc1, 0x7e, 0x07, 0xe3, 0xd7, 0x5b, 0x48, 0xf8, 0x2d, 0x30, 0x2b, 0xa0, 0xba, 0x33, 0x10,
- 0xde, 0xb7, 0x82, 0x91, 0x77, 0xf3, 0x71, 0x5c, 0x37, 0xfe, 0x15, 0x44, 0x35, 0x57, 0xaa, 0xbc,
- 0xe6, 0xd9, 0x18, 0xa5, 0x8f, 0xf7, 0xa5, 0xdf, 0x6c, 0x91, 0x7a, 0x56, 0xfe, 0x12, 0xe0, 0x36,
- 0x4e, 0xf2, 0xfc, 0x6e, 0xfa, 0xb3, 0x7e, 0xc6, 0xf9, 0x17, 0x98, 0xf6, 0x03, 0x24, 0x0b, 0x48,
- 0xb6, 0x65, 0x5b, 0x56, 0x15, 0xaf, 0x84, 0xaa, 0x9d, 0xa0, 0x7f, 0x44, 0x32, 0x88, 0x6e, 0x78,
- 0xbb, 0x69, 0x14, 0xc7, 0xfb, 0x98, 0x50, 0x0f, 0xf3, 0x87, 0x30, 0xdb, 0x8b, 0x32, 0xff, 0x3b,
- 0x80, 0xa4, 0x17, 0x0d, 0x49, 0x21, 0x10, 0xcc, 0xf5, 0x0c, 0x04, 0x23, 0xcf, 0x00, 0x30, 0xd6,
- 0xb5, 0x16, 0xb5, 0xed, 0x36, 0xa3, 0x31, 0x9e, 0x5c, 0x88, 0x9a, 0x93, 0x27, 0x30, 0x16, 0x72,
- 0xbb, 0xd3, 0x2a, 0x1b, 0x2e, 0x86, 0x47, 0x31, 0x75, 0xc8, 0x38, 0x68, 0x76, 0x1a, 0x0b, 0x23,
- 0x2c, 0x78, 0x48, 0x08, 0x8c, 0x18, 0x57, 0x97, 0x98, 0x72, 0x4c, 0xf1, 0xdb, 0xb0, 0x2f, 0x9b,
- 0xba, 0x2e, 0x25, 0xc3, 0x04, 0x63, 0xea, 0xa1, 0xad, 0x48, 0xd5, 0x54, 0x3c, 0x8b, 0xec, 0x26,
- 0x0e, 0xe6, 0x02, 0xa6, 0xfd, 0x3b, 0xb9, 0x63, 0xfc, 0x00, 0x26, 0x5c, 0xb2, 0xbe, 0xed, 0x88,
- 0x4b, 0xe6, 0x4d, 0x2b, 0xbc, 0x1a, 0x7c, 0x6b, 0x8f, 0xa8, 0x43, 0xe6, 0xdc, 0xba, 0xc4, 0x17,
- 0x14, 0x53, 0x87, 0xf2, 0xdf, 0x03, 0x88, 0xdc, 0x25, 0x92, 0x37, 0x10, 0x56, 0xfc, 0x86, 0x57,
- 0x38, 0x29, 0xfd, 0xff, 0x99, 0x3a, 0x56, 0xf1, 0xd5, 0x50, 0xde, 0x8d, 0x4e, 0x57, 0x27, 0x67,
- 0xd4, 0xf2, 0xcd, 0x26, 0xfe, 0x95, 0x04, 0x76, 0x47, 0x07, 0x0f, 0x5f, 0x40, 0x88, 0x7c, 0x32,
- 0x01, 0x54, 0xcc, 0x1f, 0x90, 0x04, 0xa2, 0xef, 0x1f, 0xe9, 0xea, 0x74, 0xf5, 0x69, 0x3e, 0x20,
- 0x31, 0x84, 0xc7, 0x94, 0x9e, 0xd1, 0x79, 0xb0, 0x24, 0x9f, 0x87, 0x3f, 0x52, 0x9c, 0xb8, 0xf6,
- 0x7f, 0xf5, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x2e, 0x8c, 0xef, 0xcb, 0xe0, 0x03, 0x00, 0x00,
+var fileDescriptor_eca3873955a29cfe = []byte{
+ // 539 bytes of a gzipped FileDescriptorProto
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x54, 0xd1, 0x6e, 0xd3, 0x4a,
+ 0x10, 0xbd, 0x4e, 0xe2, 0x38, 0x1e, 0x27, 0xb9, 0x61, 0x25, 0x90, 0xeb, 0x0a, 0x35, 0xea, 0x53,
+ 0x5f, 0x08, 0x12, 0x42, 0x42, 0x20, 0x24, 0x44, 0x44, 0x5a, 0x8a, 0x20, 0x95, 0xb6, 0x45, 0x48,
+ 0xbc, 0x44, 0x4e, 0x77, 0x5a, 0x8c, 0xec, 0x75, 0xe4, 0xdd, 0x54, 0xe2, 0x37, 0xf8, 0x09, 0xfe,
+ 0x80, 0xaf, 0xe3, 0x01, 0xed, 0xec, 0xda, 0x75, 0x68, 0xdf, 0x7c, 0x76, 0xce, 0x9c, 0x39, 0x7b,
+ 0x76, 0x64, 0x18, 0x5f, 0x55, 0xa5, 0xd4, 0x28, 0xc5, 0x6c, 0x53, 0x95, 0xba, 0x64, 0xbe, 0xcc,
+ 0xe4, 0xf7, 0xf4, 0xf0, 0x4f, 0x00, 0xfd, 0x73, 0x9d, 0xea, 0xad, 0x62, 0x2f, 0x21, 0xd2, 0xa5,
+ 0x4e, 0xf3, 0x15, 0x8a, 0x6b, 0x54, 0xb1, 0x37, 0xf5, 0x8e, 0xa2, 0x67, 0xf1, 0x8c, 0x78, 0x33,
+ 0xcb, 0x99, 0x5d, 0x18, 0xc2, 0xc2, 0xd4, 0x39, 0xe8, 0xe6, 0x9b, 0xbd, 0x81, 0xd1, 0x7a, 0x9b,
+ 0xe5, 0x62, 0xa5, 0x74, 0x5a, 0x69, 0x14, 0x71, 0x87, 0x9a, 0x93, 0xdd, 0xe6, 0xb9, 0xa1, 0x9c,
+ 0x5b, 0x06, 0x1f, 0xae, 0x5b, 0x88, 0xcd, 0x61, 0x6c, 0x05, 0xae, 0x32, 0x99, 0xa9, 0x6f, 0x28,
+ 0xe2, 0x2e, 0x29, 0xec, 0xdf, 0xa3, 0x70, 0xec, 0x28, 0xdc, 0xce, 0xac, 0x21, 0x7b, 0x0d, 0x43,
+ 0xe3, 0xbc, 0xf1, 0xd0, 0x23, 0x85, 0xbd, 0x5d, 0x05, 0xe3, 0xb7, 0xb6, 0x10, 0xe1, 0x2d, 0x30,
+ 0x57, 0xa0, 0xee, 0xc6, 0x80, 0x7f, 0xdf, 0x15, 0x4c, 0x7b, 0x33, 0x9f, 0xc6, 0x35, 0xe3, 0x9f,
+ 0x42, 0x50, 0xa0, 0x52, 0xe9, 0x35, 0xc6, 0x7d, 0x6a, 0x7d, 0xb8, 0xdb, 0xfa, 0xc9, 0x16, 0x79,
+ 0xcd, 0x4a, 0x9e, 0x00, 0xdc, 0xc6, 0xc9, 0x0e, 0xee, 0xa6, 0x3f, 0x6a, 0x67, 0x9c, 0x7c, 0x80,
+ 0x61, 0x3b, 0x40, 0x36, 0x85, 0x68, 0x93, 0x56, 0x69, 0x9e, 0x63, 0x9e, 0xa9, 0xc2, 0x35, 0xb4,
+ 0x8f, 0x58, 0x0c, 0xc1, 0x0d, 0x56, 0xeb, 0x52, 0x21, 0xbd, 0xc7, 0x80, 0xd7, 0x30, 0xf9, 0x1f,
+ 0x46, 0x3b, 0x51, 0x26, 0xbf, 0x3d, 0x88, 0x5a, 0xd1, 0xb0, 0x31, 0x74, 0x32, 0xe1, 0x34, 0x3b,
+ 0x99, 0x60, 0x8f, 0x01, 0x28, 0xd6, 0x95, 0xce, 0x0a, 0xab, 0x36, 0xe2, 0x21, 0x9d, 0x5c, 0x64,
+ 0x05, 0xb2, 0x47, 0xd0, 0xcf, 0xe4, 0x66, 0xab, 0x55, 0xdc, 0x9d, 0x76, 0x8f, 0x42, 0xee, 0x90,
+ 0x71, 0x50, 0x6e, 0x35, 0x15, 0x7a, 0x54, 0xa8, 0x21, 0x63, 0xd0, 0x13, 0xa8, 0x2e, 0x29, 0xe5,
+ 0x90, 0xd3, 0xb7, 0x61, 0x5f, 0x96, 0x45, 0x91, 0x4a, 0x41, 0x09, 0x86, 0xbc, 0x86, 0xb6, 0x22,
+ 0x55, 0x99, 0x63, 0x1c, 0xd8, 0x9b, 0x38, 0x98, 0xfc, 0xf2, 0x60, 0xd8, 0x7e, 0x94, 0x3b, 0xce,
+ 0xf7, 0x60, 0x80, 0x52, 0xb4, 0x7d, 0x07, 0x28, 0x45, 0xed, 0x5a, 0xd1, 0xdb, 0xd0, 0xb2, 0x3d,
+ 0xe0, 0x0e, 0x99, 0x73, 0x6b, 0x93, 0x56, 0x28, 0xe4, 0x0e, 0xb1, 0x7d, 0x08, 0xb7, 0x0a, 0x2b,
+ 0xab, 0xe5, 0x93, 0xd6, 0xc0, 0x1c, 0x90, 0xd8, 0x01, 0x44, 0xea, 0x87, 0xd2, 0x58, 0xd8, 0x72,
+ 0xdf, 0xbe, 0x9f, 0x3d, 0x32, 0x84, 0xe4, 0xa7, 0x07, 0x81, 0xdb, 0x01, 0xf6, 0x02, 0xfc, 0x1c,
+ 0x6f, 0x30, 0x27, 0x9f, 0xe3, 0x7f, 0xb7, 0xdc, 0xb1, 0x66, 0x1f, 0x0d, 0xe5, 0x55, 0xef, 0x74,
+ 0x79, 0x7c, 0xc6, 0x2d, 0xdf, 0x04, 0x51, 0x2f, 0x59, 0xc7, 0x46, 0xe4, 0xe0, 0xe1, 0x73, 0xf0,
+ 0x89, 0xcf, 0x06, 0x40, 0x1d, 0x93, 0xff, 0x58, 0x04, 0xc1, 0x97, 0xb7, 0x7c, 0x79, 0xba, 0x3c,
+ 0x99, 0x78, 0x2c, 0x04, 0x7f, 0xc1, 0xf9, 0x19, 0x9f, 0x74, 0xcc, 0xe7, 0xbb, 0xc5, 0xfc, 0xf3,
+ 0xc9, 0xa4, 0x3b, 0x67, 0xef, 0xbb, 0x5f, 0xc7, 0x34, 0x7c, 0x55, 0xff, 0x1f, 0xfe, 0x06, 0x00,
+ 0x00, 0xff, 0xff, 0xaf, 0x93, 0x48, 0xcf, 0x2a, 0x04, 0x00, 0x00,
}
diff --git a/ui/status/ninja_frontend/frontend.proto b/ui/status/ninja_frontend/frontend.proto
index 13fd535..baa0046 100644
--- a/ui/status/ninja_frontend/frontend.proto
+++ b/ui/status/ninja_frontend/frontend.proto
@@ -61,6 +61,10 @@
optional sint32 status = 3;
// Edge output, may contain ANSI codes.
optional string output = 4;
+ // Number of milliseconds spent executing in user mode
+ optional uint32 user_time = 5;
+ // Number of milliseconds spent executing in kernel mode
+ optional uint32 system_time = 6;
}
message Message {
@@ -68,8 +72,9 @@
INFO = 0;
WARNING = 1;
ERROR = 2;
+ DEBUG = 3;
}
- // Message priority level (INFO, WARNING, or ERROR).
+ // Message priority level (DEBUG, INFO, WARNING, ERROR).
optional Level level = 1 [default = INFO];
// Info/warning/error message from Ninja.
optional string message = 2;
diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp
index b533b0d..aa6e35d 100644
--- a/ui/terminal/Android.bp
+++ b/ui/terminal/Android.bp
@@ -17,7 +17,7 @@
pkgPath: "android/soong/ui/terminal",
deps: ["soong-ui-status"],
srcs: [
- "dumb_status.go",
+ "simple_status.go",
"format.go",
"smart_status.go",
"status.go",
diff --git a/ui/terminal/dumb_status.go b/ui/terminal/simple_status.go
similarity index 70%
rename from ui/terminal/dumb_status.go
rename to ui/terminal/simple_status.go
index 201770f..4e8c568 100644
--- a/ui/terminal/dumb_status.go
+++ b/ui/terminal/simple_status.go
@@ -21,31 +21,31 @@
"android/soong/ui/status"
)
-type dumbStatusOutput struct {
+type simpleStatusOutput struct {
writer io.Writer
formatter formatter
}
-// NewDumbStatusOutput returns a StatusOutput that represents the
+// NewSimpleStatusOutput returns a StatusOutput that represents the
// current build status similarly to Ninja's built-in terminal
// output.
-func NewDumbStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
- return &dumbStatusOutput{
+func NewSimpleStatusOutput(w io.Writer, formatter formatter) status.StatusOutput {
+ return &simpleStatusOutput{
writer: w,
formatter: formatter,
}
}
-func (s *dumbStatusOutput) Message(level status.MsgLevel, message string) {
+func (s *simpleStatusOutput) Message(level status.MsgLevel, message string) {
if level >= status.StatusLvl {
fmt.Fprintln(s.writer, s.formatter.message(level, message))
}
}
-func (s *dumbStatusOutput) StartAction(action *status.Action, counts status.Counts) {
+func (s *simpleStatusOutput) StartAction(action *status.Action, counts status.Counts) {
}
-func (s *dumbStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
+func (s *simpleStatusOutput) FinishAction(result status.ActionResult, counts status.Counts) {
str := result.Description
if str == "" {
str = result.Command
@@ -63,9 +63,9 @@
}
}
-func (s *dumbStatusOutput) Flush() {}
+func (s *simpleStatusOutput) Flush() {}
-func (s *dumbStatusOutput) Write(p []byte) (int, error) {
+func (s *simpleStatusOutput) Write(p []byte) (int, error) {
fmt.Fprint(s.writer, string(p))
return len(p), nil
}
diff --git a/ui/terminal/status.go b/ui/terminal/status.go
index 60dfc70..d8e7392 100644
--- a/ui/terminal/status.go
+++ b/ui/terminal/status.go
@@ -26,12 +26,12 @@
//
// statusFormat takes nearly all the same options as NINJA_STATUS.
// %c is currently unsupported.
-func NewStatusOutput(w io.Writer, statusFormat string, forceDumbOutput, quietBuild bool) status.StatusOutput {
+func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild bool) status.StatusOutput {
formatter := newFormatter(statusFormat, quietBuild)
- if !forceDumbOutput && isSmartTerminal(w) {
+ if !forceSimpleOutput && isSmartTerminal(w) {
return NewSmartStatusOutput(w, formatter)
} else {
- return NewDumbStatusOutput(w, formatter)
+ return NewSimpleStatusOutput(w, formatter)
}
}
diff --git a/ui/terminal/status_test.go b/ui/terminal/status_test.go
index 9f60829..aa69dff 100644
--- a/ui/terminal/status_test.go
+++ b/ui/terminal/status_test.go
@@ -26,64 +26,64 @@
func TestStatusOutput(t *testing.T) {
tests := []struct {
- name string
- calls func(stat status.StatusOutput)
- smart string
- dumb string
+ name string
+ calls func(stat status.StatusOutput)
+ smart string
+ simple string
}{
{
- name: "two actions",
- calls: twoActions,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+ name: "two actions",
+ calls: twoActions,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
},
{
- name: "two parallel actions",
- calls: twoParallelActions,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
+ name: "two parallel actions",
+ calls: twoParallelActions,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 0% 0/2] action2\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\n[100% 2/2] action2\n",
},
{
- name: "action with output",
- calls: actionsWithOutput,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+ name: "action with output",
+ calls: actionsWithOutput,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
},
{
- name: "action with output without newline",
- calls: actionsWithOutputWithoutNewline,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
+ name: "action with output without newline",
+ calls: actionsWithOutputWithoutNewline,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\noutput1\noutput2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\noutput1\noutput2\n[100% 3/3] action3\n",
},
{
- name: "action with error",
- calls: actionsWithError,
- smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
- dumb: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
+ name: "action with error",
+ calls: actionsWithError,
+ smart: "\r\x1b[1m[ 0% 0/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action1\x1b[0m\x1b[K\r\x1b[1m[ 33% 1/3] action2\x1b[0m\x1b[K\r\x1b[1m[ 66% 2/3] action2\x1b[0m\x1b[K\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n\r\x1b[1m[ 66% 2/3] action3\x1b[0m\x1b[K\r\x1b[1m[100% 3/3] action3\x1b[0m\x1b[K\n",
+ simple: "[ 33% 1/3] action1\n[ 66% 2/3] action2\nFAILED: f1 f2\ntouch f1 f2\nerror1\nerror2\n[100% 3/3] action3\n",
},
{
- name: "action with empty description",
- calls: actionWithEmptyDescription,
- smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
- dumb: "[100% 1/1] command1\n",
+ name: "action with empty description",
+ calls: actionWithEmptyDescription,
+ smart: "\r\x1b[1m[ 0% 0/1] command1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] command1\x1b[0m\x1b[K\n",
+ simple: "[100% 1/1] command1\n",
},
{
- name: "messages",
- calls: actionsWithMessages,
- smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
+ name: "messages",
+ calls: actionsWithMessages,
+ smart: "\r\x1b[1m[ 0% 0/2] action1\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action1\x1b[0m\x1b[K\r\x1b[1mstatus\x1b[0m\x1b[K\r\x1b[Kprint\nFAILED: error\n\r\x1b[1m[ 50% 1/2] action2\x1b[0m\x1b[K\r\x1b[1m[100% 2/2] action2\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action1\nstatus\nprint\nFAILED: error\n[100% 2/2] action2\n",
},
{
- name: "action with long description",
- calls: actionWithLongDescription,
- smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
- dumb: "[ 50% 1/2] action with very long description to test eliding\n",
+ name: "action with long description",
+ calls: actionWithLongDescription,
+ smart: "\r\x1b[1m[ 0% 0/2] action with very long descrip\x1b[0m\x1b[K\r\x1b[1m[ 50% 1/2] action with very long descrip\x1b[0m\x1b[K\n",
+ simple: "[ 50% 1/2] action with very long description to test eliding\n",
},
{
- name: "action with output with ansi codes",
- calls: actionWithOuptutWithAnsiCodes,
- smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
- dumb: "[100% 1/1] action1\ncolor\n",
+ name: "action with output with ansi codes",
+ calls: actionWithOuptutWithAnsiCodes,
+ smart: "\r\x1b[1m[ 0% 0/1] action1\x1b[0m\x1b[K\r\x1b[1m[100% 1/1] action1\x1b[0m\x1b[K\n\x1b[31mcolor\x1b[0m\n",
+ simple: "[100% 1/1] action1\ncolor\n",
},
}
@@ -103,24 +103,24 @@
}
})
- t.Run("dumb", func(t *testing.T) {
- dumb := &bytes.Buffer{}
- stat := NewStatusOutput(dumb, "", false, false)
+ t.Run("simple", func(t *testing.T) {
+ simple := &bytes.Buffer{}
+ stat := NewStatusOutput(simple, "", false, false)
tt.calls(stat)
stat.Flush()
- if g, w := dumb.String(), tt.dumb; g != w {
+ if g, w := simple.String(), tt.simple; g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
}
})
- t.Run("force dumb", func(t *testing.T) {
+ t.Run("force simple", func(t *testing.T) {
smart := &fakeSmartTerminal{termWidth: 40}
stat := NewStatusOutput(smart, "", true, false)
tt.calls(stat)
stat.Flush()
- if g, w := smart.String(), tt.dumb; g != w {
+ if g, w := smart.String(), tt.simple; g != w {
t.Errorf("want:\n%q\ngot:\n%q", w, g)
}
})
diff --git a/vnames.go.json b/vnames.go.json
index 5842097..7ce2d4b 100644
--- a/vnames.go.json
+++ b/vnames.go.json
@@ -3,7 +3,7 @@
"pattern": "(.*)",
"vname": {
"corpus": "android.googlesource.com/platform/superproject",
- "path": "build/soong/@1@"
+ "path": "@1@"
}
}
]
diff --git a/zip/Android.bp b/zip/Android.bp
index 259e010..5081e91 100644
--- a/zip/Android.bp
+++ b/zip/Android.bp
@@ -27,7 +27,6 @@
"rate_limit.go",
],
testSrcs: [
- "zip_test.go",
+ "zip_test.go",
],
}
-
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index fba2e4b..d603586 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -62,6 +62,15 @@
return nil
}
+type rspFiles struct{}
+
+func (rspFiles) String() string { return `""` }
+
+func (rspFiles) Set(s string) error {
+ fileArgsBuilder.RspFile(s)
+ return nil
+}
+
type dir struct{}
func (dir) String() string { return `""` }
@@ -143,7 +152,8 @@
traceFile := flags.String("trace", "", "write trace to file")
flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files")
- flags.Var(&listFiles{}, "l", "file containing list of .class files")
+ flags.Var(&listFiles{}, "l", "file containing list of files to zip")
+ flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping")
flags.Var(&dir{}, "D", "directory to include in zip")
flags.Var(&file{}, "f", "file to include in zip")
flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
diff --git a/zip/zip.go b/zip/zip.go
index 3c710a7..e27432c 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -150,6 +150,30 @@
return b
}
+func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder {
+ if b.err != nil {
+ return b
+ }
+
+ f, err := b.fs.Open(name)
+ if err != nil {
+ b.err = err
+ return b
+ }
+ defer f.Close()
+
+ list, err := ioutil.ReadAll(f)
+ if err != nil {
+ b.err = err
+ return b
+ }
+
+ arg := b.state
+ arg.SourceFiles = ReadRespFile(list)
+ b.fileArgs = append(b.fileArgs, arg)
+ return b
+}
+
func (b *FileArgsBuilder) Error() error {
if b == nil {
return nil
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 9705d6c..302a749 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -49,6 +49,9 @@
"l_nl": []byte("a/a/a\na/a/b\nc\n"),
"l_sp": []byte("a/a/a a/a/b c"),
"l2": []byte("missing\n"),
+ "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"),
+ "@ -> c": nil,
+ "foo'bar -> c": nil,
"manifest.txt": fileCustomManifest,
})
@@ -247,6 +250,19 @@
},
},
{
+ name: "rsp",
+ args: fileArgsBuilder().
+ RspFile("rsp"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("a/a/a", fileA, zip.Deflate),
+ fh("a/a/b", fileB, zip.Deflate),
+ fh("@", fileC, zip.Deflate),
+ fh("foo'bar", fileC, zip.Deflate),
+ },
+ },
+ {
name: "prefix in zip",
args: fileArgsBuilder().
PathPrefixInZip("foo").
@@ -568,6 +584,11 @@
in: `./cmd "\""-C`,
out: []string{"./cmd", `"-C`},
},
+ {
+ name: "ninja rsp file",
+ in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'",
+ out: []string{"a", "b", "@", "foo'bar", `foo"bar`},
+ },
}
for _, testCase := range testCases {