Merge "libclang_rt_prebuilt_library_shared mixed builds" am: d1227b20aa

Original change: https://android-review.googlesource.com/c/platform/build/soong/+/1845157

Change-Id: Ifd4d5d502d5e159f0aa7261c3e4875681fb42b48
This commit is contained in:
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux 2022-01-20 21:39:31 +00:00 committed by Automerger Merge Worker
commit 76b40bab19
5 changed files with 216 additions and 28 deletions

View file

@ -14,6 +14,7 @@ var (
type CcInfo struct { type CcInfo struct {
OutputFiles []string OutputFiles []string
CcObjectFiles []string CcObjectFiles []string
CcSharedLibraryFiles []string
CcStaticLibraryFiles []string CcStaticLibraryFiles []string
Includes []string Includes []string
SystemIncludes []string SystemIncludes []string
@ -128,28 +129,43 @@ else:
if linker_input.owner == target.label: if linker_input.owner == target.label:
rootStaticArchives.append(library.static_library.path) rootStaticArchives.append(library.static_library.path)
rootDynamicLibraries = [] sharedLibraries = []
rootSharedLibraries = []
shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo" shared_info_tag = "@rules_cc//examples:experimental_cc_shared_library.bzl%CcSharedLibraryInfo"
if shared_info_tag in providers(target): if shared_info_tag in providers(target):
shared_info = providers(target)[shared_info_tag] shared_info = providers(target)[shared_info_tag]
for lib in shared_info.linker_input.libraries: for lib in shared_info.linker_input.libraries:
rootDynamicLibraries += [lib.dynamic_library.path] path = lib.dynamic_library.path
rootSharedLibraries += [path]
sharedLibraries.append(path)
else:
for linker_input in linker_inputs:
for library in linker_input.libraries:
if library.dynamic_library:
path = library.dynamic_library.path
sharedLibraries.append(path)
if linker_input.owner == target.label:
rootSharedLibraries.append(path)
toc_file = "" toc_file = ""
toc_file_tag = "//build/bazel/rules:generate_toc.bzl%CcTocInfo" toc_file_tag = "//build/bazel/rules:generate_toc.bzl%CcTocInfo"
if toc_file_tag in providers(target): if toc_file_tag in providers(target):
toc_file = providers(target)[toc_file_tag].toc.path toc_file = providers(target)[toc_file_tag].toc.path
else:
# NOTE: It's OK if there's no ToC, as Soong just uses it for optimization
pass
returns = [ returns = [
outputFiles, outputFiles,
staticLibraries,
ccObjectFiles, ccObjectFiles,
sharedLibraries,
staticLibraries,
includes, includes,
system_includes, system_includes,
headers, headers,
rootStaticArchives, rootStaticArchives,
rootDynamicLibraries, rootSharedLibraries,
[toc_file] [toc_file]
] ]
@ -160,28 +176,35 @@ return "|".join([", ".join(r) for r in returns])`
// The given rawString must correspond to the string output which was created by evaluating the // The given rawString must correspond to the string output which was created by evaluating the
// Starlark given in StarlarkFunctionBody. // Starlark given in StarlarkFunctionBody.
func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) { func (g getCcInfoType) ParseResult(rawString string) (CcInfo, error) {
var outputFiles []string const expectedLen = 10
var ccObjects []string
splitString := strings.Split(rawString, "|") splitString := strings.Split(rawString, "|")
if expectedLen := 9; len(splitString) != expectedLen { if len(splitString) != expectedLen {
return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString) return CcInfo{}, fmt.Errorf("Expected %d items, got %q", expectedLen, splitString)
} }
outputFilesString := splitString[0] outputFilesString := splitString[0]
ccStaticLibrariesString := splitString[1] ccObjectsString := splitString[1]
ccObjectsString := splitString[2] ccSharedLibrariesString := splitString[2]
outputFiles = splitOrEmpty(outputFilesString, ", ") ccStaticLibrariesString := splitString[3]
includesString := splitString[4]
systemIncludesString := splitString[5]
headersString := splitString[6]
rootStaticArchivesString := splitString[7]
rootDynamicLibrariesString := splitString[8]
tocFile := splitString[9] // NOTE: Will be the empty string if there wasn't
outputFiles := splitOrEmpty(outputFilesString, ", ")
ccObjects := splitOrEmpty(ccObjectsString, ", ")
ccSharedLibraries := splitOrEmpty(ccSharedLibrariesString, ", ")
ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ") ccStaticLibraries := splitOrEmpty(ccStaticLibrariesString, ", ")
ccObjects = splitOrEmpty(ccObjectsString, ", ") includes := splitOrEmpty(includesString, ", ")
includes := splitOrEmpty(splitString[3], ", ") systemIncludes := splitOrEmpty(systemIncludesString, ", ")
systemIncludes := splitOrEmpty(splitString[4], ", ") headers := splitOrEmpty(headersString, ", ")
headers := splitOrEmpty(splitString[5], ", ") rootStaticArchives := splitOrEmpty(rootStaticArchivesString, ", ")
rootStaticArchives := splitOrEmpty(splitString[6], ", ") rootDynamicLibraries := splitOrEmpty(rootDynamicLibrariesString, ", ")
rootDynamicLibraries := splitOrEmpty(splitString[7], ", ")
tocFile := splitString[8] // NOTE: Will be the empty string if there wasn't
return CcInfo{ return CcInfo{
OutputFiles: outputFiles, OutputFiles: outputFiles,
CcObjectFiles: ccObjects, CcObjectFiles: ccObjects,
CcSharedLibraryFiles: ccSharedLibraries,
CcStaticLibraryFiles: ccStaticLibraries, CcStaticLibraryFiles: ccStaticLibraries,
Includes: includes, Includes: includes,
SystemIncludes: systemIncludes, SystemIncludes: systemIncludes,

View file

@ -63,6 +63,8 @@ func TestGetPythonBinaryParseResults(t *testing.T) {
} }
func TestGetCcInfoParseResults(t *testing.T) { func TestGetCcInfoParseResults(t *testing.T) {
const expectedSplits = 10
noResult := strings.Repeat("|", expectedSplits-1)
testCases := []struct { testCases := []struct {
description string description string
input string input string
@ -71,10 +73,11 @@ func TestGetCcInfoParseResults(t *testing.T) {
}{ }{
{ {
description: "no result", description: "no result",
input: "||||||||", input: noResult,
expectedOutput: CcInfo{ expectedOutput: CcInfo{
OutputFiles: []string{}, OutputFiles: []string{},
CcObjectFiles: []string{}, CcObjectFiles: []string{},
CcSharedLibraryFiles: []string{},
CcStaticLibraryFiles: []string{}, CcStaticLibraryFiles: []string{},
Includes: []string{}, Includes: []string{},
SystemIncludes: []string{}, SystemIncludes: []string{},
@ -86,10 +89,11 @@ func TestGetCcInfoParseResults(t *testing.T) {
}, },
{ {
description: "only output", description: "only output",
input: "test||||||||", input: "test" + noResult,
expectedOutput: CcInfo{ expectedOutput: CcInfo{
OutputFiles: []string{"test"}, OutputFiles: []string{"test"},
CcObjectFiles: []string{}, CcObjectFiles: []string{},
CcSharedLibraryFiles: []string{},
CcStaticLibraryFiles: []string{}, CcStaticLibraryFiles: []string{},
Includes: []string{}, Includes: []string{},
SystemIncludes: []string{}, SystemIncludes: []string{},
@ -99,12 +103,38 @@ func TestGetCcInfoParseResults(t *testing.T) {
TocFile: "", TocFile: "",
}, },
}, },
{
description: "only ToC",
input: noResult + "test",
expectedOutput: CcInfo{
OutputFiles: []string{},
CcObjectFiles: []string{},
CcSharedLibraryFiles: []string{},
CcStaticLibraryFiles: []string{},
Includes: []string{},
SystemIncludes: []string{},
Headers: []string{},
RootStaticArchives: []string{},
RootDynamicLibraries: []string{},
TocFile: "test",
},
},
{ {
description: "all items set", description: "all items set",
input: "out1, out2|static_lib1, static_lib2|object1, object2|., dir/subdir|system/dir, system/other/dir|dir/subdir/hdr.h|rootstaticarchive1|rootdynamiclibrary1|lib.so.toc", input: "out1, out2" +
"|object1, object2" +
"|shared_lib1, shared_lib2" +
"|static_lib1, static_lib2" +
"|., dir/subdir" +
"|system/dir, system/other/dir" +
"|dir/subdir/hdr.h" +
"|rootstaticarchive1" +
"|rootdynamiclibrary1" +
"|lib.so.toc",
expectedOutput: CcInfo{ expectedOutput: CcInfo{
OutputFiles: []string{"out1", "out2"}, OutputFiles: []string{"out1", "out2"},
CcObjectFiles: []string{"object1", "object2"}, CcObjectFiles: []string{"object1", "object2"},
CcSharedLibraryFiles: []string{"shared_lib1", "shared_lib2"},
CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"}, CcStaticLibraryFiles: []string{"static_lib1", "static_lib2"},
Includes: []string{".", "dir/subdir"}, Includes: []string{".", "dir/subdir"},
SystemIncludes: []string{"system/dir", "system/other/dir"}, SystemIncludes: []string{"system/dir", "system/other/dir"},
@ -118,22 +148,22 @@ func TestGetCcInfoParseResults(t *testing.T) {
description: "too few result splits", description: "too few result splits",
input: "|", input: "|",
expectedOutput: CcInfo{}, expectedOutput: CcInfo{},
expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, []string{"", ""}), expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, []string{"", ""}),
}, },
{ {
description: "too many result splits", description: "too many result splits",
input: strings.Repeat("|", 50), input: strings.Repeat("|", expectedSplits+1), // 2 too many
expectedOutput: CcInfo{}, expectedOutput: CcInfo{},
expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", 9, make([]string, 51)), expectedErrorMessage: fmt.Sprintf("Expected %d items, got %q", expectedSplits, make([]string, expectedSplits+2)),
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
actualOutput, err := GetCcInfo.ParseResult(tc.input) actualOutput, err := GetCcInfo.ParseResult(tc.input)
if (err == nil && tc.expectedErrorMessage != "") || if (err == nil && tc.expectedErrorMessage != "") ||
(err != nil && err.Error() != tc.expectedErrorMessage) { (err != nil && err.Error() != tc.expectedErrorMessage) {
t.Errorf("%q: expected Error %s, got %s", tc.description, tc.expectedErrorMessage, err) t.Errorf("%q:\nexpected Error %s\n, got %s", tc.description, tc.expectedErrorMessage, err)
} else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) { } else if err == nil && !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput) t.Errorf("%q:\n expected %#v\n!= actual %#v", tc.description, tc.expectedOutput, actualOutput)
} }
} }
} }

View file

@ -241,7 +241,7 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries
entries.Class = "SHARED_LIBRARIES" entries.Class = "SHARED_LIBRARIES"
entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
entries.SetString("LOCAL_SOONG_TOC", library.toc().String()) entries.SetString("LOCAL_SOONG_TOC", library.toc().String())
if !library.buildStubs() { if !library.buildStubs() && library.unstrippedOutputFile != nil {
entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String()) entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String())
} }
if len(library.Properties.Overrides) > 0 { if len(library.Properties.Overrides) > 0 {

View file

@ -298,6 +298,7 @@ func NewPrebuiltSharedLibrary(hod android.HostOrDeviceSupported) (*Module, *libr
module, library := NewPrebuiltLibrary(hod, "srcs") module, library := NewPrebuiltLibrary(hod, "srcs")
library.BuildOnlyShared() library.BuildOnlyShared()
module.bazelable = true module.bazelable = true
module.bazelHandler = &prebuiltSharedLibraryBazelHandler{module: module, library: library}
// Prebuilt shared libraries can be included in APEXes // Prebuilt shared libraries can be included in APEXes
android.InitApexModule(module) android.InitApexModule(module)
@ -426,6 +427,69 @@ func (h *prebuiltStaticLibraryBazelHandler) GenerateBazelBuildActions(ctx androi
return true return true
} }
type prebuiltSharedLibraryBazelHandler struct {
android.BazelHandler
module *Module
library *libraryDecorator
}
func (h *prebuiltSharedLibraryBazelHandler) GenerateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
ccInfo, ok, err := bazelCtx.GetCcInfo(label, android.GetConfigKey(ctx))
if err != nil {
ctx.ModuleErrorf("Error getting Bazel CcInfo for %s: %s", label, err)
}
if !ok {
return false
}
sharedLibs := ccInfo.CcSharedLibraryFiles
if len(sharedLibs) != 1 {
ctx.ModuleErrorf("expected 1 shared library from bazel target %s, got %q", label, sharedLibs)
return false
}
// TODO(b/184543518): cc_prebuilt_library_shared may have properties for re-exporting flags
// TODO(eakammer):Add stub-related flags if this library is a stub library.
// h.library.exportVersioningMacroIfNeeded(ctx)
// Dependencies on this library will expect collectedSnapshotHeaders to be set, otherwise
// validation will fail. For now, set this to an empty list.
// TODO(cparsons): More closely mirror the collectHeadersForSnapshot implementation.
h.library.collectedSnapshotHeaders = android.Paths{}
if len(sharedLibs) == 0 {
h.module.outputFile = android.OptionalPath{}
return true
}
out := android.PathForBazelOut(ctx, sharedLibs[0])
h.module.outputFile = android.OptionalPathForPath(out)
// FIXME(b/214600441): We don't yet strip prebuilt shared libraries
h.library.unstrippedOutputFile = out
var toc android.Path
if len(ccInfo.TocFile) > 0 {
toc = android.PathForBazelOut(ctx, ccInfo.TocFile)
} else {
toc = out // Just reuse `out` so ninja still gets an input but won't matter
}
info := SharedLibraryInfo{
SharedLibrary: out,
TableOfContents: android.OptionalPathForPath(toc),
Target: ctx.Target(),
}
ctx.SetProvider(SharedLibraryInfoProvider, info)
h.library.setFlagExporterInfoFromCcInfo(ctx, ccInfo)
h.module.maybeUnhideFromMake()
return true
}
func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt { func (p *prebuiltObjectLinker) prebuilt() *android.Prebuilt {
return &p.Prebuilt return &p.Prebuilt
} }

View file

@ -19,7 +19,7 @@ import (
"testing" "testing"
"android/soong/android" "android/soong/android"
"android/soong/bazel/cquery"
"github.com/google/blueprint" "github.com/google/blueprint"
) )
@ -378,3 +378,74 @@ func TestPrebuiltLibrarySanitized(t *testing.T) {
static2 = ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static_hwasan").Module().(*Module) static2 = ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static_hwasan").Module().(*Module)
assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a") assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a")
} }
func TestPrebuiltLibrarySharedWithBazelWithoutToc(t *testing.T) {
const bp = `
cc_prebuilt_library_shared {
name: "foo",
srcs: ["foo.so"],
bazel_module: { label: "//foo/bar:bar" },
}`
outBaseDir := "outputbase"
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outBaseDir,
LabelToCcInfo: map[string]cquery.CcInfo{
"//foo/bar:bar": cquery.CcInfo{
CcSharedLibraryFiles: []string{"foo.so"},
},
},
}
ctx := testCcWithConfig(t, config)
sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
pathPrefix := outBaseDir + "/execroot/__main__/"
info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
android.AssertPathRelativeToTopEquals(t, "prebuilt shared library",
pathPrefix+"foo.so", info.SharedLibrary)
android.AssertPathRelativeToTopEquals(t, "prebuilt's 'nullary' ToC",
pathPrefix+"foo.so", info.TableOfContents.Path())
outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
if err != nil {
t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
}
expectedOutputFiles := []string{pathPrefix + "foo.so"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}
func TestPrebuiltLibrarySharedWithBazelWithToc(t *testing.T) {
const bp = `
cc_prebuilt_library_shared {
name: "foo",
srcs: ["foo.so"],
bazel_module: { label: "//foo/bar:bar" },
}`
outBaseDir := "outputbase"
config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
config.BazelContext = android.MockBazelContext{
OutputBaseDir: outBaseDir,
LabelToCcInfo: map[string]cquery.CcInfo{
"//foo/bar:bar": cquery.CcInfo{
CcSharedLibraryFiles: []string{"foo.so"},
TocFile: "toc",
},
},
}
ctx := testCcWithConfig(t, config)
sharedFoo := ctx.ModuleForTests("foo", "android_arm_armv7-a-neon_shared").Module()
pathPrefix := outBaseDir + "/execroot/__main__/"
info := ctx.ModuleProvider(sharedFoo, SharedLibraryInfoProvider).(SharedLibraryInfo)
android.AssertPathRelativeToTopEquals(t, "prebuilt shared library's ToC",
pathPrefix+"toc", info.TableOfContents.Path())
android.AssertPathRelativeToTopEquals(t, "prebuilt shared library",
pathPrefix+"foo.so", info.SharedLibrary)
outputFiles, err := sharedFoo.(android.OutputFileProducer).OutputFiles("")
if err != nil {
t.Errorf("Unexpected error getting cc_object outputfiles %s", err)
}
expectedOutputFiles := []string{pathPrefix + "foo.so"}
android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())
}