blob: 101ad3d04c8c21dfc1dd9dcba71622d66b44fabb [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"
8 "sort"
9 "strings"
10
11 "github.com/google/blueprint/proptools"
12)
13
14type BazelFile struct {
15 Dir string
16 Basename string
17 Contents string
18}
19
Jingwen Chenbf61afb2021-05-06 13:31:18 +000020func CreateSoongInjectionFiles() []BazelFile {
21 var files []BazelFile
22
23 files = append(files, newFile("cc_toolchain", "BUILD", "")) // Creates a //cc_toolchain package.
24 files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
25
26 return files
27}
28
Liz Kammer2dd9ca42020-11-25 16:06:39 -080029func CreateBazelFiles(
30 ruleShims map[string]RuleShim,
Jingwen Chen40067de2021-01-26 21:58:43 -050031 buildToTargets map[string]BazelTargets,
Jingwen Chen33832f92021-01-24 22:55:54 -050032 mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080033
Jingwen Chen6c309cd2021-04-01 07:11:11 +000034 var files []BazelFile
Liz Kammer2dd9ca42020-11-25 16:06:39 -080035
Jingwen Chen33832f92021-01-24 22:55:54 -050036 if mode == QueryView {
Jingwen Chen6c309cd2021-04-01 07:11:11 +000037 // Write top level WORKSPACE.
38 files = append(files, newFile("", "WORKSPACE", ""))
39
Jingwen Chen12b4c272021-03-10 02:05:59 -050040 // Used to denote that the top level directory is a package.
41 files = append(files, newFile("", GeneratedBuildFileName, ""))
42
43 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
44
Jingwen Chen73850672020-12-14 08:25:34 -050045 // These files are only used for queryview.
46 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
47
48 for bzlFileName, ruleShim := range ruleShims {
49 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
50 }
51 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080052 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080053
Jingwen Chen33832f92021-01-24 22:55:54 -050054 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080055
56 return files
57}
58
Jingwen Chen40067de2021-01-26 21:58:43 -050059func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080060 files := make([]BazelFile, 0, len(buildToTargets))
61 for _, dir := range android.SortedStringKeys(buildToTargets) {
Rupert Shuttleworth00960792021-05-12 21:20:13 -040062 if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -040063 fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
64 continue
65 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080066 targets := buildToTargets[dir]
Liz Kammerba3ea162021-02-17 13:22:03 -050067 sort.Slice(targets, func(i, j int) bool {
68 // this will cover all bp2build generated targets
69 if targets[i].name < targets[j].name {
70 return true
71 }
72 // give a strict ordering to content from hand-crafted targets
73 return targets[i].content < targets[j].content
74 })
Jingwen Chen40067de2021-01-26 21:58:43 -050075 content := soongModuleLoad
76 if mode == Bp2Build {
Jingwen Chen1c231732021-02-05 09:38:15 -050077 content = `# This file was automatically generated by bp2build for the Bazel migration project.
78# Feel free to edit or test it, but do *not* check it into your version control system.`
79 content += "\n\n"
80 content += "package(default_visibility = [\"//visibility:public\"])"
81 content += "\n\n"
82 content += targets.LoadStatements()
Liz Kammer2dd9ca42020-11-25 16:06:39 -080083 }
Jingwen Chen40067de2021-01-26 21:58:43 -050084 if content != "" {
85 // If there are load statements, add a couple of newlines.
86 content += "\n\n"
87 }
88 content += targets.String()
Liz Kammerba3ea162021-02-17 13:22:03 -050089 files = append(files, newFile(dir, GeneratedBuildFileName, content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080090 }
91 return files
92}
93
94func newFile(dir, basename, content string) BazelFile {
95 return BazelFile{
96 Dir: dir,
97 Basename: basename,
98 Contents: content,
99 }
100}
101
102const (
103 bazelRulesSubDir = "build/bazel/queryview_rules"
104
105 // additional files:
106 // * workspace file
107 // * base BUILD file
108 // * rules BUILD file
109 // * rules providers.bzl file
110 // * rules soong_module.bzl file
111 numAdditionalFiles = 5
112)
113
114var (
115 // Certain module property names are blocklisted/ignored here, for the reasons commented.
116 ignoredPropNames = map[string]bool{
117 "name": true, // redundant, since this is explicitly generated for every target
118 "from": true, // reserved keyword
119 "in": true, // reserved keyword
Jingwen Chen88ae4082021-02-24 19:55:50 -0500120 "size": true, // reserved for tests
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800121 "arch": true, // interface prop type is not supported yet.
122 "multilib": true, // interface prop type is not supported yet.
123 "target": true, // interface prop type is not supported yet.
124 "visibility": true, // Bazel has native visibility semantics. Handle later.
125 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
126 }
127)
128
129func shouldGenerateAttribute(prop string) bool {
130 return !ignoredPropNames[prop]
131}
132
133func shouldSkipStructField(field reflect.StructField) bool {
134 if field.PkgPath != "" {
135 // Skip unexported fields. Some properties are
136 // internal to Soong only, and these fields do not have PkgPath.
137 return true
138 }
139 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
140 // but cannot be set in a .bp file
141 if proptools.HasTag(field, "blueprint", "mutated") {
142 return true
143 }
144 return false
145}
146
147// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
148// testonly = True, forcing other rules that depend on _test rules to also be
149// marked as testonly = True. This semantic constraint is not present in Soong.
150// To work around, rename "*_test" rules to "*_test_".
151func canonicalizeModuleType(moduleName string) string {
152 if strings.HasSuffix(moduleName, "_test") {
153 return moduleName + "_"
154 }
155
156 return moduleName
157}