Add sdk mutator for native modules
Compiling native modules against the NDK disables platform features like ASAN. For anything shipped on the system image there is no reason to compile against the NDK. Add a new mutator to Soong that creates a platform and an SDK variant for modules that set sdk_version, and ignore sdk_version for the platform variant. The SDK variant will be used for embedding in APKs that may be installed on older platforms. Apexes use their own variants that enforce backwards compatibility. Test: sdk_test.go Test: TestJNIPackaging Bug: 149591340 Change-Id: I7d72934aaee2e1326cc0ba5f29f51f14feec4521
This commit is contained in:
parent
b358ebb759
commit
82e192c3ae
|
@ -186,6 +186,7 @@ bootstrap_go_package {
|
||||||
"cc/rs.go",
|
"cc/rs.go",
|
||||||
"cc/sanitize.go",
|
"cc/sanitize.go",
|
||||||
"cc/sabi.go",
|
"cc/sabi.go",
|
||||||
|
"cc/sdk.go",
|
||||||
"cc/snapshot_utils.go",
|
"cc/snapshot_utils.go",
|
||||||
"cc/stl.go",
|
"cc/stl.go",
|
||||||
"cc/strip.go",
|
"cc/strip.go",
|
||||||
|
|
|
@ -53,6 +53,7 @@ func init() {
|
||||||
AddNeverAllowRules(createLibcoreRules()...)
|
AddNeverAllowRules(createLibcoreRules()...)
|
||||||
AddNeverAllowRules(createMediaRules()...)
|
AddNeverAllowRules(createMediaRules()...)
|
||||||
AddNeverAllowRules(createJavaDeviceForHostRules()...)
|
AddNeverAllowRules(createJavaDeviceForHostRules()...)
|
||||||
|
AddNeverAllowRules(createCcSdkVariantRules()...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a NeverAllow rule to the set of rules to apply.
|
// Add a NeverAllow rule to the set of rules to apply.
|
||||||
|
@ -175,6 +176,37 @@ func createJavaDeviceForHostRules() []Rule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createCcSdkVariantRules() []Rule {
|
||||||
|
sdkVersionOnlyWhitelist := []string{
|
||||||
|
// derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk.
|
||||||
|
// This sometimes works because the APEX modules that contain derive_sdk and
|
||||||
|
// derive_sdk_prefer32 suppress the platform installation rules, but fails when
|
||||||
|
// the APEX modules contain the SDK variant and the platform variant still exists.
|
||||||
|
"frameworks/base/apex/sdkextensions/derive_sdk",
|
||||||
|
}
|
||||||
|
|
||||||
|
platformVariantPropertiesWhitelist := []string{
|
||||||
|
// android_native_app_glue and libRSSupport use native_window.h but target old
|
||||||
|
// sdk versions (minimum and 9 respectively) where libnativewindow didn't exist,
|
||||||
|
// so they can't add libnativewindow to shared_libs to get the header directory
|
||||||
|
// for the platform variant. Allow them to use the platform variant
|
||||||
|
// property to set shared_libs.
|
||||||
|
"prebuilts/ndk",
|
||||||
|
"frameworks/rs",
|
||||||
|
}
|
||||||
|
|
||||||
|
return []Rule{
|
||||||
|
NeverAllow().
|
||||||
|
NotIn(sdkVersionOnlyWhitelist...).
|
||||||
|
WithMatcher("sdk_variant_only", isSetMatcherInstance).
|
||||||
|
Because("sdk_variant_only can only be used in whitelisted projects"),
|
||||||
|
NeverAllow().
|
||||||
|
NotIn(platformVariantPropertiesWhitelist...).
|
||||||
|
WithMatcher("platform.shared_libs", isSetMatcherInstance).
|
||||||
|
Because("platform variant properties can only be used in whitelisted projects"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func neverallowMutator(ctx BottomUpMutatorContext) {
|
func neverallowMutator(ctx BottomUpMutatorContext) {
|
||||||
m, ok := ctx.Module().(Module)
|
m, ok := ctx.Module().(Module)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -254,6 +286,18 @@ func (m *startsWithMatcher) String() string {
|
||||||
return ".starts-with(" + m.prefix + ")"
|
return ".starts-with(" + m.prefix + ")"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type isSetMatcher struct{}
|
||||||
|
|
||||||
|
func (m *isSetMatcher) test(value string) bool {
|
||||||
|
return value != ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *isSetMatcher) String() string {
|
||||||
|
return ".is-set"
|
||||||
|
}
|
||||||
|
|
||||||
|
var isSetMatcherInstance = &isSetMatcher{}
|
||||||
|
|
||||||
type ruleProperty struct {
|
type ruleProperty struct {
|
||||||
fields []string // e.x.: Vndk.Enabled
|
fields []string // e.x.: Vndk.Enabled
|
||||||
matcher ValueMatcher
|
matcher ValueMatcher
|
||||||
|
|
|
@ -249,6 +249,50 @@ var neverallowTests = []struct {
|
||||||
}`),
|
}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// CC sdk rule tests
|
||||||
|
{
|
||||||
|
name: `"sdk_variant_only" outside whitelist`,
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"Android.bp": []byte(`
|
||||||
|
cc_library {
|
||||||
|
name: "outside_whitelist",
|
||||||
|
sdk_version: "current",
|
||||||
|
sdk_variant_only: true,
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "outside_whitelist": violates neverallow`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `"sdk_variant_only: false" outside whitelist`,
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"Android.bp": []byte(`
|
||||||
|
cc_library {
|
||||||
|
name: "outside_whitelist",
|
||||||
|
sdk_version: "current",
|
||||||
|
sdk_variant_only: false,
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "outside_whitelist": violates neverallow`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `"platform" outside whitelist`,
|
||||||
|
fs: map[string][]byte{
|
||||||
|
"Android.bp": []byte(`
|
||||||
|
cc_library {
|
||||||
|
name: "outside_whitelist",
|
||||||
|
platform: {
|
||||||
|
shared_libs: ["libfoo"],
|
||||||
|
},
|
||||||
|
}`),
|
||||||
|
},
|
||||||
|
expectedErrors: []string{
|
||||||
|
`module "outside_whitelist": violates neverallow`,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNeverallow(t *testing.T) {
|
func TestNeverallow(t *testing.T) {
|
||||||
|
@ -289,6 +333,8 @@ type mockCcLibraryProperties struct {
|
||||||
Include_dirs []string
|
Include_dirs []string
|
||||||
Vendor_available *bool
|
Vendor_available *bool
|
||||||
Static_libs []string
|
Static_libs []string
|
||||||
|
Sdk_version *string
|
||||||
|
Sdk_variant_only *bool
|
||||||
|
|
||||||
Vndk struct {
|
Vndk struct {
|
||||||
Enabled *bool
|
Enabled *bool
|
||||||
|
@ -305,6 +351,10 @@ type mockCcLibraryProperties struct {
|
||||||
Cflags []string
|
Cflags []string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Platform struct {
|
||||||
|
Shared_libs []string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockCcLibraryModule struct {
|
type mockCcLibraryModule struct {
|
||||||
|
|
|
@ -3350,7 +3350,7 @@ func TestApexWithApps(t *testing.T) {
|
||||||
}
|
}
|
||||||
// JNI libraries including transitive deps are
|
// JNI libraries including transitive deps are
|
||||||
for _, jni := range []string{"libjni", "libfoo"} {
|
for _, jni := range []string{"libjni", "libfoo"} {
|
||||||
jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module).OutputFile()
|
jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
|
||||||
// ... embedded inside APK (jnilibs.zip)
|
// ... embedded inside APK (jnilibs.zip)
|
||||||
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
|
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
|
||||||
// ... and not directly inside the APEX
|
// ... and not directly inside the APEX
|
||||||
|
|
|
@ -90,6 +90,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) {
|
||||||
system_shared_libs: [],
|
system_shared_libs: [],
|
||||||
stl: "none",
|
stl: "none",
|
||||||
notice: "custom_notice",
|
notice: "custom_notice",
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libprofile-clang-extras_ndk",
|
name: "libprofile-clang-extras_ndk",
|
||||||
|
@ -98,6 +99,7 @@ func TestVndkApexUsesVendorVariant(t *testing.T) {
|
||||||
system_shared_libs: [],
|
system_shared_libs: [],
|
||||||
stl: "none",
|
stl: "none",
|
||||||
notice: "custom_notice",
|
notice: "custom_notice",
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
`, func(fs map[string][]byte, config android.Config) {
|
`, func(fs map[string][]byte, config android.Config) {
|
||||||
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
|
config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
|
||||||
|
|
|
@ -29,6 +29,7 @@ var (
|
||||||
vendorSuffix = ".vendor"
|
vendorSuffix = ".vendor"
|
||||||
ramdiskSuffix = ".ramdisk"
|
ramdiskSuffix = ".ramdisk"
|
||||||
recoverySuffix = ".recovery"
|
recoverySuffix = ".recovery"
|
||||||
|
sdkSuffix = ".sdk"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AndroidMkContext interface {
|
type AndroidMkContext interface {
|
||||||
|
@ -103,6 +104,28 @@ func (c *Module) AndroidMkEntries() []android.AndroidMkEntries {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
|
||||||
|
// Make the SDK variant uninstallable so that there are not two rules to install
|
||||||
|
// to the same location.
|
||||||
|
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
|
||||||
|
// Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite
|
||||||
|
// dependencies to the .sdk suffix when building a module that uses the SDK.
|
||||||
|
entries.SetString("SOONG_SDK_VARIANT_MODULES",
|
||||||
|
"$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ExtraFooters: []android.AndroidMkExtraFootersFunc{
|
||||||
|
func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
|
||||||
|
if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake &&
|
||||||
|
c.CcLibraryInterface() && c.Shared() {
|
||||||
|
// Using the SDK variant as a JNI library needs a copy of the .so that
|
||||||
|
// is not named .sdk.so so that it can be packaged into the APK with
|
||||||
|
// the right name.
|
||||||
|
fmt.Fprintln(w, "$(eval $(call copy-one-file,",
|
||||||
|
"$(LOCAL_BUILT_MODULE),",
|
||||||
|
"$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -393,6 +416,9 @@ func (library *toolchainLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
|
func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
|
||||||
|
if installer.path == (android.InstallPath{}) {
|
||||||
|
return
|
||||||
|
}
|
||||||
// Soong installation is only supported for host modules. Have Make
|
// Soong installation is only supported for host modules. Have Make
|
||||||
// installation trigger Soong installation.
|
// installation trigger Soong installation.
|
||||||
if ctx.Target().Os.Class == android.Host {
|
if ctx.Target().Os.Class == android.Host {
|
||||||
|
|
44
cc/cc.go
44
cc/cc.go
|
@ -42,6 +42,7 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) {
|
||||||
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
|
ctx.RegisterModuleType("cc_defaults", defaultsFactory)
|
||||||
|
|
||||||
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||||
|
ctx.BottomUp("sdk", sdkMutator).Parallel()
|
||||||
ctx.BottomUp("vndk", VndkMutator).Parallel()
|
ctx.BottomUp("vndk", VndkMutator).Parallel()
|
||||||
ctx.BottomUp("link", LinkageMutator).Parallel()
|
ctx.BottomUp("link", LinkageMutator).Parallel()
|
||||||
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
|
ctx.BottomUp("ndk_api", NdkApiMutator).Parallel()
|
||||||
|
@ -208,9 +209,13 @@ type BaseProperties struct {
|
||||||
// Deprecated. true is the default, false is invalid.
|
// Deprecated. true is the default, false is invalid.
|
||||||
Clang *bool `android:"arch_variant"`
|
Clang *bool `android:"arch_variant"`
|
||||||
|
|
||||||
// Minimum sdk version supported when compiling against the ndk
|
// Minimum sdk version supported when compiling against the ndk. Setting this property causes
|
||||||
|
// two variants to be built, one for the platform and one for apps.
|
||||||
Sdk_version *string
|
Sdk_version *string
|
||||||
|
|
||||||
|
// If true, always create an sdk variant and don't create a platform variant.
|
||||||
|
Sdk_variant_only *bool
|
||||||
|
|
||||||
AndroidMkSharedLibs []string `blueprint:"mutated"`
|
AndroidMkSharedLibs []string `blueprint:"mutated"`
|
||||||
AndroidMkStaticLibs []string `blueprint:"mutated"`
|
AndroidMkStaticLibs []string `blueprint:"mutated"`
|
||||||
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
|
AndroidMkRuntimeLibs []string `blueprint:"mutated"`
|
||||||
|
@ -252,6 +257,16 @@ type BaseProperties struct {
|
||||||
SnapshotRuntimeLibs []string `blueprint:"mutated"`
|
SnapshotRuntimeLibs []string `blueprint:"mutated"`
|
||||||
|
|
||||||
Installable *bool
|
Installable *bool
|
||||||
|
|
||||||
|
// Set by factories of module types that can only be referenced from variants compiled against
|
||||||
|
// the SDK.
|
||||||
|
AlwaysSdk bool `blueprint:"mutated"`
|
||||||
|
|
||||||
|
// Variant is an SDK variant created by sdkMutator
|
||||||
|
IsSdkVariant bool `blueprint:"mutated"`
|
||||||
|
// Set when both SDK and platform variants are exported to Make to trigger renaming the SDK
|
||||||
|
// variant to have a ".sdk" suffix.
|
||||||
|
SdkAndPlatformVariantVisibleToMake bool `blueprint:"mutated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VendorProperties struct {
|
type VendorProperties struct {
|
||||||
|
@ -527,8 +542,11 @@ func (c *Module) Shared() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Module) SelectedStl() string {
|
func (c *Module) SelectedStl() string {
|
||||||
|
if c.stl != nil {
|
||||||
return c.stl.Properties.SelectedStl
|
return c.stl.Properties.SelectedStl
|
||||||
}
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Module) ToolchainLibrary() bool {
|
func (c *Module) ToolchainLibrary() bool {
|
||||||
if _, ok := c.linker.(*toolchainLibraryDecorator); ok {
|
if _, ok := c.linker.(*toolchainLibraryDecorator); ok {
|
||||||
|
@ -555,6 +573,10 @@ func (c *Module) SdkVersion() string {
|
||||||
return String(c.Properties.Sdk_version)
|
return String(c.Properties.Sdk_version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Module) AlwaysSdk() bool {
|
||||||
|
return c.Properties.AlwaysSdk || Bool(c.Properties.Sdk_variant_only)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Module) IncludeDirs() android.Paths {
|
func (c *Module) IncludeDirs() android.Paths {
|
||||||
if c.linker != nil {
|
if c.linker != nil {
|
||||||
if library, ok := c.linker.(exportedFlagsProducer); ok {
|
if library, ok := c.linker.(exportedFlagsProducer); ok {
|
||||||
|
@ -803,6 +825,17 @@ func (c *Module) UseVndk() bool {
|
||||||
return c.Properties.VndkVersion != ""
|
return c.Properties.VndkVersion != ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Module) canUseSdk() bool {
|
||||||
|
return c.Os() == android.Android && !c.UseVndk() && !c.InRamdisk() && !c.InRecovery()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Module) UseSdk() bool {
|
||||||
|
if c.canUseSdk() {
|
||||||
|
return String(c.Properties.Sdk_version) != ""
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Module) isCoverageVariant() bool {
|
func (c *Module) isCoverageVariant() bool {
|
||||||
return c.coverage.Properties.IsCoverageVariant
|
return c.coverage.Properties.IsCoverageVariant
|
||||||
}
|
}
|
||||||
|
@ -1060,14 +1093,11 @@ func (ctx *moduleContextImpl) header() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *moduleContextImpl) canUseSdk() bool {
|
func (ctx *moduleContextImpl) canUseSdk() bool {
|
||||||
return ctx.ctx.Device() && !ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && !ctx.ctx.Fuchsia()
|
return ctx.mod.canUseSdk()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *moduleContextImpl) useSdk() bool {
|
func (ctx *moduleContextImpl) useSdk() bool {
|
||||||
if ctx.canUseSdk() {
|
return ctx.mod.UseSdk()
|
||||||
return String(ctx.mod.Properties.Sdk_version) != ""
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *moduleContextImpl) sdkVersion() string {
|
func (ctx *moduleContextImpl) sdkVersion() string {
|
||||||
|
@ -1386,6 +1416,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
|
||||||
c.Properties.SubName += ramdiskSuffix
|
c.Properties.SubName += ramdiskSuffix
|
||||||
} else if c.InRecovery() && !c.OnlyInRecovery() {
|
} else if c.InRecovery() && !c.OnlyInRecovery() {
|
||||||
c.Properties.SubName += recoverySuffix
|
c.Properties.SubName += recoverySuffix
|
||||||
|
} else if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake {
|
||||||
|
c.Properties.SubName += sdkSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx := &moduleContext{
|
ctx := &moduleContext{
|
||||||
|
|
|
@ -27,6 +27,7 @@ type GenruleExtraProperties struct {
|
||||||
Vendor_available *bool
|
Vendor_available *bool
|
||||||
Ramdisk_available *bool
|
Ramdisk_available *bool
|
||||||
Recovery_available *bool
|
Recovery_available *bool
|
||||||
|
Sdk_version *string
|
||||||
}
|
}
|
||||||
|
|
||||||
// cc_genrule is a genrule that can depend on other cc_* objects.
|
// cc_genrule is a genrule that can depend on other cc_* objects.
|
||||||
|
|
|
@ -1223,7 +1223,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
|
||||||
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
|
if Bool(library.Properties.Static_ndk_lib) && library.static() &&
|
||||||
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
|
!ctx.useVndk() && !ctx.inRamdisk() && !ctx.inRecovery() && ctx.Device() &&
|
||||||
library.baseLinker.sanitize.isUnsanitizedVariant() &&
|
library.baseLinker.sanitize.isUnsanitizedVariant() &&
|
||||||
!library.buildStubs() {
|
!library.buildStubs() && ctx.sdkVersion() == "" {
|
||||||
installPath := getNdkSysrootBase(ctx).Join(
|
installPath := getNdkSysrootBase(ctx).Join(
|
||||||
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
|
ctx, "usr/lib", config.NDKTriple(ctx.toolchain()), file.Base())
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,14 @@ type LinkableInterface interface {
|
||||||
InRecovery() bool
|
InRecovery() bool
|
||||||
OnlyInRecovery() bool
|
OnlyInRecovery() bool
|
||||||
|
|
||||||
|
UseSdk() bool
|
||||||
UseVndk() bool
|
UseVndk() bool
|
||||||
MustUseVendorVariant() bool
|
MustUseVendorVariant() bool
|
||||||
IsVndk() bool
|
IsVndk() bool
|
||||||
HasVendorVariant() bool
|
HasVendorVariant() bool
|
||||||
|
|
||||||
SdkVersion() string
|
SdkVersion() string
|
||||||
|
AlwaysSdk() bool
|
||||||
|
|
||||||
ToolchainLibrary() bool
|
ToolchainLibrary() bool
|
||||||
NdkPrebuiltStl() bool
|
NdkPrebuiltStl() bool
|
||||||
|
|
11
cc/linker.go
11
cc/linker.go
|
@ -158,6 +158,13 @@ type BaseLinkerProperties struct {
|
||||||
// the ramdisk variant of the C/C++ module.
|
// the ramdisk variant of the C/C++ module.
|
||||||
Exclude_static_libs []string
|
Exclude_static_libs []string
|
||||||
}
|
}
|
||||||
|
Platform struct {
|
||||||
|
// list of shared libs that should be use to build the platform variant
|
||||||
|
// of a module that sets sdk_version. This should rarely be necessary,
|
||||||
|
// in most cases the same libraries are available for the SDK and platform
|
||||||
|
// variants.
|
||||||
|
Shared_libs []string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make android::build:GetBuildNumber() available containing the build ID.
|
// make android::build:GetBuildNumber() available containing the build ID.
|
||||||
|
@ -255,6 +262,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
|
||||||
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
|
deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !ctx.useSdk() {
|
||||||
|
deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Target.Platform.Shared_libs...)
|
||||||
|
}
|
||||||
|
|
||||||
if ctx.toolchain().Bionic() {
|
if ctx.toolchain().Bionic() {
|
||||||
// libclang_rt.builtins and libatomic have to be last on the command line
|
// libclang_rt.builtins and libatomic have to be last on the command line
|
||||||
if !Bool(linker.Properties.No_libcrt) {
|
if !Bool(linker.Properties.No_libcrt) {
|
||||||
|
|
|
@ -381,6 +381,9 @@ func newStubLibrary() *Module {
|
||||||
module.linker = stub
|
module.linker = stub
|
||||||
module.installer = stub
|
module.installer = stub
|
||||||
|
|
||||||
|
module.Properties.AlwaysSdk = true
|
||||||
|
module.Properties.Sdk_version = StringPtr("current")
|
||||||
|
|
||||||
module.AddProperties(&stub.properties, &library.MutatedProperties)
|
module.AddProperties(&stub.properties, &library.MutatedProperties)
|
||||||
|
|
||||||
return module
|
return module
|
||||||
|
|
|
@ -76,6 +76,8 @@ func NdkPrebuiltObjectFactory() android.Module {
|
||||||
baseLinker: NewBaseLinker(nil),
|
baseLinker: NewBaseLinker(nil),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
module.Properties.AlwaysSdk = true
|
||||||
|
module.Properties.Sdk_version = StringPtr("current")
|
||||||
module.Properties.HideFromMake = true
|
module.Properties.HideFromMake = true
|
||||||
return module.Init()
|
return module.Init()
|
||||||
}
|
}
|
||||||
|
@ -115,10 +117,9 @@ func NdkPrebuiltSharedStlFactory() android.Module {
|
||||||
libraryDecorator: library,
|
libraryDecorator: library,
|
||||||
}
|
}
|
||||||
module.installer = nil
|
module.installer = nil
|
||||||
minVersionString := "minimum"
|
module.Properties.Sdk_version = StringPtr("minimum")
|
||||||
noStlString := "none"
|
module.Properties.AlwaysSdk = true
|
||||||
module.Properties.Sdk_version = &minVersionString
|
module.stl.Properties.Stl = StringPtr("none")
|
||||||
module.stl.Properties.Stl = &noStlString
|
|
||||||
return module.Init()
|
return module.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,6 +136,9 @@ func NdkPrebuiltStaticStlFactory() android.Module {
|
||||||
}
|
}
|
||||||
module.installer = nil
|
module.installer = nil
|
||||||
module.Properties.HideFromMake = true
|
module.Properties.HideFromMake = true
|
||||||
|
module.Properties.AlwaysSdk = true
|
||||||
|
module.Properties.Sdk_version = StringPtr("current")
|
||||||
|
module.stl.Properties.Stl = StringPtr("none")
|
||||||
module.ModuleBase.EnableNativeBridgeSupportByDefault()
|
module.ModuleBase.EnableNativeBridgeSupportByDefault()
|
||||||
return module.Init()
|
return module.Init()
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
// 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 (
|
||||||
|
"android/soong/android"
|
||||||
|
"android/soong/genrule"
|
||||||
|
)
|
||||||
|
|
||||||
|
// sdkMutator sets a creates a platform and an SDK variant for modules
|
||||||
|
// that set sdk_version, and ignores sdk_version for the platform
|
||||||
|
// variant. The SDK variant will be used for embedding in APKs
|
||||||
|
// that may be installed on older platforms. Apexes use their own
|
||||||
|
// variants that enforce backwards compatibility.
|
||||||
|
func sdkMutator(ctx android.BottomUpMutatorContext) {
|
||||||
|
if ctx.Os() != android.Android {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch m := ctx.Module().(type) {
|
||||||
|
case LinkableInterface:
|
||||||
|
if m.AlwaysSdk() {
|
||||||
|
if !m.UseSdk() {
|
||||||
|
ctx.ModuleErrorf("UseSdk() must return true when AlwaysSdk is set, did the factory forget to set Sdk_version?")
|
||||||
|
}
|
||||||
|
ctx.CreateVariations("sdk")
|
||||||
|
} else if m.UseSdk() {
|
||||||
|
modules := ctx.CreateVariations("", "sdk")
|
||||||
|
modules[0].(*Module).Properties.Sdk_version = nil
|
||||||
|
modules[1].(*Module).Properties.IsSdkVariant = true
|
||||||
|
|
||||||
|
if ctx.Config().UnbundledBuild() {
|
||||||
|
modules[0].(*Module).Properties.HideFromMake = true
|
||||||
|
} else {
|
||||||
|
modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
|
||||||
|
modules[1].(*Module).Properties.PreventInstall = true
|
||||||
|
}
|
||||||
|
ctx.AliasVariation("")
|
||||||
|
} else {
|
||||||
|
ctx.CreateVariations("")
|
||||||
|
ctx.AliasVariation("")
|
||||||
|
}
|
||||||
|
case *genrule.Module:
|
||||||
|
if p, ok := m.Extra.(*GenruleExtraProperties); ok {
|
||||||
|
if String(p.Sdk_version) != "" {
|
||||||
|
ctx.CreateVariations("", "sdk")
|
||||||
|
} else {
|
||||||
|
ctx.CreateVariations("")
|
||||||
|
}
|
||||||
|
ctx.AliasVariation("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,102 @@
|
||||||
|
// 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 (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"android/soong/android"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSdkMutator(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
cc_library {
|
||||||
|
name: "libsdk",
|
||||||
|
shared_libs: ["libsdkdep"],
|
||||||
|
sdk_version: "current",
|
||||||
|
stl: "c++_shared",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_library {
|
||||||
|
name: "libsdkdep",
|
||||||
|
sdk_version: "current",
|
||||||
|
stl: "c++_shared",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_library {
|
||||||
|
name: "libplatform",
|
||||||
|
shared_libs: ["libsdk"],
|
||||||
|
stl: "libc++",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_binary {
|
||||||
|
name: "platformbinary",
|
||||||
|
shared_libs: ["libplatform"],
|
||||||
|
stl: "libc++",
|
||||||
|
}
|
||||||
|
|
||||||
|
cc_binary {
|
||||||
|
name: "sdkbinary",
|
||||||
|
shared_libs: ["libsdk"],
|
||||||
|
sdk_version: "current",
|
||||||
|
stl: "libc++",
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
assertDep := func(t *testing.T, from, to android.TestingModule) {
|
||||||
|
t.Helper()
|
||||||
|
found := false
|
||||||
|
|
||||||
|
var toFile android.Path
|
||||||
|
m := to.Module().(*Module)
|
||||||
|
if toc := m.Toc(); toc.Valid() {
|
||||||
|
toFile = toc.Path()
|
||||||
|
} else {
|
||||||
|
toFile = m.outputFile.Path()
|
||||||
|
}
|
||||||
|
|
||||||
|
rule := from.Description("link")
|
||||||
|
for _, dep := range rule.Implicits {
|
||||||
|
if dep.String() == toFile.String() {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("expected %q in %q", toFile.String(), rule.Implicits.Strings())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := testCc(t, bp)
|
||||||
|
|
||||||
|
libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared")
|
||||||
|
libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared")
|
||||||
|
libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared")
|
||||||
|
libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared")
|
||||||
|
libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared")
|
||||||
|
platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a")
|
||||||
|
sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk")
|
||||||
|
|
||||||
|
libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared")
|
||||||
|
libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared")
|
||||||
|
|
||||||
|
assertDep(t, libsdkNDK, libsdkdepNDK)
|
||||||
|
assertDep(t, libsdkPlatform, libsdkdepPlatform)
|
||||||
|
assertDep(t, libplatform, libsdkPlatform)
|
||||||
|
assertDep(t, platformbinary, libplatform)
|
||||||
|
assertDep(t, sdkbinary, libsdkNDK)
|
||||||
|
|
||||||
|
assertDep(t, libsdkNDK, libcxxNDK)
|
||||||
|
assertDep(t, libsdkPlatform, libcxxPlatform)
|
||||||
|
}
|
|
@ -115,9 +115,13 @@ func (stl *stl) begin(ctx BaseModuleContext) {
|
||||||
switch s {
|
switch s {
|
||||||
case "libc++", "libc++_static":
|
case "libc++", "libc++_static":
|
||||||
return s
|
return s
|
||||||
|
case "c++_shared":
|
||||||
|
return "libc++"
|
||||||
|
case "c++_static":
|
||||||
|
return "libc++_static"
|
||||||
case "none":
|
case "none":
|
||||||
return ""
|
return ""
|
||||||
case "":
|
case "", "system":
|
||||||
if ctx.static() {
|
if ctx.static() {
|
||||||
return "libc++_static"
|
return "libc++_static"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -138,6 +138,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
name: "libgcc_stripped",
|
name: "libgcc_stripped",
|
||||||
vendor_available: true,
|
vendor_available: true,
|
||||||
recovery_available: true,
|
recovery_available: true,
|
||||||
|
sdk_version: "current",
|
||||||
src: "",
|
src: "",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +156,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
llndk_library {
|
llndk_library {
|
||||||
name: "libc",
|
name: "libc",
|
||||||
symbol_file: "",
|
symbol_file: "",
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libm",
|
name: "libm",
|
||||||
|
@ -174,6 +176,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
llndk_library {
|
llndk_library {
|
||||||
name: "libm",
|
name: "libm",
|
||||||
symbol_file: "",
|
symbol_file: "",
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libdl",
|
name: "libdl",
|
||||||
|
@ -193,6 +196,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
llndk_library {
|
llndk_library {
|
||||||
name: "libdl",
|
name: "libdl",
|
||||||
symbol_file: "",
|
symbol_file: "",
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libft2",
|
name: "libft2",
|
||||||
|
@ -205,6 +209,7 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
name: "libft2",
|
name: "libft2",
|
||||||
symbol_file: "",
|
symbol_file: "",
|
||||||
vendor_available: false,
|
vendor_available: false,
|
||||||
|
sdk_version: "current",
|
||||||
}
|
}
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libc++_static",
|
name: "libc++_static",
|
||||||
|
@ -336,6 +341,16 @@ func GatherRequiredDepsForTest(oses ...android.OsType) string {
|
||||||
sdk_version: "27",
|
sdk_version: "27",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ndk_prebuilt_object {
|
||||||
|
name: "ndk_crtbegin_dynamic.27",
|
||||||
|
sdk_version: "27",
|
||||||
|
}
|
||||||
|
|
||||||
|
ndk_prebuilt_object {
|
||||||
|
name: "ndk_crtend_android.27",
|
||||||
|
sdk_version: "27",
|
||||||
|
}
|
||||||
|
|
||||||
ndk_prebuilt_shared_stl {
|
ndk_prebuilt_shared_stl {
|
||||||
name: "ndk_libc++_shared",
|
name: "ndk_libc++_shared",
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ func ToolchainLibraryFactory() android.Module {
|
||||||
module.stl = nil
|
module.stl = nil
|
||||||
module.sanitize = nil
|
module.sanitize = nil
|
||||||
module.installer = nil
|
module.installer = nil
|
||||||
|
module.Properties.Sdk_version = StringPtr("current")
|
||||||
return module.Init()
|
return module.Init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -204,6 +204,13 @@ func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) {
|
||||||
for _, jniTarget := range ctx.MultiTargets() {
|
for _, jniTarget := range ctx.MultiTargets() {
|
||||||
variation := append(jniTarget.Variations(),
|
variation := append(jniTarget.Variations(),
|
||||||
blueprint.Variation{Mutator: "link", Variation: "shared"})
|
blueprint.Variation{Mutator: "link", Variation: "shared"})
|
||||||
|
|
||||||
|
// If the app builds against an Android SDK use the SDK variant of JNI dependencies
|
||||||
|
// unless jni_uses_platform_apis is set.
|
||||||
|
if a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform &&
|
||||||
|
!Bool(a.appProperties.Jni_uses_platform_apis) {
|
||||||
|
variation = append(variation, blueprint.Variation{Mutator: "sdk", Variation: "sdk"})
|
||||||
|
}
|
||||||
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
|
ctx.AddFarVariationDependencies(variation, tag, a.appProperties.Jni_libs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -791,6 +791,7 @@ func TestJNIABI(t *testing.T) {
|
||||||
cc_library {
|
cc_library {
|
||||||
name: "libjni",
|
name: "libjni",
|
||||||
system_shared_libs: [],
|
system_shared_libs: [],
|
||||||
|
sdk_version: "current",
|
||||||
stl: "none",
|
stl: "none",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,26 +929,26 @@ func TestJNIPackaging(t *testing.T) {
|
||||||
|
|
||||||
android_test {
|
android_test {
|
||||||
name: "test",
|
name: "test",
|
||||||
sdk_version: "core_platform",
|
sdk_version: "current",
|
||||||
jni_libs: ["libjni"],
|
jni_libs: ["libjni"],
|
||||||
}
|
}
|
||||||
|
|
||||||
android_test {
|
android_test {
|
||||||
name: "test_noembed",
|
name: "test_noembed",
|
||||||
sdk_version: "core_platform",
|
sdk_version: "current",
|
||||||
jni_libs: ["libjni"],
|
jni_libs: ["libjni"],
|
||||||
use_embedded_native_libs: false,
|
use_embedded_native_libs: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
android_test_helper_app {
|
android_test_helper_app {
|
||||||
name: "test_helper",
|
name: "test_helper",
|
||||||
sdk_version: "core_platform",
|
sdk_version: "current",
|
||||||
jni_libs: ["libjni"],
|
jni_libs: ["libjni"],
|
||||||
}
|
}
|
||||||
|
|
||||||
android_test_helper_app {
|
android_test_helper_app {
|
||||||
name: "test_helper_noembed",
|
name: "test_helper_noembed",
|
||||||
sdk_version: "core_platform",
|
sdk_version: "current",
|
||||||
jni_libs: ["libjni"],
|
jni_libs: ["libjni"],
|
||||||
use_embedded_native_libs: false,
|
use_embedded_native_libs: false,
|
||||||
}
|
}
|
||||||
|
@ -979,6 +980,10 @@ func TestJNIPackaging(t *testing.T) {
|
||||||
if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
|
if g, w := !strings.Contains(jniLibZip.Args["jarArgs"], "-L 0"), test.compressed; g != w {
|
||||||
t.Errorf("expected jni compressed %v, got %v", w, g)
|
t.Errorf("expected jni compressed %v, got %v", w, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(jniLibZip.Implicits[0].String(), "_sdk_") {
|
||||||
|
t.Errorf("expected input %q to use sdk variant", jniLibZip.Implicits[0].String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,6 +164,10 @@ func (mod *Module) OnlyInRecovery() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *Module) UseSdk() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) UseVndk() bool {
|
func (mod *Module) UseVndk() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -184,6 +188,10 @@ func (mod *Module) SdkVersion() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (mod *Module) AlwaysSdk() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (mod *Module) ToolchainLibrary() bool {
|
func (mod *Module) ToolchainLibrary() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue