Merge "Create a new mode in soong_ui to generate API only BUILD files"
This commit is contained in:
commit
ee08eb3c81
14 changed files with 288 additions and 25 deletions
|
@ -134,6 +134,11 @@ type Bazelable interface {
|
||||||
SetBaseModuleType(baseModuleType string)
|
SetBaseModuleType(baseModuleType string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ApiProvider is implemented by modules that contribute to an API surface
|
||||||
|
type ApiProvider interface {
|
||||||
|
ConvertWithApiBp2build(ctx TopDownMutatorContext)
|
||||||
|
}
|
||||||
|
|
||||||
// MixedBuildBuildable is an interface that module types should implement in order
|
// MixedBuildBuildable is an interface that module types should implement in order
|
||||||
// to be "handled by Bazel" in a mixed build.
|
// to be "handled by Bazel" in a mixed build.
|
||||||
type MixedBuildBuildable interface {
|
type MixedBuildBuildable interface {
|
||||||
|
@ -415,6 +420,13 @@ func (b *BazelModuleBase) shouldConvertWithBp2build(ctx bazelOtherModuleContext,
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In api_bp2build mode, all soong modules that can provide API contributions should be converted
|
||||||
|
// This is irrespective of its presence/absence in bp2build allowlists
|
||||||
|
if ctx.Config().BuildMode == ApiBp2build {
|
||||||
|
_, providesApis := module.(ApiProvider)
|
||||||
|
return providesApis
|
||||||
|
}
|
||||||
|
|
||||||
propValue := b.bazelProperties.Bazel_module.Bp2build_available
|
propValue := b.bazelProperties.Bazel_module.Bp2build_available
|
||||||
packagePath := ctx.OtherModuleDir(module)
|
packagePath := ctx.OtherModuleDir(module)
|
||||||
|
|
||||||
|
@ -510,6 +522,17 @@ func convertWithBp2build(ctx TopDownMutatorContext) {
|
||||||
bModule.ConvertWithBp2build(ctx)
|
bModule.ConvertWithBp2build(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func registerApiBp2buildConversionMutator(ctx RegisterMutatorsContext) {
|
||||||
|
ctx.TopDown("apiBp2build_conversion", convertWithApiBp2build).Parallel()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate API contribution targets if the Soong module provides APIs
|
||||||
|
func convertWithApiBp2build(ctx TopDownMutatorContext) {
|
||||||
|
if m, ok := ctx.Module().(ApiProvider); ok {
|
||||||
|
m.ConvertWithApiBp2build(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GetMainClassInManifest scans the manifest file specified in filepath and returns
|
// GetMainClassInManifest scans the manifest file specified in filepath and returns
|
||||||
// the value of attribute Main-Class in the manifest file if it exists, or returns error.
|
// the value of attribute Main-Class in the manifest file if it exists, or returns error.
|
||||||
// WARNING: this is for bp2build converters of java_* modules only.
|
// WARNING: this is for bp2build converters of java_* modules only.
|
||||||
|
|
|
@ -83,6 +83,9 @@ const (
|
||||||
// express build semantics.
|
// express build semantics.
|
||||||
GenerateQueryView
|
GenerateQueryView
|
||||||
|
|
||||||
|
// Generate BUILD files for API contributions to API surfaces
|
||||||
|
ApiBp2build
|
||||||
|
|
||||||
// Create a JSON representation of the module graph and exit.
|
// Create a JSON representation of the module graph and exit.
|
||||||
GenerateModuleGraph
|
GenerateModuleGraph
|
||||||
|
|
||||||
|
|
|
@ -31,22 +31,33 @@ import (
|
||||||
|
|
||||||
// RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
|
// RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
|
||||||
func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
|
func RegisterMutatorsForBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
|
||||||
|
bp2buildMutators := append(preArchMutators, registerBp2buildConversionMutator)
|
||||||
|
registerMutatorsForBazelConversion(ctx, bp2buildMutators)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterMutatorsForApiBazelConversion is an alternate registration pipeline for api_bp2build
|
||||||
|
// This pipeline restricts generation of Bazel targets to Soong modules that contribute APIs
|
||||||
|
func RegisterMutatorsForApiBazelConversion(ctx *Context, preArchMutators []RegisterMutatorFunc) {
|
||||||
|
bp2buildMutators := append(preArchMutators, registerApiBp2buildConversionMutator)
|
||||||
|
registerMutatorsForBazelConversion(ctx, bp2buildMutators)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerMutatorsForBazelConversion(ctx *Context, bp2buildMutators []RegisterMutatorFunc) {
|
||||||
mctx := ®isterMutatorsContext{
|
mctx := ®isterMutatorsContext{
|
||||||
bazelConversionMode: true,
|
bazelConversionMode: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
bp2buildMutators := append([]RegisterMutatorFunc{
|
allMutators := append([]RegisterMutatorFunc{
|
||||||
RegisterNamespaceMutator,
|
RegisterNamespaceMutator,
|
||||||
RegisterDefaultsPreArchMutators,
|
RegisterDefaultsPreArchMutators,
|
||||||
// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
|
// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
|
||||||
// evaluate the impact on conversion.
|
// evaluate the impact on conversion.
|
||||||
RegisterPrebuiltsPreArchMutators,
|
RegisterPrebuiltsPreArchMutators,
|
||||||
},
|
},
|
||||||
preArchMutators...)
|
bp2buildMutators...)
|
||||||
bp2buildMutators = append(bp2buildMutators, registerBp2buildConversionMutator)
|
|
||||||
|
|
||||||
// Register bp2build mutators
|
// Register bp2build mutators
|
||||||
for _, f := range bp2buildMutators {
|
for _, f := range allMutators {
|
||||||
f(mctx)
|
f(mctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,16 @@ func (ctx *Context) RegisterForBazelConversion() {
|
||||||
RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
|
RegisterMutatorsForBazelConversion(ctx, bp2buildPreArchMutators)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterForApiBazelConversion is similar to RegisterForBazelConversion except that
|
||||||
|
// it only generates API targets in the generated workspace
|
||||||
|
func (ctx *Context) RegisterForApiBazelConversion() {
|
||||||
|
for _, t := range moduleTypes {
|
||||||
|
t.register(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterMutatorsForApiBazelConversion(ctx, bp2buildPreArchMutators)
|
||||||
|
}
|
||||||
|
|
||||||
// Register the pipeline of singletons, module types, and mutators for
|
// Register the pipeline of singletons, module types, and mutators for
|
||||||
// generating build.ninja and other files for Kati, from Android.bp files.
|
// generating build.ninja and other files for Kati, from Android.bp files.
|
||||||
func (ctx *Context) Register() {
|
func (ctx *Context) Register() {
|
||||||
|
|
|
@ -461,6 +461,12 @@ func (ctx *TestContext) RegisterForBazelConversion() {
|
||||||
RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
|
RegisterMutatorsForBazelConversion(ctx.Context, ctx.bp2buildPreArch)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterForApiBazelConversion prepares a test context for API bp2build conversion.
|
||||||
|
func (ctx *TestContext) RegisterForApiBazelConversion() {
|
||||||
|
ctx.config.BuildMode = ApiBp2build
|
||||||
|
RegisterMutatorsForApiBazelConversion(ctx.Context, ctx.bp2buildPreArch)
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
|
func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
|
||||||
// This function adapts the old style ParseFileList calls that are spread throughout the tests
|
// This function adapts the old style ParseFileList calls that are spread throughout the tests
|
||||||
// to the new style that takes a config.
|
// to the new style that takes a config.
|
||||||
|
|
|
@ -163,6 +163,9 @@ const (
|
||||||
// This mode is used for discovering and introspecting the existing Soong
|
// This mode is used for discovering and introspecting the existing Soong
|
||||||
// module graph.
|
// module graph.
|
||||||
QueryView
|
QueryView
|
||||||
|
|
||||||
|
// ApiBp2build - generate BUILD files for API contribution targets
|
||||||
|
ApiBp2build
|
||||||
)
|
)
|
||||||
|
|
||||||
type unconvertedDepsMode int
|
type unconvertedDepsMode int
|
||||||
|
@ -181,6 +184,8 @@ func (mode CodegenMode) String() string {
|
||||||
return "Bp2Build"
|
return "Bp2Build"
|
||||||
case QueryView:
|
case QueryView:
|
||||||
return "QueryView"
|
return "QueryView"
|
||||||
|
case ApiBp2build:
|
||||||
|
return "ApiBp2build"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("%d", mode)
|
return fmt.Sprintf("%d", mode)
|
||||||
}
|
}
|
||||||
|
@ -327,6 +332,10 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
|
||||||
errs = append(errs, err)
|
errs = append(errs, err)
|
||||||
}
|
}
|
||||||
targets = append(targets, t)
|
targets = append(targets, t)
|
||||||
|
case ApiBp2build:
|
||||||
|
if aModule, ok := m.(android.Module); ok && aModule.IsConvertedByBp2build() {
|
||||||
|
targets, errs = generateBazelTargets(bpCtx, aModule)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
|
errs = append(errs, fmt.Errorf("Unknown code-generation mode: %s", ctx.Mode()))
|
||||||
return
|
return
|
||||||
|
|
|
@ -1853,3 +1853,27 @@ filegroup {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGenerateApiBazelTargets(t *testing.T) {
|
||||||
|
bp := `
|
||||||
|
custom {
|
||||||
|
name: "foo",
|
||||||
|
api: "foo.txt",
|
||||||
|
}
|
||||||
|
`
|
||||||
|
expectedBazelTarget := MakeBazelTarget(
|
||||||
|
"custom_api_contribution",
|
||||||
|
"foo",
|
||||||
|
AttrNameToString{
|
||||||
|
"api": `"foo.txt"`,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
registerCustomModule := func(ctx android.RegistrationContext) {
|
||||||
|
ctx.RegisterModuleType("custom", customModuleFactoryHostAndDevice)
|
||||||
|
}
|
||||||
|
RunApiBp2BuildTestCase(t, registerCustomModule, Bp2buildTestCase{
|
||||||
|
Blueprint: bp,
|
||||||
|
ExpectedBazelTargets: []string{expectedBazelTarget},
|
||||||
|
Description: "Generating API contribution Bazel targets for custom module",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -85,6 +85,7 @@ custom = rule(
|
||||||
"soong_module_name": attr.string(mandatory = True),
|
"soong_module_name": attr.string(mandatory = True),
|
||||||
"soong_module_variant": attr.string(),
|
"soong_module_variant": attr.string(),
|
||||||
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
||||||
|
"api": attr.string(),
|
||||||
"arch_paths": attr.string_list(),
|
"arch_paths": attr.string_list(),
|
||||||
"arch_paths_exclude": attr.string_list(),
|
"arch_paths_exclude": attr.string_list(),
|
||||||
# bazel_module start
|
# bazel_module start
|
||||||
|
@ -119,6 +120,7 @@ custom_defaults = rule(
|
||||||
"soong_module_name": attr.string(mandatory = True),
|
"soong_module_name": attr.string(mandatory = True),
|
||||||
"soong_module_variant": attr.string(),
|
"soong_module_variant": attr.string(),
|
||||||
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
||||||
|
"api": attr.string(),
|
||||||
"arch_paths": attr.string_list(),
|
"arch_paths": attr.string_list(),
|
||||||
"arch_paths_exclude": attr.string_list(),
|
"arch_paths_exclude": attr.string_list(),
|
||||||
"bool_prop": attr.bool(),
|
"bool_prop": attr.bool(),
|
||||||
|
@ -149,6 +151,7 @@ custom_test_ = rule(
|
||||||
"soong_module_name": attr.string(mandatory = True),
|
"soong_module_name": attr.string(mandatory = True),
|
||||||
"soong_module_variant": attr.string(),
|
"soong_module_variant": attr.string(),
|
||||||
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
"soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
|
||||||
|
"api": attr.string(),
|
||||||
"arch_paths": attr.string_list(),
|
"arch_paths": attr.string_list(),
|
||||||
"arch_paths_exclude": attr.string_list(),
|
"arch_paths_exclude": attr.string_list(),
|
||||||
"bool_prop": attr.bool(),
|
"bool_prop": attr.bool(),
|
||||||
|
|
|
@ -97,7 +97,7 @@ func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode)
|
||||||
targets.sort()
|
targets.sort()
|
||||||
|
|
||||||
var content string
|
var content string
|
||||||
if mode == Bp2Build {
|
if mode == Bp2Build || mode == ApiBp2build {
|
||||||
content = `# READ THIS FIRST:
|
content = `# READ THIS FIRST:
|
||||||
# This file was automatically generated by bp2build for the Bazel migration project.
|
# This file was automatically generated by bp2build for the Bazel migration project.
|
||||||
# Feel free to edit or test it, but do *not* check it into your version control system.
|
# Feel free to edit or test it, but do *not* check it into your version control system.
|
||||||
|
|
|
@ -24,6 +24,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/blueprint/proptools"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
"android/soong/android/allowlists"
|
"android/soong/android/allowlists"
|
||||||
"android/soong/bazel"
|
"android/soong/bazel"
|
||||||
|
@ -88,6 +90,22 @@ type Bp2buildTestCase struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
|
func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
|
||||||
|
bp2buildSetup := func(ctx *android.TestContext) {
|
||||||
|
registerModuleTypes(ctx)
|
||||||
|
ctx.RegisterForBazelConversion()
|
||||||
|
}
|
||||||
|
runBp2BuildTestCaseWithSetup(t, bp2buildSetup, tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RunApiBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.RegistrationContext), tc Bp2buildTestCase) {
|
||||||
|
apiBp2BuildSetup := func(ctx *android.TestContext) {
|
||||||
|
registerModuleTypes(ctx)
|
||||||
|
ctx.RegisterForApiBazelConversion()
|
||||||
|
}
|
||||||
|
runBp2BuildTestCaseWithSetup(t, apiBp2BuildSetup, tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func runBp2BuildTestCaseWithSetup(t *testing.T, setup func(ctx *android.TestContext), tc Bp2buildTestCase) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
dir := "."
|
dir := "."
|
||||||
filesystem := make(map[string][]byte)
|
filesystem := make(map[string][]byte)
|
||||||
|
@ -103,7 +121,7 @@ func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi
|
||||||
config := android.TestConfig(buildDir, nil, tc.Blueprint, filesystem)
|
config := android.TestConfig(buildDir, nil, tc.Blueprint, filesystem)
|
||||||
ctx := android.NewTestContext(config)
|
ctx := android.NewTestContext(config)
|
||||||
|
|
||||||
registerModuleTypes(ctx)
|
setup(ctx)
|
||||||
ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
|
ctx.RegisterModuleType(tc.ModuleTypeUnderTest, tc.ModuleTypeUnderTestFactory)
|
||||||
|
|
||||||
// A default configuration for tests to not have to specify bp2build_available on top level targets.
|
// A default configuration for tests to not have to specify bp2build_available on top level targets.
|
||||||
|
@ -118,7 +136,6 @@ func RunBp2BuildTestCase(t *testing.T, registerModuleTypes func(ctx android.Regi
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ctx.RegisterBp2BuildConfig(bp2buildConfig)
|
ctx.RegisterBp2BuildConfig(bp2buildConfig)
|
||||||
ctx.RegisterForBazelConversion()
|
|
||||||
|
|
||||||
_, parseErrs := ctx.ParseFileList(dir, toParse)
|
_, parseErrs := ctx.ParseFileList(dir, toParse)
|
||||||
if errored(t, tc, parseErrs) {
|
if errored(t, tc, parseErrs) {
|
||||||
|
@ -198,6 +215,8 @@ type customProps struct {
|
||||||
|
|
||||||
// Prop used to indicate this conversion should be 1 module -> multiple targets
|
// Prop used to indicate this conversion should be 1 module -> multiple targets
|
||||||
One_to_many_prop *bool
|
One_to_many_prop *bool
|
||||||
|
|
||||||
|
Api *string // File describing the APIs of this module
|
||||||
}
|
}
|
||||||
|
|
||||||
type customModule struct {
|
type customModule struct {
|
||||||
|
@ -320,6 +339,7 @@ type customBazelModuleAttributes struct {
|
||||||
String_ptr_prop *string
|
String_ptr_prop *string
|
||||||
String_list_prop []string
|
String_list_prop []string
|
||||||
Arch_paths bazel.LabelListAttribute
|
Arch_paths bazel.LabelListAttribute
|
||||||
|
Api bazel.LabelAttribute
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
||||||
|
@ -364,6 +384,23 @@ func (m *customModule) ConvertWithBp2build(ctx android.TopDownMutatorContext) {
|
||||||
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
|
ctx.CreateBazelTargetModule(props, android.CommonAttributes{Name: m.Name()}, attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ android.ApiProvider = (*customModule)(nil)
|
||||||
|
|
||||||
|
func (c *customModule) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
|
||||||
|
props := bazel.BazelTargetModuleProperties{
|
||||||
|
Rule_class: "custom_api_contribution",
|
||||||
|
}
|
||||||
|
apiAttribute := bazel.MakeLabelAttribute(
|
||||||
|
android.BazelLabelForModuleSrcSingle(ctx, proptools.String(c.props.Api)).Label,
|
||||||
|
)
|
||||||
|
attrs := &customBazelModuleAttributes{
|
||||||
|
Api: *apiAttribute,
|
||||||
|
}
|
||||||
|
ctx.CreateBazelTargetModule(props,
|
||||||
|
android.CommonAttributes{Name: c.Name()},
|
||||||
|
attrs)
|
||||||
|
}
|
||||||
|
|
||||||
// A bp2build mutator that uses load statements and creates a 1:M mapping from
|
// A bp2build mutator that uses load statements and creates a 1:M mapping from
|
||||||
// module to target.
|
// module to target.
|
||||||
func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
|
func customBp2buildOneToMany(ctx android.TopDownMutatorContext, m *customModule) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
"android/soong/bazel"
|
||||||
"android/soong/bp2build"
|
"android/soong/bp2build"
|
||||||
"android/soong/shared"
|
"android/soong/shared"
|
||||||
"android/soong/ui/metrics/bp2build_metrics_proto"
|
"android/soong/ui/metrics/bp2build_metrics_proto"
|
||||||
|
@ -48,11 +49,12 @@ var (
|
||||||
delveListen string
|
delveListen string
|
||||||
delvePath string
|
delvePath string
|
||||||
|
|
||||||
moduleGraphFile string
|
moduleGraphFile string
|
||||||
moduleActionsFile string
|
moduleActionsFile string
|
||||||
docFile string
|
docFile string
|
||||||
bazelQueryViewDir string
|
bazelQueryViewDir string
|
||||||
bp2buildMarker string
|
bazelApiBp2buildDir string
|
||||||
|
bp2buildMarker string
|
||||||
|
|
||||||
cmdlineArgs bootstrap.Args
|
cmdlineArgs bootstrap.Args
|
||||||
)
|
)
|
||||||
|
@ -81,6 +83,7 @@ func init() {
|
||||||
flag.StringVar(&moduleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
|
flag.StringVar(&moduleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
|
||||||
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
|
flag.StringVar(&docFile, "soong_docs", "", "build documentation file to output")
|
||||||
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
|
flag.StringVar(&bazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
|
||||||
|
flag.StringVar(&bazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top")
|
||||||
flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
|
flag.StringVar(&bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
|
||||||
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
|
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
|
||||||
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
|
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
|
||||||
|
@ -129,6 +132,8 @@ func newConfig(availableEnv map[string]string) android.Config {
|
||||||
buildMode = android.Bp2build
|
buildMode = android.Bp2build
|
||||||
} else if bazelQueryViewDir != "" {
|
} else if bazelQueryViewDir != "" {
|
||||||
buildMode = android.GenerateQueryView
|
buildMode = android.GenerateQueryView
|
||||||
|
} else if bazelApiBp2buildDir != "" {
|
||||||
|
buildMode = android.ApiBp2build
|
||||||
} else if moduleGraphFile != "" {
|
} else if moduleGraphFile != "" {
|
||||||
buildMode = android.GenerateModuleGraph
|
buildMode = android.GenerateModuleGraph
|
||||||
} else if docFile != "" {
|
} else if docFile != "" {
|
||||||
|
@ -178,7 +183,7 @@ func runQueryView(queryviewDir, queryviewMarker string, configuration android.Co
|
||||||
defer ctx.EventHandler.End("queryview")
|
defer ctx.EventHandler.End("queryview")
|
||||||
codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
|
codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView)
|
||||||
absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
|
absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
|
||||||
if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil {
|
if err := createBazelWorkspace(codegenContext, absoluteQueryViewDir); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s", err)
|
fmt.Fprintf(os.Stderr, "%s", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
@ -186,6 +191,96 @@ func runQueryView(queryviewDir, queryviewMarker string, configuration android.Co
|
||||||
touch(shared.JoinPath(topDir, queryviewMarker))
|
touch(shared.JoinPath(topDir, queryviewMarker))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the code-generation phase to convert API contributions to BUILD files.
|
||||||
|
// Return marker file for the new synthetic workspace
|
||||||
|
func runApiBp2build(configuration android.Config, extraNinjaDeps []string) string {
|
||||||
|
// Create a new context and register mutators that are only meaningful to API export
|
||||||
|
ctx := android.NewContext(configuration)
|
||||||
|
ctx.EventHandler.Begin("api_bp2build")
|
||||||
|
defer ctx.EventHandler.End("api_bp2build")
|
||||||
|
ctx.SetNameInterface(newNameResolver(configuration))
|
||||||
|
ctx.RegisterForApiBazelConversion()
|
||||||
|
|
||||||
|
// Register the Android.bp files in the tree
|
||||||
|
// Add them to the workspace's .d file
|
||||||
|
ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
|
||||||
|
if paths, err := ctx.ListModulePaths("."); err == nil {
|
||||||
|
extraNinjaDeps = append(extraNinjaDeps, paths...)
|
||||||
|
} else {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the loading and analysis phase
|
||||||
|
ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs,
|
||||||
|
bootstrap.StopBeforePrepareBuildActions,
|
||||||
|
ctx.Context,
|
||||||
|
configuration)
|
||||||
|
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
|
||||||
|
|
||||||
|
// Add the globbed dependencies
|
||||||
|
globs := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
|
||||||
|
ninjaDeps = append(ninjaDeps, globs...)
|
||||||
|
|
||||||
|
// Run codegen to generate BUILD files
|
||||||
|
codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.ApiBp2build)
|
||||||
|
absoluteApiBp2buildDir := shared.JoinPath(topDir, bazelApiBp2buildDir)
|
||||||
|
if err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "%s", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
|
||||||
|
|
||||||
|
// Create soong_injection repository
|
||||||
|
soongInjectionFiles := bp2build.CreateSoongInjectionFiles(configuration, bp2build.CodegenMetrics{})
|
||||||
|
absoluteSoongInjectionDir := shared.JoinPath(topDir, configuration.SoongOutDir(), bazel.SoongInjectionDirName)
|
||||||
|
for _, file := range soongInjectionFiles {
|
||||||
|
writeReadOnlyFile(absoluteSoongInjectionDir, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace := shared.JoinPath(configuration.SoongOutDir(), "api_bp2build")
|
||||||
|
|
||||||
|
excludes := bazelArtifacts()
|
||||||
|
// Exclude all src BUILD files
|
||||||
|
excludes = append(excludes, apiBuildFileExcludes()...)
|
||||||
|
|
||||||
|
// Create the symlink forest
|
||||||
|
symlinkDeps := bp2build.PlantSymlinkForest(
|
||||||
|
configuration,
|
||||||
|
topDir,
|
||||||
|
workspace,
|
||||||
|
bazelApiBp2buildDir,
|
||||||
|
".",
|
||||||
|
excludes)
|
||||||
|
ninjaDeps = append(ninjaDeps, symlinkDeps...)
|
||||||
|
|
||||||
|
workspaceMarkerFile := workspace + ".marker"
|
||||||
|
writeDepFile(workspaceMarkerFile, *ctx.EventHandler, ninjaDeps)
|
||||||
|
touch(shared.JoinPath(topDir, workspaceMarkerFile))
|
||||||
|
return workspaceMarkerFile
|
||||||
|
}
|
||||||
|
|
||||||
|
// With some exceptions, api_bp2build does not have any dependencies on the checked-in BUILD files
|
||||||
|
// Exclude them from the generated workspace to prevent unrelated errors during the loading phase
|
||||||
|
func apiBuildFileExcludes() []string {
|
||||||
|
ret := make([]string, 0)
|
||||||
|
|
||||||
|
srcs, err := getExistingBazelRelatedFiles(topDir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
for _, src := range srcs {
|
||||||
|
if src != "WORKSPACE" &&
|
||||||
|
src != "BUILD" &&
|
||||||
|
src != "BUILD.bazel" &&
|
||||||
|
!strings.HasPrefix(src, "build/bazel") &&
|
||||||
|
!strings.HasPrefix(src, "prebuilts/clang") {
|
||||||
|
ret = append(ret, src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
|
func writeMetrics(configuration android.Config, eventHandler metrics.EventHandler, metricsDir string) {
|
||||||
if len(metricsDir) < 1 {
|
if len(metricsDir) < 1 {
|
||||||
fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
|
fmt.Fprintf(os.Stderr, "\nMissing required env var for generating soong metrics: LOG_DIR\n")
|
||||||
|
@ -248,6 +343,8 @@ func doChosenActivity(ctx *android.Context, configuration android.Config, extraN
|
||||||
return bp2buildMarker
|
return bp2buildMarker
|
||||||
} else if configuration.IsMixedBuildsEnabled() {
|
} else if configuration.IsMixedBuildsEnabled() {
|
||||||
runMixedModeBuild(configuration, ctx, extraNinjaDeps)
|
runMixedModeBuild(configuration, ctx, extraNinjaDeps)
|
||||||
|
} else if configuration.BuildMode == android.ApiBp2build {
|
||||||
|
return runApiBp2build(configuration, extraNinjaDeps)
|
||||||
} else {
|
} else {
|
||||||
var stopBefore bootstrap.StopBefore
|
var stopBefore bootstrap.StopBefore
|
||||||
if configuration.BuildMode == android.GenerateModuleGraph {
|
if configuration.BuildMode == android.GenerateModuleGraph {
|
||||||
|
@ -476,6 +573,16 @@ func getExistingBazelRelatedFiles(topDir string) ([]string, error) {
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func bazelArtifacts() []string {
|
||||||
|
return []string{
|
||||||
|
"bazel-bin",
|
||||||
|
"bazel-genfiles",
|
||||||
|
"bazel-out",
|
||||||
|
"bazel-testlogs",
|
||||||
|
"bazel-" + filepath.Base(topDir),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Run Soong in the bp2build mode. This creates a standalone context that registers
|
// Run Soong in the bp2build mode. This creates a standalone context that registers
|
||||||
// an alternate pipeline of mutators and singletons specifically for generating
|
// an alternate pipeline of mutators and singletons specifically for generating
|
||||||
// Bazel BUILD files instead of Ninja files.
|
// Bazel BUILD files instead of Ninja files.
|
||||||
|
@ -524,13 +631,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
|
||||||
generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
|
generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
|
||||||
workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
|
workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
|
||||||
|
|
||||||
excludes := []string{
|
excludes := bazelArtifacts()
|
||||||
"bazel-bin",
|
|
||||||
"bazel-genfiles",
|
|
||||||
"bazel-out",
|
|
||||||
"bazel-testlogs",
|
|
||||||
"bazel-" + filepath.Base(topDir),
|
|
||||||
}
|
|
||||||
|
|
||||||
if outDir[0] != '/' {
|
if outDir[0] != '/' {
|
||||||
excludes = append(excludes, outDir)
|
excludes = append(excludes, outDir)
|
||||||
|
|
|
@ -23,8 +23,9 @@ import (
|
||||||
"android/soong/bp2build"
|
"android/soong/bp2build"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string) error {
|
// A helper function to generate a Read-only Bazel workspace in outDir
|
||||||
os.RemoveAll(bazelQueryViewDir)
|
func createBazelWorkspace(ctx *bp2build.CodegenContext, outDir string) error {
|
||||||
|
os.RemoveAll(outDir)
|
||||||
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
|
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
|
||||||
|
|
||||||
res, err := bp2build.GenerateBazelTargets(ctx, true)
|
res, err := bp2build.GenerateBazelTargets(ctx, true)
|
||||||
|
@ -33,9 +34,9 @@ func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
|
filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
|
||||||
bp2build.QueryView)
|
ctx.Mode())
|
||||||
for _, f := range filesToWrite {
|
for _, f := range filesToWrite {
|
||||||
if err := writeReadOnlyFile(bazelQueryViewDir, f); err != nil {
|
if err := writeReadOnlyFile(outDir, f); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,7 @@ type configImpl struct {
|
||||||
checkbuild bool
|
checkbuild bool
|
||||||
dist bool
|
dist bool
|
||||||
jsonModuleGraph bool
|
jsonModuleGraph bool
|
||||||
|
apiBp2build bool // Generate BUILD files for Soong modules that contribute APIs
|
||||||
bp2build bool
|
bp2build bool
|
||||||
queryview bool
|
queryview bool
|
||||||
reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
|
reportMkMetrics bool // Collect and report mk2bp migration progress metrics.
|
||||||
|
@ -756,6 +757,8 @@ func (c *configImpl) parseArgs(ctx Context, args []string) {
|
||||||
c.jsonModuleGraph = true
|
c.jsonModuleGraph = true
|
||||||
} else if arg == "bp2build" {
|
} else if arg == "bp2build" {
|
||||||
c.bp2build = true
|
c.bp2build = true
|
||||||
|
} else if arg == "api_bp2build" {
|
||||||
|
c.apiBp2build = true
|
||||||
} else if arg == "queryview" {
|
} else if arg == "queryview" {
|
||||||
c.queryview = true
|
c.queryview = true
|
||||||
} else if arg == "soong_docs" {
|
} else if arg == "soong_docs" {
|
||||||
|
@ -833,7 +836,7 @@ func (c *configImpl) SoongBuildInvocationNeeded() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() {
|
if !c.JsonModuleGraph() && !c.Bp2Build() && !c.Queryview() && !c.SoongDocs() && !c.ApiBp2build() {
|
||||||
// Command line was empty, the default Ninja target is built
|
// Command line was empty, the default Ninja target is built
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -916,6 +919,10 @@ func (c *configImpl) QueryviewMarkerFile() string {
|
||||||
return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
|
return shared.JoinPath(c.SoongOutDir(), "queryview.marker")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configImpl) ApiBp2buildMarkerFile() string {
|
||||||
|
return shared.JoinPath(c.SoongOutDir(), "api_bp2build.marker")
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configImpl) ModuleGraphFile() string {
|
func (c *configImpl) ModuleGraphFile() string {
|
||||||
return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
|
return shared.JoinPath(c.SoongOutDir(), "module-graph.json")
|
||||||
}
|
}
|
||||||
|
@ -957,6 +964,10 @@ func (c *configImpl) Bp2Build() bool {
|
||||||
return c.bp2build
|
return c.bp2build
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *configImpl) ApiBp2build() bool {
|
||||||
|
return c.apiBp2build
|
||||||
|
}
|
||||||
|
|
||||||
func (c *configImpl) Queryview() bool {
|
func (c *configImpl) Queryview() bool {
|
||||||
return c.queryview
|
return c.queryview
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ const (
|
||||||
bp2buildTag = "bp2build"
|
bp2buildTag = "bp2build"
|
||||||
jsonModuleGraphTag = "modulegraph"
|
jsonModuleGraphTag = "modulegraph"
|
||||||
queryviewTag = "queryview"
|
queryviewTag = "queryview"
|
||||||
|
apiBp2buildTag = "api_bp2build"
|
||||||
soongDocsTag = "soong_docs"
|
soongDocsTag = "soong_docs"
|
||||||
|
|
||||||
// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
|
// bootstrapEpoch is used to determine if an incremental build is incompatible with the current
|
||||||
|
@ -237,6 +238,7 @@ func bootstrapGlobFileList(config Config) []string {
|
||||||
config.NamedGlobFile(bp2buildTag),
|
config.NamedGlobFile(bp2buildTag),
|
||||||
config.NamedGlobFile(jsonModuleGraphTag),
|
config.NamedGlobFile(jsonModuleGraphTag),
|
||||||
config.NamedGlobFile(queryviewTag),
|
config.NamedGlobFile(queryviewTag),
|
||||||
|
config.NamedGlobFile(apiBp2buildTag),
|
||||||
config.NamedGlobFile(soongDocsTag),
|
config.NamedGlobFile(soongDocsTag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -307,6 +309,19 @@ func bootstrapBlueprint(ctx Context, config Config) {
|
||||||
fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
|
fmt.Sprintf("generating the Soong module graph as a Bazel workspace at %s", queryviewDir),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The BUILD files will be generated in out/soong/.api_bp2build (no symlinks to src files)
|
||||||
|
// The final workspace will be generated in out/soong/api_bp2build
|
||||||
|
apiBp2buildDir := filepath.Join(config.SoongOutDir(), ".api_bp2build")
|
||||||
|
apiBp2buildInvocation := primaryBuilderInvocation(
|
||||||
|
config,
|
||||||
|
apiBp2buildTag,
|
||||||
|
config.ApiBp2buildMarkerFile(),
|
||||||
|
[]string{
|
||||||
|
"--bazel_api_bp2build_dir", apiBp2buildDir,
|
||||||
|
},
|
||||||
|
fmt.Sprintf("generating BUILD files for API contributions at %s", apiBp2buildDir),
|
||||||
|
)
|
||||||
|
|
||||||
soongDocsInvocation := primaryBuilderInvocation(
|
soongDocsInvocation := primaryBuilderInvocation(
|
||||||
config,
|
config,
|
||||||
soongDocsTag,
|
soongDocsTag,
|
||||||
|
@ -345,6 +360,7 @@ func bootstrapBlueprint(ctx Context, config Config) {
|
||||||
bp2buildInvocation,
|
bp2buildInvocation,
|
||||||
jsonModuleGraphInvocation,
|
jsonModuleGraphInvocation,
|
||||||
queryviewInvocation,
|
queryviewInvocation,
|
||||||
|
apiBp2buildInvocation,
|
||||||
soongDocsInvocation},
|
soongDocsInvocation},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,6 +433,10 @@ func runSoong(ctx Context, config Config) {
|
||||||
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(queryviewTag))
|
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(queryviewTag))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.ApiBp2build() {
|
||||||
|
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(apiBp2buildTag))
|
||||||
|
}
|
||||||
|
|
||||||
if config.SoongDocs() {
|
if config.SoongDocs() {
|
||||||
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongDocsTag))
|
checkEnvironmentFile(soongBuildEnv, config.UsedEnvFile(soongDocsTag))
|
||||||
}
|
}
|
||||||
|
@ -480,6 +500,10 @@ func runSoong(ctx Context, config Config) {
|
||||||
targets = append(targets, config.QueryviewMarkerFile())
|
targets = append(targets, config.QueryviewMarkerFile())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.ApiBp2build() {
|
||||||
|
targets = append(targets, config.ApiBp2buildMarkerFile())
|
||||||
|
}
|
||||||
|
|
||||||
if config.SoongDocs() {
|
if config.SoongDocs() {
|
||||||
targets = append(targets, config.SoongDocsHtml())
|
targets = append(targets, config.SoongDocsHtml())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue