blob: c6972358708f39a7d61c7b51d7710f907ec27fe6 [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001package bp2build
2
3import (
Jingwen Chen0ee88a62022-01-07 14:55:29 +00004 "encoding/json"
Cole Fausteb644cf2023-04-11 13:48:17 -07005 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08006 "reflect"
Cole Faust37d27c42023-04-12 10:27:45 -07007 "strconv"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08008 "strings"
9
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux447f6c92021-08-31 20:30:36 +000010 "android/soong/android"
usta40caf952023-08-04 16:52:14 -040011 "android/soong/apex"
Trevor Radcliffe4f95ee92023-01-19 16:02:47 +000012 "android/soong/cc"
Sam Delmerico932c01c2022-03-25 16:33:26 +000013 cc_config "android/soong/cc/config"
14 java_config "android/soong/java/config"
Vinh Tran80f6b212023-08-23 13:49:13 -040015 rust_config "android/soong/rust/config"
usta40caf952023-08-04 16:52:14 -040016 "android/soong/starlark_fmt"
Jingwen Chen7810e172022-07-29 02:25:34 +000017
Cole Faust6054cdf2023-09-12 10:07:07 -070018 "github.com/google/blueprint"
Liz Kammer2dd9ca42020-11-25 16:06:39 -080019 "github.com/google/blueprint/proptools"
20)
21
22type BazelFile struct {
23 Dir string
24 Basename string
25 Contents string
26}
27
Cole Faust6054cdf2023-09-12 10:07:07 -070028// createSoongInjectionDirFiles returns most of the files to write to the soong_injection directory.
29// Some other files also come from CreateProductConfigFiles
30func createSoongInjectionDirFiles(ctx *CodegenContext, metrics CodegenMetrics) ([]BazelFile, error) {
31 cfg := ctx.Config()
Jingwen Chenbf61afb2021-05-06 13:31:18 +000032 var files []BazelFile
33
Sam Delmerico46d08b42022-11-15 15:51:04 -050034 files = append(files, newFile("android", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
35 files = append(files, newFile("android", "constants.bzl", android.BazelCcToolchainVars(cfg)))
36
Cole Faust6054cdf2023-09-12 10:07:07 -070037 // Visit all modules to determine the list of ndk libraries
38 // This list will be used to add additional flags for cc stub generation
39 ndkLibsStringFormatted := []string{}
40 ctx.Context().VisitAllModules(func(m blueprint.Module) {
41 if ctx.Context().ModuleType(m) == "ndk_library" {
42 ndkLibsStringFormatted = append(ndkLibsStringFormatted, fmt.Sprintf(`"%s"`, m.Name())) // name will be `"libc.ndk"`
43 }
44 })
45
Jingwen Chenc63677b2021-06-17 05:43:19 +000046 files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
Trevor Radcliffe4f95ee92023-01-19 16:02:47 +000047 files = append(files, newFile("cc_toolchain", "config_constants.bzl", cc_config.BazelCcToolchainVars(cfg)))
48 files = append(files, newFile("cc_toolchain", "sanitizer_constants.bzl", cc.BazelCcSanitizerToolchainVars(cfg)))
Cole Faust6054cdf2023-09-12 10:07:07 -070049 files = append(files, newFile("cc_toolchain", "ndk_libs.bzl", fmt.Sprintf("ndk_libs = [%v]", strings.Join(ndkLibsStringFormatted, ", "))))
Sam Delmerico932c01c2022-03-25 16:33:26 +000050
51 files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
52 files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
Jingwen Chenbf61afb2021-05-06 13:31:18 +000053
Vinh Tran80f6b212023-08-23 13:49:13 -040054 files = append(files, newFile("rust_toolchain", GeneratedBuildFileName, "")) // Creates a //rust_toolchain package.
55 files = append(files, newFile("rust_toolchain", "constants.bzl", rust_config.BazelRustToolchainVars(cfg)))
56
Jingwen Chen7810e172022-07-29 02:25:34 +000057 files = append(files, newFile("apex_toolchain", GeneratedBuildFileName, "")) // Creates a //apex_toolchain package.
Cole Faust9e384e22023-02-08 17:43:09 -080058 apexToolchainVars, err := apex.BazelApexToolchainVars()
59 if err != nil {
60 return nil, err
61 }
62 files = append(files, newFile("apex_toolchain", "constants.bzl", apexToolchainVars))
Jingwen Chen7810e172022-07-29 02:25:34 +000063
Liz Kammer32c634b2023-08-25 17:42:42 -040064 if buf, err := json.MarshalIndent(metrics.convertedModuleWithType, "", " "); err != nil {
65 return []BazelFile{}, err
66 } else {
67 files = append(files, newFile("metrics", "converted_modules.json", string(buf)))
68 }
Jingwen Chenc63677b2021-06-17 05:43:19 +000069
Kevin Dagostino60f562a2022-09-20 03:54:47 +000070 convertedModulePathMap, err := json.MarshalIndent(metrics.convertedModulePathMap, "", "\t")
71 if err != nil {
72 panic(err)
73 }
Jingwen Chen61342112023-04-11 08:49:01 +000074 files = append(files, newFile("metrics", GeneratedBuildFileName, "")) // Creates a //metrics package.
Kevin Dagostino60f562a2022-09-20 03:54:47 +000075 files = append(files, newFile("metrics", "converted_modules_path_map.json", string(convertedModulePathMap)))
Jingwen Chen61342112023-04-11 08:49:01 +000076 files = append(files, newFile("metrics", "converted_modules_path_map.bzl", "modules = "+strings.ReplaceAll(string(convertedModulePathMap), "\\", "\\\\")))
Kevin Dagostino60f562a2022-09-20 03:54:47 +000077
Jingwen Chen01812022021-11-19 14:29:43 +000078 files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
79
Liz Kammere8303bd2022-02-16 09:02:48 -050080 files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
81
Cole Faust34867402023-04-28 12:32:27 -070082 apiLevelsMap, err := android.GetApiLevelsMap(cfg)
83 if err != nil {
84 return nil, err
85 }
86 apiLevelsContent, err := json.Marshal(apiLevelsMap)
Jingwen Chen0ee88a62022-01-07 14:55:29 +000087 if err != nil {
Cole Faust9e384e22023-02-08 17:43:09 -080088 return nil, err
Jingwen Chen0ee88a62022-01-07 14:55:29 +000089 }
90 files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
Alix Espino4fd7e742023-02-24 14:46:43 +000091 // TODO(b/269691302) value of apiLevelsContent is product variable dependent and should be avoided for soong injection
Jingwen Chen0ee88a62022-01-07 14:55:29 +000092 files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
Cole Fausteb644cf2023-04-11 13:48:17 -070093 files = append(files, newFile("api_levels", "platform_versions.bzl", platformVersionContents(cfg)))
Jingwen Chen0ee88a62022-01-07 14:55:29 +000094
Sam Delmericocb3c52c2023-02-03 17:40:08 -050095 files = append(files, newFile("allowlists", GeneratedBuildFileName, ""))
Cole Faust705968d2022-12-14 11:32:05 -080096 // TODO(b/262781701): Create an alternate soong_build entrypoint for writing out these files only when requested
97 files = append(files, newFile("allowlists", "mixed_build_prod_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelProdMode), "\n")+"\n"))
98 files = append(files, newFile("allowlists", "mixed_build_staging_allowlist.txt", strings.Join(android.GetBazelEnabledModules(android.BazelStagingMode), "\n")+"\n"))
99
Cole Faust9e384e22023-02-08 17:43:09 -0800100 return files, nil
Jingwen Chenbf61afb2021-05-06 13:31:18 +0000101}
102
Cole Fausteb644cf2023-04-11 13:48:17 -0700103func platformVersionContents(cfg android.Config) string {
104 // Despite these coming from cfg.productVariables, they are actually hardcoded in global
105 // makefiles, not set in individual product config makesfiles, so they're safe to just export
106 // and load() directly.
107
108 platformVersionActiveCodenames := make([]string, 0, len(cfg.PlatformVersionActiveCodenames()))
109 for _, codename := range cfg.PlatformVersionActiveCodenames() {
110 platformVersionActiveCodenames = append(platformVersionActiveCodenames, fmt.Sprintf("%q", codename))
111 }
112
Cole Faust37d27c42023-04-12 10:27:45 -0700113 platformSdkVersion := "None"
114 if cfg.RawPlatformSdkVersion() != nil {
115 platformSdkVersion = strconv.Itoa(*cfg.RawPlatformSdkVersion())
116 }
117
Cole Fausteb644cf2023-04-11 13:48:17 -0700118 return fmt.Sprintf(`
119platform_versions = struct(
120 platform_sdk_final = %s,
Cole Faust37d27c42023-04-12 10:27:45 -0700121 platform_sdk_version = %s,
Cole Fausteb644cf2023-04-11 13:48:17 -0700122 platform_sdk_codename = %q,
123 platform_version_active_codenames = [%s],
124)
Cole Faust37d27c42023-04-12 10:27:45 -0700125`, starlark_fmt.PrintBool(cfg.PlatformSdkFinal()), platformSdkVersion, cfg.PlatformSdkCodename(), strings.Join(platformVersionActiveCodenames, ", "))
Cole Fausteb644cf2023-04-11 13:48:17 -0700126}
127
usta40caf952023-08-04 16:52:14 -0400128func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Jingwen Chen6c309cd2021-04-01 07:11:11 +0000129 var files []BazelFile
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800130
Jingwen Chen33832f92021-01-24 22:55:54 -0500131 if mode == QueryView {
Jingwen Chen6c309cd2021-04-01 07:11:11 +0000132 // Write top level WORKSPACE.
133 files = append(files, newFile("", "WORKSPACE", ""))
134
Jingwen Chen12b4c272021-03-10 02:05:59 -0500135 // Used to denote that the top level directory is a package.
136 files = append(files, newFile("", GeneratedBuildFileName, ""))
137
138 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
139
Jingwen Chen73850672020-12-14 08:25:34 -0500140 // These files are only used for queryview.
141 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
142
143 for bzlFileName, ruleShim := range ruleShims {
144 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
145 }
146 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800147 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800148
Cole Faust324a92e2022-08-23 15:29:05 -0700149 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800150
151 return files
152}
153
Cole Faust324a92e2022-08-23 15:29:05 -0700154func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800155 files := make([]BazelFile, 0, len(buildToTargets))
Cole Faust18994c72023-02-28 16:02:16 -0800156 for _, dir := range android.SortedKeys(buildToTargets) {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800157 targets := buildToTargets[dir]
Jingwen Chen49109762021-05-25 05:16:48 +0000158 targets.sort()
159
160 var content string
Chris Parsons73f411b2023-06-20 21:46:57 +0000161 if mode == Bp2Build {
Jingwen Chen49109762021-05-25 05:16:48 +0000162 content = `# READ THIS FIRST:
163# This file was automatically generated by bp2build for the Bazel migration project.
164# Feel free to edit or test it, but do *not* check it into your version control system.
165`
Jingwen Chen1c231732021-02-05 09:38:15 -0500166 content += targets.LoadStatements()
Sasha Smundak8bea2672022-08-04 13:31:14 -0700167 content += "\n\n"
168 // Get package rule from the handcrafted BUILD file, otherwise emit the default one.
169 prText := "package(default_visibility = [\"//visibility:public\"])\n"
170 if pr := targets.packageRule(); pr != nil {
171 prText = pr.content
172 }
173 content += prText
Jingwen Chen49109762021-05-25 05:16:48 +0000174 } else if mode == QueryView {
175 content = soongModuleLoad
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800176 }
Jingwen Chen40067de2021-01-26 21:58:43 -0500177 if content != "" {
178 // If there are load statements, add a couple of newlines.
179 content += "\n\n"
180 }
181 content += targets.String()
Liz Kammerba3ea162021-02-17 13:22:03 -0500182 files = append(files, newFile(dir, GeneratedBuildFileName, content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800183 }
184 return files
185}
186
187func newFile(dir, basename, content string) BazelFile {
188 return BazelFile{
189 Dir: dir,
190 Basename: basename,
191 Contents: content,
192 }
193}
194
195const (
196 bazelRulesSubDir = "build/bazel/queryview_rules"
197
198 // additional files:
199 // * workspace file
200 // * base BUILD file
201 // * rules BUILD file
202 // * rules providers.bzl file
203 // * rules soong_module.bzl file
204 numAdditionalFiles = 5
205)
206
207var (
208 // Certain module property names are blocklisted/ignored here, for the reasons commented.
209 ignoredPropNames = map[string]bool{
Sam Delmerico263efde2022-09-08 10:43:42 -0400210 "name": true, // redundant, since this is explicitly generated for every target
211 "from": true, // reserved keyword
212 "in": true, // reserved keyword
213 "size": true, // reserved for tests
214 "arch": true, // interface prop type is not supported yet.
215 "multilib": true, // interface prop type is not supported yet.
216 "target": true, // interface prop type is not supported yet.
217 "visibility": true, // Bazel has native visibility semantics. Handle later.
218 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
219 "for": true, // reserved keyword, b/233579439
220 "versions_with_info": true, // TODO(b/245730552) struct properties not fully supported
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800221 }
222)
223
224func shouldGenerateAttribute(prop string) bool {
225 return !ignoredPropNames[prop]
226}
227
228func shouldSkipStructField(field reflect.StructField) bool {
Liz Kammer7a210ac2021-09-22 15:52:58 -0400229 if field.PkgPath != "" && !field.Anonymous {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800230 // Skip unexported fields. Some properties are
231 // internal to Soong only, and these fields do not have PkgPath.
232 return true
233 }
Sasha Smundak8bea2672022-08-04 13:31:14 -0700234 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc.
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800235 // but cannot be set in a .bp file
236 if proptools.HasTag(field, "blueprint", "mutated") {
237 return true
238 }
239 return false
240}
241
242// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
243// testonly = True, forcing other rules that depend on _test rules to also be
244// marked as testonly = True. This semantic constraint is not present in Soong.
245// To work around, rename "*_test" rules to "*_test_".
246func canonicalizeModuleType(moduleName string) string {
247 if strings.HasSuffix(moduleName, "_test") {
248 return moduleName + "_"
249 }
250
251 return moduleName
252}