diff options
author | Logan Chien <loganchien@google.com> | 2017-10-31 18:04:35 +0800 |
---|---|---|
committer | Logan Chien <loganchien@google.com> | 2018-01-23 01:40:54 +0000 |
commit | f35117410769f705a6c5fd497e508c3706a77fca (patch) | |
tree | 2d35c488ee923268538f7e4846f0e1401730563b /cc | |
parent | a167e3ba42b75337a2fd521ab8adf3ab29bd4392 (diff) | |
download | build_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.go | 9 | ||||
-rw-r--r-- | cc/cc.go | 118 | ||||
-rw-r--r-- | cc/cc_test.go | 620 | ||||
-rw-r--r-- | cc/library.go | 23 | ||||
-rw-r--r-- | cc/vndk.go | 61 |
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(), @@ -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) @@ -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() { |