Direct Bazel builds from m.

This CL adds support to bp2build/Soong to dump a BUILD file under
out/soong/soong_injection/targets containing alias targets to their real
targets for every converted Soong module, regardless of whether they are
handcrafted or generated.

Test: TH
Change-Id: Ic1816fda5d019c395301618134fac68b3057d752
This commit is contained in:
Jingwen Chen
2021-06-17 05:43:19 +00:00
parent c4dc9b4f08
commit c63677b3c9
10 changed files with 126 additions and 44 deletions

View File

@@ -19,6 +19,7 @@ import (
"path/filepath"
"regexp"
"sort"
"strings"
)
// BazelTargetModuleProperties contain properties and metadata used for
@@ -33,6 +34,10 @@ type BazelTargetModuleProperties struct {
const BazelTargetModuleNamePrefix = "__bp2build__"
func StripNamePrefix(moduleName string) string {
return strings.TrimPrefix(moduleName, BazelTargetModuleNamePrefix)
}
var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
// Label is used to represent a Bazel compatible Label. Also stores the original

View File

@@ -11,6 +11,7 @@ bootstrap_go_package {
"build_conversion.go",
"bzl_conversion.go",
"configurability.go",
"compatibility.go",
"constants.go",
"conversion.go",
"metrics.go",

View File

@@ -29,12 +29,12 @@ func Codegen(ctx *CodegenContext) CodegenMetrics {
bp2buildDir := android.PathForOutput(ctx, "bp2build")
android.RemoveAllOutputDir(bp2buildDir)
buildToTargets, metrics := GenerateBazelTargets(ctx, true)
buildToTargets, metrics, compatLayer := GenerateBazelTargets(ctx, true)
bp2buildFiles := CreateBazelFiles(nil, buildToTargets, ctx.mode)
writeFiles(ctx, bp2buildDir, bp2buildFiles)
soongInjectionDir := android.PathForOutput(ctx, bazel.SoongInjectionDirName)
writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles())
writeFiles(ctx, soongInjectionDir, CreateSoongInjectionFiles(compatLayer))
return metrics
}

View File

@@ -32,6 +32,7 @@ type BazelAttributes struct {
type BazelTarget struct {
name string
packageName string
content string
ruleClass string
bzlLoadLocation string
@@ -44,6 +45,16 @@ func (t BazelTarget) IsLoadedFromStarlark() bool {
return t.bzlLoadLocation != ""
}
// Label is the fully qualified Bazel label constructed from the BazelTarget's
// package name and target name.
func (t BazelTarget) Label() string {
if t.packageName == "." {
return "//:" + t.name
} else {
return "//" + t.packageName + ":" + t.name
}
}
// BazelTargets is a typedef for a slice of BazelTarget objects.
type BazelTargets []BazelTarget
@@ -213,7 +224,7 @@ func propsToAttributes(props map[string]string) string {
return attributes
}
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[string]BazelTargets, CodegenMetrics) {
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[string]BazelTargets, CodegenMetrics, CodegenCompatLayer) {
buildFileToTargets := make(map[string]BazelTargets)
buildFileToAppend := make(map[string]bool)
@@ -222,6 +233,10 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
RuleClassCount: make(map[string]int),
}
compatLayer := CodegenCompatLayer{
NameToLabelMap: make(map[string]string),
}
dirs := make(map[string]bool)
bpCtx := ctx.Context()
@@ -236,6 +251,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
metrics.handCraftedTargetCount += 1
metrics.TotalModuleCount += 1
compatLayer.AddNameToLabelEntry(m.Name(), b.HandcraftedLabel())
pathToBuildFile := getBazelPackagePath(b)
// We are using the entire contents of handcrafted build file, so if multiple targets within
// a package have handcrafted targets, we only want to include the contents one time.
@@ -253,6 +269,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
} else if btm, ok := m.(android.BazelTargetModule); ok {
t = generateBazelTarget(bpCtx, m, btm)
metrics.RuleClassCount[t.ruleClass] += 1
compatLayer.AddNameToLabelEntry(m.Name(), t.Label())
} else {
metrics.TotalModuleCount += 1
return
@@ -283,7 +300,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (map[str
}
}
return buildFileToTargets, metrics
return buildFileToTargets, metrics, compatLayer
}
func getBazelPackagePath(b android.Bazelable) string {
@@ -324,6 +341,7 @@ func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module, btm android.B
targetName := targetNameForBp2Build(ctx, m)
return BazelTarget{
name: targetName,
packageName: ctx.ModuleDir(m),
ruleClass: ruleClass,
bzlLoadLocation: bzlLoadLocation,
content: fmt.Sprintf(

View File

@@ -1398,14 +1398,14 @@ func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
bp: `filegroup {
name: "fg_foo",
bazel_module: { label: "//other:fg_foo" },
}
name: "fg_foo",
bazel_module: { label: "//other:fg_foo" },
}
filegroup {
name: "foo",
bazel_module: { label: "//other:foo" },
}`,
filegroup {
name: "foo",
bazel_module: { label: "//other:foo" },
}`,
expectedBazelTargets: []string{
`// BUILD file`,
},
@@ -1414,25 +1414,31 @@ filegroup {
},
},
{
description: "filegroup bazel_module.label and bp2build",
description: "filegroup bazel_module.label and bp2build in subdir",
moduleTypeUnderTest: "filegroup",
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
bp: `filegroup {
name: "fg_foo",
bazel_module: {
label: "//other:fg_foo",
bp2build_available: true,
},
}`,
dir: "other",
bp: ``,
fs: map[string]string{
"other/Android.bp": `filegroup {
name: "fg_foo",
bazel_module: {
bp2build_available: true,
},
}
filegroup {
name: "fg_bar",
bazel_module: {
label: "//other:fg_bar"
},
}`,
"other/BUILD.bazel": `// definition for fg_bar`,
},
expectedBazelTargets: []string{
`filegroup(
name = "fg_foo",
)`,
`// BUILD file`,
},
fs: map[string]string{
"other/BUILD.bazel": `// BUILD file`,
)`, `// definition for fg_bar`,
},
},
{
@@ -1441,18 +1447,18 @@ filegroup {
moduleTypeUnderTestFactory: android.FileGroupFactory,
moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
bp: `filegroup {
name: "fg_foo",
bazel_module: {
label: "//other:fg_foo",
},
}
name: "fg_foo",
bazel_module: {
label: "//other:fg_foo",
},
}
filegroup {
name: "fg_bar",
bazel_module: {
bp2build_available: true,
},
}`,
filegroup {
name: "fg_bar",
bazel_module: {
bp2build_available: true,
},
}`,
expectedBazelTargets: []string{
`filegroup(
name = "fg_bar",

31
bp2build/compatibility.go Normal file
View File

@@ -0,0 +1,31 @@
package bp2build
import (
"android/soong/bazel"
"fmt"
)
// Data from the code generation process that is used to improve compatibility
// between build systems.
type CodegenCompatLayer struct {
// A map from the original module name to the generated/handcrafted Bazel
// label for legacy build systems to be able to build a fully-qualified
// Bazel target from an unique module name.
NameToLabelMap map[string]string
}
// Log an entry of module name -> Bazel target label.
func (compatLayer CodegenCompatLayer) AddNameToLabelEntry(name, label string) {
// The module name may be prefixed with bazel.BazelTargetModuleNamePrefix if
// generated from bp2build.
name = bazel.StripNamePrefix(name)
if existingLabel, ok := compatLayer.NameToLabelMap[name]; ok {
panic(fmt.Errorf(
"Module '%s' maps to more than one Bazel target label: %s, %s. "+
"This shouldn't happen. It probably indicates a bug with the bp2build internals.",
name,
existingLabel,
label))
}
compatLayer.NameToLabelMap[name] = label
}

View File

@@ -16,15 +16,31 @@ type BazelFile struct {
Contents string
}
func CreateSoongInjectionFiles() []BazelFile {
func CreateSoongInjectionFiles(compatLayer CodegenCompatLayer) []BazelFile {
var files []BazelFile
files = append(files, newFile("cc_toolchain", "BUILD", "")) // Creates a //cc_toolchain package.
files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
files = append(files, newFile("module_name_to_label", GeneratedBuildFileName, nameToLabelAliases(compatLayer.NameToLabelMap)))
return files
}
func nameToLabelAliases(nameToLabelMap map[string]string) string {
ret := make([]string, len(nameToLabelMap))
for k, v := range nameToLabelMap {
// v is the fully qualified label rooted at '//'
ret = append(ret, fmt.Sprintf(
`alias(
name = "%s",
actual = "@%s",
)`, k, v))
}
return strings.Join(ret, "\n\n")
}
func CreateBazelFiles(
ruleShims map[string]RuleShim,
buildToTargets map[string]BazelTargets,

View File

@@ -80,17 +80,21 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
}
func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
files := CreateSoongInjectionFiles()
files := CreateSoongInjectionFiles(CodegenCompatLayer{})
expectedFilePaths := []bazelFilepath{
{
dir: "cc_toolchain",
basename: "BUILD",
basename: GeneratedBuildFileName,
},
{
dir: "cc_toolchain",
basename: "constants.bzl",
},
{
dir: "module_name_to_label",
basename: GeneratedBuildFileName,
},
}
if len(files) != len(expectedFilePaths) {
@@ -104,7 +108,7 @@ func TestCreateBazelFiles_Bp2Build_CreatesDefaultFiles(t *testing.T) {
t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename)
}
if expectedFile.basename != "BUILD" && actualFile.Contents == "" {
if expectedFile.basename != GeneratedBuildFileName && actualFile.Contents == "" {
t.Errorf("Contents of %s unexpected empty.", actualFile)
}
}

View File

@@ -213,6 +213,6 @@ func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
// Helper method for tests to easily access the targets in a dir.
func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) BazelTargets {
// TODO: Set generateFilegroups to true and/or remove the generateFilegroups argument completely
buildFileToTargets, _ := GenerateBazelTargets(codegenCtx, false)
buildFileToTargets, _, _ := GenerateBazelTargets(codegenCtx, false)
return buildFileToTargets[dir]
}

View File

@@ -25,9 +25,10 @@ import (
func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string) error {
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
// Ignore metrics reporting for queryview, since queryview is already a full-repo
// conversion and can use data from bazel query directly.
buildToTargets, _ := bp2build.GenerateBazelTargets(ctx, true)
// Ignore metrics reporting and compat layers for queryview, since queryview
// is already a full-repo conversion and can use data from bazel query
// directly.
buildToTargets, _, _ := bp2build.GenerateBazelTargets(ctx, true)
filesToWrite := bp2build.CreateBazelFiles(ruleShims, buildToTargets, bp2build.QueryView)
for _, f := range filesToWrite {