| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 1 | package bp2build | 
 | 2 |  | 
 | 3 | import ( | 
| Jingwen Chen | 0ee88a6 | 2022-01-07 14:55:29 +0000 | [diff] [blame] | 4 | 	"encoding/json" | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 5 | 	"fmt" | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 6 | 	"reflect" | 
| Cole Faust | 37d27c4 | 2023-04-12 10:27:45 -0700 | [diff] [blame] | 7 | 	"strconv" | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 8 | 	"strings" | 
 | 9 |  | 
| Alex Márquez Pérez Muñíz Díaz Púras Thaureaux | 447f6c9 | 2021-08-31 20:30:36 +0000 | [diff] [blame] | 10 | 	"android/soong/android" | 
| usta | 40caf95 | 2023-08-04 16:52:14 -0400 | [diff] [blame] | 11 | 	"android/soong/apex" | 
| Trevor Radcliffe | 4f95ee9 | 2023-01-19 16:02:47 +0000 | [diff] [blame] | 12 | 	"android/soong/cc" | 
| Sam Delmerico | 932c01c | 2022-03-25 16:33:26 +0000 | [diff] [blame] | 13 | 	cc_config "android/soong/cc/config" | 
 | 14 | 	java_config "android/soong/java/config" | 
| Vinh Tran | 80f6b21 | 2023-08-23 13:49:13 -0400 | [diff] [blame] | 15 | 	rust_config "android/soong/rust/config" | 
| usta | 40caf95 | 2023-08-04 16:52:14 -0400 | [diff] [blame] | 16 | 	"android/soong/starlark_fmt" | 
| Jingwen Chen | 7810e17 | 2022-07-29 02:25:34 +0000 | [diff] [blame] | 17 |  | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 18 | 	"github.com/google/blueprint/proptools" | 
 | 19 | ) | 
 | 20 |  | 
 | 21 | type BazelFile struct { | 
 | 22 | 	Dir      string | 
 | 23 | 	Basename string | 
 | 24 | 	Contents string | 
 | 25 | } | 
 | 26 |  | 
| Cole Faust | 6054cdf | 2023-09-12 10:07:07 -0700 | [diff] [blame] | 27 | // createSoongInjectionDirFiles returns most of the files to write to the soong_injection directory. | 
 | 28 | // Some other files also come from CreateProductConfigFiles | 
 | 29 | func createSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) { | 
 | 30 | 	cfg := ctx.Config() | 
| Jingwen Chen | bf61afb | 2021-05-06 13:31:18 +0000 | [diff] [blame] | 31 | 	var files []BazelFile | 
 | 32 |  | 
| Sam Delmerico | 46d08b4 | 2022-11-15 15:51:04 -0500 | [diff] [blame] | 33 | 	files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package. | 
 | 34 | 	files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg))) | 
 | 35 |  | 
| Jingwen Chen | c63677b | 2021-06-17 05:43:19 +0000 | [diff] [blame] | 36 | 	files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package. | 
| Trevor Radcliffe | 4f95ee9 | 2023-01-19 16:02:47 +0000 | [diff] [blame] | 37 | 	files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg))) | 
 | 38 | 	files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg))) | 
| Sam Delmerico | 932c01c | 2022-03-25 16:33:26 +0000 | [diff] [blame] | 39 |  | 
 | 40 | 	files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package. | 
 | 41 | 	files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg))) | 
| Jingwen Chen | bf61afb | 2021-05-06 13:31:18 +0000 | [diff] [blame] | 42 |  | 
| Vinh Tran | 80f6b21 | 2023-08-23 13:49:13 -0400 | [diff] [blame] | 43 | 	files = append(files, newFile("rust_toolchain", GeneratedBuildFileName, "")) // Creates a //rust_toolchain package. | 
 | 44 | 	files = append(files, newFile("rust_toolchain", "constants.bzl", rust_config.BazelRustToolchainVars(cfg))) | 
 | 45 |  | 
