Merge changes I8ca452aa,I437fc890,If9446700 into main
* changes:
Handle .proto files in different package for filegroups
Handle .proto files that end up in a different package
Allow creation of BazelTargets in a different directory
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 69bcd2e..6bfa05d 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -121,6 +121,7 @@
"development/sdk": Bp2BuildDefaultTrueRecursively,
"external/aac": Bp2BuildDefaultTrueRecursively,
+ "external/abseil-cpp": Bp2BuildDefaultTrueRecursively,
"external/arm-optimized-routines": Bp2BuildDefaultTrueRecursively,
"external/auto": Bp2BuildDefaultTrue,
"external/auto/android-annotation-stubs": Bp2BuildDefaultTrueRecursively,
@@ -189,7 +190,11 @@
"external/ow2-asm": Bp2BuildDefaultTrueRecursively,
"external/pcre": Bp2BuildDefaultTrueRecursively,
"external/protobuf": Bp2BuildDefaultTrueRecursively,
+ "external/python/pyyaml/lib/yaml": Bp2BuildDefaultTrueRecursively,
"external/python/six": Bp2BuildDefaultTrueRecursively,
+ "external/python/jinja/src": Bp2BuildDefaultTrueRecursively,
+ "external/python/markupsafe/src": Bp2BuildDefaultTrueRecursively,
+ "external/python/setuptools": Bp2BuildDefaultTrueRecursively,
"external/rappor": Bp2BuildDefaultTrueRecursively,
"external/scudo": Bp2BuildDefaultTrueRecursively,
"external/selinux/checkpolicy": Bp2BuildDefaultTrueRecursively,
@@ -434,6 +439,7 @@
"external/bazelbuild-rules_java":/* recursive = */ true,
"external/bazelbuild-rules_license":/* recursive = */ true,
"external/bazelbuild-rules_go":/* recursive = */ true,
+ "external/bazelbuild-rules_python":/* recursive = */ true,
"external/bazelbuild-kotlin-rules":/* recursive = */ true,
"external/bazel-skylib":/* recursive = */ true,
"external/protobuf":/* recursive = */ false,
@@ -813,6 +819,8 @@
"chre_flatbuffers",
"event_logger",
"hal_unit_tests",
+
+ "merge_annotation_zips_test",
}
Bp2buildModuleTypeAlwaysConvertList = []string{
@@ -836,6 +844,10 @@
// the "prebuilt_" prefix to the name, so that it's differentiable from
// the source versions within Soong's module graph.
Bp2buildModuleDoNotConvertList = []string{
+ // TODO(b/263326760): Failed already.
+ "minijail_compiler_unittest",
+ "minijail_parser_unittest",
+
// Depends on unconverted libandroid, libgui
"dvr_buffer_queue-test",
"dvr_display-test",
@@ -1516,73 +1528,6 @@
"libartd-runtime-gtest",
}
- MixedBuildsDisabledList = []string{
- "libruy_static", "libtflite_kernel_utils", // TODO(b/237315968); Depend on prebuilt stl, not from source
-
- "art_libdexfile_dex_instruction_list_header", // breaks libart_mterp.armng, header not found
-
- "libbrotli", // http://b/198585397, ld.lld: error: bionic/libc/arch-arm64/generic/bionic/memmove.S:95:(.text+0x10): relocation R_AARCH64_CONDBR19 out of range: -1404176 is not in [-1048576, 1048575]; references __memcpy
- "minijail_constants_json", // http://b/200899432, bazel-built cc_genrule does not work in mixed build when it is a dependency of another soong module.
-
- "cap_names.h", // TODO(b/204913827) runfiles need to be handled in mixed builds
- "libcap", // TODO(b/204913827) runfiles need to be handled in mixed builds
- "libprotobuf-cpp-full", "libprotobuf-cpp-lite", // Unsupported product&vendor suffix. b/204811222 and b/204810610.
-
- // Depends on libprotobuf-cpp-*
- "libadb_pairing_connection",
- "libadb_pairing_connection_static",
- "libadb_pairing_server", "libadb_pairing_server_static",
-
- // java_import[_host] issues
- // tradefed prebuilts depend on libprotobuf
- "prebuilt_tradefed",
- "prebuilt_tradefed-test-framework",
- // handcrafted BUILD.bazel files in //prebuilts/...
- "prebuilt_r8lib-prebuilt",
- "prebuilt_sdk-core-lambda-stubs",
- "prebuilt_android-support-collections-nodeps",
- "prebuilt_android-arch-core-common-nodeps",
- "prebuilt_android-arch-lifecycle-common-java8-nodeps",
- "prebuilt_android-arch-lifecycle-common-nodeps",
- "prebuilt_android-support-annotations-nodeps",
- "prebuilt_android-arch-paging-common-nodeps",
- "prebuilt_android-arch-room-common-nodeps",
- // TODO(b/217750501) exclude_dirs property not supported
- "prebuilt_kotlin-reflect",
- "prebuilt_kotlin-stdlib",
- "prebuilt_kotlin-stdlib-jdk7",
- "prebuilt_kotlin-stdlib-jdk8",
- "prebuilt_kotlin-test",
- // TODO(b/217750501) exclude_files property not supported
- "prebuilt_currysrc_org.eclipse",
-
- // TODO(b/266459895): re-enable libunwindstack
- "libunwindstack",
- "libunwindstack_stdout_log",
- "libunwindstack_no_dex",
- "libunwindstack_utils",
- "unwind_reg_info",
- "libunwindstack_local",
- "unwind_for_offline",
- "unwind",
- "unwind_info",
- "unwind_symbols",
- "libEGL",
- "libGLESv2",
- "libc_malloc_debug",
- "libcodec2_hidl@1.0",
- "libcodec2_hidl@1.1",
- "libcodec2_hidl@1.2",
- "libfdtrack",
- "libgui",
- "libgui_bufferqueue_static",
- "libmedia_codecserviceregistrant",
- "libstagefright_bufferqueue_helper_novndk",
- "libutils_test",
- "libutilscallstack",
- "mediaswcodec",
- }
-
// Bazel prod-mode allowlist. Modules in this list are built by Bazel
// in either prod mode or staging mode.
ProdMixedBuildsEnabledList = []string{
@@ -1643,4 +1588,14 @@
"art_": DEFAULT_PRIORITIZED_WEIGHT,
"ndk_library": DEFAULT_PRIORITIZED_WEIGHT,
}
+
+ BazelSandwichTargets = []struct {
+ Label string
+ Host bool
+ }{
+ {
+ Label: "//build/bazel/examples/partitions:system_image",
+ Host: false,
+ },
+ }
)
diff --git a/android/bazel.go b/android/bazel.go
index 0d2c777..df30ff2 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -22,6 +22,7 @@
"android/soong/ui/metrics/bp2build_metrics_proto"
"github.com/google/blueprint"
+ "github.com/google/blueprint/bootstrap"
"github.com/google/blueprint/proptools"
"android/soong/android/allowlists"
@@ -426,8 +427,23 @@
return ModuleIncompatibility
}
+func isGoModule(module blueprint.Module) bool {
+ if _, ok := module.(*bootstrap.GoPackage); ok {
+ return true
+ }
+ if _, ok := module.(*bootstrap.GoBinary); ok {
+ return true
+ }
+ return false
+}
+
// ConvertedToBazel returns whether this module has been converted (with bp2build or manually) to Bazel.
func convertedToBazel(ctx BazelConversionContext, module blueprint.Module) bool {
+ // Special-case bootstrap_go_package and bootstrap_go_binary
+ // These do not implement Bazelable, but have been converted
+ if isGoModule(module) {
+ return true
+ }
b, ok := module.(Bazelable)
if !ok {
return false
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 94bc88b..fda8a22 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -22,6 +22,7 @@
"os"
"path"
"path/filepath"
+ "regexp"
"runtime"
"sort"
"strings"
@@ -186,6 +187,8 @@
// Returns the depsets defined in Bazel's aquery response.
AqueryDepsets() []bazel.AqueryDepset
+
+ QueueBazelSandwichCqueryRequests(config Config) error
}
type bazelRunner interface {
@@ -264,6 +267,10 @@
m.BazelRequests[key] = true
}
+func (m MockBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (m MockBazelContext) GetOutputFiles(label string, _ configKey) ([]string, error) {
result, ok := m.LabelToOutputFiles[label]
if !ok {
@@ -424,6 +431,10 @@
panic("unimplemented")
}
+func (n noopBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ panic("unimplemented")
+}
+
func (n noopBazelContext) GetOutputFiles(_ string, _ configKey) ([]string, error) {
panic("unimplemented")
}
@@ -1042,6 +1053,64 @@
allBazelCommands = []bazelCommand{aqueryCmd, cqueryCmd, buildCmd}
)
+func GetBazelSandwichCqueryRequests(config Config) ([]cqueryKey, error) {
+ result := make([]cqueryKey, 0, len(allowlists.BazelSandwichTargets))
+ labelRegex := regexp.MustCompile("^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$")
+ // Note that bazel "targets" are different from soong "targets", the bazel targets are
+ // synonymous with soong modules, and soong targets are a configuration a module is built in.
+ for _, target := range allowlists.BazelSandwichTargets {
+ match := labelRegex.FindStringSubmatch(target.Label)
+ if match == nil {
+ return nil, fmt.Errorf("invalid label, must match `^@?//([a-zA-Z0-9/_-]+):[a-zA-Z0-9_-]+$`: %s", target.Label)
+ }
+ if _, err := os.Stat(absolutePath(match[1])); err != nil {
+ if os.IsNotExist(err) {
+ // Ignore bazel sandwich targets that don't exist.
+ continue
+ } else {
+ return nil, err
+ }
+ }
+
+ var soongTarget Target
+ if target.Host {
+ soongTarget = config.BuildOSTarget
+ } else {
+ soongTarget = config.AndroidCommonTarget
+ if soongTarget.Os.Class != Device {
+ // kernel-build-tools seems to set the AndroidCommonTarget to a linux host
+ // target for some reason, disable device builds in that case.
+ continue
+ }
+ }
+
+ result = append(result, cqueryKey{
+ label: target.Label,
+ requestType: cquery.GetOutputFiles,
+ configKey: configKey{
+ arch: soongTarget.Arch.String(),
+ osType: soongTarget.Os,
+ },
+ })
+ }
+ return result, nil
+}
+
+// QueueBazelSandwichCqueryRequests queues cquery requests for all the bazel labels in
+// bazel_sandwich_targets. These will later be given phony targets so that they can be built on the
+// command line.
+func (context *mixedBuildBazelContext) QueueBazelSandwichCqueryRequests(config Config) error {
+ requests, err := GetBazelSandwichCqueryRequests(config)
+ if err != nil {
+ return err
+ }
+ for _, request := range requests {
+ context.QueueBazelRequest(request.label, request.requestType, request.configKey)
+ }
+
+ return nil
+}
+
// Issues commands to Bazel to receive results for all cquery requests
// queued in the BazelContext.
func (context *mixedBuildBazelContext) InvokeBazel(config Config, ctx invokeBazelContext) error {
@@ -1255,6 +1324,11 @@
executionRoot := path.Join(ctx.Config().BazelContext.OutputBase(), "execroot", "__main__")
bazelOutDir := path.Join(executionRoot, "bazel-out")
+ rel, err := filepath.Rel(ctx.Config().OutDir(), executionRoot)
+ if err != nil {
+ ctx.Errorf("%s", err.Error())
+ }
+ dotdotsToOutRoot := strings.Repeat("../", strings.Count(rel, "/")+1)
for index, buildStatement := range ctx.Config().BazelContext.BuildStatementsToRegister() {
// nil build statements are a valid case where we do not create an action because it is
// unnecessary or handled by other processing
@@ -1286,7 +1360,8 @@
})
}
}
- createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset)
+ createCommand(rule.Command(), buildStatement, executionRoot, bazelOutDir, ctx, depsetHashToDepset, dotdotsToOutRoot)
+
desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
rule.Build(fmt.Sprintf("bazel %d", index), desc)
continue
@@ -1331,6 +1406,24 @@
panic(fmt.Sprintf("unhandled build statement: %v", buildStatement))
}
}
+
+ // Create phony targets for all the bazel sandwich output files
+ requests, err := GetBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ for _, request := range requests {
+ files, err := ctx.Config().BazelContext.GetOutputFiles(request.label, request.configKey)
+ if err != nil {
+ ctx.Errorf(err.Error())
+ }
+ filesAsPaths := make([]Path, 0, len(files))
+ for _, file := range files {
+ filesAsPaths = append(filesAsPaths, PathForBazelOut(ctx, file))
+ }
+ ctx.Phony("bazel_sandwich", filesAsPaths...)
+ }
+ ctx.Phony("checkbuild", PathForPhony(ctx, "bazel_sandwich"))
}
// Returns a out dir path for a sandboxed mixed build action
@@ -1344,7 +1437,7 @@
}
// Register bazel-owned build statements (obtained from the aquery invocation).
-func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset) {
+func createCommand(cmd *RuleBuilderCommand, buildStatement *bazel.BuildStatement, executionRoot string, bazelOutDir string, ctx BuilderContext, depsetHashToDepset map[string]bazel.AqueryDepset, dotdotsToOutRoot string) {
// executionRoot is the action cwd.
if buildStatement.ShouldRunInSbox {
// mkdir -p ensures that the directory exists when run via sbox
@@ -1367,14 +1460,17 @@
cmd.Flag(pair.Key + "=" + pair.Value)
}
+ command := buildStatement.Command
+ command = strings.ReplaceAll(command, "{DOTDOTS_TO_OUTPUT_ROOT}", dotdotsToOutRoot)
+
// The actual Bazel action.
- if len(buildStatement.Command) > 16*1024 {
+ if len(command) > 16*1024 {
commandFile := PathForBazelOut(ctx, buildStatement.OutputPaths[0]+".sh")
- WriteFileRule(ctx, commandFile, buildStatement.Command)
+ WriteFileRule(ctx, commandFile, command)
cmd.Text("bash").Text(buildStatement.OutputPaths[0] + ".sh").Implicit(commandFile)
} else {
- cmd.Text(buildStatement.Command)
+ cmd.Text(command)
}
for _, outputPath := range buildStatement.OutputPaths {
@@ -1403,6 +1499,9 @@
cmd.Implicit(PathForPhony(ctx, otherDepsetName))
}
}
+ for _, implicitPath := range buildStatement.ImplicitDeps {
+ cmd.Implicit(PathForArbitraryOutput(ctx, implicitPath))
+ }
if depfile := buildStatement.Depfile; depfile != nil {
// The paths in depfile are relative to `executionRoot`.
diff --git a/android/bazel_handler_test.go b/android/bazel_handler_test.go
index e08a471..9a3c8fc 100644
--- a/android/bazel_handler_test.go
+++ b/android/bazel_handler_test.go
@@ -181,7 +181,7 @@
cmd := RuleBuilderCommand{}
ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
- createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+ createCommand(&cmd, got[0], "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
if actual, expected := cmd.buf.String(), testCase.command; expected != actual {
t.Errorf("expected: [%s], actual: [%s]", expected, actual)
}
@@ -224,7 +224,7 @@
cmd := RuleBuilderCommand{}
ctx := builderContextForTests{PathContextForTesting(TestConfig("out", nil, "", nil))}
- createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{})
+ createCommand(&cmd, statement, "test/exec_root", "test/bazel_out", ctx, map[string]bazel.AqueryDepset{}, "")
// Assert that the output is generated in an intermediate directory
// fe05bcdcdc4928012781a5f1a2a77cbb5398e106 is the sha1 checksum of "one"
if actual, expected := cmd.outputs[0].String(), "out/soong/mixed_build_sbox_intermediates/fe05bcdcdc4928012781a5f1a2a77cbb5398e106/test/exec_root/one"; expected != actual {
diff --git a/android/bazel_paths.go b/android/bazel_paths.go
index 7568543..b08a4ca 100644
--- a/android/bazel_paths.go
+++ b/android/bazel_paths.go
@@ -431,7 +431,7 @@
func BazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
- if !convertedToBazel(ctx, module) {
+ if !convertedToBazel(ctx, module) || isGoModule(module) {
return bp2buildModuleLabel(ctx, module)
}
b, _ := module.(Bazelable)
diff --git a/android/config.go b/android/config.go
index 72ff224..eb89493 100644
--- a/android/config.go
+++ b/android/config.go
@@ -414,6 +414,12 @@
return nil
}
+type productVariableStarlarkRepresentation struct {
+ soongType string
+ selectable bool
+ archVariant bool
+}
+
func saveToBazelConfigFile(config *ProductVariables, outDir string) error {
dir := filepath.Join(outDir, bazel.SoongInjectionDirName, "product_config")
err := createDirIfNonexistent(dir, os.ModePerm)
@@ -421,32 +427,43 @@
return fmt.Errorf("Could not create dir %s: %s", dir, err)
}
- nonArchVariantProductVariables := []string{}
- archVariantProductVariables := []string{}
+ allProductVariablesType := reflect.TypeOf((*ProductVariables)(nil)).Elem()
+ productVariablesInfo := make(map[string]productVariableStarlarkRepresentation)
p := variableProperties{}
t := reflect.TypeOf(p.Product_variables)
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
- nonArchVariantProductVariables = append(nonArchVariantProductVariables, strings.ToLower(f.Name))
- if proptools.HasTag(f, "android", "arch_variant") {
- archVariantProductVariables = append(archVariantProductVariables, strings.ToLower(f.Name))
+ if f.Name == "Pdk" {
+ // Pdk is deprecated and has no effect as of aosp/1319667
+ continue
+ }
+ archVariant := proptools.HasTag(f, "android", "arch_variant")
+ if mainProductVariablesStructField, ok := allProductVariablesType.FieldByName(f.Name); ok {
+ productVariablesInfo[f.Name] = productVariableStarlarkRepresentation{
+ soongType: stringRepresentationOfSimpleType(mainProductVariablesStructField.Type),
+ selectable: true,
+ archVariant: archVariant,
+ }
+ } else {
+ panic("Unknown variable " + f.Name)
}
}
- nonArchVariantProductVariablesJson := starlark_fmt.PrintStringList(nonArchVariantProductVariables, 0)
- if err != nil {
- return fmt.Errorf("cannot marshal product variable data: %s", err.Error())
- }
-
- archVariantProductVariablesJson := starlark_fmt.PrintStringList(archVariantProductVariables, 0)
- if err != nil {
- return fmt.Errorf("cannot marshal arch variant product variable data: %s", err.Error())
- }
-
err = pathtools.WriteFileIfChanged(filepath.Join(dir, "product_variable_constants.bzl"), []byte(fmt.Sprintf(`
-product_var_constraints = %s
-arch_variant_product_var_constraints = %s
-`, nonArchVariantProductVariablesJson, archVariantProductVariablesJson)), 0644)
+# product_var_constant_info is a map of product variables to information about them. The fields are:
+# - soongType: The type of the product variable as it appears in soong's ProductVariables struct.
+# examples are string, bool, int, *bool, *string, []string, etc. This may be an overly
+# conservative estimation of the type, for example a *bool could oftentimes just be a
+# bool that defaults to false.
+# - selectable: if this product variable can be selected on in Android.bp/build files. This means
+# it's listed in the "variableProperties" soong struct. Currently all variables in
+# this list are selectable because we only need the selectable ones at the moment,
+# but the list may be expanded later.
+# - archVariant: If the variable is tagged as arch variant in the "variableProperties" struct.
+product_var_constant_info = %s
+product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable]
+arch_variant_product_var_constraints = [k for k, v in product_var_constant_info.items() if v.selectable and v.archVariant]
+`, starlark_fmt.PrintAny(productVariablesInfo, 0))), 0644)
if err != nil {
return fmt.Errorf("Could not write .bzl config file %s", err)
}
@@ -459,6 +476,23 @@
return nil
}
+func stringRepresentationOfSimpleType(ty reflect.Type) string {
+ switch ty.Kind() {
+ case reflect.String:
+ return "string"
+ case reflect.Bool:
+ return "bool"
+ case reflect.Int:
+ return "int"
+ case reflect.Slice:
+ return "[]" + stringRepresentationOfSimpleType(ty.Elem())
+ case reflect.Pointer:
+ return "*" + stringRepresentationOfSimpleType(ty.Elem())
+ default:
+ panic("unimplemented type: " + ty.Kind().String())
+ }
+}
+
// NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that
// use the android package.
func NullConfig(outDir, soongOutDir string) Config {
diff --git a/android/module.go b/android/module.go
index 5fecd83..0120a54 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1378,15 +1378,15 @@
}
}
- productConfigEnabledLabels := []bazel.Label{}
+ productConfigEnabledAttribute := bazel.LabelListAttribute{}
// TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we
// should handle it correctly
if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice {
// If the module is not enabled by default, then we can check if a
// product variable enables it
- productConfigEnabledLabels = productVariableConfigEnableLabels(ctx)
+ productConfigEnabledAttribute = productVariableConfigEnableAttribute(ctx)
- if len(productConfigEnabledLabels) > 0 {
+ if len(productConfigEnabledAttribute.ConfigurableValues) > 0 {
// In this case, an existing product variable configuration overrides any
// module-level `enable: false` definition
newValue := true
@@ -1394,10 +1394,6 @@
}
}
- productConfigEnabledAttribute := bazel.MakeLabelListAttribute(bazel.LabelList{
- productConfigEnabledLabels, nil,
- })
-
platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute(
bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil},
bazel.LabelList{[]bazel.Label{}, nil})
@@ -1428,31 +1424,28 @@
// Check product variables for `enabled: true` flag override.
// Returns a list of the constraint_value targets who enable this override.
-func productVariableConfigEnableLabels(ctx *topDownMutatorContext) []bazel.Label {
+func productVariableConfigEnableAttribute(ctx *topDownMutatorContext) bazel.LabelListAttribute {
+ result := bazel.LabelListAttribute{}
productVariableProps := ProductVariableProperties(ctx, ctx.Module())
- productConfigEnablingTargets := []bazel.Label{}
- const propName = "Enabled"
- if productConfigProps, exists := productVariableProps[propName]; exists {
+ if productConfigProps, exists := productVariableProps["Enabled"]; exists {
for productConfigProp, prop := range productConfigProps {
flag, ok := prop.(*bool)
if !ok {
- ctx.ModuleErrorf("Could not convert product variable %s property", proptools.PropertyNameForField(propName))
+ ctx.ModuleErrorf("Could not convert product variable enabled property")
}
if *flag {
axis := productConfigProp.ConfigurationAxis()
- targetLabel := axis.SelectKey(productConfigProp.SelectKey())
- productConfigEnablingTargets = append(productConfigEnablingTargets, bazel.Label{
- Label: targetLabel,
- })
+ result.SetSelectValue(axis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{{Label: "@platforms//:incompatible"}}))
+ result.SetSelectValue(axis, productConfigProp.SelectKey(), bazel.LabelList{Includes: []bazel.Label{}})
} else {
// TODO(b/210546943): handle negative case where `enabled: false`
- ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943", proptools.PropertyNameForField(propName))
+ ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943")
}
}
}
- return productConfigEnablingTargets
+ return result
}
// A ModuleBase object contains the properties that are common to all Android
diff --git a/android/paths.go b/android/paths.go
index e16cb37..325a953 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -1029,16 +1029,16 @@
return p
}
+func (p basePath) RelativeToTop() Path {
+ ensureTestOnly()
+ return p
+}
+
// SourcePath is a Path representing a file path rooted from SrcDir
type SourcePath struct {
basePath
}
-func (p SourcePath) RelativeToTop() Path {
- ensureTestOnly()
- return p
-}
-
var _ Path = SourcePath{}
func (p SourcePath) withRel(rel string) SourcePath {
@@ -1126,6 +1126,16 @@
return path
}
+// PathForArbitraryOutput creates a path for the given components. Unlike PathForOutput,
+// the path is relative to the root of the output folder, not the out/soong folder.
+func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) Path {
+ p, err := validatePath(pathComponents...)
+ if err != nil {
+ reportPathError(ctx, err)
+ }
+ return basePath{path: filepath.Join(ctx.Config().OutDir(), p)}
+}
+
// MaybeExistentPathForSource joins the provided path components and validates that the result
// neither escapes the source dir nor is in the out dir.
// It does not validate whether the path exists.
diff --git a/android/prebuilt_build_tool.go b/android/prebuilt_build_tool.go
index e5edf91..aeae20f 100644
--- a/android/prebuilt_build_tool.go
+++ b/android/prebuilt_build_tool.go
@@ -102,6 +102,10 @@
// prebuilt_build_tool is to declare prebuilts to be used during the build, particularly for use
// in genrules with the "tools" property.
func prebuiltBuildToolFactory() Module {
+ return NewPrebuiltBuildTool()
+}
+
+func NewPrebuiltBuildTool() Module {
module := &prebuiltBuildTool{}
module.AddProperties(&module.properties)
InitSingleSourcePrebuiltModule(module, &module.properties, "Src")
diff --git a/android/variable.go b/android/variable.go
index 7fb81b9..03a80c1 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -160,6 +160,7 @@
}
}
+ // Deprecated, has no effect as of aosp/1319667
Pdk struct {
Enabled *bool `android:"arch_variant"`
} `android:"arch_variant"`
diff --git a/bazel/aquery.go b/bazel/aquery.go
index 2c080a1..d77d59a 100644
--- a/bazel/aquery.go
+++ b/bazel/aquery.go
@@ -17,15 +17,15 @@
import (
"crypto/sha256"
"encoding/base64"
+ "encoding/json"
"fmt"
"path/filepath"
+ analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
"reflect"
"sort"
"strings"
"sync"
- analysis_v2_proto "prebuilts/bazel/common/proto/analysis_v2"
-
"github.com/google/blueprint/metrics"
"github.com/google/blueprint/proptools"
"google.golang.org/protobuf/proto"
@@ -119,6 +119,10 @@
// If ShouldRunInSbox is true, Soong will use sbox to created an isolated environment
// and run the mixed build action there
ShouldRunInSbox bool
+ // A list of files to add as implicit deps to the outputs of this BuildStatement.
+ // Unlike most properties in BuildStatement, these paths must be relative to the root of
+ // the whole out/ folder, instead of relative to ctx.Config().BazelContext.OutputBase()
+ ImplicitDeps []string
}
// A helper type for aquery processing which facilitates retrieval of path IDs from their
@@ -581,6 +585,72 @@
}, nil
}
+type bazelSandwichJson struct {
+ Target string `json:"target"`
+ DependOnTarget *bool `json:"depend_on_target,omitempty"`
+ ImplicitDeps []string `json:"implicit_deps"`
+}
+
+func (a *aqueryArtifactHandler) unresolvedSymlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
+ outputPaths, depfile, err := a.getOutputPaths(actionEntry)
+ if err != nil {
+ return nil, err
+ }
+ if len(actionEntry.InputDepSetIds) != 0 || len(outputPaths) != 1 {
+ return nil, fmt.Errorf("expected 0 inputs and 1 output to symlink action, got: input %q, output %q", actionEntry.InputDepSetIds, outputPaths)
+ }
+ target := actionEntry.UnresolvedSymlinkTarget
+ if target == "" {
+ return nil, fmt.Errorf("expected an unresolved_symlink_target, but didn't get one")
+ }
+ if filepath.Clean(target) != target {
+ return nil, fmt.Errorf("expected %q, got %q", filepath.Clean(target), target)
+ }
+ if strings.HasPrefix(target, "/") {
+ return nil, fmt.Errorf("no absolute symlinks allowed: %s", target)
+ }
+
+ out := outputPaths[0]
+ outDir := filepath.Dir(out)
+ var implicitDeps []string
+ if strings.HasPrefix(target, "bazel_sandwich:") {
+ j := bazelSandwichJson{}
+ err := json.Unmarshal([]byte(target[len("bazel_sandwich:"):]), &j)
+ if err != nil {
+ return nil, err
+ }
+ if proptools.BoolDefault(j.DependOnTarget, true) {
+ implicitDeps = append(implicitDeps, j.Target)
+ }
+ implicitDeps = append(implicitDeps, j.ImplicitDeps...)
+ dotDotsToReachCwd := ""
+ if outDir != "." {
+ dotDotsToReachCwd = strings.Repeat("../", strings.Count(outDir, "/")+1)
+ }
+ target = proptools.ShellEscapeIncludingSpaces(j.Target)
+ target = "{DOTDOTS_TO_OUTPUT_ROOT}" + dotDotsToReachCwd + target
+ } else {
+ target = proptools.ShellEscapeIncludingSpaces(target)
+ }
+
+ outDir = proptools.ShellEscapeIncludingSpaces(outDir)
+ out = proptools.ShellEscapeIncludingSpaces(out)
+ // Use absolute paths, because some soong actions don't play well with relative paths (for example, `cp -d`).
+ command := fmt.Sprintf("mkdir -p %[1]s && rm -f %[2]s && ln -sf %[3]s %[2]s", outDir, out, target)
+ symlinkPaths := outputPaths[:]
+
+ buildStatement := &BuildStatement{
+ Command: command,
+ Depfile: depfile,
+ OutputPaths: outputPaths,
+ Env: actionEntry.EnvironmentVariables,
+ Mnemonic: actionEntry.Mnemonic,
+ SymlinkPaths: symlinkPaths,
+ ImplicitDeps: implicitDeps,
+ }
+ return buildStatement, nil
+}
+
func (a *aqueryArtifactHandler) symlinkActionBuildStatement(actionEntry *analysis_v2_proto.Action) (*BuildStatement, error) {
outputPaths, depfile, err := a.getOutputPaths(actionEntry)
if err != nil {
@@ -690,6 +760,8 @@
return a.fileWriteActionBuildStatement(actionEntry)
case "SymlinkTree":
return a.symlinkTreeActionBuildStatement(actionEntry)
+ case "UnresolvedSymlink":
+ return a.unresolvedSymlinkActionBuildStatement(actionEntry)
}
if len(actionEntry.Arguments) < 1 {
diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go
index 19a584f..32c87a0 100644
--- a/bazel/aquery_test.go
+++ b/bazel/aquery_test.go
@@ -357,9 +357,11 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 1; len(actual) != expected {
t.Fatalf("Expected %d build statements, got %d", expected, len(actual))
+ return
}
bs := actual[0]
@@ -544,6 +546,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -756,9 +759,11 @@
actualBuildStatements, actualDepsets, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
if expected := 2; len(actualBuildStatements) != expected {
t.Fatalf("Expected %d build statements, got %d %#v", expected, len(actualBuildStatements), actualBuildStatements)
+ return
}
expectedDepsetFiles := [][]string{
@@ -859,6 +864,7 @@
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -907,6 +913,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1017,6 +1024,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
expectedBuildStatements := []*BuildStatement{
@@ -1088,6 +1096,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1126,6 +1135,7 @@
actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
if err != nil {
t.Errorf("Unexpected error %q", err)
+ return
}
assertBuildStatements(t, []*BuildStatement{
&BuildStatement{
@@ -1136,6 +1146,126 @@
}, actual)
}
+func TestUnresolvedSymlink(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "symlink/target"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf symlink/target path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwich(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ ImplicitDeps: []string{"target/product/emulator_x86_64/system"},
+ }}, actual)
+}
+
+func TestUnresolvedSymlinkBazelSandwichWithAlternativeDeps(t *testing.T) {
+ const inputString = `
+{
+ "artifacts": [
+ { "id": 1, "path_fragment_id": 1 }
+ ],
+ "actions": [{
+ "target_id": 1,
+ "action_key": "x",
+ "mnemonic": "UnresolvedSymlink",
+ "configuration_id": 1,
+ "output_ids": [1],
+ "primary_output_id": 1,
+ "execution_platform": "//build/bazel/platforms:linux_x86_64",
+ "unresolved_symlink_target": "bazel_sandwich:{\"depend_on_target\":false,\"implicit_deps\":[\"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp\"],\"target\":\"target/product/emulator_x86_64/system\"}"
+ }],
+ "path_fragments": [
+ { "id": 1, "label": "path/to/symlink" }
+ ]
+}
+`
+ data, err := JsonToActionGraphContainer(inputString)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ actual, _, err := AqueryBuildStatements(data, &metrics.EventHandler{})
+ if err != nil {
+ t.Errorf("Unexpected error %q", err)
+ return
+ }
+ assertBuildStatements(t, []*BuildStatement{{
+ Command: "mkdir -p path/to && rm -f path/to/symlink && ln -sf {DOTDOTS_TO_OUTPUT_ROOT}../../target/product/emulator_x86_64/system path/to/symlink",
+ OutputPaths: []string{"path/to/symlink"},
+ Mnemonic: "UnresolvedSymlink",
+ SymlinkPaths: []string{"path/to/symlink"},
+ // Note that the target of the symlink, target/product/emulator_x86_64/system, is not listed here
+ ImplicitDeps: []string{"target/product/emulator_x86_64/obj/PACKAGING/systemimage_intermediates/staging_dir.stamp"},
+ }}, actual)
+}
+
func assertError(t *testing.T, err error, expected string) {
t.Helper()
if err == nil {
@@ -1201,6 +1331,9 @@
if !reflect.DeepEqual(sortedStrings(first.SymlinkPaths), sortedStrings(second.SymlinkPaths)) {
return "SymlinkPaths"
}
+ if !reflect.DeepEqual(sortedStrings(first.ImplicitDeps), sortedStrings(second.ImplicitDeps)) {
+ return "ImplicitDeps"
+ }
if first.Depfile != second.Depfile {
return "Depfile"
}
diff --git a/bazel/configurability.go b/bazel/configurability.go
index d962a1d..671e5c1 100644
--- a/bazel/configurability.go
+++ b/bazel/configurability.go
@@ -67,7 +67,7 @@
ConditionsDefaultSelectKey = "//conditions:default"
- productVariableBazelPackage = "//build/bazel/product_variables"
+ productVariableBazelPackage = "//build/bazel/product_config/config_settings"
AndroidAndInApex = "android-in_apex"
AndroidPlatform = "system"
diff --git a/bp2build/apex_conversion_test.go b/bp2build/apex_conversion_test.go
index 84c7ea2..2383247 100644
--- a/bp2build/apex_conversion_test.go
+++ b/bp2build/apex_conversion_test.go
@@ -1555,7 +1555,7 @@
"file_contexts": `":foo-file_contexts"`,
"manifest": `"apex_manifest.json"`,
"min_sdk_version": `select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
"//conditions:default": "31",
})`,
"package_name": `"pkg_name"`,
@@ -1564,7 +1564,7 @@
"file_contexts": `":foo-file_contexts"`,
"manifest": `"apex_manifest.json"`,
"min_sdk_version": `select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "30",
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "30",
"//conditions:default": "31",
})`,
"package_name": `"override_pkg_name"`,
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index cfe52db..5f7b382 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -15,7 +15,6 @@
package bp2build
import (
- "android/soong/starlark_import"
"fmt"
"os"
"path/filepath"
@@ -24,6 +23,7 @@
"android/soong/android"
"android/soong/bazel"
"android/soong/shared"
+ "android/soong/starlark_import"
)
func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
@@ -67,6 +67,8 @@
// writing .bzl files that are equivalent to Android.bp files that are capable
// of being built with Bazel.
func Codegen(ctx *CodegenContext) *CodegenMetrics {
+ ctx.Context().BeginEvent("Codegen")
+ defer ctx.Context().EndEvent("Codegen")
// This directory stores BUILD files that could be eventually checked-in.
bp2buildDir := android.PathForOutput(ctx, "bp2build")
@@ -79,7 +81,10 @@
fmt.Printf("ERROR: Encountered %d error(s): \nERROR: %s", len(errs), strings.Join(errMsgs, "\n"))
os.Exit(1)
}
- bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
+ var bp2buildFiles []BazelFile
+ ctx.Context().EventHandler.Do("CreateBazelFile", func() {
+ bp2buildFiles = CreateBazelFiles(nil, res.buildFileToTargets, ctx.mode)
+ })
injectionFiles, additionalBp2buildFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
if err != nil {
fmt.Printf("%s\n", err.Error())
@@ -111,7 +116,7 @@
func CreateSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
var ret []BazelFile
- productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx)
+ productConfigInjectionFiles, productConfigBp2BuildDirFiles, err := CreateProductConfigFiles(ctx, metrics)
if err != nil {
return nil, nil, err
}
diff --git a/bp2build/bp2build_product_config.go b/bp2build/bp2build_product_config.go
index f56e6d8..12a9b15 100644
--- a/bp2build/bp2build_product_config.go
+++ b/bp2build/bp2build_product_config.go
@@ -2,6 +2,7 @@
import (
"android/soong/android"
+ "android/soong/android/soongconfig"
"android/soong/starlark_import"
"encoding/json"
"fmt"
@@ -15,7 +16,8 @@
)
func CreateProductConfigFiles(
- ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
+ ctx *CodegenContext,
+ metrics CodegenMetrics) ([]BazelFile, []BazelFile, error) {
cfg := &ctx.config
targetProduct := "unknown"
if cfg.HasDeviceProduct() {
@@ -51,11 +53,24 @@
"{VARIANT}", targetBuildVariant,
"{PRODUCT_FOLDER}", currentProductFolder)
- platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables)
+ platformMappingContent, err := platformMappingContent(
+ productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"),
+ &productVariables,
+ ctx.Config().Bp2buildSoongConfigDefinitions,
+ metrics.convertedModulePathMap)
if err != nil {
return nil, nil, err
}
+ productsForTestingMap, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
+ if err != nil {
+ return nil, nil, err
+ }
+ productsForTesting := android.SortedKeys(productsForTestingMap)
+ for i := range productsForTesting {
+ productsForTesting[i] = fmt.Sprintf(" \"@//build/bazel/tests/products:%s\",", productsForTesting[i])
+ }
+
injectionDirFiles := []BazelFile{
newFile(
currentProductFolder,
@@ -97,6 +112,7 @@
android_product(
name = "mixed_builds_product-{VARIANT}",
soong_variables = _soong_variables,
+ extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
)
`)),
newFile(
@@ -109,9 +125,8 @@
# currently lunched product, they should all be listed here
product_labels = [
"@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
- "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
-]
-`)),
+ "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}",
+`)+strings.Join(productsForTesting, "\n")+"\n]\n"),
newFile(
"product_config_platforms",
"common.bazelrc",
@@ -120,6 +135,7 @@
build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
+build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86
build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
@@ -147,20 +163,37 @@
return injectionDirFiles, bp2buildDirFiles, nil
}
-func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables) (string, error) {
+func platformMappingContent(
+ mainProductLabel string,
+ mainProductVariables *android.ProductVariables,
+ soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+ convertedModulePathMap map[string]string) (string, error) {
productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
if err != nil {
return "", err
}
var result strings.Builder
+
+ mergedConvertedModulePathMap := make(map[string]string)
+ for k, v := range convertedModulePathMap {
+ mergedConvertedModulePathMap[k] = v
+ }
+ additionalModuleNamesToPackages, err := starlark_import.GetStarlarkValue[map[string]string]("additional_module_names_to_packages")
+ if err != nil {
+ return "", err
+ }
+ for k, v := range additionalModuleNamesToPackages {
+ mergedConvertedModulePathMap[k] = v
+ }
+
result.WriteString("platforms:\n")
- platformMappingSingleProduct(mainProductLabel, mainProductVariables, &result)
+ platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
for product, productVariablesStarlark := range productsForTesting {
productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
if err != nil {
return "", err
}
- platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, &result)
+ platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, mergedConvertedModulePathMap, &result)
}
return result.String(), nil
}
@@ -179,7 +212,12 @@
"_windows_x86_64",
}
-func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, result *strings.Builder) {
+func platformMappingSingleProduct(
+ label string,
+ productVariables *android.ProductVariables,
+ soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions,
+ convertedModulePathMap map[string]string,
+ result *strings.Builder) {
targetBuildVariant := "user"
if proptools.Bool(productVariables.Eng) {
targetBuildVariant = "eng"
@@ -187,33 +225,98 @@
targetBuildVariant = "userdebug"
}
+ platform_sdk_version := -1
+ if productVariables.Platform_sdk_version != nil {
+ platform_sdk_version = *productVariables.Platform_sdk_version
+ }
+
+ defaultAppCertificateFilegroup := "//build/bazel/utils:empty_filegroup"
+ if proptools.String(productVariables.DefaultAppCertificate) != "" {
+ defaultAppCertificateFilegroup = "@//" + filepath.Dir(proptools.String(productVariables.DefaultAppCertificate)) + ":android_certificate_directory"
+ }
+
for _, suffix := range bazelPlatformSuffixes {
result.WriteString(" ")
result.WriteString(label)
result.WriteString(suffix)
result.WriteString("\n")
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
- result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate_filegroup=%s\n", defaultAppCertificateFilegroup))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.Device_page_size_agnostic)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_sdk_version=%d\n", platform_sdk_version))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:treble_linker_namespaces=%t\n", proptools.Bool(productVariables.Treble_linker_namespaces)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
+
+ for _, override := range productVariables.CertificateOverrides {
+ parts := strings.SplitN(override, ":", 2)
+ if apexPath, ok := convertedModulePathMap[parts[0]]; ok {
+ if overrideCertPath, ok := convertedModulePathMap[parts[1]]; ok {
+ result.WriteString(fmt.Sprintf(" --%s:%s_certificate_override=%s:%s\n", apexPath, parts[0], overrideCertPath, parts[1]))
+ }
+ }
+ }
+
+ for namespace, namespaceContents := range productVariables.VendorVars {
+ for variable, value := range namespaceContents {
+ key := namespace + "__" + variable
+ _, hasBool := soongConfigDefinitions.BoolVars[key]
+ _, hasString := soongConfigDefinitions.StringVars[key]
+ _, hasValue := soongConfigDefinitions.ValueVars[key]
+ if !hasBool && !hasString && !hasValue {
+ // Not all soong config variables are defined in Android.bp files. For example,
+ // prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard
+ // way, that causes them to be present in the soong.variables file but not
+ // defined in an Android.bp file. There's also nothing stopping you from setting
+ // a variable in make that doesn't exist in soong. We only generate build
+ // settings for the ones that exist in soong, so skip all others.
+ continue
+ }
+ if hasBool && hasString || hasBool && hasValue || hasString && hasValue {
+ panic(fmt.Sprintf("Soong config variable %s:%s appears to be of multiple types. bool? %t, string? %t, value? %t", namespace, variable, hasBool, hasString, hasValue))
+ }
+ if hasBool {
+ // Logic copied from soongConfig.Bool()
+ value = strings.ToLower(value)
+ if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" {
+ value = "true"
+ } else {
+ value = "false"
+ }
+ }
+ result.WriteString(fmt.Sprintf(" --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value))
+ }
+ }
}
}
@@ -224,12 +327,20 @@
field := productVarsReflect.Field(i)
fieldType := productVarsReflect.Type().Field(i)
name := fieldType.Name
- if name == "BootJars" || name == "ApexBootJars" || name == "VendorVars" ||
- name == "VendorSnapshotModules" || name == "RecoverySnapshotModules" {
+ if name == "BootJars" || name == "ApexBootJars" || name == "VendorSnapshotModules" ||
+ name == "RecoverySnapshotModules" {
// These variables have more complicated types, and we don't need them right now
continue
}
if _, ok := in[name]; ok {
+ if name == "VendorVars" {
+ vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name])
+ if err != nil {
+ return result, err
+ }
+ field.Set(reflect.ValueOf(vendorVars))
+ continue
+ }
switch field.Type().Kind() {
case reflect.Bool:
val, err := starlark_import.Unmarshal[bool](in[name])
@@ -281,5 +392,9 @@
}
}
+ result.Native_coverage = proptools.BoolPtr(
+ proptools.Bool(result.GcovCoverage) ||
+ proptools.Bool(result.ClangCoverage))
+
return result, nil
}
diff --git a/bp2build/bp2build_product_config_test.go b/bp2build/bp2build_product_config_test.go
index 3dd53ce..02d83b4 100644
--- a/bp2build/bp2build_product_config_test.go
+++ b/bp2build/bp2build_product_config_test.go
@@ -69,6 +69,7 @@
t.Error(err)
continue
}
+ testCase.result.Native_coverage = proptools.BoolPtr(false)
if !reflect.DeepEqual(testCase.result, productVariables) {
expected, err := json.Marshal(testCase.result)
if err != nil {
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 3de5213..6f41f37 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -653,6 +653,8 @@
}
func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (conversionResults, []error) {
+ ctx.Context().BeginEvent("GenerateBazelTargets")
+ defer ctx.Context().EndEvent("GenerateBazelTargets")
buildFileToTargets := make(map[string]BazelTargets)
// Simple metrics tracking for bp2build
@@ -744,10 +746,12 @@
targets, targetErrs = generateBazelTargetsGoPackage(bpCtx, glib, nameToGoLibMap)
errs = append(errs, targetErrs...)
metrics.IncrementRuleClassCount("go_library")
+ metrics.AddConvertedModule(glib, "go_library", dir)
} else if gbin, ok := m.(*bootstrap.GoBinary); ok {
targets, targetErrs = generateBazelTargetsGoBinary(bpCtx, gbin, nameToGoLibMap)
errs = append(errs, targetErrs...)
metrics.IncrementRuleClassCount("go_binary")
+ metrics.AddConvertedModule(gbin, "go_binary", dir)
} else {
metrics.AddUnconvertedModule(m, moduleType, dir, android.UnconvertedReason{
ReasonType: int(bp2build_metrics_proto.UnconvertedReasonType_TYPE_UNSUPPORTED),
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index c646336..8ee0439 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -640,7 +640,10 @@
}`,
ExpectedBazelTargets: []string{
MakeBazelTargetNoRestrictions("custom", "foo", AttrNameToString{
- "target_compatible_with": `["//build/bazel/product_variables:unbundled_build"]`,
+ "target_compatible_with": `select({
+ "//build/bazel/product_config/config_settings:unbundled_build": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ })`,
}),
},
},
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index 2f51ca7..402d4b0 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -202,7 +202,7 @@
content: "irrelevant",
},
}
- files := CreateBazelFiles(android.NullConfig("out", "out/soong"), ruleShims, make(map[string]BazelTargets), QueryView)
+ files := CreateBazelFiles(ruleShims, make(map[string]BazelTargets), QueryView)
var actualSoongModuleBzl BazelFile
for _, f := range files {
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index cac604b..e425b36 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -1260,14 +1260,14 @@
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte": [],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": [],
"//conditions:default": [":malloc_not_svelte_static_lib_excludes_bp2build_cc_library_static"],
})`,
"implementation_dynamic_deps": `select({
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_shared_lib_excludes"],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_shared_lib"],
"//conditions:default": [],
})`,
"srcs_c": `["common.c"]`,
@@ -1275,7 +1275,7 @@
"//build/bazel/platforms/arch:arm": [],
"//conditions:default": [":arm_whole_static_lib_excludes_bp2build_cc_library_static"],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_whole_static_lib_bp2build_cc_library_static"],
"//conditions:default": [":malloc_not_svelte_whole_static_lib_excludes_bp2build_cc_library_static"],
})`,
}),
@@ -1307,7 +1307,7 @@
`,
ExpectedBazelTargets: makeCcLibraryTargets("foo_static", AttrNameToString{
"implementation_deps": `select({
- "//build/bazel/product_variables:malloc_not_svelte": [":malloc_not_svelte_header_lib"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": [":malloc_not_svelte_header_lib"],
"//conditions:default": [],
})`,
"srcs_c": `["common.c"]`,
@@ -4643,7 +4643,7 @@
"-Wextra",
"-DDEBUG_ONLY_CODE=0",
] + select({
- "//build/bazel/product_variables:eng": [
+ "//build/bazel/product_config/config_settings:eng": [
"-UDEBUG_ONLY_CODE",
"-DDEBUG_ONLY_CODE=1",
],
diff --git a/bp2build/cc_library_static_conversion_test.go b/bp2build/cc_library_static_conversion_test.go
index 03e9cd0..26baf89 100644
--- a/bp2build/cc_library_static_conversion_test.go
+++ b/bp2build/cc_library_static_conversion_test.go
@@ -1188,13 +1188,13 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"copts": `select({
- "//build/bazel/product_variables:binder32bit": ["-Wbinder32bit"],
+ "//build/bazel/product_config/config_settings:binder32bit": ["-Wbinder32bit"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_zero_contents": ["-Wmalloc_zero_contents"],
+ "//build/bazel/product_config/config_settings:malloc_zero_contents": ["-Wmalloc_zero_contents"],
"//conditions:default": [],
})`,
"srcs_c": `["common.c"]`,
@@ -1248,19 +1248,19 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"copts": `select({
- "//build/bazel/product_variables:malloc_not_svelte": ["-Wmalloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte": ["-Wmalloc_not_svelte"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte-android": ["-Wandroid_malloc_not_svelte"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte-arm": ["-Wlib32_malloc_not_svelte"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte-arm64": ["-Warm64_malloc_not_svelte"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
+ "//build/bazel/product_config/config_settings:malloc_not_svelte-x86": ["-Wlib32_malloc_not_svelte"],
"//conditions:default": [],
})`,
"srcs_c": `["common.c"]`,
@@ -1287,7 +1287,7 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_library_static", "foo_static", AttrNameToString{
"asflags": `select({
- "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+ "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
})`,
"srcs_as": `["common.S"]`,
@@ -2247,3 +2247,38 @@
]`,
})}})
}
+
+func TestCcLibraryWithProtoInGeneratedSrcs(t *testing.T) {
+ runCcLibraryStaticTestCase(t, Bp2buildTestCase{
+ Description: "cc_library with a .proto file generated from a genrule",
+ ModuleTypeUnderTest: "cc_library_static",
+ ModuleTypeUnderTestFactory: cc.LibraryStaticFactory,
+ Blueprint: soongCcLibraryPreamble + `
+cc_library_static {
+ name: "mylib",
+ generated_sources: ["myprotogen"],
+}
+genrule {
+ name: "myprotogen",
+ out: ["myproto.proto"],
+}
+` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+ ExpectedBazelTargets: []string{
+ MakeBazelTarget("cc_library_static", "mylib", AttrNameToString{
+ "local_includes": `["."]`,
+ "deps": `[":libprotobuf-cpp-lite"]`,
+ "implementation_whole_archive_deps": `[":mylib_cc_proto_lite"]`,
+ }),
+ MakeBazelTarget("cc_lite_proto_library", "mylib_cc_proto_lite", AttrNameToString{
+ "deps": `[":mylib_proto"]`,
+ }),
+ MakeBazelTarget("proto_library", "mylib_proto", AttrNameToString{
+ "srcs": `[":myprotogen"]`,
+ }),
+ MakeBazelTargetNoRestrictions("genrule", "myprotogen", AttrNameToString{
+ "cmd": `""`,
+ "outs": `["myproto.proto"]`,
+ }),
+ },
+ })
+}
diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
index eab84e1..ecfcb5a 100644
--- a/bp2build/cc_object_conversion_test.go
+++ b/bp2build/cc_object_conversion_test.go
@@ -200,7 +200,7 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("cc_object", "foo", AttrNameToString{
"asflags": `select({
- "//build/bazel/product_variables:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
+ "//build/bazel/product_config/config_settings:platform_sdk_version": ["-DPLATFORM_SDK_VERSION=$(Platform_sdk_version)"],
"//conditions:default": [],
})`,
"copts": `["-fno-addrsig"]`,
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index d5f2386..f280924 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -1,7 +1,6 @@
package bp2build
import (
- "android/soong/starlark_fmt"
"encoding/json"
"fmt"
"reflect"
@@ -9,11 +8,11 @@
"strings"
"android/soong/android"
+ "android/soong/apex"
"android/soong/cc"
cc_config "android/soong/cc/config"
java_config "android/soong/java/config"
-
- "android/soong/apex"
+ "android/soong/starlark_fmt"
"github.com/google/blueprint/proptools"
)
@@ -105,12 +104,7 @@
`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
}
-func CreateBazelFiles(
- cfg android.Config,
- ruleShims map[string]RuleShim,
- buildToTargets map[string]BazelTargets,
- mode CodegenMode) []BazelFile {
-
+func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
var files []BazelFile
if mode == QueryView {
diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go
index 00ffd79..15284ce 100644
--- a/bp2build/conversion_test.go
+++ b/bp2build/conversion_test.go
@@ -27,8 +27,7 @@
}
func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) {
- files := CreateBazelFiles(android.NullConfig("out", "out/soong"),
- map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
+ files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView)
expectedFilePaths := []bazelFilepath{
{
dir: "",
diff --git a/bp2build/prebuilt_etc_conversion_test.go b/bp2build/prebuilt_etc_conversion_test.go
index aa0a5b7..5b2d609 100644
--- a/bp2build/prebuilt_etc_conversion_test.go
+++ b/bp2build/prebuilt_etc_conversion_test.go
@@ -149,7 +149,7 @@
MakeBazelTarget("prebuilt_file", "apex_tz_version", AttrNameToString{
"filename": `"tz_version"`,
"src": `select({
- "//build/bazel/product_variables:native_coverage": "src1",
+ "//build/bazel/product_config/config_settings:native_coverage": "src1",
"//conditions:default": "version/tz_version",
})`,
"dir": `"etc"`,
@@ -318,7 +318,7 @@
"dir": `"etc"`,
"src": `select({
"//build/bazel/platforms/arch:arm": "armSrc",
- "//build/bazel/product_variables:native_coverage-arm": "nativeCoverageArmSrc",
+ "//build/bazel/product_config/config_settings:native_coverage-arm": "nativeCoverageArmSrc",
"//conditions:default": None,
})`,
})}})
diff --git a/bp2build/soong_config_module_type_conversion_test.go b/bp2build/soong_config_module_type_conversion_test.go
index 143597d..1ff47f2 100644
--- a/bp2build/soong_config_module_type_conversion_test.go
+++ b/bp2build/soong_config_module_type_conversion_test.go
@@ -91,7 +91,7 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+ "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}),
local_includes = ["."],
@@ -140,7 +140,7 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+ "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}),
local_includes = ["."],
@@ -191,9 +191,9 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
- "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
- "//build/bazel/product_variables:acme__board__soc_c": [],
+ "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
"//conditions:default": ["-DSOC_DEFAULT"],
}),
local_includes = ["."],
@@ -240,7 +240,7 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+ "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}),
local_includes = ["."],
@@ -310,15 +310,15 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
- "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
- "//build/bazel/product_variables:acme__board__soc_c": [],
+ "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
"//conditions:default": ["-DSOC_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:acme__feature1": ["-DFEATURE1"],
+ "//build/bazel/product_config/config_settings:acme__feature1": ["-DFEATURE1"],
"//conditions:default": ["-DDEFAULT1"],
}) + select({
- "//build/bazel/product_variables:acme__feature2": ["-DFEATURE2"],
+ "//build/bazel/product_config/config_settings:acme__feature2": ["-DFEATURE2"],
"//conditions:default": ["-DDEFAULT2"],
}),
local_includes = ["."],
@@ -380,15 +380,15 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "foo",
copts = select({
- "//build/bazel/product_variables:acme__board__soc_a": ["-DSOC_A"],
- "//build/bazel/product_variables:acme__board__soc_b": ["-DSOC_B"],
- "//build/bazel/product_variables:acme__board__soc_c": [],
+ "//build/bazel/product_config/config_settings:acme__board__soc_a": ["-DSOC_A"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_b": ["-DSOC_B"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
"//conditions:default": ["-DSOC_DEFAULT"],
}),
implementation_deps = select({
- "//build/bazel/product_variables:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
- "//build/bazel/product_variables:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
- "//build/bazel/product_variables:acme__board__soc_c": [],
+ "//build/bazel/product_config/config_settings:acme__board__soc_a": ["//foo/bar:soc_a_dep"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_b": ["//foo/bar:soc_b_dep"],
+ "//build/bazel/product_config/config_settings:acme__board__soc_c": [],
"//conditions:default": ["//foo/bar:soc_default_static_dep"],
}),
local_includes = ["."],
@@ -446,7 +446,7 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
- "//build/bazel/product_variables:vendor_foo__feature": [
+ "//build/bazel/product_config/config_settings:vendor_foo__feature": [
"-cflag_feature_2",
"-cflag_feature_1",
],
@@ -527,11 +527,11 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
asflags = select({
- "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
+ "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
"//conditions:default": ["-asflag_default_bar"],
}),
copts = select({
- "//build/bazel/product_variables:acme__feature": [
+ "//build/bazel/product_config/config_settings:acme__feature": [
"-cflag_foo",
"-cflag_bar",
],
@@ -546,11 +546,11 @@
`cc_library_static(
name = "lib2",
asflags = select({
- "//build/bazel/product_variables:acme__feature": ["-asflag_bar"],
+ "//build/bazel/product_config/config_settings:acme__feature": ["-asflag_bar"],
"//conditions:default": ["-asflag_default_bar"],
}),
copts = select({
- "//build/bazel/product_variables:acme__feature": [
+ "//build/bazel/product_config/config_settings:acme__feature": [
"-cflag_bar",
"-cflag_foo",
],
@@ -643,13 +643,13 @@
ExpectedBazelTargets: []string{`cc_library_static(
name = "lib",
copts = select({
- "//build/bazel/product_variables:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
+ "//build/bazel/product_config/config_settings:vendor_bar__feature": ["-DVENDOR_BAR_FEATURE"],
"//conditions:default": ["-DVENDOR_BAR_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
+ "//build/bazel/product_config/config_settings:vendor_foo__feature": ["-DVENDOR_FOO_FEATURE"],
"//conditions:default": ["-DVENDOR_FOO_DEFAULT"],
}) + select({
- "//build/bazel/product_variables:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
+ "//build/bazel/product_config/config_settings:vendor_qux__feature": ["-DVENDOR_QUX_FEATURE"],
"//conditions:default": ["-DVENDOR_QUX_DEFAULT"],
}),
local_includes = ["."],
@@ -697,7 +697,7 @@
ExpectedBazelTargets: []string{
MakeBazelTarget("custom", "foo", AttrNameToString{
"string_literal_prop": `select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": "29",
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": "29",
"//conditions:default": "30",
})`,
}),
@@ -779,7 +779,7 @@
ExpectedBazelTargets: []string{`cc_binary(
name = "library_linking_strategy_sample_binary",
dynamic_deps = select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
"//conditions:default": [
"//foo/bar:lib_b",
"//foo/bar:lib_a",
@@ -868,7 +868,7 @@
ExpectedBazelTargets: []string{
MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary", AttrNameToString{
"dynamic_deps": `select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
"//conditions:default": [
"//foo/bar:lib_b",
"//foo/bar:lib_c",
@@ -877,7 +877,7 @@
}),
MakeBazelTargetNoRestrictions("cc_binary", "library_linking_strategy_sample_binary_with_excludes", AttrNameToString{
"dynamic_deps": `select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
"//conditions:default": ["//foo/bar:lib_b"],
})`,
}),
@@ -965,14 +965,14 @@
ExpectedBazelTargets: []string{`cc_binary(
name = "library_linking_strategy_sample_binary",
deps = select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
"//foo/bar:lib_b_bp2build_cc_library_static",
"//foo/bar:lib_a_bp2build_cc_library_static",
],
"//conditions:default": [],
}),
dynamic_deps = select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
"//conditions:default": [
"//foo/bar:lib_b",
"//foo/bar:lib_a",
@@ -1046,14 +1046,14 @@
ExpectedBazelTargets: []string{`cc_binary(
name = "library_linking_strategy_sample_binary",
deps = select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [
"//foo/bar:lib_a_bp2build_cc_library_static",
"//foo/bar:lib_b_bp2build_cc_library_static",
],
"//conditions:default": [],
}),
dynamic_deps = select({
- "//build/bazel/product_variables:android__library_linking_strategy__prefer_static": [],
+ "//build/bazel/product_config/config_settings:android__library_linking_strategy__prefer_static": [],
"//conditions:default": [
"//foo/bar:lib_a",
"//foo/bar:lib_b",
@@ -1134,13 +1134,13 @@
ExpectedBazelTargets: []string{`cc_binary(
name = "alphabet_binary",
deps = select({
- "//build/bazel/product_variables:android__alphabet__a": [],
- "//build/bazel/product_variables:android__alphabet__b": [],
+ "//build/bazel/product_config/config_settings:android__alphabet__a": [],
+ "//build/bazel/product_config/config_settings:android__alphabet__b": [],
"//conditions:default": ["//foo/bar:lib_default_bp2build_cc_library_static"],
}),
dynamic_deps = select({
- "//build/bazel/product_variables:android__alphabet__a": ["//foo/bar:lib_a"],
- "//build/bazel/product_variables:android__alphabet__b": ["//foo/bar:lib_b"],
+ "//build/bazel/product_config/config_settings:android__alphabet__a": ["//foo/bar:lib_a"],
+ "//build/bazel/product_config/config_settings:android__alphabet__b": ["//foo/bar:lib_b"],
"//conditions:default": [],
}),
local_includes = ["."],
@@ -1199,7 +1199,7 @@
name = "alphabet_binary",
local_includes = ["."],
srcs = ["main.cc"],
- target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"] + select({
+ target_compatible_with = select({
"//build/bazel/platforms/os_arch:android_x86_64": ["@platforms//:incompatible"],
"//build/bazel/platforms/os_arch:darwin_arm64": ["@platforms//:incompatible"],
"//build/bazel/platforms/os_arch:darwin_x86_64": ["@platforms//:incompatible"],
@@ -1208,6 +1208,9 @@
"//build/bazel/platforms/os_arch:linux_musl_x86_64": ["@platforms//:incompatible"],
"//build/bazel/platforms/os_arch:windows_x86_64": ["@platforms//:incompatible"],
"//conditions:default": [],
+ }) + select({
+ "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
+ "//conditions:default": ["@platforms//:incompatible"],
}),
)`}})
}
@@ -1252,7 +1255,10 @@
name = "alphabet_binary",
local_includes = ["."],
srcs = ["main.cc"],
- target_compatible_with = ["//build/bazel/product_variables:alphabet_module__special_build"],
+ target_compatible_with = select({
+ "//build/bazel/product_config/config_settings:alphabet_module__special_build": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
)`}})
}
@@ -1389,16 +1395,16 @@
"//build/bazel/platforms/os:android": ["-DFOO"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:my_namespace__my_bool_variable__android": ["-DBAR"],
- "//build/bazel/product_variables:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__android": ["-DBAR"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_bool_variable__conditions_default__android": ["-DBAZ"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1": ["-DVALUE1_NOT_ANDROID"],
"//conditions:default": [],
}) + select({
- "//build/bazel/product_variables:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
- "//build/bazel/product_variables:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
- "//build/bazel/product_variables:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__conditions_default__android": ["-DSTRING_VAR_CONDITIONS_DEFAULT"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value1__android": ["-DVALUE1"],
+ "//build/bazel/product_config/config_settings:my_namespace__my_string_variable__value2__android": ["-DVALUE2"],
"//conditions:default": [],
}),
local_includes = ["."],
diff --git a/cc/Android.bp b/cc/Android.bp
index e88ea03..c32d854 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -37,6 +37,7 @@
"linkable.go",
"lto.go",
"makevars.go",
+ "orderfile.go",
"pgo.go",
"prebuilt.go",
"proto.go",
@@ -104,6 +105,7 @@
"lto_test.go",
"ndk_test.go",
"object_test.go",
+ "orderfile_test.go",
"prebuilt_test.go",
"proto_test.go",
"sanitize_test.go",
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 9e485d6..9d90a5b 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -48,6 +48,8 @@
genrulePartition = "genrule"
+ protoFromGenPartition = "proto_gen"
+
hdrPartition = "hdr"
stubsSuffix = "_stub_libs_current"
@@ -126,6 +128,41 @@
}
}
+// Returns an unchanged label and a bool indicating whether the dep is a genrule that produces .proto files
+func protoFromGenPartitionMapper(pathCtx android.BazelConversionContext) bazel.LabelMapper {
+ return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) {
+ mod, exists := ctx.ModuleFromName(label.OriginalModuleName)
+ if !exists {
+ return label.Label, false
+ }
+ gen, isGen := mod.(*genrule.Module)
+ if !isGen {
+ return label.Label, false
+ }
+ if containsProto(ctx, gen.RawOutputFiles(pathCtx)) {
+ // Return unmodified label + true
+ // True will ensure that this module gets dropped from `srcs` of the generated cc_* target. `srcs` is reserved for .cpp files
+ return label.Label, true
+ }
+ return label.Label, false
+ }
+}
+
+// Returns true if srcs contains only .proto files
+// Raises an exception if there is a combination of .proto and non .proto srcs
+func containsProto(ctx bazel.OtherModuleContext, srcs []string) bool {
+ onlyProtos := false
+ for _, src := range srcs {
+ if strings.HasSuffix(src, ".proto") {
+ onlyProtos = true
+ } else if onlyProtos {
+ // This is not a proto file, and we have encountered a .proto file previously
+ ctx.ModuleErrorf("TOOD: Add bp2build support combination of .proto and non .proto files in outs of genrule")
+ }
+ }
+ return onlyProtos
+}
+
// groupSrcsByExtension partitions `srcs` into groups based on file extension.
func groupSrcsByExtension(ctx android.BazelConversionPathContext, srcs bazel.LabelListAttribute) bazel.PartitionToLabelListAttribute {
// Convert filegroup dependencies into extension-specific filegroups filtered in the filegroup.bzl
@@ -159,10 +196,11 @@
// contains .l or .ll files we will need to find a way to add a
// LabelMapper for these that identifies these filegroups and
// converts them appropriately
- lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}},
- llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}},
- rScriptSrcPartition: bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
- xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+ lSrcPartition: bazel.LabelPartition{Extensions: []string{".l"}},
+ llSrcPartition: bazel.LabelPartition{Extensions: []string{".ll"}},
+ rScriptSrcPartition: bazel.LabelPartition{Extensions: []string{".fs", ".rscript"}},
+ xsdSrcPartition: bazel.LabelPartition{LabelMapper: android.XsdLabelMapper(xsdConfigCppTarget)},
+ protoFromGenPartition: bazel.LabelPartition{LabelMapper: protoFromGenPartitionMapper(ctx)},
// C++ is the "catch-all" group, and comprises generated sources because we don't
// know the language of these sources until the genrule is executed.
cppSrcPartition: bazel.LabelPartition{Extensions: []string{".cpp", ".cc", ".cxx", ".mm"}, LabelMapper: addSuffixForFilegroup("_cpp_srcs"), Keep_remainder: true},
@@ -594,6 +632,7 @@
partitionedHdrs := partitionHeaders(ctx, exportHdrs)
ca.protoSrcs = partitionedSrcs[protoSrcPartition]
+ ca.protoSrcs.Append(partitionedSrcs[protoFromGenPartition])
ca.aidlSrcs = partitionedSrcs[aidlSrcPartition]
for p, lla := range partitionedSrcs {
diff --git a/cc/cc.go b/cc/cc.go
index be67286..3b92696 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -74,6 +74,9 @@
ctx.TopDown("afdo_deps", afdoDepsMutator)
ctx.BottomUp("afdo", afdoMutator).Parallel()
+ ctx.TopDown("orderfile_deps", orderfileDepsMutator)
+ ctx.BottomUp("orderfile", orderfileMutator).Parallel()
+
ctx.TopDown("lto_deps", ltoDepsMutator)
ctx.BottomUp("lto", ltoMutator).Parallel()
@@ -526,6 +529,7 @@
getVndkExtendsModuleName() string
isAfdoCompile() bool
isPgoCompile() bool
+ isOrderfileCompile() bool
isCfi() bool
isFuzzer() bool
isNDKStubLibrary() bool
@@ -885,6 +889,7 @@
lto *lto
afdo *afdo
pgo *pgo
+ orderfile *orderfile
library libraryInterface
@@ -1259,6 +1264,9 @@
if c.pgo != nil {
c.AddProperties(c.pgo.props()...)
}
+ if c.orderfile != nil {
+ c.AddProperties(c.orderfile.props()...)
+ }
for _, feature := range c.features {
c.AddProperties(feature.props()...)
}
@@ -1392,6 +1400,13 @@
return false
}
+func (c *Module) isOrderfileCompile() bool {
+ if orderfile := c.orderfile; orderfile != nil {
+ return orderfile.Properties.OrderfileLoad
+ }
+ return false
+}
+
func (c *Module) isCfi() bool {
if sanitize := c.sanitize; sanitize != nil {
return Bool(sanitize.Properties.SanitizeMutated.Cfi)
@@ -1697,6 +1712,10 @@
return ctx.mod.isPgoCompile()
}
+func (ctx *moduleContextImpl) isOrderfileCompile() bool {
+ return ctx.mod.isOrderfileCompile()
+}
+
func (ctx *moduleContextImpl) isCfi() bool {
return ctx.mod.isCfi()
}
@@ -1806,6 +1825,7 @@
module.lto = <o{}
module.afdo = &afdo{}
module.pgo = &pgo{}
+ module.orderfile = &orderfile{}
return module
}
@@ -2234,6 +2254,9 @@
if c.pgo != nil {
flags = c.pgo.flags(ctx, flags)
}
+ if c.orderfile != nil {
+ flags = c.orderfile.flags(ctx, flags)
+ }
for _, feature := range c.features {
flags = feature.flags(ctx, flags)
}
@@ -2376,6 +2399,9 @@
if c.lto != nil {
c.lto.begin(ctx)
}
+ if c.orderfile != nil {
+ c.orderfile.begin(ctx)
+ }
if c.pgo != nil {
c.pgo.begin(ctx)
}
@@ -4284,6 +4310,7 @@
<OProperties{},
&AfdoProperties{},
&PgoProperties{},
+ &OrderfileProperties{},
&android.ProtoProperties{},
// RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules.
&RustBindgenClangProperties{},
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index f9b3eac..dd612ce 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -21,7 +21,6 @@
var VndkMustUseVendorVariantList = []string{
"android.hardware.nfc@1.2",
"libbinder",
- "libdumpstateutil",
"libcrypto",
"libexpat",
"libgatekeeper",
diff --git a/cc/lto.go b/cc/lto.go
index 44361db..df9ca0a 100644
--- a/cc/lto.go
+++ b/cc/lto.go
@@ -135,10 +135,14 @@
ltoLdFlags = append(ltoLdFlags, cachePolicyFormat+policy)
}
- // If the module does not have a profile, be conservative and limit cross TU inline
- // limit to 5 LLVM IR instructions, to balance binary size increase and performance.
- if !ctx.Darwin() && !ctx.isPgoCompile() && !ctx.isAfdoCompile() {
- ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
+ // Reduce the inlining threshold for a better balance of binary size and
+ // performance.
+ if !ctx.Darwin() {
+ if ctx.isPgoCompile() || ctx.isAfdoCompile() {
+ ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40")
+ } else {
+ ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5")
+ }
}
flags.Local.CFlags = append(flags.Local.CFlags, ltoCFlags...)
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index f0b7cc5..9281aeb 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -31,9 +31,8 @@
func init() {
pctx.HostBinToolVariable("ndkStubGenerator", "ndkstubgen")
- pctx.HostBinToolVariable("abidiff", "abidiff")
- pctx.HostBinToolVariable("abitidy", "abitidy")
- pctx.HostBinToolVariable("abidw", "abidw")
+ pctx.HostBinToolVariable("stg", "stg")
+ pctx.HostBinToolVariable("stgdiff", "stgdiff")
}
var (
@@ -44,28 +43,20 @@
CommandDeps: []string{"$ndkStubGenerator"},
}, "arch", "apiLevel", "apiMap", "flags")
- abidw = pctx.AndroidStaticRule("abidw",
+ stg = pctx.AndroidStaticRule("stg",
blueprint.RuleParams{
- Command: "$abidw --type-id-style hash --no-corpus-path " +
- "--no-show-locs --no-comp-dir-path -w $symbolList " +
- "$in --out-file $out",
- CommandDeps: []string{"$abidw"},
+ Command: "$stg -S :$symbolList --elf $in -o $out",
+ CommandDeps: []string{"$stg"},
}, "symbolList")
- abitidy = pctx.AndroidStaticRule("abitidy",
- blueprint.RuleParams{
- Command: "$abitidy --all $flags -i $in -o $out",
- CommandDeps: []string{"$abitidy"},
- }, "flags")
-
- abidiff = pctx.AndroidStaticRule("abidiff",
+ stgdiff = pctx.AndroidStaticRule("stgdiff",
blueprint.RuleParams{
// Need to create *some* output for ninja. We don't want to use tee
// because we don't want to spam the build output with "nothing
// changed" messages, so redirect output message to $out, and if
// changes were detected print the output and fail.
- Command: "$abidiff $args $in > $out || (cat $out && false)",
- CommandDeps: []string{"$abidiff"},
+ Command: "$stgdiff $args --stg $in -o $out || (cat $out && false)",
+ CommandDeps: []string{"$stgdiff"},
}, "args")
ndkLibrarySuffix = ".ndk"
@@ -107,12 +98,6 @@
// https://github.com/android-ndk/ndk/issues/265.
Unversioned_until *string
- // If true, does not emit errors when APIs lacking type information are
- // found. This is false by default and should not be enabled outside bionic,
- // where it is enabled pending a fix for http://b/190554910 (no debug info
- // for asm implemented symbols).
- Allow_untyped_symbols *bool
-
// Headers presented by this library to the Public API Surface
Export_header_libs []string
}
@@ -326,7 +311,7 @@
apiLevel android.ApiLevel) android.OptionalPath {
subpath := filepath.Join("prebuilts/abi-dumps/ndk", apiLevel.String(),
- ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.xml")
+ ctx.Arch().ArchType.String(), this.libraryName(ctx), "abi.stg")
return android.ExistentPathForSource(ctx, subpath)
}
@@ -359,34 +344,17 @@
func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) {
implementationLibrary := this.findImplementationLibrary(ctx)
- abiRawPath := getNdkAbiDumpInstallBase(ctx).Join(ctx,
- this.apiLevel.String(), ctx.Arch().ArchType.String(),
- this.libraryName(ctx), "abi.raw.xml")
- ctx.Build(pctx, android.BuildParams{
- Rule: abidw,
- Description: fmt.Sprintf("abidw %s", implementationLibrary),
- Input: implementationLibrary,
- Output: abiRawPath,
- Implicit: symbolList,
- Args: map[string]string{
- "symbolList": symbolList.String(),
- },
- })
-
this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx,
this.apiLevel.String(), ctx.Arch().ArchType.String(),
- this.libraryName(ctx), "abi.xml")
- untypedFlag := "--abort-on-untyped-symbols"
- if proptools.BoolDefault(this.properties.Allow_untyped_symbols, false) {
- untypedFlag = ""
- }
+ this.libraryName(ctx), "abi.stg")
ctx.Build(pctx, android.BuildParams{
- Rule: abitidy,
- Description: fmt.Sprintf("abitidy %s", implementationLibrary),
- Input: abiRawPath,
+ Rule: stg,
+ Description: fmt.Sprintf("stg %s", implementationLibrary),
+ Input: implementationLibrary,
+ Implicit: symbolList,
Output: this.abiDumpPath,
Args: map[string]string{
- "flags": untypedFlag,
+ "symbolList": symbolList.String(),
},
})
}
@@ -405,7 +373,7 @@
func (this *stubDecorator) diffAbi(ctx ModuleContext) {
// Catch any ABI changes compared to the checked-in definition of this API
// level.
- abiDiffPath := android.PathForModuleOut(ctx, "abidiff.timestamp")
+ abiDiffPath := android.PathForModuleOut(ctx, "stgdiff.timestamp")
prebuiltAbiDump := this.findPrebuiltAbiDump(ctx, this.apiLevel)
missingPrebuiltError := fmt.Sprintf(
"Did not find prebuilt ABI dump for %q (%q). Generate with "+
@@ -421,11 +389,14 @@
})
} else {
ctx.Build(pctx, android.BuildParams{
- Rule: abidiff,
- Description: fmt.Sprintf("abidiff %s %s", prebuiltAbiDump,
+ Rule: stgdiff,
+ Description: fmt.Sprintf("Comparing ABI %s %s", prebuiltAbiDump,
this.abiDumpPath),
Output: abiDiffPath,
Inputs: android.Paths{prebuiltAbiDump.Path(), this.abiDumpPath},
+ Args: map[string]string{
+ "args": "--format=small",
+ },
})
}
this.abiDiffPaths = append(this.abiDiffPaths, abiDiffPath)
@@ -452,13 +423,13 @@
})
} else {
ctx.Build(pctx, android.BuildParams{
- Rule: abidiff,
+ Rule: stgdiff,
Description: fmt.Sprintf("abidiff %s %s", this.abiDumpPath,
nextAbiDump),
Output: nextAbiDiffPath,
Inputs: android.Paths{this.abiDumpPath, nextAbiDump.Path()},
Args: map[string]string{
- "args": "--no-added-syms",
+ "args": "--format=small --ignore=interface_addition",
},
})
}
diff --git a/cc/orderfile.go b/cc/orderfile.go
new file mode 100644
index 0000000..cc1ab29
--- /dev/null
+++ b/cc/orderfile.go
@@ -0,0 +1,257 @@
+// Copyright 2023 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.
+//
+// Note: If you want to know how to use orderfile for your binary or shared
+// library, you can go look at the README in toolchains/pgo-profiles/orderfiles
+
+package cc
+
+import (
+ "fmt"
+
+ "android/soong/android"
+)
+
+// Order files are text files containing symbols representing functions names.
+// Linkers (lld) uses order files to layout functions in a specific order.
+// These binaries with ordered symbols will reduce page faults and improve a program's launch time
+// due to the efficient loading of symbols during a program’s cold-start.
+var (
+ // Add flags to ignore warnings about symbols not be found
+ // or not allowed to be ordered
+ orderfileOtherFlags = []string{
+ "-Wl,--no-warn-symbol-ordering",
+ }
+
+ // Add folder projects for orderfiles
+ globalOrderfileProjects = []string{
+ "toolchain/pgo-profiles/orderfiles",
+ "vendor/google_data/pgo_profile/orderfiles",
+ }
+)
+
+var orderfileProjectsConfigKey = android.NewOnceKey("OrderfileProjects")
+
+const orderfileProfileFlag = "-forder-file-instrumentation"
+const orderfileUseFormat = "-Wl,--symbol-ordering-file=%s"
+
+func getOrderfileProjects(config android.DeviceConfig) []string {
+ return config.OnceStringSlice(orderfileProjectsConfigKey, func() []string {
+ return globalOrderfileProjects
+ })
+}
+
+func recordMissingOrderfile(ctx BaseModuleContext, missing string) {
+ getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true)
+}
+
+type OrderfileProperties struct {
+ Orderfile struct {
+ Instrumentation *bool
+ Order_file_path *string `android:"arch_variant"`
+ Load_order_file *bool `android:"arch_variant"`
+ // Additional compiler flags to use when building this module
+ // for orderfile profiling.
+ Cflags []string `android:"arch_variant"`
+ } `android:"arch_variant"`
+
+ ShouldProfileModule bool `blueprint:"mutated"`
+ OrderfileLoad bool `blueprint:"mutated"`
+ OrderfileInstrLink bool `blueprint:"mutated"`
+}
+
+type orderfile struct {
+ Properties OrderfileProperties
+}
+
+func (props *OrderfileProperties) shouldInstrument() bool {
+ return Bool(props.Orderfile.Instrumentation)
+}
+
+// ShouldLoadOrderfile returns true if we need to load the order file rather than
+// profile the binary or shared library
+func (props *OrderfileProperties) shouldLoadOrderfile() bool {
+ return Bool(props.Orderfile.Load_order_file) && props.Orderfile.Order_file_path != nil
+}
+
+// orderfileEnabled returns true for binaries and shared libraries
+// if instrument flag is set to true
+func (orderfile *orderfile) orderfileEnabled() bool {
+ return orderfile != nil && orderfile.Properties.shouldInstrument()
+}
+
+// orderfileLinkEnabled returns true for binaries and shared libraries
+// if you should instrument dependencies
+func (orderfile *orderfile) orderfileLinkEnabled() bool {
+ return orderfile != nil && orderfile.Properties.OrderfileInstrLink
+}
+
+func (orderfile *orderfile) props() []interface{} {
+ return []interface{}{&orderfile.Properties}
+}
+
+// Get the path to the order file by checking it is valid and not empty
+func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.OptionalPath {
+ orderFile := *props.Orderfile.Order_file_path
+
+ // Test if the order file is present in any of the Orderfile projects
+ for _, profileProject := range getOrderfileProjects(ctx.DeviceConfig()) {
+ path := android.ExistentPathForSource(ctx, profileProject, orderFile)
+ if path.Valid() {
+ return path
+ }
+ }
+
+ // Record that this module's order file is absent
+ missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName()
+ recordMissingOrderfile(ctx, missing)
+
+ return android.OptionalPath{}
+}
+
+func (props *OrderfileProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags {
+ flags.Local.CFlags = append(flags.Local.CFlags, props.Orderfile.Cflags...)
+ flags.Local.CFlags = append(flags.Local.CFlags, orderfileProfileFlag)
+ flags.Local.CFlags = append(flags.Local.CFlags, "-mllvm -enable-order-file-instrumentation")
+ flags.Local.LdFlags = append(flags.Local.LdFlags, orderfileProfileFlag)
+ return flags
+}
+
+
+func (props *OrderfileProperties) loadOrderfileFlags(ctx ModuleContext, file string) []string {
+ flags := []string{fmt.Sprintf(orderfileUseFormat, file)}
+ flags = append(flags, orderfileOtherFlags...)
+ return flags
+}
+
+func (props *OrderfileProperties) addLoadFlags(ctx ModuleContext, flags Flags) Flags {
+ orderFile := props.getOrderfile(ctx)
+ orderFilePath := orderFile.Path()
+ loadFlags := props.loadOrderfileFlags(ctx, orderFilePath.String())
+
+ flags.Local.CFlags = append(flags.Local.CFlags, loadFlags...)
+ flags.Local.LdFlags = append(flags.Local.LdFlags, loadFlags...)
+
+ // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt
+ // if orderfile gets updated
+ flags.CFlagsDeps = append(flags.CFlagsDeps, orderFilePath)
+ flags.LdFlagsDeps = append(flags.LdFlagsDeps, orderFilePath)
+ return flags
+}
+
+func (orderfile *orderfile) begin(ctx BaseModuleContext) {
+ // Currently, we are not enabling orderfiles for host
+ if ctx.Host() {
+ return
+ }
+
+ // Currently, we are not enabling orderfiles to begin from static libraries
+ if ctx.static() && !ctx.staticBinary() {
+ return
+ }
+
+ if ctx.DeviceConfig().ClangCoverageEnabled() {
+ return
+ }
+
+ // Checking if orderfile is enabled for this module
+ if !orderfile.orderfileEnabled() {
+ return
+ }
+
+ orderfile.Properties.OrderfileLoad = orderfile.Properties.shouldLoadOrderfile()
+ orderfile.Properties.ShouldProfileModule = !orderfile.Properties.shouldLoadOrderfile()
+ orderfile.Properties.OrderfileInstrLink = orderfile.orderfileEnabled() && !orderfile.Properties.shouldLoadOrderfile()
+}
+
+func (orderfile *orderfile) flags(ctx ModuleContext, flags Flags) Flags {
+ props := orderfile.Properties
+ // Add flags to load the orderfile using the path in its Android.bp
+ if orderfile.Properties.OrderfileLoad {
+ flags = props.addLoadFlags(ctx, flags)
+ return flags
+ }
+
+ // Add flags to profile this module
+ if props.ShouldProfileModule {
+ flags = props.addInstrumentationProfileGatherFlags(ctx, flags)
+ return flags
+ }
+
+ return flags
+}
+
+// Propagate profile orderfile flags down from binaries and shared libraries
+// We do not allow propagation for load flags because the orderfile is specific
+// to the module (binary / shared library)
+func orderfileDepsMutator(mctx android.TopDownMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok {
+ if !m.orderfile.orderfileLinkEnabled() {
+ return
+ }
+ mctx.WalkDeps(func(dep android.
+ Module, parent android.Module) bool {
+ tag := mctx.OtherModuleDependencyTag(dep)
+ libTag, isLibTag := tag.(libraryDependencyTag)
+
+ // Do not recurse down non-static dependencies
+ if isLibTag {
+ if !libTag.static() {
+ return false
+ }
+ } else {
+ if tag != objDepTag && tag != reuseObjTag {
+ return false
+ }
+ }
+
+ if dep, ok := dep.(*Module); ok {
+ if m.orderfile.Properties.OrderfileInstrLink {
+ dep.orderfile.Properties.OrderfileInstrLink = true;
+ }
+ }
+
+ return true
+ })
+ }
+}
+
+// Create orderfile variants for modules that need them
+func orderfileMutator(mctx android.BottomUpMutatorContext) {
+ if m, ok := mctx.Module().(*Module); ok && m.orderfile != nil {
+ if !m.static() && m.orderfile.orderfileEnabled() {
+ mctx.SetDependencyVariation("orderfile")
+ return
+ }
+
+ variationNames := []string{""}
+ if m.orderfile.Properties.OrderfileInstrLink {
+ variationNames = append(variationNames, "orderfile")
+ }
+
+ if len(variationNames) > 1 {
+ modules := mctx.CreateVariations(variationNames...)
+ for i, name := range variationNames {
+ if name == "" {
+ continue
+ }
+ variation := modules[i].(*Module)
+ variation.Properties.PreventInstall = true
+ variation.Properties.HideFromMake = true
+ variation.orderfile.Properties.ShouldProfileModule = true
+ variation.orderfile.Properties.OrderfileLoad = false
+ }
+ }
+ }
+}
diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go
new file mode 100644
index 0000000..9e30bd2
--- /dev/null
+++ b/cc/orderfile_test.go
@@ -0,0 +1,493 @@
+// Copyright 2023 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 cc
+
+import (
+ "testing"
+ "strings"
+
+ "android/soong/android"
+)
+
+func TestOrderfileProfileSharedLibrary(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: false,
+ order_file_path: "",
+ },
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-forder-file-instrumentation"
+
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+ // Check cFlags of orderfile-enabled module
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check ldFlags of orderfile-enabled module
+ ldFlags := libTest.Rule("ld").Args["ldFlags"]
+ if !strings.Contains(ldFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+ }
+}
+
+func TestOrderfileLoadSharedLibrary(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: true,
+ order_file_path: "libTest.orderfile",
+ },
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/libTest.orderfile", "TEST"),
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile"
+
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+ // Check cFlags of orderfile-enabled module
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check ldFlags of orderfile-enabled module
+ ldFlags := libTest.Rule("ld").Args["ldFlags"]
+ if !strings.Contains(ldFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+ }
+}
+
+func TestOrderfileProfileBinary(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_binary {
+ name: "test",
+ srcs: ["test.c"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: false,
+ order_file_path: "",
+ },
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-forder-file-instrumentation"
+
+ test := result.ModuleForTests("test", "android_arm64_armv8-a")
+
+ // Check cFlags of orderfile-enabled module
+ cFlags := test.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'test' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check ldFlags of orderfile-enabled module
+ ldFlags := test.Rule("ld").Args["ldFlags"]
+ if !strings.Contains(ldFlags, expectedCFlag) {
+ t.Errorf("Expected 'test' to enable orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+ }
+}
+
+func TestOrderfileLoadBinary(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_binary {
+ name: "test",
+ srcs: ["test.c"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: true,
+ order_file_path: "test.orderfile",
+ },
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+ test := result.ModuleForTests("test", "android_arm64_armv8-a")
+
+ // Check cFlags of orderfile-enabled module
+ cFlags := test.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'test' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check ldFlags of orderfile-enabled module
+ ldFlags := test.Rule("ld").Args["ldFlags"]
+ if !strings.Contains(ldFlags, expectedCFlag) {
+ t.Errorf("Expected 'test' to load orderfile, but did not find %q in ldflags %q", expectedCFlag, ldFlags)
+ }
+}
+
+// Profile flags should propagate through static libraries
+func TestOrderfileProfilePropagateStaticDeps(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ static_libs: ["libFoo"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: false,
+ order_file_path: "",
+ },
+ }
+
+ cc_library_static {
+ name: "libFoo",
+ srcs: ["foo.c"],
+ static_libs: ["libBar"],
+ }
+
+ cc_library_static {
+ name: "libBar",
+ srcs: ["bar.c"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-forder-file-instrumentation"
+
+ // Check cFlags of orderfile-enabled module
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check cFlags of orderfile variant static libraries
+ libFooOfVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_orderfile")
+ libBarOfVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_orderfile")
+
+ cFlags = libFooOfVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFooOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBarOfVariant.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBarOfVariant' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edge from orderfile-enabled module to orderfile variant static libraries
+ if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) {
+ t.Errorf("libTest missing dependency on orderfile variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) {
+ t.Errorf("libTest missing dependency on orderfile variant of libBar")
+ }
+
+ // Check cFlags of the non-orderfile variant static libraries
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+ cFlags = libFoo.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBar.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+ if hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest has dependency on non-orderfile variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libTest has dependency on non-orderfile variant of libBar")
+ }
+}
+
+// Load flags should never propagate
+func TestOrderfileLoadPropagateStaticDeps(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ static_libs: ["libFoo"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: true,
+ order_file_path: "test.orderfile",
+ },
+ }
+
+ cc_library_static {
+ name: "libFoo",
+ srcs: ["foo.c"],
+ static_libs: ["libBar"],
+ }
+
+ cc_library_static {
+ name: "libBar",
+ srcs: ["bar.c"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ android.FixtureAddTextFile("toolchain/pgo-profiles/orderfiles/test.orderfile", "TEST"),
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile"
+
+ // Check cFlags of orderfile-enabled module
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to load orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check cFlags of the non-orderfile variant static libraries
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+ cFlags = libFoo.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBar.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' not load orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+ if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+ }
+
+ // Make sure no orderfile variants are created for static libraries because the flags were not propagated
+ libFooVariants := result.ModuleVariantsForTests("libFoo")
+ for _, v := range libFooVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+ }
+ }
+
+ libBarVariants := result.ModuleVariantsForTests("libBar")
+ for _, v := range libBarVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+ }
+ }
+}
+
+// Profile flags should not propagate through shared libraries
+func TestOrderfileProfilePropagateSharedDeps(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_shared {
+ name: "libTest",
+ srcs: ["test.c"],
+ shared_libs: ["libFoo"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: false,
+ order_file_path: "",
+ },
+ }
+
+ cc_library_shared {
+ name: "libFoo",
+ srcs: ["foo.c"],
+ static_libs: ["libBar"],
+ }
+
+ cc_library_static {
+ name: "libBar",
+ srcs: ["bar.c"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-forder-file-instrumentation"
+
+ // Check cFlags of orderfile-enabled module
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
+
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if !strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to enable orderfile, but did not find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check cFlags of the static and shared libraries
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_shared")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+ cFlags = libFoo.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBar.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries
+ if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+ }
+
+ // Make sure no orderfile variants are created for libraries because the flags were not propagated
+ libFooVariants := result.ModuleVariantsForTests("libFoo")
+ for _, v := range libFooVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+ }
+ }
+
+ libBarVariants := result.ModuleVariantsForTests("libBar")
+ for _, v := range libBarVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+ }
+ }
+}
+
+// Profile flags should not work or be propagated if orderfile flags start at a static library
+func TestOrderfileProfileStaticLibrary(t *testing.T) {
+ t.Parallel()
+ bp := `
+ cc_library_static {
+ name: "libTest",
+ srcs: ["test.c"],
+ static_libs: ["libFoo"],
+ orderfile : {
+ instrumentation: true,
+ load_order_file: false,
+ order_file_path: "",
+ },
+ }
+
+ cc_library_static {
+ name: "libFoo",
+ srcs: ["foo.c"],
+ static_libs: ["libBar"],
+ }
+
+ cc_library_static {
+ name: "libBar",
+ srcs: ["bar.c"],
+ }
+ `
+
+ result := android.GroupFixturePreparers(
+ prepareForCcTest,
+ ).RunTestWithBp(t, bp)
+
+ expectedCFlag := "-forder-file-instrumentation"
+
+ // Check cFlags of module
+ libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static")
+
+ cFlags := libTest.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libTest' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check cFlags of the static libraries
+ libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static")
+ libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
+
+ cFlags = libFoo.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libFoo' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ cFlags = libBar.Rule("cc").Args["cFlags"]
+ if strings.Contains(cFlags, expectedCFlag) {
+ t.Errorf("Expected 'libBar' to not enable orderfile, but did find %q in cflags %q", expectedCFlag, cFlags)
+ }
+
+ // Check dependency edge from orderfile-enabled module to non-orderfile variant libraries
+ if !hasDirectDep(result, libTest.Module(), libFoo.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libFoo")
+ }
+
+ if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
+ t.Errorf("libTest missing dependency on non-orderfile variant of libBar")
+ }
+
+ // Make sure no orderfile variants are created for static libraries because the flags were not propagated
+ libFooVariants := result.ModuleVariantsForTests("libFoo")
+ for _, v := range libFooVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libFoo' to not contain 'orderfile', but found %q", v)
+ }
+ }
+
+ libBarVariants := result.ModuleVariantsForTests("libBar")
+ for _, v := range libBarVariants {
+ if strings.Contains(v, "orderfile") {
+ t.Errorf("Expected variants for 'libBar' to not contain 'orderfile', but found %q", v)
+ }
+ }
+}
\ No newline at end of file
diff --git a/cc/sanitize.go b/cc/sanitize.go
index c1ef970..30bce9b 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -87,6 +87,8 @@
hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"}
deviceOnlySanitizeFlags = []string{"-fsanitize-trap=all", "-ftrap-function=abort"}
+
+ noSanitizeLinkRuntimeFlag = "-fno-sanitize-link-runtime"
)
type SanitizerType int
@@ -407,6 +409,8 @@
exportedVars.ExportStringListStaticVariable("HostOnlySanitizeFlags", hostOnlySanitizeFlags)
exportedVars.ExportStringList("DeviceOnlySanitizeFlags", deviceOnlySanitizeFlags)
+ exportedVars.ExportStringList("MinimalRuntimeFlags", minimalRuntimeFlags)
+
// Leave out "-flto" from the slices exported to bazel, as we will use the
// dedicated LTO feature for this. For C Flags and Linker Flags, also leave
// out the cross DSO flag which will be added separately under the correct conditions.
@@ -422,6 +426,8 @@
exportedVars.ExportString("CfiExportsMapFilename", cfiExportsMapFilename)
exportedVars.ExportString("CfiAssemblySupportFlag", cfiAssemblySupportFlag)
+ exportedVars.ExportString("NoSanitizeLinkRuntimeFlag", noSanitizeLinkRuntimeFlag)
+
android.RegisterMakeVarsProvider(pctx, cfiMakeVarsProvider)
android.RegisterMakeVarsProvider(pctx, hwasanMakeVarsProvider)
}
@@ -923,7 +929,7 @@
// Bionic and musl sanitizer runtimes have already been added as dependencies so that
// the right variant of the runtime will be used (with the "-android" or "-musl"
// suffixes), so don't let clang the runtime library.
- flags.Local.LdFlags = append(flags.Local.LdFlags, "-fno-sanitize-link-runtime")
+ flags.Local.LdFlags = append(flags.Local.LdFlags, noSanitizeLinkRuntimeFlag)
} else {
// Host sanitizers only link symbols in the final executable, so
// there will always be undefined symbols in intermediate libraries.
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 5ea84bc..20e366e 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -121,6 +121,10 @@
defer ctx.EventHandler.End("mixed_build")
bazelHook := func() error {
+ err := ctx.Config().BazelContext.QueueBazelSandwichCqueryRequests(ctx.Config())
+ if err != nil {
+ return err
+ }
return ctx.Config().BazelContext.InvokeBazel(ctx.Config(), ctx)
}
ctx.SetBeforePrepareBuildActionsHook(bazelHook)
@@ -810,9 +814,7 @@
// Run the code-generation phase to convert BazelTargetModules to BUILD files
// and print conversion codegenMetrics to the user.
codegenContext := bp2build.NewCodegenContext(ctx.Config(), ctx, bp2build.Bp2Build, topDir)
- ctx.EventHandler.Do("codegen", func() {
- codegenMetrics = bp2build.Codegen(codegenContext)
- })
+ codegenMetrics = bp2build.Codegen(codegenContext)
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 67cb6cf..5c2316a 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -15,7 +15,6 @@
package main
import (
- "android/soong/starlark_import"
"io/fs"
"io/ioutil"
"os"
@@ -23,6 +22,7 @@
"android/soong/android"
"android/soong/bp2build"
+ "android/soong/starlark_import"
)
// A helper function to generate a Read-only Bazel workspace in outDir
@@ -35,8 +35,7 @@
panic(err)
}
- filesToWrite := bp2build.CreateBazelFiles(ctx.Config(), ruleShims, res.BuildDirToTargets(),
- ctx.Mode())
+ filesToWrite := bp2build.CreateBazelFiles(ruleShims, res.BuildDirToTargets(), ctx.Mode())
bazelRcFiles, err2 := CopyBazelRcFiles()
if err2 != nil {
return err2
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 69ba1e9..8a8d605 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -1012,16 +1012,7 @@
Tags: tags,
}, attrs)
} else {
- // The Out prop is not in an immediately accessible field
- // in the Module struct, so use GetProperties and cast it
- // to the known struct prop.
- var outs []string
- for _, propIntf := range m.GetProperties() {
- if props, ok := propIntf.(*genRuleProperties); ok {
- outs = props.Out
- break
- }
- }
+ outs := m.RawOutputFiles(ctx)
for _, out := range outs {
if out == bazelName {
// This is a workaround to circumvent a Bazel warning where a genrule's
@@ -1096,6 +1087,25 @@
Export_includes []string
}
+// RawOutputFfiles returns the raw outputs specified in Android.bp
+// This does not contain the fully resolved path relative to the top of the tree
+func (g *Module) RawOutputFiles(ctx android.BazelConversionContext) []string {
+ if ctx.Config().BuildMode != android.Bp2build {
+ ctx.ModuleErrorf("RawOutputFiles is only supported in bp2build mode")
+ }
+ // The Out prop is not in an immediately accessible field
+ // in the Module struct, so use GetProperties and cast it
+ // to the known struct prop.
+ var outs []string
+ for _, propIntf := range g.GetProperties() {
+ if props, ok := propIntf.(*genRuleProperties); ok {
+ outs = props.Out
+ break
+ }
+ }
+ return outs
+}
+
var Bool = proptools.Bool
var String = proptools.String
diff --git a/java/aapt2.go b/java/aapt2.go
index 7845a0b..4cff8a7 100644
--- a/java/aapt2.go
+++ b/java/aapt2.go
@@ -150,7 +150,8 @@
`${config.Aapt2Cmd} link -o $out $flags --java $genDir --proguard $proguardOptions ` +
`--output-text-symbols ${rTxt} $inFlags && ` +
`${config.SoongZipCmd} -write_if_changed -jar -o $genJar -C $genDir -D $genDir &&` +
- `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages '`,
+ `${config.ExtractJarPackagesCmd} -i $genJar -o $extraPackages --prefix '--extra-packages ' && ` +
+ `rm -rf $genDir`,
CommandDeps: []string{
"${config.Aapt2Cmd}",
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 1bb4996..8494d02 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -122,3 +122,17 @@
--warning_check RemoteViewLayout
--warning_check SupportAnnotationUsage
--warning_check UniqueConstants
+
+# TODO(b/294098365): these checks fail in AOSP, but pass downstream
+--warning_check ForegroundServiceType
+--warning_check MutableImplicitPendingIntent
+
+--warning_check ExactAlarm
+--warning_check ExpiredTargetSdkVersion
+--warning_check ForegroundServicePermission
+--warning_check ObsoleteSdkInt
+--warning_check ScheduleExactAlarm
+--warning_check StartActivityAndCollapseDeprecated
+--warning_check UnspecifiedRegisterReceiverFlag
+--warning_check WearMaterialTheme
+--warning_check WearStandaloneAppFlag
diff --git a/python/bp2build.go b/python/bp2build.go
index 7c28da3..41e9f49 100644
--- a/python/bp2build.go
+++ b/python/bp2build.go
@@ -222,7 +222,8 @@
props := bazel.BazelTargetModuleProperties{
// Use the native py_binary rule.
- Rule_class: "py_test",
+ Rule_class: "py_test",
+ Bzl_load_location: "//build/bazel/rules/python:py_test.bzl",
}
ctx.CreateBazelTargetModule(props, android.CommonAttributes{
diff --git a/starlark_fmt/format.go b/starlark_fmt/format.go
index 4209507..0224bcf 100644
--- a/starlark_fmt/format.go
+++ b/starlark_fmt/format.go
@@ -16,6 +16,7 @@
import (
"fmt"
+ "reflect"
"sort"
"strconv"
"strings"
@@ -33,6 +34,72 @@
return strings.Repeat(" ", level*indent)
}
+func PrintAny(value any, indentLevel int) string {
+ return printAnyRecursive(reflect.ValueOf(value), indentLevel)
+}
+
+func printAnyRecursive(value reflect.Value, indentLevel int) string {
+ switch value.Type().Kind() {
+ case reflect.String:
+ val := value.String()
+ if strings.Contains(val, "\"") || strings.Contains(val, "\n") {
+ return `'''` + val + `'''`
+ }
+ return `"` + val + `"`
+ case reflect.Bool:
+ if value.Bool() {
+ return "True"
+ } else {
+ return "False"
+ }
+ case reflect.Int:
+ return fmt.Sprintf("%d", value.Int())
+ case reflect.Slice:
+ if value.Len() == 0 {
+ return "[]"
+ } else if value.Len() == 1 {
+ return "[" + printAnyRecursive(value.Index(0), indentLevel) + "]"
+ }
+ list := make([]string, 0, value.Len()+2)
+ list = append(list, "[")
+ innerIndent := Indention(indentLevel + 1)
+ for i := 0; i < value.Len(); i++ {
+ list = append(list, innerIndent+printAnyRecursive(value.Index(i), indentLevel+1)+`,`)
+ }
+ list = append(list, Indention(indentLevel)+"]")
+ return strings.Join(list, "\n")
+ case reflect.Map:
+ if value.Len() == 0 {
+ return "{}"
+ }
+ items := make([]string, 0, value.Len())
+ for _, key := range value.MapKeys() {
+ items = append(items, fmt.Sprintf(`%s%s: %s,`, Indention(indentLevel+1), printAnyRecursive(key, indentLevel+1), printAnyRecursive(value.MapIndex(key), indentLevel+1)))
+ }
+ sort.Strings(items)
+ return fmt.Sprintf(`{
+%s
+%s}`, strings.Join(items, "\n"), Indention(indentLevel))
+ case reflect.Struct:
+ if value.NumField() == 0 {
+ return "struct()"
+ }
+ items := make([]string, 0, value.NumField()+2)
+ items = append(items, "struct(")
+ for i := 0; i < value.NumField(); i++ {
+ if value.Type().Field(i).Anonymous {
+ panic("anonymous fields aren't supported")
+ }
+ name := value.Type().Field(i).Name
+ items = append(items, fmt.Sprintf(`%s%s = %s,`, Indention(indentLevel+1), name, printAnyRecursive(value.Field(i), indentLevel+1)))
+ }
+ items = append(items, Indention(indentLevel)+")")
+ return strings.Join(items, "\n")
+ default:
+ panic("Unhandled kind: " + value.Kind().String())
+ }
+}
+
// PrintBool returns a Starlark compatible bool string.
func PrintBool(item bool) string {
if item {
diff --git a/tests/lib.sh b/tests/lib.sh
index 40b317b..f3db76f 100644
--- a/tests/lib.sh
+++ b/tests/lib.sh
@@ -52,6 +52,10 @@
cp -R "$REAL_TOP/$dir" "$MOCK_TOP/$parent"
}
+function delete_directory {
+ rm -rf "$MOCK_TOP/$1"
+}
+
function symlink_file {
local file="$1"
@@ -138,6 +142,9 @@
copy_directory build/bazel
copy_directory build/bazel_common_rules
+ # This requires pulling more tools into the mock top to build partitions
+ delete_directory build/bazel/examples/partitions
+
symlink_directory packages/modules/common/build
symlink_directory prebuilts/bazel
symlink_directory prebuilts/clang
@@ -147,6 +154,7 @@
symlink_directory external/bazelbuild-rules_go
symlink_directory external/bazelbuild-rules_license
symlink_directory external/bazelbuild-kotlin-rules
+ symlink_directory external/bazelbuild-rules_python
symlink_directory external/bazelbuild-rules_java
symlink_file WORKSPACE
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 48f654e..6b9ff8b 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -22,7 +22,5 @@
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
"$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
-"$TOP/build/soong/tests/sbom_test.sh"
-
"$TOP/build/bazel/ci/b_test.sh"
diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh
index afec6b1..2534b20 100755
--- a/tests/sbom_test.sh
+++ b/tests/sbom_test.sh
@@ -238,10 +238,45 @@
diff_files "$file_list_file" "$files_in_spdx_file" "$partition_name"
done
+ verify_package_verification_code "$product_out/sbom.spdx"
+
# Teardown
cleanup "${out_dir}"
}
+function verify_package_verification_code {
+ local sbom_file="$1"; shift
+
+ local -a file_checksums
+ local package_product_found=
+ while read -r line;
+ do
+ if grep -q 'PackageVerificationCode' <<<"$line"
+ then
+ package_product_found=true
+ fi
+ if [ -n "$package_product_found" ]
+ then
+ if grep -q 'FileChecksum' <<< "$line"
+ then
+ checksum=$(echo $line | sed 's/^.*: //')
+ file_checksums+=("$checksum")
+ fi
+ fi
+ done <<< "$(grep -E 'PackageVerificationCode|FileChecksum' $sbom_file)"
+ IFS=$'\n' file_checksums=($(sort <<<"${file_checksums[*]}")); unset IFS
+ IFS= expected_package_verification_code=$(printf "${file_checksums[*]}" | sha1sum | sed 's/[[:space:]]*-//'); unset IFS
+
+ actual_package_verification_code=$(grep PackageVerificationCode $sbom_file | sed 's/PackageVerificationCode: //g')
+ if [ $actual_package_verification_code = $expected_package_verification_code ]
+ then
+ echo "Package verification code is correct."
+ else
+ echo "Unexpected package verification code."
+ exit 1
+ fi
+}
+
function test_sbom_unbundled_apex {
# Setup
out_dir="$(setup)"