Merge changes from topic "cc_prebuilt_stubs" into main

* changes:
  Skip `-Wl,--version-script` on libclang_rt.* stubs (temp hack)
  Special case the stubgen args for bionic libs
  Add stub generation support to cc_prebuilt_library
This commit is contained in:
Spandan Das
2024-08-27 19:37:08 +00:00
committed by Gerrit Code Review
4 changed files with 153 additions and 52 deletions

View File

@@ -906,7 +906,7 @@ func TestApexWithStubs(t *testing.T) {
cc_library {
name: "mylib",
srcs: ["mylib.cpp"],
shared_libs: ["mylib2", "mylib3"],
shared_libs: ["mylib2", "mylib3", "my_prebuilt_platform_lib", "my_prebuilt_platform_stub_only_lib"],
system_shared_libs: [],
stl: "none",
apex_available: [ "myapex" ],
@@ -919,6 +919,7 @@ func TestApexWithStubs(t *testing.T) {
system_shared_libs: [],
stl: "none",
stubs: {
symbol_file: "mylib2.map.txt",
versions: ["1", "2", "3"],
},
}
@@ -930,6 +931,7 @@ func TestApexWithStubs(t *testing.T) {
system_shared_libs: [],
stl: "none",
stubs: {
symbol_file: "mylib3.map.txt",
versions: ["10", "11", "12"],
},
apex_available: [ "myapex" ],
@@ -943,6 +945,24 @@ func TestApexWithStubs(t *testing.T) {
apex_available: [ "myapex" ],
}
cc_prebuilt_library_shared {
name: "my_prebuilt_platform_lib",
stubs: {
symbol_file: "my_prebuilt_platform_lib.map.txt",
versions: ["1", "2", "3"],
},
srcs: ["foo.so"],
}
// Similar to my_prebuilt_platform_lib, but this library only provides stubs, i.e. srcs is empty
cc_prebuilt_library_shared {
name: "my_prebuilt_platform_stub_only_lib",
stubs: {
symbol_file: "my_prebuilt_platform_stub_only_lib.map.txt",
versions: ["1", "2", "3"],
}
}
rust_binary {
name: "foo.rust",
srcs: ["foo.rs"],
@@ -1022,6 +1042,20 @@ func TestApexWithStubs(t *testing.T) {
apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule")
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so")
// Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
ensureContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_lib.so")
// ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_lib.so")
// Ensure that genstub for platform-provided lib is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
// Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib
ensureContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_stub_only_lib.so")
// ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib
ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_stub_only_lib.so")
// Ensure that genstub for platform-provided lib is invoked with --systemapi
ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_stub_only_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi")
}
func TestApexShouldNotEmbedStubVariant(t *testing.T) {
@@ -1156,6 +1190,7 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
system_shared_libs: [],
stl: "none",
stubs: {
symbol_file: "mylib2.map.txt",
versions: ["28", "29", "30", "current"],
},
min_sdk_version: "28",
@@ -1168,6 +1203,7 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) {
system_shared_libs: [],
stl: "none",
stubs: {
symbol_file: "mylib3.map.txt",
versions: ["28", "29", "30", "current"],
},
apex_available: [ "myapex" ],
@@ -11940,7 +11976,7 @@ func TestPrebuiltStubNoinstall(t *testing.T) {
).RunTest(t)
ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld")
android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared/libfoo.so")
android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared_current/libfoo.so")
installRules := result.InstallMakeRulesForTesting(t)

View File

@@ -927,7 +927,7 @@ func TestLlndkLibrary(t *testing.T) {
cc_prebuilt_library_shared {
name: "libllndkprebuilt",
stubs: { versions: ["1", "2"] },
stubs: { versions: ["1", "2"] , symbol_file: "libllndkprebuilt.map.txt" },
llndk: {
symbol_file: "libllndkprebuilt.map.txt",
},

View File

@@ -594,43 +594,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
return objs
}
if library.buildStubs() {
symbolFile := String(library.Properties.Stubs.Symbol_file)
if symbolFile != "" && !strings.HasSuffix(symbolFile, ".map.txt") {
ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
return Objects{}
}
library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
// systemapi, respectively. The former is for symbols defined in platform libraries
// and the latter is for symbols defined in APEXes.
// A single library can contain either # apex or # systemapi, but not both.
// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
// However, having this distinction helps guard accidental
// promotion or demotion of API and also helps the API review process b/191371676
var flag string
if ctx.Module().(android.ApexModule).NotInPlatform() {
flag = "--apex"
} else {
flag = "--systemapi"
}
// b/184712170, unless the lib is an NDK library, exclude all public symbols from
// the stub so that it is mandated that all symbols are explicitly marked with
// either apex or systemapi.
if !ctx.Module().(*Module).IsNdk(ctx.Config()) {
flag = flag + " --no-ndk"
}
nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
library.versionScriptPath = android.OptionalPathForPath(
nativeAbiResult.versionScript)
// Parse symbol file to get API list for coverage
if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
return library.compileModuleLibApiStubs(ctx, flags, deps)
}
srcs := library.baseCompiler.Properties.Srcs.GetOrDefault(ctx, nil)
@@ -681,6 +645,61 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa
return objs
}
// Compile stubs for the API surface between platform and apex
// This method will be used by source and prebuilt cc module types.
func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
// TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
if library.Properties.Stubs.Symbol_file == nil {
return Objects{}
}
symbolFile := String(library.Properties.Stubs.Symbol_file)
library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile)
// b/239274367 --apex and --systemapi filters symbols tagged with # apex and #
// systemapi, respectively. The former is for symbols defined in platform libraries
// and the latter is for symbols defined in APEXes.
// A single library can contain either # apex or # systemapi, but not both.
// The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op.
// However, having this distinction helps guard accidental
// promotion or demotion of API and also helps the API review process b/191371676
var flag string
if ctx.Module().(android.ApexModule).NotInPlatform() {
flag = "--apex"
} else {
flag = "--systemapi"
}
// b/184712170, unless the lib is an NDK library, exclude all public symbols from
// the stub so that it is mandated that all symbols are explicitly marked with
// either apex or systemapi.
if !ctx.Module().(*Module).IsNdk(ctx.Config()) &&
// the symbol files of libclang libs are autogenerated and do not contain systemapi tags
// TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols
!strings.Contains(ctx.ModuleName(), "libclang_rt") {
flag = flag + " --no-ndk"
}
// TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches.
if isBionic(ctx.baseModuleName()) {
// set the flags explicitly for bionic libs.
// this is necessary for development in minimal branches which does not contain bionic/*.
// In such minimal branches, e.g. on the prebuilt libc stubs
// 1. IsNdk will return false (since the ndk_library definition for libc does not exist)
// 2. NotInPlatform will return true (since the source com.android.runtime does not exist)
flag = "--apex"
}
nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile,
android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag)
objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc)
library.versionScriptPath = android.OptionalPathForPath(
nativeAbiResult.versionScript)
// Parse symbol file to get API list for coverage
if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() {
library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile)
}
return objs
}
type libraryInterface interface {
versionedInterface
@@ -1182,12 +1201,17 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext,
return unstrippedOutputFile
}
func addStubDependencyProviders(ctx ModuleContext) {
// Visits the stub variants of the library and returns a struct containing the stub .so paths
func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary {
stubsInfo := []SharedStubLibrary{}
stubs := ctx.GetDirectDepsWithTag(stubImplDepTag)
if len(stubs) > 0 {
var stubsInfo []SharedStubLibrary
for _, stub := range stubs {
stubInfo, _ := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
stubInfo, ok := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider)
// TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk.
if !ok {
continue
}
flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider)
stubsInfo = append(stubsInfo, SharedStubLibrary{
Version: moduleLibraryInterface(stub).stubsVersion(),
@@ -1195,12 +1219,15 @@ func addStubDependencyProviders(ctx ModuleContext) {
FlagExporterInfo: flagInfo,
})
}
if len(stubsInfo) > 0 {
android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{
SharedStubLibraries: stubsInfo,
IsLLNDK: ctx.IsLlndk(),
})
}
}
return stubsInfo
}
func (library *libraryDecorator) unstrippedOutputFilePath() android.Path {
return library.unstrippedOutputFile

View File

@@ -16,6 +16,7 @@ package cc
import (
"path/filepath"
"strings"
"github.com/google/blueprint/proptools"
@@ -95,10 +96,6 @@ func (p *prebuiltLibraryLinker) linkerDeps(ctx DepsContext, deps Deps) Deps {
return p.libraryDecorator.linkerDeps(ctx, deps)
}
func (p *prebuiltLibraryLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags {
return flags
}
func (p *prebuiltLibraryLinker) linkerProps() []interface{} {
return p.libraryDecorator.linkerProps()
}
@@ -117,6 +114,30 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
// TODO(ccross): verify shared library dependencies
srcs := p.prebuiltSrcs(ctx)
stubInfo := addStubDependencyProviders(ctx)
// Stub variants will create a stub .so file from stub .c files
if p.buildStubs() && objs.objFiles != nil {
// TODO (b/275273834): Make objs.objFiles == nil a hard error when the symbol files have been added to module sdk.
// The map.txt files of libclang_rt.* contain version information, but the checked in .so files do not.
// e.g. libclang_rt.* libs impl
// $ nm -D prebuilts/../libclang_rt.hwasan-aarch64-android.so
// __hwasan_init
// stubs generated from .map.txt
// $ nm -D out/soong/.intermediates/../<stubs>/libclang_rt.hwasan-aarch64-android.so
// __hwasan_init@@LIBCLANG_RT_ASAN
// Special-case libclang_rt.* libs to account for this discrepancy.
// TODO (spandandas): Remove this special case https://r.android.com/3236596 has been submitted, and a new set of map.txt
// files of libclang_rt.* libs have been generated.
if strings.Contains(ctx.ModuleName(), "libclang_rt.") {
p.versionScriptPath = android.OptionalPathForPath(nil)
}
return p.linkShared(ctx, flags, deps, objs)
}
if len(srcs) > 0 {
if len(srcs) > 1 {
ctx.PropertyErrorf("srcs", "multiple prebuilt source files")
@@ -203,6 +224,16 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext,
return outputFile
}
} else if p.shared() && len(stubInfo) > 0 {
// This is a prebuilt which does not have any implementation (nil `srcs`), but provides APIs.
// Provide the latest (i.e. `current`) stubs to reverse dependencies.
latestStub := stubInfo[len(stubInfo)-1].SharedLibraryInfo.SharedLibrary
android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{
SharedLibrary: latestStub,
Target: ctx.Target(),
})
return latestStub
}
if p.header() {
@@ -257,11 +288,11 @@ func (p *prebuiltLibraryLinker) implementationModuleName(name string) string {
func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) (*Module, *libraryDecorator) {
module, library := NewLibrary(hod)
module.compiler = nil
prebuilt := &prebuiltLibraryLinker{
libraryDecorator: library,
}
module.compiler = prebuilt
module.linker = prebuilt
module.library = prebuilt
@@ -280,6 +311,13 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string)
return module, library
}
func (p *prebuiltLibraryLinker) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
if p.buildStubs() && p.stubsVersion() != "" {
return p.compileModuleLibApiStubs(ctx, flags, deps)
}
return Objects{}
}
// cc_prebuilt_library installs a precompiled shared library that are
// listed in the srcs property in the device's directory.
func PrebuiltLibraryFactory() android.Module {