Merge "Allow platform modules to link to vendor public libraries"

This commit is contained in:
Treehugger Robot 2018-03-30 03:41:22 +00:00 committed by Gerrit Code Review
commit 01b715e94e
8 changed files with 309 additions and 0 deletions

View file

@ -163,6 +163,8 @@ bootstrap_go_package {
"cc/kernel_headers.go",
"cc/genrule.go",
"cc/vendor_public_library.go",
],
testSrcs: [
"cc/cc_test.go",

View file

@ -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)
}

View file

@ -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 {

View file

@ -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")
})
}

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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, " "))

150
cc/vendor_public_library.go Normal file
View file

@ -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)
}