Merge "Allow exporting bazel mixed build allowlists to simple text files"
diff --git a/android/config.go b/android/config.go
index 9d9ab30..9c1a484 100644
--- a/android/config.go
+++ b/android/config.go
@@ -21,7 +21,6 @@
"bytes"
"encoding/json"
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"reflect"
@@ -70,6 +69,26 @@
type SoongBuildMode int
+type CmdArgs struct {
+ bootstrap.Args
+ RunGoTests bool
+ OutDir string
+ SoongOutDir string
+
+ SymlinkForestMarker string
+ Bp2buildMarker string
+ BazelQueryViewDir string
+ BazelApiBp2buildDir string
+ ModuleGraphFile string
+ ModuleActionsFile string
+ DocFile string
+
+ BazelMode bool
+ BazelModeDev bool
+ BazelModeStaging bool
+ BazelForceEnabledModules string
+}
+
// Build modes that soong_build can run as.
const (
// Don't use bazel at all during module analysis.
@@ -307,7 +326,7 @@
return fmt.Errorf("cannot marshal config data: %s", err.Error())
}
- f, err := ioutil.TempFile(filepath.Dir(filename), "config")
+ f, err := os.CreateTemp(filepath.Dir(filename), "config")
if err != nil {
return fmt.Errorf("cannot create empty config file %s: %s", filename, err.Error())
}
@@ -404,20 +423,19 @@
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
-func NewConfig(moduleListFile string, buildMode SoongBuildMode, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string,
- bazelForceEnabledModules []string) (Config, error) {
+func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) {
// Make a config with default options.
config := &config{
- ProductVariablesFileName: filepath.Join(soongOutDir, productVariablesFileName),
+ ProductVariablesFileName: filepath.Join(cmdArgs.SoongOutDir, productVariablesFileName),
env: availableEnv,
- outDir: outDir,
- soongOutDir: soongOutDir,
- runGoTests: runGoTests,
+ outDir: cmdArgs.OutDir,
+ soongOutDir: cmdArgs.SoongOutDir,
+ runGoTests: cmdArgs.RunGoTests,
multilibConflicts: make(map[ArchType]bool),
- moduleListFile: moduleListFile,
+ moduleListFile: cmdArgs.ModuleListFile,
fs: pathtools.NewOsFs(absSrcDir),
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
@@ -430,7 +448,7 @@
// Soundness check of the build and source directories. This won't catch strange
// configurations with symlinks, but at least checks the obvious case.
- absBuildDir, err := filepath.Abs(soongOutDir)
+ absBuildDir, err := filepath.Abs(cmdArgs.SoongOutDir)
if err != nil {
return Config{}, err
}
@@ -450,7 +468,7 @@
return Config{}, err
}
- KatiEnabledMarkerFile := filepath.Join(soongOutDir, ".soong.kati_enabled")
+ KatiEnabledMarkerFile := filepath.Join(cmdArgs.SoongOutDir, ".soong.kati_enabled")
if _, err := os.Stat(absolutePath(KatiEnabledMarkerFile)); err == nil {
config.katiEnabled = true
}
@@ -503,11 +521,32 @@
config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
}
- config.BuildMode = buildMode
+ if cmdArgs.SymlinkForestMarker != "" {
+ config.BuildMode = SymlinkForest
+ } else if cmdArgs.Bp2buildMarker != "" {
+ config.BuildMode = Bp2build
+ } else if cmdArgs.BazelQueryViewDir != "" {
+ config.BuildMode = GenerateQueryView
+ } else if cmdArgs.BazelApiBp2buildDir != "" {
+ config.BuildMode = ApiBp2build
+ } else if cmdArgs.ModuleGraphFile != "" {
+ config.BuildMode = GenerateModuleGraph
+ } else if cmdArgs.DocFile != "" {
+ config.BuildMode = GenerateDocFile
+ } else if cmdArgs.BazelModeDev {
+ config.BuildMode = BazelDevMode
+ } else if cmdArgs.BazelMode {
+ config.BuildMode = BazelProdMode
+ } else if cmdArgs.BazelModeStaging {
+ config.BuildMode = BazelStagingMode
+ } else {
+ config.BuildMode = AnalysisNoBazel
+ }
+
config.BazelContext, err = NewBazelContext(config)
config.Bp2buildPackageConfig = GetBp2BuildAllowList()
- for _, module := range bazelForceEnabledModules {
+ for _, module := range strings.Split(cmdArgs.BazelForceEnabledModules, ",") {
config.bazelForceEnabledModules[module] = struct{}{}
}
@@ -1150,7 +1189,7 @@
return nil, nil
}
ctx.AddNinjaFileDeps(path.String())
- return ioutil.ReadFile(absolutePath(path.String()))
+ return os.ReadFile(absolutePath(path.String()))
}
func (c *deviceConfig) WithDexpreopt() bool {
@@ -1169,7 +1208,7 @@
return c.multilibConflicts[arch]
}
-func (c *config) PrebuiltHiddenApiDir(ctx PathContext) string {
+func (c *config) PrebuiltHiddenApiDir(_ PathContext) string {
return String(c.productVariables.PrebuiltHiddenApiDir)
}
diff --git a/android/module.go b/android/module.go
index 681f724..bf9737a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -27,7 +27,6 @@
"text/scanner"
"android/soong/bazel"
-
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
diff --git a/android/register.go b/android/register.go
index 33e9ea3..9a3d3aa 100644
--- a/android/register.go
+++ b/android/register.go
@@ -35,7 +35,7 @@
// tests.
componentName() string
- // register registers this component in the supplied context.
+ // registers this component in the supplied context.
register(ctx *Context)
}
@@ -124,7 +124,7 @@
return func() blueprint.Singleton {
singleton := factory()
if makevars, ok := singleton.(SingletonMakeVarsProvider); ok {
- registerSingletonMakeVarsProvider(ctx.config, makevars)
+ ctx.registerSingletonMakeVarsProvider(makevars)
}
return &singletonAdaptor{Singleton: singleton}
}
@@ -208,6 +208,14 @@
singletons.registerAll(ctx)
}
+func (ctx *Context) Config() Config {
+ return ctx.config
+}
+
+func (ctx *Context) registerSingletonMakeVarsProvider(makevars SingletonMakeVarsProvider) {
+ registerSingletonMakeVarsProvider(ctx.config, makevars)
+}
+
func collateGloballyRegisteredSingletons() sortableComponents {
allSingletons := append(sortableComponents(nil), singletons...)
allSingletons = append(allSingletons,
@@ -335,7 +343,7 @@
PreArchMutators(f)
}
-func (ctx *initRegistrationContext) HardCodedPreArchMutators(f RegisterMutatorFunc) {
+func (ctx *initRegistrationContext) HardCodedPreArchMutators(_ RegisterMutatorFunc) {
// Nothing to do as the mutators are hard code in preArch in mutator.go
}
diff --git a/bp2build/cc_test_conversion_test.go b/bp2build/cc_test_conversion_test.go
index 8c2d30d..b20f6ff 100644
--- a/bp2build/cc_test_conversion_test.go
+++ b/bp2build/cc_test_conversion_test.go
@@ -26,6 +26,7 @@
type ccTestBp2buildTestCase struct {
description string
blueprint string
+ filesystem map[string]string
targets []testBazelTarget
}
@@ -41,12 +42,12 @@
func runCcTestTestCase(t *testing.T, testCase ccTestBp2buildTestCase) {
t.Helper()
moduleTypeUnderTest := "cc_test"
-
description := fmt.Sprintf("%s %s", moduleTypeUnderTest, testCase.description)
t.Run(description, func(t *testing.T) {
t.Helper()
RunBp2BuildTestCase(t, registerCcTestModuleTypes, Bp2buildTestCase{
ExpectedBazelTargets: generateBazelTargetsForTest(testCase.targets, android.HostAndDeviceSupported),
+ Filesystem: testCase.filesystem,
ModuleTypeUnderTest: moduleTypeUnderTest,
ModuleTypeUnderTestFactory: cc.TestFactory,
Description: description,
@@ -172,3 +173,90 @@
},
})
}
+
+func TestCcTest_TestConfig(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "cc test that sets a test_config",
+ filesystem: map[string]string{
+ "test_config.xml": "",
+ },
+ blueprint: `
+cc_test {
+ name: "mytest",
+ srcs: ["test.cpp"],
+ test_config: "test_config.xml",
+}
+`,
+ targets: []testBazelTarget{
+ {"cc_test", "mytest", AttrNameToString{
+ "gtest": "True",
+ "isolated": "True",
+ "local_includes": `["."]`,
+ "srcs": `["test.cpp"]`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ "test_config": `"test_config.xml"`,
+ },
+ },
+ },
+ })
+}
+
+func TestCcTest_TestConfigAndroidTestXML(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "cc test that defaults to test config AndroidTest.xml",
+ filesystem: map[string]string{
+ "AndroidTest.xml": "",
+ },
+ blueprint: `
+cc_test {
+ name: "mytest",
+ srcs: ["test.cpp"],
+}
+`,
+ targets: []testBazelTarget{
+ {"cc_test", "mytest", AttrNameToString{
+ "gtest": "True",
+ "isolated": "True",
+ "local_includes": `["."]`,
+ "srcs": `["test.cpp"]`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ "test_config": `"AndroidTest.xml"`,
+ },
+ },
+ },
+ })
+}
+
+func TestCcTest_TestConfigTemplateOptions(t *testing.T) {
+ runCcTestTestCase(t, ccTestBp2buildTestCase{
+ description: "cc test that sets test config template attributes",
+ filesystem: map[string]string{
+ "test_config_template.xml": "",
+ },
+ blueprint: `
+cc_test {
+ name: "mytest",
+ srcs: ["test.cpp"],
+ test_config_template: "test_config_template.xml",
+ auto_gen_config: true,
+}
+`,
+ targets: []testBazelTarget{
+ {"cc_test", "mytest", AttrNameToString{
+ "auto_generate_test_config": "True",
+ "gtest": "True",
+ "isolated": "True",
+ "local_includes": `["."]`,
+ "srcs": `["test.cpp"]`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ "template_configs": `[
+ "'<target_preparer class=\"com.android.tradefed.targetprep.RootTargetPreparer\">\\n <option name=\"force-root\" value=\"false\" />\\n </target_preparer>'",
+ "'<option name=\"not-shardable\" value=\"true\" />'",
+ ]`,
+ "template_install_base": `"/data/local/tmp"`,
+ "template_test_config": `"test_config_template.xml"`,
+ },
+ },
+ },
+ })
+}
diff --git a/cc/test.go b/cc/test.go
index 536210b..dee6ed6 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -378,12 +378,6 @@
}
func (test *testBinary) install(ctx ModuleContext, file android.Path) {
- // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
- testInstallBase := "/data/local/tmp"
- if ctx.inVendor() || ctx.useVndk() {
- testInstallBase = "/data/local/tests/vendor"
- }
-
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
for _, dataSrcPath := range dataSrcPaths {
@@ -415,52 +409,20 @@
}
})
- var configs []tradefed.Config
- for _, module := range test.Properties.Test_mainline_modules {
- configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
- }
- if Bool(test.Properties.Require_root) {
- configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
- } else {
- var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
- configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
- }
- if Bool(test.Properties.Disable_framework) {
- var options []tradefed.Option
- configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
- }
- if test.isolated(ctx) {
- configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"})
- }
- if test.Properties.Test_options.Run_test_as != nil {
- configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)})
- }
- for _, tag := range test.Properties.Test_options.Test_suite_tag {
- configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
- }
- if test.Properties.Test_options.Min_shipping_api_level != nil {
- if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
- ctx.PropertyErrorf("test_options.min_shipping_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.")
- }
- var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_shipping_api_level), 10)})
- configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
- }
- if test.Properties.Test_options.Vsr_min_shipping_api_level != nil {
- var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "vsr-min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Vsr_min_shipping_api_level), 10)})
- configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
- }
- if test.Properties.Test_options.Min_vndk_version != nil {
- var options []tradefed.Option
- options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*test.Properties.Test_options.Min_vndk_version), 10)})
- options = append(options, tradefed.Option{Name: "api-level-prop", Value: "ro.vndk.version"})
- configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
- }
+ useVendor := ctx.inVendor() || ctx.useVndk()
+ testInstallBase := getTestInstallBase(useVendor)
+ configs := getTradefedConfigOptions(ctx, &test.Properties, test.isolated(ctx))
- test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
- test.Properties.Test_config_template, test.testDecorator.InstallerProperties.Test_suites, configs, test.Properties.Auto_gen_config, testInstallBase)
+ test.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(test.Properties.Test_config).
+ SetTestTemplateConfigProp(test.Properties.Test_config_template).
+ SetTestSuites(test.testDecorator.InstallerProperties.Test_suites).
+ SetConfig(configs).
+ SetAutoGenConfig(test.Properties.Auto_gen_config).
+ SetTestInstallBase(testInstallBase).
+ SetDeviceTemplate("${NativeTestConfigTemplate}").
+ SetHostTemplate("${NativeHostTestConfigTemplate}").
+ Build()
test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs)
@@ -479,6 +441,63 @@
test.binaryDecorator.baseInstaller.install(ctx, file)
}
+func getTestInstallBase(useVendor bool) string {
+ // TODO: (b/167308193) Switch to /data/local/tests/unrestricted as the default install base.
+ testInstallBase := "/data/local/tmp"
+ if useVendor {
+ testInstallBase = "/data/local/tests/vendor"
+ }
+ return testInstallBase
+}
+
+func getTradefedConfigOptions(ctx android.EarlyModuleContext, properties *TestBinaryProperties, isolated bool) []tradefed.Config {
+ var configs []tradefed.Config
+
+ for _, module := range properties.Test_mainline_modules {
+ configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module})
+ }
+ if Bool(properties.Require_root) {
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
+ } else {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{Name: "force-root", Value: "false"})
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
+ }
+ if Bool(properties.Disable_framework) {
+ var options []tradefed.Option
+ configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.StopServicesSetup", options})
+ }
+ if isolated {
+ configs = append(configs, tradefed.Option{Name: "not-shardable", Value: "true"})
+ }
+ if properties.Test_options.Run_test_as != nil {
+ configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(properties.Test_options.Run_test_as)})
+ }
+ for _, tag := range properties.Test_options.Test_suite_tag {
+ configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
+ }
+ if properties.Test_options.Min_shipping_api_level != nil {
+ if properties.Test_options.Vsr_min_shipping_api_level != nil {
+ ctx.PropertyErrorf("test_options.min_shipping_api_level", "must not be set at the same time as 'vsr_min_shipping_api_level'.")
+ }
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*properties.Test_options.Min_shipping_api_level), 10)})
+ configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
+ }
+ if properties.Test_options.Vsr_min_shipping_api_level != nil {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{Name: "vsr-min-api-level", Value: strconv.FormatInt(int64(*properties.Test_options.Vsr_min_shipping_api_level), 10)})
+ configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController", options})
+ }
+ if properties.Test_options.Min_vndk_version != nil {
+ var options []tradefed.Option
+ options = append(options, tradefed.Option{Name: "min-api-level", Value: strconv.FormatInt(int64(*properties.Test_options.Min_vndk_version), 10)})
+ options = append(options, tradefed.Option{Name: "api-level-prop", Value: "ro.vndk.version"})
+ configs = append(configs, tradefed.Object{"module_controller", "com.android.tradefed.testtype.suite.module.MinApiLevelModuleController", options})
+ }
+ return configs
+}
+
func NewTest(hod android.HostOrDeviceSupported, bazelable bool) *Module {
module, binary := newBinary(hod, bazelable)
module.multilib = android.MultilibBoth
@@ -616,8 +635,15 @@
if Bool(benchmark.Properties.Require_root) {
configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
}
- benchmark.testConfig = tradefed.AutoGenNativeBenchmarkTestConfig(ctx, benchmark.Properties.Test_config,
- benchmark.Properties.Test_config_template, benchmark.Properties.Test_suites, configs, benchmark.Properties.Auto_gen_config)
+ benchmark.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(benchmark.Properties.Test_config).
+ SetTestTemplateConfigProp(benchmark.Properties.Test_config_template).
+ SetTestSuites(benchmark.Properties.Test_suites).
+ SetConfig(configs).
+ SetAutoGenConfig(benchmark.Properties.Auto_gen_config).
+ SetDeviceTemplate("${NativeBenchmarkTestConfigTemplate}").
+ SetHostTemplate("${NativeBenchmarkTestConfigTemplate}").
+ Build()
benchmark.binaryDecorator.baseInstaller.dir = filepath.Join("benchmarktest", ctx.ModuleName())
benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName())
@@ -645,6 +671,7 @@
Isolated bool
tidyAttributes
+ tradefed.TestConfigAttributes
}
// testBinaryBp2build is the bp2build converter for cc_test modules. A cc_test's
@@ -655,7 +682,6 @@
// TODO(b/244432609): handle `isolated` property.
// TODO(b/244432134): handle custom runpaths for tests that assume runfile layouts not
// default to bazel. (see linkerInit function)
-// TODO(b/244432500): handle test.testConfig generation (see install function)
func testBinaryBp2build(ctx android.TopDownMutatorContext, m *Module) {
var testBinaryAttrs testBinaryAttributes
testBinaryAttrs.binaryAttributes = binaryBp2buildAttrs(ctx, m)
@@ -688,6 +714,25 @@
}
}
+ for _, testProps := range m.GetProperties() {
+ if p, ok := testProps.(*TestBinaryProperties); ok {
+ useVendor := false // TODO Bug: 262914724
+ testInstallBase := getTestInstallBase(useVendor)
+ testConfigAttributes := tradefed.GetTestConfigAttributes(
+ ctx,
+ p.Test_config,
+ p.Test_options.Extra_test_configs,
+ p.Auto_gen_config,
+ p.Test_options.Test_suite_tag,
+ p.Test_config_template,
+ getTradefedConfigOptions(ctx, p, testBinaryAttrs.Isolated),
+ &testInstallBase,
+ )
+ testBinaryAttrs.TestConfigAttributes = testConfigAttributes
+ }
+ }
+
+ // TODO (b/262914724): convert to tradefed_cc_test and tradefed_cc_test_host
ctx.CreateBazelTargetModule(
bazel.BazelTargetModuleProperties{
Rule_class: "cc_test",
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index bea8df0..744a10c 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -18,7 +18,6 @@
"bytes"
"flag"
"fmt"
- "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -38,38 +37,26 @@
var (
topDir string
- outDir string
- soongOutDir string
availableEnvFile string
usedEnvFile string
- runGoTests bool
-
globFile string
globListDir string
delveListen string
delvePath string
- moduleGraphFile string
- moduleActionsFile string
- docFile string
- bazelQueryViewDir string
- bazelApiBp2buildDir string
- bp2buildMarker string
- symlinkForestMarker string
-
- cmdlineArgs bootstrap.Args
+ cmdlineArgs android.CmdArgs
)
func init() {
// Flags that make sense in every mode
flag.StringVar(&topDir, "top", "", "Top directory of the Android source tree")
- flag.StringVar(&soongOutDir, "soong_out", "", "Soong output directory (usually $TOP/out/soong)")
+ flag.StringVar(&cmdlineArgs.SoongOutDir, "soong_out", "", "Soong output directory (usually $TOP/out/soong)")
flag.StringVar(&availableEnvFile, "available_env", "", "File containing available environment variables")
flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables")
flag.StringVar(&globFile, "globFile", "build-globs.ninja", "the Ninja file of globs to output")
flag.StringVar(&globListDir, "globListDir", "", "the directory containing the glob list files")
- flag.StringVar(&outDir, "out", "", "the ninja builddir directory")
+ flag.StringVar(&cmdlineArgs.OutDir, "out", "", "the ninja builddir directory")
flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse")
// Debug flags
@@ -81,13 +68,13 @@
flag.BoolVar(&cmdlineArgs.NoGC, "nogc", false, "turn off GC for debugging")
// Flags representing various modes soong_build can run in
- flag.StringVar(&moduleGraphFile, "module_graph_file", "", "JSON module graph file to output")
- 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(&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(&symlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
+ flag.StringVar(&cmdlineArgs.ModuleGraphFile, "module_graph_file", "", "JSON module graph file to output")
+ flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules")
+ flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output")
+ flag.StringVar(&cmdlineArgs.BazelQueryViewDir, "bazel_queryview_dir", "", "path to the bazel queryview directory relative to --top")
+ flag.StringVar(&cmdlineArgs.BazelApiBp2buildDir, "bazel_api_bp2build_dir", "", "path to the bazel api_bp2build directory relative to --top")
+ flag.StringVar(&cmdlineArgs.Bp2buildMarker, "bp2build_marker", "", "If set, run bp2build, touch the specified marker file then exit")
+ flag.StringVar(&cmdlineArgs.SymlinkForestMarker, "symlink_forest_marker", "", "If set, create the bp2build symlink forest, touch the specified marker file, then exit")
flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output")
flag.StringVar(&cmdlineArgs.BazelForceEnabledModules, "bazel-force-enabled-modules", "", "additional modules to build with Bazel. Comma-delimited")
flag.BoolVar(&cmdlineArgs.EmptyNinjaFile, "empty-ninja-file", false, "write out a 0-byte ninja file")
@@ -95,9 +82,9 @@
flag.BoolVar(&cmdlineArgs.BazelModeStaging, "bazel-mode-staging", false, "use bazel for analysis of certain near-ready modules")
flag.BoolVar(&cmdlineArgs.BazelModeDev, "bazel-mode-dev", false, "use bazel for analysis of a large number of modules (less stable)")
- // Flags that probably shouldn't be flags of soong_build but we haven't found
+ // Flags that probably shouldn't be flags of soong_build, but we haven't found
// the time to remove them yet
- flag.BoolVar(&runGoTests, "t", false, "build and run go tests during bootstrap")
+ flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap")
// Disable deterministic randomization in the protobuf package, so incremental
// builds with unrelated Soong changes don't trigger large rebuilds (since we
@@ -118,87 +105,44 @@
return ctx
}
-func newConfig(availableEnv map[string]string) android.Config {
- var buildMode android.SoongBuildMode
- var bazelForceEnabledModules []string
- if len(cmdlineArgs.BazelForceEnabledModules) > 0 {
- bazelForceEnabledModules = strings.Split(cmdlineArgs.BazelForceEnabledModules, ",")
- }
-
- if symlinkForestMarker != "" {
- buildMode = android.SymlinkForest
- } else if bp2buildMarker != "" {
- buildMode = android.Bp2build
- } else if bazelQueryViewDir != "" {
- buildMode = android.GenerateQueryView
- } else if bazelApiBp2buildDir != "" {
- buildMode = android.ApiBp2build
- } else if moduleGraphFile != "" {
- buildMode = android.GenerateModuleGraph
- } else if docFile != "" {
- buildMode = android.GenerateDocFile
- } else if cmdlineArgs.BazelModeDev {
- buildMode = android.BazelDevMode
- } else if cmdlineArgs.BazelMode {
- buildMode = android.BazelProdMode
- } else if cmdlineArgs.BazelModeStaging {
- buildMode = android.BazelStagingMode
- } else {
- buildMode = android.AnalysisNoBazel
- }
-
- configuration, err := android.NewConfig(cmdlineArgs.ModuleListFile, buildMode, runGoTests, outDir, soongOutDir, availableEnv, bazelForceEnabledModules)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s", err)
- os.Exit(1)
- }
- return configuration
-}
-
// Bazel-enabled mode. Attaches a mutator to queue Bazel requests, adds a
// BeforePrepareBuildActionsHook to invoke Bazel, and then uses Bazel metadata
// for modules that should be handled by Bazel.
-func runMixedModeBuild(configuration android.Config, ctx *android.Context, extraNinjaDeps []string) string {
+func runMixedModeBuild(ctx *android.Context, extraNinjaDeps []string) string {
ctx.EventHandler.Begin("mixed_build")
defer ctx.EventHandler.End("mixed_build")
bazelHook := func() error {
- return configuration.BazelContext.InvokeBazel(configuration, ctx)
+ return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
- ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs, bootstrap.DoEverything, ctx.Context, configuration)
+ ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, bootstrap.DoEverything, ctx.Context, ctx.Config())
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- bazelPaths, err := readBazelPaths(configuration)
+ bazelPaths, err := readFileLines(ctx.Config().Getenv("BAZEL_DEPS_FILE"))
if err != nil {
panic("Bazel deps file not found: " + err.Error())
}
ninjaDeps = append(ninjaDeps, bazelPaths...)
-
- globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
- ninjaDeps = append(ninjaDeps, globListFiles...)
+ ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
return cmdlineArgs.OutFile
}
// Run the code-generation phase to convert BazelTargetModules to BUILD files.
-func runQueryView(queryviewDir, queryviewMarker string, configuration android.Config, ctx *android.Context) {
+func runQueryView(queryviewDir, queryviewMarker string, ctx *android.Context) {
ctx.EventHandler.Begin("queryview")
defer ctx.EventHandler.End("queryview")
- codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.QueryView)
- absoluteQueryViewDir := shared.JoinPath(topDir, queryviewDir)
- if err := createBazelWorkspace(codegenContext, absoluteQueryViewDir); err != nil {
- fmt.Fprintf(os.Stderr, "%s", err)
- os.Exit(1)
- }
-
+ codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.QueryView)
+ err := createBazelWorkspace(codegenContext, shared.JoinPath(topDir, queryviewDir))
+ maybeQuit(err, "")
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, ctx *android.Context, extraNinjaDeps []string) string {
+func runApiBp2build(ctx *android.Context, extraNinjaDeps []string) string {
ctx.EventHandler.Begin("api_bp2build")
defer ctx.EventHandler.End("api_bp2build")
// Do not allow missing dependencies.
@@ -215,28 +159,25 @@
}
// Run the loading and analysis phase
- ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs,
+ ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args,
bootstrap.StopBeforePrepareBuildActions,
ctx.Context,
- configuration)
+ ctx.Config())
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
// Add the globbed dependencies
- globs := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
- ninjaDeps = append(ninjaDeps, globs...)
+ ninjaDeps = append(ninjaDeps, writeBuildGlobsNinjaFile(ctx)...)
// 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)
- }
+ codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.ApiBp2build)
+ absoluteApiBp2buildDir := shared.JoinPath(topDir, cmdlineArgs.BazelApiBp2buildDir)
+ err := createBazelWorkspace(codegenContext, absoluteApiBp2buildDir)
+ maybeQuit(err, "")
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
// Create soong_injection repository
- soongInjectionFiles := bp2build.CreateSoongInjectionFiles(configuration, bp2build.CreateCodegenMetrics())
- absoluteSoongInjectionDir := shared.JoinPath(topDir, configuration.SoongOutDir(), bazel.SoongInjectionDirName)
+ soongInjectionFiles := bp2build.CreateSoongInjectionFiles(ctx.Config(), bp2build.CreateCodegenMetrics())
+ absoluteSoongInjectionDir := shared.JoinPath(topDir, ctx.Config().SoongOutDir(), bazel.SoongInjectionDirName)
for _, file := range soongInjectionFiles {
// The API targets in api_bp2build workspace do not have any dependency on api_bp2build.
// But we need to create these files to prevent errors during Bazel analysis.
@@ -246,24 +187,14 @@
writeReadWriteFile(absoluteSoongInjectionDir, file)
}
- workspace := shared.JoinPath(configuration.SoongOutDir(), "api_bp2build")
-
- excludes := bazelArtifacts()
- // Exclude all src BUILD files
- excludes = append(excludes, apiBuildFileExcludes()...)
-
- // Android.bp files for api surfaces are mounted to out/, but out/ should not be a
- // dep for api_bp2build.
- // Otherwise api_bp2build will be run every single time
- excludes = append(excludes, configuration.OutDir())
-
+ workspace := shared.JoinPath(ctx.Config().SoongOutDir(), "api_bp2build")
// Create the symlink forest
symlinkDeps := bp2build.PlantSymlinkForest(
- configuration.IsEnvTrue("BP2BUILD_VERBOSE"),
+ ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE"),
topDir,
workspace,
- bazelApiBp2buildDir,
- excludes)
+ cmdlineArgs.BazelApiBp2buildDir,
+ apiBuildFileExcludes(ctx))
ninjaDeps = append(ninjaDeps, symlinkDeps...)
workspaceMarkerFile := workspace + ".marker"
@@ -274,15 +205,12 @@
// 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)
-
+func apiBuildFileExcludes(ctx *android.Context) []string {
+ ret := bazelArtifacts()
srcs, err := getExistingBazelRelatedFiles(topDir)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
- os.Exit(1)
- }
+ maybeQuit(err, "Error determining existing Bazel-related files")
for _, src := range srcs {
+ // Exclude all src BUILD files
if src != "WORKSPACE" &&
src != "BUILD" &&
src != "BUILD.bazel" &&
@@ -292,6 +220,9 @@
ret = append(ret, src)
}
}
+ // Android.bp files for api surfaces are mounted to out/, but out/ should not be a
+ // dep for api_bp2build. Otherwise, api_bp2build will be run every single time
+ ret = append(ret, ctx.Config().OutDir())
return ret
}
@@ -302,36 +233,30 @@
}
metricsFile := filepath.Join(metricsDir, "soong_build_metrics.pb")
err := android.WriteMetrics(configuration, eventHandler, metricsFile)
- if err != nil {
- fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err)
- os.Exit(1)
- }
+ maybeQuit(err, "error writing soong_build metrics %s", metricsFile)
}
-func writeJsonModuleGraphAndActions(ctx *android.Context, graphPath string, actionsPath string) {
- graphFile, graphErr := os.Create(shared.JoinPath(topDir, graphPath))
- actionsFile, actionsErr := os.Create(shared.JoinPath(topDir, actionsPath))
- if graphErr != nil || actionsErr != nil {
- fmt.Fprintf(os.Stderr, "Graph err: %s, actions err: %s", graphErr, actionsErr)
- os.Exit(1)
- }
-
+func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) {
+ graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile))
+ maybeQuit(graphErr, "graph err")
defer graphFile.Close()
+ actionsFile, actionsErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleActionsFile))
+ maybeQuit(actionsErr, "actions err")
defer actionsFile.Close()
ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile)
}
-func writeBuildGlobsNinjaFile(ctx *android.Context, buildDir string, config interface{}) []string {
+func writeBuildGlobsNinjaFile(ctx *android.Context) []string {
ctx.EventHandler.Begin("globs_ninja_file")
defer ctx.EventHandler.End("globs_ninja_file")
- globDir := bootstrap.GlobDirectory(buildDir, globListDir)
+ globDir := bootstrap.GlobDirectory(ctx.Config().SoongOutDir(), globListDir)
bootstrap.WriteBuildGlobsNinjaFile(&bootstrap.GlobSingleton{
GlobLister: ctx.Globs,
GlobFile: globFile,
GlobDir: globDir,
SrcDir: ctx.SrcDir(),
- }, config)
+ }, ctx.Config())
return bootstrap.GlobFileListFiles(globDir)
}
@@ -340,83 +265,50 @@
defer eventHandler.End("ninja_deps")
depFile := shared.JoinPath(topDir, outputFile+".d")
err := deptools.WriteDepFile(depFile, outputFile, ninjaDeps)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error writing depfile '%s': %s\n", depFile, err)
- os.Exit(1)
- }
-}
-
-// doChosenActivity runs Soong for a specific activity, like bp2build, queryview
-// or the actual Soong build for the build.ninja file. Returns the top level
-// output file of the specific activity.
-func doChosenActivity(ctx *android.Context, configuration android.Config, extraNinjaDeps []string, metricsDir string) string {
- if configuration.BuildMode == android.SymlinkForest {
- return runSymlinkForestCreation(configuration, ctx, extraNinjaDeps, metricsDir)
- } else if configuration.BuildMode == android.Bp2build {
- // Run the alternate pipeline of bp2build mutators and singleton to convert
- // Blueprint to BUILD files before everything else.
- return runBp2Build(configuration, ctx, extraNinjaDeps, metricsDir)
- } else if configuration.BuildMode == android.ApiBp2build {
- outputFile := runApiBp2build(configuration, ctx, extraNinjaDeps)
- writeMetrics(configuration, ctx.EventHandler, metricsDir)
- return outputFile
- } else {
- ctx.Register()
-
- var outputFile string
- if configuration.IsMixedBuildsEnabled() {
- outputFile = runMixedModeBuild(configuration, ctx, extraNinjaDeps)
- } else {
- outputFile = runSoongOnlyBuild(configuration, ctx, extraNinjaDeps)
- }
-
- writeMetrics(configuration, ctx.EventHandler, metricsDir)
-
- return outputFile
- }
+ maybeQuit(err, "error writing depfile '%s'", depFile)
}
// runSoongOnlyBuild runs the standard Soong build in a number of different modes.
-func runSoongOnlyBuild(configuration android.Config, ctx *android.Context, extraNinjaDeps []string) string {
+func runSoongOnlyBuild(ctx *android.Context, extraNinjaDeps []string) string {
ctx.EventHandler.Begin("soong_build")
defer ctx.EventHandler.End("soong_build")
var stopBefore bootstrap.StopBefore
- if configuration.BuildMode == android.GenerateModuleGraph {
+ switch ctx.Config().BuildMode {
+ case android.GenerateModuleGraph:
stopBefore = bootstrap.StopBeforeWriteNinja
- } else if configuration.BuildMode == android.GenerateQueryView || configuration.BuildMode == android.GenerateDocFile {
+ case android.GenerateQueryView | android.GenerateDocFile:
stopBefore = bootstrap.StopBeforePrepareBuildActions
- } else {
+ default:
stopBefore = bootstrap.DoEverything
}
- ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs, stopBefore, ctx.Context, configuration)
+ ninjaDeps := bootstrap.RunBlueprint(cmdlineArgs.Args, stopBefore, ctx.Context, ctx.Config())
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
- globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
+ globListFiles := writeBuildGlobsNinjaFile(ctx)
ninjaDeps = append(ninjaDeps, globListFiles...)
// Convert the Soong module graph into Bazel BUILD files.
- if configuration.BuildMode == android.GenerateQueryView {
- queryviewMarkerFile := bazelQueryViewDir + ".marker"
- runQueryView(bazelQueryViewDir, queryviewMarkerFile, configuration, ctx)
+ switch ctx.Config().BuildMode {
+ case android.GenerateQueryView:
+ queryviewMarkerFile := cmdlineArgs.BazelQueryViewDir + ".marker"
+ runQueryView(cmdlineArgs.BazelQueryViewDir, queryviewMarkerFile, ctx)
writeDepFile(queryviewMarkerFile, ctx.EventHandler, ninjaDeps)
return queryviewMarkerFile
- } else if configuration.BuildMode == android.GenerateModuleGraph {
- writeJsonModuleGraphAndActions(ctx, moduleGraphFile, moduleActionsFile)
- writeDepFile(moduleGraphFile, ctx.EventHandler, ninjaDeps)
- return moduleGraphFile
- } else if configuration.BuildMode == android.GenerateDocFile {
+ case android.GenerateModuleGraph:
+ writeJsonModuleGraphAndActions(ctx, cmdlineArgs)
+ writeDepFile(cmdlineArgs.ModuleGraphFile, ctx.EventHandler, ninjaDeps)
+ return cmdlineArgs.ModuleGraphFile
+ case android.GenerateDocFile:
// TODO: we could make writeDocs() return the list of documentation files
// written and add them to the .d file. Then soong_docs would be re-run
// whenever one is deleted.
- if err := writeDocs(ctx, shared.JoinPath(topDir, docFile)); err != nil {
- fmt.Fprintf(os.Stderr, "error building Soong documentation: %s\n", err)
- os.Exit(1)
- }
- writeDepFile(docFile, ctx.EventHandler, ninjaDeps)
- return docFile
- } else {
+ err := writeDocs(ctx, shared.JoinPath(topDir, cmdlineArgs.DocFile))
+ maybeQuit(err, "error building Soong documentation")
+ writeDepFile(cmdlineArgs.DocFile, ctx.EventHandler, ninjaDeps)
+ return cmdlineArgs.DocFile
+ default:
// The actual output (build.ninja) was written in the RunBlueprint() call
// above
writeDepFile(cmdlineArgs.OutFile, ctx.EventHandler, ninjaDeps)
@@ -442,13 +334,8 @@
fmt.Fprintf(os.Stderr, "--available_env not set\n")
os.Exit(1)
}
-
result, err := shared.EnvFromFile(shared.JoinPath(topDir, availableEnvFile))
- if err != nil {
- fmt.Fprintf(os.Stderr, "error reading available environment file '%s': %s\n", availableEnvFile, err)
- os.Exit(1)
- }
-
+ maybeQuit(err, "error reading available environment file '%s'", availableEnvFile)
return result
}
@@ -459,17 +346,13 @@
android.InitSandbox(topDir)
availableEnv := parseAvailableEnv()
-
- configuration := newConfig(availableEnv)
- extraNinjaDeps := []string{
- configuration.ProductVariablesFileName,
- usedEnvFile,
- }
-
+ configuration, err := android.NewConfig(cmdlineArgs, availableEnv)
+ maybeQuit(err, "")
if configuration.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
configuration.SetAllowMissingDependencies()
}
+ extraNinjaDeps := []string{configuration.ProductVariablesFileName, usedEnvFile}
if shared.IsDebugging() {
// Add a non-existent file to the dependencies so that soong_build will rerun when the debugger is
// enabled even if it completed successfully.
@@ -478,12 +361,33 @@
// Bypass configuration.Getenv, as LOG_DIR does not need to be dependency tracked. By definition, it will
// change between every CI build, so tracking it would require re-running Soong for every build.
- logDir := availableEnv["LOG_DIR"]
+ metricsDir := availableEnv["LOG_DIR"]
ctx := newContext(configuration)
- finalOutputFile := doChosenActivity(ctx, configuration, extraNinjaDeps, logDir)
+ var finalOutputFile string
+ // Run Soong for a specific activity, like bp2build, queryview
+ // or the actual Soong build for the build.ninja file.
+ switch configuration.BuildMode {
+ case android.SymlinkForest:
+ finalOutputFile = runSymlinkForestCreation(ctx, extraNinjaDeps, metricsDir)
+ case android.Bp2build:
+ // Run the alternate pipeline of bp2build mutators and singleton to convert
+ // Blueprint to BUILD files before everything else.
+ finalOutputFile = runBp2Build(ctx, extraNinjaDeps, metricsDir)
+ case android.ApiBp2build:
+ finalOutputFile = runApiBp2build(ctx, extraNinjaDeps)
+ writeMetrics(configuration, ctx.EventHandler, metricsDir)
+ default:
+ ctx.Register()
+ if configuration.IsMixedBuildsEnabled() {
+ finalOutputFile = runMixedModeBuild(ctx, extraNinjaDeps)
+ } else {
+ finalOutputFile = runSoongOnlyBuild(ctx, extraNinjaDeps)
+ }
+ writeMetrics(configuration, ctx.EventHandler, metricsDir)
+ }
writeUsedEnvironmentFile(configuration, finalOutputFile)
}
@@ -494,24 +398,19 @@
path := shared.JoinPath(topDir, usedEnvFile)
data, err := shared.EnvFileContents(configuration.EnvDeps())
- if err != nil {
- fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
- os.Exit(1)
- }
+ maybeQuit(err, "error writing used environment file '%s'\n", usedEnvFile)
if preexistingData, err := os.ReadFile(path); err != nil {
if !os.IsNotExist(err) {
- fmt.Fprintf(os.Stderr, "error reading used environment file '%s': %s\n", usedEnvFile, err)
- os.Exit(1)
+ maybeQuit(err, "error reading used environment file '%s'", usedEnvFile)
}
} else if bytes.Equal(preexistingData, data) {
// used environment file is unchanged
return
}
- if err = os.WriteFile(path, data, 0666); err != nil {
- fmt.Fprintf(os.Stderr, "error writing used environment file '%s': %s\n", usedEnvFile, err)
- os.Exit(1)
- }
+ err = os.WriteFile(path, data, 0666)
+ maybeQuit(err, "error writing used environment file '%s'", usedEnvFile)
+
// Touch the output file so that it's not older than the file we just
// wrote. We can't write the environment file earlier because one an access
// new environment variables while writing it.
@@ -520,88 +419,13 @@
func touch(path string) {
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
- os.Exit(1)
- }
-
+ maybeQuit(err, "Error touching '%s'", path)
err = f.Close()
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error touching '%s': %s\n", path, err)
- os.Exit(1)
- }
+ maybeQuit(err, "Error touching '%s'", path)
currentTime := time.Now().Local()
err = os.Chtimes(path, currentTime, currentTime)
- if err != nil {
- fmt.Fprintf(os.Stderr, "error touching '%s': %s\n", path, err)
- os.Exit(1)
- }
-}
-
-// Find BUILD files in the srcDir which are not in the allowlist
-// (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir)
-// and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
-func getPathsToIgnoredBuildFiles(config android.Bp2BuildConversionAllowlist, topDir string, srcDirBazelFiles []string, verbose bool) []string {
- paths := make([]string, 0)
-
- for _, srcDirBazelFileRelativePath := range srcDirBazelFiles {
- srcDirBazelFileFullPath := shared.JoinPath(topDir, srcDirBazelFileRelativePath)
- fileInfo, err := os.Stat(srcDirBazelFileFullPath)
- if err != nil {
- // Warn about error, but continue trying to check files
- fmt.Fprintf(os.Stderr, "WARNING: Error accessing path '%s', err: %s\n", srcDirBazelFileFullPath, err)
- continue
- }
- if fileInfo.IsDir() {
- // Don't ignore entire directories
- continue
- }
- if fileInfo.Name() != "BUILD" && fileInfo.Name() != "BUILD.bazel" {
- // Don't ignore this file - it is not a build file
- continue
- }
- if config.ShouldKeepExistingBuildFileForDir(filepath.Dir(srcDirBazelFileRelativePath)) {
- // Don't ignore this existing build file
- continue
- }
- if verbose {
- fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", srcDirBazelFileRelativePath)
- }
- paths = append(paths, srcDirBazelFileRelativePath)
- }
-
- return paths
-}
-
-// Returns temporary symlink forest excludes necessary for bazel build //external/... (and bazel build //frameworks/...) to work
-func getTemporaryExcludes() []string {
- excludes := make([]string, 0)
-
- // FIXME: 'autotest_lib' is a symlink back to external/autotest, and this causes an infinite symlink expansion error for Bazel
- excludes = append(excludes, "external/autotest/venv/autotest_lib")
- excludes = append(excludes, "external/autotest/autotest_lib")
- excludes = append(excludes, "external/autotest/client/autotest_lib/client")
-
- // FIXME: The external/google-fruit/extras/bazel_root/third_party/fruit dir is poison
- // It contains several symlinks back to real source dirs, and those source dirs contain BUILD files we want to ignore
- excludes = append(excludes, "external/google-fruit/extras/bazel_root/third_party/fruit")
-
- // FIXME: 'frameworks/compile/slang' has a filegroup error due to an escaping issue
- excludes = append(excludes, "frameworks/compile/slang")
-
- // FIXME(b/260809113): 'prebuilts/clang/host/linux-x86/clang-dev' is a tool-generated symlink directory that contains a BUILD file.
- // The bazel files finder code doesn't traverse into symlink dirs, and hence is not aware of this BUILD file and exclude it accordingly
- // during symlink forest generation when checking against keepExistingBuildFiles allowlist.
- //
- // This is necessary because globs in //prebuilts/clang/host/linux-x86/BUILD
- // currently assume no subpackages (keepExistingBuildFile is not recursive for that directory).
- //
- // This is a bandaid until we the symlink forest logic can intelligently exclude BUILD files found in source symlink dirs according
- // to the keepExistingBuildFile allowlist.
- excludes = append(excludes, "prebuilts/clang/host/linux-x86/clang-dev")
-
- return excludes
+ maybeQuit(err, "error touching '%s'", path)
}
// Read the bazel.list file that the Soong Finder already dumped earlier (hopefully)
@@ -612,12 +436,7 @@
// Assume this was a relative path under topDir
bazelFinderFile = filepath.Join(topDir, bazelFinderFile)
}
- data, err := ioutil.ReadFile(bazelFinderFile)
- if err != nil {
- return nil, err
- }
- files := strings.Split(strings.TrimSpace(string(data)), "\n")
- return files, nil
+ return readFileLines(bazelFinderFile)
}
func bazelArtifacts() []string {
@@ -639,41 +458,25 @@
// Ideally, bp2build would write a file that contains instructions to the
// symlink tree creation binary. Then the latter would not need to depend on
// the very heavy-weight machinery of soong_build .
-func runSymlinkForestCreation(configuration android.Config, ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
+func runSymlinkForestCreation(ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
ctx.EventHandler.Do("symlink_forest", func() {
var ninjaDeps []string
ninjaDeps = append(ninjaDeps, extraNinjaDeps...)
-
- generatedRoot := shared.JoinPath(configuration.SoongOutDir(), "bp2build")
- workspaceRoot := shared.JoinPath(configuration.SoongOutDir(), "workspace")
-
- excludes := bazelArtifacts()
-
- if outDir[0] != '/' {
- excludes = append(excludes, outDir)
- }
-
- existingBazelRelatedFiles, err := getExistingBazelRelatedFiles(topDir)
- if err != nil {
- fmt.Fprintf(os.Stderr, "Error determining existing Bazel-related files: %s\n", err)
- os.Exit(1)
- }
-
- pathsToIgnoredBuildFiles := getPathsToIgnoredBuildFiles(configuration.Bp2buildPackageConfig, topDir, existingBazelRelatedFiles, configuration.IsEnvTrue("BP2BUILD_VERBOSE"))
- excludes = append(excludes, pathsToIgnoredBuildFiles...)
- excludes = append(excludes, getTemporaryExcludes()...)
+ verbose := ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE")
// PlantSymlinkForest() returns all the directories that were readdir()'ed.
// Such a directory SHOULD be added to `ninjaDeps` so that a child directory
// or file created/deleted under it would trigger an update of the symlink forest.
+ generatedRoot := shared.JoinPath(ctx.Config().SoongOutDir(), "bp2build")
+ workspaceRoot := shared.JoinPath(ctx.Config().SoongOutDir(), "workspace")
ctx.EventHandler.Do("plant", func() {
symlinkForestDeps := bp2build.PlantSymlinkForest(
- configuration.IsEnvTrue("BP2BUILD_VERBOSE"), topDir, workspaceRoot, generatedRoot, excludes)
+ verbose, topDir, workspaceRoot, generatedRoot, excludedFromSymlinkForest(ctx, verbose))
ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
})
- writeDepFile(symlinkForestMarker, ctx.EventHandler, ninjaDeps)
- touch(shared.JoinPath(topDir, symlinkForestMarker))
+ writeDepFile(cmdlineArgs.SymlinkForestMarker, ctx.EventHandler, ninjaDeps)
+ touch(shared.JoinPath(topDir, cmdlineArgs.SymlinkForestMarker))
})
codegenMetrics := bp2build.ReadCodegenMetrics(metricsDir)
if codegenMetrics == nil {
@@ -684,21 +487,84 @@
//invocation of codegen. We should simply use a separate .pb file
}
writeBp2BuildMetrics(codegenMetrics, ctx.EventHandler, metricsDir)
+ return cmdlineArgs.SymlinkForestMarker
+}
- return symlinkForestMarker
+func excludedFromSymlinkForest(ctx *android.Context, verbose bool) []string {
+ excluded := bazelArtifacts()
+ if cmdlineArgs.OutDir[0] != '/' {
+ excluded = append(excluded, cmdlineArgs.OutDir)
+ }
+
+ // Find BUILD files in the srcDir which are not in the allowlist
+ // (android.Bp2BuildConversionAllowlist#ShouldKeepExistingBuildFileForDir)
+ // and return their paths so they can be left out of the Bazel workspace dir (i.e. ignored)
+ existingBazelFiles, err := getExistingBazelRelatedFiles(topDir)
+ maybeQuit(err, "Error determining existing Bazel-related files")
+
+ for _, path := range existingBazelFiles {
+ fullPath := shared.JoinPath(topDir, path)
+ fileInfo, err2 := os.Stat(fullPath)
+ if err2 != nil {
+ // Warn about error, but continue trying to check files
+ fmt.Fprintf(os.Stderr, "WARNING: Error accessing path '%s', err: %s\n", fullPath, err2)
+ continue
+ }
+ // Exclude only files named 'BUILD' or 'BUILD.bazel' and unless forcibly kept
+ if fileInfo.IsDir() ||
+ (fileInfo.Name() != "BUILD" && fileInfo.Name() != "BUILD.bazel") ||
+ ctx.Config().Bp2buildPackageConfig.ShouldKeepExistingBuildFileForDir(filepath.Dir(path)) {
+ // Don't ignore this existing build file
+ continue
+ }
+ if verbose {
+ fmt.Fprintf(os.Stderr, "Ignoring existing BUILD file: %s\n", path)
+ }
+ excluded = append(excluded, path)
+ }
+
+ // Temporarily exclude stuff to make `bazel build //external/...` (and `bazel build //frameworks/...`) work
+ excluded = append(excluded,
+ // FIXME: 'autotest_lib' is a symlink back to external/autotest, and this causes an infinite
+ // symlink expansion error for Bazel
+ "external/autotest/venv/autotest_lib",
+ "external/autotest/autotest_lib",
+ "external/autotest/client/autotest_lib/client",
+
+ // FIXME: The external/google-fruit/extras/bazel_root/third_party/fruit dir is poison
+ // It contains several symlinks back to real source dirs, and those source dirs contain
+ // BUILD files we want to ignore
+ "external/google-fruit/extras/bazel_root/third_party/fruit",
+
+ // FIXME: 'frameworks/compile/slang' has a filegroup error due to an escaping issue
+ "frameworks/compile/slang",
+
+ // FIXME(b/260809113): 'prebuilts/clang/host/linux-x86/clang-dev' is a tool-generated symlink
+ // directory that contains a BUILD file. The bazel files finder code doesn't traverse into symlink dirs,
+ // and hence is not aware of this BUILD file and exclude it accordingly during symlink forest generation
+ // when checking against keepExistingBuildFiles allowlist.
+ //
+ // This is necessary because globs in //prebuilts/clang/host/linux-x86/BUILD
+ // currently assume no subpackages (keepExistingBuildFile is not recursive for that directory).
+ //
+ // This is a bandaid until we the symlink forest logic can intelligently exclude BUILD files found in
+ // source symlink dirs according to the keepExistingBuildFile allowlist.
+ "prebuilts/clang/host/linux-x86/clang-dev",
+ )
+ return excluded
}
// Run Soong in the bp2build mode. This creates a standalone context that registers
// an alternate pipeline of mutators and singletons specifically for generating
// Bazel BUILD files instead of Ninja files.
-func runBp2Build(configuration android.Config, ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
+func runBp2Build(ctx *android.Context, extraNinjaDeps []string, metricsDir string) string {
var codegenMetrics *bp2build.CodegenMetrics
ctx.EventHandler.Do("bp2build", func() {
// Propagate "allow misssing dependencies" bit. This is normally set in
// newContext(), but we create ctx without calling that method.
- ctx.SetAllowMissingDependencies(configuration.AllowMissingDependencies())
- ctx.SetNameInterface(newNameResolver(configuration))
+ ctx.SetAllowMissingDependencies(ctx.Config().AllowMissingDependencies())
+ ctx.SetNameInterface(newNameResolver(ctx.Config()))
ctx.RegisterForBazelConversion()
ctx.SetModuleListFile(cmdlineArgs.ModuleListFile)
@@ -710,34 +576,35 @@
// from the regular Modules.
ctx.EventHandler.Do("bootstrap", func() {
blueprintArgs := cmdlineArgs
- bootstrapDeps := bootstrap.RunBlueprint(blueprintArgs, bootstrap.StopBeforePrepareBuildActions, ctx.Context, configuration)
+ bootstrapDeps := bootstrap.RunBlueprint(blueprintArgs.Args,
+ bootstrap.StopBeforePrepareBuildActions, ctx.Context, ctx.Config())
ninjaDeps = append(ninjaDeps, bootstrapDeps...)
})
- globListFiles := writeBuildGlobsNinjaFile(ctx, configuration.SoongOutDir(), configuration)
+ globListFiles := writeBuildGlobsNinjaFile(ctx)
ninjaDeps = append(ninjaDeps, globListFiles...)
// Run the code-generation phase to convert BazelTargetModules to BUILD files
// and print conversion codegenMetrics to the user.
- codegenContext := bp2build.NewCodegenContext(configuration, ctx, bp2build.Bp2Build)
+ codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build)
ctx.EventHandler.Do("codegen", func() {
codegenMetrics = bp2build.Codegen(codegenContext)
})
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
- writeDepFile(bp2buildMarker, ctx.EventHandler, ninjaDeps)
- touch(shared.JoinPath(topDir, bp2buildMarker))
+ writeDepFile(cmdlineArgs.Bp2buildMarker, ctx.EventHandler, ninjaDeps)
+ touch(shared.JoinPath(topDir, cmdlineArgs.Bp2buildMarker))
})
// Only report metrics when in bp2build mode. The metrics aren't relevant
// for queryview, since that's a total repo-wide conversion and there's a
// 1:1 mapping for each module.
- if configuration.IsEnvTrue("BP2BUILD_VERBOSE") {
+ if ctx.Config().IsEnvTrue("BP2BUILD_VERBOSE") {
codegenMetrics.Print()
}
writeBp2BuildMetrics(codegenMetrics, ctx.EventHandler, metricsDir)
- return bp2buildMarker
+ return cmdlineArgs.Bp2buildMarker
}
// Write Bp2Build metrics into $LOG_DIR
@@ -756,13 +623,22 @@
codegenMetrics.Write(metricsDir)
}
-func readBazelPaths(configuration android.Config) ([]string, error) {
- depsPath := configuration.Getenv("BAZEL_DEPS_FILE")
-
- data, err := os.ReadFile(depsPath)
- if err != nil {
- return nil, err
+func readFileLines(path string) ([]string, error) {
+ data, err := os.ReadFile(path)
+ if err == nil {
+ return strings.Split(strings.TrimSpace(string(data)), "\n"), nil
}
- paths := strings.Split(strings.TrimSpace(string(data)), "\n")
- return paths, nil
+ return nil, err
+
+}
+func maybeQuit(err error, format string, args ...interface{}) {
+ if err == nil {
+ return
+ }
+ if format != "" {
+ fmt.Fprintln(os.Stderr, fmt.Sprintf(format, args...)+": "+err.Error())
+ } else {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ os.Exit(1)
}
diff --git a/java/java.go b/java/java.go
index 9dd5850..dd24376 100644
--- a/java/java.go
+++ b/java/java.go
@@ -888,6 +888,10 @@
// a list of extra test configuration files that should be installed with the module.
Extra_test_configs []string `android:"path,arch_variant"`
+
+ // Extra <option> tags to add to the auto generated test xml file. The "key"
+ // is optional in each of these.
+ Tradefed_options []tradefed.Option
}
type testProperties struct {
@@ -1166,8 +1170,18 @@
j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest)
}
- j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
- j.testProperties.Test_suites, configs, j.testProperties.Auto_gen_config, j.testProperties.Test_options.Unit_test)
+ j.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(j.testProperties.Test_config).
+ SetTestTemplateConfigProp(j.testProperties.Test_config_template).
+ SetTestSuites(j.testProperties.Test_suites).
+ SetConfig(configs).
+ SetOptionsForAutogenerated(j.testProperties.Test_options.Tradefed_options).
+ SetAutoGenConfig(j.testProperties.Auto_gen_config).
+ SetUnitTest(j.testProperties.Test_options.Unit_test).
+ SetDeviceTemplate("${JavaTestConfigTemplate}").
+ SetHostTemplate("${JavaHostTestConfigTemplate}").
+ SetHostUnitTestTemplate("${JavaHostUnitTestConfigTemplate}").
+ Build()
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
@@ -1212,8 +1226,13 @@
}
func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
- j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.prebuiltTestProperties.Test_config, nil,
- j.prebuiltTestProperties.Test_suites, nil, nil, nil)
+ j.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(j.prebuiltTestProperties.Test_config).
+ SetTestSuites(j.prebuiltTestProperties.Test_suites).
+ SetDeviceTemplate("${JavaTestConfigTemplate}").
+ SetHostTemplate("${JavaHostTestConfigTemplate}").
+ SetHostUnitTestTemplate("${JavaHostUnitTestConfigTemplate}").
+ Build()
j.Import.GenerateAndroidBuildActions(ctx)
}
diff --git a/java/java_test.go b/java/java_test.go
index dff1fd0..62a372c 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -1945,3 +1945,25 @@
}
}
}
+
+func TestTradefedOptions(t *testing.T) {
+ result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, `
+java_test_host {
+ name: "foo",
+ test_options: {
+ tradefed_options: [
+ {
+ name: "exclude-path",
+ value: "org/apache"
+ }
+ ]
+ }
+}
+`)
+ args := result.ModuleForTests("foo", "linux_glibc_common").
+ Output("out/soong/.intermediates/foo/linux_glibc_common/foo.config").Args
+ expected := proptools.NinjaAndShellEscape("<option name=\"exclude-path\" value=\"org/apache\" />")
+ if args["extraConfigs"] != expected {
+ t.Errorf("Expected args[\"extraConfigs\"] to equal %q, was %q", expected, args["extraConfigs"])
+ }
+}
diff --git a/java/robolectric.go b/java/robolectric.go
index 6e8d591..63e05d8 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -131,9 +131,14 @@
r.forceOSType = ctx.Config().BuildOS
r.forceArchType = ctx.Config().BuildArch
- r.testConfig = tradefed.AutoGenRobolectricTestConfig(ctx, r.testProperties.Test_config,
- r.testProperties.Test_config_template, r.testProperties.Test_suites,
- r.testProperties.Auto_gen_config)
+ r.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(r.testProperties.Test_config).
+ SetTestTemplateConfigProp(r.testProperties.Test_config_template).
+ SetTestSuites(r.testProperties.Test_suites).
+ SetAutoGenConfig(r.testProperties.Auto_gen_config).
+ SetDeviceTemplate("${RobolectricTestConfigTemplate}").
+ SetHostTemplate("${RobolectricTestConfigTemplate}").
+ Build()
r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data)
roboTestConfig := android.PathForModuleGen(ctx, "robolectric").
diff --git a/python/test.go b/python/test.go
index b9b3465..5781df7 100644
--- a/python/test.go
+++ b/python/test.go
@@ -67,9 +67,14 @@
}
func (test *testDecorator) install(ctx android.ModuleContext, file android.Path) {
- test.testConfig = tradefed.AutoGenPythonBinaryHostTestConfig(ctx, test.testProperties.Test_config,
- test.testProperties.Test_config_template, test.binaryDecorator.binaryProperties.Test_suites,
- test.binaryDecorator.binaryProperties.Auto_gen_config)
+ test.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(test.testProperties.Test_config).
+ SetTestTemplateConfigProp(test.testProperties.Test_config_template).
+ SetTestSuites(test.binaryDecorator.binaryProperties.Test_suites).
+ SetAutoGenConfig(test.binaryDecorator.binaryProperties.Auto_gen_config).
+ SetDeviceTemplate("${PythonBinaryHostTestConfigTemplate}").
+ SetHostTemplate("${PythonBinaryHostTestConfigTemplate}").
+ Build()
test.binaryDecorator.pythonInstaller.dir = "nativetest"
test.binaryDecorator.pythonInstaller.dir64 = "nativetest64"
diff --git a/rust/benchmark.go b/rust/benchmark.go
index 0e84243..b417a2d 100644
--- a/rust/benchmark.go
+++ b/rust/benchmark.go
@@ -112,12 +112,14 @@
}
func (benchmark *benchmarkDecorator) install(ctx ModuleContext) {
- benchmark.testConfig = tradefed.AutoGenRustBenchmarkConfig(ctx,
- benchmark.Properties.Test_config,
- benchmark.Properties.Test_config_template,
- benchmark.Properties.Test_suites,
- nil,
- benchmark.Properties.Auto_gen_config)
+ benchmark.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(benchmark.Properties.Test_config).
+ SetTestTemplateConfigProp(benchmark.Properties.Test_config_template).
+ SetTestSuites(benchmark.Properties.Test_suites).
+ SetAutoGenConfig(benchmark.Properties.Auto_gen_config).
+ SetDeviceTemplate("${RustDeviceBenchmarkConfigTemplate}").
+ SetHostTemplate("${RustHostBenchmarkConfigTemplate}").
+ Build()
// default relative install path is module name
if !Bool(benchmark.Properties.No_named_install_directory) {
diff --git a/rust/test.go b/rust/test.go
index 0cc3bca..ecc7d5d 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -130,13 +130,16 @@
configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
}
- test.testConfig = tradefed.AutoGenRustTestConfig(ctx,
- test.Properties.Test_config,
- test.Properties.Test_config_template,
- test.Properties.Test_suites,
- configs,
- test.Properties.Auto_gen_config,
- testInstallBase)
+ test.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(test.Properties.Test_config).
+ SetTestTemplateConfigProp(test.Properties.Test_config_template).
+ SetTestSuites(test.Properties.Test_suites).
+ SetConfig(configs).
+ SetAutoGenConfig(test.Properties.Auto_gen_config).
+ SetTestInstallBase(testInstallBase).
+ SetDeviceTemplate("${RustDeviceTestConfigTemplate}").
+ SetHostTemplate("${RustHostTestConfigTemplate}").
+ Build()
dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data)
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 9627329..4eae397 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -379,8 +379,16 @@
}
configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.PushFilePreparer", options})
}
- s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config,
- s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base())
+ s.testConfig = tradefed.NewMaybeAutoGenTestConfigBuilder(ctx).
+ SetTestConfigProp(s.testProperties.Test_config).
+ SetTestTemplateConfigProp(s.testProperties.Test_config_template).
+ SetTestSuites(s.testProperties.Test_suites).
+ SetConfig(configs).
+ SetAutoGenConfig(s.testProperties.Auto_gen_config).
+ SetOutputFileName(s.outputFilePath.Base()).
+ SetDeviceTemplate("${ShellTestConfigTemplate}").
+ SetHostTemplate("${ShellTestConfigTemplate}").
+ Build()
s.dataModules = make(map[string]android.Path)
ctx.VisitDirectDeps(func(dep android.Module) {
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index f0336a3..a161108 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -11,6 +11,7 @@
],
srcs: [
"autogen.go",
+ "autogen_bazel.go",
"config.go",
"makevars.go",
],
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index c2429ab..236e559 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -107,15 +107,134 @@
}
-func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config, testInstallBase string) {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "", testInstallBase)
+// MaybeAutoGenTestConfigBuilder provides a Build() method that will either
+// generate a AndroidTest.xml file, or use an existing user-supplied one.
+// It used to be a bunch of separate functions for each language, but was
+// converted to this builder pattern to have one function that accepts many
+// optional arguments.
+type MaybeAutoGenTestConfigBuilder struct {
+ ctx android.ModuleContext
+ name string
+ outputFileName string
+ testConfigProp *string
+ testConfigTemplateProp *string
+ testSuites []string
+ config []Config
+ configsForAutogenerated []Config
+ autoGenConfig *bool
+ unitTest *bool
+ testInstallBase string
+ deviceTemplate string
+ hostTemplate string
+ hostUnitTestTemplate string
}
-func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, testInstallBase string) {
- autogenTemplateWithNameAndOutputFile(ctx, name, output, template, configs, "", testInstallBase)
+func NewMaybeAutoGenTestConfigBuilder(ctx android.ModuleContext) *MaybeAutoGenTestConfigBuilder {
+ return &MaybeAutoGenTestConfigBuilder{
+ ctx: ctx,
+ name: ctx.ModuleName(),
+ }
}
-func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
+func (b *MaybeAutoGenTestConfigBuilder) SetName(name string) *MaybeAutoGenTestConfigBuilder {
+ b.name = name
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetOutputFileName(outputFileName string) *MaybeAutoGenTestConfigBuilder {
+ b.outputFileName = outputFileName
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetTestConfigProp(testConfigProp *string) *MaybeAutoGenTestConfigBuilder {
+ b.testConfigProp = testConfigProp
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetTestTemplateConfigProp(testConfigTemplateProp *string) *MaybeAutoGenTestConfigBuilder {
+ b.testConfigTemplateProp = testConfigTemplateProp
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetTestSuites(testSuites []string) *MaybeAutoGenTestConfigBuilder {
+ b.testSuites = testSuites
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetConfig(config []Config) *MaybeAutoGenTestConfigBuilder {
+ b.config = config
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetOptionsForAutogenerated(configsForAutogenerated []Option) *MaybeAutoGenTestConfigBuilder {
+ configs := make([]Config, 0, len(configsForAutogenerated))
+ for _, c := range configsForAutogenerated {
+ configs = append(configs, c)
+ }
+ b.configsForAutogenerated = configs
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetUnitTest(unitTest *bool) *MaybeAutoGenTestConfigBuilder {
+ b.unitTest = unitTest
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetAutoGenConfig(autoGenConfig *bool) *MaybeAutoGenTestConfigBuilder {
+ b.autoGenConfig = autoGenConfig
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetTestInstallBase(testInstallBase string) *MaybeAutoGenTestConfigBuilder {
+ b.testInstallBase = testInstallBase
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetDeviceTemplate(deviceTemplate string) *MaybeAutoGenTestConfigBuilder {
+ b.deviceTemplate = deviceTemplate
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetHostTemplate(hostTemplate string) *MaybeAutoGenTestConfigBuilder {
+ b.hostTemplate = hostTemplate
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) SetHostUnitTestTemplate(hostUnitTestTemplate string) *MaybeAutoGenTestConfigBuilder {
+ b.hostUnitTestTemplate = hostUnitTestTemplate
+ return b
+}
+
+func (b *MaybeAutoGenTestConfigBuilder) Build() android.Path {
+ config := append(b.config, b.configsForAutogenerated...)
+ path, autogenPath := testConfigPath(b.ctx, b.testConfigProp, b.testSuites, b.autoGenConfig, b.testConfigTemplateProp)
+ if autogenPath != nil {
+ templatePath := getTestConfigTemplate(b.ctx, b.testConfigTemplateProp)
+ if templatePath.Valid() {
+ autogenTemplate(b.ctx, b.name, autogenPath, templatePath.String(), config, b.outputFileName, b.testInstallBase)
+ } else {
+ if b.ctx.Device() {
+ autogenTemplate(b.ctx, b.name, autogenPath, b.deviceTemplate, config, b.outputFileName, b.testInstallBase)
+ } else {
+ if Bool(b.unitTest) {
+ autogenTemplate(b.ctx, b.name, autogenPath, b.hostUnitTestTemplate, config, b.outputFileName, b.testInstallBase)
+ } else {
+ autogenTemplate(b.ctx, b.name, autogenPath, b.hostTemplate, config, b.outputFileName, b.testInstallBase)
+ }
+ }
+ }
+ return autogenPath
+ }
+ if len(b.configsForAutogenerated) > 0 {
+ b.ctx.ModuleErrorf("Extra tradefed configurations were provided for an autogenerated xml file, but the autogenerated xml file was not used.")
+ }
+ return path
+}
+
+func autogenTemplate(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string, testInstallBase string) {
+ if template == "" {
+ ctx.ModuleErrorf("Empty template")
+ }
var configStrings []string
for _, config := range configs {
configStrings = append(configStrings, config.Config())
@@ -137,148 +256,6 @@
})
}
-func AutoGenNativeTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path {
-
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase)
- } else {
- if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${NativeTestConfigTemplate}", config, testInstallBase)
- } else {
- autogenTemplate(ctx, autogenPath, "${NativeHostTestConfigTemplate}", config, testInstallBase)
- }
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenShellTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, outputFileName string) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName, "")
- } else {
- autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName, "")
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), configs, "")
- } else {
- autogenTemplate(ctx, autogenPath, "${NativeBenchmarkTestConfigTemplate}", configs, "")
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenJavaTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
- testSuites []string, config []Config, autoGenConfig *bool, unitTest *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
- } else {
- if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${JavaTestConfigTemplate}", config, "")
- } else {
- if Bool(unitTest) {
- autogenTemplate(ctx, autogenPath, "${JavaHostUnitTestConfigTemplate}", config, "")
- } else {
- autogenTemplate(ctx, autogenPath, "${JavaHostTestConfigTemplate}", config, "")
- }
- }
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenPythonBinaryHostTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
-
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
- } else {
- autogenTemplate(ctx, autogenPath, "${PythonBinaryHostTestConfigTemplate}", nil, "")
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, testInstallBase string) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), config, testInstallBase)
- } else {
- if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config, testInstallBase)
- } else {
- autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config, testInstallBase)
- }
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenRustBenchmarkConfig(ctx android.ModuleContext, testConfigProp *string,
- testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), config, "")
- } else {
- if ctx.Device() {
- autogenTemplate(ctx, autogenPath, "${RustDeviceBenchmarkConfigTemplate}", config, "")
- } else {
- autogenTemplate(ctx, autogenPath, "${RustHostBenchmarkConfigTemplate}", config, "")
- }
- }
- return autogenPath
- }
- return path
-}
-
-func AutoGenRobolectricTestConfig(ctx android.ModuleContext, testConfigProp *string, testConfigTemplateProp *string,
- testSuites []string, autoGenConfig *bool) android.Path {
- path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
- if autogenPath != nil {
- templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
- if templatePath.Valid() {
- autogenTemplate(ctx, autogenPath, templatePath.String(), nil, "")
- } else {
- autogenTemplate(ctx, autogenPath, "${RobolectricTestConfigTemplate}", nil, "")
- }
- return autogenPath
- }
- return path
-}
-
var autogenInstrumentationTest = pctx.StaticRule("autogenInstrumentationTest", blueprint.RuleParams{
Command: "${AutoGenTestConfigScript} $out $in ${EmptyTestConfig} $template ${extraConfigs}",
CommandDeps: []string{
diff --git a/tradefed/autogen_bazel.go b/tradefed/autogen_bazel.go
new file mode 100644
index 0000000..d3109d9
--- /dev/null
+++ b/tradefed/autogen_bazel.go
@@ -0,0 +1,105 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package tradefed
+
+import (
+ "android/soong/android"
+ "android/soong/bazel"
+
+ "github.com/google/blueprint/proptools"
+)
+
+const (
+ InstrumentationTestConfigTemplate = "build/make/core/instrumentation_test_config_template.xml"
+ JavaTestConfigTemplate = "build/make/core/java_test_config_template.xml"
+ JavaHostTestConfigTemplate = "build/make/core/java_host_test_config_template.xml"
+ JavaHostUnitTestConfigTemplate = "build/make/core/java_host_unit_test_config_template.xml"
+ NativeBenchmarkTestConfigTemplate = "build/make/core/native_benchmark_test_config_template.xml"
+ NativeHostTestConfigTemplate = "build/make/core/native_host_test_config_template.xml"
+ NativeTestConfigTemplate = "build/make/core/native_test_config_template.xml"
+ PythonBinaryHostTestConfigTemplate = "build/make/core/python_binary_host_test_config_template.xml"
+ RustDeviceTestConfigTemplate = "build/make/core/rust_device_test_config_template.xml"
+ RustHostTestConfigTemplate = "build/make/core/rust_host_test_config_template.xml"
+ RustDeviceBenchmarkConfigTemplate = "build/make/core/rust_device_benchmark_config_template.xml"
+ RustHostBenchmarkConfigTemplate = "build/make/core/rust_host_benchmark_config_template.xml"
+ RobolectricTestConfigTemplate = "build/make/core/robolectric_test_config_template.xml"
+ ShellTestConfigTemplate = "build/make/core/shell_test_config_template.xml"
+)
+
+type TestConfigAttributes struct {
+ Test_config *bazel.Label
+
+ Auto_generate_test_config *bool
+ Template_test_config *bazel.Label
+ Template_configs []string
+ Template_install_base *string
+}
+
+func GetTestConfigAttributes(
+ ctx android.TopDownMutatorContext,
+ testConfig *string,
+ extraTestConfigs []string,
+ autoGenConfig *bool,
+ testSuites []string,
+ template *string,
+ templateConfigs []Config,
+ templateInstallBase *string) TestConfigAttributes {
+
+ attrs := TestConfigAttributes{}
+ attrs.Test_config = GetTestConfig(ctx, testConfig)
+ // do not generate a test config if
+ // 1) test config already found
+ // 2) autoGenConfig == false
+ // 3) CTS tests and no template specified.
+ // CTS Modules can be used for test data, so test config files must be explicitly specified.
+ if (attrs.Template_test_config != nil) ||
+ proptools.Bool(autoGenConfig) == false ||
+ (template == nil && !android.InList("cts", testSuites)) {
+
+ return attrs
+ }
+
+ // Add properties for the bazel rule to generate a test config
+ // since a test config was not specified.
+ templateLabel := android.BazelLabelForModuleSrcSingle(ctx, *template)
+ attrs.Template_test_config = &templateLabel
+ attrs.Auto_generate_test_config = autoGenConfig
+ var configStrings []string
+ for _, c := range templateConfigs {
+ configString := proptools.NinjaAndShellEscape(c.Config())
+ configStrings = append(configStrings, configString)
+ }
+ attrs.Template_configs = configStrings
+ attrs.Template_install_base = templateInstallBase
+ return attrs
+}
+
+func GetTestConfig(
+ ctx android.TopDownMutatorContext,
+ testConfig *string,
+) *bazel.Label {
+
+ if testConfig != nil {
+ c, _ := android.BazelStringOrLabelFromProp(ctx, testConfig)
+ if c.Value != nil {
+ return c.Value
+ }
+ }
+
+ // check for default AndroidTest.xml
+ defaultTestConfigPath := ctx.ModuleDir() + "/AndroidTest.xml"
+ c, _ := android.BazelStringOrLabelFromProp(ctx, &defaultTestConfigPath)
+ return c.Value
+}