blob: 1790dd7b8aa66cf2645e438bd4b9c64f1bcaee33 [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001package bp2build
2
3import (
Jingwen Chen0ee88a62022-01-07 14:55:29 +00004 "encoding/json"
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -04005 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08006 "reflect"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08007 "strings"
8
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux447f6c92021-08-31 20:30:36 +00009 "android/soong/android"
Sam Delmerico932c01c2022-03-25 16:33:26 +000010 cc_config "android/soong/cc/config"
11 java_config "android/soong/java/config"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux447f6c92021-08-31 20:30:36 +000012
Liz Kammer2dd9ca42020-11-25 16:06:39 -080013 "github.com/google/blueprint/proptools"
14)
15
16type BazelFile struct {
17 Dir string
18 Basename string
19 Contents string
20}
21
Chris Parsons3b1f83d2021-10-14 14:08:38 -040022func CreateSoongInjectionFiles(cfg android.Config, metrics CodegenMetrics) []BazelFile {
Jingwen Chenbf61afb2021-05-06 13:31:18 +000023 var files []BazelFile
24
Jingwen Chenc63677b2021-06-17 05:43:19 +000025 files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
Sam Delmerico932c01c2022-03-25 16:33:26 +000026 files = append(files, newFile("cc_toolchain", "constants.bzl", cc_config.BazelCcToolchainVars(cfg)))
27
28 files = append(files, newFile("java_toolchain", GeneratedBuildFileName, "")) // Creates a //java_toolchain package.
29 files = append(files, newFile("java_toolchain", "constants.bzl", java_config.BazelJavaToolchainVars(cfg)))
Jingwen Chenbf61afb2021-05-06 13:31:18 +000030
Jingwen Chen61174502021-09-17 08:40:45 +000031 files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
Jingwen Chenc63677b2021-06-17 05:43:19 +000032
Jingwen Chen01812022021-11-19 14:29:43 +000033 files = append(files, newFile("product_config", "soong_config_variables.bzl", cfg.Bp2buildSoongConfigDefinitions.String()))
34
Liz Kammere8303bd2022-02-16 09:02:48 -050035 files = append(files, newFile("product_config", "arch_configuration.bzl", android.StarlarkArchConfigurations()))
36
Jingwen Chen0ee88a62022-01-07 14:55:29 +000037 apiLevelsContent, err := json.Marshal(android.GetApiLevelsMap(cfg))
38 if err != nil {
39 panic(err)
40 }
41 files = append(files, newFile("api_levels", GeneratedBuildFileName, `exports_files(["api_levels.json"])`))
42 files = append(files, newFile("api_levels", "api_levels.json", string(apiLevelsContent)))
Yu Liufc603162022-03-01 15:44:08 -080043 files = append(files, newFile("api_levels", "api_levels.bzl", android.StarlarkApiLevelConfigs(cfg)))
Jingwen Chen0ee88a62022-01-07 14:55:29 +000044
Jingwen Chenbf61afb2021-05-06 13:31:18 +000045 return files
46}
47
Jingwen Chen61174502021-09-17 08:40:45 +000048func convertedModules(convertedModules []string) string {
49 return strings.Join(convertedModules, "\n")
Jingwen Chenc63677b2021-06-17 05:43:19 +000050}
51
Liz Kammer2dd9ca42020-11-25 16:06:39 -080052func CreateBazelFiles(
53 ruleShims map[string]RuleShim,
Jingwen Chen40067de2021-01-26 21:58:43 -050054 buildToTargets map[string]BazelTargets,
Jingwen Chen33832f92021-01-24 22:55:54 -050055 mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080056
Jingwen Chen6c309cd2021-04-01 07:11:11 +000057 var files []BazelFile
Liz Kammer2dd9ca42020-11-25 16:06:39 -080058
Jingwen Chen33832f92021-01-24 22:55:54 -050059 if mode == QueryView {
Jingwen Chen6c309cd2021-04-01 07:11:11 +000060 // Write top level WORKSPACE.
61 files = append(files, newFile("", "WORKSPACE", ""))
62
Jingwen Chen12b4c272021-03-10 02:05:59 -050063 // Used to denote that the top level directory is a package.
64 files = append(files, newFile("", GeneratedBuildFileName, ""))
65
66 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
67
Jingwen Chen73850672020-12-14 08:25:34 -050068 // These files are only used for queryview.
69 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
70
71 for bzlFileName, ruleShim := range ruleShims {
72 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
73 }
74 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080075 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080076
Jingwen Chen33832f92021-01-24 22:55:54 -050077 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080078
79 return files
80}
81
Jingwen Chen40067de2021-01-26 21:58:43 -050082func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080083 files := make([]BazelFile, 0, len(buildToTargets))
84 for _, dir := range android.SortedStringKeys(buildToTargets) {
Rupert Shuttleworth00960792021-05-12 21:20:13 -040085 if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -040086 fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
87 continue
88 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080089 targets := buildToTargets[dir]
Jingwen Chen49109762021-05-25 05:16:48 +000090 targets.sort()
91
92 var content string
Jingwen Chen40067de2021-01-26 21:58:43 -050093 if mode == Bp2Build {
Jingwen Chen49109762021-05-25 05:16:48 +000094 content = `# READ THIS FIRST:
95# This file was automatically generated by bp2build for the Bazel migration project.
96# Feel free to edit or test it, but do *not* check it into your version control system.
97`
98 if targets.hasHandcraftedTargets() {
99 // For BUILD files with both handcrafted and generated targets,
100 // don't hardcode actual content, like package() declarations.
101 // Leave that responsibility to the checked-in BUILD file
102 // instead.
103 content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.`
104 } else {
105 // For fully-generated BUILD files, hardcode the default visibility.
106 content += "package(default_visibility = [\"//visibility:public\"])"
107 }
108 content += "\n"
Jingwen Chen1c231732021-02-05 09:38:15 -0500109 content += targets.LoadStatements()
Jingwen Chen49109762021-05-25 05:16:48 +0000110 } else if mode == QueryView {
111 content = soongModuleLoad
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800112 }
Jingwen Chen40067de2021-01-26 21:58:43 -0500113 if content != "" {
114 // If there are load statements, add a couple of newlines.
115 content += "\n\n"
116 }
117 content += targets.String()
Liz Kammerba3ea162021-02-17 13:22:03 -0500118 files = append(files, newFile(dir, GeneratedBuildFileName, content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800119 }
120 return files
121}
122
123func newFile(dir, basename, content string) BazelFile {
124 return BazelFile{
125 Dir: dir,
126 Basename: basename,
127 Contents: content,
128 }
129}
130
131const (
132 bazelRulesSubDir = "build/bazel/queryview_rules"
133
134 // additional files:
135 // * workspace file
136 // * base BUILD file
137 // * rules BUILD file
138 // * rules providers.bzl file
139 // * rules soong_module.bzl file
140 numAdditionalFiles = 5
141)
142
143var (
144 // Certain module property names are blocklisted/ignored here, for the reasons commented.
145 ignoredPropNames = map[string]bool{
146 "name": true, // redundant, since this is explicitly generated for every target
147 "from": true, // reserved keyword
148 "in": true, // reserved keyword
Jingwen Chen88ae4082021-02-24 19:55:50 -0500149 "size": true, // reserved for tests
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800150 "arch": true, // interface prop type is not supported yet.
151 "multilib": true, // interface prop type is not supported yet.
152 "target": true, // interface prop type is not supported yet.
153 "visibility": true, // Bazel has native visibility semantics. Handle later.
154 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
155 }
156)
157
158func shouldGenerateAttribute(prop string) bool {
159 return !ignoredPropNames[prop]
160}
161
162func shouldSkipStructField(field reflect.StructField) bool {
Liz Kammer7a210ac2021-09-22 15:52:58 -0400163 if field.PkgPath != "" && !field.Anonymous {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800164 // Skip unexported fields. Some properties are
165 // internal to Soong only, and these fields do not have PkgPath.
166 return true
167 }
168 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
169 // but cannot be set in a .bp file
170 if proptools.HasTag(field, "blueprint", "mutated") {
171 return true
172 }
173 return false
174}
175
176// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
177// testonly = True, forcing other rules that depend on _test rules to also be
178// marked as testonly = True. This semantic constraint is not present in Soong.
179// To work around, rename "*_test" rules to "*_test_".
180func canonicalizeModuleType(moduleName string) string {
181 if strings.HasSuffix(moduleName, "_test") {
182 return moduleName + "_"
183 }
184
185 return moduleName
186}