Refactor mixed builds to only take one pass
This large refactoring has both immense performance implications and improves mixed builds complexity / usability. Summary: 1. Queueing calls to Bazel is done in a new mutator instead of a full soong_build pass. Normal soong_build flow is interrupted (via a functional hook in blueprint) to invoke bazel and parse its response. 2. Implementing mixed build support for additional modules is as simple as implementing MixedBuildsBuildable. In this interface, define the request that must be queued to Bazel, and then subsequently define how to handle the returned bazel cquery metadata. 3. Mixed builds consists of only a single pass. This greatly improves mixed build performance. Result: A 33% runtime improvement on soong analysis phase with mixed builds. Caveats: C++ BazelHandler handling still remains a bit of a mess; I did what I could within this CL's scope, but this may require additional cleanup. Test: Treehugger Test: Verified that aosp_arm ninja file is bit-for-bit identical with or without this change. Change-Id: I412d9c94d429105f4ebfafc84100d546069e6621
This commit is contained in:
70
cc/cc.go
70
cc/cc.go
@@ -772,6 +772,19 @@ func IsTestPerSrcDepTag(depTag blueprint.DependencyTag) bool {
|
||||
return ok && ccDepTag == testPerSrcDepTag
|
||||
}
|
||||
|
||||
// bazelHandler is the interface for a helper object related to deferring to Bazel for
|
||||
// processing a cc module (during Bazel mixed builds). Individual module types should define
|
||||
// their own bazel handler if they support being handled by Bazel.
|
||||
type BazelHandler interface {
|
||||
// QueueBazelCall invokes request-queueing functions on the BazelContext
|
||||
//so that these requests are handled when Bazel's cquery is invoked.
|
||||
QueueBazelCall(ctx android.BaseModuleContext, label string)
|
||||
|
||||
// ProcessBazelQueryResponse uses information retrieved from Bazel to set properties
|
||||
// on the current module with given label.
|
||||
ProcessBazelQueryResponse(ctx android.ModuleContext, label string)
|
||||
}
|
||||
|
||||
// Module contains the properties and members used by all C/C++ module types, and implements
|
||||
// the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces
|
||||
// to construct the output file. Behavior can be customized with a Customizer, or "decorator",
|
||||
@@ -811,7 +824,7 @@ type Module struct {
|
||||
compiler compiler
|
||||
linker linker
|
||||
installer installer
|
||||
bazelHandler android.BazelHandler
|
||||
bazelHandler BazelHandler
|
||||
|
||||
features []feature
|
||||
stl *stl
|
||||
@@ -1773,31 +1786,51 @@ func GetSubnameProperty(actx android.ModuleContext, c LinkableInterface) string
|
||||
return subName
|
||||
}
|
||||
|
||||
// Returns true if Bazel was successfully used for the analysis of this module.
|
||||
func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool {
|
||||
var bazelModuleLabel string
|
||||
var _ android.MixedBuildBuildable = (*Module)(nil)
|
||||
|
||||
func (c *Module) getBazelModuleLabel(ctx android.BaseModuleContext) string {
|
||||
if c.typ() == fullLibrary && c.static() {
|
||||
// cc_library is a special case in bp2build; two targets are generated -- one for each
|
||||
// of the shared and static variants. The shared variant keeps the module name, but the
|
||||
// static variant uses a different suffixed name.
|
||||
bazelModuleLabel = bazelLabelForStaticModule(actx, c)
|
||||
} else {
|
||||
bazelModuleLabel = c.GetBazelLabel(actx, c)
|
||||
return bazelLabelForStaticModule(ctx, c)
|
||||
}
|
||||
return c.GetBazelLabel(ctx, c)
|
||||
}
|
||||
|
||||
func (c *Module) QueueBazelCall(ctx android.BaseModuleContext) {
|
||||
c.bazelHandler.QueueBazelCall(ctx, c.getBazelModuleLabel(ctx))
|
||||
}
|
||||
|
||||
func (c *Module) IsMixedBuildSupported(ctx android.BaseModuleContext) bool {
|
||||
return c.bazelHandler != nil
|
||||
}
|
||||
|
||||
func (c *Module) ProcessBazelQueryResponse(ctx android.ModuleContext) {
|
||||
bazelModuleLabel := c.getBazelModuleLabel(ctx)
|
||||
|
||||
c.bazelHandler.ProcessBazelQueryResponse(ctx, bazelModuleLabel)
|
||||
|
||||
c.Properties.SubName = GetSubnameProperty(ctx, c)
|
||||
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
||||
if !apexInfo.IsForPlatform() {
|
||||
c.hideApexVariantFromMake = true
|
||||
}
|
||||
|
||||
bazelActionsUsed := false
|
||||
// Mixed builds mode is disabled for modules outside of device OS.
|
||||
// TODO(b/200841190): Support non-device OS in mixed builds.
|
||||
if android.MixedBuildsEnabled(actx) && c.bazelHandler != nil {
|
||||
bazelActionsUsed = c.bazelHandler.GenerateBazelBuildActions(actx, bazelModuleLabel)
|
||||
c.makeLinkType = GetMakeLinkType(ctx, c)
|
||||
|
||||
mctx := &moduleContext{
|
||||
ModuleContext: ctx,
|
||||
moduleContextImpl: moduleContextImpl{
|
||||
mod: c,
|
||||
},
|
||||
}
|
||||
return bazelActionsUsed
|
||||
mctx.ctx = mctx
|
||||
|
||||
c.maybeInstall(mctx, apexInfo)
|
||||
}
|
||||
|
||||
func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
|
||||
// TODO(cparsons): Any logic in this method occurring prior to querying Bazel should be
|
||||
// requested from Bazel instead.
|
||||
|
||||
// Handle the case of a test module split by `test_per_src` mutator.
|
||||
//
|
||||
// The `test_per_src` mutator adds an extra variation named "", depending on all the other
|
||||
@@ -1824,11 +1857,6 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) {
|
||||
}
|
||||
ctx.ctx = ctx
|
||||
|
||||
if c.maybeGenerateBazelActions(actx) {
|
||||
c.maybeInstall(ctx, apexInfo)
|
||||
return
|
||||
}
|
||||
|
||||
deps := c.depsToPaths(ctx)
|
||||
if ctx.Failed() {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user