Merge "Add bp2build mode to soong_build." am: 946e0b69d2

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

Change-Id: Ic200db7f6932a890a4814b6fdaf3f598ca9cb94f
This commit is contained in:
Jingwen Chen 2020-12-07 08:06:21 +00:00 committed by Automerger Merge Worker
commit abe87e8813
4 changed files with 93 additions and 14 deletions

View File

@ -44,6 +44,11 @@ func registerMutatorsToContext(ctx *blueprint.Context, mutators []*mutator) {
}
}
func registerMutatorsForBazelConversion(ctx *blueprint.Context) {
// FIXME(b/171263886): Start bringing in mutators to make the Bionic
// module subgraph suitable for automated conversion.
}
func registerMutators(ctx *blueprint.Context, preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc) {
mctx := &registerMutatorsContext{}

View File

@ -26,15 +26,40 @@ import (
// for calling the soong_build primary builder in the main build.ninja file.
func init() {
RegisterSingletonType("bazel_queryview", BazelQueryViewSingleton)
RegisterSingletonType("bazel_converter", BazelConverterSingleton)
}
// BazelQueryViewSingleton is the singleton responsible for registering the
// soong_build build statement that will convert the Soong module graph after
// applying *all* mutators, enabing the feature to query the final state of the
// Soong graph. This mode is meant for querying the build graph state, and not meant
// for generating BUILD files to be checked in.
func BazelQueryViewSingleton() Singleton {
return &bazelQueryViewSingleton{}
}
type bazelQueryViewSingleton struct{}
// BazelConverterSingleton is the singleton responsible for registering the soong_build
// build statement that will convert the Soong module graph by applying an alternate
// pipeline of mutators, with the goal of reaching semantic equivalence between the original
// Blueprint and final BUILD files. Using this mode, the goal is to be able to
// build with these BUILD files directly in the source tree.
func BazelConverterSingleton() Singleton {
return &bazelConverterSingleton{}
}
type bazelQueryViewSingleton struct{}
type bazelConverterSingleton struct{}
func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode bool) {
name := "queryview"
additionalEnvVars := ""
descriptionTemplate := "[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir"
if converterMode {
name = "bp2build"
additionalEnvVars = "CONVERT_TO_BAZEL=true"
descriptionTemplate = "[EXPERIMENTAL, PRE-PRODUCTION] Converting all Android.bp to Bazel BUILD files with %s at $outDir"
}
func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
// Create a build and rule statement, using the Bazel QueryView's WORKSPACE
// file as the output file marker.
var deps Paths
@ -42,22 +67,23 @@ func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
deps = append(deps, moduleListFilePath)
deps = append(deps, pathForBuildToolDep(ctx, ctx.Config().ProductVariablesFileName))
bazelQueryViewDirectory := PathForOutput(ctx, "queryview")
bazelQueryViewDirectory := PathForOutput(ctx, name)
bazelQueryViewWorkspaceFile := bazelQueryViewDirectory.Join(ctx, "WORKSPACE")
primaryBuilder := primaryBuilderPath(ctx)
bazelQueryView := ctx.Rule(pctx, "bazelQueryView",
blueprint.RuleParams{
Command: fmt.Sprintf(
"rm -rf ${outDir}/* && "+
"%s --bazel_queryview_dir ${outDir} %s && "+
"%s %s --bazel_queryview_dir ${outDir} %s && "+
"echo WORKSPACE: `cat %s` > ${outDir}/.queryview-depfile.d",
additionalEnvVars,
primaryBuilder.String(),
strings.Join(os.Args[1:], " "),
moduleListFilePath.String(), // Use the contents of Android.bp.list as the depfile.
),
CommandDeps: []string{primaryBuilder.String()},
Description: fmt.Sprintf(
"[EXPERIMENTAL, PRE-PRODUCTION] Creating the Bazel QueryView workspace with %s at $outDir",
descriptionTemplate,
primaryBuilder.Base()),
Deps: blueprint.DepsGCC,
Depfile: "${outDir}/.queryview-depfile.d",
@ -73,6 +99,14 @@ func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
},
})
// Add a phony target for building the Bazel QueryView
ctx.Phony("queryview", bazelQueryViewWorkspaceFile)
// Add a phony target for generating the workspace
ctx.Phony(name, bazelQueryViewWorkspaceFile)
}
func (c *bazelQueryViewSingleton) GenerateBuildActions(ctx SingletonContext) {
generateBuildActionsForBazelConversion(ctx, false)
}
func (c *bazelConverterSingleton) GenerateBuildActions(ctx SingletonContext) {
generateBuildActionsForBazelConversion(ctx, true)
}

View File

@ -90,6 +90,21 @@ func NewContext(config Config) *Context {
return ctx
}
// RegisterForBazelConversion registers an alternate shadow pipeline of
// singletons, module types and mutators to register for converting Blueprint
// files to semantically equivalent BUILD files.
func (ctx *Context) RegisterForBazelConversion() {
for _, t := range moduleTypes {
ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
}
bazelConverterSingleton := singleton{"bp2build", BazelConverterSingleton}
ctx.RegisterSingletonType(bazelConverterSingleton.name,
SingletonFactoryAdaptor(ctx, bazelConverterSingleton.factory))
registerMutatorsForBazelConversion(ctx.Context)
}
func (ctx *Context) Register() {
for _, t := range preSingletons {
ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))

View File

@ -51,10 +51,22 @@ func newNameResolver(config android.Config) *android.NameResolver {
return android.NewNameResolver(exportFilter)
}
// bazelConversionRequested checks that the user is intending to convert
// Blueprint to Bazel BUILD files.
func bazelConversionRequested(configuration android.Config) bool {
return configuration.IsEnvTrue("CONVERT_TO_BAZEL")
}
func newContext(srcDir string, configuration android.Config) *android.Context {
ctx := android.NewContext(configuration)
ctx.Register()
if !shouldPrepareBuildActions() {
if bazelConversionRequested(configuration) {
// Register an alternate set of singletons and mutators for bazel
// conversion for Bazel conversion.
ctx.RegisterForBazelConversion()
} else {
ctx.Register()
}
if !shouldPrepareBuildActions(configuration) {
configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
}
ctx.SetNameInterface(newNameResolver(configuration))
@ -114,6 +126,8 @@ func main() {
ctx = newContext(srcDir, configuration)
bootstrap.Main(ctx.Context, configuration, extraNinjaDeps...)
}
// Convert the Soong module graph into Bazel BUILD files.
if bazelQueryViewDir != "" {
if err := createBazelQueryView(ctx, bazelQueryViewDir); err != nil {
fmt.Fprintf(os.Stderr, "%s", err)
@ -130,7 +144,7 @@ func main() {
// TODO(ccross): make this a command line argument. Requires plumbing through blueprint
// to affect the command line of the primary builder.
if shouldPrepareBuildActions() {
if shouldPrepareBuildActions(configuration) {
metricsFile := filepath.Join(bootstrap.BuildDir, "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, metricsFile)
if err != nil {
@ -140,8 +154,19 @@ func main() {
}
}
func shouldPrepareBuildActions() bool {
// If we're writing soong_docs or queryview, don't write build.ninja or
// collect metrics.
return docFile == "" && bazelQueryViewDir == ""
// shouldPrepareBuildActions reads configuration and flags if build actions
// should be generated.
func shouldPrepareBuildActions(configuration android.Config) bool {
// Generating Soong docs
if docFile != "" {
return false
}
// Generating a directory for Soong query (queryview)
if bazelQueryViewDir != "" {
return false
}
// Generating a directory for converted Bazel BUILD files
return !bazelConversionRequested(configuration)
}