blob: 75bc2b4153afd79c8ca288c377f6316fb8b9dc40 [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001package bp2build
2
3import (
4 "android/soong/android"
Jingwen Chenbf61afb2021-05-06 13:31:18 +00005 "android/soong/cc/config"
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -04006 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08007 "reflect"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08008 "strings"
9
10 "github.com/google/blueprint/proptools"
11)
12
13type BazelFile struct {
14 Dir string
15 Basename string
16 Contents string
17}
18
Jingwen Chenc63677b2021-06-17 05:43:19 +000019func CreateSoongInjectionFiles(compatLayer CodegenCompatLayer) []BazelFile {
Jingwen Chenbf61afb2021-05-06 13:31:18 +000020 var files []BazelFile
21
Jingwen Chenc63677b2021-06-17 05:43:19 +000022 files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
Jingwen Chenbf61afb2021-05-06 13:31:18 +000023 files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
24
Jingwen Chenc63677b2021-06-17 05:43:19 +000025 files = append(files, newFile("module_name_to_label", GeneratedBuildFileName, nameToLabelAliases(compatLayer.NameToLabelMap)))
26
Jingwen Chenbf61afb2021-05-06 13:31:18 +000027 return files
28}
29
Jingwen Chenc63677b2021-06-17 05:43:19 +000030func nameToLabelAliases(nameToLabelMap map[string]string) string {
31 ret := make([]string, len(nameToLabelMap))
32
33 for k, v := range nameToLabelMap {
34 // v is the fully qualified label rooted at '//'
35 ret = append(ret, fmt.Sprintf(
36 `alias(
37 name = "%s",
38 actual = "@%s",
39)`, k, v))
40 }
41 return strings.Join(ret, "\n\n")
42}
43
Liz Kammer2dd9ca42020-11-25 16:06:39 -080044func CreateBazelFiles(
45 ruleShims map[string]RuleShim,
Jingwen Chen40067de2021-01-26 21:58:43 -050046 buildToTargets map[string]BazelTargets,
Jingwen Chen33832f92021-01-24 22:55:54 -050047 mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080048
Jingwen Chen6c309cd2021-04-01 07:11:11 +000049 var files []BazelFile
Liz Kammer2dd9ca42020-11-25 16:06:39 -080050
Jingwen Chen33832f92021-01-24 22:55:54 -050051 if mode == QueryView {
Jingwen Chen6c309cd2021-04-01 07:11:11 +000052 // Write top level WORKSPACE.
53 files = append(files, newFile("", "WORKSPACE", ""))
54
Jingwen Chen12b4c272021-03-10 02:05:59 -050055 // Used to denote that the top level directory is a package.
56 files = append(files, newFile("", GeneratedBuildFileName, ""))
57
58 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
59
Jingwen Chen73850672020-12-14 08:25:34 -050060 // These files are only used for queryview.
61 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
62
63 for bzlFileName, ruleShim := range ruleShims {
64 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
65 }
66 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080067 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080068
Jingwen Chen33832f92021-01-24 22:55:54 -050069 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080070
71 return files
72}
73
Jingwen Chen40067de2021-01-26 21:58:43 -050074func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080075 files := make([]BazelFile, 0, len(buildToTargets))
76 for _, dir := range android.SortedStringKeys(buildToTargets) {
Rupert Shuttleworth00960792021-05-12 21:20:13 -040077 if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -040078 fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
79 continue
80 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080081 targets := buildToTargets[dir]
Jingwen Chen49109762021-05-25 05:16:48 +000082 targets.sort()
83
84 var content string
Jingwen Chen40067de2021-01-26 21:58:43 -050085 if mode == Bp2Build {
Jingwen Chen49109762021-05-25 05:16:48 +000086 content = `# READ THIS FIRST:
87# This file was automatically generated by bp2build for the Bazel migration project.
88# Feel free to edit or test it, but do *not* check it into your version control system.
89`
90 if targets.hasHandcraftedTargets() {
91 // For BUILD files with both handcrafted and generated targets,
92 // don't hardcode actual content, like package() declarations.
93 // Leave that responsibility to the checked-in BUILD file
94 // instead.
95 content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.`
96 } else {
97 // For fully-generated BUILD files, hardcode the default visibility.
98 content += "package(default_visibility = [\"//visibility:public\"])"
99 }
100 content += "\n"
Jingwen Chen1c231732021-02-05 09:38:15 -0500101 content += targets.LoadStatements()
Jingwen Chen49109762021-05-25 05:16:48 +0000102 } else if mode == QueryView {
103 content = soongModuleLoad
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800104 }
Jingwen Chen40067de2021-01-26 21:58:43 -0500105 if content != "" {
106 // If there are load statements, add a couple of newlines.
107 content += "\n\n"
108 }
109 content += targets.String()
Liz Kammerba3ea162021-02-17 13:22:03 -0500110 files = append(files, newFile(dir, GeneratedBuildFileName, content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800111 }
112 return files
113}
114
115func newFile(dir, basename, content string) BazelFile {
116 return BazelFile{
117 Dir: dir,
118 Basename: basename,
119 Contents: content,
120 }
121}
122
123const (
124 bazelRulesSubDir = "build/bazel/queryview_rules"
125
126 // additional files:
127 // * workspace file
128 // * base BUILD file
129 // * rules BUILD file
130 // * rules providers.bzl file
131 // * rules soong_module.bzl file
132 numAdditionalFiles = 5
133)
134
135var (
136 // Certain module property names are blocklisted/ignored here, for the reasons commented.
137 ignoredPropNames = map[string]bool{
138 "name": true, // redundant, since this is explicitly generated for every target
139 "from": true, // reserved keyword
140 "in": true, // reserved keyword
Jingwen Chen88ae4082021-02-24 19:55:50 -0500141 "size": true, // reserved for tests
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800142 "arch": true, // interface prop type is not supported yet.
143 "multilib": true, // interface prop type is not supported yet.
144 "target": true, // interface prop type is not supported yet.
145 "visibility": true, // Bazel has native visibility semantics. Handle later.
146 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
147 }
148)
149
150func shouldGenerateAttribute(prop string) bool {
151 return !ignoredPropNames[prop]
152}
153
154func shouldSkipStructField(field reflect.StructField) bool {
155 if field.PkgPath != "" {
156 // Skip unexported fields. Some properties are
157 // internal to Soong only, and these fields do not have PkgPath.
158 return true
159 }
160 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
161 // but cannot be set in a .bp file
162 if proptools.HasTag(field, "blueprint", "mutated") {
163 return true
164 }
165 return false
166}
167
168// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
169// testonly = True, forcing other rules that depend on _test rules to also be
170// marked as testonly = True. This semantic constraint is not present in Soong.
171// To work around, rename "*_test" rules to "*_test_".
172func canonicalizeModuleType(moduleName string) string {
173 if strings.HasSuffix(moduleName, "_test") {
174 return moduleName + "_"
175 }
176
177 return moduleName
178}