blob: db478db35134c2542b4a8a4a256e839a10415da8 [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}
125build:linux_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
126build:linux_bionic_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_bionic_x86_64
127build:linux_musl_x86 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86
128build:linux_musl_x86_64 --platforms=@soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_musl_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800129`)),
130 newFile(
131 "product_config_platforms",
132 "linux.bazelrc",
133 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700134build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_linux_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800135`)),
136 newFile(
137 "product_config_platforms",
138 "darwin.bazelrc",
139 productReplacer.Replace(`
Cole Faust319abae2023-06-06 15:12:49 -0700140build --host_platform @soong_injection//{PRODUCT_FOLDER}:{PRODUCT}-{VARIANT}_darwin_x86_64
Cole Faustb85d1a12022-11-08 18:14:01 -0800141`)),
142 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700143 bp2buildDirFiles := []BazelFile{
144 newFile(
145 "",
146 "platform_mappings",
147 platformMappingContent),
148 }
149 return injectionDirFiles, bp2buildDirFiles, nil
150}
Cole Faustb85d1a12022-11-08 18:14:01 -0800151
Cole Faust87c0c332023-07-31 12:10:12 -0700152func platformMappingContent(mainProductLabel string, mainProductVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions) (string, error) {
Cole Faustf8231dd2023-04-21 17:37:11 -0700153 productsForTesting, err := starlark_import.GetStarlarkValue[map[string]map[string]starlark.Value]("products_for_testing")
154 if err != nil {
155 return "", err
156 }
Cole Faustf055db62023-07-24 15:17:03 -0700157 var result strings.Builder
158 result.WriteString("platforms:\n")
Cole Faust87c0c332023-07-31 12:10:12 -0700159 platformMappingSingleProduct(mainProductLabel, mainProductVariables, soongConfigDefinitions, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700160 for product, productVariablesStarlark := range productsForTesting {
161 productVariables, err := starlarkMapToProductVariables(productVariablesStarlark)
162 if err != nil {
163 return "", err
164 }
Cole Faust87c0c332023-07-31 12:10:12 -0700165 platformMappingSingleProduct("@//build/bazel/tests/products:"+product, &productVariables, soongConfigDefinitions, &result)
Cole Faustf8231dd2023-04-21 17:37:11 -0700166 }
Cole Faustf055db62023-07-24 15:17:03 -0700167 return result.String(), nil
Cole Faustf8231dd2023-04-21 17:37:11 -0700168}
169
Cole Faust88c8efb2023-07-18 11:05:16 -0700170var bazelPlatformSuffixes = []string{
171 "",
172 "_darwin_arm64",
173 "_darwin_x86_64",
174 "_linux_bionic_arm64",
175 "_linux_bionic_x86_64",
176 "_linux_musl_x86",
177 "_linux_musl_x86_64",
178 "_linux_x86",
179 "_linux_x86_64",
180 "_windows_x86",
181 "_windows_x86_64",
182}
183
Cole Faust87c0c332023-07-31 12:10:12 -0700184func platformMappingSingleProduct(label string, productVariables *android.ProductVariables, soongConfigDefinitions soongconfig.Bp2BuildSoongConfigDefinitions, result *strings.Builder) {
Cole Faustf055db62023-07-24 15:17:03 -0700185 targetBuildVariant := "user"
186 if proptools.Bool(productVariables.Eng) {
187 targetBuildVariant = "eng"
188 } else if proptools.Bool(productVariables.Debuggable) {
189 targetBuildVariant = "userdebug"
Cole Faustf8231dd2023-04-21 17:37:11 -0700190 }
Cole Faustf055db62023-07-24 15:17:03 -0700191
192 for _, suffix := range bazelPlatformSuffixes {
193 result.WriteString(" ")
194 result.WriteString(label)
195 result.WriteString(suffix)
196 result.WriteString("\n")
197 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 -0700198 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:arc=%t\n", proptools.Bool(productVariables.Arc)))
Cole Faustf055db62023-07-24 15:17:03 -0700199 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 -0700200 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:binder32bit=%t\n", proptools.Bool(productVariables.Binder32bit)))
201 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 -0700202 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_id=%s\n", proptools.String(productVariables.BuildId)))
203 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:build_version_tags=%s\n", strings.Join(productVariables.BuildVersionTags, ",")))
204 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:certificate_overrides=%s\n", strings.Join(productVariables.CertificateOverrides, ",")))
205 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_exclude_paths=%s\n", strings.Join(productVariables.CFIExcludePaths, ",")))
206 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:cfi_include_paths=%s\n", strings.Join(productVariables.CFIIncludePaths, ",")))
207 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:compressed_apex=%t\n", proptools.Bool(productVariables.CompressedApex)))
Cole Faust87c0c332023-07-31 12:10:12 -0700208 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:debuggable=%t\n", proptools.Bool(productVariables.Debuggable)))
Cole Faustf055db62023-07-24 15:17:03 -0700209 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:default_app_certificate=%s\n", proptools.String(productVariables.DefaultAppCertificate)))
210 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_abi=%s\n", strings.Join(productVariables.DeviceAbi, ",")))
211 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_max_page_size_supported=%s\n", proptools.String(productVariables.DeviceMaxPageSizeSupported)))
212 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_name=%s\n", proptools.String(productVariables.DeviceName)))
Cole Faust87c0c332023-07-31 12:10:12 -0700213 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 -0700214 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:device_product=%s\n", proptools.String(productVariables.DeviceProduct)))
215 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enable_cfi=%t\n", proptools.BoolDefault(productVariables.EnableCFI, true)))
Cole Faust87c0c332023-07-31 12:10:12 -0700216 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:enforce_vintf_manifest=%t\n", proptools.Bool(productVariables.Enforce_vintf_manifest)))
217 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:eng=%t\n", proptools.Bool(productVariables.Eng)))
218 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_not_svelte=%t\n", proptools.Bool(productVariables.Malloc_not_svelte)))
219 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:malloc_pattern_fill_contents=%t\n", proptools.Bool(productVariables.Malloc_pattern_fill_contents)))
220 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 -0700221 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 -0700222 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:native_coverage=%t\n", proptools.Bool(productVariables.Native_coverage)))
Cole Faustf055db62023-07-24 15:17:03 -0700223 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_version_name=%s\n", proptools.String(productVariables.Platform_version_name)))
224 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_brand=%s\n", productVariables.ProductBrand))
225 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:product_manufacturer=%s\n", productVariables.ProductManufacturer))
Cole Faust87c0c332023-07-31 12:10:12 -0700226 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:platform_sdk_version=%d\n", *productVariables.Platform_sdk_version))
227 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:safestack=%t\n", proptools.Bool(productVariables.Safestack)))
Cole Faustf055db62023-07-24 15:17:03 -0700228 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:target_build_variant=%s\n", targetBuildVariant))
Cole Faust87c0c332023-07-31 12:10:12 -0700229 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 -0700230 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:tidy_checks=%s\n", proptools.String(productVariables.TidyChecks)))
Cole Faust87c0c332023-07-31 12:10:12 -0700231 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:uml=%t\n", proptools.Bool(productVariables.Uml)))
Cole Faustf055db62023-07-24 15:17:03 -0700232 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config:unbundled_build=%t\n", proptools.Bool(productVariables.Unbundled_build)))
233 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 -0700234 for namespace, namespaceContents := range productVariables.VendorVars {
235 for variable, value := range namespaceContents {
236 key := namespace + "__" + variable
237 _, hasBool := soongConfigDefinitions.BoolVars[key]
238 _, hasString := soongConfigDefinitions.StringVars[key]
239 _, hasValue := soongConfigDefinitions.ValueVars[key]
240 if !hasBool && !hasString && !hasValue {
241 // Not all soong config variables are defined in Android.bp files. For example,
242 // prebuilt_bootclasspath_fragment uses soong config variables in a nonstandard
243 // way, that causes them to be present in the soong.variables file but not
244 // defined in an Android.bp file. There's also nothing stopping you from setting
245 // a variable in make that doesn't exist in soong. We only generate build
246 // settings for the ones that exist in soong, so skip all others.
247 continue
248 }
249 if hasBool && hasString || hasBool && hasValue || hasString && hasValue {
250 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))
251 }
252 if hasBool {
253 // Logic copied from soongConfig.Bool()
254 value = strings.ToLower(value)
255 if value == "1" || value == "y" || value == "yes" || value == "on" || value == "true" {
256 value = "true"
257 } else {
258 value = "false"
259 }
260 }
261 result.WriteString(fmt.Sprintf(" --//build/bazel/product_config/soong_config_variables:%s=%s\n", strings.ToLower(key), value))
262 }
263 }
Cole Faustf055db62023-07-24 15:17:03 -0700264 }
Cole Faustf8231dd2023-04-21 17:37:11 -0700265}
266
267func starlarkMapToProductVariables(in map[string]starlark.Value) (android.ProductVariables, error) {
Cole Faustf8231dd2023-04-21 17:37:11 -0700268 result := android.ProductVariables{}
Cole Faustf055db62023-07-24 15:17:03 -0700269 productVarsReflect := reflect.ValueOf(&result).Elem()
270 for i := 0; i < productVarsReflect.NumField(); i++ {
271 field := productVarsReflect.Field(i)
272 fieldType := productVarsReflect.Type().Field(i)
273 name := fieldType.Name
Cole Faust87c0c332023-07-31 12:10:12 -0700274 if name == "BootJars" || name == "ApexBootJars" || name == "VendorSnapshotModules" ||
275 name == "RecoverySnapshotModules" {
Cole Faustf055db62023-07-24 15:17:03 -0700276 // These variables have more complicated types, and we don't need them right now
277 continue
278 }
279 if _, ok := in[name]; ok {
Cole Faust87c0c332023-07-31 12:10:12 -0700280 if name == "VendorVars" {
281 vendorVars, err := starlark_import.Unmarshal[map[string]map[string]string](in[name])
282 if err != nil {
283 return result, err
284 }
285 field.Set(reflect.ValueOf(vendorVars))
286 continue
287 }
Cole Faustf055db62023-07-24 15:17:03 -0700288 switch field.Type().Kind() {
289 case reflect.Bool:
290 val, err := starlark_import.Unmarshal[bool](in[name])
291 if err != nil {
292 return result, err
293 }
294 field.SetBool(val)
295 case reflect.String:
296 val, err := starlark_import.Unmarshal[string](in[name])
297 if err != nil {
298 return result, err
299 }
300 field.SetString(val)
301 case reflect.Slice:
302 if field.Type().Elem().Kind() != reflect.String {
303 return result, fmt.Errorf("slices of types other than strings are unimplemented")
304 }
305 val, err := starlark_import.UnmarshalReflect(in[name], field.Type())
306 if err != nil {
307 return result, err
308 }
309 field.Set(val)
310 case reflect.Pointer:
311 switch field.Type().Elem().Kind() {
312 case reflect.Bool:
313 val, err := starlark_import.UnmarshalNoneable[bool](in[name])
314 if err != nil {
315 return result, err
316 }
317 field.Set(reflect.ValueOf(val))
318 case reflect.String:
319 val, err := starlark_import.UnmarshalNoneable[string](in[name])
320 if err != nil {
321 return result, err
322 }
323 field.Set(reflect.ValueOf(val))
324 case reflect.Int:
325 val, err := starlark_import.UnmarshalNoneable[int](in[name])
326 if err != nil {
327 return result, err
328 }
329 field.Set(reflect.ValueOf(val))
330 default:
331 return result, fmt.Errorf("pointers of types other than strings/bools are unimplemented: %s", field.Type().Elem().Kind().String())
332 }
333 default:
334 return result, fmt.Errorf("unimplemented type: %s", field.Type().String())
335 }
336 }
Cole Faust88c8efb2023-07-18 11:05:16 -0700337 }
Cole Faustf055db62023-07-24 15:17:03 -0700338
Cole Faust87c0c332023-07-31 12:10:12 -0700339 result.Native_coverage = proptools.BoolPtr(
340 proptools.Bool(result.GcovCoverage) ||
341 proptools.Bool(result.ClangCoverage))
342
Cole Faustb85d1a12022-11-08 18:14:01 -0800343 return result, nil
344}