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

Commit daa54bcb authored by Jingwen Chen's avatar Jingwen Chen
Browse files

Implement code-generation step for bp2build.

Implement bp2build codegen as a discrete step that runs after an
alternatively registered pipeline of mutators, instead of a
presingleton.

bp2build codegen requires a Context that supports VisitAllModules and
PathContext, so this CL also makes a BpToBuildWrapperContext that
conforms to PathContext by adding two method implementations.

Test: GENERATE_BAZEL_FILES=true m nothing && bazel query //... --config=bp2build | wc -l # 31433
Test: m queryview && bazel query //... --config=queryview # 63638

Change-Id: I0dd359746584b228046d2d0ff00895f28f9bdfc3
parent 4d31a041
Loading
Loading
Loading
Loading
+4 −16
Original line number Diff line number Diff line
@@ -37,9 +37,6 @@ type singleton struct {
var singletons []singleton
var preSingletons []singleton

var bazelConverterSingletons []singleton
var bazelConverterPreSingletons []singleton

type mutator struct {
	name            string
	bottomUpMutator blueprint.BottomUpMutator
@@ -94,14 +91,6 @@ func RegisterPreSingletonType(name string, factory SingletonFactory) {
	preSingletons = append(preSingletons, singleton{name, factory})
}

func RegisterBazelConverterSingletonType(name string, factory SingletonFactory) {
	bazelConverterSingletons = append(bazelConverterSingletons, singleton{name, factory})
}

func RegisterBazelConverterPreSingletonType(name string, factory SingletonFactory) {
	bazelConverterPreSingletons = append(bazelConverterPreSingletons, singleton{name, factory})
}

type Context struct {
	*blueprint.Context
	config Config
@@ -117,21 +106,20 @@ func NewContext(config Config) *Context {
// singletons, module types and mutators to register for converting Blueprint
// files to semantically equivalent BUILD files.
func (ctx *Context) RegisterForBazelConversion() {
	for _, t := range bazelConverterPreSingletons {
		ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
	}

	for _, t := range moduleTypes {
		ctx.RegisterModuleType(t.name, ModuleFactoryAdaptor(t.factory))
	}

	for _, t := range bazelConverterSingletons {
	// Required for SingletonModule types, even though we are not using them.
	for _, t := range singletons {
		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
	}

	registerMutatorsForBazelConversion(ctx.Context)
}

// Register the pipeline of singletons, module types, and mutators for
// generating build.ninja and other files for Kati, from Android.bp files.
func (ctx *Context) Register() {
	for _, t := range preSingletons {
		ctx.RegisterPreSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
+12 −30
Original line number Diff line number Diff line
@@ -16,52 +16,34 @@ package bp2build

import (
	"android/soong/android"
	"fmt"
	"os"
)

// The Bazel bp2build singleton is responsible for writing .bzl files that are equivalent to
// The Bazel bp2build code generator is responsible for writing .bzl files that are equivalent to
// Android.bp files that are capable of being built with Bazel.
func init() {
	android.RegisterBazelConverterPreSingletonType("androidbp_to_build", AndroidBpToBuildSingleton)
}

func AndroidBpToBuildSingleton() android.Singleton {
	return &androidBpToBuildSingleton{
		name: "bp2build",
	}
}

type androidBpToBuildSingleton struct {
	name      string
	outputDir android.OutputPath
}

func (s *androidBpToBuildSingleton) GenerateBuildActions(ctx android.SingletonContext) {
	s.outputDir = android.PathForOutput(ctx, s.name)
	android.RemoveAllOutputDir(s.outputDir)

	if !ctx.Config().IsEnvTrue("CONVERT_TO_BAZEL") {
		return
	}
func Codegen(ctx CodegenContext) {
	outputDir := android.PathForOutput(ctx, "bp2build")
	android.RemoveAllOutputDir(outputDir)

	ruleShims := CreateRuleShims(android.ModuleTypeFactories())

	buildToTargets := GenerateSoongModuleTargets(ctx)
	buildToTargets := GenerateSoongModuleTargets(ctx.Context())

	filesToWrite := CreateBazelFiles(ruleShims, buildToTargets)
	for _, f := range filesToWrite {
		if err := s.writeFile(ctx, f); err != nil {
			ctx.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
		if err := writeFile(outputDir, ctx, f); err != nil {
			fmt.Errorf("Failed to write %q (dir %q) due to %q", f.Basename, f.Dir, err)
		}
	}
}

func (s *androidBpToBuildSingleton) getOutputPath(ctx android.PathContext, dir string) android.OutputPath {
	return s.outputDir.Join(ctx, dir)
func writeFile(outputDir android.OutputPath, ctx android.PathContext, f BazelFile) error {
	return writeReadOnlyFile(ctx, getOutputPath(outputDir, ctx, f.Dir), f.Basename, f.Contents)
}

func (s *androidBpToBuildSingleton) writeFile(ctx android.PathContext, f BazelFile) error {
	return writeReadOnlyFile(ctx, s.getOutputPath(ctx, f.Dir), f.Basename, f.Contents)
func getOutputPath(outputDir android.OutputPath, ctx android.PathContext, dir string) android.OutputPath {
	return outputDir.Join(ctx, dir)
}

// The auto-conversion directory should be read-only, sufficient for bazel query. The files
+22 −4
Original line number Diff line number Diff line
@@ -39,8 +39,26 @@ type bpToBuildContext interface {
	ModuleSubDir(module blueprint.Module) string
	ModuleType(module blueprint.Module) string

	VisitAllModulesBlueprint(visit func(blueprint.Module))
	VisitDirectDeps(module android.Module, visit func(android.Module))
	VisitAllModules(visit func(blueprint.Module))
	VisitDirectDeps(module blueprint.Module, visit func(blueprint.Module))
}

type CodegenContext struct {
	config  android.Config
	context android.Context
}

func (ctx CodegenContext) AddNinjaFileDeps(...string) {}
func (ctx CodegenContext) Config() android.Config     { return ctx.config }
func (ctx CodegenContext) Context() android.Context   { return ctx.context }

// NewCodegenContext creates a wrapper context that conforms to PathContext for
// writing BUILD files in the output directory.
func NewCodegenContext(config android.Config, context android.Context) CodegenContext {
	return CodegenContext{
		context: context,
		config:  config,
	}
}

// props is an unsorted map. This function ensures that
@@ -57,7 +75,7 @@ func propsToAttributes(props map[string]string) string {

func GenerateSoongModuleTargets(ctx bpToBuildContext) map[string][]BazelTarget {
	buildFileToTargets := make(map[string][]BazelTarget)
	ctx.VisitAllModulesBlueprint(func(m blueprint.Module) {
	ctx.VisitAllModules(func(m blueprint.Module) {
		dir := ctx.ModuleDir(m)
		t := generateSoongModuleTarget(ctx, m)
		buildFileToTargets[ctx.ModuleDir(m)] = append(buildFileToTargets[dir], t)
@@ -75,7 +93,7 @@ func generateSoongModuleTarget(ctx bpToBuildContext, m blueprint.Module) BazelTa
	// out the implications of that.
	depLabels := map[string]bool{}
	if aModule, ok := m.(android.Module); ok {
		ctx.VisitDirectDeps(aModule, func(depModule android.Module) {
		ctx.VisitDirectDeps(aModule, func(depModule blueprint.Module) {
			depLabels[qualifiedTargetLabel(ctx, depModule)] = true
		})
	}
+1 −5
Original line number Diff line number Diff line
@@ -200,11 +200,7 @@ func TestGenerateSoongModuleTargets(t *testing.T) {
		_, errs = ctx.PrepareBuildActions(config)
		android.FailIfErrored(t, errs)

		bp2BuildCtx := bp2buildBlueprintWrapContext{
			bpCtx: ctx.Context.Context,
		}

		bazelTargets := GenerateSoongModuleTargets(&bp2BuildCtx)[dir]
		bazelTargets := GenerateSoongModuleTargets(ctx.Context.Context)[dir]
		if g, w := len(bazelTargets), 1; g != w {
			t.Fatalf("Expected %d bazel target, got %d", w, g)
		}
+0 −34
Original line number Diff line number Diff line
@@ -2,8 +2,6 @@ package bp2build

import (
	"android/soong/android"

	"github.com/google/blueprint"
)

type nestedProps struct {
@@ -102,35 +100,3 @@ func customDefaultsModuleFactory() android.Module {
	android.InitDefaultsModule(m)
	return m
}

type bp2buildBlueprintWrapContext struct {
	bpCtx *blueprint.Context
}

func (ctx *bp2buildBlueprintWrapContext) ModuleName(module blueprint.Module) string {
	return ctx.bpCtx.ModuleName(module)
}

func (ctx *bp2buildBlueprintWrapContext) ModuleDir(module blueprint.Module) string {
	return ctx.bpCtx.ModuleDir(module)
}

func (ctx *bp2buildBlueprintWrapContext) ModuleSubDir(module blueprint.Module) string {
	return ctx.bpCtx.ModuleSubDir(module)
}

func (ctx *bp2buildBlueprintWrapContext) ModuleType(module blueprint.Module) string {
	return ctx.bpCtx.ModuleType(module)
}

func (ctx *bp2buildBlueprintWrapContext) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
	ctx.bpCtx.VisitAllModules(visit)
}

func (ctx *bp2buildBlueprintWrapContext) VisitDirectDeps(module android.Module, visit func(android.Module)) {
	ctx.bpCtx.VisitDirectDeps(module, func(m blueprint.Module) {
		if aModule, ok := m.(android.Module); ok {
			visit(aModule)
		}
	})
}
Loading