blob: 2513af898de2c77e946334066fbdf87e8ec71e4e [file] [log] [blame]
Cole Faustb85d1a12022-11-08 18:14:01 -08001package bp2build
2
3import (
Cole Faustf8231dd2023-04-21 17:37:11 -07004 "android/soong/android"
5 "android/soong/starlark_import"
6 "encoding/json"
Cole Faustb85d1a12022-11-08 18:14:01 -08007 "fmt"
8 "os"
9 "path/filepath"
Cole Faustf055db62023-07-24 15:17:03 -070010 "reflect"
Cole Faustb85d1a12022-11-08 18:14:01 -080011 "strings"
Cole Faustf8231dd2023-04-21 17:37:11 -070012
13 "github.com/google/blueprint/proptools"
14 "go.starlark.net/starlark"
Cole Faustb85d1a12022-11-08 18:14:01 -080015)
16
17func CreateProductConfigFiles(
Cole Faustf8231dd2023-04-21 17:37:11 -070018 ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
Cole Faustb85d1a12022-11-08 18:14:01 -080019 cfg := &ctx.config
20 targetProduct := "unknown"
21 if cfg.HasDeviceProduct() {
22 targetProduct = cfg.DeviceProduct()
23 }
24 targetBuildVariant := "user"
25 if cfg.Eng() {
26 targetBuildVariant = "eng"
27 } else if cfg.Debuggable() {
28 targetBuildVariant = "userdebug"
29 }
30
31 productVariablesFileName := cfg.ProductVariablesFileName
32 if !strings.HasPrefix(productVariablesFileName, "/") {
33 productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
34 }
Cole Faustf8231dd2023-04-21 17:37:11 -070035 productVariablesBytes, err := os.ReadFile(productVariablesFileName)
Cole Faustb85d1a12022-11-08 18:14:01 -080036 if err != nil {
Cole Faustf8231dd2023-04-21 17:37:11 -070037 return nil, nil, err
38 }
39 productVariables := android.ProductVariables{}
40 err = json.Unmarshal(productVariablesBytes, &productVariables)
41 if err != nil {
42 return nil, nil, err
Cole Faustb85d1a12022-11-08 18:14:01 -080043 }
44
45 // TODO(b/249685973): the name is product_config_platforms because product_config
46 // was already used for other files. Deduplicate them.
47 currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant)
48
49 productReplacer := strings.NewReplacer(
50 "{PRODUCT}", targetProduct,
51 "{VARIANT}", targetBuildVariant,
52 "{PRODUCT_FOLDER}", currentProductFolder)
53
Cole Faustf8231dd2023-04-21 17:37:11 -070054 platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables)
55 if err != nil {
56 return nil, nil, err
57 }
58
59 injectionDirFiles := []BazelFile{
Cole Faustb85d1a12022-11-08 18:14:01 -080060 newFile(
61 currentProductFolder,
62 "soong.variables.bzl",
Cole Faustf8231dd2023-04-21 17:37:11 -070063 `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`),
Cole Faustb85d1a12022-11-08 18:14:01 -080064 newFile(
65 currentProductFolder,
66 "BUILD",
67 productReplacer.Replace(`
68package(default_visibility=[
69 "@soong_injection//product_config_platforms:__subpackages__",
70 "@//build/bazel/product_config:__subpackages__",
71])
72load(":soong.variables.bzl", _soong_variables = "variables")
Cole Faustbd249822023-03-24 16:03:43 -070073load("@//build/bazel/product_config:android_product.bzl", "android_product")
Cole Faustb85d1a12022-11-08 18:14:01 -080074
75android_product(
76 name = "{PRODUCT}-{VARIANT}",
77 soong_variables = _soong_variables,
78)
79`)),
80 newFile(
81 "product_config_platforms",
82 "BUILD.bazel",
83 productReplacer.Replace(`
84package(default_visibility = [
85 "@//build/bazel/product_config:__subpackages__",
86 "@soong_injection//product_config_platforms:__subpackages__",
87])
Jingwen Chen583ab212023-05-30 09:45:23 +000088
89load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables")
90load("@//build/bazel/product_config:android_product.bzl", "android_product")
91
Cole Faust319abae2023-06-06 15:12:49 -070092# Bazel will qualify its outputs by the platform name. When switching between products, this
93# means that soong-built files that depend on bazel-built files will suddenly get different
94# dependency files, because the path changes, and they will be rebuilt. In order to avoid this
95# extra rebuilding, make mixed builds always use a single platform so that the bazel artifacts
96# are always under the same path.
Jingwen Chen583ab212023-05-30 09:45:23 +000097android_product(
Cole Faust319abae2023-06-06 15:12:49 -070098 name = "mixed_builds_product-{VARIANT}",
Jingwen Chen583ab212023-05-30 09:45:23 +000099 soong_variables = _soong_variables,
Cole Faustbc65a3f2023-08-01 16:38:55 +0000100 extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
Jingwen Chen583ab212023-05-30 09:45:23 +0000101)
Cole Faust117bb742023-03-29 14:46:20 -0700102`)),
103 newFile(
104 "product_config_platforms",
105 "product_labels.bzl",
106 productReplacer.Replace(`
107# This file keeps a list of all the products in the android source tree, because they're
108# discovered as part of a preprocessing step before bazel runs.
109# TODO: When we start generating the platforms for more than just the
110# currently lunched product, they should all be listed here
111product_labels = [
Cole Faust319abae2023-06-06 15:12:49 -0700112 "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
Cole Faust117bb742023-03-29 14:46:20 -0700113 "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
114]
Cole Faustb85d1a12022-11-08 18:14:01 -0800115`)),
116 newFile(
117 "product_config_platforms",
118 "common.bazelrc",
119 productReplacer.Replace(`
Cole Faustf8231dd2023-04-21 17:37:11 -0700120build --platform_mappings=platform_mappings
Cole Faust319abae2023-06-06 15:12:49 -0700121build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800122
Cole Faust319abae2023-06-06 15:12:49 -0700123build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
124build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
125build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
126build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
127build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800128`)),
129 newFile(
130 "product_config_platforms",
131 "linux.bazelrc",
132 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700133build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800134`)),
135 newFile(
136 "product_config_platforms",
137 "darwin.bazelrc",
138 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700139build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800140`)),
141 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700142 bp2buildDirFiles := []BazelFile{
143 newFile(
144 "",
145 "platform_mappings",
146 platformMappingContent),
147 }
148 return injectionDirFiles, bp2buildDirFiles, nil
149}
Cole Faustb85d1a12022-11-08 18:14:01 -0800150
Cole Faustf8231dd2023-04-21 17:37:11 -0700151func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables) (string, error) {
152 productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
153 if err != nil {
154 return "", err
155 }
Cole Faustf055db62023-07-24 15:17:03 -0700156 var result strings.Builder
157 result.WriteString("platforms:\n")
158 platformMappingSingleProduct(mainProductLabel, mainProductVariables, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700159 for product, productVariablesStarlark := range productsForTesting {
160 productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
161 if err != nil {
162 return "", err
163 }
Cole Faustf055db62023-07-24 15:17:03 -0700164 platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700165 }
Cole Faustf055db62023-07-24 15:17:03 -0700166 return result.String(), nil
Cole Faustf8231dd2023-04-21 17:37:11 -0700167}
168
Cole Faust88c8efb2023-07-18 11:05:16 -0700169var bazelPlatformSuffixes = []string{
170 "",
171 "_darwin_arm64",
172 "_darwin_x86_64",
173 "_linux_bionic_arm64",
174 "_linux_bionic_x86_64",
175 "_linux_musl_x86",
176 "_linux_musl_x86_64",
177 "_linux_x86",
178 "_linux_x86_64",
179 "_windows_x86",
180 "_windows_x86_64",
181}
182
Cole Faustf055db62023-07-24 15:17:03 -0700183func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, result *strings.Builder) {
184 targetBuildVariant := "user"
185 if proptools.Bool(productVariables.Eng) {
186 targetBuildVariant = "eng"
187 } else if proptools.Bool(productVariables.Debuggable) {
188 targetBuildVariant = "userdebug"
Cole Faustf8231dd2023-04-21 17:37:11 -0700189 }
Cole Faustf055db62023-07-24 15:17:03 -0700190
191 for _, suffix := range bazelPlatformSuffixes {
192 result.WriteString(" ")
193 result.WriteString(label)
194 result.WriteString(suffix)
195 result.WriteString("\n")
196 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
197 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
198 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
199 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
200 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
201 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
202 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
203 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
204 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
205 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
206 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
207 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
208 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
209 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
210 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
211 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
212 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
213 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
214 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
215 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
216 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
217 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
218 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700219}
220
221func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
Cole Faustf8231dd2023-04-21 17:37:11 -0700222 result := android.ProductVariables{}
Cole Faustf055db62023-07-24 15:17:03 -0700223 productVarsReflect := reflect.ValueOf(&result).Elem()
224 for i := 0; i < productVarsReflect.NumField(); i++ {
225 field := productVarsReflect.Field(i)
226 fieldType := productVarsReflect.Type().Field(i)
227 name := fieldType.Name
228 if name == "BootJars" || name == "ApexBootJars" || name == "VendorVars" ||
229 name == "VendorSnapshotModules" || name == "RecoverySnapshotModules" {
230 // These variables have more complicated types, and we don't need them right now
231 continue
232 }
233 if _, ok := in[name]; ok {
234 switch field.Type().Kind() {
235 case reflect.Bool:
236 val, err := starlark_import.Unmarshal[bool](in[name])
237 if err != nil {
238 return result, err
239 }
240 field.SetBool(val)
241 case reflect.String:
242 val, err := starlark_import.Unmarshal[string](in[name])
243 if err != nil {
244 return result, err
245 }
246 field.SetString(val)
247 case reflect.Slice:
248 if field.Type().Elem().Kind() != reflect.String {
249 return result, fmt.Errorf("slices of types other than strings are unimplemented")
250 }
251 val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
252 if err != nil {
253 return result, err
254 }
255 field.Set(val)
256 case reflect.Pointer:
257 switch field.Type().Elem().Kind() {
258 case reflect.Bool:
259 val, err := starlark_import.UnmarshalNoneable[bool](in[name])
260 if err != nil {
261 return result, err
262 }
263 field.Set(reflect.ValueOf(val))
264 case reflect.String:
265 val, err := starlark_import.UnmarshalNoneable[string](in[name])
266 if err != nil {
267 return result, err
268 }
269 field.Set(reflect.ValueOf(val))
270 case reflect.Int:
271 val, err := starlark_import.UnmarshalNoneable[int](in[name])
272 if err != nil {
273 return result, err
274 }
275 field.Set(reflect.ValueOf(val))
276 default:
277 return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
278 }
279 default:
280 return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
281 }
282 }
Cole Faust88c8efb2023-07-18 11:05:16 -0700283 }
Cole Faustf055db62023-07-24 15:17:03 -0700284
Cole Faustb85d1a12022-11-08 18:14:01 -0800285 return result, nil
286}