Merge "Deprecate USE_GOMA and replace with FORCE_USE_GOMA"
diff --git a/android/api_levels.go b/android/api_levels.go
index 0872066..ddcdbb7 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -24,6 +24,192 @@
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,37 @@
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,
+ "R": 30,
+ }
+
+ 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/arch.go b/android/arch.go
index 8500bc7..4141138 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -125,6 +125,7 @@
Arm64: {
"armv8_a",
"armv8_2a",
+ "armv8-2a-dotprod",
"cortex-a53",
"cortex-a55",
"cortex-a72",
@@ -172,6 +173,9 @@
Arm: {
"neon",
},
+ Arm64: {
+ "dotprod",
+ },
X86: {
"ssse3",
"sse4",
@@ -209,6 +213,11 @@
"neon",
},
},
+ Arm64: {
+ "armv8-2a-dotprod": {
+ "dotprod",
+ },
+ },
X86: {
"amberlake": {
"ssse3",
@@ -1628,9 +1637,10 @@
{"arm64", "armv8-a", "kryo", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "exynos-m1", []string{"arm64-v8a"}},
{"arm64", "armv8-a", "exynos-m2", []string{"arm64-v8a"}},
- {"arm64", "armv8-2a", "cortex-a75", []string{"arm64-v8a"}},
- {"arm64", "armv8-2a", "cortex-a76", []string{"arm64-v8a"}},
{"arm64", "armv8-2a", "kryo385", []string{"arm64-v8a"}},
+ {"arm64", "armv8-2a-dotprod", "cortex-a55", []string{"arm64-v8a"}},
+ {"arm64", "armv8-2a-dotprod", "cortex-a75", []string{"arm64-v8a"}},
+ {"arm64", "armv8-2a-dotprod", "cortex-a76", []string{"arm64-v8a"}},
{"x86", "", "", []string{"x86"}},
{"x86", "atom", "", []string{"x86"}},
{"x86", "haswell", "", []string{"x86"}},
diff --git a/android/config.go b/android/config.go
index dd622e5..1c06e8c 100644
--- a/android/config.go
+++ b/android/config.go
@@ -642,8 +642,34 @@
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 003a9df..374986e 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -18,7 +18,6 @@
"bytes"
"fmt"
"sort"
- "strconv"
"strings"
"github.com/google/blueprint"
@@ -31,7 +30,7 @@
}
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/apex/apex_test.go b/apex/apex_test.go
index 610f667..5c49667 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -2282,30 +2282,40 @@
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 TestApex_withPrebuiltFirmware(t *testing.T) {
+ testCases := []struct {
+ name string
+ additionalProp string
+ }{
+ {"system apex with prebuilt_firmware", ""},
+ {"vendor apex with prebuilt_firmware", "vendor: true,"},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx, _ := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ prebuilts: ["myfirmware"],
+ `+tc.additionalProp+`
+ }
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+ prebuilt_firmware {
+ name: "myfirmware",
+ src: "myfirmware.bin",
+ filename_from_src: true,
+ `+tc.additionalProp+`
+ }
+ `)
+ ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+ "etc/firmware/myfirmware.bin",
+ })
+ })
+ }
}
func TestAndroidMk_UseVendorRequired(t *testing.T) {
diff --git a/cc/Android.bp b/cc/Android.bp
index 831911e..ff2cdf3 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -13,6 +13,7 @@
],
srcs: [
"androidmk.go",
+ "api_level.go",
"builder.go",
"cc.go",
"ccdeps.go",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 380b4e9..5bdbac6 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -451,7 +451,7 @@
}
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 0000000..c93d6ed
--- /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
+}
diff --git a/cc/cc.go b/cc/cc.go
index 70229be..b5a0261 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -629,7 +629,7 @@
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 @@
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 @@
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/arm64_device.go b/cc/config/arm64_device.go
index 62d8cc8..e6024aa 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -34,6 +34,9 @@
"armv8-2a": []string{
"-march=armv8.2-a",
},
+ "armv8-2a-dotprod": []string{
+ "-march=armv8.2-a+dotprod",
+ },
}
arm64Ldflags = []string{
@@ -100,6 +103,7 @@
pctx.StaticVariable("Arm64ClangArmv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
pctx.StaticVariable("Arm64ClangArmv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
+ pctx.StaticVariable("Arm64ClangArmv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
pctx.StaticVariable("Arm64ClangCortexA53Cflags",
strings.Join(arm64ClangCpuVariantCflags["cortex-a53"], " "))
@@ -121,6 +125,7 @@
arm64ClangArchVariantCflagsVar = map[string]string{
"armv8-a": "${config.Arm64ClangArmv8ACflags}",
"armv8-2a": "${config.Arm64ClangArmv82ACflags}",
+ "armv8-2a-dotprod": "${config.Arm64ClangArmv82ADotprodCflags}",
}
arm64ClangCpuVariantCflagsVar = map[string]string{
@@ -198,6 +203,7 @@
switch arch.ArchVariant {
case "armv8-a":
case "armv8-2a":
+ case "armv8-2a-dotprod":
// Nothing extra for armv8-a/armv8-2a
default:
panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant))
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 7db405c..441bff2 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -42,7 +42,6 @@
"-Wno-literal-suffix",
"-Wno-maybe-uninitialized",
"-Wno-old-style-declaration",
- "-Wno-psabi",
"-Wno-unused-but-set-parameter",
"-Wno-unused-but-set-variable",
"-Wno-unused-local-typedefs",
@@ -93,7 +92,9 @@
// 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{}
+var ClangTidyDisableChecks = []string{
+ "misc-no-recursion",
+}
func init() {
pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{
@@ -103,6 +104,10 @@
// not emit the table by default on Android since NDK still uses GNU binutils.
"-faddrsig",
+ // Turn on -fcommon explicitly, since Clang now defaults to -fno-common. The cleanup bug
+ // tracking this is http://b/151457797.
+ "-fcommon",
+
// Help catch common 32/64-bit errors.
"-Werror=int-conversion",
@@ -183,6 +188,8 @@
"-Wno-enum-enum-conversion", // http://b/154138986
"-Wno-enum-float-conversion", // http://b/154255917
"-Wno-pessimizing-move", // http://b/154270751
+ // New warnings to be fixed after clang-r399163
+ "-Wno-non-c-typedef-for-linkage", // http://b/161304145
}, " "))
// Extra cflags for external third-party projects to disable warnings that
@@ -205,6 +212,9 @@
"-Wno-xor-used-as-pow",
// http://b/145211022
"-Wno-final-dtor-non-final-class",
+
+ // http://b/165945989
+ "-Wno-psabi",
}, " "))
}
diff --git a/cc/config/global.go b/cc/config/global.go
index 32f163d..f9b3cc8 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -114,6 +114,12 @@
noOverrideGlobalCflags = []string{
"-Werror=int-to-pointer-cast",
"-Werror=pointer-to-int-cast",
+ // http://b/161386391 for -Wno-void-pointer-to-enum-cast
+ "-Wno-void-pointer-to-enum-cast",
+ // http://b/161386391 for -Wno-void-pointer-to-int-cast
+ "-Wno-void-pointer-to-int-cast",
+ // http://b/161386391 for -Wno-pointer-to-int-cast
+ "-Wno-pointer-to-int-cast",
"-Werror=fortify-source",
}
@@ -126,12 +132,10 @@
ExperimentalCStdVersion = "gnu11"
ExperimentalCppStdVersion = "gnu++2a"
- NdkMaxPrebuiltVersionInt = 27
-
// prebuilts/clang default settings.
ClangDefaultBase = "prebuilts/clang/host"
- ClangDefaultVersion = "clang-r383902b"
- ClangDefaultShortVersion = "11.0.2"
+ ClangDefaultVersion = "clang-r399163"
+ ClangDefaultShortVersion = "11.0.4"
// Directories with warnings from Android.bp files.
WarningAllowedProjects = []string{
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index b5b5553..b77df79 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -39,6 +39,9 @@
// Get 64-bit off_t and related functions.
"-D_FILE_OFFSET_BITS=64",
+ // Don't adjust the layout of bitfields like msvc does.
+ "-mno-ms-bitfields",
+
"--sysroot ${WindowsGccRoot}/${WindowsGccTriple}",
}
windowsClangCflags = append(ClangFilterUnknownCflags(windowsCflags), []string{}...)
diff --git a/cc/lto.go b/cc/lto.go
index 9868cdf..e034337 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -52,6 +52,9 @@
// Use clang lld instead of gnu ld.
Use_clang_lld *bool
+
+ // Use -fwhole-program-vtables cflag.
+ Whole_program_vtables *bool
}
type lto struct {
@@ -97,6 +100,10 @@
flags.Local.CFlags = append(flags.Local.CFlags, ltoFlag)
flags.Local.LdFlags = append(flags.Local.LdFlags, ltoFlag)
+ if Bool(lto.Properties.Whole_program_vtables) {
+ flags.Local.CFlags = append(flags.Local.CFlags, "-fwhole-program-vtables")
+ }
+
if ctx.Config().IsEnvTrue("USE_THINLTO_CACHE") && Bool(lto.Properties.Lto.Thin) && lto.useClangLld(ctx) {
// Set appropriate ThinLTO cache policy
cacheDirFormat := "-Wl,--thinlto-cache-dir="
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index fe3efc0..4c6d98c 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -16,7 +16,6 @@
import (
"fmt"
- "strconv"
"strings"
"sync"
@@ -52,6 +51,10 @@
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 @@
// 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 @@
versionScriptPath android.ModuleGenPath
parsedCoverageXmlPath android.ModuleOutPath
installPath android.Path
+
+ apiLevel android.ApiLevel
+ firstVersion android.ApiLevel
+ unversionedUntil android.ApiLevel
}
-// 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
-}
-
-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()
+ from android.ApiLevel, perSplit func(*Module, android.ApiLevel)) {
- firstSupportedVersion, err := normalizeNdkApiLevel(ctx, propValue,
- ctx.Arch())
- if err != nil {
- ctx.PropertyErrorf(propName, err.Error())
+ 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())
+ }
}
-
- 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))
- }
- 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 @@
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 @@
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) 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) 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 @@
}
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)
}
diff --git a/cc/stl.go b/cc/stl.go
index e18fe95..406fa3a 100644
--- a/cc/stl.go
+++ b/cc/stl.go
@@ -17,7 +17,6 @@
import (
"android/soong/android"
"fmt"
- "strconv"
)
func getNdkStlFamily(m LinkableInterface) string {
@@ -136,23 +135,8 @@
}
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/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 5dd2a86..8e35679 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -172,13 +172,7 @@
}
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
+ return p.installDirBase
}
func (p *PrebuiltEtc) Installable() bool {
@@ -205,7 +199,13 @@
ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
}
- p.installDirPath = android.PathForModuleInstall(ctx, p.BaseDir(), p.SubDir())
+ // 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
+ }
+ p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
// This ensures that outputFilePath has the correct name for others to
// use, as the source file may have a different name.
diff --git a/java/dex.go b/java/dex.go
index 21a5926..055d479 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -135,6 +135,7 @@
"$r8Template": &remoteexec.REParams{
Labels: map[string]string{"type": "compile", "compiler": "r8"},
Inputs: []string{"$implicits", "${config.R8Jar}"},
+ OutputFiles: []string{"${outUsage}"},
ExecStrategy: "${config.RER8ExecStrategy}",
ToolchainInputs: []string{"${config.JavaCmd}"},
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
diff --git a/java/droiddoc.go b/java/droiddoc.go
index e39a556..85a61dd 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1298,6 +1298,7 @@
cmd.BuiltTool(ctx, "metalava").
Flag(config.JavacVmFlags).
+ Flag("-J--add-opens=java.base/java.util=ALL-UNNAMED").
FlagWithArg("-encoding ", "UTF-8").
FlagWithArg("-source ", javaVersion.String()).
FlagWithRspFileInputList("@", srcs).
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index b6af3bf..61a9b97 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -92,31 +92,34 @@
// stubFlagsRule creates the rule to build hiddenapi-stub-flags.txt out of dex jars from stub modules and boot image
// modules.
func stubFlagsRule(ctx android.SingletonContext) {
- // Public API stubs
- publicStubModules := []string{
- "android_stubs_current",
+ var publicStubModules []string
+ var systemStubModules []string
+ var testStubModules []string
+ var corePlatformStubModules []string
+
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ // Build configuration mandates using prebuilt stub modules
+ publicStubModules = append(publicStubModules, "sdk_public_current_android")
+ systemStubModules = append(systemStubModules, "sdk_system_current_android")
+ testStubModules = append(testStubModules, "sdk_test_current_android")
+ } else {
+ // Use stub modules built from source
+ publicStubModules = append(publicStubModules, "android_stubs_current")
+ systemStubModules = append(systemStubModules, "android_system_stubs_current")
+ testStubModules = append(testStubModules, "android_test_stubs_current")
}
+ // We do not have prebuilts of the core platform api yet
+ corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
// 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().AlwaysUsePrebuiltSdks() {
- publicStubModules = append(publicStubModules, "android.test.base.stubs")
- }
-
- // System API stubs
- systemStubModules := []string{
- "android_system_stubs_current",
- }
-
- // Test API stubs
- testStubModules := []string{
- "android_test_stubs_current",
- }
-
- // Core Platform API stubs
- corePlatformStubModules := []string{
- "legacy.core.platform.api.stubs",
+ if inList("android.test.base", ctx.Config().BootJars()) {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ publicStubModules = append(publicStubModules, "sdk_public_current_android.test.base")
+ } else {
+ publicStubModules = append(publicStubModules, "android.test.base.stubs")
+ }
}
// Allow products to define their own stubs for custom product jars that apps can use.
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index bcca93a..dbdab7a 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -16,8 +16,11 @@
import (
"android/soong/android"
+ "fmt"
"strings"
"testing"
+
+ "github.com/google/blueprint/proptools"
)
func testConfigWithBootJars(bp string, bootJars []string) android.Config {
@@ -32,19 +35,30 @@
return ctx
}
-func testHiddenAPI(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) {
+func testHiddenAPIWithConfig(t *testing.T, config android.Config) *android.TestContext {
t.Helper()
- config := testConfigWithBootJars(bp, bootJars)
ctx := testContextWithHiddenAPI()
run(t, ctx, config)
+ return ctx
+}
- return ctx, config
+func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string) (*android.TestContext, android.Config) {
+ config := testConfigWithBootJars(bp, bootJars)
+
+ return testHiddenAPIWithConfig(t, config), config
+}
+
+func testHiddenAPIUnbundled(t *testing.T, unbundled bool) (*android.TestContext, android.Config) {
+ config := testConfig(nil, ``, nil)
+ config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(unbundled)
+
+ return testHiddenAPIWithConfig(t, config), config
}
func TestHiddenAPISingleton(t *testing.T) {
- ctx, _ := testHiddenAPI(t, `
+ ctx, _ := testHiddenAPIBootJars(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -61,7 +75,7 @@
}
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
- ctx, _ := testHiddenAPI(t, `
+ ctx, _ := testHiddenAPIBootJars(t, `
java_import {
name: "foo",
jars: ["a.jar"],
@@ -78,7 +92,7 @@
}
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
- ctx, _ := testHiddenAPI(t, `
+ ctx, _ := testHiddenAPIBootJars(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -107,7 +121,7 @@
}
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
- ctx, _ := testHiddenAPI(t, `
+ ctx, _ := testHiddenAPIBootJars(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -134,3 +148,72 @@
t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
}
}
+
+func TestHiddenAPISingletonSdks(t *testing.T) {
+ testCases := []struct {
+ name string
+ unbundledBuild bool
+ publicStub string
+ systemStub string
+ testStub string
+ corePlatformStub string
+ }{
+ {
+ name: "testBundled",
+ unbundledBuild: false,
+ publicStub: "android_stubs_current",
+ systemStub: "android_system_stubs_current",
+ testStub: "android_test_stubs_current",
+ corePlatformStub: "legacy.core.platform.api.stubs",
+ }, {
+ name: "testUnbundled",
+ unbundledBuild: true,
+ publicStub: "sdk_public_current_android",
+ systemStub: "sdk_system_current_android",
+ testStub: "sdk_test_current_android",
+ corePlatformStub: "legacy.core.platform.api.stubs",
+ },
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ ctx, _ := testHiddenAPIUnbundled(t, tc.unbundledBuild)
+
+ hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenapiRule := hiddenAPI.Rule("hiddenapi")
+ wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild)
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, wantPublicStubs) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantPublicStubs, hiddenapiRule.RuleParams.Command)
+ }
+
+ wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild)
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, wantSystemStubs) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantSystemStubs, hiddenapiRule.RuleParams.Command)
+ }
+
+ wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild)
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, wantTestStubs) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantTestStubs, hiddenapiRule.RuleParams.Command)
+ }
+
+ wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(tc.corePlatformStub)
+ if !strings.Contains(hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) {
+ t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantCorePlatformStubs, hiddenapiRule.RuleParams.Command)
+ }
+ })
+ }
+}
+
+func generateDexedPath(subDir, dex, module string) string {
+ return fmt.Sprintf("%s/.intermediates/%s/android_common/%s/%s.jar", buildDir, subDir, dex, module)
+}
+
+func generateDexPath(module string) string {
+ return generateDexedPath(module, "dex", module)
+}
+
+func generateSdkDexPath(module string, unbundled bool) string {
+ if unbundled {
+ return generateDexedPath("prebuilts/sdk/"+module, "dex", module)
+ }
+ return generateDexPath(module)
+}
diff --git a/java/testing.go b/java/testing.go
index 322dc9e..a472413 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -88,7 +88,7 @@
"prebuilts/sdk/30/system/api/bar-removed.txt": nil,
"prebuilts/sdk/30/test/api/bar-removed.txt": nil,
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
- "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
+ "prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"], imports_sdk_version: "none", imports_compile_dex:true,}`),
"bin.py": nil,
python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
diff --git a/rust/androidmk.go b/rust/androidmk.go
index edae0e6..5a33f77 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -178,6 +178,10 @@
}
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 cfef57a..394abfc 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -40,7 +40,7 @@
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 664578d..aeb904b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -146,8 +146,13 @@
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 @@
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 56a8ef8..a25523c 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -191,7 +191,7 @@
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/config/arm64_device.go b/rust/config/arm64_device.go
index 7d13c42..21b22a4 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -28,6 +28,7 @@
Arm64ArchVariantRustFlags = map[string][]string{
"armv8-a": []string{},
"armv8-2a": []string{},
+ "armv8-2a-dotprod": []string{},
}
)
diff --git a/rust/config/global.go b/rust/config/global.go
index 6a5251b..71c4240 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.45.2"
+ RustDefaultVersion = "1.46.0"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 73673d0..90155ca 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -154,12 +154,12 @@
}
// 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 a442933..4931f19 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -21,6 +21,11 @@
"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 @@
// 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 @@
// 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 @@
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 @@
setShared()
setStatic()
+ // Set libstd linkage
+ setRlibStd()
+ setDylibStd()
+
// Build a specific library variant
BuildOnlyFFI()
BuildOnlyRust()
@@ -121,6 +137,10 @@
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 @@
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 @@
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 @@
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 @@
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 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 f1bc050..fec3992 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -37,7 +37,7 @@
}`)
// 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 @@
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 @@
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 @@
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 b98992c..e561477 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -40,6 +40,7 @@
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 @@
Dylibs []string
Rlibs []string
Rustlibs []string
+ Stdlibs []string
ProcMacros []string
SharedLibs []string
StaticLibs []string
@@ -293,7 +295,7 @@
Disabled() bool
SetDisabled()
- static() bool
+ staticStd(ctx *depsContext) bool
}
type exportedFlagsProducer interface {
@@ -782,14 +784,15 @@
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 @@
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 @@
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 89ce359..4842a4c 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -189,7 +189,7 @@
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 @@
}
`)
- 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 @@
// 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 @@
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 d93fc31..0679448 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -133,3 +133,7 @@
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 2382b18..fea2ad0 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -17,6 +17,8 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
func TestRustTest(t *testing.T) {
@@ -33,3 +35,35 @@
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 0144c82..ee303ed 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -32,6 +32,7 @@
srcs: ["libstd.so"],
},
host_supported: true,
+ sysroot: true,
}
rust_prebuilt_library {
name: "libtest_x86_64-unknown-linux-gnu",
@@ -43,6 +44,7 @@
srcs: ["libtest.so"],
},
host_supported: true,
+ sysroot: true,
}
rust_prebuilt_library {
name: "libstd_x86_64-apple-darwin",
@@ -54,6 +56,7 @@
srcs: ["libstd.so"],
},
host_supported: true,
+ sysroot: true,
}
rust_prebuilt_library {
name: "libtest_x86_64-apple-darwin",
@@ -65,6 +68,7 @@
srcs: ["libtest.so"],
},
host_supported: true,
+ sysroot: true,
}
//////////////////////////////
// Device module requirements
@@ -82,6 +86,7 @@
no_stdlibs: true,
host_supported: true,
native_coverage: false,
+ sysroot: true,
}
rust_library {
name: "libtest",
@@ -90,6 +95,7 @@
no_stdlibs: true,
host_supported: true,
native_coverage: false,
+ sysroot: true,
}
rust_library {
name: "libprotobuf",
@@ -134,6 +140,7 @@
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)