Merge changes I2c0e2f4b,I539f38ab,I7ffa177c into main
* changes:
Don't mutate sources when reusing objects
Add PostApex mutator stage
Add test for sabi propagation to static libraries
diff --git a/Android.bp b/Android.bp
index ab8e4a0..d71bcec 100644
--- a/Android.bp
+++ b/Android.bp
@@ -142,12 +142,10 @@
visibility: ["//visibility:public"],
}
-// TODO(b/365670526): remove the cuttlefish visibility once it is fully removed
product_config {
name: "product_config",
visibility: [
"//build/make/target/product/generic",
- "//device/google/cuttlefish/system_image",
],
}
@@ -158,7 +156,6 @@
// Currently, only microdroid and cf system image can refer to system-build.prop
visibility: [
"//build/make/target/product/generic",
- "//device/google/cuttlefish/system_image",
"//packages/modules/Virtualization/build/microdroid",
],
}
diff --git a/aconfig/build_flags/Android.bp b/aconfig/build_flags/Android.bp
index b3c7339..139aeac 100644
--- a/aconfig/build_flags/Android.bp
+++ b/aconfig/build_flags/Android.bp
@@ -13,10 +13,11 @@
"soong-android",
],
srcs: [
- "all_build_flag_declarations.go",
"build_flags.go",
+ "build_flags_singleton.go",
"declarations.go",
"init.go",
+ "release_configs.go",
],
testSrcs: [
],
diff --git a/aconfig/build_flags/all_build_flag_declarations.go b/aconfig/build_flags/all_build_flag_declarations.go
deleted file mode 100644
index 5f02912..0000000
--- a/aconfig/build_flags/all_build_flag_declarations.go
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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 build_flags
-
-import (
- "android/soong/android"
-)
-
-// A singleton module that collects all of the build flags declared in the
-// tree into a single combined file for export to the external flag setting
-// server (inside Google it's Gantry).
-//
-// Note that this is ALL build_declarations modules present in the tree, not just
-// ones that are relevant to the product currently being built, so that that infra
-// doesn't need to pull from multiple builds and merge them.
-func AllBuildFlagDeclarationsFactory() android.Singleton {
- return &allBuildFlagDeclarationsSingleton{}
-}
-
-type allBuildFlagDeclarationsSingleton struct {
- intermediateBinaryProtoPath android.OutputPath
- intermediateTextProtoPath android.OutputPath
-}
-
-func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
- // Find all of the build_flag_declarations modules
- var intermediateFiles android.Paths
- ctx.VisitAllModules(func(module android.Module) {
- decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
- if !ok {
- return
- }
- intermediateFiles = append(intermediateFiles, decl.IntermediateCacheOutputPath)
- })
-
- // Generate build action for build_flag (binary proto output)
- this.intermediateBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
- ctx.Build(pctx, android.BuildParams{
- Rule: allDeclarationsRule,
- Inputs: intermediateFiles,
- Output: this.intermediateBinaryProtoPath,
- Description: "all_build_flag_declarations",
- Args: map[string]string{
- "intermediates": android.JoinPathsWithPrefix(intermediateFiles, "--intermediate "),
- },
- })
- ctx.Phony("all_build_flag_declarations", this.intermediateBinaryProtoPath)
-
- // Generate build action for build_flag (text proto output)
- this.intermediateTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
- ctx.Build(pctx, android.BuildParams{
- Rule: allDeclarationsRuleTextProto,
- Input: this.intermediateBinaryProtoPath,
- Output: this.intermediateTextProtoPath,
- Description: "all_build_flag_declarations_textproto",
- })
- ctx.Phony("all_build_flag_declarations_textproto", this.intermediateTextProtoPath)
-}
-
-func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
- ctx.DistForGoal("droid", this.intermediateBinaryProtoPath)
- for _, goal := range []string{"docs", "droid", "sdk"} {
- ctx.DistForGoalWithFilename(goal, this.intermediateBinaryProtoPath, "build_flags/all_flags.pb")
- ctx.DistForGoalWithFilename(goal, this.intermediateTextProtoPath, "build_flags/all_flags.textproto")
- }
-}
diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go
new file mode 100644
index 0000000..ba27a85
--- /dev/null
+++ b/aconfig/build_flags/build_flags_singleton.go
@@ -0,0 +1,123 @@
+// 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 build_flags
+
+import (
+ "android/soong/android"
+)
+
+// A singleton module that collects all of the build flags declared in the
+// tree into a single combined file for export to the external flag setting
+// server (inside Google it's Gantry).
+//
+// Note that this is ALL build_declarations modules present in the tree, not just
+// ones that are relevant to the product currently being built, so that that infra
+// doesn't need to pull from multiple builds and merge them.
+func AllBuildFlagDeclarationsFactory() android.Singleton {
+ return &allBuildFlagDeclarationsSingleton{}
+}
+
+type allBuildFlagDeclarationsSingleton struct {
+ flagsBinaryProtoPath android.OutputPath
+ flagsTextProtoPath android.OutputPath
+ configsBinaryProtoPath android.OutputPath
+ configsTextProtoPath android.OutputPath
+}
+
+func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+ // Find all of the build_flag_declarations modules
+ var flagsFiles android.Paths
+ // Find all of the release_config_contribution modules
+ var contributionDirs android.Paths
+ ctx.VisitAllModules(func(module android.Module) {
+ decl, ok := android.OtherModuleProvider(ctx, module, BuildFlagDeclarationsProviderKey)
+ if ok {
+ flagsFiles = append(flagsFiles, decl.IntermediateCacheOutputPath)
+ }
+
+ contrib, ok := android.OtherModuleProvider(ctx, module, ReleaseConfigContributionsProviderKey)
+ if ok {
+ contributionDirs = append(contributionDirs, contrib.ContributionDir)
+ }
+ })
+
+ // Generate build action for build_flag (binary proto output)
+ this.flagsBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allDeclarationsRule,
+ Inputs: flagsFiles,
+ Output: this.flagsBinaryProtoPath,
+ Description: "all_build_flag_declarations",
+ Args: map[string]string{
+ "intermediates": android.JoinPathsWithPrefix(flagsFiles, "--intermediate "),
+ },
+ })
+ ctx.Phony("all_build_flag_declarations", this.flagsBinaryProtoPath)
+
+ // Generate build action for build_flag (text proto output)
+ this.flagsTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allDeclarationsRuleTextProto,
+ Input: this.flagsBinaryProtoPath,
+ Output: this.flagsTextProtoPath,
+ Description: "all_build_flag_declarations_textproto",
+ })
+ ctx.Phony("all_build_flag_declarations_textproto", this.flagsTextProtoPath)
+
+ // Generate build action for release_configs (binary proto output)
+ this.configsBinaryProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.pb")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsBinaryProtoPath,
+ Description: "all_release_config_contributions",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "pb",
+ },
+ })
+ ctx.Phony("all_release_config_contributions", this.configsBinaryProtoPath)
+
+ this.configsTextProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.textproto")
+ ctx.Build(pctx, android.BuildParams{
+ Rule: allReleaseConfigContributionsRule,
+ Inputs: contributionDirs,
+ Output: this.configsTextProtoPath,
+ Description: "all_release_config_contributions_textproto",
+ Args: map[string]string{
+ "dirs": android.JoinPathsWithPrefix(contributionDirs, "--dir "),
+ "format": "textproto",
+ },
+ })
+ ctx.Phony("all_release_config_contributions_textproto", this.configsTextProtoPath)
+
+ // Add a simple target for ci/build_metadata to use.
+ ctx.Phony("release_config_metadata",
+ this.flagsBinaryProtoPath,
+ this.flagsTextProtoPath,
+ this.configsBinaryProtoPath,
+ this.configsTextProtoPath,
+ )
+}
+
+func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) {
+ ctx.DistForGoal("droid", this.flagsBinaryProtoPath)
+ for _, goal := range []string{"docs", "droid", "sdk"} {
+ ctx.DistForGoalWithFilename(goal, this.flagsBinaryProtoPath, "build_flags/all_flags.pb")
+ ctx.DistForGoalWithFilename(goal, this.flagsTextProtoPath, "build_flags/all_flags.textproto")
+ ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb")
+ ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto")
+ }
+}
diff --git a/aconfig/build_flags/declarations.go b/aconfig/build_flags/declarations.go
index e927db2..4a54269 100644
--- a/aconfig/build_flags/declarations.go
+++ b/aconfig/build_flags/declarations.go
@@ -35,7 +35,7 @@
// Properties for "aconfig_declarations"
properties struct {
- // aconfig files, relative to this Android.bp file
+ // build flag declaration files, relative to this Android.bp file
Srcs []string `android:"path"`
}
}
diff --git a/aconfig/build_flags/init.go b/aconfig/build_flags/init.go
index dc1369c..a7575e8 100644
--- a/aconfig/build_flags/init.go
+++ b/aconfig/build_flags/init.go
@@ -65,15 +65,32 @@
"${buildFlagDeclarations}",
},
})
+
+ allReleaseConfigContributionsRule = pctx.AndroidStaticRule("all-release-config-contributions-dump",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
+ allReleaseConfigContributionsRuleText = pctx.AndroidStaticRule("all-release-config-contributions-dumptext",
+ blueprint.RuleParams{
+ Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`,
+ CommandDeps: []string{
+ "${releaseConfigContributions}",
+ },
+ }, "dirs", "format")
)
func init() {
RegisterBuildComponents(android.InitRegistrationContext)
pctx.Import("android/soong/android")
pctx.HostBinToolVariable("buildFlagDeclarations", "build-flag-declarations")
+ pctx.HostBinToolVariable("releaseConfigContributions", "release-config-contributions")
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("build_flag_declarations", DeclarationsFactory)
+ ctx.RegisterModuleType("release_config_contributions", ReleaseConfigContributionsFactory)
ctx.RegisterParallelSingletonType("all_build_flag_declarations", AllBuildFlagDeclarationsFactory)
}
diff --git a/aconfig/build_flags/release_configs.go b/aconfig/build_flags/release_configs.go
new file mode 100644
index 0000000..3fa8a7c
--- /dev/null
+++ b/aconfig/build_flags/release_configs.go
@@ -0,0 +1,78 @@
+// 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 build_flags
+
+import (
+ "path/filepath"
+
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+type ReleaseConfigContributionsProviderData struct {
+ ContributionDir android.SourcePath
+}
+
+var ReleaseConfigContributionsProviderKey = blueprint.NewProvider[ReleaseConfigContributionsProviderData]()
+
+// Soong uses `release_config_contributions` modules to produce the
+// `build_flags/all_release_config_contributions.*` artifacts, listing *all* of
+// the directories in the source tree that contribute to each release config,
+// whether or not they are actually used for the lunch product.
+//
+// This artifact helps flagging automation determine in which directory a flag
+// should be placed by default.
+type ReleaseConfigContributionsModule struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ // Properties for "release_config_contributions"
+ properties struct {
+ // The `release_configs/*.textproto` files provided by this
+ // directory, relative to this Android.bp file
+ Srcs []string `android:"path"`
+ }
+}
+
+func ReleaseConfigContributionsFactory() android.Module {
+ module := &ReleaseConfigContributionsModule{}
+
+ android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
+ module.AddProperties(&module.properties)
+
+ return module
+}
+
+func (module *ReleaseConfigContributionsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ srcs := android.PathsForModuleSrc(ctx, module.properties.Srcs)
+ if len(srcs) == 0 {
+ return
+ }
+ contributionDir := filepath.Dir(filepath.Dir(srcs[0].String()))
+ for _, file := range srcs {
+ if filepath.Dir(filepath.Dir(file.String())) != contributionDir {
+ ctx.ModuleErrorf("Cannot include %s with %s contributions", file, contributionDir)
+ }
+ if filepath.Base(filepath.Dir(file.String())) != "release_configs" || file.Ext() != ".textproto" {
+ ctx.ModuleErrorf("Invalid contribution file %s", file)
+ }
+ }
+ android.SetProvider(ctx, ReleaseConfigContributionsProviderKey, ReleaseConfigContributionsProviderData{
+ ContributionDir: android.PathForSource(ctx, contributionDir),
+ })
+
+}
diff --git a/apex/apex.go b/apex/apex.go
index 63b8d38..d7dc6d7 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -395,7 +395,7 @@
// Apex Container package name. Override value for attribute package:name in
// AndroidManifest.xml
- Package_name string
+ Package_name proptools.Configurable[string]
// A txt file containing list of files that are allowed to be included in this APEX.
Allowed_files *string `android:"path"`
@@ -1110,23 +1110,6 @@
if am, ok := mctx.Module().(android.ApexModule); ok {
android.ApexInfoMutator(mctx, am)
}
- enforceAppUpdatability(mctx)
-}
-
-// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
-func enforceAppUpdatability(mctx android.TopDownMutatorContext) {
- if !mctx.Module().Enabled(mctx) {
- return
- }
- if apex, ok := mctx.Module().(*apexBundle); ok && apex.Updatable() {
- // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
- mctx.VisitDirectDeps(func(module android.Module) {
- // ignore android_test_app
- if app, ok := module.(*java.AndroidApp); ok {
- app.SetUpdatable(true)
- }
- })
- }
}
// TODO: b/215736885 Whittle the denylist
@@ -1872,6 +1855,7 @@
a.CheckMinSdkVersion(ctx)
a.checkStaticLinkingToStubLibraries(ctx)
a.checkStaticExecutables(ctx)
+ a.enforceAppUpdatability(ctx)
if len(a.properties.Tests) > 0 && !a.testApex {
ctx.PropertyErrorf("tests", "property allowed only in apex_test module type")
return false
@@ -2397,6 +2381,24 @@
}
}
+// enforceAppUpdatability propagates updatable=true to apps of updatable apexes
+func (a *apexBundle) enforceAppUpdatability(mctx android.ModuleContext) {
+ if !a.Enabled(mctx) {
+ return
+ }
+ if a.Updatable() {
+ // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults
+ mctx.VisitDirectDeps(func(module android.Module) {
+ if appInfo, ok := android.OtherModuleProvider(mctx, module, java.AppInfoProvider); ok {
+ // ignore android_test_app
+ if !appInfo.TestHelperApp && !appInfo.Updatable {
+ mctx.ModuleErrorf("app dependency %s must have updatable: true", mctx.OtherModuleName(module))
+ }
+ }
+ })
+ }
+}
+
// apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that
// the bootclasspath_fragment contributes to the apex.
func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module blueprint.Module) []apexFile {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b372d7f..da6214d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5450,7 +5450,7 @@
android.PrepareForTestWithAllowMissingDependencies,
android.FixtureMergeMockFs(map[string][]byte{
"build/soong/scripts/check_boot_jars/package_allowed_list.txt": nil,
- "frameworks/base/boot/boot-profile.txt": nil,
+ "frameworks/base/boot/boot-profile.txt": nil,
}),
)
@@ -9876,7 +9876,7 @@
apex {
name: "myapex",
key: "myapex.key",
- updatable: %v,
+ updatable: true,
apps: [
"myapp",
],
@@ -9887,7 +9887,6 @@
}
android_app {
name: "myapp",
- updatable: %v,
apex_available: [
"myapex",
],
@@ -9895,42 +9894,10 @@
min_sdk_version: "30",
}
`
- testCases := []struct {
- name string
- apex_is_updatable_bp bool
- app_is_updatable_bp bool
- app_is_updatable_expected bool
- }{
- {
- name: "Non-updatable apex respects updatable property of non-updatable app",
- apex_is_updatable_bp: false,
- app_is_updatable_bp: false,
- app_is_updatable_expected: false,
- },
- {
- name: "Non-updatable apex respects updatable property of updatable app",
- apex_is_updatable_bp: false,
- app_is_updatable_bp: true,
- app_is_updatable_expected: true,
- },
- {
- name: "Updatable apex respects updatable property of updatable app",
- apex_is_updatable_bp: true,
- app_is_updatable_bp: true,
- app_is_updatable_expected: true,
- },
- {
- name: "Updatable apex sets updatable=true on non-updatable app",
- apex_is_updatable_bp: true,
- app_is_updatable_bp: false,
- app_is_updatable_expected: true,
- },
- }
- for _, testCase := range testCases {
- result := testApex(t, fmt.Sprintf(bp, testCase.apex_is_updatable_bp, testCase.app_is_updatable_bp))
- myapp := result.ModuleForTests("myapp", "android_common").Module().(*java.AndroidApp)
- android.AssertBoolEquals(t, testCase.name, testCase.app_is_updatable_expected, myapp.Updatable())
- }
+ _ = android.GroupFixturePreparers(
+ prepareForApexTest,
+ ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("app dependency myapp must have updatable: true")).
+ RunTestWithBp(t, bp)
}
func TestTrimmedApex(t *testing.T) {
@@ -11699,6 +11666,7 @@
sdk_version: "core_current",
min_sdk_version: "30",
manifest: "AndroidManifest.xml",
+ updatable: true,
}
`)
}
diff --git a/apex/builder.go b/apex/builder.go
index 4db20e9..371d7d5 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -1074,8 +1074,9 @@
}
return ""
}
- if a.overridableProperties.Package_name != "" {
- return a.overridableProperties.Package_name
+ packageNameFromProp := a.overridableProperties.Package_name.GetOrDefault(ctx, "")
+ if packageNameFromProp != "" {
+ return packageNameFromProp
}
manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
if overridden {
diff --git a/apex/vndk.go b/apex/vndk.go
index 3ececc5..5e630c0 100644
--- a/apex/vndk.go
+++ b/apex/vndk.go
@@ -20,6 +20,7 @@
"android/soong/android"
"android/soong/cc"
+ "github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -66,7 +67,14 @@
vndkApexName := "com.android.vndk." + vndkVersion
if mctx.OtherModuleExists(vndkApexName) {
- mctx.AddReverseDependency(mctx.Module(), sharedLibTag, vndkApexName)
+ // Reverse dependencies must exactly specify the variant they want, starting from the
+ // current module's variant. But unlike cc modules, the vndk apex doesn't have
+ // arch/image/link variations, so we explicitly remove them here.
+ mctx.AddReverseVariationDependency([]blueprint.Variation{
+ {Mutator: "arch", Variation: "common"},
+ {Mutator: "image", Variation: ""},
+ {Mutator: "link", Variation: ""},
+ }, sharedLibTag, vndkApexName)
}
} else if a, ok := mctx.Module().(*apexBundle); ok && a.vndkApex {
if a.IsNativeBridgeSupported() {
diff --git a/bazel/Android.bp b/bazel/Android.bp
deleted file mode 100644
index f8273a8..0000000
--- a/bazel/Android.bp
+++ /dev/null
@@ -1,22 +0,0 @@
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-bootstrap_go_package {
- name: "soong-bazel",
- pkgPath: "android/soong/bazel",
- srcs: [
- "configurability.go",
- "properties.go",
- "testing.go",
- ],
- testSrcs: [
- "properties_test.go",
- ],
- pluginFor: [
- "soong_build",
- ],
- deps: [
- "blueprint",
- ],
-}
diff --git a/bazel/configurability.go b/bazel/configurability.go
deleted file mode 100644
index 3a65614..0000000
--- a/bazel/configurability.go
+++ /dev/null
@@ -1,391 +0,0 @@
-// Copyright 2021 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 bazel
-
-import (
- "fmt"
- "math"
- "sort"
- "strings"
-)
-
-const (
- // ArchType names in arch.go
- archArm = "arm"
- archArm64 = "arm64"
- archRiscv64 = "riscv64"
- archX86 = "x86"
- archX86_64 = "x86_64"
-
- // OsType names in arch.go
- OsAndroid = "android"
- OsDarwin = "darwin"
- OsLinux = "linux_glibc"
- osLinuxMusl = "linux_musl"
- osLinuxBionic = "linux_bionic"
- OsWindows = "windows"
-
- // Targets in arch.go
- osArchAndroidArm = "android_arm"
- OsArchAndroidArm64 = "android_arm64"
- osArchAndroidRiscv64 = "android_riscv64"
- osArchAndroidX86 = "android_x86"
- osArchAndroidX86_64 = "android_x86_64"
- osArchDarwinArm64 = "darwin_arm64"
- osArchDarwinX86_64 = "darwin_x86_64"
- osArchLinuxX86 = "linux_glibc_x86"
- osArchLinuxX86_64 = "linux_glibc_x86_64"
- osArchLinuxMuslArm = "linux_musl_arm"
- osArchLinuxMuslArm64 = "linux_musl_arm64"
- osArchLinuxMuslX86 = "linux_musl_x86"
- osArchLinuxMuslX86_64 = "linux_musl_x86_64"
- osArchLinuxBionicArm64 = "linux_bionic_arm64"
- osArchLinuxBionicX86_64 = "linux_bionic_x86_64"
- osArchWindowsX86 = "windows_x86"
- osArchWindowsX86_64 = "windows_x86_64"
-
- // This is the string representation of the default condition wherever a
- // configurable attribute is used in a select statement, i.e.
- // //conditions:default for Bazel.
- //
- // This is consistently named "conditions_default" to mirror the Soong
- // config variable default key in an Android.bp file, although there's no
- // integration with Soong config variables (yet).
- ConditionsDefaultConfigKey = "conditions_default"
-
- ConditionsDefaultSelectKey = "//conditions:default"
-
- productVariableBazelPackage = "//build/bazel/product_config/config_settings"
-
- AndroidAndInApex = "android-in_apex"
- AndroidPlatform = "system"
- Unbundled_app = "unbundled_app"
-
- InApex = "in_apex"
- NonApex = "non_apex"
-
- ErrorproneDisabled = "errorprone_disabled"
- // TODO: b/294868620 - Remove when completing the bug
- SanitizersEnabled = "sanitizers_enabled"
-)
-
-func PowerSetWithoutEmptySet[T any](items []T) [][]T {
- resultSize := int(math.Pow(2, float64(len(items))))
- powerSet := make([][]T, 0, resultSize-1)
- for i := 1; i < resultSize; i++ {
- combination := make([]T, 0)
- for j := 0; j < len(items); j++ {
- if (i>>j)%2 == 1 {
- combination = append(combination, items[j])
- }
- }
- powerSet = append(powerSet, combination)
- }
- return powerSet
-}
-
-func createPlatformArchMap() map[string]string {
- // Copy of archFeatures from android/arch_list.go because the bazel
- // package can't access the android package
- archFeatures := map[string][]string{
- "arm": {},
- "arm64": {
- "dotprod",
- },
- "riscv64": {},
- "x86": {
- "ssse3",
- "sse4",
- "sse4_1",
- "sse4_2",
- "aes_ni",
- "avx",
- "avx2",
- "avx512",
- "popcnt",
- "movbe",
- },
- "x86_64": {
- "ssse3",
- "sse4",
- "sse4_1",
- "sse4_2",
- "aes_ni",
- "avx",
- "avx2",
- "avx512",
- "popcnt",
- },
- }
- result := make(map[string]string)
- for arch, allFeatures := range archFeatures {
- result[arch] = "//build/bazel_common_rules/platforms/arch:" + arch
- // Sometimes we want to select on multiple features being active, so
- // add the power set of all possible features to the map. More details
- // in android.ModuleBase.GetArchVariantProperties
- for _, features := range PowerSetWithoutEmptySet(allFeatures) {
- sort.Strings(features)
- archFeaturesName := arch + "-" + strings.Join(features, "-")
- result[archFeaturesName] = "//build/bazel/platforms/arch/variants:" + archFeaturesName
- }
- }
- result[ConditionsDefaultConfigKey] = ConditionsDefaultSelectKey
- return result
-}
-
-var (
- // These are the list of OSes and architectures with a Bazel config_setting
- // and constraint value equivalent. These exist in arch.go, but the android
- // package depends on the bazel package, so a cyclic dependency prevents
- // using those variables here.
-
- // A map of architectures to the Bazel label of the constraint_value
- // for the @platforms//cpu:cpu constraint_setting
- platformArchMap = createPlatformArchMap()
-
- // A map of target operating systems to the Bazel label of the
- // constraint_value for the @platforms//os:os constraint_setting
- platformOsMap = map[string]string{
- OsAndroid: "//build/bazel_common_rules/platforms/os:android",
- OsDarwin: "//build/bazel_common_rules/platforms/os:darwin",
- OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc",
- osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl",
- osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic",
- OsWindows: "//build/bazel_common_rules/platforms/os:windows",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
- }
-
- platformOsArchMap = map[string]string{
- osArchAndroidArm: "//build/bazel_common_rules/platforms/os_arch:android_arm",
- OsArchAndroidArm64: "//build/bazel_common_rules/platforms/os_arch:android_arm64",
- osArchAndroidRiscv64: "//build/bazel_common_rules/platforms/os_arch:android_riscv64",
- osArchAndroidX86: "//build/bazel_common_rules/platforms/os_arch:android_x86",
- osArchAndroidX86_64: "//build/bazel_common_rules/platforms/os_arch:android_x86_64",
- osArchDarwinArm64: "//build/bazel_common_rules/platforms/os_arch:darwin_arm64",
- osArchDarwinX86_64: "//build/bazel_common_rules/platforms/os_arch:darwin_x86_64",
- osArchLinuxX86: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86",
- osArchLinuxX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_glibc_x86_64",
- osArchLinuxMuslArm: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm",
- osArchLinuxMuslArm64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_arm64",
- osArchLinuxMuslX86: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86",
- osArchLinuxMuslX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_musl_x86_64",
- osArchLinuxBionicArm64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_arm64",
- osArchLinuxBionicX86_64: "//build/bazel_common_rules/platforms/os_arch:linux_bionic_x86_64",
- osArchWindowsX86: "//build/bazel_common_rules/platforms/os_arch:windows_x86",
- osArchWindowsX86_64: "//build/bazel_common_rules/platforms/os_arch:windows_x86_64",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey, // The default condition of an os select map.
- }
-
- // Map where keys are OsType names, and values are slices containing the archs
- // that that OS supports.
- // These definitions copied from arch.go.
- // TODO(cparsons): Source from arch.go; this task is nontrivial, as it currently results
- // in a cyclic dependency.
- osToArchMap = map[string][]string{
- OsAndroid: {archArm, archArm64, archRiscv64, archX86, archX86_64},
- OsLinux: {archX86, archX86_64},
- osLinuxMusl: {archX86, archX86_64},
- OsDarwin: {archArm64, archX86_64},
- osLinuxBionic: {archArm64, archX86_64},
- // TODO(cparsons): According to arch.go, this should contain archArm, archArm64, as well.
- OsWindows: {archX86, archX86_64},
- }
-
- osAndInApexMap = map[string]string{
- AndroidAndInApex: "//build/bazel/rules/apex:android-in_apex",
- AndroidPlatform: "//build/bazel/rules/apex:system",
- Unbundled_app: "//build/bazel/rules/apex:unbundled_app",
- OsDarwin: "//build/bazel_common_rules/platforms/os:darwin",
- OsLinux: "//build/bazel_common_rules/platforms/os:linux_glibc",
- osLinuxMusl: "//build/bazel_common_rules/platforms/os:linux_musl",
- osLinuxBionic: "//build/bazel_common_rules/platforms/os:linux_bionic",
- OsWindows: "//build/bazel_common_rules/platforms/os:windows",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- inApexMap = map[string]string{
- InApex: "//build/bazel/rules/apex:in_apex",
- NonApex: "//build/bazel/rules/apex:non_apex",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- errorProneMap = map[string]string{
- ErrorproneDisabled: "//build/bazel/rules/java/errorprone:errorprone_globally_disabled",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabledMap = map[string]string{
- SanitizersEnabled: "//build/bazel/rules/cc:sanitizers_enabled",
- ConditionsDefaultConfigKey: ConditionsDefaultSelectKey,
- }
-)
-
-// basic configuration types
-type configurationType int
-
-const (
- noConfig configurationType = iota
- arch
- os
- osArch
- productVariables
- osAndInApex
- inApex
- errorProneDisabled
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabled
-)
-
-func osArchString(os string, arch string) string {
- return fmt.Sprintf("%s_%s", os, arch)
-}
-
-func (ct configurationType) String() string {
- return map[configurationType]string{
- noConfig: "no_config",
- arch: "arch",
- os: "os",
- osArch: "arch_os",
- productVariables: "product_variables",
- osAndInApex: "os_in_apex",
- inApex: "in_apex",
- errorProneDisabled: "errorprone_disabled",
- // TODO: b/294868620 - Remove when completing the bug
- sanitizersEnabled: "sanitizers_enabled",
- }[ct]
-}
-
-func (ct configurationType) validateConfig(config string) {
- switch ct {
- case noConfig:
- if config != "" {
- panic(fmt.Errorf("Cannot specify config with %s, but got %s", ct, config))
- }
- case arch:
- if _, ok := platformArchMap[config]; !ok {
- panic(fmt.Errorf("Unknown arch: %s", config))
- }
- case os:
- if _, ok := platformOsMap[config]; !ok {
- panic(fmt.Errorf("Unknown os: %s", config))
- }
- case osArch:
- if _, ok := platformOsArchMap[config]; !ok {
- panic(fmt.Errorf("Unknown os+arch: %s", config))
- }
- case productVariables:
- // do nothing
- case osAndInApex:
- // do nothing
- // this axis can contain additional per-apex keys
- case inApex:
- if _, ok := inApexMap[config]; !ok {
- panic(fmt.Errorf("Unknown in_apex config: %s", config))
- }
- case errorProneDisabled:
- if _, ok := errorProneMap[config]; !ok {
- panic(fmt.Errorf("Unknown errorprone config: %s", config))
- }
- // TODO: b/294868620 - Remove when completing the bug
- case sanitizersEnabled:
- if _, ok := sanitizersEnabledMap[config]; !ok {
- panic(fmt.Errorf("Unknown sanitizers_enabled config: %s", config))
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ct))
- }
-}
-
-// SelectKey returns the Bazel select key for a given configurationType and config string.
-func (ca ConfigurationAxis) SelectKey(config string) string {
- ca.validateConfig(config)
- switch ca.configurationType {
- case noConfig:
- panic(fmt.Errorf("SelectKey is unnecessary for noConfig ConfigurationType "))
- case arch:
- return platformArchMap[config]
- case os:
- return platformOsMap[config]
- case osArch:
- return platformOsArchMap[config]
- case productVariables:
- if config == ConditionsDefaultConfigKey {
- return ConditionsDefaultSelectKey
- }
- return fmt.Sprintf("%s:%s", productVariableBazelPackage, config)
- case osAndInApex:
- if ret, exists := osAndInApexMap[config]; exists {
- return ret
- }
- return config
- case inApex:
- return inApexMap[config]
- case errorProneDisabled:
- return errorProneMap[config]
- // TODO: b/294868620 - Remove when completing the bug
- case sanitizersEnabled:
- return sanitizersEnabledMap[config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationType %d", ca.configurationType))
- }
-}
-
-var (
- // Indicating there is no configuration axis
- NoConfigAxis = ConfigurationAxis{configurationType: noConfig}
- // An axis for architecture-specific configurations
- ArchConfigurationAxis = ConfigurationAxis{configurationType: arch}
- // An axis for os-specific configurations
- OsConfigurationAxis = ConfigurationAxis{configurationType: os}
- // An axis for arch+os-specific configurations
- OsArchConfigurationAxis = ConfigurationAxis{configurationType: osArch}
- // An axis for os+in_apex-specific configurations
- OsAndInApexAxis = ConfigurationAxis{configurationType: osAndInApex}
- // An axis for in_apex-specific configurations
- InApexAxis = ConfigurationAxis{configurationType: inApex}
-
- ErrorProneAxis = ConfigurationAxis{configurationType: errorProneDisabled}
-
- // TODO: b/294868620 - Remove when completing the bug
- SanitizersEnabledAxis = ConfigurationAxis{configurationType: sanitizersEnabled}
-)
-
-// ProductVariableConfigurationAxis returns an axis for the given product variable
-func ProductVariableConfigurationAxis(archVariant bool, variable string) ConfigurationAxis {
- return ConfigurationAxis{
- configurationType: productVariables,
- subType: variable,
- archVariant: archVariant,
- }
-}
-
-// ConfigurationAxis is an independent axis for configuration, there should be no overlap between
-// elements within an axis.
-type ConfigurationAxis struct {
- configurationType
- // some configuration types (e.g. productVariables) have multiple independent axes, subType helps
- // distinguish between them without needing to list all 17 product variables.
- subType string
-
- archVariant bool
-}
-
-func (ca *ConfigurationAxis) less(other ConfigurationAxis) bool {
- if ca.configurationType == other.configurationType {
- return ca.subType < other.subType
- }
- return ca.configurationType < other.configurationType
-}
diff --git a/bazel/properties.go b/bazel/properties.go
deleted file mode 100644
index 9c63bc0..0000000
--- a/bazel/properties.go
+++ /dev/null
@@ -1,1467 +0,0 @@
-// Copyright 2020 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 bazel
-
-import (
- "fmt"
- "path/filepath"
- "reflect"
- "regexp"
- "sort"
- "strings"
-
- "github.com/google/blueprint"
-)
-
-// BazelTargetModuleProperties contain properties and metadata used for
-// Blueprint to BUILD file conversion.
-type BazelTargetModuleProperties struct {
- // The Bazel rule class for this target.
- Rule_class string `blueprint:"mutated"`
-
- // The target label for the bzl file containing the definition of the rule class.
- Bzl_load_location string `blueprint:"mutated"`
-}
-
-var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)")
-
-// Label is used to represent a Bazel compatible Label. Also stores the original
-// bp text to support string replacement.
-type Label struct {
- // The string representation of a Bazel target label. This can be a relative
- // or fully qualified label. These labels are used for generating BUILD
- // files with bp2build.
- Label string
-
- // The original Soong/Blueprint module name that the label was derived from.
- // This is used for replacing references to the original name with the new
- // label, for example in genrule cmds.
- //
- // While there is a reversible 1:1 mapping from the module name to Bazel
- // label with bp2build that could make computing the original module name
- // from the label automatic, it is not the case for handcrafted targets,
- // where modules can have a custom label mapping through the { bazel_module:
- // { label: <label> } } property.
- //
- // With handcrafted labels, those modules don't go through bp2build
- // conversion, but relies on handcrafted targets in the source tree.
- OriginalModuleName string
-}
-
-// LabelList is used to represent a list of Bazel labels.
-type LabelList struct {
- Includes []Label
- Excludes []Label
-}
-
-// MakeLabelList creates a LabelList from a list Label
-func MakeLabelList(labels []Label) LabelList {
- return LabelList{
- Includes: labels,
- Excludes: nil,
- }
-}
-
-func SortedConfigurationAxes[T any](m map[ConfigurationAxis]T) []ConfigurationAxis {
- keys := make([]ConfigurationAxis, 0, len(m))
- for k := range m {
- keys = append(keys, k)
- }
-
- sort.Slice(keys, func(i, j int) bool { return keys[i].less(keys[j]) })
- return keys
-}
-
-// MakeLabelListFromTargetNames creates a LabelList from unqualified target names
-// This is a utiltity function for bp2build converters of Soong modules that have 1:many generated targets
-func MakeLabelListFromTargetNames(targetNames []string) LabelList {
- labels := []Label{}
- for _, name := range targetNames {
- label := Label{Label: ":" + name}
- labels = append(labels, label)
- }
- return MakeLabelList(labels)
-}
-
-func (ll *LabelList) Equals(other LabelList) bool {
- if len(ll.Includes) != len(other.Includes) || len(ll.Excludes) != len(other.Excludes) {
- return false
- }
- for i, _ := range ll.Includes {
- if ll.Includes[i] != other.Includes[i] {
- return false
- }
- }
- for i, _ := range ll.Excludes {
- if ll.Excludes[i] != other.Excludes[i] {
- return false
- }
- }
- return true
-}
-
-func (ll *LabelList) IsNil() bool {
- return ll.Includes == nil && ll.Excludes == nil
-}
-
-func (ll *LabelList) IsEmpty() bool {
- return len(ll.Includes) == 0 && len(ll.Excludes) == 0
-}
-
-func (ll *LabelList) deepCopy() LabelList {
- return LabelList{
- Includes: ll.Includes[:],
- Excludes: ll.Excludes[:],
- }
-}
-
-// uniqueParentDirectories returns a list of the unique parent directories for
-// all files in ll.Includes.
-func (ll *LabelList) uniqueParentDirectories() []string {
- dirMap := map[string]bool{}
- for _, label := range ll.Includes {
- dirMap[filepath.Dir(label.Label)] = true
- }
- dirs := []string{}
- for dir := range dirMap {
- dirs = append(dirs, dir)
- }
- return dirs
-}
-
-// Add inserts the label Label at the end of the LabelList.Includes.
-func (ll *LabelList) Add(label *Label) {
- if label == nil {
- return
- }
- ll.Includes = append(ll.Includes, *label)
-}
-
-// AddExclude inserts the label Label at the end of the LabelList.Excludes.
-func (ll *LabelList) AddExclude(label *Label) {
- if label == nil {
- return
- }
- ll.Excludes = append(ll.Excludes, *label)
-}
-
-// Append appends the fields of other labelList to the corresponding fields of ll.
-func (ll *LabelList) Append(other LabelList) {
- if len(ll.Includes) > 0 || len(other.Includes) > 0 {
- ll.Includes = append(ll.Includes, other.Includes...)
- }
- if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
- ll.Excludes = append(ll.Excludes, other.Excludes...)
- }
-}
-
-// Partition splits a LabelList into two LabelLists depending on the return value
-// of the predicate.
-// This function preserves the Includes and Excludes, but it does not provide
-// that information to the partition function.
-func (ll *LabelList) Partition(predicate func(label Label) bool) (LabelList, LabelList) {
- predicated := LabelList{}
- unpredicated := LabelList{}
- for _, include := range ll.Includes {
- if predicate(include) {
- predicated.Add(&include)
- } else {
- unpredicated.Add(&include)
- }
- }
- for _, exclude := range ll.Excludes {
- if predicate(exclude) {
- predicated.AddExclude(&exclude)
- } else {
- unpredicated.AddExclude(&exclude)
- }
- }
- return predicated, unpredicated
-}
-
-// UniqueSortedBazelLabels takes a []Label and deduplicates the labels, and returns
-// the slice in a sorted order.
-func UniqueSortedBazelLabels(originalLabels []Label) []Label {
- uniqueLabels := FirstUniqueBazelLabels(originalLabels)
- sort.SliceStable(uniqueLabels, func(i, j int) bool {
- return uniqueLabels[i].Label < uniqueLabels[j].Label
- })
- return uniqueLabels
-}
-
-func FirstUniqueBazelLabels(originalLabels []Label) []Label {
- var labels []Label
- found := make(map[string]bool, len(originalLabels))
- for _, l := range originalLabels {
- if _, ok := found[l.Label]; ok {
- continue
- }
- labels = append(labels, l)
- found[l.Label] = true
- }
- return labels
-}
-
-func FirstUniqueBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = FirstUniqueBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = FirstUniqueBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
-}
-
-func UniqueSortedBazelLabelList(originalLabelList LabelList) LabelList {
- var uniqueLabelList LabelList
- uniqueLabelList.Includes = UniqueSortedBazelLabels(originalLabelList.Includes)
- uniqueLabelList.Excludes = UniqueSortedBazelLabels(originalLabelList.Excludes)
- return uniqueLabelList
-}
-
-// Subtract needle from haystack
-func SubtractStrings(haystack []string, needle []string) []string {
- // This is really a set
- needleMap := make(map[string]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
-
- var strings []string
- for _, s := range haystack {
- if exclude := needleMap[s]; !exclude {
- strings = append(strings, s)
- }
- }
-
- return strings
-}
-
-// Subtract needle from haystack
-func SubtractBazelLabels(haystack []Label, needle []Label) []Label {
- // This is really a set
- needleMap := make(map[Label]bool)
- for _, s := range needle {
- needleMap[s] = true
- }
-
- var labels []Label
- for _, label := range haystack {
- if exclude := needleMap[label]; !exclude {
- labels = append(labels, label)
- }
- }
-
- return labels
-}
-
-// Appends two LabelLists, returning the combined list.
-func AppendBazelLabelLists(a LabelList, b LabelList) LabelList {
- var result LabelList
- result.Includes = append(a.Includes, b.Includes...)
- result.Excludes = append(a.Excludes, b.Excludes...)
- return result
-}
-
-// Subtract needle from haystack
-func SubtractBazelLabelList(haystack LabelList, needle LabelList) LabelList {
- var result LabelList
- result.Includes = SubtractBazelLabels(haystack.Includes, needle.Includes)
- // NOTE: Excludes are intentionally not subtracted
- result.Excludes = haystack.Excludes
- return result
-}
-
-// FirstUniqueBazelLabelListAttribute takes a LabelListAttribute and makes the LabelList for
-// each axis/configuration by keeping the first instance of a Label and omitting all subsequent
-// repetitions.
-func FirstUniqueBazelLabelListAttribute(attr LabelListAttribute) LabelListAttribute {
- var result LabelListAttribute
- result.Value = FirstUniqueBazelLabelList(attr.Value)
- if attr.HasConfigurableValues() {
- result.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, configToLabels := range attr.ConfigurableValues {
- for c, l := range configToLabels {
- result.SetSelectValue(axis, c, FirstUniqueBazelLabelList(l))
- }
- }
-
- return result
-}
-
-// SubtractBazelLabelListAttribute subtract needle from haystack for LabelList in each
-// axis/configuration.
-func SubtractBazelLabelListAttribute(haystack LabelListAttribute, needle LabelListAttribute) LabelListAttribute {
- var result LabelListAttribute
- result.Value = SubtractBazelLabelList(haystack.Value, needle.Value)
- if haystack.HasConfigurableValues() {
- result.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, configToLabels := range haystack.ConfigurableValues {
- for haystackConfig, haystackLabels := range configToLabels {
- result.SetSelectValue(axis, haystackConfig, SubtractBazelLabelList(haystackLabels, needle.SelectValue(axis, haystackConfig)))
- }
- }
-
- return result
-}
-
-type Attribute interface {
- HasConfigurableValues() bool
-}
-
-type labelSelectValues map[string]*Label
-
-type configurableLabels map[ConfigurationAxis]labelSelectValues
-
-func (cl configurableLabels) setValueForAxis(axis ConfigurationAxis, config string, value *Label) {
- if cl[axis] == nil {
- cl[axis] = make(labelSelectValues)
- }
- cl[axis][config] = value
-}
-
-// Represents an attribute whose value is a single label
-type LabelAttribute struct {
- Value *Label
-
- ConfigurableValues configurableLabels
-}
-
-func (la *LabelAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range la.ConfigurableValues {
- if len(la.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// Collapse reduces the configurable axes of the label attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable label
-// attribute can only be comprised by a single select.
-func (la *LabelAttribute) Collapse() error {
- axisTypes := la.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- if containsArch {
- allProductVariablesAreArchVariant := true
- for k := range la.ConfigurableValues {
- if k.configurationType == productVariables && !k.archVariant {
- allProductVariablesAreArchVariant = false
- }
- }
- if !allProductVariablesAreArchVariant {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- } else {
- return fmt.Errorf("label attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := la.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := la.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := la.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- } else if osVal != nil && archVal == nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *osVal)
- } else if osVal == nil && archVal != nil {
- la.SetSelectValue(OsArchConfigurationAxis, osArch, *archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(la.ConfigurableValues, ArchConfigurationAxis)
- delete(la.ConfigurableValues, OsConfigurationAxis)
- }
- return nil
-}
-
-// HasConfigurableValues returns whether there are configurable values set for this label.
-func (la LabelAttribute) HasConfigurableValues() bool {
- for _, selectValues := range la.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets the base, non-configured value for the Label
-func (la *LabelAttribute) SetValue(value Label) {
- la.SetSelectValue(NoConfigAxis, "", value)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (la *LabelAttribute) SetSelectValue(axis ConfigurationAxis, config string, value Label) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- la.Value = &value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if la.ConfigurableValues == nil {
- la.ConfigurableValues = make(configurableLabels)
- }
- la.ConfigurableValues.setValueForAxis(axis, config, &value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (la *LabelAttribute) SelectValue(axis ConfigurationAxis, config string) *Label {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return la.Value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- return la.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (la *LabelAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(la.ConfigurableValues)
-}
-
-// MakeLabelAttribute turns a string into a LabelAttribute
-func MakeLabelAttribute(label string) *LabelAttribute {
- return &LabelAttribute{
- Value: &Label{
- Label: label,
- },
- }
-}
-
-type configToBools map[string]bool
-
-func (ctb configToBools) setValue(config string, value *bool) {
- if value == nil {
- if _, ok := ctb[config]; ok {
- delete(ctb, config)
- }
- return
- }
- ctb[config] = *value
-}
-
-type configurableBools map[ConfigurationAxis]configToBools
-
-func (cb configurableBools) setValueForAxis(axis ConfigurationAxis, config string, value *bool) {
- if cb[axis] == nil {
- cb[axis] = make(configToBools)
- }
- cb[axis].setValue(config, value)
-}
-
-// BoolAttribute represents an attribute whose value is a single bool but may be configurable..
-type BoolAttribute struct {
- Value *bool
-
- ConfigurableValues configurableBools
-}
-
-// HasConfigurableValues returns whether there are configurable values for this attribute.
-func (ba BoolAttribute) HasConfigurableValues() bool {
- for _, cfgToBools := range ba.ConfigurableValues {
- if len(cfgToBools) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets value for the no config axis
-func (ba *BoolAttribute) SetValue(value *bool) {
- ba.SetSelectValue(NoConfigAxis, "", value)
-}
-
-// SetSelectValue sets value for the given axis/config.
-func (ba *BoolAttribute) SetSelectValue(axis ConfigurationAxis, config string, value *bool) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- ba.Value = value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if ba.ConfigurableValues == nil {
- ba.ConfigurableValues = make(configurableBools)
- }
- ba.ConfigurableValues.setValueForAxis(axis, config, value)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// ToLabelListAttribute creates and returns a LabelListAttribute from this
-// bool attribute, where each bool in this attribute corresponds to a
-// label list value in the resultant attribute.
-func (ba *BoolAttribute) ToLabelListAttribute(falseVal LabelList, trueVal LabelList) (LabelListAttribute, error) {
- getLabelList := func(boolPtr *bool) LabelList {
- if boolPtr == nil {
- return LabelList{nil, nil}
- } else if *boolPtr {
- return trueVal
- } else {
- return falseVal
- }
- }
-
- mainVal := getLabelList(ba.Value)
- if !ba.HasConfigurableValues() {
- return MakeLabelListAttribute(mainVal), nil
- }
-
- result := LabelListAttribute{}
- if err := ba.Collapse(); err != nil {
- return result, err
- }
-
- for axis, configToBools := range ba.ConfigurableValues {
- if len(configToBools) < 1 {
- continue
- }
- for config, boolPtr := range configToBools {
- val := getLabelList(&boolPtr)
- if !val.Equals(mainVal) {
- result.SetSelectValue(axis, config, val)
- }
- }
- result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
- }
-
- return result, nil
-}
-
-// ToStringListAttribute creates a StringListAttribute from this BoolAttribute,
-// where each bool corresponds to a string list value generated by the provided
-// function.
-// TODO(b/271425661): Generalize this
-func (ba *BoolAttribute) ToStringListAttribute(valueFunc func(boolPtr *bool, axis ConfigurationAxis, config string) []string) (StringListAttribute, error) {
- mainVal := valueFunc(ba.Value, NoConfigAxis, "")
- if !ba.HasConfigurableValues() {
- return MakeStringListAttribute(mainVal), nil
- }
-
- result := StringListAttribute{}
- if err := ba.Collapse(); err != nil {
- return result, err
- }
-
- for axis, configToBools := range ba.ConfigurableValues {
- if len(configToBools) < 1 {
- continue
- }
- for config, boolPtr := range configToBools {
- val := valueFunc(&boolPtr, axis, config)
- if !reflect.DeepEqual(val, mainVal) {
- result.SetSelectValue(axis, config, val)
- }
- }
- result.SetSelectValue(axis, ConditionsDefaultConfigKey, mainVal)
- }
-
- return result, nil
-}
-
-// Collapse reduces the configurable axes of the boolean attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable boolean
-// attribute can only be comprised by a single select.
-func (ba *BoolAttribute) Collapse() error {
- axisTypes := ba.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("boolean attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := ba.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := ba.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := ba.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- ba.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- // All os_arch values are now set. Clear os and arch axes.
- delete(ba.ConfigurableValues, ArchConfigurationAxis)
- delete(ba.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(ba.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", ba))
- }
- }
- return nil
-}
-
-func (ba *BoolAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range ba.ConfigurableValues {
- if len(ba.ConfigurableValues[k]) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// SelectValue gets the value for the given axis/config.
-func (ba BoolAttribute) SelectValue(axis ConfigurationAxis, config string) *bool {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return ba.Value
- case arch, os, osArch, productVariables, osAndInApex, sanitizersEnabled:
- if v, ok := ba.ConfigurableValues[axis][config]; ok {
- return &v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (ba *BoolAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(ba.ConfigurableValues)
-}
-
-// labelListSelectValues supports config-specific label_list typed Bazel attribute values.
-type labelListSelectValues map[string]LabelList
-
-func (ll labelListSelectValues) addSelects(label labelSelectValues) {
- for k, v := range label {
- if label == nil {
- continue
- }
- l := ll[k]
- (&l).Add(v)
- ll[k] = l
- }
-}
-
-func (ll labelListSelectValues) appendSelects(other labelListSelectValues, forceSpecifyEmptyList bool) {
- for k, v := range other {
- l := ll[k]
- if forceSpecifyEmptyList && l.IsNil() && !v.IsNil() {
- l.Includes = []Label{}
- }
- (&l).Append(v)
- ll[k] = l
- }
-}
-
-// HasConfigurableValues returns whether there are configurable values within this set of selects.
-func (ll labelListSelectValues) HasConfigurableValues() bool {
- for _, v := range ll {
- if v.Includes != nil {
- return true
- }
- }
- return false
-}
-
-// LabelListAttribute is used to represent a list of Bazel labels as an
-// attribute.
-type LabelListAttribute struct {
- // The non-configured attribute label list Value. Required.
- Value LabelList
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableLabelLists
-
- // If true, differentiate between "nil" and "empty" list. nil means that
- // this attribute should not be specified at all, and "empty" means that
- // the attribute should be explicitly specified as an empty list.
- // This mode facilitates use of attribute defaults: an empty list should
- // override the default.
- ForceSpecifyEmptyList bool
-
- // If true, signal the intent to the code generator to emit all select keys,
- // even if the Includes list for that key is empty. This mode facilitates
- // specific select statements where an empty list for a non-default select
- // key has a meaning.
- EmitEmptyList bool
-
- // If a property has struct tag "variant_prepend", this value should
- // be set to True, so that when bp2build generates BUILD.bazel, variant
- // properties(select ...) come before general properties.
- Prepend bool
-}
-
-type configurableLabelLists map[ConfigurationAxis]labelListSelectValues
-
-func (cll configurableLabelLists) setValueForAxis(axis ConfigurationAxis, config string, list LabelList) {
- if list.IsNil() {
- if _, ok := cll[axis][config]; ok {
- delete(cll[axis], config)
- }
- return
- }
- if cll[axis] == nil {
- cll[axis] = make(labelListSelectValues)
- }
-
- cll[axis][config] = list
-}
-
-func (cll configurableLabelLists) Append(other configurableLabelLists, forceSpecifyEmptyList bool) {
- for axis, otherSelects := range other {
- selects := cll[axis]
- if selects == nil {
- selects = make(labelListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects, forceSpecifyEmptyList)
- cll[axis] = selects
- }
-}
-
-func (lla *LabelListAttribute) Clone() *LabelListAttribute {
- result := &LabelListAttribute{ForceSpecifyEmptyList: lla.ForceSpecifyEmptyList}
- return result.Append(*lla)
-}
-
-// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value.
-func MakeLabelListAttribute(value LabelList) LabelListAttribute {
- return LabelListAttribute{
- Value: value,
- ConfigurableValues: make(configurableLabelLists),
- }
-}
-
-// MakeSingleLabelListAttribute initializes a LabelListAttribute as a non-arch specific list with 1 element, the given Label.
-func MakeSingleLabelListAttribute(value Label) LabelListAttribute {
- return MakeLabelListAttribute(MakeLabelList([]Label{value}))
-}
-
-func (lla *LabelListAttribute) SetValue(list LabelList) {
- lla.SetSelectValue(NoConfigAxis, "", list)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (lla *LabelListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list LabelList) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- lla.Value = list
- case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (lla *LabelListAttribute) SelectValue(axis ConfigurationAxis, config string) LabelList {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return lla.Value
- case arch, os, osArch, productVariables, osAndInApex, inApex, errorProneDisabled, sanitizersEnabled:
- return lla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (lla *LabelListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(lla.ConfigurableValues)
-}
-
-// Append all values, including os and arch specific ones, from another
-// LabelListAttribute to this LabelListAttribute. Returns this LabelListAttribute.
-func (lla *LabelListAttribute) Append(other LabelListAttribute) *LabelListAttribute {
- forceSpecifyEmptyList := lla.ForceSpecifyEmptyList || other.ForceSpecifyEmptyList
- if forceSpecifyEmptyList && lla.Value.IsNil() && !other.Value.IsNil() {
- lla.Value.Includes = []Label{}
- }
- lla.Value.Append(other.Value)
- if lla.ConfigurableValues == nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- lla.ConfigurableValues.Append(other.ConfigurableValues, forceSpecifyEmptyList)
- return lla
-}
-
-// Add inserts the labels for each axis of LabelAttribute at the end of corresponding axis's
-// LabelList within the LabelListAttribute
-func (lla *LabelListAttribute) Add(label *LabelAttribute) {
- if label == nil {
- return
- }
-
- lla.Value.Add(label.Value)
- if lla.ConfigurableValues == nil && label.ConfigurableValues != nil {
- lla.ConfigurableValues = make(configurableLabelLists)
- }
- for axis, _ := range label.ConfigurableValues {
- if _, exists := lla.ConfigurableValues[axis]; !exists {
- lla.ConfigurableValues[axis] = make(labelListSelectValues)
- }
- lla.ConfigurableValues[axis].addSelects(label.ConfigurableValues[axis])
- }
-}
-
-// HasConfigurableValues returns true if the attribute contains axis-specific label list values.
-func (lla LabelListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range lla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// HasAxisSpecificValues returns true if the attribute contains axis specific label list values from a given axis
-func (lla LabelListAttribute) HasAxisSpecificValues(axis ConfigurationAxis) bool {
- for _, values := range lla.ConfigurableValues[axis] {
- if !values.IsNil() {
- return true
- }
- }
- return false
-}
-
-// IsEmpty returns true if the attribute has no values under any configuration.
-func (lla LabelListAttribute) IsEmpty() bool {
- if len(lla.Value.Includes) > 0 {
- return false
- }
- for axis, _ := range lla.ConfigurableValues {
- if lla.ConfigurableValues[axis].HasConfigurableValues() {
- return false
- }
- }
- return true
-}
-
-// IsNil returns true if the attribute has not been set for any configuration.
-func (lla LabelListAttribute) IsNil() bool {
- if lla.Value.Includes != nil {
- return false
- }
- return !lla.HasConfigurableValues()
-}
-
-// Exclude for the given axis, config, removes Includes in labelList from Includes and appends them
-// to Excludes. This is to special case any excludes that are not specified in a bp file but need to
-// be removed, e.g. if they could cause duplicate element failures.
-func (lla *LabelListAttribute) Exclude(axis ConfigurationAxis, config string, labelList LabelList) {
- val := lla.SelectValue(axis, config)
- newList := SubtractBazelLabelList(val, labelList)
- newList.Excludes = append(newList.Excludes, labelList.Includes...)
- lla.SetSelectValue(axis, config, newList)
-}
-
-// ResolveExcludes handles excludes across the various axes, ensuring that items are removed from
-// the base value and included in default values as appropriate.
-func (lla *LabelListAttribute) ResolveExcludes() {
- // If there are OsAndInApexAxis, we need to use
- // * includes from the OS & in APEX Axis for non-Android configs for libraries that need to be
- // included in non-Android OSes
- // * excludes from the OS Axis for non-Android configs, to exclude libraries that should _not_
- // be included in the non-Android OSes
- if _, ok := lla.ConfigurableValues[OsAndInApexAxis]; ok {
- inApexLabels := lla.ConfigurableValues[OsAndInApexAxis][ConditionsDefaultConfigKey]
- for config, labels := range lla.ConfigurableValues[OsConfigurationAxis] {
- // OsAndroid has already handled its excludes.
- // We only need to copy the excludes from other arches, so if there are none, skip it.
- if config == OsAndroid || len(labels.Excludes) == 0 {
- continue
- }
- lla.ConfigurableValues[OsAndInApexAxis][config] = LabelList{
- Includes: inApexLabels.Includes,
- Excludes: labels.Excludes,
- }
- }
- }
-
- for axis, configToLabels := range lla.ConfigurableValues {
- baseLabels := lla.Value.deepCopy()
- for config, val := range configToLabels {
- // Exclude config-specific excludes from base value
- lla.Value = SubtractBazelLabelList(lla.Value, LabelList{Includes: val.Excludes})
-
- // add base values to config specific to add labels excluded by others in this axis
- // then remove all config-specific excludes
- allLabels := baseLabels.deepCopy()
- allLabels.Append(val)
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(allLabels, LabelList{Includes: allLabels.Excludes})
- }
-
- // After going through all configs, delete the duplicates in the config
- // values that are already in the base Value.
- for config, val := range configToLabels {
- lla.ConfigurableValues[axis][config] = SubtractBazelLabelList(val, lla.Value)
- }
-
- // Now that the Value list is finalized for this axis, compare it with
- // the original list, and union the difference with the default
- // condition for the axis.
- difference := SubtractBazelLabelList(baseLabels, lla.Value)
- existingDefaults := lla.ConfigurableValues[axis][ConditionsDefaultConfigKey]
- existingDefaults.Append(difference)
- lla.ConfigurableValues[axis][ConditionsDefaultConfigKey] = FirstUniqueBazelLabelList(existingDefaults)
-
- // if everything ends up without includes, just delete the axis
- if !lla.ConfigurableValues[axis].HasConfigurableValues() {
- delete(lla.ConfigurableValues, axis)
- }
- }
-}
-
-// Partition splits a LabelListAttribute into two LabelListAttributes depending
-// on the return value of the predicate.
-// This function preserves the Includes and Excludes, but it does not provide
-// that information to the partition function.
-func (lla LabelListAttribute) Partition(predicate func(label Label) bool) (LabelListAttribute, LabelListAttribute) {
- predicated := LabelListAttribute{}
- unpredicated := LabelListAttribute{}
-
- valuePartitionTrue, valuePartitionFalse := lla.Value.Partition(predicate)
- predicated.SetValue(valuePartitionTrue)
- unpredicated.SetValue(valuePartitionFalse)
-
- for axis, selectValueLabelLists := range lla.ConfigurableValues {
- for config, labelList := range selectValueLabelLists {
- configPredicated, configUnpredicated := labelList.Partition(predicate)
- predicated.SetSelectValue(axis, config, configPredicated)
- unpredicated.SetSelectValue(axis, config, configUnpredicated)
- }
- }
-
- return predicated, unpredicated
-}
-
-// OtherModuleContext is a limited context that has methods with information about other modules.
-type OtherModuleContext interface {
- ModuleFromName(name string) (blueprint.Module, bool)
- OtherModuleType(m blueprint.Module) string
- OtherModuleName(m blueprint.Module) string
- OtherModuleDir(m blueprint.Module) string
- ModuleErrorf(fmt string, args ...interface{})
-}
-
-// LabelMapper is a function that takes a OtherModuleContext and returns a (potentially changed)
-// label and whether it was changed.
-type LabelMapper func(OtherModuleContext, Label) (string, bool)
-
-// LabelPartition contains descriptions of a partition for labels
-type LabelPartition struct {
- // Extensions to include in this partition
- Extensions []string
- // LabelMapper is a function that can map a label to a new label, and indicate whether to include
- // the mapped label in the partition
- LabelMapper LabelMapper
- // Whether to store files not included in any other partition in a group of LabelPartitions
- // Only one partition in a group of LabelPartitions can enabled Keep_remainder
- Keep_remainder bool
-}
-
-// LabelPartitions is a map of partition name to a LabelPartition describing the elements of the
-// partition
-type LabelPartitions map[string]LabelPartition
-
-// filter returns a pointer to a label if the label should be included in the partition or nil if
-// not.
-func (lf LabelPartition) filter(ctx OtherModuleContext, label Label) *Label {
- if lf.LabelMapper != nil {
- if newLabel, changed := lf.LabelMapper(ctx, label); changed {
- return &Label{newLabel, label.OriginalModuleName}
- }
- }
- for _, ext := range lf.Extensions {
- if strings.HasSuffix(label.Label, ext) {
- return &label
- }
- }
-
- return nil
-}
-
-// PartitionToLabelListAttribute is map of partition name to a LabelListAttribute
-type PartitionToLabelListAttribute map[string]LabelListAttribute
-
-type partitionToLabelList map[string]*LabelList
-
-func (p partitionToLabelList) appendIncludes(partition string, label Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Includes = append(p[partition].Includes, label)
-}
-
-func (p partitionToLabelList) excludes(partition string, excludes []Label) {
- if _, ok := p[partition]; !ok {
- p[partition] = &LabelList{}
- }
- p[partition].Excludes = excludes
-}
-
-// PartitionLabelListAttribute partitions a LabelListAttribute into the requested partitions
-func PartitionLabelListAttribute(ctx OtherModuleContext, lla *LabelListAttribute, partitions LabelPartitions) PartitionToLabelListAttribute {
- ret := PartitionToLabelListAttribute{}
- var partitionNames []string
- // Stored as a pointer to distinguish nil (no remainder partition) from empty string partition
- var remainderPartition *string
- for p, f := range partitions {
- partitionNames = append(partitionNames, p)
- if f.Keep_remainder {
- if remainderPartition != nil {
- panic("only one partition can store the remainder")
- }
- // If we take the address of p in a loop, we'll end up with the last value of p in
- // remainderPartition, we want the requested partition
- capturePartition := p
- remainderPartition = &capturePartition
- }
- }
-
- partitionLabelList := func(axis ConfigurationAxis, config string) {
- value := lla.SelectValue(axis, config)
- partitionToLabels := partitionToLabelList{}
- for _, item := range value.Includes {
- wasFiltered := false
- var inPartition *string
- for partition, f := range partitions {
- filtered := f.filter(ctx, item)
- if filtered == nil {
- // did not match this filter, keep looking
- continue
- }
- wasFiltered = true
- partitionToLabels.appendIncludes(partition, *filtered)
- // don't need to check other partitions if this filter used the item,
- // continue checking if mapped to another name
- if *filtered == item {
- if inPartition != nil {
- ctx.ModuleErrorf("%q was found in multiple partitions: %q, %q", item.Label, *inPartition, partition)
- }
- capturePartition := partition
- inPartition = &capturePartition
- }
- }
-
- // if not specified in a partition, add to remainder partition if one exists
- if !wasFiltered && remainderPartition != nil {
- partitionToLabels.appendIncludes(*remainderPartition, item)
- }
- }
-
- // ensure empty lists are maintained
- if value.Excludes != nil {
- for _, partition := range partitionNames {
- partitionToLabels.excludes(partition, value.Excludes)
- }
- }
-
- for partition, list := range partitionToLabels {
- val := ret[partition]
- (&val).SetSelectValue(axis, config, *list)
- ret[partition] = val
- }
- }
-
- partitionLabelList(NoConfigAxis, "")
- for axis, configToList := range lla.ConfigurableValues {
- for config, _ := range configToList {
- partitionLabelList(axis, config)
- }
- }
- return ret
-}
-
-// StringAttribute corresponds to the string Bazel attribute type with
-// support for additional metadata, like configurations.
-type StringAttribute struct {
- // The base value of the string attribute.
- Value *string
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStrings
-}
-
-type configurableStrings map[ConfigurationAxis]stringSelectValues
-
-func (cs configurableStrings) setValueForAxis(axis ConfigurationAxis, config string, str *string) {
- if cs[axis] == nil {
- cs[axis] = make(stringSelectValues)
- }
- cs[axis][config] = str
-}
-
-type stringSelectValues map[string]*string
-
-// HasConfigurableValues returns true if the attribute contains axis-specific string values.
-func (sa StringAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sa.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// SetValue sets the base, non-configured value for the Label
-func (sa *StringAttribute) SetValue(value string) {
- sa.SetSelectValue(NoConfigAxis, "", &value)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (sa *StringAttribute) SetSelectValue(axis ConfigurationAxis, config string, str *string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sa.Value = str
- case arch, os, osArch, productVariables, sanitizersEnabled:
- if sa.ConfigurableValues == nil {
- sa.ConfigurableValues = make(configurableStrings)
- }
- sa.ConfigurableValues.setValueForAxis(axis, config, str)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (sa *StringAttribute) SelectValue(axis ConfigurationAxis, config string) *string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sa.Value
- case arch, os, osArch, productVariables, sanitizersEnabled:
- if v, ok := sa.ConfigurableValues[axis][config]; ok {
- return v
- } else {
- return nil
- }
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (sa *StringAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(sa.ConfigurableValues)
-}
-
-// Collapse reduces the configurable axes of the string attribute to a single axis.
-// This is necessary for final writing to bp2build, as a configurable string
-// attribute can only be comprised by a single select.
-func (sa *StringAttribute) Collapse() error {
- axisTypes := sa.axisTypes()
- _, containsOs := axisTypes[os]
- _, containsArch := axisTypes[arch]
- _, containsOsArch := axisTypes[osArch]
- _, containsProductVariables := axisTypes[productVariables]
- if containsProductVariables {
- if containsOs || containsArch || containsOsArch {
- return fmt.Errorf("string attribute could not be collapsed as it has two or more unrelated axes")
- }
- }
- if (containsOs && containsArch) || (containsOsArch && (containsOs || containsArch)) {
- // If a bool attribute has both os and arch configuration axes, the only
- // way to successfully union their values is to increase the granularity
- // of the configuration criteria to os_arch.
- for osType, supportedArchs := range osToArchMap {
- for _, supportedArch := range supportedArchs {
- osArch := osArchString(osType, supportedArch)
- if archOsVal := sa.SelectValue(OsArchConfigurationAxis, osArch); archOsVal != nil {
- // Do nothing, as the arch_os is explicitly defined already.
- } else {
- archVal := sa.SelectValue(ArchConfigurationAxis, supportedArch)
- osVal := sa.SelectValue(OsConfigurationAxis, osType)
- if osVal != nil && archVal != nil {
- // In this case, arch takes precedence. (This fits legacy Soong behavior, as arch mutator
- // runs after os mutator.
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- } else if osVal != nil && archVal == nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, osVal)
- } else if osVal == nil && archVal != nil {
- sa.SetSelectValue(OsArchConfigurationAxis, osArch, archVal)
- }
- }
- }
- }
- /// All os_arch values are now set. Clear os and arch axes.
- delete(sa.ConfigurableValues, ArchConfigurationAxis)
- delete(sa.ConfigurableValues, OsConfigurationAxis)
- // Verify post-condition; this should never fail, provided no additional
- // axes are introduced.
- if len(sa.ConfigurableValues) > 1 {
- panic(fmt.Errorf("error in collapsing attribute: %#v", sa))
- }
- } else if containsProductVariables {
- usedBaseValue := false
- for a, configToProp := range sa.ConfigurableValues {
- if a.configurationType == productVariables {
- for c, p := range configToProp {
- if p == nil {
- sa.SetSelectValue(a, c, sa.Value)
- usedBaseValue = true
- }
- }
- }
- }
- if usedBaseValue {
- sa.Value = nil
- }
- }
- return nil
-}
-
-func (sa *StringAttribute) axisTypes() map[configurationType]bool {
- types := map[configurationType]bool{}
- for k := range sa.ConfigurableValues {
- if strs := sa.ConfigurableValues[k]; len(strs) > 0 {
- types[k.configurationType] = true
- }
- }
- return types
-}
-
-// StringListAttribute corresponds to the string_list Bazel attribute type with
-// support for additional metadata, like configurations.
-type StringListAttribute struct {
- // The base value of the string list attribute.
- Value []string
-
- // The configured attribute label list Values. Optional
- // a map of independent configurability axes
- ConfigurableValues configurableStringLists
-
- // If a property has struct tag "variant_prepend", this value should
- // be set to True, so that when bp2build generates BUILD.bazel, variant
- // properties(select ...) come before general properties.
- Prepend bool
-}
-
-// IsEmpty returns true if the attribute has no values under any configuration.
-func (sla StringListAttribute) IsEmpty() bool {
- return len(sla.Value) == 0 && !sla.HasConfigurableValues()
-}
-
-type configurableStringLists map[ConfigurationAxis]stringListSelectValues
-
-func (csl configurableStringLists) Append(other configurableStringLists) {
- for axis, otherSelects := range other {
- selects := csl[axis]
- if selects == nil {
- selects = make(stringListSelectValues, len(otherSelects))
- }
- selects.appendSelects(otherSelects)
- csl[axis] = selects
- }
-}
-
-func (csl configurableStringLists) setValueForAxis(axis ConfigurationAxis, config string, list []string) {
- if csl[axis] == nil {
- csl[axis] = make(stringListSelectValues)
- }
- csl[axis][config] = list
-}
-
-type stringListSelectValues map[string][]string
-
-func (sl stringListSelectValues) appendSelects(other stringListSelectValues) {
- for k, v := range other {
- sl[k] = append(sl[k], v...)
- }
-}
-
-func (sl stringListSelectValues) hasConfigurableValues(other stringListSelectValues) bool {
- for _, val := range sl {
- if len(val) > 0 {
- return true
- }
- }
- return false
-}
-
-// MakeStringListAttribute initializes a StringListAttribute with the non-arch specific value.
-func MakeStringListAttribute(value []string) StringListAttribute {
- // NOTE: These strings are not necessarily unique or sorted.
- return StringListAttribute{
- Value: value,
- ConfigurableValues: make(configurableStringLists),
- }
-}
-
-// HasConfigurableValues returns true if the attribute contains axis-specific string_list values.
-func (sla StringListAttribute) HasConfigurableValues() bool {
- for _, selectValues := range sla.ConfigurableValues {
- if len(selectValues) > 0 {
- return true
- }
- }
- return false
-}
-
-// Append appends all values, including os and arch specific ones, from another
-// StringListAttribute to this StringListAttribute
-func (sla *StringListAttribute) Append(other StringListAttribute) *StringListAttribute {
- sla.Value = append(sla.Value, other.Value...)
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.Append(other.ConfigurableValues)
- return sla
-}
-
-func (sla *StringListAttribute) Clone() *StringListAttribute {
- result := &StringListAttribute{}
- return result.Append(*sla)
-}
-
-// SetSelectValue set a value for a bazel select for the given axis, config and value.
-func (sla *StringListAttribute) SetSelectValue(axis ConfigurationAxis, config string, list []string) {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- sla.Value = list
- case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
- if sla.ConfigurableValues == nil {
- sla.ConfigurableValues = make(configurableStringLists)
- }
- sla.ConfigurableValues.setValueForAxis(axis, config, list)
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SelectValue gets a value for a bazel select for the given axis and config.
-func (sla *StringListAttribute) SelectValue(axis ConfigurationAxis, config string) []string {
- axis.validateConfig(config)
- switch axis.configurationType {
- case noConfig:
- return sla.Value
- case arch, os, osArch, productVariables, osAndInApex, errorProneDisabled, sanitizersEnabled:
- return sla.ConfigurableValues[axis][config]
- default:
- panic(fmt.Errorf("Unrecognized ConfigurationAxis %s", axis))
- }
-}
-
-// SortedConfigurationAxes returns all the used ConfigurationAxis in sorted order.
-func (sla *StringListAttribute) SortedConfigurationAxes() []ConfigurationAxis {
- return SortedConfigurationAxes(sla.ConfigurableValues)
-}
-
-// DeduplicateAxesFromBase ensures no duplication of items between the no-configuration value and
-// configuration-specific values. For example, if we would convert this StringListAttribute as:
-//
-// ["a", "b", "c"] + select({
-// "//condition:one": ["a", "d"],
-// "//conditions:default": [],
-// })
-//
-// after this function, we would convert this StringListAttribute as:
-//
-// ["a", "b", "c"] + select({
-// "//condition:one": ["d"],
-// "//conditions:default": [],
-// })
-func (sla *StringListAttribute) DeduplicateAxesFromBase() {
- base := sla.Value
- for axis, configToList := range sla.ConfigurableValues {
- for config, list := range configToList {
- remaining := SubtractStrings(list, base)
- if len(remaining) == 0 {
- delete(sla.ConfigurableValues[axis], config)
- } else {
- sla.ConfigurableValues[axis][config] = remaining
- }
- }
- }
-}
-
-// TryVariableSubstitution, replace string substitution formatting within each string in slice with
-// Starlark string.format compatible tag for productVariable.
-func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) {
- if len(slice) == 0 {
- return slice, false
- }
- ret := make([]string, 0, len(slice))
- changesMade := false
- for _, s := range slice {
- newS, changed := TryVariableSubstitution(s, productVariable)
- ret = append(ret, newS)
- changesMade = changesMade || changed
- }
- return ret, changesMade
-}
-
-// TryVariableSubstitution, replace string substitution formatting within s with Starlark
-// string.format compatible tag for productVariable.
-func TryVariableSubstitution(s string, productVariable string) (string, bool) {
- sub := productVariableSubstitutionPattern.ReplaceAllString(s, "$("+productVariable+")")
- return sub, s != sub
-}
-
-// StringMapAttribute is a map of strings.
-// The use case for this is storing the flag_values in a config_setting object.
-// Bazel rules do not support map attributes, and this should NOT be used in Bazel rules.
-type StringMapAttribute map[string]string
-
-// ConfigSettingAttributes stores the keys of a config_setting object.
-type ConfigSettingAttributes struct {
- // Each key in Flag_values is a label to a custom string_setting
- Flag_values StringMapAttribute
- // Each element in Constraint_values is a label to a constraint_value
- Constraint_values LabelListAttribute
-}
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
deleted file mode 100644
index 751cb8b..0000000
--- a/bazel/properties_test.go
+++ /dev/null
@@ -1,836 +0,0 @@
-// Copyright 2021 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 bazel
-
-import (
- "reflect"
- "strings"
- "testing"
-
- "github.com/google/blueprint/proptools"
-)
-
-func TestUniqueBazelLabels(t *testing.T) {
- testCases := []struct {
- originalLabels []Label
- expectedUniqueLabels []Label
- }{
- {
- originalLabels: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "a"},
- {Label: "c"},
- // namespaces
- {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace
- {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when reference from root namespace
- },
- expectedUniqueLabels: []Label{
- {Label: "//foo:bar", OriginalModuleName: "bar"},
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabels := UniqueSortedBazelLabels(tc.originalLabels)
- if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
- }
- }
-}
-
-func TestSubtractStrings(t *testing.T) {
- testCases := []struct {
- haystack []string
- needle []string
- expectedResult []string
- }{
- {
- haystack: []string{
- "a",
- "b",
- "c",
- },
- needle: []string{
- "a",
- },
- expectedResult: []string{
- "b", "c",
- },
- },
- }
- for _, tc := range testCases {
- actualResult := SubtractStrings(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expectedResult, actualResult) {
- t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
- }
- }
-}
-
-func TestSubtractBazelLabelList(t *testing.T) {
- testCases := []struct {
- haystack LabelList
- needle LabelList
- expectedResult LabelList
- }{
- {
- haystack: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- needle: LabelList{
- Includes: []Label{
- {Label: "a"},
- },
- Excludes: []Label{
- {Label: "z"},
- },
- },
- // NOTE: Excludes are intentionally not subtracted
- expectedResult: LabelList{
- Includes: []Label{
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualResult := SubtractBazelLabelList(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expectedResult, actualResult) {
- t.Fatalf("Expected %v, got %v", tc.expectedResult, actualResult)
- }
- }
-}
-
-func TestSubtractBazelLabelListAttribute(t *testing.T) {
- testCases := []struct {
- haystack LabelListAttribute
- needle LabelListAttribute
- expected LabelListAttribute
- }{
- {
- haystack: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "a", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_1", "arm_2"}, []string{}),
- "x86": makeLabelList([]string{"x86_3", "x86_4", "x86_5"}, []string{"x86_5"}),
- },
- },
- },
- needle: LabelListAttribute{
- Value: makeLabelList(
- []string{"d", "a"},
- []string{"x", "y2", "z2"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_1", "arm_3"}, []string{}),
- "x86": makeLabelList([]string{"x86_3", "x86_4"}, []string{"x86_6"}),
- },
- },
- },
- expected: LabelListAttribute{
- Value: makeLabelList(
- []string{"b", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"arm_2"}, []string{}),
- "x86": makeLabelList([]string{"x86_5"}, []string{"x86_5"}),
- },
- },
- ForceSpecifyEmptyList: false,
- EmitEmptyList: false,
- Prepend: false,
- },
- },
- }
- for _, tc := range testCases {
- got := SubtractBazelLabelListAttribute(tc.haystack, tc.needle)
- if !reflect.DeepEqual(tc.expected, got) {
- t.Fatalf("Expected\n%v, but got\n%v", tc.expected, got)
- }
- }
-}
-
-func TestFirstUniqueBazelLabelList(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelList
- expectedUniqueLabelList LabelList
- }{
- {
- originalLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "a"},
- {Label: "c"},
- // namespaces
- {Label: "//foo:bar", OriginalModuleName: "bar"}, // when referenced from foo namespace
- {Label: "//foo:bar", OriginalModuleName: "//foo:bar"}, // when referenced from root namespace
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- expectedUniqueLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- {Label: "//foo:bar", OriginalModuleName: "bar"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := FirstUniqueBazelLabelList(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func TestFirstUniqueBazelLabelListAttribute(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelListAttribute
- expectedUniqueLabelList LabelListAttribute
- }{
- {
- originalLabelList: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "a", "c"},
- []string{"x", "x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"1", "2", "1"}, []string{}),
- "x86": makeLabelList([]string{"3", "4", "4"}, []string{"5", "5"}),
- },
- },
- },
- expectedUniqueLabelList: LabelListAttribute{
- Value: makeLabelList(
- []string{"a", "b", "c"},
- []string{"x", "y", "z"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"1", "2"}, []string{}),
- "x86": makeLabelList([]string{"3", "4"}, []string{"5"}),
- },
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := FirstUniqueBazelLabelListAttribute(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func TestUniqueSortedBazelLabelList(t *testing.T) {
- testCases := []struct {
- originalLabelList LabelList
- expectedUniqueLabelList LabelList
- }{
- {
- originalLabelList: LabelList{
- Includes: []Label{
- {Label: "c"},
- {Label: "a"},
- {Label: "a"},
- {Label: "b"},
- },
- Excludes: []Label{
- {Label: "y"},
- {Label: "z"},
- {Label: "x"},
- {Label: "x"},
- },
- },
- expectedUniqueLabelList: LabelList{
- Includes: []Label{
- {Label: "a"},
- {Label: "b"},
- {Label: "c"},
- },
- Excludes: []Label{
- {Label: "x"},
- {Label: "y"},
- {Label: "z"},
- },
- },
- },
- }
- for _, tc := range testCases {
- actualUniqueLabelList := UniqueSortedBazelLabelList(tc.originalLabelList)
- if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
- t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
- }
- }
-}
-
-func makeLabels(labels ...string) []Label {
- var ret []Label
- for _, l := range labels {
- ret = append(ret, Label{Label: l})
- }
- return ret
-}
-
-func makeLabelList(includes, excludes []string) LabelList {
- return LabelList{
- Includes: makeLabels(includes...),
- Excludes: makeLabels(excludes...),
- }
-}
-
-func TestResolveExcludes(t *testing.T) {
- attr := LabelListAttribute{
- Value: makeLabelList(
- []string{
- "all_include",
- "arm_exclude",
- "android_exclude",
- "product_config_exclude",
- },
- []string{"all_exclude"},
- ),
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{}, []string{"arm_exclude"}),
- "x86": makeLabelList([]string{"x86_include"}, []string{}),
- ConditionsDefaultConfigKey: makeLabelList([]string{"default_include"}, []string{}),
- },
- OsConfigurationAxis: labelListSelectValues{
- "android": makeLabelList([]string{}, []string{"android_exclude"}),
- "linux": makeLabelList([]string{"linux_include"}, []string{}),
- },
- OsArchConfigurationAxis: labelListSelectValues{
- "linux_x86": makeLabelList([]string{"linux_x86_include"}, []string{}),
- },
- ProductVariableConfigurationAxis(false, "product_with_defaults"): labelListSelectValues{
- "a": makeLabelList([]string{}, []string{"not_in_value"}),
- "b": makeLabelList([]string{"b_val"}, []string{}),
- "c": makeLabelList([]string{"c_val"}, []string{}),
- ConditionsDefaultConfigKey: makeLabelList([]string{"c_val", "default", "default2", "all_exclude"}, []string{}),
- },
- ProductVariableConfigurationAxis(false, "product_only_with_excludes"): labelListSelectValues{
- "a": makeLabelList([]string{}, []string{"product_config_exclude"}),
- },
- },
- }
-
- attr.ResolveExcludes()
-
- expectedBaseIncludes := []Label{{Label: "all_include"}}
- if !reflect.DeepEqual(expectedBaseIncludes, attr.Value.Includes) {
- t.Errorf("Expected Value includes %q, got %q", attr.Value.Includes, expectedBaseIncludes)
- }
- var nilLabels []Label
- expectedConfiguredIncludes := map[ConfigurationAxis]map[string][]Label{
- ArchConfigurationAxis: {
- "arm": nilLabels,
- "x86": makeLabels("arm_exclude", "x86_include"),
- ConditionsDefaultConfigKey: makeLabels("arm_exclude", "default_include"),
- },
- OsConfigurationAxis: {
- "android": nilLabels,
- "linux": makeLabels("android_exclude", "linux_include"),
- ConditionsDefaultConfigKey: makeLabels("android_exclude"),
- },
- OsArchConfigurationAxis: {
- "linux_x86": makeLabels("linux_x86_include"),
- ConditionsDefaultConfigKey: nilLabels,
- },
- ProductVariableConfigurationAxis(false, "product_with_defaults"): {
- "a": nilLabels,
- "b": makeLabels("b_val"),
- "c": makeLabels("c_val"),
- ConditionsDefaultConfigKey: makeLabels("c_val", "default", "default2"),
- },
- ProductVariableConfigurationAxis(false, "product_only_with_excludes"): {
- "a": nilLabels,
- ConditionsDefaultConfigKey: makeLabels("product_config_exclude"),
- },
- }
- for _, axis := range attr.SortedConfigurationAxes() {
- if _, ok := expectedConfiguredIncludes[axis]; !ok {
- t.Errorf("Found unexpected axis %s", axis)
- continue
- }
- expectedForAxis := expectedConfiguredIncludes[axis]
- gotForAxis := attr.ConfigurableValues[axis]
- if len(expectedForAxis) != len(gotForAxis) {
- t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
- }
- for config, value := range gotForAxis {
- if expected, ok := expectedForAxis[config]; ok {
- if !reflect.DeepEqual(expected, value.Includes) {
- t.Errorf("For %s,\nexpected: %#v\ngot %#v", axis, expected, value.Includes)
- }
- } else {
- t.Errorf("Got unexpected config %q for %s", config, axis)
- }
- }
- }
-}
-
-func TestLabelListAttributePartition(t *testing.T) {
- testCases := []struct {
- name string
- input LabelListAttribute
- predicated LabelListAttribute
- unpredicated LabelListAttribute
- predicate func(label Label) bool
- }{
- {
- name: "move all to predicated partition",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- unpredicated: LabelListAttribute{},
- predicate: func(label Label) bool {
- return true
- },
- },
- {
- name: "move all to unpredicated partition",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: LabelListAttribute{},
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicate: func(label Label) bool {
- return false
- },
- },
- {
- name: "partition includes and excludes",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "keep2"},
- []string{"keep1", "keep2"},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"throw1", "throw2"},
- []string{"throw1", "throw2"},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "partition excludes only",
- input: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"keep1", "throw1", "keep2", "throw2"},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"keep1", "keep2"},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{},
- []string{"throw1", "throw2"},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "partition includes only",
- input: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "throw1", "keep2", "throw2"},
- []string{},
- )),
- predicated: MakeLabelListAttribute(makeLabelList(
- []string{"keep1", "keep2"},
- []string{},
- )),
- unpredicated: MakeLabelListAttribute(makeLabelList(
- []string{"throw1", "throw2"},
- []string{},
- )),
- predicate: func(label Label) bool {
- return strings.HasPrefix(label.Label, "keep")
- },
- },
- {
- name: "empty partition",
- input: MakeLabelListAttribute(makeLabelList([]string{}, []string{})),
- predicated: LabelListAttribute{},
- unpredicated: LabelListAttribute{},
- predicate: func(label Label) bool {
- return true
- },
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- predicated, unpredicated := tc.input.Partition(tc.predicate)
- if !predicated.Value.Equals(tc.predicated.Value) {
- t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
- }
- for axis, configs := range predicated.ConfigurableValues {
- tcConfigs, ok := tc.predicated.ConfigurableValues[axis]
- if !ok || !reflect.DeepEqual(configs, tcConfigs) {
- t.Errorf("expected predicated labels to be %v; got %v", tc.predicated, predicated)
- }
- }
- if !unpredicated.Value.Equals(tc.unpredicated.Value) {
- t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
- }
- for axis, configs := range unpredicated.ConfigurableValues {
- tcConfigs, ok := tc.unpredicated.ConfigurableValues[axis]
- if !ok || !reflect.DeepEqual(configs, tcConfigs) {
- t.Errorf("expected unpredicated labels to be %v; got %v", tc.unpredicated, unpredicated)
- }
- }
- })
- }
-}
-
-// labelAddSuffixForTypeMapper returns a LabelMapper that adds suffix to label name for modules of
-// typ
-func labelAddSuffixForTypeMapper(suffix, typ string) LabelMapper {
- return func(omc OtherModuleContext, label Label) (string, bool) {
- m, ok := omc.ModuleFromName(label.Label)
- if !ok {
- return label.Label, false
- }
- mTyp := omc.OtherModuleType(m)
- if typ == mTyp {
- return label.Label + suffix, true
- }
- return label.Label, false
- }
-}
-
-func TestPartitionLabelListAttribute(t *testing.T) {
- testCases := []struct {
- name string
- ctx *OtherModuleTestContext
- labelList LabelListAttribute
- filters LabelPartitions
- expected PartitionToLabelListAttribute
- expectedErrMsg *string
- }{
- {
- name: "no configurable values",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, remainder partition",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}, Keep_remainder: true},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "d.d", "e.e"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, empty partition",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "c.c"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "no configurable values, has map",
- ctx: &OtherModuleTestContext{
- Modules: []TestModuleInfo{{ModuleName: "srcs", Typ: "fg", Dir: "dir"}},
- },
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "srcs", "b.b", "c.c"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}, LabelMapper: labelAddSuffixForTypeMapper("_a", "fg")},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{Value: makeLabelList([]string{"a.a", "srcs_a"}, []string{})},
- "B": LabelListAttribute{Value: makeLabelList([]string{"b.b"}, []string{})},
- "C": LabelListAttribute{Value: makeLabelList([]string{"c.c"}, []string{})},
- },
- },
- {
- name: "configurable values, keeps empty if excludes",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"a.a", "c.c"}, []string{}),
- "arm": makeLabelList([]string{"b.b"}, []string{}),
- "x86_64": makeLabelList([]string{"b.b"}, []string{"d.d"}),
- },
- },
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "B": LabelPartition{Extensions: []string{".b"}},
- "C": LabelPartition{Extensions: []string{".c"}},
- },
- expected: PartitionToLabelListAttribute{
- "A": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"a.a"}, []string{}),
- "x86_64": makeLabelList([]string{}, []string{"c.c"}),
- },
- },
- },
- "B": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "arm": makeLabelList([]string{"b.b"}, []string{}),
- "x86_64": makeLabelList([]string{"b.b"}, []string{"c.c"}),
- },
- },
- },
- "C": LabelListAttribute{
- ConfigurableValues: configurableLabelLists{
- ArchConfigurationAxis: labelListSelectValues{
- "x86": makeLabelList([]string{"c.c"}, []string{}),
- "x86_64": makeLabelList([]string{}, []string{"c.c"}),
- },
- },
- },
- },
- },
- {
- name: "error for multiple partitions same value",
- ctx: &OtherModuleTestContext{},
- labelList: LabelListAttribute{
- Value: makeLabelList([]string{"a.a", "b.b", "c.c", "d.d", "e.e"}, []string{}),
- },
- filters: LabelPartitions{
- "A": LabelPartition{Extensions: []string{".a"}},
- "other A": LabelPartition{Extensions: []string{".a"}},
- },
- expected: PartitionToLabelListAttribute{},
- expectedErrMsg: proptools.StringPtr(`"a.a" was found in multiple partitions:`),
- },
- }
-
- for _, tc := range testCases {
- t.Run(tc.name, func(t *testing.T) {
- got := PartitionLabelListAttribute(tc.ctx, &tc.labelList, tc.filters)
-
- if hasErrors, expectsErr := len(tc.ctx.errors) > 0, tc.expectedErrMsg != nil; hasErrors != expectsErr {
- t.Errorf("Unexpected error(s): %q, expected: %q", tc.ctx.errors, *tc.expectedErrMsg)
- } else if tc.expectedErrMsg != nil {
- found := false
- for _, err := range tc.ctx.errors {
- if strings.Contains(err, *tc.expectedErrMsg) {
- found = true
- break
- }
- }
-
- if !found {
- t.Errorf("Expected error message: %q, got %q", *tc.expectedErrMsg, tc.ctx.errors)
- }
- return
- }
-
- if len(tc.expected) != len(got) {
- t.Errorf("Expected %d partitions, got %d partitions", len(tc.expected), len(got))
- }
- for partition, expectedLla := range tc.expected {
- gotLla, ok := got[partition]
- if !ok {
- t.Errorf("Expected partition %q, but it was not found %v", partition, got)
- continue
- }
- expectedLabelList := expectedLla.Value
- gotLabelList := gotLla.Value
- if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
- t.Errorf("Expected no config includes %v, got %v", expectedLabelList.Includes, gotLabelList.Includes)
- }
- expectedAxes := expectedLla.SortedConfigurationAxes()
- gotAxes := gotLla.SortedConfigurationAxes()
- if !reflect.DeepEqual(expectedAxes, gotAxes) {
- t.Errorf("Expected axes %v, got %v (%#v)", expectedAxes, gotAxes, gotLla)
- }
- for _, axis := range expectedLla.SortedConfigurationAxes() {
- if _, exists := gotLla.ConfigurableValues[axis]; !exists {
- t.Errorf("Expected %s to be a supported axis, but it was not found", axis)
- }
- if expected, got := expectedLla.ConfigurableValues[axis], gotLla.ConfigurableValues[axis]; len(expected) != len(got) {
- t.Errorf("For axis %q: expected configs %v, got %v", axis, expected, got)
- }
- for config, expectedLabelList := range expectedLla.ConfigurableValues[axis] {
- gotLabelList, exists := gotLla.ConfigurableValues[axis][config]
- if !exists {
- t.Errorf("Expected %s to be a supported config, but config was not found", config)
- continue
- }
- if !reflect.DeepEqual(expectedLabelList.Includes, gotLabelList.Includes) {
- t.Errorf("Expected %s %s includes %v, got %v", axis, config, expectedLabelList.Includes, gotLabelList.Includes)
- }
- }
- }
- }
- })
- }
-}
-
-func TestDeduplicateAxesFromBase(t *testing.T) {
- attr := StringListAttribute{
- Value: []string{
- "all_include",
- "arm_include",
- "android_include",
- "linux_x86_include",
- },
- ConfigurableValues: configurableStringLists{
- ArchConfigurationAxis: stringListSelectValues{
- "arm": []string{"arm_include"},
- "x86": []string{"x86_include"},
- },
- OsConfigurationAxis: stringListSelectValues{
- "android": []string{"android_include"},
- "linux": []string{"linux_include"},
- },
- OsArchConfigurationAxis: stringListSelectValues{
- "linux_x86": {"linux_x86_include"},
- },
- ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
- "a": []string{"not_in_value"},
- },
- },
- }
-
- attr.DeduplicateAxesFromBase()
-
- expectedBaseIncludes := []string{
- "all_include",
- "arm_include",
- "android_include",
- "linux_x86_include",
- }
- if !reflect.DeepEqual(expectedBaseIncludes, attr.Value) {
- t.Errorf("Expected Value includes %q, got %q", attr.Value, expectedBaseIncludes)
- }
- expectedConfiguredIncludes := configurableStringLists{
- ArchConfigurationAxis: stringListSelectValues{
- "x86": []string{"x86_include"},
- },
- OsConfigurationAxis: stringListSelectValues{
- "linux": []string{"linux_include"},
- },
- OsArchConfigurationAxis: stringListSelectValues{},
- ProductVariableConfigurationAxis(false, "a"): stringListSelectValues{
- "a": []string{"not_in_value"},
- },
- }
- for _, axis := range attr.SortedConfigurationAxes() {
- if _, ok := expectedConfiguredIncludes[axis]; !ok {
- t.Errorf("Found unexpected axis %s", axis)
- continue
- }
- expectedForAxis := expectedConfiguredIncludes[axis]
- gotForAxis := attr.ConfigurableValues[axis]
- if len(expectedForAxis) != len(gotForAxis) {
- t.Errorf("Expected %d configs for %s, got %d: %s", len(expectedForAxis), axis, len(gotForAxis), gotForAxis)
- }
- for config, value := range gotForAxis {
- if expected, ok := expectedForAxis[config]; ok {
- if !reflect.DeepEqual(expected, value) {
- t.Errorf("For %s, expected: %#v, got %#v", axis, expected, value)
- }
- } else {
- t.Errorf("Got unexpected config %q for %s", config, axis)
- }
- }
- }
-}
diff --git a/bazel/testing.go b/bazel/testing.go
deleted file mode 100644
index 9a43b61..0000000
--- a/bazel/testing.go
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2021 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 bazel
-
-import (
- "fmt"
-
- "github.com/google/blueprint"
-)
-
-// TestModuleInfo implements blueprint.Module interface with sufficient information to mock a subset of
-// a blueprint ModuleContext
-type TestModuleInfo struct {
- ModuleName string
- Typ string
- Dir string
-}
-
-// Name returns name for testModuleInfo -- required to implement blueprint.Module
-func (mi TestModuleInfo) Name() string {
- return mi.ModuleName
-}
-
-// GenerateBuildActions unused, but required to implmeent blueprint.Module
-func (mi TestModuleInfo) GenerateBuildActions(blueprint.ModuleContext) {}
-
-func (mi TestModuleInfo) equals(other TestModuleInfo) bool {
- return mi.ModuleName == other.ModuleName && mi.Typ == other.Typ && mi.Dir == other.Dir
-}
-
-// ensure testModuleInfo implements blueprint.Module
-var _ blueprint.Module = TestModuleInfo{}
-
-// OtherModuleTestContext is a mock context that implements OtherModuleContext
-type OtherModuleTestContext struct {
- Modules []TestModuleInfo
- errors []string
-}
-
-// ModuleFromName retrieves the testModuleInfo corresponding to name, if it exists
-func (omc *OtherModuleTestContext) ModuleFromName(name string) (blueprint.Module, bool) {
- for _, m := range omc.Modules {
- if m.ModuleName == name {
- return m, true
- }
- }
- return TestModuleInfo{}, false
-}
-
-// testModuleInfo returns the testModuleInfo corresponding to a blueprint.Module if it exists in omc
-func (omc *OtherModuleTestContext) testModuleInfo(m blueprint.Module) (TestModuleInfo, bool) {
- mi, ok := m.(TestModuleInfo)
- if !ok {
- return TestModuleInfo{}, false
- }
- for _, other := range omc.Modules {
- if other.equals(mi) {
- return mi, true
- }
- }
- return TestModuleInfo{}, false
-}
-
-// OtherModuleType returns type of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleType(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.Typ
- }
- return ""
-}
-
-// OtherModuleName returns name of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleName(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.ModuleName
- }
- return ""
-}
-
-// OtherModuleDir returns dir of m if it exists in omc
-func (omc *OtherModuleTestContext) OtherModuleDir(m blueprint.Module) string {
- if mi, ok := omc.testModuleInfo(m); ok {
- return mi.Dir
- }
- return ""
-}
-
-func (omc *OtherModuleTestContext) ModuleErrorf(format string, args ...interface{}) {
- omc.errors = append(omc.errors, fmt.Sprintf(format, args...))
-}
-
-// Ensure otherModuleTestContext implements OtherModuleContext
-var _ OtherModuleContext = &OtherModuleTestContext{}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index ba12682..28c0268 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -9,7 +9,6 @@
"androidbp_to_build_templates.go",
"build_conversion.go",
"bzl_conversion.go",
- "configurability.go",
"constants.go",
"conversion.go",
],
@@ -21,7 +20,6 @@
"soong-android-allowlists",
"soong-android-soongconfig",
"soong-apex",
- "soong-bazel",
"soong-cc",
"soong-cc-config",
"soong-etc",
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index bd56768..18213a8 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -26,7 +26,6 @@
"strings"
"android/soong/android"
- "android/soong/bazel"
"android/soong/starlark_fmt"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -182,12 +181,11 @@
}
type CodegenContext struct {
- config android.Config
- context *android.Context
- mode CodegenMode
- additionalDeps []string
- unconvertedDepMode unconvertedDepsMode
- topDir string
+ config android.Config
+ context *android.Context
+ mode CodegenMode
+ additionalDeps []string
+ topDir string
}
func (ctx *CodegenContext) Mode() CodegenMode {
@@ -207,16 +205,6 @@
QueryView CodegenMode = iota
)
-type unconvertedDepsMode int
-
-const (
- // Include a warning in conversion metrics about converted modules with unconverted direct deps
- warnUnconvertedDeps unconvertedDepsMode = iota
- // Error and fail conversion if encountering a module with unconverted direct deps
- // Enabled by setting environment variable `BP2BUILD_ERROR_UNCONVERTED`
- errorModulesUnconvertedDeps
-)
-
func (mode CodegenMode) String() string {
switch mode {
case QueryView:
@@ -245,13 +233,11 @@
// NewCodegenContext creates a wrapper context that conforms to PathContext for
// writing BUILD files in the output directory.
func NewCodegenContext(config android.Config, context *android.Context, mode CodegenMode, topDir string) *CodegenContext {
- var unconvertedDeps unconvertedDepsMode
return &CodegenContext{
- context: context,
- config: config,
- mode: mode,
- unconvertedDepMode: unconvertedDeps,
- topDir: topDir,
+ context: context,
+ config: config,
+ mode: mode,
+ topDir: topDir,
}
}
@@ -482,14 +468,6 @@
}), nil
case reflect.Struct:
- // Special cases where the bp2build sends additional information to the codegenerator
- // by wrapping the attributes in a custom struct type.
- if attr, ok := propertyValue.Interface().(bazel.Attribute); ok {
- return prettyPrintAttribute(attr, indent)
- } else if label, ok := propertyValue.Interface().(bazel.Label); ok {
- return fmt.Sprintf("%q", label.Label), nil
- }
-
// Sort and print the struct props by the key.
structProps, err := extractStructProperties(propertyValue, indent)
@@ -506,7 +484,7 @@
// Interfaces are used for for arch, multilib and target properties.
return "", nil
case reflect.Map:
- if v, ok := propertyValue.Interface().(bazel.StringMapAttribute); ok {
+ if v, ok := propertyValue.Interface().(map[string]string); ok {
return starlark_fmt.PrintStringStringDict(v, indent), nil
}
return "", fmt.Errorf("bp2build expects map of type map[string]string for field: %s", propertyValue)
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
deleted file mode 100644
index 3d9f0a2..0000000
--- a/bp2build/configurability.go
+++ /dev/null
@@ -1,328 +0,0 @@
-package bp2build
-
-import (
- "fmt"
- "reflect"
-
- "android/soong/android"
- "android/soong/bazel"
- "android/soong/starlark_fmt"
-)
-
-// Configurability support for bp2build.
-
-type selects map[string]reflect.Value
-
-func getStringValue(str bazel.StringAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(str.Value)
-
- if !str.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range str.SortedConfigurationAxes() {
- configToStrs := str.ConfigurableValues[axis]
- for config, strs := range configToStrs {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(strs)
- }
- }
-
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- if _, ok := ret[bazel.ConditionsDefaultSelectKey]; !ok {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
- }
-
- return value, []selects{ret}
-}
-
-func getStringListValues(list bazel.StringListAttribute) (reflect.Value, []selects, bool) {
- value := reflect.ValueOf(list.Value)
- prepend := list.Prepend
- if !list.HasConfigurableValues() {
- return value, []selects{}, prepend
- }
-
- var ret []selects
- for _, axis := range list.SortedConfigurationAxes() {
- configToLists := list.ConfigurableValues[axis]
- archSelects := map[string]reflect.Value{}
- for config, labels := range configToLists {
- selectKey := axis.SelectKey(config)
- archSelects[selectKey] = reflect.ValueOf(labels)
- }
- if len(archSelects) > 0 {
- ret = append(ret, archSelects)
- }
- }
-
- return value, ret, prepend
-}
-
-func getLabelValue(label bazel.LabelAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(label.Value)
- if !label.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range label.SortedConfigurationAxes() {
- configToLabels := label.ConfigurableValues[axis]
- for config, labels := range configToLabels {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(labels)
- }
- }
-
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
-
- return value, []selects{ret}
-}
-
-func getBoolValue(boolAttr bazel.BoolAttribute) (reflect.Value, []selects) {
- value := reflect.ValueOf(boolAttr.Value)
- if !boolAttr.HasConfigurableValues() {
- return value, []selects{}
- }
-
- ret := selects{}
- for _, axis := range boolAttr.SortedConfigurationAxes() {
- configToBools := boolAttr.ConfigurableValues[axis]
- for config, bools := range configToBools {
- selectKey := axis.SelectKey(config)
- ret[selectKey] = reflect.ValueOf(bools)
- }
- }
- // if there is a select, use the base value as the conditions default value
- if len(ret) > 0 {
- ret[bazel.ConditionsDefaultSelectKey] = value
- value = reflect.Zero(value.Type())
- }
-
- return value, []selects{ret}
-}
-func getLabelListValues(list bazel.LabelListAttribute) (reflect.Value, []selects, bool) {
- value := reflect.ValueOf(list.Value.Includes)
- prepend := list.Prepend
- var ret []selects
- for _, axis := range list.SortedConfigurationAxes() {
- configToLabels := list.ConfigurableValues[axis]
- if !configToLabels.HasConfigurableValues() {
- continue
- }
- archSelects := map[string]reflect.Value{}
- defaultVal := configToLabels[bazel.ConditionsDefaultConfigKey]
- // Skip empty list values unless ether EmitEmptyList is true, or these values differ from the default.
- emitEmptyList := list.EmitEmptyList || len(defaultVal.Includes) > 0
- for config, labels := range configToLabels {
- // Omit any entries in the map which match the default value, for brevity.
- if config != bazel.ConditionsDefaultConfigKey && labels.Equals(defaultVal) {
- continue
- }
- selectKey := axis.SelectKey(config)
- if use, value := labelListSelectValue(selectKey, labels, emitEmptyList); use {
- archSelects[selectKey] = value
- }
- }
- if len(archSelects) > 0 {
- ret = append(ret, archSelects)
- }
- }
-
- return value, ret, prepend
-}
-
-func labelListSelectValue(selectKey string, list bazel.LabelList, emitEmptyList bool) (bool, reflect.Value) {
- if selectKey == bazel.ConditionsDefaultSelectKey || emitEmptyList || len(list.Includes) > 0 {
- return true, reflect.ValueOf(list.Includes)
- } else if len(list.Excludes) > 0 {
- // if there is still an excludes -- we need to have an empty list for this select & use the
- // value in conditions default Includes
- return true, reflect.ValueOf([]string{})
- }
- return false, reflect.Zero(reflect.TypeOf([]string{}))
-}
-
-var (
- emptyBazelList = "[]"
- bazelNone = "None"
-)
-
-// prettyPrintAttribute converts an Attribute to its Bazel syntax. May contain
-// select statements.
-func prettyPrintAttribute(v bazel.Attribute, indent int) (string, error) {
- var value reflect.Value
- // configurableAttrs is the list of individual select statements to be
- // concatenated together. These select statements should be along different
- // axes. For example, one element may be
- // `select({"//color:red": "one", "//color:green": "two"})`, and the second
- // element may be `select({"//animal:cat": "three", "//animal:dog": "four"}).
- // These selects should be sorted by axis identifier.
- var configurableAttrs []selects
- var prepend bool
- var defaultSelectValue *string
- var emitZeroValues bool
- // If true, print the default attribute value, even if the attribute is zero.
- shouldPrintDefault := false
- switch list := v.(type) {
- case bazel.StringAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getStringValue(list)
- defaultSelectValue = &bazelNone
- case bazel.StringListAttribute:
- value, configurableAttrs, prepend = getStringListValues(list)
- defaultSelectValue = &emptyBazelList
- case bazel.LabelListAttribute:
- value, configurableAttrs, prepend = getLabelListValues(list)
- emitZeroValues = list.EmitEmptyList
- defaultSelectValue = &emptyBazelList
- if list.ForceSpecifyEmptyList && (!value.IsNil() || list.HasConfigurableValues()) {
- shouldPrintDefault = true
- }
- case bazel.LabelAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getLabelValue(list)
- defaultSelectValue = &bazelNone
- case bazel.BoolAttribute:
- if err := list.Collapse(); err != nil {
- return "", err
- }
- value, configurableAttrs = getBoolValue(list)
- defaultSelectValue = &bazelNone
- default:
- return "", fmt.Errorf("Not a supported Bazel attribute type: %s", v)
- }
-
- var err error
- ret := ""
- if value.Kind() != reflect.Invalid {
- s, err := prettyPrint(value, indent, false) // never emit zero values for the base value
- if err != nil {
- return ret, err
- }
-
- ret += s
- }
- // Convenience function to prepend/append selects components to an attribute value.
- concatenateSelects := func(selectsData selects, defaultValue *string, s string, prepend bool) (string, error) {
- selectMap, err := prettyPrintSelectMap(selectsData, defaultValue, indent, emitZeroValues)
- if err != nil {
- return "", err
- }
- var left, right string
- if prepend {
- left, right = selectMap, s
- } else {
- left, right = s, selectMap
- }
- if left != "" && right != "" {
- left += " + "
- }
- left += right
-
- return left, nil
- }
-
- for _, configurableAttr := range configurableAttrs {
- ret, err = concatenateSelects(configurableAttr, defaultSelectValue, ret, prepend)
- if err != nil {
- return "", err
- }
- }
-
- if ret == "" && shouldPrintDefault {
- return *defaultSelectValue, nil
- }
- return ret, nil
-}
-
-// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way
-// to construct a select map for any kind of attribute type.
-func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue *string, indent int, emitZeroValues bool) (string, error) {
- if selectMap == nil {
- return "", nil
- }
-
- var selects string
- for _, selectKey := range android.SortedKeys(selectMap) {
- if selectKey == bazel.ConditionsDefaultSelectKey {
- // Handle default condition later.
- continue
- }
- value := selectMap[selectKey]
- if isZero(value) && !emitZeroValues && isZero(selectMap[bazel.ConditionsDefaultSelectKey]) {
- // Ignore zero values to not generate empty lists. However, always note zero values if
- // the default value is non-zero.
- continue
- }
- s, err := prettyPrintSelectEntry(value, selectKey, indent, true)
- if err != nil {
- return "", err
- }
- // s could still be an empty string, e.g. unset slices of structs with
- // length of 0.
- if s != "" {
- selects += s + ",\n"
- }
- }
-
- if len(selects) == 0 {
- // If there is a default value, and there are no selects for this axis, print that without any selects.
- if val, exists := selectMap[bazel.ConditionsDefaultSelectKey]; exists {
- return prettyPrint(val, indent, emitZeroValues)
- }
- // No conditions (or all values are empty lists), so no need for a map.
- return "", nil
- }
-
- // Create the map.
- ret := "select({\n"
- ret += selects
-
- // Handle the default condition
- s, err := prettyPrintSelectEntry(selectMap[bazel.ConditionsDefaultSelectKey], bazel.ConditionsDefaultSelectKey, indent, emitZeroValues)
- if err != nil {
- return "", err
- }
- if s != "" {
- // Print the custom default value.
- ret += s
- ret += ",\n"
- } else if defaultValue != nil {
- // Print an explicit empty list (the default value) even if the value is
- // empty, to avoid errors about not finding a configuration that matches.
- ret += fmt.Sprintf("%s\"%s\": %s,\n", starlark_fmt.Indention(indent+1), bazel.ConditionsDefaultSelectKey, *defaultValue)
- }
-
- ret += starlark_fmt.Indention(indent)
- ret += "})"
-
- return ret, nil
-}
-
-// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map
-// with a provided key.
-func prettyPrintSelectEntry(value reflect.Value, key string, indent int, emitZeroValues bool) (string, error) {
- s := starlark_fmt.Indention(indent + 1)
- v, err := prettyPrint(value, indent+1, emitZeroValues)
- if err != nil {
- return "", err
- }
- if v == "" {
- return "", nil
- }
- s += fmt.Sprintf("\"%s\": %s", key, v)
- return s, nil
-}
diff --git a/bp2build/constants.go b/bp2build/constants.go
index 4870dff..76ba106 100644
--- a/bp2build/constants.go
+++ b/bp2build/constants.go
@@ -20,9 +20,4 @@
// The file name used for automatically generated files.
GeneratedBuildFileName = "BUILD.bazel"
-
- // The file name used for hand-crafted build targets.
- // NOTE: It is okay that this matches GeneratedBuildFileName, since we generate BUILD files in a different directory to source files
- // FIXME: Because there are hundreds of existing BUILD.bazel files in the AOSP tree, we should pick another name here, like BUILD.android
- HandcraftedBuildFileName = "BUILD.bazel"
)
diff --git a/cc/sanitize.go b/cc/sanitize.go
index a8722a0..7f52ce1 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -79,7 +79,7 @@
minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined",
"-fno-sanitize-recover=integer,undefined"}
- memtagStackCommonFlags = []string{"-Xclang -target-feature -Xclang +mte"}
+ memtagStackCommonFlags = []string{"-march=armv8-a+memtag"}
memtagStackLlvmFlags = []string{"-dom-tree-reachability-max-bbs-to-explore=128"}
hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"}
diff --git a/cmd/release_config/release_config_contributions/Android.bp b/cmd/release_config/release_config_contributions/Android.bp
new file mode 100644
index 0000000..6882ea2
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/Android.bp
@@ -0,0 +1,32 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+blueprint_go_binary {
+ name: "release-config-contributions",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-release_config-proto",
+ "soong-cmd-release_config-lib",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
+
+bootstrap_go_package {
+ name: "soong-cmd-release_config-release_config_contributions",
+ pkgPath: "android/soong/cmd/release_config/release_config_contributions",
+ deps: [
+ "golang-protobuf-encoding-prototext",
+ "golang-protobuf-reflect-protoreflect",
+ "golang-protobuf-runtime-protoimpl",
+ "soong-cmd-release_config-proto",
+ "soong-cmd-release_config-lib",
+ ],
+ srcs: [
+ "main.go",
+ ],
+}
diff --git a/cmd/release_config/release_config_contributions/main.go b/cmd/release_config/release_config_contributions/main.go
new file mode 100644
index 0000000..a954cf1
--- /dev/null
+++ b/cmd/release_config/release_config_contributions/main.go
@@ -0,0 +1,130 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "slices"
+ "strings"
+
+ rc_lib "android/soong/cmd/release_config/release_config_lib"
+ rc_proto "android/soong/cmd/release_config/release_config_proto"
+)
+
+type Flags struct {
+ // The path to the top of the workspace. Default: ".".
+ top string
+
+ // Output file.
+ output string
+
+ // Format for output file
+ format string
+
+ // List of release config directories to process.
+ dirs rc_lib.StringList
+
+ // Disable warning messages
+ quiet bool
+
+ // Panic on errors.
+ debug bool
+}
+
+func sortDirectories(dirList []string) {
+ order := func(dir string) int {
+ switch {
+ // These three are always in this order.
+ case dir == "build/release":
+ return 1
+ case dir == "vendor/google_shared/build/release":
+ return 2
+ case dir == "vendor/google/release":
+ return 3
+ // Keep their subdirs in the same order.
+ case strings.HasPrefix(dir, "build/release/"):
+ return 21
+ case strings.HasPrefix(dir, "vendor/google_shared/build/release/"):
+ return 22
+ case strings.HasPrefix(dir, "vendor/google/release/"):
+ return 23
+ // Everything else sorts by directory path.
+ default:
+ return 99
+ }
+ }
+
+ slices.SortFunc(dirList, func(a, b string) int {
+ aOrder, bOrder := order(a), order(b)
+ if aOrder != bOrder {
+ return aOrder - bOrder
+ }
+ return strings.Compare(a, b)
+ })
+}
+
+func main() {
+ var flags Flags
+ topDir, err := rc_lib.GetTopDir()
+
+ // Handle the common arguments
+ flag.StringVar(&flags.top, "top", topDir, "path to top of workspace")
+ flag.Var(&flags.dirs, "dir", "path to a release config contribution directory. May be repeated")
+ flag.StringVar(&flags.format, "format", "pb", "output file format")
+ flag.StringVar(&flags.output, "output", "release_config_contributions.pb", "output file")
+ flag.BoolVar(&flags.debug, "debug", false, "turn on debugging output for errors")
+ flag.BoolVar(&flags.quiet, "quiet", false, "disable warning messages")
+ flag.Parse()
+
+ errorExit := func(err error) {
+ if flags.debug {
+ panic(err)
+ }
+ fmt.Fprintf(os.Stderr, "%s\n", err)
+ os.Exit(1)
+ }
+
+ if flags.quiet {
+ rc_lib.DisableWarnings()
+ }
+
+ if err = os.Chdir(flags.top); err != nil {
+ errorExit(err)
+ }
+
+ contributingDirsMap := make(map[string][]string)
+ for _, dir := range flags.dirs {
+ contributions, err := rc_lib.EnumerateReleaseConfigs(dir)
+ if err != nil {
+ errorExit(err)
+ }
+ for _, name := range contributions {
+ contributingDirsMap[name] = append(contributingDirsMap[name], dir)
+ }
+ }
+
+ releaseConfigNames := []string{}
+ for name := range contributingDirsMap {
+ releaseConfigNames = append(releaseConfigNames, name)
+ }
+ slices.Sort(releaseConfigNames)
+
+ message := &rc_proto.ReleaseConfigContributionsArtifacts{
+ ReleaseConfigContributionsArtifactList: []*rc_proto.ReleaseConfigContributionsArtifact{},
+ }
+ for _, name := range releaseConfigNames {
+ dirs := contributingDirsMap[name]
+ sortDirectories(dirs)
+ message.ReleaseConfigContributionsArtifactList = append(
+ message.ReleaseConfigContributionsArtifactList,
+ &rc_proto.ReleaseConfigContributionsArtifact{
+ Name: &name,
+ ContributingDirectories: dirs,
+ })
+ }
+
+ err = rc_lib.WriteFormattedMessage(flags.output, flags.format, message)
+ if err != nil {
+ errorExit(err)
+ }
+}
diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go
index 97eb8f1..831ec02 100644
--- a/cmd/release_config/release_config_lib/release_configs.go
+++ b/cmd/release_config/release_config_lib/release_configs.go
@@ -248,6 +248,18 @@
return configs.configDirs[index], nil
}
+// Return the (unsorted) release configs contributed to by `dir`.
+func EnumerateReleaseConfigs(dir string) ([]string, error) {
+ var ret []string
+ err := WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error {
+ // Strip off the trailing `.textproto` from the name.
+ name := filepath.Base(path)
+ ret = append(ret, name[:len(name)-10])
+ return err
+ })
+ return ret, err
+}
+
func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error {
if _, err := os.Stat(path); err != nil {
return fmt.Errorf("%s does not exist\n", path)
diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp
index c34d203..c6869b1 100644
--- a/cmd/release_config/release_config_proto/Android.bp
+++ b/cmd/release_config/release_config_proto/Android.bp
@@ -28,5 +28,6 @@
"build_flags_declarations.pb.go",
"build_flags_src.pb.go",
"build_flags_out.pb.go",
+ "release_configs_contributions.pb.go",
],
}
diff --git a/cmd/release_config/release_config_proto/regen.sh b/cmd/release_config/release_config_proto/regen.sh
index 23e3115..a92bfc0 100644
--- a/cmd/release_config/release_config_proto/regen.sh
+++ b/cmd/release_config/release_config_proto/regen.sh
@@ -1,3 +1,3 @@
#!/bin/bash
-aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto build_flags_common.proto build_flags_declarations.proto
+aprotoc --go_out=paths=source_relative:. build_flags_src.proto build_flags_out.proto build_flags_common.proto build_flags_declarations.proto release_configs_contributions.proto
diff --git a/cmd/release_config/release_config_proto/release_configs_contributions.pb.go b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go
new file mode 100644
index 0000000..54854f1
--- /dev/null
+++ b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go
@@ -0,0 +1,252 @@
+//
+// Copyright (C) 2025 The Android Open-Source Project
+//
+// 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.33.0
+// protoc v3.21.12
+// source: release_configs_contributions.proto
+
+package release_config_proto
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type ReleaseConfigContributionsArtifact struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The name of the release config.
+ Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"`
+ // The release config contribution directories that may contribute to this
+ // release config.
+ ContributingDirectories []string `protobuf:"bytes,2,rep,name=contributing_directories,json=contributingDirectories" json:"contributing_directories,omitempty"`
+}
+
+func (x *ReleaseConfigContributionsArtifact) Reset() {
+ *x = ReleaseConfigContributionsArtifact{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_release_configs_contributions_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReleaseConfigContributionsArtifact) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigContributionsArtifact) ProtoMessage() {}
+
+func (x *ReleaseConfigContributionsArtifact) ProtoReflect() protoreflect.Message {
+ mi := &file_release_configs_contributions_proto_msgTypes[0]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigContributionsArtifact.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigContributionsArtifact) Descriptor() ([]byte, []int) {
+ return file_release_configs_contributions_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *ReleaseConfigContributionsArtifact) GetName() string {
+ if x != nil && x.Name != nil {
+ return *x.Name
+ }
+ return ""
+}
+
+func (x *ReleaseConfigContributionsArtifact) GetContributingDirectories() []string {
+ if x != nil {
+ return x.ContributingDirectories
+ }
+ return nil
+}
+
+type ReleaseConfigContributionsArtifacts struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ // The artifacts
+ ReleaseConfigContributionsArtifactList []*ReleaseConfigContributionsArtifact `protobuf:"bytes,1,rep,name=release_config_contributions_artifact_list,json=releaseConfigContributionsArtifactList" json:"release_config_contributions_artifact_list,omitempty"`
+}
+
+func (x *ReleaseConfigContributionsArtifacts) Reset() {
+ *x = ReleaseConfigContributionsArtifacts{}
+ if protoimpl.UnsafeEnabled {
+ mi := &file_release_configs_contributions_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+ }
+}
+
+func (x *ReleaseConfigContributionsArtifacts) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*ReleaseConfigContributionsArtifacts) ProtoMessage() {}
+
+func (x *ReleaseConfigContributionsArtifacts) ProtoReflect() protoreflect.Message {
+ mi := &file_release_configs_contributions_proto_msgTypes[1]
+ if protoimpl.UnsafeEnabled && x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use ReleaseConfigContributionsArtifacts.ProtoReflect.Descriptor instead.
+func (*ReleaseConfigContributionsArtifacts) Descriptor() ([]byte, []int) {
+ return file_release_configs_contributions_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *ReleaseConfigContributionsArtifacts) GetReleaseConfigContributionsArtifactList() []*ReleaseConfigContributionsArtifact {
+ if x != nil {
+ return x.ReleaseConfigContributionsArtifactList
+ }
+ return nil
+}
+
+var File_release_configs_contributions_proto protoreflect.FileDescriptor
+
+var file_release_configs_contributions_proto_rawDesc = []byte{
+ 0x0a, 0x23, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67,
+ 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e,
+ 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72,
+ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72,
+ 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x22, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f,
+ 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a,
+ 0x18, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x69,
+ 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52,
+ 0x17, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x44, 0x69, 0x72,
+ 0x65, 0x63, 0x74, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x22, 0xc4, 0x01, 0x0a, 0x23, 0x52, 0x65, 0x6c,
+ 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69,
+ 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73,
+ 0x12, 0x9c, 0x01, 0x0a, 0x2a, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e,
+ 0x66, 0x69, 0x67, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e,
+ 0x73, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18,
+ 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66,
+ 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x41,
+ 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x26, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65,
+ 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69,
+ 0x6f, 0x6e, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x42,
+ 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67,
+ 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f,
+ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f,
+}
+
+var (
+ file_release_configs_contributions_proto_rawDescOnce sync.Once
+ file_release_configs_contributions_proto_rawDescData = file_release_configs_contributions_proto_rawDesc
+)
+
+func file_release_configs_contributions_proto_rawDescGZIP() []byte {
+ file_release_configs_contributions_proto_rawDescOnce.Do(func() {
+ file_release_configs_contributions_proto_rawDescData = protoimpl.X.CompressGZIP(file_release_configs_contributions_proto_rawDescData)
+ })
+ return file_release_configs_contributions_proto_rawDescData
+}
+
+var file_release_configs_contributions_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_release_configs_contributions_proto_goTypes = []interface{}{
+ (*ReleaseConfigContributionsArtifact)(nil), // 0: android.release_config_proto.ReleaseConfigContributionsArtifact
+ (*ReleaseConfigContributionsArtifacts)(nil), // 1: android.release_config_proto.ReleaseConfigContributionsArtifacts
+}
+var file_release_configs_contributions_proto_depIdxs = []int32{
+ 0, // 0: android.release_config_proto.ReleaseConfigContributionsArtifacts.release_config_contributions_artifact_list:type_name -> android.release_config_proto.ReleaseConfigContributionsArtifact
+ 1, // [1:1] is the sub-list for method output_type
+ 1, // [1:1] is the sub-list for method input_type
+ 1, // [1:1] is the sub-list for extension type_name
+ 1, // [1:1] is the sub-list for extension extendee
+ 0, // [0:1] is the sub-list for field type_name
+}
+
+func init() { file_release_configs_contributions_proto_init() }
+func file_release_configs_contributions_proto_init() {
+ if File_release_configs_contributions_proto != nil {
+ return
+ }
+ if !protoimpl.UnsafeEnabled {
+ file_release_configs_contributions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReleaseConfigContributionsArtifact); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ file_release_configs_contributions_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
+ switch v := v.(*ReleaseConfigContributionsArtifacts); i {
+ case 0:
+ return &v.state
+ case 1:
+ return &v.sizeCache
+ case 2:
+ return &v.unknownFields
+ default:
+ return nil
+ }
+ }
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_release_configs_contributions_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_release_configs_contributions_proto_goTypes,
+ DependencyIndexes: file_release_configs_contributions_proto_depIdxs,
+ MessageInfos: file_release_configs_contributions_proto_msgTypes,
+ }.Build()
+ File_release_configs_contributions_proto = out.File
+ file_release_configs_contributions_proto_rawDesc = nil
+ file_release_configs_contributions_proto_goTypes = nil
+ file_release_configs_contributions_proto_depIdxs = nil
+}
diff --git a/cmd/release_config/release_config_proto/release_configs_contributions.proto b/cmd/release_config/release_config_proto/release_configs_contributions.proto
new file mode 100644
index 0000000..bc7aeda
--- /dev/null
+++ b/cmd/release_config/release_config_proto/release_configs_contributions.proto
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2025 The Android Open-Source Project
+//
+// 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.
+
+syntax = "proto2";
+package android.release_config_proto;
+option go_package = "android/soong/release_config/release_config_proto";
+
+message ReleaseConfigContributionsArtifact {
+ // The name of the release config.
+ optional string name = 1;
+
+ // The release config contribution directories that may contribute to this
+ // release config.
+ repeated string contributing_directories = 2;
+}
+
+message ReleaseConfigContributionsArtifacts {
+ // The artifacts
+ repeated ReleaseConfigContributionsArtifact release_config_contributions_artifact_list = 1;
+}
diff --git a/compliance/Android.bp b/compliance/Android.bp
index 80f5685..72c2f27 100644
--- a/compliance/Android.bp
+++ b/compliance/Android.bp
@@ -35,6 +35,5 @@
partition_name: "system",
visibility: [
"//build/make/target/product/generic",
- "//device/google/cuttlefish/system_image",
],
}
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 0353992..a26fac7 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -37,7 +37,7 @@
func registerBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("android_filesystem", filesystemFactory)
ctx.RegisterModuleType("android_filesystem_defaults", filesystemDefaultsFactory)
- ctx.RegisterModuleType("android_system_image", systemImageFactory)
+ ctx.RegisterModuleType("android_system_image", SystemImageFactory)
ctx.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory)
ctx.RegisterModuleType("avb_add_hash_footer_defaults", avbAddHashFooterDefaultsFactory)
ctx.RegisterModuleType("avb_gen_vbmeta_image", avbGenVbmetaImageFactory)
@@ -49,7 +49,7 @@
android.PackagingBase
android.DefaultableModuleBase
- properties filesystemProperties
+ properties FilesystemProperties
// Function that builds extra files under the root directory and returns the files
buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
@@ -71,7 +71,7 @@
Name *string
}
-type filesystemProperties struct {
+type FilesystemProperties struct {
// When set to true, sign the image with avbtool. Default is false.
Use_avb *bool
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 63cb627..57239ae 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -33,7 +33,7 @@
// android_system_image is a specialization of android_filesystem for the 'system' partition.
// Currently, the only difference is the inclusion of linker.config.pb file which specifies
// the provided and the required libraries to and from APEXes.
-func systemImageFactory() android.Module {
+func SystemImageFactory() android.Module {
module := &systemImage{}
module.AddProperties(&module.properties)
module.filesystem.buildExtraFiles = module.buildExtraFiles
@@ -42,6 +42,10 @@
return module
}
+func (s systemImage) FsProps() FilesystemProperties {
+ return s.filesystem.properties
+}
+
func (s *systemImage) buildExtraFiles(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths {
if s.filesystem.properties.Partition_type != nil {
ctx.PropertyErrorf("partition_type", "partition_type must be unset on an android_system_image module. It is assumed to be 'system'.")
diff --git a/fsgen/Android.bp b/fsgen/Android.bp
new file mode 100644
index 0000000..aa8881f
--- /dev/null
+++ b/fsgen/Android.bp
@@ -0,0 +1,21 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-fsgen",
+ pkgPath: "android/soong/fsgen",
+ deps: [
+ "blueprint",
+ "soong",
+ "soong-android",
+ "soong-filesystem",
+ ],
+ srcs: [
+ "filesystem_creator.go",
+ ],
+ testSrcs: [
+ "filesystem_creator_test.go",
+ ],
+ pluginFor: ["soong_build"],
+}
diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go
new file mode 100644
index 0000000..ca948f4
--- /dev/null
+++ b/fsgen/filesystem_creator.go
@@ -0,0 +1,111 @@
+// Copyright (C) 2024 The Android Open Source Project
+//
+// 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 fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/filesystem"
+ "fmt"
+ "strconv"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ registerBuildComponents(android.InitRegistrationContext)
+}
+
+func registerBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("soong_filesystem_creator", filesystemCreatorFactory)
+}
+
+type filesystemCreator struct {
+ android.ModuleBase
+}
+
+func filesystemCreatorFactory() android.Module {
+ module := &filesystemCreator{}
+
+ android.InitAndroidModule(module)
+ android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+ module.createInternalModules(ctx)
+ })
+
+ return module
+}
+
+func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) {
+ f.createSystemImage(ctx)
+}
+
+func (f *filesystemCreator) createSystemImage(ctx android.LoadHookContext) {
+ baseProps := &struct {
+ Name *string
+ }{
+ Name: proptools.StringPtr(fmt.Sprintf("%s_generated_system_image", ctx.Config().DeviceProduct())),
+ }
+
+ fsProps := &(filesystem.FilesystemProperties{})
+ partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
+ systemPartitionVars := partitionVars.PartitionQualifiedVariables["system"]
+
+ // BOARD_AVB_ENABLE
+ fsProps.Use_avb = proptools.BoolPtr(partitionVars.BoardAvbEnable)
+ // BOARD_AVB_KEY_PATH
+ fsProps.Avb_private_key = proptools.StringPtr(systemPartitionVars.BoardAvbKeyPath)
+ // BOARD_AVB_ALGORITHM
+ fsProps.Avb_algorithm = proptools.StringPtr(systemPartitionVars.BoardAvbAlgorithm)
+ // BOARD_AVB_SYSTEM_ROLLBACK_INDEX
+ if rollbackIndex, err := strconv.ParseInt(systemPartitionVars.BoardAvbRollbackIndex, 10, 64); err == nil {
+ fsProps.Rollback_index = proptools.Int64Ptr(rollbackIndex)
+ }
+
+ fsProps.Partition_name = proptools.StringPtr("system")
+ // BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE
+ fsProps.Type = proptools.StringPtr(systemPartitionVars.BoardFileSystemType)
+
+ fsProps.Base_dir = proptools.StringPtr("system")
+
+ fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true)
+
+ // Identical to that of the generic_system_image
+ fsProps.Fsverity.Inputs = []string{
+ "etc/boot-image.prof",
+ "etc/dirty-image-objects",
+ "etc/preloaded-classes",
+ "etc/classpaths/*.pb",
+ "framework/*",
+ "framework/*/*", // framework/{arch}
+ "framework/oat/*/*", // framework/oat/{arch}
+ }
+
+ // system_image properties that are not set:
+ // - filesystemProperties.Avb_hash_algorithm
+ // - filesystemProperties.File_contexts
+ // - filesystemProperties.Dirs
+ // - filesystemProperties.Symlinks
+ // - filesystemProperties.Fake_timestamp
+ // - filesystemProperties.Uuid
+ // - filesystemProperties.Mount_point
+ // - filesystemProperties.Include_make_built_files
+ // - filesystemProperties.Build_logtags
+ // - filesystemProperties.Fsverity.Libs
+ // - systemImageProperties.Linker_config_src
+ ctx.CreateModule(filesystem.SystemImageFactory, baseProps, fsProps)
+}
+
+func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+
+}
diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go
new file mode 100644
index 0000000..6bb0e77
--- /dev/null
+++ b/fsgen/filesystem_creator_test.go
@@ -0,0 +1,87 @@
+// Copyright 2024 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 fsgen
+
+import (
+ "android/soong/android"
+ "android/soong/filesystem"
+ "testing"
+
+ "github.com/google/blueprint/proptools"
+)
+
+var prepareForTestWithFsgenBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents)
+
+func TestFileSystemCreatorSystemImageProps(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ android.PrepareForIntegrationTestWithAndroid,
+ android.PrepareForTestWithAndroidBuildComponents,
+ filesystem.PrepareForTestWithFilesystemBuildComponents,
+ prepareForTestWithFsgenBuildComponents,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbEnable = true
+ config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.PartitionQualifiedVariables =
+ map[string]android.PartitionQualifiedVariablesType{
+ "system": {
+ BoardAvbKeyPath: "external/avb/test/data/testkey_rsa4096.pem",
+ BoardAvbAlgorithm: "SHA256_RSA4096",
+ BoardAvbRollbackIndex: "0",
+ BoardFileSystemType: "ext4",
+ },
+ }
+ }),
+ android.FixtureMergeMockFs(android.MockFS{
+ "external/avb/test/data/testkey_rsa4096.pem": nil,
+ }),
+ ).RunTestWithBp(t, `
+ soong_filesystem_creator {
+ name: "foo",
+ }
+ `)
+
+ fooSystem := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().(interface {
+ FsProps() filesystem.FilesystemProperties
+ })
+ android.AssertBoolEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_ENABLE'",
+ true,
+ proptools.Bool(fooSystem.FsProps().Use_avb),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_KEY_PATH'",
+ "external/avb/test/data/testkey_rsa4096.pem",
+ proptools.String(fooSystem.FsProps().Avb_private_key),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_ALGORITHM'",
+ "SHA256_RSA4096",
+ proptools.String(fooSystem.FsProps().Avb_algorithm),
+ )
+ android.AssertIntEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_AVB_SYSTEM_ROLLBACK_INDEX'",
+ 0,
+ proptools.Int(fooSystem.FsProps().Rollback_index),
+ )
+ android.AssertStringEquals(
+ t,
+ "Property expected to match the product variable 'BOARD_SYSTEMIMAGE_FILE_SYSTEM_TYPE'",
+ "ext4",
+ proptools.String(fooSystem.FsProps().Type),
+ )
+}
diff --git a/java/app.go b/java/app.go
index 381808a..1358faf 100644
--- a/java/app.go
+++ b/java/app.go
@@ -63,6 +63,16 @@
ctx.RegisterModuleType("override_android_test", OverrideAndroidTestModuleFactory)
}
+type AppInfo struct {
+ // Updatable is set to the value of the updatable property
+ Updatable bool
+
+ // TestHelperApp is true if the module is a android_test_helper_app
+ TestHelperApp bool
+}
+
+var AppInfoProvider = blueprint.NewProvider[*AppInfo]()
+
// AndroidManifest.xml merging
// package splits
@@ -385,7 +395,10 @@
android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{
TestOnly: true,
})
-
+ android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+ Updatable: Bool(a.appProperties.Updatable),
+ TestHelperApp: true,
+ })
}
func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
@@ -393,6 +406,10 @@
a.checkEmbedJnis(ctx)
a.generateAndroidBuildActions(ctx)
a.generateJavaUsedByApex(ctx)
+ android.SetProvider(ctx, AppInfoProvider, &AppInfo{
+ Updatable: Bool(a.appProperties.Updatable),
+ TestHelperApp: false,
+ })
}
func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) {
@@ -1206,10 +1223,6 @@
return Bool(a.appProperties.Updatable)
}
-func (a *AndroidApp) SetUpdatable(val bool) {
- a.appProperties.Updatable = &val
-}
-
func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string {
certificate, overridden := ctx.DeviceConfig().OverrideCertificateFor(ctx.ModuleName())
if overridden {
diff --git a/java/base.go b/java/base.go
index 32bfc17..fc21c44 100644
--- a/java/base.go
+++ b/java/base.go
@@ -218,11 +218,15 @@
// the stubs via static libs.
Is_stubs_module *bool
- // If true, enable the "Ravenizer" tool on the output jar.
- // "Ravenizer" is a tool for Ravenwood tests, but it can also be enabled on other kinds
- // of java targets.
Ravenizer struct {
+ // If true, enable the "Ravenizer" tool on the output jar.
+ // "Ravenizer" is a tool for Ravenwood tests, but it can also be enabled on other kinds
+ // of java targets.
Enabled *bool
+
+ // If true, the "Ravenizer" tool will remove all Mockito and DexMaker
+ // classes from the output jar.
+ Strip_mockito *bool
}
// Contributing api surface of the stub module. Is not visible to bp modules, and should
@@ -1134,8 +1138,9 @@
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
- if re := proptools.Bool(j.properties.Ravenizer.Enabled); re {
- j.ravenizer.enabled = re
+ // Only override the original value if explicitly set
+ if j.properties.Ravenizer.Enabled != nil {
+ j.ravenizer.enabled = *j.properties.Ravenizer.Enabled
}
deps := j.collectDeps(ctx)
@@ -1624,12 +1629,11 @@
if j.ravenizer.enabled {
ravenizerInput := outputFile
ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", jarName)
- ctx.Build(pctx, android.BuildParams{
- Rule: ravenizer,
- Description: "ravenizer",
- Input: ravenizerInput,
- Output: ravenizerOutput,
- })
+ ravenizerArgs := ""
+ if proptools.Bool(j.properties.Ravenizer.Strip_mockito) {
+ ravenizerArgs = "--strip-mockito"
+ }
+ TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs)
outputFile = ravenizerOutput
localImplementationJars = android.Paths{ravenizerOutput}
completeStaticLibsImplementationJars = android.NewDepSet(android.PREORDER, localImplementationJars, nil)
diff --git a/java/builder.go b/java/builder.go
index 81b0feb..e5d5109 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -260,10 +260,10 @@
ravenizer = pctx.AndroidStaticRule("ravenizer",
blueprint.RuleParams{
- Command: "rm -f $out && ${ravenizer} --in-jar $in --out-jar $out",
+ Command: "rm -f $out && ${ravenizer} --in-jar $in --out-jar $out $ravenizerArgs",
CommandDeps: []string{"${ravenizer}"},
},
- )
+ "ravenizerArgs")
apimapper = pctx.AndroidStaticRule("apimapper",
blueprint.RuleParams{
@@ -703,6 +703,7 @@
// Remove any module-info.class files that may have come from prebuilt jars, they cause problems
// for downstream tools like desugar.
jarArgs = append(jarArgs, "-stripFile module-info.class")
+ jarArgs = append(jarArgs, "-stripFile META-INF/versions/*/module-info.class")
if stripDirEntries {
jarArgs = append(jarArgs, "-D")
@@ -782,12 +783,15 @@
}
func TransformRavenizer(ctx android.ModuleContext, outputFile android.WritablePath,
- inputFile android.Path) {
+ inputFile android.Path, ravenizerArgs string) {
ctx.Build(pctx, android.BuildParams{
Rule: ravenizer,
Description: "ravenizer",
Output: outputFile,
Input: inputFile,
+ Args: map[string]string{
+ "ravenizerArgs": ravenizerArgs,
+ },
})
}
diff --git a/rust/compiler.go b/rust/compiler.go
index a2546a1..5bce16b 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -39,13 +39,13 @@
initialize(ctx ModuleContext)
compilerFlags(ctx ModuleContext, flags Flags) Flags
cfgFlags(ctx ModuleContext, flags Flags) Flags
- featureFlags(ctx ModuleContext, flags Flags) Flags
+ featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags
compilerProps() []interface{}
compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput
compilerDeps(ctx DepsContext, deps Deps) Deps
crateName() string
edition() string
- features() []string
+ features(ctx android.ConfigurableEvaluatorContext, module *Module) []string
rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath
Thinlto() bool
@@ -194,7 +194,7 @@
Crate_name string `android:"arch_variant"`
// list of features to enable for this crate
- Features []string `android:"arch_variant"`
+ Features proptools.Configurable[[]string] `android:"arch_variant"`
// list of configuration options to enable for this crate. To enable features, use the "features" property.
Cfgs proptools.Configurable[[]string] `android:"arch_variant"`
@@ -346,22 +346,23 @@
return flags
}
-func (compiler *baseCompiler) features() []string {
- return compiler.Properties.Features
+func (compiler *baseCompiler) features(ctx android.ConfigurableEvaluatorContext, module *Module) []string {
+ eval := module.ConfigurableEvaluator(ctx)
+ return compiler.Properties.Features.GetOrDefault(eval, nil)
}
-func (compiler *baseCompiler) featuresToFlags() []string {
+func (compiler *baseCompiler) featuresToFlags(ctx android.ConfigurableEvaluatorContext, module *Module) []string {
flags := []string{}
- for _, feature := range compiler.features() {
+ for _, feature := range compiler.features(ctx, module) {
flags = append(flags, "--cfg 'feature=\""+feature+"\"'")
}
return flags
}
-func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags {
- flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags()...)
- flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags()...)
+func (compiler *baseCompiler) featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags {
+ flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(ctx, module)...)
+ flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags(ctx, module)...)
return flags
}
diff --git a/rust/project_json.go b/rust/project_json.go
index 24dcc89..6c1e320 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -151,7 +151,7 @@
crate.Env["OUT_DIR"] = rModule.compiler.cargoOutDir().String()
}
- for _, feature := range rModule.compiler.features() {
+ for _, feature := range rModule.compiler.features(ctx, rModule) {
crate.Cfg = append(crate.Cfg, "feature=\""+feature+"\"")
}
diff --git a/rust/rust.go b/rust/rust.go
index 50f822b..5602edc 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -920,7 +920,7 @@
if mod.compiler != nil {
flags = mod.compiler.compilerFlags(ctx, flags)
flags = mod.compiler.cfgFlags(ctx, flags)
- flags = mod.compiler.featureFlags(ctx, flags)
+ flags = mod.compiler.featureFlags(ctx, mod, flags)
}
if mod.coverage != nil {
flags, deps = mod.coverage.flags(ctx, flags, deps)
diff --git a/soong_ui.bash b/soong_ui.bash
index 2f688ef..be78b68 100755
--- a/soong_ui.bash
+++ b/soong_ui.bash
@@ -14,18 +14,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../make/shell_utils.sh
+require_top
+
# To track how long we took to startup.
case $(uname -s) in
Darwin)
- export TRACE_BEGIN_SOONG=`$T/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
+ export TRACE_BEGIN_SOONG=`$TOP/prebuilts/build-tools/path/darwin-x86/date +%s%3N`
;;
*)
export TRACE_BEGIN_SOONG=$(date +%s%N)
;;
esac
-source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../make/shell_utils.sh
-require_top
setup_cog_env_if_needed
# Save the current PWD for use in soong_ui