Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edd16668 authored by Sasha Smundak's avatar Sasha Smundak
Browse files

Add CcUnstrippedInfo provider and use it in mixed builds

The build uses unstripped binary/shared library to extract function
signatures, so for each each target of this kind Bazel should return
its unstripped version, too.

Fixes: 220164721
Test: treehugger

Change-Id: Id5f6143340519bf2ae98791a9e981d1306bb08d1
parent d5384e83
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -144,6 +144,9 @@ type BazelContext interface {
	// Returns the results of the GetApexInfo query (including output files)
	GetApexInfo(label string, cfgkey configKey) (cquery.ApexCqueryInfo, error)

	// Returns the results of the GetCcUnstrippedInfo query
	GetCcUnstrippedInfo(label string, cfgkey configKey) (cquery.CcUnstrippedInfo, error)

	// ** end Cquery Results Retrieval Functions

	// Issues commands to Bazel to receive results for all cquery requests
@@ -223,6 +226,7 @@ type MockBazelContext struct {
	LabelToCcInfo       map[string]cquery.CcInfo
	LabelToPythonBinary map[string]string
	LabelToApexInfo     map[string]cquery.ApexCqueryInfo
	LabelToCcBinary     map[string]cquery.CcUnstrippedInfo
}

func (m MockBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
@@ -248,6 +252,11 @@ func (n MockBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryI
	panic("unimplemented")
}

func (m MockBazelContext) GetCcUnstrippedInfo(label string, _ configKey) (cquery.CcUnstrippedInfo, error) {
	result, _ := m.LabelToCcBinary[label]
	return result, nil
}

func (m MockBazelContext) InvokeBazel(_ Config) error {
	panic("unimplemented")
}
@@ -311,6 +320,14 @@ func (bazelCtx *bazelContext) GetApexInfo(label string, cfgKey configKey) (cquer
	return cquery.ApexCqueryInfo{}, fmt.Errorf("no bazel response found for %v", key)
}

func (bazelCtx *bazelContext) GetCcUnstrippedInfo(label string, cfgKey configKey) (cquery.CcUnstrippedInfo, error) {
	key := makeCqueryKey(label, cquery.GetCcUnstrippedInfo, cfgKey)
	if rawString, ok := bazelCtx.results[key]; ok {
		return cquery.GetCcUnstrippedInfo.ParseResult(strings.TrimSpace(rawString)), nil
	}
	return cquery.CcUnstrippedInfo{}, fmt.Errorf("no bazel response for %s", key)
}

func (n noopBazelContext) QueueBazelRequest(_ string, _ cqueryRequest, _ configKey) {
	panic("unimplemented")
}
@@ -331,6 +348,11 @@ func (n noopBazelContext) GetApexInfo(_ string, _ configKey) (cquery.ApexCqueryI
	panic("unimplemented")
}

func (n noopBazelContext) GetCcUnstrippedInfo(_ string, _ configKey) (cquery.CcUnstrippedInfo, error) {
	//TODO implement me
	panic("implement me")
}

func (n noopBazelContext) InvokeBazel(_ Config) error {
	panic("unimplemented")
}
+54 −5
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@ var (
	GetPythonBinary     = &getPythonBinaryRequestType{}
	GetCcInfo           = &getCcInfoType{}
	GetApexInfo         = &getApexInfoType{}
	GetCcUnstrippedInfo = &getCcUnstippedInfoType{}
)

type CcInfo struct {
@@ -30,6 +31,7 @@ type CcInfo struct {
	// but general cc_library will also have dynamic libraries in output files).
	RootDynamicLibraries []string
	TocFile              string
	UnstrippedOutput     string
}

type getOutputFilesRequestType struct{}
@@ -135,12 +137,17 @@ sharedLibraries = []
rootSharedLibraries = []

shared_info_tag = "//build/bazel/rules/cc:cc_library_shared.bzl%CcSharedLibraryOutputInfo"
unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
unstripped = ""

if shared_info_tag in providers(target):
  shared_info = providers(target)[shared_info_tag]
  path = shared_info.output_file.path
  sharedLibraries.append(path)
  rootSharedLibraries += [path]
  unstripped = path
  if unstripped_tag in providers(target):
    unstripped = providers(target)[unstripped_tag].unstripped.path
else:
  for linker_input in linker_inputs:
    for library in linker_input.libraries:
@@ -168,7 +175,8 @@ return json_encode({
	"Headers": headers,
	"RootStaticArchives": rootStaticArchives,
	"RootDynamicLibraries": rootSharedLibraries,
	"TocFile": toc_file
	"TocFile": toc_file,
	"UnstrippedOutput": unstripped,
})`

}
@@ -237,6 +245,47 @@ func (g getApexInfoType) ParseResult(rawString string) ApexCqueryInfo {
	return info
}

// getCcUnstrippedInfoType implements cqueryRequest interface. It handles the
// interaction with `bazel cquery` to retrieve CcUnstrippedInfo provided
// by the` cc_binary` and `cc_shared_library` rules.
type getCcUnstippedInfoType struct{}

func (g getCcUnstippedInfoType) Name() string {
	return "getCcUnstrippedInfo"
}

func (g getCcUnstippedInfoType) StarlarkFunctionBody() string {
	return `unstripped_tag = "//build/bazel/rules/cc:stripped_cc_common.bzl%CcUnstrippedInfo"
p = providers(target)
output_path = target.files.to_list()[0].path
unstripped = output_path
if unstripped_tag in p:
    unstripped = p[unstripped_tag].unstripped.files.to_list()[0].path
return json_encode({
    "OutputFile":  output_path,
    "UnstrippedOutput": unstripped,
})
`
}

// ParseResult returns a value obtained by parsing the result of the request's Starlark function.
// The given rawString must correspond to the string output which was created by evaluating the
// Starlark given in StarlarkFunctionBody.
func (g getCcUnstippedInfoType) ParseResult(rawString string) CcUnstrippedInfo {
	var info CcUnstrippedInfo
	decoder := json.NewDecoder(strings.NewReader(rawString))
	decoder.DisallowUnknownFields() //useful to detect typos, e.g. in unit tests
	if err := decoder.Decode(&info); err != nil {
		panic(fmt.Errorf("cannot parse cquery result '%s': %s", rawString, err))
	}
	return info
}

type CcUnstrippedInfo struct {
	OutputFile       string
	UnstrippedOutput string
}

// splitOrEmpty is a modification of strings.Split() that returns an empty list
// if the given string is empty.
func splitOrEmpty(s string, sep string) []string {
+28 −0
Original line number Diff line number Diff line
@@ -165,3 +165,31 @@ func TestGetApexInfoParseResults(t *testing.T) {
		}
	}
}

func TestGetCcUnstrippedParseResults(t *testing.T) {
	testCases := []struct {
		description    string
		input          string
		expectedOutput CcUnstrippedInfo
	}{
		{
			description:    "no result",
			input:          "{}",
			expectedOutput: CcUnstrippedInfo{},
		},
		{
			description: "one result",
			input:       `{"OutputFile":"myapp", "UnstrippedOutput":"myapp_unstripped"}`,
			expectedOutput: CcUnstrippedInfo{
				OutputFile:       "myapp",
				UnstrippedOutput: "myapp_unstripped",
			},
		},
	}
	for _, tc := range testCases {
		actualOutput := GetCcUnstrippedInfo.ParseResult(tc.input)
		if !reflect.DeepEqual(tc.expectedOutput, actualOutput) {
			t.Errorf("%q: expected %#v != actual %#v", tc.description, tc.expectedOutput, actualOutput)
		}
	}
}
+4 −9
Original line number Diff line number Diff line
@@ -577,25 +577,20 @@ var _ BazelHandler = (*ccBinaryBazelHandler)(nil)

func (handler *ccBinaryBazelHandler) QueueBazelCall(ctx android.BaseModuleContext, label string) {
	bazelCtx := ctx.Config().BazelContext
	bazelCtx.QueueBazelRequest(label, cquery.GetOutputFiles, android.GetConfigKey(ctx))
	bazelCtx.QueueBazelRequest(label, cquery.GetCcUnstrippedInfo, android.GetConfigKey(ctx))
}

func (handler *ccBinaryBazelHandler) ProcessBazelQueryResponse(ctx android.ModuleContext, label string) {
	bazelCtx := ctx.Config().BazelContext
	filePaths, err := bazelCtx.GetOutputFiles(label, android.GetConfigKey(ctx))
	info, err := bazelCtx.GetCcUnstrippedInfo(label, android.GetConfigKey(ctx))
	if err != nil {
		ctx.ModuleErrorf(err.Error())
		return
	}

	if len(filePaths) != 1 {
		ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, filePaths)
		return
	}
	outputFilePath := android.PathForBazelOut(ctx, filePaths[0])
	outputFilePath := android.PathForBazelOut(ctx, info.OutputFile)
	handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
	// TODO(b/220164721): We need to decide if we should return the stripped as the unstripped.
	handler.module.linker.(*binaryDecorator).unstrippedOutputFile = outputFilePath
	handler.module.linker.(*binaryDecorator).unstrippedOutputFile = android.PathForBazelOut(ctx, info.UnstrippedOutput)
}

func binaryBp2buildAttrs(ctx android.TopDownMutatorContext, m *Module) binaryAttributes {
+7 −3
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
package cc

import (
	"android/soong/bazel/cquery"
	"testing"

	"android/soong/android"
@@ -30,8 +31,11 @@ cc_binary {
	config := TestConfig(t.TempDir(), android.Android, nil, bp, nil)
	config.BazelContext = android.MockBazelContext{
		OutputBaseDir: "outputbase",
		LabelToOutputFiles: map[string][]string{
			"//foo/bar:bar": []string{"foo"},
		LabelToCcBinary: map[string]cquery.CcUnstrippedInfo{
			"//foo/bar:bar": cquery.CcUnstrippedInfo{
				OutputFile:       "foo",
				UnstrippedOutput: "foo.unstripped",
			},
		},
	}
	ctx := testCcWithConfig(t, config)
@@ -46,7 +50,7 @@ cc_binary {
	android.AssertDeepEquals(t, "output files", expectedOutputFiles, outputFiles.Strings())

	unStrippedFilePath := binMod.(*Module).UnstrippedOutputFile()
	expectedUnStrippedFile := "outputbase/execroot/__main__/foo"
	expectedUnStrippedFile := "outputbase/execroot/__main__/foo.unstripped"
	android.AssertStringEquals(t, "Unstripped output file", expectedUnStrippedFile, unStrippedFilePath.String())
}

Loading