diff options
| -rw-r--r-- | android/api_levels.go | 216 | ||||
| -rw-r--r-- | android/config.go | 30 | ||||
| -rw-r--r-- | android/makevars.go | 3 | ||||
| -rw-r--r-- | cc/Android.bp | 1 | ||||
| -rw-r--r-- | cc/androidmk.go | 2 | ||||
| -rw-r--r-- | cc/api_level.go | 71 | ||||
| -rw-r--r-- | cc/cc.go | 15 | ||||
| -rw-r--r-- | cc/config/global.go | 2 | ||||
| -rw-r--r-- | cc/ndk_library.go | 200 | ||||
| -rw-r--r-- | cc/stl.go | 20 | ||||
| -rw-r--r-- | rust/androidmk.go | 4 | ||||
| -rw-r--r-- | rust/binary_test.go | 2 | ||||
| -rw-r--r-- | rust/compiler.go | 19 | ||||
| -rw-r--r-- | rust/compiler_test.go | 2 | ||||
| -rw-r--r-- | rust/coverage_test.go | 4 | ||||
| -rw-r--r-- | rust/library.go | 61 | ||||
| -rw-r--r-- | rust/library_test.go | 54 | ||||
| -rw-r--r-- | rust/rust.go | 47 | ||||
| -rw-r--r-- | rust/rust_test.go | 14 | ||||
| -rw-r--r-- | rust/test.go | 4 | ||||
| -rw-r--r-- | rust/test_test.go | 34 | ||||
| -rw-r--r-- | rust/testing.go | 7 |
22 files changed, 608 insertions, 204 deletions
diff --git a/android/api_levels.go b/android/api_levels.go index 087206633..e5405ca08 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -24,6 +24,192 @@ func init() { RegisterSingletonType("api_levels", ApiLevelsSingleton) } +// An API level, which may be a finalized (numbered) API, a preview (codenamed) +// API, or the future API level (10000). Can be parsed from a string with +// ApiLevelFromUser or ApiLevelOrPanic. +// +// The different *types* of API levels are handled separately. Currently only +// Java has these, and they're managed with the sdkKind enum of the sdkSpec. A +// future cleanup should be to migrate sdkSpec to using ApiLevel instead of its +// sdkVersion int, and to move sdkSpec into this package. +type ApiLevel struct { + // The string representation of the API level. + value string + + // A number associated with the API level. The exact value depends on + // whether this API level is a preview or final API. + // + // For final API levels, this is the assigned version number. + // + // For preview API levels, this value has no meaning except to index known + // previews to determine ordering. + number int + + // Identifies this API level as either a preview or final API level. + isPreview bool +} + +// Returns the canonical name for this API level. For a finalized API level +// this will be the API number as a string. For a preview API level this +// will be the codename, or "current". +func (this ApiLevel) String() string { + return this.value +} + +// Returns true if this is a non-final API level. +func (this ApiLevel) IsPreview() bool { + return this.isPreview +} + +// Returns true if this is the unfinalized "current" API level. This means +// different things across Java and native. Java APIs do not use explicit +// codenames, so all non-final codenames are grouped into "current". For native +// explicit codenames are typically used, and current is the union of all +// non-final APIs, including those that may not yet be in any codename. +// +// Note that in a build where the platform is final, "current" will not be a +// preview API level but will instead be canonicalized to the final API level. +func (this ApiLevel) IsCurrent() bool { + return this.value == "current" +} + +// Returns -1 if the current API level is less than the argument, 0 if they +// are equal, and 1 if it is greater than the argument. +func (this ApiLevel) CompareTo(other ApiLevel) int { + if this.IsPreview() && !other.IsPreview() { + return 1 + } else if !this.IsPreview() && other.IsPreview() { + return -1 + } + + if this.number < other.number { + return -1 + } else if this.number == other.number { + return 0 + } else { + return 1 + } +} + +func (this ApiLevel) EqualTo(other ApiLevel) bool { + return this.CompareTo(other) == 0 +} + +func (this ApiLevel) GreaterThan(other ApiLevel) bool { + return this.CompareTo(other) > 0 +} + +func (this ApiLevel) GreaterThanOrEqualTo(other ApiLevel) bool { + return this.CompareTo(other) >= 0 +} + +func (this ApiLevel) LessThan(other ApiLevel) bool { + return this.CompareTo(other) < 0 +} + +func (this ApiLevel) LessThanOrEqualTo(other ApiLevel) bool { + return this.CompareTo(other) <= 0 +} + +func uncheckedFinalApiLevel(num int) ApiLevel { + return ApiLevel{ + value: strconv.Itoa(num), + number: num, + isPreview: false, + } +} + +// TODO: Merge with FutureApiLevel +var CurrentApiLevel = ApiLevel{ + value: "current", + number: 10000, + isPreview: true, +} + +var NoneApiLevel = ApiLevel{ + value: "(no version)", + // Not 0 because we don't want this to compare equal with the first preview. + number: -1, + isPreview: true, +} + +// The first version that introduced 64-bit ABIs. +var FirstLp64Version = uncheckedFinalApiLevel(21) + +// The first API level that does not require NDK code to link +// libandroid_support. +var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21) + +// If the `raw` input is the codename of an API level has been finalized, this +// function returns the API level number associated with that API level. If the +// input is *not* a finalized codename, the input is returned unmodified. +// +// For example, at the time of writing, R has been finalized as API level 30, +// but S is in development so it has no number assigned. For the following +// inputs: +// +// * "30" -> "30" +// * "R" -> "30" +// * "S" -> "S" +func ReplaceFinalizedCodenames(ctx EarlyModuleContext, raw string) string { + num, ok := getFinalCodenamesMap(ctx.Config())[raw] + if !ok { + return raw + } + + return strconv.Itoa(num) +} + +// Converts the given string `raw` to an ApiLevel, possibly returning an error. +// +// `raw` must be non-empty. Passing an empty string results in a panic. +// +// "current" will return CurrentApiLevel, which is the ApiLevel associated with +// an arbitrary future release (often referred to as API level 10000). +// +// Finalized codenames will be interpreted as their final API levels, not the +// preview of the associated releases. R is now API 30, not the R preview. +// +// Future codenames return a preview API level that has no associated integer. +// +// Inputs that are not "current", known previews, or convertible to an integer +// will return an error. +func ApiLevelFromUser(ctx EarlyModuleContext, raw string) (ApiLevel, error) { + if raw == "" { + panic("API level string must be non-empty") + } + + if raw == "current" { + return CurrentApiLevel, nil + } + + for _, preview := range ctx.Config().PreviewApiLevels() { + if raw == preview.String() { + return preview, nil + } + } + + canonical := ReplaceFinalizedCodenames(ctx, raw) + asInt, err := strconv.Atoi(canonical) + if err != nil { + return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical) + } + + apiLevel := uncheckedFinalApiLevel(asInt) + return apiLevel, nil +} + +// Converts an API level string `raw` into an ApiLevel in the same method as +// `ApiLevelFromUser`, but the input is assumed to have no errors and any errors +// will panic instead of returning an error. +func ApiLevelOrPanic(ctx EarlyModuleContext, raw string) ApiLevel { + value, err := ApiLevelFromUser(ctx, raw) + if err != nil { + panic(err.Error()) + } + return value +} + func ApiLevelsSingleton() Singleton { return &apiLevelsSingleton{} } @@ -52,6 +238,36 @@ func GetApiLevelsJson(ctx PathContext) WritablePath { return PathForOutput(ctx, "api_levels.json") } +var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap") + +func getFinalCodenamesMap(config Config) map[string]int { + return config.Once(finalCodenamesMapKey, func() interface{} { + apiLevelsMap := map[string]int{ + "G": 9, + "I": 14, + "J": 16, + "J-MR1": 17, + "J-MR2": 18, + "K": 19, + "L": 21, + "L-MR1": 22, + "M": 23, + "N": 24, + "N-MR1": 25, + "O": 26, + "O-MR1": 27, + "P": 28, + "Q": 29, + } + + if Bool(config.productVariables.Platform_sdk_final) { + apiLevelsMap["current"] = config.PlatformSdkVersionInt() + } + + return apiLevelsMap + }).(map[string]int) +} + var apiLevelsMapKey = NewOnceKey("ApiLevelsMap") func getApiLevelsMap(config Config) map[string]int { diff --git a/android/config.go b/android/config.go index dd622e5b2..1c06e8c55 100644 --- a/android/config.go +++ b/android/config.go @@ -642,8 +642,34 @@ func (c *config) PlatformBaseOS() string { return String(c.productVariables.Platform_base_os) } -func (c *config) MinSupportedSdkVersion() int { - return 16 +func (c *config) MinSupportedSdkVersion() ApiLevel { + return uncheckedFinalApiLevel(16) +} + +func (c *config) FinalApiLevels() []ApiLevel { + var levels []ApiLevel + for i := 1; i <= c.PlatformSdkVersionInt(); i++ { + levels = append(levels, uncheckedFinalApiLevel(i)) + } + return levels +} + +func (c *config) PreviewApiLevels() []ApiLevel { + var levels []ApiLevel + for i, codename := range c.PlatformVersionActiveCodenames() { + levels = append(levels, ApiLevel{ + value: codename, + number: i, + isPreview: true, + }) + } + return levels +} + +func (c *config) AllSupportedApiLevels() []ApiLevel { + var levels []ApiLevel + levels = append(levels, c.FinalApiLevels()...) + return append(levels, c.PreviewApiLevels()...) } func (c *config) DefaultAppTargetSdkInt() int { diff --git a/android/makevars.go b/android/makevars.go index 003a9df32..374986e84 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -18,7 +18,6 @@ import ( "bytes" "fmt" "sort" - "strconv" "strings" "github.com/google/blueprint" @@ -31,7 +30,7 @@ func init() { } func androidMakeVarsProvider(ctx MakeVarsContext) { - ctx.Strict("MIN_SUPPORTED_SDK_VERSION", strconv.Itoa(ctx.Config().MinSupportedSdkVersion())) + ctx.Strict("MIN_SUPPORTED_SDK_VERSION", ctx.Config().MinSupportedSdkVersion().String()) } /////////////////////////////////////////////////////////////////////////////// diff --git a/cc/Android.bp b/cc/Android.bp index 831911e45..ff2cdf374 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -13,6 +13,7 @@ bootstrap_go_package { ], srcs: [ "androidmk.go", + "api_level.go", "builder.go", "cc.go", "ccdeps.go", diff --git a/cc/androidmk.go b/cc/androidmk.go index 380b4e92f..5bdbac649 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -451,7 +451,7 @@ func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries * } func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.SubName = ndkLibrarySuffix + "." + c.properties.ApiLevel + entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String() entries.Class = "SHARED_LIBRARIES" entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) { diff --git a/cc/api_level.go b/cc/api_level.go new file mode 100644 index 000000000..c93d6eda3 --- /dev/null +++ b/cc/api_level.go @@ -0,0 +1,71 @@ +// 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 cc + +import ( + "fmt" + + "android/soong/android" +) + +func minApiForArch(ctx android.BaseModuleContext, + arch android.ArchType) android.ApiLevel { + + switch arch { + case android.Arm, android.X86: + return ctx.Config().MinSupportedSdkVersion() + case android.Arm64, android.X86_64: + return android.FirstLp64Version + default: + panic(fmt.Errorf("Unknown arch %q", arch)) + } +} + +func nativeApiLevelFromUser(ctx android.BaseModuleContext, + raw string) (android.ApiLevel, error) { + + min := minApiForArch(ctx, ctx.Arch().ArchType) + if raw == "minimum" { + return min, nil + } + + value, err := android.ApiLevelFromUser(ctx, raw) + if err != nil { + return android.NoneApiLevel, err + } + + if value.LessThan(min) { + return min, nil + } + + return value, nil +} + +func nativeApiLevelFromUserWithDefault(ctx android.BaseModuleContext, + raw string, defaultValue string) (android.ApiLevel, error) { + if raw == "" { + raw = defaultValue + } + return nativeApiLevelFromUser(ctx, raw) +} + +func nativeApiLevelOrPanic(ctx android.BaseModuleContext, + raw string) android.ApiLevel { + value, err := nativeApiLevelFromUser(ctx, raw) + if err != nil { + panic(err.Error()) + } + return value +} @@ -629,7 +629,7 @@ func (c *Module) Toc() android.OptionalPath { func (c *Module) ApiLevel() string { if c.linker != nil { if stub, ok := c.linker.(*stubDecorator); ok { - return stub.properties.ApiLevel + return stub.apiLevel.String() } } panic(fmt.Errorf("ApiLevel() called on non-stub library module: %q", c.BaseModuleName())) @@ -1682,11 +1682,13 @@ func (c *Module) begin(ctx BaseModuleContext) { feature.begin(ctx) } if ctx.useSdk() && c.IsSdkVariant() { - version, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch()) + version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", err.Error()) + c.Properties.Sdk_version = nil + } else { + c.Properties.Sdk_version = StringPtr(version.String()) } - c.Properties.Sdk_version = StringPtr(version) } } @@ -3119,13 +3121,6 @@ func (c *Module) IsSdkVariant() bool { return c.Properties.IsSdkVariant || c.AlwaysSdk() } -func getCurrentNdkPrebuiltVersion(ctx DepsContext) string { - if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt { - return strconv.Itoa(config.NdkMaxPrebuiltVersionInt) - } - return ctx.Config().PlatformSdkVersion() -} - func kytheExtractAllFactory() android.Singleton { return &kytheExtractAllSingleton{} } diff --git a/cc/config/global.go b/cc/config/global.go index 32f163d88..b9f033288 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -126,8 +126,6 @@ var ( ExperimentalCStdVersion = "gnu11" ExperimentalCppStdVersion = "gnu++2a" - NdkMaxPrebuiltVersionInt = 27 - // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" ClangDefaultVersion = "clang-r383902b" diff --git a/cc/ndk_library.go b/cc/ndk_library.go index fe3efc01e..4c6d98c52 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "strconv" "strings" "sync" @@ -52,6 +51,10 @@ var ( ndkKnownLibsLock sync.Mutex ) +// The First_version and Unversioned_until properties of this struct should not +// be used directly, but rather through the ApiLevel returning methods +// firstVersion() and unversionedUntil(). + // Creates a stub shared library based on the provided version file. // // Example: @@ -77,9 +80,7 @@ type libraryProperties struct { // 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 - // "ndkstubgen.py" as it is + // Use via apiLevel on the stubDecorator. ApiLevel string `blueprint:"mutated"` // True if this API is not yet ready to be shipped in the NDK. It will be @@ -96,125 +97,33 @@ type stubDecorator struct { versionScriptPath android.ModuleGenPath parsedCoverageXmlPath android.ModuleOutPath installPath android.Path -} - -// OMG GO -func intMax(a int, b int) int { - if a > b { - return a - } else { - return b - } -} - -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 - } - - minVersion := ctx.Config().MinSupportedSdkVersion() - firstArchVersions := map[android.ArchType]int{ - android.Arm: minVersion, - android.Arm64: 21, - android.X86: minVersion, - android.X86_64: 21, - } - - firstArchVersion, ok := firstArchVersions[arch.ArchType] - if !ok { - panic(fmt.Errorf("Arch %q not found in firstArchVersions", arch.ArchType)) - } - - if apiLevel == "minimum" { - return strconv.Itoa(firstArchVersion), nil - } - // If the NDK drops support for a platform version, we don't want to have to - // fix up every module that was using it as its SDK version. Clip to the - // supported version here instead. - version, err := strconv.Atoi(apiLevel) - if err != nil { - // Non-integer API levels are codenames. - return apiLevel, nil - } - version = intMax(version, minVersion) - - return strconv.Itoa(intMax(version, firstArchVersion)), nil + apiLevel android.ApiLevel + firstVersion android.ApiLevel + unversionedUntil android.ApiLevel } -func getFirstGeneratedVersion(firstSupportedVersion string, platformVersion int) (int, error) { - if firstSupportedVersion == "current" { - return platformVersion + 1, nil - } - - return strconv.Atoi(firstSupportedVersion) -} - -func shouldUseVersionScript(ctx android.BaseModuleContext, stub *stubDecorator) (bool, error) { - // unversioned_until is normally empty, in which case we should use the version script. - if String(stub.properties.Unversioned_until) == "" { - return true, nil - } - - if String(stub.properties.Unversioned_until) == "current" { - if stub.properties.ApiLevel == "current" { - return true, nil - } else { - return false, nil - } - } - - if stub.properties.ApiLevel == "current" { - return true, nil - } - - unversionedUntil, err := android.ApiStrToNum(ctx, String(stub.properties.Unversioned_until)) - if err != nil { - return true, err - } - - version, err := android.ApiStrToNum(ctx, stub.properties.ApiLevel) - if err != nil { - return true, err - } - - return version >= unversionedUntil, nil +func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool { + return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil) } func generatePerApiVariants(ctx android.BottomUpMutatorContext, m *Module, - propName string, propValue string, perSplit func(*Module, string)) { - platformVersion := ctx.Config().PlatformSdkVersionInt() - - firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue, - ctx.Arch()) - if err != nil { - ctx.PropertyErrorf(propName, err.Error()) - } - - firstGenVersion, err := getFirstGeneratedVersion(firstSupportedVersion, - platformVersion) - if err != nil { - // In theory this is impossible because we've already run this through - // normalizeNdkApiLevel above. - ctx.PropertyErrorf(propName, err.Error()) - } - - var versionStrs []string - for version := firstGenVersion; version <= platformVersion; version++ { - versionStrs = append(versionStrs, strconv.Itoa(version)) + from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) { + + var versions []android.ApiLevel + versionStrs := []string{} + for _, version := range ctx.Config().AllSupportedApiLevels() { + if version.GreaterThanOrEqualTo(from) { + versions = append(versions, version) + versionStrs = append(versionStrs, version.String()) + } } - versionStrs = append(versionStrs, ctx.Config().PlatformVersionActiveCodenames()...) - versionStrs = append(versionStrs, "current") + versions = append(versions, android.CurrentApiLevel) + versionStrs = append(versionStrs, android.CurrentApiLevel.String()) modules := ctx.CreateVariations(versionStrs...) for i, module := range modules { - perSplit(module.(*Module), versionStrs[i]) + perSplit(module.(*Module), versions[i]) } } @@ -228,25 +137,56 @@ func NdkApiMutator(ctx android.BottomUpMutatorContext) { ctx.Module().Disable() return } - generatePerApiVariants(ctx, m, "first_version", - String(compiler.properties.First_version), - func(m *Module, version string) { + firstVersion, err := nativeApiLevelFromUser(ctx, + String(compiler.properties.First_version)) + if err != nil { + ctx.PropertyErrorf("first_version", err.Error()) + return + } + generatePerApiVariants(ctx, m, firstVersion, + func(m *Module, version android.ApiLevel) { m.compiler.(*stubDecorator).properties.ApiLevel = - version + version.String() }) } 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 + from, err := nativeApiLevelFromUser(ctx, m.MinSdkVersion()) + if err != nil { + ctx.PropertyErrorf("min_sdk_version", err.Error()) + return + } + generatePerApiVariants(ctx, m, from, + func(m *Module, version android.ApiLevel) { + m.Properties.Sdk_version = StringPtr(version.String()) }) } } } } +func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool { + this.apiLevel = nativeApiLevelOrPanic(ctx, this.properties.ApiLevel) + + var err error + this.firstVersion, err = nativeApiLevelFromUser(ctx, + String(this.properties.First_version)) + if err != nil { + ctx.PropertyErrorf("first_version", err.Error()) + return false + } + + this.unversionedUntil, err = nativeApiLevelFromUserWithDefault(ctx, + String(this.properties.Unversioned_until), "minimum") + if err != nil { + ctx.PropertyErrorf("unversioned_until", err.Error()) + return false + } + + return true +} + func (c *stubDecorator) compilerInit(ctx BaseModuleContext) { c.baseCompiler.compilerInit(ctx) @@ -340,11 +280,16 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O ctx.PropertyErrorf("symbol_file", "must end with .map.txt") } + if !c.initializeProperties(ctx) { + // Emits its own errors, so we don't need to. + return Objects{} + } + symbolFile := String(c.properties.Symbol_file) objs, versionScript := compileStubLibrary(ctx, flags, symbolFile, - c.properties.ApiLevel, "") + c.apiLevel.String(), "") c.versionScriptPath = versionScript - if c.properties.ApiLevel == "current" && ctx.PrimaryArch() { + if c.apiLevel.IsCurrent() && ctx.PrimaryArch() { c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile) } return objs @@ -366,12 +311,7 @@ func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - useVersionScript, err := shouldUseVersionScript(ctx, stub) - if err != nil { - ctx.ModuleErrorf(err.Error()) - } - - if useVersionScript { + if shouldUseVersionScript(ctx, stub) { linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String() flags.Local.LdFlags = append(flags.Local.LdFlags, linkerScriptFlag) flags.LdFlagsDeps = append(flags.LdFlagsDeps, stub.versionScriptPath) @@ -386,8 +326,6 @@ func (stub *stubDecorator) nativeCoverage() bool { func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) { arch := ctx.Target().Arch.ArchType.Name - apiLevel := stub.properties.ApiLevel - // arm64 isn't actually a multilib toolchain, so unlike the other LP64 // architectures it's just installed to lib. libDir := "lib" @@ -396,7 +334,7 @@ func (stub *stubDecorator) install(ctx ModuleContext, path android.Path) { } installDir := getNdkInstallBase(ctx).Join(ctx, fmt.Sprintf( - "platforms/android-%s/arch-%s/usr/%s", apiLevel, arch, libDir)) + "platforms/android-%s/arch-%s/usr/%s", stub.apiLevel, arch, libDir)) stub.installPath = ctx.InstallFile(installDir, path.Base(), path) } @@ -17,7 +17,6 @@ package cc import ( "android/soong/android" "fmt" - "strconv" ) func getNdkStlFamily(m LinkableInterface) string { @@ -136,23 +135,8 @@ func (stl *stl) begin(ctx BaseModuleContext) { } func needsLibAndroidSupport(ctx BaseModuleContext) bool { - versionStr, err := normalizeNdkApiLevel(ctx, ctx.sdkVersion(), ctx.Arch()) - if err != nil { - ctx.PropertyErrorf("sdk_version", err.Error()) - } - - if versionStr == "current" { - return false - } - - version, err := strconv.Atoi(versionStr) - if err != nil { - panic(fmt.Sprintf( - "invalid API level returned from normalizeNdkApiLevel: %q", - versionStr)) - } - - return version < 21 + version := nativeApiLevelOrPanic(ctx, ctx.sdkVersion()) + return version.LessThan(android.FirstNonLibAndroidSupportVersion) } func staticUnwinder(ctx android.BaseModuleContext) string { diff --git a/rust/androidmk.go b/rust/androidmk.go index edae0e63d..5a33f77fa 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -178,6 +178,10 @@ func (proto *protobufDecorator) AndroidMk(ctx AndroidMkContext, ret *android.And } func (compiler *baseCompiler) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + if compiler.path == (android.InstallPath{}) { + return + } + var unstrippedOutputFile android.OptionalPath // Soong installation is only supported for host modules. Have Make // installation trigger Soong installation. diff --git a/rust/binary_test.go b/rust/binary_test.go index cfef57a77..394abfcdd 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -40,7 +40,7 @@ func TestBinaryLinkage(t *testing.T) { 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) { + if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) { t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") } diff --git a/rust/compiler.go b/rust/compiler.go index 664578d82..aeb904b37 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -146,8 +146,13 @@ func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath { panic("baseCompiler does not implement coverageOutputZipPath()") } -func (compiler *baseCompiler) static() bool { - return false +func (compiler *baseCompiler) staticStd(ctx *depsContext) bool { + // For devices, we always link stdlibs in as dylibs by default. + if ctx.Device() { + return false + } else { + return true + } } var _ compiler = (*baseCompiler)(nil) @@ -221,15 +226,7 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { stdlib = stdlib + "_" + ctx.toolchain().RustTriple() } - // 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) - } + deps.Stdlibs = append(deps.Stdlibs, stdlib) } } return deps diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 56a8ef8ac..a25523c05 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -191,7 +191,7 @@ func TestStdDeviceLinkage(t *testing.T) { crate_name: "foo", }`) fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) - fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module) + fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 73673d035..90155ca6e 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -154,12 +154,12 @@ func TestCoverageZip(t *testing.T) { } // Make sure the expected inputs are provided to the zip rule. - if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_cov/librlib.gcno") || + if !android.SuffixInList(fizzZipInputs, "android_arm64_armv8-a_rlib_dylib-std_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") || + if !android.SuffixInList(libfooZipInputs, "android_arm64_armv8-a_rlib_dylib-std_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) } diff --git a/rust/library.go b/rust/library.go index a44293307..4931f1995 100644 --- a/rust/library.go +++ b/rust/library.go @@ -21,6 +21,11 @@ import ( "android/soong/android" ) +var ( + DylibStdlibSuffix = ".dylib-std" + RlibStdlibSuffix = ".rlib-std" +) + func init() { android.RegisterModuleType("rust_library", RustLibraryFactory) android.RegisterModuleType("rust_library_dylib", RustLibraryDylibFactory) @@ -49,6 +54,9 @@ type LibraryCompilerProperties struct { // path to include directories to pass to cc_* modules, only relevant for static/shared variants. Include_dirs []string `android:"path,arch_variant"` + + // Whether this library is part of the Rust toolchain sysroot. + Sysroot *bool } type LibraryMutatedProperties struct { @@ -73,6 +81,9 @@ type LibraryMutatedProperties struct { // This variant is disabled and should not be compiled // (used for SourceProvider variants that produce only source) VariantIsDisabled bool `blueprint:"mutated"` + + // Whether this library variant should be link libstd via rlibs + VariantIsStaticStd bool `blueprint:"mutated"` } type libraryDecorator struct { @@ -91,6 +102,7 @@ type libraryInterface interface { dylib() bool static() bool shared() bool + sysroot() bool // Returns true if the build options for the module have selected a particular build type buildRlib() bool @@ -104,6 +116,10 @@ type libraryInterface interface { setShared() setStatic() + // Set libstd linkage + setRlibStd() + setDylibStd() + // Build a specific library variant BuildOnlyFFI() BuildOnlyRust() @@ -121,6 +137,10 @@ func (library *libraryDecorator) rlib() bool { return library.MutatedProperties.VariantIsRlib } +func (library *libraryDecorator) sysroot() bool { + return Bool(library.Properties.Sysroot) +} + func (library *libraryDecorator) dylib() bool { return library.MutatedProperties.VariantIsDylib } @@ -133,6 +153,11 @@ func (library *libraryDecorator) static() bool { return library.MutatedProperties.VariantIsStatic } +func (library *libraryDecorator) staticStd(ctx *depsContext) bool { + // libraries should only request the staticStd when building a static FFI or when variant is staticStd + return library.static() || library.MutatedProperties.VariantIsStaticStd +} + func (library *libraryDecorator) buildRlib() bool { return library.MutatedProperties.BuildRlib && BoolDefault(library.Properties.Rlib.Enabled, true) } @@ -163,6 +188,14 @@ func (library *libraryDecorator) setDylib() { library.MutatedProperties.VariantIsShared = false } +func (library *libraryDecorator) setRlibStd() { + library.MutatedProperties.VariantIsStaticStd = true +} + +func (library *libraryDecorator) setDylibStd() { + library.MutatedProperties.VariantIsStaticStd = false +} + func (library *libraryDecorator) setShared() { library.MutatedProperties.VariantIsStatic = false library.MutatedProperties.VariantIsShared = true @@ -450,6 +483,13 @@ func (library *libraryDecorator) getStem(ctx ModuleContext) string { return stem + String(library.baseCompiler.Properties.Suffix) } +func (library *libraryDecorator) install(ctx ModuleContext) { + // Only shared and dylib variants make sense to install. + if library.shared() || library.dylib() { + library.baseCompiler.install(ctx) + } +} + func (library *libraryDecorator) Disabled() bool { return library.MutatedProperties.VariantIsDisabled } @@ -493,7 +533,6 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { 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. @@ -515,3 +554,23 @@ func LibraryMutator(mctx android.BottomUpMutatorContext) { } } } + +func LibstdMutator(mctx android.BottomUpMutatorContext) { + if m, ok := mctx.Module().(*Module); ok && m.compiler != nil && !m.compiler.Disabled() { + switch library := m.compiler.(type) { + case libraryInterface: + // Only create a variant if a library is actually being built. + if library.rlib() && !library.sysroot() { + variants := []string{"rlib-std", "dylib-std"} + modules := mctx.CreateLocalVariations(variants...) + + rlib := modules[0].(*Module) + dylib := modules[1].(*Module) + rlib.compiler.(libraryInterface).setRlibStd() + dylib.compiler.(libraryInterface).setDylibStd() + rlib.Properties.SubName += RlibStdlibSuffix + dylib.Properties.SubName += DylibStdlibSuffix + } + } + } +} diff --git a/rust/library_test.go b/rust/library_test.go index f1bc0507b..fec3992aa 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -37,7 +37,7 @@ func TestLibraryVariants(t *testing.T) { }`) // Test all variants are being built. - libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib").Output("libfoo.rlib") + libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Output("libfoo.rlib") libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Output("libfoo.dylib.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") @@ -182,14 +182,14 @@ func TestAutoDeps(t *testing.T) { rustlibs: ["libbar"], }`) - libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib") + libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std") 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.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("libbar not present as rlib dependency in static lib") } if android.InList("libbar", static.Module().(*Module).Properties.AndroidMkDylibs) { t.Errorf("libbar present as dynamic dependency in static lib") @@ -200,8 +200,8 @@ func TestAutoDeps(t *testing.T) { 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") + if android.InList("libbar.dylib-std", dyn.Module().(*Module).Properties.AndroidMkRlibs) { + t.Errorf("libbar present as rlib dependency in dynamic lib") } } @@ -238,3 +238,45 @@ func TestStrippedLibrary(t *testing.T) { t.Errorf("stripped version of bar has been generated") } } + +func TestLibstdLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + } + rust_ffi { + name: "libbar", + srcs: ["foo.rs"], + crate_name: "bar", + rustlibs: ["libfoo"], + }`) + + libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) + libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) + + libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module) + libbarStatic := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module().(*Module) + + if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) { + t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib") + } + if !android.InList("libstd", libfooRlibDynamic.Properties.AndroidMkDylibs) { + t.Errorf("dylib-std variant for device rust_library_rlib does not link libstd as an dylib") + } + if !android.InList("libstd", libfooDylib.Properties.AndroidMkDylibs) { + t.Errorf("Device rust_library_dylib does not link libstd as an dylib") + } + + if !android.InList("libstd", libbarShared.Properties.AndroidMkDylibs) { + t.Errorf("Device rust_ffi_shared does not link libstd as an dylib") + } + if !android.InList("libstd", libbarStatic.Properties.AndroidMkRlibs) { + t.Errorf("Device rust_ffi_static does not link libstd as an rlib") + } + if !android.InList("libfoo.rlib-std", libbarStatic.Properties.AndroidMkRlibs) { + t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant") + } +} diff --git a/rust/rust.go b/rust/rust.go index b98992c9b..e5614770b 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -40,6 +40,7 @@ func init() { android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel() ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) pctx.Import("android/soong/rust/config") @@ -237,6 +238,7 @@ type Deps struct { Dylibs []string Rlibs []string Rustlibs []string + Stdlibs []string ProcMacros []string SharedLibs []string StaticLibs []string @@ -293,7 +295,7 @@ type compiler interface { Disabled() bool SetDisabled() - static() bool + staticStd(ctx *depsContext) bool } type exportedFlagsProducer interface { @@ -782,14 +784,15 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { directDylibDeps = append(directDylibDeps, rustDep) mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, depName) case rlibDepTag: + rlib, ok := rustDep.compiler.(libraryInterface) if !ok || !rlib.rlib() { - ctx.ModuleErrorf("mod %q not an rlib library", depName) + ctx.ModuleErrorf("mod %q not an rlib library", depName+rustDep.Properties.SubName) return } depPaths.coverageFiles = append(depPaths.coverageFiles, rustDep.CoverageFiles()...) directRlibDeps = append(directRlibDeps, rustDep) - mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName) + mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, depName+rustDep.Properties.SubName) case procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, depName) @@ -976,8 +979,19 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { commonDepVariations = append(commonDepVariations, blueprint.Variation{Mutator: "image", Variation: android.CoreVariation}) } + stdLinkage := "dylib-std" + if mod.compiler.staticStd(ctx) { + stdLinkage = "rlib-std" + } + + rlibDepVariations := commonDepVariations + if lib, ok := mod.compiler.(libraryInterface); !ok || !lib.sysroot() { + rlibDepVariations = append(rlibDepVariations, + blueprint.Variation{Mutator: "rust_stdlinkage", Variation: stdLinkage}) + } + actx.AddVariationDependencies( - append(commonDepVariations, []blueprint.Variation{ + append(rlibDepVariations, []blueprint.Variation{ {Mutator: "rust_libraries", Variation: "rlib"}}...), rlibDepTag, deps.Rlibs...) actx.AddVariationDependencies( @@ -987,12 +1001,27 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { 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...) + if autoDep.depTag == rlibDepTag { + actx.AddVariationDependencies( + append(rlibDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}), + autoDep.depTag, deps.Rustlibs...) + } else { + actx.AddVariationDependencies( + append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: autoDep.variation}), + autoDep.depTag, deps.Rustlibs...) + } + } + if deps.Stdlibs != nil { + if mod.compiler.staticStd(ctx) { + actx.AddVariationDependencies( + append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "rlib"}), + rlibDepTag, deps.Stdlibs...) + } else { + actx.AddVariationDependencies( + append(commonDepVariations, blueprint.Variation{Mutator: "rust_libraries", Variation: "dylib"}), + dylibDepTag, deps.Stdlibs...) + } } - actx.AddVariationDependencies(append(commonDepVariations, blueprint.Variation{Mutator: "link", Variation: "shared"}), cc.SharedDepTag(), deps.SharedLibs...) diff --git a/rust/rust_test.go b/rust/rust_test.go index 89ce35919..4842a4ca8 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -189,7 +189,7 @@ func TestDepsTracking(t *testing.T) { t.Errorf("Dylib dependency not detected (dependency missing from AndroidMkDylibs)") } - if !android.InList("librlib", module.Properties.AndroidMkRlibs) { + if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) { t.Errorf("Rlib dependency not detected (dependency missing from AndroidMkRlibs)") } @@ -253,7 +253,7 @@ func TestSourceProviderDeps(t *testing.T) { } `) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Rule("rustc") + libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").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()) } @@ -279,15 +279,15 @@ func TestSourceProviderDeps(t *testing.T) { // 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) { + if !android.InList("libbindings.dylib-std", 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) { + if !android.InList("libbindings.dylib-std", 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) { + if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) { t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") } @@ -365,6 +365,6 @@ func TestMultilib(t *testing.T) { crate_name: "foo", }`) - _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib") - _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib") + _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std") + _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std") } diff --git a/rust/test.go b/rust/test.go index d93fc313f..067944858 100644 --- a/rust/test.go +++ b/rust/test.go @@ -133,3 +133,7 @@ func RustTestHostFactory() android.Module { module, _ := NewRustTest(android.HostSupported) return module.Init() } + +func (test *testDecorator) staticStd(ctx *depsContext) bool { + return true +} diff --git a/rust/test_test.go b/rust/test_test.go index 2382b1848..fea2ad059 100644 --- a/rust/test_test.go +++ b/rust/test_test.go @@ -17,6 +17,8 @@ package rust import ( "strings" "testing" + + "android/soong/android" ) func TestRustTest(t *testing.T) { @@ -33,3 +35,35 @@ func TestRustTest(t *testing.T) { t.Errorf("wrong output path: %v; expected: %v", outPath, expectedOut) } } + +func TestRustTestLinkage(t *testing.T) { + ctx := testRust(t, ` + rust_test { + name: "my_test", + srcs: ["foo.rs"], + rustlibs: ["libfoo"], + rlibs: ["libbar"], + } + rust_library { + name: "libfoo", + srcs: ["foo.rs"], + crate_name: "foo", + } + rust_library { + name: "libbar", + srcs: ["foo.rs"], + crate_name: "bar", + }`) + + testingModule := ctx.ModuleForTests("my_test", "android_arm64_armv8-a").Module().(*Module) + + if !android.InList("libfoo.rlib-std", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("rlib-std variant for libfoo not detected as a rustlib-defined rlib dependency for device rust_test module") + } + if !android.InList("libbar.rlib-std", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("rlib-std variant for libbar not detected as an rlib dependency for device rust_test module") + } + if !android.InList("libstd", testingModule.Properties.AndroidMkRlibs) { + t.Errorf("Device rust_test module 'my_test' does not link libstd as an rlib") + } +} diff --git a/rust/testing.go b/rust/testing.go index 0144c8218..ee303ed02 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -32,6 +32,7 @@ func GatherRequiredDepsForTest() string { srcs: ["libstd.so"], }, host_supported: true, + sysroot: true, } rust_prebuilt_library { name: "libtest_x86_64-unknown-linux-gnu", @@ -43,6 +44,7 @@ func GatherRequiredDepsForTest() string { srcs: ["libtest.so"], }, host_supported: true, + sysroot: true, } rust_prebuilt_library { name: "libstd_x86_64-apple-darwin", @@ -54,6 +56,7 @@ func GatherRequiredDepsForTest() string { srcs: ["libstd.so"], }, host_supported: true, + sysroot: true, } rust_prebuilt_library { name: "libtest_x86_64-apple-darwin", @@ -65,6 +68,7 @@ func GatherRequiredDepsForTest() string { srcs: ["libtest.so"], }, host_supported: true, + sysroot: true, } ////////////////////////////// // Device module requirements @@ -82,6 +86,7 @@ func GatherRequiredDepsForTest() string { no_stdlibs: true, host_supported: true, native_coverage: false, + sysroot: true, } rust_library { name: "libtest", @@ -90,6 +95,7 @@ func GatherRequiredDepsForTest() string { no_stdlibs: true, host_supported: true, native_coverage: false, + sysroot: true, } rust_library { name: "libprotobuf", @@ -134,6 +140,7 @@ func CreateTestContext() *android.TestContext { ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { // rust mutators ctx.BottomUp("rust_libraries", LibraryMutator).Parallel() + ctx.BottomUp("rust_stdlinkage", LibstdMutator).Parallel() ctx.BottomUp("rust_begin", BeginMutator).Parallel() }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) |