blob: 2f3dc1c171558845f8d61bf49a065d0b754e38bc [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"
Cole Faust87c0c332023-07-31 12:10:12 -07005 "android/soong/android/soongconfig"
Cole Faustf8231dd2023-04-21 17:37:11 -07006 "android/soong/starlark_import"
7 "encoding/json"
Cole Faustb85d1a12022-11-08 18:14:01 -08008 "fmt"
9 "os"
10 "path/filepath"
Cole Faustf055db62023-07-24 15:17:03 -070011 "reflect"
Cole Faustb85d1a12022-11-08 18:14:01 -080012 "strings"
Cole Faustf8231dd2023-04-21 17:37:11 -070013
14 "github.com/google/blueprint/proptools"
15 "go.starlark.net/starlark"
Cole Faustb85d1a12022-11-08 18:14:01 -080016)
17
18func CreateProductConfigFiles(
Cole Faustf8231dd2023-04-21 17:37:11 -070019 ctx *CodegenContext) ([]BazelFile, []BazelFile, error) {
Cole Faustb85d1a12022-11-08 18:14:01 -080020 cfg := &ctx.config
21 targetProduct := "unknown"
22 if cfg.HasDeviceProduct() {
23 targetProduct = cfg.DeviceProduct()
24 }
25 targetBuildVariant := "user"
26 if cfg.Eng() {
27 targetBuildVariant = "eng"
28 } else if cfg.Debuggable() {
29 targetBuildVariant = "userdebug"
30 }
31
32 productVariablesFileName := cfg.ProductVariablesFileName
33 if !strings.HasPrefix(productVariablesFileName, "/") {
34 productVariablesFileName = filepath.Join(ctx.topDir, productVariablesFileName)
35 }
Cole Faustf8231dd2023-04-21 17:37:11 -070036 productVariablesBytes, err := os.ReadFile(productVariablesFileName)
Cole Faustb85d1a12022-11-08 18:14:01 -080037 if err != nil {
Cole Faustf8231dd2023-04-21 17:37:11 -070038 return nil, nil, err
39 }
40 productVariables := android.ProductVariables{}
41 err = json.Unmarshal(productVariablesBytes, &productVariables)
42 if err != nil {
43 return nil, nil, err
Cole Faustb85d1a12022-11-08 18:14:01 -080044 }
45
46 // TODO(b/249685973): the name is product_config_platforms because product_config
47 // was already used for other files. Deduplicate them.
48 currentProductFolder := fmt.Sprintf("product_config_platforms/products/%s-%s", targetProduct, targetBuildVariant)
49
50 productReplacer := strings.NewReplacer(
51 "{PRODUCT}", targetProduct,
52 "{VARIANT}", targetBuildVariant,
53 "{PRODUCT_FOLDER}", currentProductFolder)
54
Cole Faust87c0c332023-07-31 12:10:12 -070055 platformMappingContent, err := platformMappingContent(productReplacer.Replace("@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"), &productVariables, ctx.Config().Bp2buildSoongConfigDefinitions)
Cole Faustf8231dd2023-04-21 17:37:11 -070056 if err != nil {
57 return nil, nil, err
58 }
59
60 injectionDirFiles := []BazelFile{
Cole Faustb85d1a12022-11-08 18:14:01 -080061 newFile(
62 currentProductFolder,
63 "soong.variables.bzl",
Cole Faustf8231dd2023-04-21 17:37:11 -070064 `variables = json.decode("""`+strings.ReplaceAll(string(productVariablesBytes), "\\", "\\\\")+`""")`),
Cole Faustb85d1a12022-11-08 18:14:01 -080065 newFile(
66 currentProductFolder,
67 "BUILD",
68 productReplacer.Replace(`
69package(default_visibility=[
70 "@soong_injection//product_config_platforms:__subpackages__",
71 "@//build/bazel/product_config:__subpackages__",
72])
73load(":soong.variables.bzl", _soong_variables = "variables")
Cole Faustbd249822023-03-24 16:03:43 -070074load("@//build/bazel/product_config:android_product.bzl", "android_product")
Cole Faustb85d1a12022-11-08 18:14:01 -080075
76android_product(
77 name = "{PRODUCT}-{VARIANT}",
78 soong_variables = _soong_variables,
79)
80`)),
81 newFile(
82 "product_config_platforms",
83 "BUILD.bazel",
84 productReplacer.Replace(`
85package(default_visibility = [
86 "@//build/bazel/product_config:__subpackages__",
87 "@soong_injection//product_config_platforms:__subpackages__",
88])
Jingwen Chen583ab212023-05-30 09:45:23 +000089
90load("//{PRODUCT_FOLDER}:soong.variables.bzl", _soong_variables = "variables")
91load("@//build/bazel/product_config:android_product.bzl", "android_product")
92
Cole Faust319abae2023-06-06 15:12:49 -070093# Bazel will qualify its outputs by the platform name. When switching between products, this
94# means that soong-built files that depend on bazel-built files will suddenly get different
95# dependency files, because the path changes, and they will be rebuilt. In order to avoid this
96# extra rebuilding, make mixed builds always use a single platform so that the bazel artifacts
97# are always under the same path.
Jingwen Chen583ab212023-05-30 09:45:23 +000098android_product(
Cole Faust319abae2023-06-06 15:12:49 -070099 name = "mixed_builds_product-{VARIANT}",
Jingwen Chen583ab212023-05-30 09:45:23 +0000100 soong_variables = _soong_variables,
Cole Faustbc65a3f2023-08-01 16:38:55 +0000101 extra_constraints = ["@//build/bazel/platforms:mixed_builds"],
Jingwen Chen583ab212023-05-30 09:45:23 +0000102)
Cole Faust117bb742023-03-29 14:46:20 -0700103`)),
104 newFile(
105 "product_config_platforms",
106 "product_labels.bzl",
107 productReplacer.Replace(`
108# This file keeps a list of all the products in the android source tree, because they're
109# discovered as part of a preprocessing step before bazel runs.
110# TODO: When we start generating the platforms for more than just the
111# currently lunched product, they should all be listed here
112product_labels = [
Cole Faust319abae2023-06-06 15:12:49 -0700113 "@soong_injection//product_config_platforms:mixed_builds_product-{VARIANT}",
Cole Faust117bb742023-03-29 14:46:20 -0700114 "@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}"
115]
Cole Faustb85d1a12022-11-08 18:14:01 -0800116`)),
117 newFile(
118 "product_config_platforms",
119 "common.bazelrc",
120 productReplacer.Replace(`
Cole Faustf8231dd2023-04-21 17:37:11 -0700121build --platform_mappings=platform_mappings
Cole Faust319abae2023-06-06 15:12:49 -0700122build --platforms @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800123
Cole Faust319abae2023-06-06 15:12:49 -0700124build:android --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}
Cole Faustd1acaa42023-08-03 17:04:03 -0700125build:linux_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86
Cole Faust319abae2023-06-06 15:12:49 -0700126build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
127build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
128build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
129build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800130`)),
131 newFile(
132 "product_config_platforms",
133 "linux.bazelrc",
134 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700135build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800136`)),
137 newFile(
138 "product_config_platforms",
139 "darwin.bazelrc",
140 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700141build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800142`)),
143 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700144 bp2buildDirFiles := []BazelFile{
145 newFile(
146 "",
147 "platform_mappings",
148 platformMappingContent),
149 }
150 return injectionDirFiles, bp2buildDirFiles, nil
151}
Cole Faustb85d1a12022-11-08 18:14:01 -0800152
Cole Faust87c0c332023-07-31 12:10:12 -0700153func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions) (string, error) {
Cole Faustf8231dd2023-04-21 17:37:11 -0700154 productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
155 if err != nil {
156 return "", err
157 }
Cole Faustf055db62023-07-24 15:17:03 -0700158 var result strings.Builder
159 result.WriteString("platforms:\n")
Cole Faust87c0c332023-07-31 12:10:12 -0700160 platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700161 for product, productVariablesStarlark := range productsForTesting {
162 productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
163 if err != nil {
164 return "", err
165 }
Cole Faust87c0c332023-07-31 12:10:12 -0700166 platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700167 }
Cole Faustf055db62023-07-24 15:17:03 -0700168 return result.String(), nil
Cole Faustf8231dd2023-04-21 17:37:11 -0700169}
170
Cole Faust88c8efb2023-07-18 11:05:16 -0700171var bazelPlatformSuffixes = []string{
172 "",
173 "_darwin_arm64",
174 "_darwin_x86_64",
175 "_linux_bionic_arm64",
176 "_linux_bionic_x86_64",
177 "_linux_musl_x86",
178 "_linux_musl_x86_64",
179 "_linux_x86",
180 "_linux_x86_64",
181 "_windows_x86",
182 "_windows_x86_64",
183}
184
Cole Faust87c0c332023-07-31 12:10:12 -0700185func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, result *strings.Builder) {
Cole Faustf055db62023-07-24 15:17:03 -0700186 targetBuildVariant := "user"
187 if proptools.Bool(productVariables.Eng) {
188 targetBuildVariant = "eng"
189 } else if proptools.Bool(productVariables.Debuggable) {
190 targetBuildVariant = "userdebug"
Cole Faustf8231dd2023-04-21 17:37:11 -0700191 }
Cole Faustf055db62023-07-24 15:17:03 -0700192
193 for _, suffix := range bazelPlatformSuffixes {
194 result.WriteString(" ")
195 result.WriteString(label)
196 result.WriteString(suffix)
197 result.WriteString("\n")
198 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:always_use_prebuilt_sdks=%t\n", proptools.Bool(productVariables.Always_use_prebuilt_sdks)))
Cole Faust87c0c332023-07-31 12:10:12 -0700199 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
Cole Faustf055db62023-07-24 15:17:03 -0700200 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:apex_global_min_sdk_version_override=%s\n", proptools.String(productVariables.ApexGlobalMinSdkVersionOverride)))
Cole Faust87c0c332023-07-31 12:10:12 -0700201 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit)))
202 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_from_text_stub=%t\n", proptools.Bool(productVariables.Build_from_text_stub)))
Cole Faustf055db62023-07-24 15:17:03 -0700203 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
204 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
205 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
206 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
207 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
208 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
Cole Faust87c0c332023-07-31 12:10:12 -0700209 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
Cole Faustf055db62023-07-24 15:17:03 -0700210 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
211 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
212 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
213 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
Cole Faust87c0c332023-07-31 12:10:12 -0700214 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_page_size_agnostic=%t\n", proptools.Bool(productVariables.Device_page_size_agnostic)))
Cole Faustf055db62023-07-24 15:17:03 -0700215 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
216 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
Cole Faust87c0c332023-07-31 12:10:12 -0700217 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
218 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng)))
219 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
220 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents)))
221 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_zero_contents=%t\n", proptools.Bool(productVariables.Malloc_zero_contents)))
Cole Faustf055db62023-07-24 15:17:03 -0700222 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:manifest_package_name_overrides=%s\n", strings.Join(productVariables.ManifestPackageNameOverrides, ",")))
Cole Faust87c0c332023-07-31 12:10:12 -0700223 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
Cole Faustf055db62023-07-24 15:17:03 -0700224 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
225 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
226 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
Cole Faust87c0c332023-07-31 12:10:12 -0700227 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_sdk_version=%d\n", *productVariables.Platform_sdk_version))
228 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
Cole Faustf055db62023-07-24 15:17:03 -0700229 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
Cole Faust87c0c332023-07-31 12:10:12 -0700230 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:treble_linker_namespaces=%t\n", proptools.Bool(productVariables.Treble_linker_namespaces)))
Cole Faustf055db62023-07-24 15:17:03 -0700231 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
Cole Faust87c0c332023-07-31 12:10:12 -0700232 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
Cole Faustf055db62023-07-24 15:17:03 -0700233 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
234 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build_apps=%s\n", strings.Join(productVariables.Unbundled_build_apps, ",")))
Cole Faust87c0c332023-07-31 12:10:12 -0700235 for namespace, namespaceContents := range productVariables.VendorVars {
236 for variable, value := range namespaceContents {
237 key := namespace + "__" + variable
238 _, hasBool := soongConfigDefinitions.BoolVars[key]
239 _, hasString := soongConfigDefinitions.StringVars[key]
240 _, hasValue := soongConfigDefinitions.ValueVars[key]
241 if !hasBool && !hasString && !hasValue {
242 // Not all soong config variables are defined in Android.bp files. For example,
243 // prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard
244 // way, that causes them to be present in the soong.variables file but not
245 // defined in an Android.bp file. There's also nothing stopping you from setting
246 // a variable in make that doesn't exist in soong. We only generate build
247 // settings for the ones that exist in soong, so skip all others.
248 continue
249 }
250 if hasBool && hasString || hasBool && hasValue || hasString && hasValue {
251 panic(fmt.Sprintf("Soong config variable %s:%s appears to be of multiple types. bool? %t, string? %t, value? %t", namespace, variable, hasBool, hasString, hasValue))
252 }
253 if hasBool {
254 // Logic copied from soongConfig.Bool()
255 value = strings.ToLower(value)
256 if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" {
257 value = "true"
258 } else {
259 value = "false"
260 }
261 }
262 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value))
263 }
264 }
Cole Faustf055db62023-07-24 15:17:03 -0700265 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700266}
267
268func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
Cole Faustf8231dd2023-04-21 17:37:11 -0700269 result := android.ProductVariables{}
Cole Faustf055db62023-07-24 15:17:03 -0700270 productVarsReflect := reflect.ValueOf(&result).Elem()
271 for i := 0; i < productVarsReflect.NumField(); i++ {
272 field := productVarsReflect.Field(i)
273 fieldType := productVarsReflect.Type().Field(i)
274 name := fieldType.Name
Cole Faust87c0c332023-07-31 12:10:12 -0700275 if name == "BootJars" || name == "ApexBootJars" || name == "VendorSnapshotModules" ||
276 name == "RecoverySnapshotModules" {
Cole Faustf055db62023-07-24 15:17:03 -0700277 // These variables have more complicated types, and we don't need them right now
278 continue
279 }
280 if _, ok := in[name]; ok {
Cole Faust87c0c332023-07-31 12:10:12 -0700281 if name == "VendorVars" {
282 vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name])
283 if err != nil {
284 return result, err
285 }
286 field.Set(reflect.ValueOf(vendorVars))
287 continue
288 }
Cole Faustf055db62023-07-24 15:17:03 -0700289 switch field.Type().Kind() {
290 case reflect.Bool:
291 val, err := starlark_import.Unmarshal[bool](in[name])
292 if err != nil {
293 return result, err
294 }
295 field.SetBool(val)
296 case reflect.String:
297 val, err := starlark_import.Unmarshal[string](in[name])
298 if err != nil {
299 return result, err
300 }
301 field.SetString(val)
302 case reflect.Slice:
303 if field.Type().Elem().Kind() != reflect.String {
304 return result, fmt.Errorf("slices of types other than strings are unimplemented")
305 }
306 val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
307 if err != nil {
308 return result, err
309 }
310 field.Set(val)
311 case reflect.Pointer:
312 switch field.Type().Elem().Kind() {
313 case reflect.Bool:
314 val, err := starlark_import.UnmarshalNoneable[bool](in[name])
315 if err != nil {
316 return result, err
317 }
318 field.Set(reflect.ValueOf(val))
319 case reflect.String:
320 val, err := starlark_import.UnmarshalNoneable[string](in[name])
321 if err != nil {
322 return result, err
323 }
324 field.Set(reflect.ValueOf(val))
325 case reflect.Int:
326 val, err := starlark_import.UnmarshalNoneable[int](in[name])
327 if err != nil {
328 return result, err
329 }
330 field.Set(reflect.ValueOf(val))
331 default:
332 return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
333 }
334 default:
335 return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
336 }
337 }
Cole Faust88c8efb2023-07-18 11:05:16 -0700338 }
Cole Faustf055db62023-07-24 15:17:03 -0700339
Cole Faust87c0c332023-07-31 12:10:12 -0700340 result.Native_coverage = proptools.BoolPtr(
341 proptools.Bool(result.GcovCoverage) ||
342 proptools.Bool(result.ClangCoverage))
343
Cole Faustb85d1a12022-11-08 18:14:01 -0800344 return result, nil
345}