aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiyong Park <jiyong@google.com>2018-12-04 14:07:56 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2018-12-04 14:07:56 +0000
commitce16f3bac8ed6719a52cfa77463b8df78ad0c7b5 (patch)
treec06828e382ec2ffb38fb05a8523f5a853ab64c9a
parent3a33fe535eb6ee4f67b9840cf28a33e3d9edbdee (diff)
parent25fc6a9cc9b665882f6a422462cbc5d0670af87c (diff)
downloadbuild_soong-ce16f3bac8ed6719a52cfa77463b8df78ad0c7b5.tar.gz
build_soong-ce16f3bac8ed6719a52cfa77463b8df78ad0c7b5.tar.bz2
build_soong-ce16f3bac8ed6719a52cfa77463b8df78ad0c7b5.zip
Merge "Stubs variant is used when building for APEX"
-rw-r--r--Android.bp3
-rw-r--r--android/apex.go64
-rw-r--r--apex/apex.go22
-rw-r--r--apex/apex_test.go369
-rw-r--r--cc/cc.go112
-rw-r--r--cc/cc_test.go2
-rw-r--r--cc/library.go59
7 files changed, 589 insertions, 42 deletions
diff --git a/Android.bp b/Android.bp
index 9711c116..76f6798c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -353,6 +353,9 @@ bootstrap_go_package {
"apex/apex.go",
"apex/key.go",
],
+ testSrcs: [
+ "apex/apex_test.go",
+ ],
pluginFor: ["soong_build"],
}
diff --git a/android/apex.go b/android/apex.go
index dae88cec..3a191cf6 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -14,6 +14,8 @@
package android
+import "sync"
+
// ApexModule is the interface that a module type is expected to implement if
// the module has to be built differently depending on whether the module
// is destined for an apex or not (installed to one of the regular partitions).
@@ -94,6 +96,68 @@ func (m *ApexModuleBase) IsInstallableToApex() bool {
return false
}
+// This structure maps a module name to the set of APEX bundle names that the module
+// should be built for. Examples:
+//
+// ...["foo"]["bar"] == true: module foo is directly depended on by APEX bar
+// ...["foo"]["bar"] == false: module foo is indirectly depended on by APEX bar
+// ...["foo"]["bar"] doesn't exist: foo is not built for APEX bar
+// ...["foo"] doesn't exist: foo is not built for any APEX
+func apexBundleNamesMap(config Config) map[string]map[string]bool {
+ return config.Once("apexBundleNames", func() interface{} {
+ return make(map[string]map[string]bool)
+ }).(map[string]map[string]bool)
+}
+
+var bundleNamesMapMutex sync.Mutex
+
+// Mark that a module named moduleName should be built for an apex named bundleName
+// directDep should be set to true if the module is a direct dependency of the apex.
+func BuildModuleForApexBundle(ctx BaseModuleContext, moduleName string, bundleName string, directDep bool) {
+ bundleNamesMapMutex.Lock()
+ defer bundleNamesMapMutex.Unlock()
+ bundleNames, ok := apexBundleNamesMap(ctx.Config())[moduleName]
+ if !ok {
+ bundleNames = make(map[string]bool)
+ apexBundleNamesMap(ctx.Config())[moduleName] = bundleNames
+ }
+ bundleNames[bundleName] = bundleNames[bundleName] || directDep
+}
+
+// Returns the list of apex bundle names that the module named moduleName
+// should be built for.
+func GetApexBundlesForModule(ctx BaseModuleContext, moduleName string) map[string]bool {
+ bundleNamesMapMutex.Lock()
+ defer bundleNamesMapMutex.Unlock()
+ return apexBundleNamesMap(ctx.Config())[moduleName]
+}
+
+// Tests if moduleName is directly depended on by bundleName (i.e. referenced in
+// native_shared_libs, etc.)
+func DirectlyInApex(config Config, bundleName string, moduleName string) bool {
+ bundleNamesMapMutex.Lock()
+ defer bundleNamesMapMutex.Unlock()
+ if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok {
+ return bundleNames[bundleName]
+ }
+ return false
+}
+
+// Tests if moduleName is directly depended on by any APEX. If this returns true,
+// that means the module is part of the platform.
+func DirectlyInAnyApex(config Config, moduleName string) bool {
+ bundleNamesMapMutex.Lock()
+ defer bundleNamesMapMutex.Unlock()
+ if bundleNames, ok := apexBundleNamesMap(config)[moduleName]; ok {
+ for bn := range bundleNames {
+ if bundleNames[bn] {
+ return true
+ }
+ }
+ }
+ return false
+}
+
func InitApexModule(m ApexModule) {
base := m.apexModuleBase()
base.canHaveApexVariants = true
diff --git a/apex/apex.go b/apex/apex.go
index 8a652db0..52fa561d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -128,13 +128,6 @@ func init() {
})
}
-// maps a module name to set of apex bundle names that the module should be built for
-func apexBundleNamesFor(config android.Config) map[string]map[string]bool {
- return config.Once("apexBundleNames", func() interface{} {
- return make(map[string]map[string]bool)
- }).(map[string]map[string]bool)
-}
-
// Mark the direct and transitive dependencies of apex bundles so that they
// can be built for the apex bundles.
func apexDepsMutator(mctx android.TopDownMutatorContext) {
@@ -143,12 +136,9 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
mctx.WalkDeps(func(child, parent android.Module) bool {
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() {
moduleName := mctx.OtherModuleName(am) + "-" + am.Target().String()
- bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]
- if !ok {
- bundleNames = make(map[string]bool)
- apexBundleNamesFor(mctx.Config())[moduleName] = bundleNames
- }
- bundleNames[apexBundleName] = true
+ // If the parent is apexBundle, this child is directly depended.
+ _, directDep := parent.(*apexBundle)
+ android.BuildModuleForApexBundle(mctx, moduleName, apexBundleName, directDep)
return true
} else {
return false
@@ -161,7 +151,8 @@ func apexDepsMutator(mctx android.TopDownMutatorContext) {
func apexMutator(mctx android.BottomUpMutatorContext) {
if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
moduleName := mctx.ModuleName() + "-" + am.Target().String()
- if bundleNames, ok := apexBundleNamesFor(mctx.Config())[moduleName]; ok {
+ bundleNames := android.GetApexBundlesForModule(mctx, moduleName)
+ if len(bundleNames) > 0 {
variations := []string{"platform"}
for bn := range bundleNames {
variations = append(variations, bn)
@@ -495,6 +486,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// indirect dependencies
if am, ok := child.(android.ApexModule); ok && am.CanHaveApexVariants() && am.IsInstallableToApex() {
if cc, ok := child.(*cc.Module); ok {
+ if cc.IsStubs() || cc.HasStubsVariants() {
+ return false
+ }
depName := ctx.OtherModuleName(child)
fileToCopy, dirInApex := getCopyManifestForNativeLibrary(cc)
filesInfo = append(filesInfo, apexFile{fileToCopy, depName, cc.Arch().ArchType, dirInApex, nativeSharedLib})
diff --git a/apex/apex_test.go b/apex/apex_test.go
new file mode 100644
index 00000000..41d8455d
--- /dev/null
+++ b/apex/apex_test.go
@@ -0,0 +1,369 @@
+// Copyright 2018 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package apex
+
+import (
+ "android/soong/android"
+ "android/soong/cc"
+ "io/ioutil"
+ "os"
+ "strings"
+ "testing"
+)
+
+func testApex(t *testing.T, bp string) *android.TestContext {
+ config, buildDir := setup(t)
+ defer teardown(buildDir)
+
+ ctx := android.NewTestArchContext()
+ ctx.RegisterModuleType("apex", android.ModuleFactoryAdaptor(apexBundleFactory))
+ ctx.RegisterModuleType("apex_key", android.ModuleFactoryAdaptor(apexKeyFactory))
+
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("apex_deps", apexDepsMutator)
+ ctx.BottomUp("apex", apexMutator)
+ })
+
+ ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(cc.LibraryFactory))
+ ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(cc.LibrarySharedFactory))
+ ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(cc.ObjectFactory))
+ ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(cc.ToolchainLibraryFactory))
+ ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("link", cc.LinkageMutator).Parallel()
+ ctx.BottomUp("version", cc.VersionMutator).Parallel()
+ ctx.BottomUp("begin", cc.BeginMutator).Parallel()
+ })
+
+ ctx.Register()
+
+ bp = bp + `
+ toolchain_library {
+ name: "libcompiler_rt-extras",
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libatomic",
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libgcc",
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-aarch64-android",
+ src: "",
+ }
+
+ toolchain_library {
+ name: "libclang_rt.builtins-arm-android",
+ src: "",
+ }
+
+ cc_object {
+ name: "crtbegin_so",
+ stl: "none",
+ }
+
+ cc_object {
+ name: "crtend_so",
+ stl: "none",
+ }
+
+ `
+
+ ctx.MockFileSystem(map[string][]byte{
+ "Android.bp": []byte(bp),
+ "testkey.avbpubkey": nil,
+ "testkey.pem": nil,
+ "build/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "mylib.cpp": nil,
+ })
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ return ctx
+}
+
+func setup(t *testing.T) (config android.Config, buildDir string) {
+ buildDir, err := ioutil.TempDir("", "soong_apex_test")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ config = android.TestArchConfig(buildDir, nil)
+
+ return
+}
+
+func teardown(buildDir string) {
+ os.RemoveAll(buildDir)
+}
+
+// ensure that 'result' contains 'expected'
+func ensureContains(t *testing.T, result string, expected string) {
+ if !strings.Contains(result, expected) {
+ t.Errorf("%q is not found in %q", expected, result)
+ }
+}
+
+// ensures that 'result' does not contain 'notExpected'
+func ensureNotContains(t *testing.T, result string, notExpected string) {
+ if strings.Contains(result, notExpected) {
+ t.Errorf("%q is found in %q", notExpected, result)
+ }
+}
+
+func ensureListContains(t *testing.T, result []string, expected string) {
+ if !android.InList(expected, result) {
+ t.Errorf("%q is not found in %v", expected, result)
+ }
+}
+
+func ensureListNotContains(t *testing.T, result []string, notExpected string) {
+ if android.InList(notExpected, result) {
+ t.Errorf("%q is found in %v", notExpected, result)
+ }
+}
+
+// Minimal test
+func TestBasicApex(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ // Ensure that main rule creates an output
+ ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
+
+ // Ensure that apex variant is created for the direct dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
+
+ // Ensure that apex variant is created for the indirect dep
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
+
+ // Ensure that both direct and indirect deps are copied into apex
+ ensureContains(t, copyCmds, "image/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image/lib64/mylib2.so")
+}
+
+func TestApexWithStubs(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "mylib3"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["mylib2", "mylib3"],
+ system_shared_libs: [],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "mylib2",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["1", "2", "3"],
+ },
+ }
+
+ cc_library {
+ name: "mylib3",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["10", "11", "12"],
+ },
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ // Ensure that direct non-stubs dep is always included
+ ensureContains(t, copyCmds, "image/lib64/mylib.so")
+
+ // Ensure that indirect stubs dep is not included
+ ensureNotContains(t, copyCmds, "image/lib64/mylib2.so")
+
+ // Ensure that direct stubs dep is included
+ ensureContains(t, copyCmds, "image/lib64/mylib3.so")
+
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+
+ // Ensure that mylib is linking with the latest version of stubs for mylib2
+ ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3_myapex/mylib2.so")
+ // ... and not linking to the non-stub (impl) variant of mylib2
+ ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_myapex/mylib2.so")
+
+ // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex)
+ ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so")
+ // .. and not linking to the stubs variant of mylib3
+ ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
+}
+
+func TestApexWithSystemLibsStubs(t *testing.T) {
+ ctx := testApex(t, `
+ apex {
+ name: "myapex",
+ key: "myapex.key",
+ native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"],
+ }
+
+ apex_key {
+ name: "myapex.key",
+ public_key: "testkey.avbpubkey",
+ private_key: "testkey.pem",
+ }
+
+ cc_library {
+ name: "mylib",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libdl#27"],
+ stl: "none",
+ }
+
+ cc_library_shared {
+ name: "mylib_shared",
+ srcs: ["mylib.cpp"],
+ shared_libs: ["libdl#27"],
+ stl: "none",
+ }
+
+ cc_library {
+ name: "libc",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
+ }
+
+ cc_library {
+ name: "libm",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
+ }
+
+ cc_library {
+ name: "libdl",
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
+ stl: "none",
+ stubs: {
+ versions: ["27", "28", "29"],
+ },
+ }
+ `)
+
+ apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule")
+ copyCmds := apexRule.Args["copy_commands"]
+
+ // Ensure that mylib, libm, libdl are included.
+ ensureContains(t, copyCmds, "image/lib64/mylib.so")
+ ensureContains(t, copyCmds, "image/lib64/libm.so")
+ ensureContains(t, copyCmds, "image/lib64/libdl.so")
+
+ // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs)
+ ensureNotContains(t, copyCmds, "image/lib64/libc.so")
+
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"]
+
+ // For dependency to libc
+ // Ensure that mylib is linking with the latest version of stubs
+ ensureContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_29_myapex/libc.so")
+ // ... and not linking to the non-stub (impl) variant
+ ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_myapex/libc.so")
+ // ... Cflags from stub is correctly exported to mylib
+ ensureContains(t, mylibCFlags, "__LIBC_API__=29")
+ ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29")
+
+ // For dependency to libm
+ // Ensure that mylib is linking with the non-stub (impl) variant
+ ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so")
+ // ... and not linking to the stub variant
+ ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29_myapex/libm.so")
+ // ... and is not compiling with the stub
+ ensureNotContains(t, mylibCFlags, "__LIBM_API__=29")
+ ensureNotContains(t, mylibSharedCFlags, "__LIBM_API__=29")
+
+ // For dependency to libdl
+ // Ensure that mylib is linking with the specified version of stubs
+ ensureContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_27_myapex/libdl.so")
+ // ... and not linking to the other versions of stubs
+ ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28_myapex/libdl.so")
+ ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29_myapex/libdl.so")
+ // ... and not linking to the non-stub (impl) variant
+ ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so")
+ // ... Cflags from stub is correctly exported to mylib
+ ensureContains(t, mylibCFlags, "__LIBDL_API__=27")
+ ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27")
+}
diff --git a/cc/cc.go b/cc/cc.go
index 8a0bf71b..b8cbf26a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -39,7 +39,7 @@ func init() {
ctx.BottomUp("vndk", vndkMutator).Parallel()
ctx.BottomUp("ndk_api", ndkApiMutator).Parallel()
ctx.BottomUp("test_per_src", testPerSrcMutator).Parallel()
- ctx.BottomUp("version", versionMutator).Parallel()
+ ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
})
@@ -248,6 +248,7 @@ type ModuleContextIntf interface {
getVndkExtendsModuleName() string
isPgoCompile() bool
useClangLld(actx ModuleContext) bool
+ isApex() bool
}
type ModuleContext interface {
@@ -308,6 +309,8 @@ type dependencyTag struct {
library bool
reexportFlags bool
+
+ explicitlyVersioned bool
}
var (
@@ -511,6 +514,20 @@ func (c *Module) onlyInRecovery() bool {
return c.ModuleBase.InstallInRecovery()
}
+func (c *Module) IsStubs() bool {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return library.buildStubs()
+ }
+ return false
+}
+
+func (c *Module) HasStubsVariants() bool {
+ if library, ok := c.linker.(*libraryDecorator); ok {
+ return len(library.Properties.Stubs.Versions) > 0
+ }
+ return false
+}
+
type baseModuleContext struct {
android.BaseContext
moduleContextImpl
@@ -649,6 +666,11 @@ func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
return ctx.mod.getVndkExtendsModuleName()
}
+// Tests if this module is built for APEX
+func (ctx *moduleContextImpl) isApex() bool {
+ return ctx.mod.ApexName() != ""
+}
+
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -1081,6 +1103,30 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
{Mutator: "link", Variation: "static"},
}, lateStaticDepTag, deps.LateStaticLibs...)
+ addSharedLibDependencies := func(depTag dependencyTag, name string, version string) {
+ var variations []blueprint.Variation
+ variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
+ versionVariantAvail := ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery()
+ if version != "" && versionVariantAvail {
+ // Version is explicitly specified. i.e. libFoo#30
+ variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
+ depTag.explicitlyVersioned = true
+ }
+ actx.AddVariationDependencies(variations, depTag, name)
+
+ // If the version is not specified, add dependency to the latest stubs library.
+ // The stubs library will be used when the depending module is built for APEX and
+ // the dependent module is not in the same APEX.
+ latestVersion := latestStubsVersionFor(actx.Config(), name)
+ if version == "" && latestVersion != "" && versionVariantAvail {
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {Mutator: "link", Variation: "shared"},
+ {Mutator: "version", Variation: latestVersion},
+ }, depTag, name)
+ // Note that depTag.explicitlyVersioned is false in this case.
+ }
+ }
+
// shared lib names without the #version suffix
var sharedLibNames []string
@@ -1091,29 +1137,17 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
if inList(lib, deps.ReexportSharedLibHeaders) {
depTag = sharedExportDepTag
}
- var variations []blueprint.Variation
- variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
- if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
- variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
- }
- actx.AddVariationDependencies(variations, depTag, name)
+ addSharedLibDependencies(depTag, name, version)
}
for _, lib := range deps.LateSharedLibs {
- name, version := stubsLibNameAndVersion(lib)
- if inList(name, sharedLibNames) {
+ if inList(lib, sharedLibNames) {
// This is to handle the case that some of the late shared libs (libc, libdl, libm, ...)
// are added also to SharedLibs with version (e.g., libc#10). If not skipped, we will be
// linking against both the stubs lib and the non-stubs lib at the same time.
continue
}
- depTag := lateSharedDepTag
- var variations []blueprint.Variation
- variations = append(variations, blueprint.Variation{Mutator: "link", Variation: "shared"})
- if version != "" && ctx.Os() == android.Android && !ctx.useVndk() && !c.inRecovery() {
- variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version})
- }
- actx.AddVariationDependencies(variations, depTag, name)
+ addSharedLibDependencies(lateSharedDepTag, lib, "")
}
actx.AddVariationDependencies([]blueprint.Variation{
@@ -1372,7 +1406,53 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
return
}
}
+
+ // Extract explicitlyVersioned field from the depTag and reset it inside the struct.
+ // Otherwise, sharedDepTag and lateSharedDepTag with explicitlyVersioned set to true
+ // won't be matched to sharedDepTag and lateSharedDepTag.
+ explicitlyVersioned := false
+ if t, ok := depTag.(dependencyTag); ok {
+ explicitlyVersioned = t.explicitlyVersioned
+ t.explicitlyVersioned = false
+ depTag = t
+ }
+
if t, ok := depTag.(dependencyTag); ok && t.library {
+ if dependentLibrary, ok := ccDep.linker.(*libraryDecorator); ok {
+ depIsStubs := dependentLibrary.buildStubs()
+ depHasStubs := ccDep.HasStubsVariants()
+ depNameWithTarget := depName + "-" + ccDep.Target().String()
+ depInSameApex := android.DirectlyInApex(ctx.Config(), c.ApexName(), depNameWithTarget)
+ depInPlatform := !android.DirectlyInAnyApex(ctx.Config(), depNameWithTarget)
+
+ var useThisDep bool
+ if depIsStubs && explicitlyVersioned {
+ // Always respect dependency to the versioned stubs (i.e. libX#10)
+ useThisDep = true
+ } else if !depHasStubs {
+ // Use non-stub variant if that is the only choice
+ // (i.e. depending on a lib without stubs.version property)
+ useThisDep = true
+ } else if c.IsForPlatform() {
+ // If not building for APEX, use stubs only when it is from
+ // an APEX (and not from platform)
+ useThisDep = (depInPlatform != depIsStubs)
+ if c.inRecovery() {
+ // However, for recovery modules, since there is no APEX there,
+ // always link to non-stub variant
+ useThisDep = !depIsStubs
+ }
+ } else {
+ // If building for APEX, use stubs only when it is not from
+ // the same APEX
+ useThisDep = (depInSameApex != depIsStubs)
+ }
+
+ if !useThisDep {
+ return // stop processing this dep
+ }
+ }
+
if i, ok := ccDep.linker.(exportedFlagsProducer); ok {
flags := i.exportedFlags()
deps := i.exportedFlagsDeps()
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 41f633a9..e368fb34 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -66,7 +66,7 @@ func createTestContext(t *testing.T, config android.Config, bp string) *android.
ctx.BottomUp("image", imageMutator).Parallel()
ctx.BottomUp("link", LinkageMutator).Parallel()
ctx.BottomUp("vndk", vndkMutator).Parallel()
- ctx.BottomUp("version", versionMutator).Parallel()
+ ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
})
ctx.Register()
diff --git a/cc/library.go b/cc/library.go
index 8b8fe023..822274a1 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -16,6 +16,8 @@ package cc
import (
"regexp"
+ "sort"
+ "strconv"
"strings"
"sync"
@@ -981,30 +983,65 @@ func LinkageMutator(mctx android.BottomUpMutatorContext) {
}
}
+// maps a module name to the list of stubs versions available for the module
+func stubsVersionsFor(config android.Config) map[string][]string {
+ return config.Once("stubVersions", func() interface{} {
+ return make(map[string][]string)
+ }).(map[string][]string)
+}
+
+var stubsVersionsLock sync.Mutex
+
+func latestStubsVersionFor(config android.Config, name string) string {
+ versions, ok := stubsVersionsFor(config)[name]
+ if ok && len(versions) > 0 {
+ // the versions are alreay sorted in ascending order
+ return versions[len(versions)-1]
+ }
+ return ""
+}
+
// Version mutator splits a module into the mandatory non-stubs variant
-// (which is named "impl") and zero or more stubs variants.
-func versionMutator(mctx android.BottomUpMutatorContext) {
+// (which is unnamed) and zero or more stubs variants.
+func VersionMutator(mctx android.BottomUpMutatorContext) {
if mctx.Os() != android.Android {
return
}
if m, ok := mctx.Module().(*Module); ok && !m.inRecovery() && m.linker != nil {
- if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() {
- versions := []string{""}
+ if library, ok := m.linker.(*libraryDecorator); ok && library.buildShared() &&
+ len(library.Properties.Stubs.Versions) > 0 {
+ versions := []string{}
for _, v := range library.Properties.Stubs.Versions {
+ if _, err := strconv.Atoi(v); err != nil {
+ mctx.PropertyErrorf("versions", "%q is not a number", v)
+ }
versions = append(versions, v)
}
+ sort.Slice(versions, func(i, j int) bool {
+ left, _ := strconv.Atoi(versions[i])
+ right, _ := strconv.Atoi(versions[j])
+ return left < right
+ })
+
+ // save the list of versions for later use
+ copiedVersions := make([]string, len(versions))
+ copy(copiedVersions, versions)
+ stubsVersionsLock.Lock()
+ defer stubsVersionsLock.Unlock()
+ stubsVersionsFor(mctx.Config())[mctx.ModuleName()] = copiedVersions
+
+ // "" is for the non-stubs variant
+ versions = append(versions, "")
+
modules := mctx.CreateVariations(versions...)
for i, m := range modules {
l := m.(*Module).linker.(*libraryDecorator)
- if i == 0 {
- l.MutatedProperties.BuildStubs = false
- continue
+ if versions[i] != "" {
+ l.MutatedProperties.BuildStubs = true
+ l.MutatedProperties.StubsVersion = versions[i]
+ m.(*Module).Properties.HideFromMake = true
}
- // Mark that this variant is for stubs.
- l.MutatedProperties.BuildStubs = true
- l.MutatedProperties.StubsVersion = versions[i]
- m.(*Module).Properties.HideFromMake = true
}
} else {
mctx.CreateVariations("")