| Jingwen Chen | 7810e17 | 2022-07-29 02:25:34 +0000 | [diff] [blame] | 46 | 	files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package. | 
| Cole Faust | 9e384e2 | 2023-02-08 17:43:09 -0800 | [diff] [blame] | 47 | 	apexToolchainVars, err := apex.BazelApexToolchainVars() | 
 | 48 | 	if err != nil { | 
 | 49 | 		return nil, err | 
 | 50 | 	} | 
 | 51 | 	files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars)) | 
| Jingwen Chen | 7810e17 | 2022-07-29 02:25:34 +0000 | [diff] [blame] | 52 |  | 
| Liz Kammer | 32c634b | 2023-08-25 17:42:42 -0400 | [diff] [blame] | 53 | 	if buf, err := json.MarshalIndent(metrics.convertedModuleWithType, "", "  "); err != nil { | 
 | 54 | 		return []BazelFile{}, err | 
 | 55 | 	} else { | 
 | 56 | 		files = append(files, newFile("metrics", "converted_modules.json", string(buf))) | 
 | 57 | 	} | 
| Jingwen Chen | c63677b | 2021-06-17 05:43:19 +0000 | [diff] [blame] | 58 |  | 
| Kevin Dagostino | 60f562a | 2022-09-20 03:54:47 +0000 | [diff] [blame] | 59 | 	convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t") | 
 | 60 | 	if err != nil { | 
 | 61 | 		panic(err) | 
 | 62 | 	} | 
| Jingwen Chen | 6134211 | 2023-04-11 08:49:01 +0000 | [diff] [blame] | 63 | 	files = append(files, newFile("metrics", GeneratedBuildFileName, "")) // Creates a //metrics package. | 
| Kevin Dagostino | 60f562a | 2022-09-20 03:54:47 +0000 | [diff] [blame] | 64 | 	files = append(files, newFile("metrics", "converted_modules_path_map.json", string(convertedModulePathMap))) | 
| Jingwen Chen | 6134211 | 2023-04-11 08:49:01 +0000 | [diff] [blame] | 65 | 	files = append(files, newFile("metrics", "converted_modules_path_map.bzl", "modules = "+strings.ReplaceAll(string(convertedModulePathMap), "\\", "\\\\"))) | 
| Kevin Dagostino | 60f562a | 2022-09-20 03:54:47 +0000 | [diff] [blame] | 66 |  | 
| Jingwen Chen | 0181202 | 2021-11-19 14:29:43 +0000 | [diff] [blame] | 67 | 	files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String())) | 
 | 68 |  | 
| Liz Kammer | e8303bd | 2022-02-16 09:02:48 -0500 | [diff] [blame] | 69 | 	files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations())) | 
 | 70 |  | 
| Cole Faust | 3486740 | 2023-04-28 12:32:27 -0700 | [diff] [blame] | 71 | 	apiLevelsMap, err := android.GetApiLevelsMap(cfg) | 
 | 72 | 	if err != nil { | 
 | 73 | 		return nil, err | 
 | 74 | 	} | 
 | 75 | 	apiLevelsContent, err := json.Marshal(apiLevelsMap) | 
