diff --git a/Android.bp b/Android.bp index 916292633..ec69df8a7 100644 --- a/Android.bp +++ b/Android.bp @@ -163,6 +163,8 @@ bootstrap_go_package { "cc/kernel_headers.go", "cc/genrule.go", + + "cc/vendor_public_library.go", ], testSrcs: [ "cc/cc_test.go", diff --git a/android/makevars.go b/android/makevars.go index 00a20f5aa..b6cd571f5 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -36,6 +36,7 @@ func androidMakeVarsProvider(ctx MakeVarsContext) { // Interface for other packages to use to declare make variables type MakeVarsContext interface { Config() Config + SingletonContext() SingletonContext // Verify the make variable matches the Soong version, fail the build // if it does not. If the make variable is empty, just set it. @@ -230,6 +231,10 @@ func (c *makeVarsContext) Config() Config { return c.config } +func (c *makeVarsContext) SingletonContext() SingletonContext { + return c.ctx +} + func (c *makeVarsContext) Eval(ninjaStr string) (string, error) { return c.ctx.Eval(c.pctx, ninjaStr) } diff --git a/android/module.go b/android/module.go index 4a8e8acf6..1e5447006 100644 --- a/android/module.go +++ b/android/module.go @@ -177,6 +177,7 @@ type Module interface { InstallInData() bool InstallInSanitizerDir() bool SkipInstall() + ExportedToMake() bool AddProperties(props ...interface{}) GetProperties() []interface{} @@ -507,6 +508,10 @@ func (a *ModuleBase) SkipInstall() { a.commonProperties.SkipInstall = true } +func (a *ModuleBase) ExportedToMake() bool { + return a.commonProperties.NamespaceExportedToMake +} + func (a *ModuleBase) computeInstallDeps( ctx blueprint.ModuleContext) Paths { diff --git a/cc/androidmk.go b/cc/androidmk.go index e78c4199c..56ff713c0 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -383,3 +383,18 @@ func (c *ndkPrebuiltStlLinker) AndroidMk(ctx AndroidMkContext, ret *android.Andr fmt.Fprintln(w, "LOCAL_COPY_TO_INTERMEDIATE_LIBRARIES := false") }) } + +func (c *vendorPublicLibraryStubDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) { + ret.Class = "SHARED_LIBRARIES" + ret.SubName = vendorPublicLibrarySuffix + + ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) { + c.libraryDecorator.androidMkWriteExportedFlags(w) + + fmt.Fprintln(w, "LOCAL_BUILT_MODULE_STEM := $(LOCAL_MODULE)"+outputFile.Ext()) + fmt.Fprintln(w, "LOCAL_STRIP_MODULE := false") + fmt.Fprintln(w, "LOCAL_SYSTEM_SHARED_LIBRARIES :=") + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + fmt.Fprintln(w, "LOCAL_NO_NOTICE_FILE := true") + }) +} diff --git a/cc/cc.go b/cc/cc.go index 721f4b136..e91711eef 100644 --- a/cc/cc.go +++ b/cc/cc.go @@ -922,6 +922,16 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { } } else if ctx.useVndk() && inList(entry, llndkLibraries) { nonvariantLibs = append(nonvariantLibs, entry+llndkLibrarySuffix) + } else if (ctx.Platform() || ctx.ProductSpecific()) && inList(entry, vendorPublicLibraries) { + vendorPublicLib := entry + vendorPublicLibrarySuffix + if actx.OtherModuleExists(vendorPublicLib) { + nonvariantLibs = append(nonvariantLibs, vendorPublicLib) + } else { + // This can happen if vendor_public_library module is defined in a + // namespace that isn't visible to the current module. In that case, + // link to the original library. + nonvariantLibs = append(nonvariantLibs, entry) + } } else { nonvariantLibs = append(nonvariantLibs, entry) } @@ -1306,14 +1316,18 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch depTag { case sharedDepTag, sharedExportDepTag, lateSharedDepTag: libName := strings.TrimSuffix(depName, llndkLibrarySuffix) + libName = strings.TrimSuffix(libName, vendorPublicLibrarySuffix) libName = strings.TrimPrefix(libName, "prebuilt_") isLLndk := inList(libName, llndkLibraries) + isVendorPublicLib := inList(libName, vendorPublicLibraries) var makeLibName string bothVendorAndCoreVariantsExist := ccDep.hasVendorVariant() || isLLndk if c.useVndk() && bothVendorAndCoreVariantsExist { // The vendor module in Make will have been renamed to not conflict with the core // module, so update the dependency name here accordingly. makeLibName = libName + vendorSuffix + } else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib { + makeLibName = libName + vendorPublicLibrarySuffix } else { makeLibName = libName } diff --git a/cc/cc_test.go b/cc/cc_test.go index 437211cd9..75aa2906a 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -56,15 +56,18 @@ func createTestContext(t *testing.T, config android.Config, bp string) *android. ctx := android.NewTestArchContext() ctx.RegisterModuleType("cc_library", android.ModuleFactoryAdaptor(LibraryFactory)) ctx.RegisterModuleType("cc_library_shared", android.ModuleFactoryAdaptor(LibrarySharedFactory)) + ctx.RegisterModuleType("cc_library_headers", android.ModuleFactoryAdaptor(LibraryHeaderFactory)) ctx.RegisterModuleType("toolchain_library", android.ModuleFactoryAdaptor(toolchainLibraryFactory)) ctx.RegisterModuleType("llndk_library", android.ModuleFactoryAdaptor(llndkLibraryFactory)) ctx.RegisterModuleType("llndk_headers", android.ModuleFactoryAdaptor(llndkHeadersFactory)) + ctx.RegisterModuleType("vendor_public_library", android.ModuleFactoryAdaptor(vendorPublicLibraryFactory)) ctx.RegisterModuleType("cc_object", android.ModuleFactoryAdaptor(objectFactory)) ctx.RegisterModuleType("filegroup", android.ModuleFactoryAdaptor(genrule.FileGroupFactory)) ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { ctx.BottomUp("image", vendorMutator).Parallel() ctx.BottomUp("link", linkageMutator).Parallel() ctx.BottomUp("vndk", vndkMutator).Parallel() + ctx.BottomUp("begin", beginMutator).Parallel() }) ctx.Register() @@ -115,6 +118,34 @@ func createTestContext(t *testing.T, config android.Config, bp string) *android. name: "libdl", symbol_file: "", } + cc_library { + name: "libc++_static", + no_libgcc: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + vendor_available: true, + } + cc_library { + name: "libc++", + no_libgcc: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + vendor_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, + } + cc_library { + name: "libunwind_llvm", + no_libgcc: true, + nocrt: true, + system_shared_libs: [], + stl: "none", + vendor_available: true, + } cc_object { name: "crtbegin_so", @@ -1077,16 +1108,20 @@ func TestStaticLibDepReordering(t *testing.T) { cc_library { name: "a", static_libs: ["b", "c", "d"], + stl: "none", } cc_library { name: "b", + stl: "none", } cc_library { name: "c", static_libs: ["b"], + stl: "none", } cc_library { name: "d", + stl: "none", } `) @@ -1111,13 +1146,16 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) { cc_library { name: "a", static_libs: ["b", "c"], + stl: "none", } cc_library { name: "b", + stl: "none", } cc_library { name: "c", shared_libs: ["b"], + stl: "none", } `) @@ -1249,3 +1287,68 @@ func TestCompilerFlags(t *testing.T) { } } } + +func TestVendorPublicLibraries(t *testing.T) { + ctx := testCc(t, ` + cc_library_headers { + name: "libvendorpublic_headers", + export_include_dirs: ["my_include"], + } + vendor_public_library { + name: "libvendorpublic", + symbol_file: "", + export_public_headers: ["libvendorpublic_headers"], + } + cc_library { + name: "libvendorpublic", + srcs: ["foo.c"], + vendor: true, + no_libgcc: true, + nocrt: true, + } + + cc_library { + name: "libsystem", + shared_libs: ["libvendorpublic"], + vendor: false, + srcs: ["foo.c"], + no_libgcc: true, + nocrt: true, + } + cc_library { + name: "libvendor", + shared_libs: ["libvendorpublic"], + vendor: true, + srcs: ["foo.c"], + no_libgcc: true, + nocrt: true, + } + `) + + variant := "android_arm64_armv8-a_core_shared" + + // test if header search paths are correctly added + // _static variant is used since _shared reuses *.o from the static variant + cc := ctx.ModuleForTests("libsystem", strings.Replace(variant, "_shared", "_static", 1)).Rule("cc") + cflags := cc.Args["cFlags"] + if !strings.Contains(cflags, "-Imy_include") { + t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags) + } + + // test if libsystem is linked to the stub + ld := ctx.ModuleForTests("libsystem", variant).Rule("ld") + libflags := ld.Args["libFlags"] + stubPaths := getOutputPaths(ctx, variant, []string{"libvendorpublic" + vendorPublicLibrarySuffix}) + if !strings.Contains(libflags, stubPaths[0].String()) { + t.Errorf("libflags for libsystem must contain %#v, but was %#v", stubPaths[0], libflags) + } + + // test if libvendor is linked to the real shared lib + ld = ctx.ModuleForTests("libvendor", strings.Replace(variant, "_core", "_vendor", 1)).Rule("ld") + libflags = ld.Args["libFlags"] + stubPaths = getOutputPaths(ctx, strings.Replace(variant, "_core", "_vendor", 1), []string{"libvendorpublic"}) + if !strings.Contains(libflags, stubPaths[0].String()) { + t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags) + } + +} diff --git a/cc/makevars.go b/cc/makevars.go index 042af2a14..2664ee19d 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -100,6 +100,21 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("LLNDK_LIBRARIES", strings.Join(llndkLibraries, " ")) ctx.Strict("VNDK_PRIVATE_LIBRARIES", strings.Join(vndkPrivateLibraries, " ")) + // Filter vendor_public_library that are exported to make + exportedVendorPublicLibraries := []string{} + ctx.SingletonContext().VisitAllModules(func(module android.Module) { + if ccModule, ok := module.(*Module); ok { + baseName := ccModule.BaseModuleName() + if inList(baseName, vendorPublicLibraries) && module.ExportedToMake() { + if !inList(baseName, exportedVendorPublicLibraries) { + exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName) + } + } + } + }) + sort.Strings(exportedVendorPublicLibraries) + ctx.Strict("VENDOR_PUBLIC_LIBRARIES", strings.Join(exportedVendorPublicLibraries, " ")) + sort.Strings(lsdumpPaths) ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " ")) diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go new file mode 100644 index 000000000..da41cbc31 --- /dev/null +++ b/cc/vendor_public_library.go @@ -0,0 +1,150 @@ +// 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 cc + +import ( + "strings" + "sync" + + "android/soong/android" +) + +var ( + vendorPublicLibrarySuffix = ".vendorpublic" + + vendorPublicLibraries = []string{} + vendorPublicLibrariesLock sync.Mutex +) + +// Creates a stub shared library for a vendor public library. Vendor public libraries +// are vendor libraries (owned by them and installed to /vendor partition) that are +// exposed to Android apps via JNI. The libraries are made public by being listed in +// /vendor/etc/public.libraries.txt. +// +// This stub library is a build-time only artifact that provides symbols that are +// exposed from a vendor public library. +// +// Example: +// +// vendor_public_library { +// name: "libfoo", +// symbol_file: "libfoo.map.txt", +// export_public_headers: ["libfoo_headers"], +// } +// +// cc_headers { +// name: "libfoo_headers", +// export_include_dirs: ["include"], +// } +// +type vendorPublicLibraryProperties struct { + // Relative path to the symbol map. + Symbol_file *string + + // Whether the system library uses symbol versions. + Unversioned *bool + + // list of header libs to re-export include directories from. + Export_public_headers []string `android:"arch_variant"` +} + +type vendorPublicLibraryStubDecorator struct { + *libraryDecorator + + Properties vendorPublicLibraryProperties + + versionScriptPath android.ModuleGenPath +} + +func (stub *vendorPublicLibraryStubDecorator) Name(name string) string { + return name + vendorPublicLibrarySuffix +} + +func (stub *vendorPublicLibraryStubDecorator) compilerInit(ctx BaseModuleContext) { + stub.baseCompiler.compilerInit(ctx) + + name := ctx.baseModuleName() + if strings.HasSuffix(name, vendorPublicLibrarySuffix) { + ctx.PropertyErrorf("name", "Do not append %q manually, just use the base name", vendorPublicLibrarySuffix) + } + + vendorPublicLibrariesLock.Lock() + defer vendorPublicLibrariesLock.Unlock() + for _, lib := range vendorPublicLibraries { + if lib == name { + return + } + } + vendorPublicLibraries = append(vendorPublicLibraries, name) +} + +func (stub *vendorPublicLibraryStubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags { + flags = stub.baseCompiler.compilerFlags(ctx, flags, deps) + return addStubLibraryCompilerFlags(flags) +} + +func (stub *vendorPublicLibraryStubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { + objs, versionScript := compileStubLibrary(ctx, flags, String(stub.Properties.Symbol_file), "current", "") + stub.versionScriptPath = versionScript + return objs +} + +func (stub *vendorPublicLibraryStubDecorator) linkerDeps(ctx DepsContext, deps Deps) Deps { + headers := stub.Properties.Export_public_headers + deps.HeaderLibs = append(deps.HeaderLibs, headers...) + deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, headers...) + return deps +} + +func (stub *vendorPublicLibraryStubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + stub.libraryDecorator.libName = strings.TrimSuffix(ctx.ModuleName(), vendorPublicLibrarySuffix) + return stub.libraryDecorator.linkerFlags(ctx, flags) +} + +func (stub *vendorPublicLibraryStubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, + objs Objects) android.Path { + if !Bool(stub.Properties.Unversioned) { + linkerScriptFlag := "-Wl,--version-script," + stub.versionScriptPath.String() + flags.LdFlags = append(flags.LdFlags, linkerScriptFlag) + } + return stub.libraryDecorator.link(ctx, flags, deps, objs) +} + +func vendorPublicLibraryFactory() android.Module { + module, library := NewLibrary(android.DeviceSupported) + library.BuildOnlyShared() + module.stl = nil + module.sanitize = nil + library.StripProperties.Strip.None = BoolPtr(true) + + stub := &vendorPublicLibraryStubDecorator{ + libraryDecorator: library, + } + module.compiler = stub + module.linker = stub + module.installer = nil + + module.AddProperties( + &stub.Properties, + &library.MutatedProperties, + &library.flagExporter.Properties) + + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibBoth) + return module +} + +func init() { + android.RegisterModuleType("vendor_public_library", vendorPublicLibraryFactory) +}