aboutsummaryrefslogtreecommitdiffstats
path: root/cc
diff options
context:
space:
mode:
authorLogan Chien <loganchien@google.com>2017-10-31 18:04:35 +0800
committerLogan Chien <loganchien@google.com>2018-01-23 01:40:54 +0000
commitf35117410769f705a6c5fd497e508c3706a77fca (patch)
tree2d35c488ee923268538f7e4846f0e1401730563b /cc
parenta167e3ba42b75337a2fd521ab8adf3ab29bd4392 (diff)
downloadbuild_soong-f35117410769f705a6c5fd497e508c3706a77fca.tar.gz
build_soong-f35117410769f705a6c5fd497e508c3706a77fca.tar.bz2
build_soong-f35117410769f705a6c5fd497e508c3706a77fca.zip
Support VNDK extensions
This commit adds `extends: "name"` property and provides basic support to VNDK extensions. This is the simplest example: ``` cc_library { name: "libvndk", vendor_available: true, vndk { enabled: true, }, } cc_library { name: "libvndk_ext", vendor: true, vndk: { enabled: true, extends: "libvndk", }, } ``` A vndk extension library must extend an existing vndk library which has `vendor_available: true`. These two libraries must have the same `support_system_process` property. VNDK-ext libraries are installed to `/vendor/lib[64]/vndk` and VNDK-SP-ext libraries are installed to `/vendor/lib[64]/vndk-sp` by default. If there is a matching abi-dumps in `prebuilts/abi-dumps`, `header-abi-diff` will be invoked to check for ABI breakages. Bug: 38340960 Test: lunch aosp_walleye-userdebug && make -j8 # runs unit tests Test: lunch aosp_arm-userdebug && make -j8 # build a target w/o VNDK Test: Create a lsdump for a vndk lib, add an exported API to vndk lib, and build fails as expected. Test: Create a lsdump for a vndk lib, create an vndk extension lib with extra API, and build succeeds as expected. Test: Create libutils_ext, add an extra function to libutils_ext, and call it from a HIDL service. Change-Id: Iba90e08848ee99814405457f047321e6b52b2df0
Diffstat (limited to 'cc')
-rw-r--r--cc/builder.go9
-rw-r--r--cc/cc.go118
-rw-r--r--cc/cc_test.go620
-rw-r--r--cc/library.go23
-rw-r--r--cc/vndk.go61
5 files changed, 778 insertions, 53 deletions
diff --git a/cc/builder.go b/cc/builder.go
index 1e1c4f23..fe35d5c1 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -38,7 +38,6 @@ const (
var (
abiCheckAllowFlags = []string{
- "-allow-extensions",
"-allow-unreferenced-changes",
"-allow-unreferenced-elf-symbol-changes",
}
@@ -711,12 +710,18 @@ func UnzipRefDump(ctx android.ModuleContext, zippedRefDump android.Path, baseNam
}
func SourceAbiDiff(ctx android.ModuleContext, inputDump android.Path, referenceDump android.Path,
- baseName, exportedHeaderFlags string) android.OptionalPath {
+ baseName, exportedHeaderFlags string, isVndkExt bool) android.OptionalPath {
+
outputFile := android.PathForModuleOut(ctx, baseName+".abidiff")
+
localAbiCheckAllowFlags := append([]string(nil), abiCheckAllowFlags...)
if exportedHeaderFlags == "" {
localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-advice-only")
}
+ if isVndkExt {
+ localAbiCheckAllowFlags = append(localAbiCheckAllowFlags, "-allow-extensions")
+ }
+
ctx.Build(pctx, android.BuildParams{
Rule: sAbiDiff,
Description: "header-abi-diff " + outputFile.Base(),
diff --git a/cc/cc.go b/cc/cc.go
index a3af3042..9b1f2203 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -205,9 +205,11 @@ type ModuleContextIntf interface {
useVndk() bool
isVndk() bool
isVndkSp() bool
+ isVndkExt() bool
createVndkSourceAbiDump() bool
selectedStl() string
baseModuleName() string
+ getVndkExtendsModuleName() string
}
type ModuleContext interface {
@@ -289,6 +291,7 @@ var (
reuseObjTag = dependencyTag{name: "reuse objects"}
ndkStubDepTag = dependencyTag{name: "ndk stub", library: true}
ndkLateStubDepTag = dependencyTag{name: "ndk late stub", library: true}
+ vndkExtDepTag = dependencyTag{name: "vndk extends", library: true}
)
// Module contains the properties and members used by all C/C++ module types, and implements
@@ -398,12 +401,33 @@ func (c *Module) useVndk() bool {
}
func (c *Module) isVndk() bool {
- if c.vndkdep != nil {
- return c.vndkdep.isVndk()
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndk()
+ }
+ return false
+}
+
+func (c *Module) isVndkSp() bool {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndkSp()
+ }
+ return false
+}
+
+func (c *Module) isVndkExt() bool {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.isVndkExt()
}
return false
}
+func (c *Module) getVndkExtendsModuleName() string {
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ return vndkdep.getVndkExtendsModuleName()
+ }
+ return ""
+}
+
// Returns true only when this module is configured to have core and vendor
// variants.
func (c *Module) hasVendorVariant() bool {
@@ -474,18 +498,20 @@ func (ctx *moduleContextImpl) sdkVersion() string {
return ""
}
-func (ctx *moduleContextImpl) isVndk() bool {
- return ctx.mod.isVndk()
-}
func (ctx *moduleContextImpl) useVndk() bool {
return ctx.mod.useVndk()
}
+func (ctx *moduleContextImpl) isVndk() bool {
+ return ctx.mod.isVndk()
+}
+
func (ctx *moduleContextImpl) isVndkSp() bool {
- if vndk := ctx.mod.vndkdep; vndk != nil {
- return vndk.isVndkSp()
- }
- return false
+ return ctx.mod.isVndkSp()
+}
+
+func (ctx *moduleContextImpl) isVndkExt() bool {
+ return ctx.mod.isVndkExt()
}
// Create source abi dumps if the module belongs to the list of VndkLibraries.
@@ -504,6 +530,10 @@ func (ctx *moduleContextImpl) baseModuleName() string {
return ctx.mod.ModuleBase.BaseModuleName()
}
+func (ctx *moduleContextImpl) getVndkExtendsModuleName() string {
+ return ctx.mod.getVndkExtendsModuleName()
+}
+
func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module {
return &Module{
hod: hod,
@@ -935,6 +965,18 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) {
{"ndk_api", version}, {"link", "shared"}}, ndkStubDepTag, variantNdkLibs...)
actx.AddVariationDependencies([]blueprint.Variation{
{"ndk_api", version}, {"link", "shared"}}, ndkLateStubDepTag, variantLateNdkLibs...)
+
+ if vndkdep := c.vndkdep; vndkdep != nil {
+ if vndkdep.isVndkExt() {
+ baseModuleMode := vendorMode
+ if actx.DeviceConfig().VndkVersion() == "" {
+ baseModuleMode = coreMode
+ }
+ actx.AddVariationDependencies([]blueprint.Variation{
+ {"image", baseModuleMode}, {"link", "shared"}}, vndkExtDepTag,
+ vndkdep.getVndkExtendsModuleName())
+ }
+ }
}
func beginMutator(ctx android.BottomUpMutatorContext) {
@@ -959,7 +1001,7 @@ func (c *Module) clang(ctx BaseModuleContext) bool {
// Whether a module can link to another module, taking into
// account NDK linking.
-func checkLinkType(ctx android.ModuleContext, from *Module, to *Module) {
+func checkLinkType(ctx android.ModuleContext, from *Module, to *Module, tag dependencyTag) {
if from.Target().Os != android.Android {
// Host code is not restricted
return
@@ -969,7 +1011,7 @@ func checkLinkType(ctx android.ModuleContext, from *Module, to *Module) {
// each vendor-available module needs to check
// link-type for VNDK.
if from.vndkdep != nil {
- from.vndkdep.vndkCheckLinkType(ctx, to)
+ from.vndkdep.vndkCheckLinkType(ctx, to, tag)
}
return
}
@@ -1151,7 +1193,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps {
}
}
- checkLinkType(ctx, c, ccDep)
+ checkLinkType(ctx, c, ccDep, t)
}
var ptr *android.Paths
@@ -1411,21 +1453,47 @@ func vendorMutator(mctx android.BottomUpMutatorContext) {
}
// Sanity check
- if m.VendorProperties.Vendor_available != nil && (mctx.SocSpecific() || mctx.DeviceSpecific()) {
+ vendorSpecific := mctx.SocSpecific() || mctx.DeviceSpecific()
+
+ if m.VendorProperties.Vendor_available != nil && vendorSpecific {
mctx.PropertyErrorf("vendor_available",
"doesn't make sense at the same time as `vendor: true`, `proprietary: true`, or `device_specific:true`")
return
}
- if vndk := m.vndkdep; vndk != nil {
- if vndk.isVndk() && m.VendorProperties.Vendor_available == nil {
- mctx.PropertyErrorf("vndk",
- "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
- return
- }
- if !vndk.isVndk() && vndk.isVndkSp() {
- mctx.PropertyErrorf("vndk",
- "must set `enabled: true` to set `support_system_process: true`")
- return
+
+ if vndkdep := m.vndkdep; vndkdep != nil {
+ if vndkdep.isVndk() {
+ if vendorSpecific {
+ if !vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `extends: \"...\"` to vndk extension")
+ return
+ }
+ } else {
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `vendor: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ return
+ }
+ if m.VendorProperties.Vendor_available == nil {
+ mctx.PropertyErrorf("vndk",
+ "vendor_available must be set to either true or false when `vndk: {enabled: true}`")
+ return
+ }
+ }
+ } else {
+ if vndkdep.isVndkSp() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `support_system_process: true`")
+ return
+ }
+ if vndkdep.isVndkExt() {
+ mctx.PropertyErrorf("vndk",
+ "must set `enabled: true` to set `extends: %q`",
+ m.getVndkExtendsModuleName())
+ return
+ }
}
}
@@ -1453,14 +1521,14 @@ func vendorMutator(mctx android.BottomUpMutatorContext) {
vendor.Properties.PreventInstall = true
vendor.Properties.HideFromMake = true
}
- } else if m.hasVendorVariant() {
+ } else if m.hasVendorVariant() && !vendorSpecific {
// This will be available in both /system and /vendor
// or a /system directory that is available to vendor.
mod := mctx.CreateVariations(coreMode, vendorMode)
vendor := mod[1].(*Module)
vendor.Properties.UseVndk = true
squashVendorSrcs(vendor)
- } else if (mctx.SocSpecific() || mctx.DeviceSpecific()) && String(m.Properties.Sdk_version) == "" {
+ } else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
// This will be available in /vendor (or /odm) only
mod := mctx.CreateVariations(vendorMode)
vendor := mod[0].(*Module)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 4d8c4fb2..19e4703b 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -22,6 +22,7 @@ import (
"io/ioutil"
"os"
"reflect"
+ "regexp"
"sort"
"strings"
"testing"
@@ -52,10 +53,7 @@ func TestMain(m *testing.M) {
os.Exit(run())
}
-func testCc(t *testing.T, bp string) *android.TestContext {
- config := android.TestArchConfig(buildDir, nil)
- config.ProductVariables.DeviceVndkVersion = StringPtr("current")
-
+func createTestContext(t *testing.T, config android.Config, bp string) *android.TestContext {
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory))
@@ -90,8 +88,8 @@ func testCc(t *testing.T, bp string) *android.TestContext {
cc_library {
name: "libc",
- no_libgcc : true,
- nocrt : true,
+ no_libgcc: true,
+ nocrt: true,
system_shared_libs: [],
}
llndk_library {
@@ -100,8 +98,8 @@ func testCc(t *testing.T, bp string) *android.TestContext {
}
cc_library {
name: "libm",
- no_libgcc : true,
- nocrt : true,
+ no_libgcc: true,
+ nocrt: true,
system_shared_libs: [],
}
llndk_library {
@@ -110,8 +108,8 @@ func testCc(t *testing.T, bp string) *android.TestContext {
}
cc_library {
name: "libdl",
- no_libgcc : true,
- nocrt : true,
+ no_libgcc: true,
+ nocrt: true,
system_shared_libs: [],
}
llndk_library {
@@ -142,6 +140,12 @@ func testCc(t *testing.T, bp string) *android.TestContext {
"my_include": nil,
})
+ return ctx
+}
+
+func testCcWithConfig(t *testing.T, bp string, config android.Config) *android.TestContext {
+ ctx := createTestContext(t, config, bp)
+
_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
failIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
@@ -150,14 +154,56 @@ func testCc(t *testing.T, bp string) *android.TestContext {
return ctx
}
+func testCc(t *testing.T, bp string) *android.TestContext {
+ config := android.TestArchConfig(buildDir, nil)
+ config.ProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ return testCcWithConfig(t, bp, config)
+}
+
+func testCcNoVndk(t *testing.T, bp string) *android.TestContext {
+ config := android.TestArchConfig(buildDir, nil)
+ config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ return testCcWithConfig(t, bp, config)
+}
+
+func testCcError(t *testing.T, pattern string, bp string) {
+ config := android.TestArchConfig(buildDir, nil)
+ config.ProductVariables.DeviceVndkVersion = StringPtr("current")
+ config.ProductVariables.Platform_vndk_version = StringPtr("VER")
+
+ ctx := createTestContext(t, config, bp)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ if len(errs) > 0 {
+ failIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ _, errs = ctx.PrepareBuildActions(config)
+ if len(errs) > 0 {
+ failIfNoMatchingErrors(t, pattern, errs)
+ return
+ }
+
+ t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+}
+
+const (
+ coreVariant = "android_arm64_armv8-a_core_shared"
+ vendorVariant = "android_arm64_armv8-a_vendor_shared"
+)
+
func TestVendorSrc(t *testing.T) {
ctx := testCc(t, `
cc_library {
name: "libTest",
srcs: ["foo.c"],
- no_libgcc : true,
- nocrt : true,
- system_shared_libs : [],
+ no_libgcc: true,
+ nocrt: true,
+ system_shared_libs: [],
vendor_available: true,
target: {
vendor: {
@@ -167,7 +213,7 @@ func TestVendorSrc(t *testing.T) {
}
`)
- ld := ctx.ModuleForTests("libTest", "android_arm_armv7-a-neon_vendor_shared").Rule("ld")
+ ld := ctx.ModuleForTests("libTest", vendorVariant).Rule("ld")
var objs []string
for _, o := range ld.Inputs {
objs = append(objs, o.Base())
@@ -177,6 +223,524 @@ func TestVendorSrc(t *testing.T) {
}
}
+func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string,
+ isVndkSp bool, extends string) {
+
+ mod := ctx.ModuleForTests(name, vendorVariant).Module().(*Module)
+ if !mod.hasVendorVariant() {
+ t.Error("%q must have vendor variant", name)
+ }
+
+ // Check library properties.
+ lib, ok := mod.compiler.(*libraryDecorator)
+ if !ok {
+ t.Errorf("%q must have libraryDecorator", name)
+ } else if lib.baseInstaller.subDir != subDir {
+ t.Errorf("%q must use %q as subdir but it is using %q", name, subDir,
+ lib.baseInstaller.subDir)
+ }
+
+ // Check VNDK properties.
+ if mod.vndkdep == nil {
+ t.Fatalf("%q must have `vndkdep`", name)
+ }
+ if !mod.isVndk() {
+ t.Errorf("%q isVndk() must equal to true", name)
+ }
+ if mod.isVndkSp() != isVndkSp {
+ t.Errorf("%q isVndkSp() must equal to %t", name, isVndkSp)
+ }
+
+ // Check VNDK extension properties.
+ isVndkExt := extends != ""
+ if mod.isVndkExt() != isVndkExt {
+ t.Errorf("%q isVndkExt() must equal to %t", name, isVndkExt)
+ }
+
+ if actualExtends := mod.getVndkExtendsModuleName(); actualExtends != extends {
+ t.Errorf("%q must extend from %q but get %q", name, extends, actualExtends)
+ }
+}
+
+func TestVndk(t *testing.T) {
+ ctx := testCc(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_private",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_private",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+ `)
+
+ checkVndkModule(t, ctx, "libvndk", "vndk-VER", false, "")
+ checkVndkModule(t, ctx, "libvndk_private", "vndk-VER", false, "")
+ checkVndkModule(t, ctx, "libvndk_sp", "vndk-sp-VER", true, "")
+ checkVndkModule(t, ctx, "libvndk_sp_private", "vndk-sp-VER", true, "")
+}
+
+func TestVndkExt(t *testing.T) {
+ // This test checks the VNDK-Ext properties.
+ ctx := testCc(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
+
+ checkVndkModule(t, ctx, "libvndk_ext", "vndk", false, "libvndk")
+}
+
+func TestVndkExtNoVndk(t *testing.T) {
+ // This test checks the VNDK-Ext properties when BOARD_VNDK_VERSION is not set.
+ ctx := testCcNoVndk(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
+
+ // Ensures that the core variant of "libvndk_ext" can be found.
+ mod := ctx.ModuleForTests("libvndk_ext", coreVariant).Module().(*Module)
+ if extends := mod.getVndkExtendsModuleName(); extends != "libvndk" {
+ t.Errorf("\"libvndk_ext\" must extend from \"libvndk\" but get %q", extends)
+ }
+}
+
+func TestVndkExtError(t *testing.T) {
+ // This test ensures an error is emitted in ill-formed vndk-ext definition.
+ testCcError(t, "must set `vendor: true` to set `extends: \".*\"`", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
+
+ testCcError(t, "must set `extends: \"\\.\\.\\.\"` to vndk extension", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVndkExtInconsistentSupportSystemProcessError(t *testing.T) {
+ // This test ensures an error is emitted for inconsistent support_system_process.
+ testCcError(t, "module \".*\" with mismatched support_system_process", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+ `)
+
+ testCcError(t, "module \".*\" with mismatched support_system_process", `
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ },
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVndkExtVendorAvailableFalseError(t *testing.T) {
+ // This test ensures an error is emitted when a vndk-ext library extends a vndk library
+ // with `vendor_available: false`.
+ testCcError(t, "`extends` refers module \".*\" which does not have `vendor_available: true`", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVendorModuleUsesVndkExt(t *testing.T) {
+ // This test ensures a vendor module can depend on a vndk-ext library.
+ testCc(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ shared_libs: ["libvndk_ext", "libvndk_sp_ext"],
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVndkExtUsesVendorLib(t *testing.T) {
+ // This test ensures a vndk-ext library can depend on a vendor library.
+ testCc(t, `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ shared_libs: ["libvendor"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVndkSpExtUsesVendorLibError(t *testing.T) {
+ // This test ensures an error is emitted if a vndk-sp-ext library depends on a vendor
+ // library.
+ testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ support_system_process: true,
+ },
+ shared_libs: ["libvendor"], // Cause an error
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvendor",
+ vendor: true,
+ nocrt: true,
+ }
+ `)
+}
+
+func TestVndkUsesVndkExtError(t *testing.T) {
+ // This test ensures an error is emitted if a vndk/vndk-sp library depends on a
+ // vndk-ext/vndk-sp-ext library.
+ testCcError(t, "dependency \".*\" of \".*\" missing variant", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk2",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ shared_libs: ["libvndk_ext"],
+ nocrt: true,
+ }
+ `)
+
+ // The pattern should be "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\""
+ // but target.vendor.shared_libs has not been supported yet.
+ testCcError(t, "unrecognized property \"target.vendor.shared_libs\"", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk",
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk2",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ target: {
+ vendor: {
+ shared_libs: ["libvndk_ext"],
+ },
+ },
+ nocrt: true,
+ }
+ `)
+
+ testCcError(t, "dependency \".*\" of \".*\" missing variant", `
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ support_system_process: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_2",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ shared_libs: ["libvndk_sp_ext"],
+ nocrt: true,
+ }
+ `)
+
+ // The pattern should be "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\""
+ // but target.vendor.shared_libs has not been supported yet.
+ testCcError(t, "unrecognized property \"target.vendor.shared_libs\"", `
+ cc_library {
+ name: "libvndk_sp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp_ext",
+ vendor: true,
+ vndk: {
+ enabled: true,
+ extends: "libvndk_sp",
+ },
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libvndk_sp2",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ target: {
+ vendor: {
+ shared_libs: ["libvndk_sp_ext"],
+ },
+ },
+ nocrt: true,
+ }
+ `)
+}
+
var (
str11 = "01234567891"
str10 = str11[:10]
@@ -499,6 +1063,7 @@ func TestLinkReordering(t *testing.T) {
}
}
}
+
func failIfErrored(t *testing.T, errs []error) {
if len(errs) > 0 {
for _, err := range errs {
@@ -508,6 +1073,29 @@ func failIfErrored(t *testing.T, errs []error) {
}
}
+func failIfNoMatchingErrors(t *testing.T, pattern string, errs []error) {
+ matcher, err := regexp.Compile(pattern)
+ if err != nil {
+ t.Errorf("failed to compile regular expression %q because %s", pattern, err)
+ }
+
+ found := false
+
+ for _, err := range errs {
+ if matcher.FindStringIndex(err.Error()) != nil {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs))
+ for i, err := range errs {
+ t.Errorf("errs[%d] = %s", i, err)
+ }
+ }
+}
+
func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) {
for _, moduleName := range moduleNames {
module := ctx.ModuleForTests(moduleName, variant).Module().(*Module)
@@ -597,8 +1185,8 @@ func TestLlndkHeaders(t *testing.T) {
shared_libs: ["libllndk"],
vendor: true,
srcs: ["foo.c"],
- no_libgcc : true,
- nocrt : true,
+ no_libgcc: true,
+ nocrt: true,
}
`)
diff --git a/cc/library.go b/cc/library.go
index 9661f441..00282fcf 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -416,6 +416,10 @@ func (library *libraryDecorator) getLibName(ctx ModuleContext) string {
name = ctx.baseModuleName()
}
+ if ctx.isVndkExt() {
+ name = ctx.getVndkExtendsModuleName()
+ }
+
if ctx.Host() && Bool(library.Properties.Unique_host_soname) {
if !strings.HasSuffix(name, "-host") {
name = name + "-host"
@@ -619,7 +623,12 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
//Also take into account object re-use.
if len(objs.sAbiDumpFiles) > 0 && ctx.createVndkSourceAbiDump() {
- refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, "current", fileName, vndkVsNdk(ctx), true)
+ vndkVersion := "current"
+ if ver := ctx.DeviceConfig().VndkVersion(); ver != "" {
+ vndkVersion = ver
+ }
+
+ refSourceDumpFile := android.PathForVndkRefAbiDump(ctx, vndkVersion, fileName, vndkVsNdk(ctx), true)
exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
var SourceAbiFlags []string
for _, dir := range exportIncludeDirs.Strings() {
@@ -632,7 +641,8 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objec
library.sAbiOutputFile = TransformDumpToLinkedDump(ctx, objs.sAbiDumpFiles, soFile, fileName, exportedHeaderFlags)
if refSourceDumpFile.Valid() {
unzippedRefDump := UnzipRefDump(ctx, refSourceDumpFile.Path(), fileName)
- library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(), unzippedRefDump, fileName, exportedHeaderFlags)
+ library.sAbiDiff = SourceAbiDiff(ctx, library.sAbiOutputFile.Path(),
+ unzippedRefDump, fileName, exportedHeaderFlags, ctx.isVndkExt())
}
}
}
@@ -721,8 +731,13 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) {
} else if ctx.isVndk() {
library.baseInstaller.subDir = "vndk"
}
- if ctx.isVndk() && ctx.DeviceConfig().PlatformVndkVersion() != "current" {
- library.baseInstaller.subDir += "-" + ctx.DeviceConfig().PlatformVndkVersion()
+
+ // Append a version to vndk or vndk-sp directories on the system partition.
+ if ctx.isVndk() && !ctx.isVndkExt() {
+ vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
+ if vndkVersion != "current" && vndkVersion != "" {
+ library.baseInstaller.subDir += "-" + vndkVersion
+ }
}
}
library.baseInstaller.install(ctx, file)
diff --git a/cc/vndk.go b/cc/vndk.go
index a61b74c9..d417bea6 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -42,6 +42,9 @@ type VndkProperties struct {
// the module is VNDK-core and can link to other VNDK-core,
// VNDK-SP or LL-NDK modules only.
Support_system_process *bool
+
+ // Extending another module
+ Extends *string
}
}
@@ -67,17 +70,31 @@ func (vndk *vndkdep) isVndkSp() bool {
return Bool(vndk.Properties.Vndk.Support_system_process)
}
+func (vndk *vndkdep) isVndkExt() bool {
+ return vndk.Properties.Vndk.Extends != nil
+}
+
+func (vndk *vndkdep) getVndkExtendsModuleName() string {
+ return String(vndk.Properties.Vndk.Extends)
+}
+
func (vndk *vndkdep) typeName() string {
if !vndk.isVndk() {
return "native:vendor"
}
+ if !vndk.isVndkExt() {
+ if !vndk.isVndkSp() {
+ return "native:vendor:vndk"
+ }
+ return "native:vendor:vndksp"
+ }
if !vndk.isVndkSp() {
- return "native:vendor:vndk"
+ return "native:vendor:vndkext"
}
- return "native:vendor:vndksp"
+ return "native:vendor:vndkspext"
}
-func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module) {
+func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module, tag dependencyTag) {
if to.linker == nil {
return
}
@@ -109,11 +126,43 @@ func (vndk *vndkdep) vndkCheckLinkType(ctx android.ModuleContext, to *Module) {
vndk.typeName(), to.Name())
return
}
+ if tag == vndkExtDepTag {
+ // Ensure `extends: "name"` property refers a vndk module that has vendor_available
+ // and has identical vndk properties.
+ if to.vndkdep == nil || !to.vndkdep.isVndk() {
+ ctx.ModuleErrorf("`extends` refers a non-vndk module %q", to.Name())
+ return
+ }
+ if vndk.isVndkSp() != to.vndkdep.isVndkSp() {
+ ctx.ModuleErrorf(
+ "`extends` refers a module %q with mismatched support_system_process",
+ to.Name())
+ return
+ }
+ if !Bool(to.VendorProperties.Vendor_available) {
+ ctx.ModuleErrorf(
+ "`extends` refers module %q which does not have `vendor_available: true`",
+ to.Name())
+ return
+ }
+ }
if to.vndkdep == nil {
return
}
- if (vndk.isVndk() && !to.vndkdep.isVndk()) || (vndk.isVndkSp() && !to.vndkdep.isVndkSp()) {
- ctx.ModuleErrorf("(%s) should not link to %q(%s)",
+
+ // VNDK-core and VNDK-SP must not depend on VNDK extensions.
+ if (vndk.isVndk() || vndk.isVndkSp()) && !vndk.isVndkExt() && to.vndkdep.isVndkExt() {
+ ctx.ModuleErrorf("(%s) should not link to %q (%s)",
+ vndk.typeName(), to.Name(), to.vndkdep.typeName())
+ return
+ }
+
+ // VNDK-core must be only depend on VNDK-SP or LL-NDK. VNDK-SP must only depend on
+ // LL-NDK, regardless the extension status. VNDK-Ext may depend on vendor libraries, but
+ // VNDK-SP-Ext must remain self-contained.
+ if (vndk.isVndk() && !to.vndkdep.isVndk() && !vndk.isVndkExt()) ||
+ (vndk.isVndkSp() && !to.vndkdep.isVndkSp()) {
+ ctx.ModuleErrorf("(%s) should not link to %q (%s)",
vndk.typeName(), to.Name(), to.vndkdep.typeName())
return
}
@@ -149,7 +198,7 @@ func vndkMutator(mctx android.BottomUpMutatorContext) {
prebuilt_lib, is_prebuilt_lib := m.linker.(*prebuiltLibraryLinker)
if (is_lib && lib.shared()) || (is_prebuilt_lib && prebuilt_lib.shared()) {
name := strings.TrimPrefix(m.Name(), "prebuilt_")
- if m.vndkdep.isVndk() {
+ if m.vndkdep.isVndk() && !m.vndkdep.isVndkExt() {
vndkLibrariesLock.Lock()
defer vndkLibrariesLock.Unlock()
if m.vndkdep.isVndkSp() {