| Jingwen Chen | 0ee88a6 | 2022-01-07 14:55:29 +0000 | [diff] [blame] | 76 | 	if err != nil { | 
| Cole Faust | 9e384e2 | 2023-02-08 17:43:09 -0800 | [diff] [blame] | 77 | 		return nil, err | 
| Jingwen Chen | 0ee88a6 | 2022-01-07 14:55:29 +0000 | [diff] [blame] | 78 | 	} | 
 | 79 | 	files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`)) | 
| Alix Espino | 4fd7e74 | 2023-02-24 14:46:43 +0000 | [diff] [blame] | 80 | 	// TODO(b/269691302)  value of apiLevelsContent is product variable dependent and should be avoided for soong injection | 
| Jingwen Chen | 0ee88a6 | 2022-01-07 14:55:29 +0000 | [diff] [blame] | 81 | 	files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent))) | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 82 | 	files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg))) | 
| Jingwen Chen | 0ee88a6 | 2022-01-07 14:55:29 +0000 | [diff] [blame] | 83 |  | 
| Sam Delmerico | cb3c52c | 2023-02-03 17:40:08 -0500 | [diff] [blame] | 84 | 	files = append(files, newFile("allowlists", GeneratedBuildFileName, "")) | 
| Cole Faust | 705968d | 2022-12-14 11:32:05 -0800 | [diff] [blame] | 85 | 	// TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested | 
 | 86 | 	files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n")) | 
 | 87 | 	files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n")) | 
 | 88 |  | 
| Cole Faust | 9e384e2 | 2023-02-08 17:43:09 -0800 | [diff] [blame] | 89 | 	return files, nil | 
| Jingwen Chen | bf61afb | 2021-05-06 13:31:18 +0000 | [diff] [blame] | 90 | } | 
 | 91 |  | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 92 | func platformVersionContents(cfg android.Config) string { | 
 | 93 | 	// Despite these coming from cfg.productVariables, they are actually hardcoded in global | 
 | 94 | 	// makefiles, not set in individual product config makesfiles, so they're safe to just export | 
 | 95 | 	// and load() directly. | 
 | 96 |  | 
 | 97 | 	platformVersionActiveCodenames := make([]string, 0, len(cfg.PlatformVersionActiveCodenames())) | 
 | 98 | 	for _, codename := range cfg.PlatformVersionActiveCodenames() { | 
 | 99 | 		platformVersionActiveCodenames = append(platformVersionActiveCodenames, fmt.Sprintf("%q", codename)) | 
 | 100 | 	} | 
 | 101 |  | 
| Cole Faust | 37d27c4 | 2023-04-12 10:27:45 -0700 | [diff] [blame] | 102 | 	platformSdkVersion := "None" | 
 | 103 | 	if cfg.RawPlatformSdkVersion() != nil { | 
 | 104 | 		platformSdkVersion = strconv.Itoa(*cfg.RawPlatformSdkVersion()) | 
 | 105 | 	} | 
 | 106 |  | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 107 | 	return fmt.Sprintf(` | 
 | 108 | platform_versions = struct( | 
 | 109 |     platform_sdk_final = %s, | 
| Cole Faust | 37d27c4 | 2023-04-12 10:27:45 -0700 | [diff] [blame] | 110 |     platform_sdk_version = %s, | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 111 |     platform_sdk_codename = %q, | 
 | 112 |     platform_version_active_codenames = [%s], | 
 | 113 | ) | 
| Cole Faust | 37d27c4 | 2023-04-12 10:27:45 -0700 | [diff] [blame] | 114 | `, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", ")) | 
| Cole Faust | eb644cf | 2023-04-11 13:48:17 -0700 | [diff] [blame] | 115 | } | 
 | 116 |  | 
| usta | 40caf95 | 2023-08-04 16:52:14 -0400 | [diff] [blame] | 117 | func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { | 
| Jingwen Chen | 6c309cd | 2021-04-01 07:11:11 +0000 | [diff] [blame] | 118 | 	var files []BazelFile | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 119 |  | 
| Jingwen Chen | 33832f9 | 2021-01-24 22:55:54 -0500 | [diff] [blame] | 120 | 	if mode == QueryView { | 
| Jingwen Chen | 6c309cd | 2021-04-01 07:11:11 +0000 | [diff] [blame] | 121 | 		// Write top level WORKSPACE. | 
 | 122 | 		files = append(files, newFile("", "WORKSPACE", "")) | 
 | 123 |  | 
| Jingwen Chen | 12b4c27 | 2021-03-10 02:05:59 -0500 | [diff] [blame] | 124 | 		// Used to denote that the top level directory is a package. | 
 | 125 | 		files = append(files, newFile("", GeneratedBuildFileName, "")) | 
 | 126 |  | 
 | 127 | 		files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, "")) | 
 | 128 |  | 
| Jingwen Chen | 7385067 | 2020-12-14 08:25:34 -0500 | [diff] [blame] | 129 | 		// These files are only used for queryview. | 
 | 130 | 		files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl)) | 
 | 131 |  | 
 | 132 | 		for bzlFileName, ruleShim := range ruleShims { | 
 | 133 | 			files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content)) | 
 | 134 | 		} | 
 | 135 | 		files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))) | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 136 | 	} | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 137 |  | 
| Cole Faust | 324a92e | 2022-08-23 15:29:05 -0700 | [diff] [blame] | 138 | 	files = append(files, createBuildFiles(buildToTargets, mode)...) | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 139 |  | 
 | 140 | 	return files | 
 | 141 | } | 
 | 142 |  | 
| Cole Faust | 324a92e | 2022-08-23 15:29:05 -0700 | [diff] [blame] | 143 | func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 144 | 	files := make([]BazelFile, 0, len(buildToTargets)) | 
| Cole Faust | 18994c7 | 2023-02-28 16:02:16 -0800 | [diff] [blame] | 145 | 	for _, dir := range android.SortedKeys(buildToTargets) { | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 146 | 		targets := buildToTargets[dir] | 
| Jingwen Chen | 4910976 | 2021-05-25 05:16:48 +0000 | [diff] [blame] | 147 | 		targets.sort() | 
 | 148 |  | 
 | 149 | 		var content string | 
| Chris Parsons | 73f411b | 2023-06-20 21:46:57 +0000 | [diff] [blame] | 150 | 		if mode == Bp2Build { | 
| Jingwen Chen | 4910976 | 2021-05-25 05:16:48 +0000 | [diff] [blame] | 151 | 			content = `# READ THIS FIRST: | 
 | 152 | # This file was automatically generated by bp2build for the Bazel migration project. | 
 | 153 | # Feel free to edit or test it, but do *not* check it into your version control system. | 
 | 154 | ` | 
| Jingwen Chen | 1c23173 | 2021-02-05 09:38:15 -0500 | [diff] [blame] | 155 | 			content += targets.LoadStatements() | 
| Sasha Smundak | 8bea267 | 2022-08-04 13:31:14 -0700 | [diff] [blame] | 156 | 			content += "\n\n" | 
 | 157 | 			// Get package rule from the handcrafted BUILD file, otherwise emit the default one. | 
 | 158 | 			prText := "package(default_visibility = [\"//visibility:public\"])\n" | 
 | 159 | 			if pr := targets.packageRule(); pr != nil { | 
 | 160 | 				prText = pr.content | 
 | 161 | 			} | 
 | 162 | 			content += prText | 
| Jingwen Chen | 4910976 | 2021-05-25 05:16:48 +0000 | [diff] [blame] | 163 | 		} else if mode == QueryView { | 
 | 164 | 			content = soongModuleLoad | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 165 | 		} | 
| Jingwen Chen | 40067de | 2021-01-26 21:58:43 -0500 | [diff] [blame] | 166 | 		if content != "" { | 
 | 167 | 			// If there are load statements, add a couple of newlines. | 
 | 168 | 			content += "\n\n" | 
 | 169 | 		} | 
 | 170 | 		content += targets.String() | 
| Liz Kammer | ba3ea16 | 2021-02-17 13:22:03 -0500 | [diff] [blame] | 171 | 		files = append(files, newFile(dir, GeneratedBuildFileName, content)) | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 172 | 	} | 
 | 173 | 	return files | 
 | 174 | } | 
 | 175 |  | 
 | 176 | func newFile(dir, basename, content string) BazelFile { | 
 | 177 | 	return BazelFile{ | 
 | 178 | 		Dir:      dir, | 
 | 179 | 		Basename: basename, | 
 | 180 | 		Contents: content, | 
 | 181 | 	} | 
 | 182 | } | 
 | 183 |  | 
 | 184 | const ( | 
 | 185 | 	bazelRulesSubDir = "build/bazel/queryview_rules" | 
 | 186 |  | 
 | 187 | 	// additional files: | 
 | 188 | 	//  * workspace file | 
 | 189 | 	//  * base BUILD file | 
 | 190 | 	//  * rules BUILD file | 
 | 191 | 	//  * rules providers.bzl file | 
 | 192 | 	//  * rules soong_module.bzl file | 
 | 193 | 	numAdditionalFiles = 5 | 
 | 194 | ) | 
 | 195 |  | 
 | 196 | var ( | 
 | 197 | 	// Certain module property names are blocklisted/ignored here, for the reasons commented. | 
 | 198 | 	ignoredPropNames = map[string]bool{ | 
| Sam Delmerico | 263efde | 2022-09-08 10:43:42 -0400 | [diff] [blame] | 199 | 		"name":               true, // redundant, since this is explicitly generated for every target | 
 | 200 | 		"from":               true, // reserved keyword | 
 | 201 | 		"in":                 true, // reserved keyword | 
 | 202 | 		"size":               true, // reserved for tests | 
 | 203 | 		"arch":               true, // interface prop type is not supported yet. | 
 | 204 | 		"multilib":           true, // interface prop type is not supported yet. | 
 | 205 | 		"target":             true, // interface prop type is not supported yet. | 
 | 206 | 		"visibility":         true, // Bazel has native visibility semantics. Handle later. | 
 | 207 | 		"features":           true, // There is already a built-in attribute 'features' which cannot be overridden. | 
 | 208 | 		"for":                true, // reserved keyword, b/233579439 | 
 | 209 | 		"versions_with_info": true, // TODO(b/245730552) struct properties not fully supported | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 210 | 	} | 
 | 211 | ) | 
 | 212 |  | 
 | 213 | func shouldGenerateAttribute(prop string) bool { | 
 | 214 | 	return !ignoredPropNames[prop] | 
 | 215 | } | 
 | 216 |  | 
 | 217 | func shouldSkipStructField(field reflect.StructField) bool { | 
| Liz Kammer | 7a210ac | 2021-09-22 15:52:58 -0400 | [diff] [blame] | 218 | 	if field.PkgPath != "" && !field.Anonymous { | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 219 | 		// Skip unexported fields. Some properties are | 
 | 220 | 		// internal to Soong only, and these fields do not have PkgPath. | 
 | 221 | 		return true | 
 | 222 | 	} | 
| Sasha Smundak | 8bea267 | 2022-08-04 13:31:14 -0700 | [diff] [blame] | 223 | 	// fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc. | 
| Liz Kammer | 2dd9ca4 | 2020-11-25 16:06:39 -0800 | [diff] [blame] | 224 | 	// but cannot be set in a .bp file | 
 | 225 | 	if proptools.HasTag(field, "blueprint", "mutated") { | 
 | 226 | 		return true | 
 | 227 | 	} | 
 | 228 | 	return false | 
 | 229 | } | 
 | 230 |  | 
 | 231 | // FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as | 
 | 232 | // testonly = True, forcing other rules that depend on _test rules to also be | 
 | 233 | // marked as testonly = True. This semantic constraint is not present in Soong. | 
 | 234 | // To work around, rename "*_test" rules to "*_test_". | 
 | 235 | func canonicalizeModuleType(moduleName string) string { | 
 | 236 | 	if strings.HasSuffix(moduleName, "_test") { | 
 | 237 | 		return moduleName + "_" | 
 | 238 | 	} | 
 | 239 |  | 
 | 240 | 	return moduleName | 
 | 241 | } |