blob: 1225f2bed27cf147a250e84c42b9acacd39f78e8 [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001package bp2build
2
3import (
4 "android/soong/android"
5 "reflect"
6 "sort"
7 "strings"
8
9 "github.com/google/blueprint/proptools"
10)
11
12type BazelFile struct {
13 Dir string
14 Basename string
15 Contents string
16}
17
18func CreateBazelFiles(
19 ruleShims map[string]RuleShim,
Jingwen Chen40067de2021-01-26 21:58:43 -050020 buildToTargets map[string]BazelTargets,
Jingwen Chen33832f92021-01-24 22:55:54 -050021 mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080022 files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
23
24 // Write top level files: WORKSPACE and BUILD. These files are empty.
25 files = append(files, newFile("", "WORKSPACE", ""))
26 // Used to denote that the top level directory is a package.
27 files = append(files, newFile("", "BUILD", ""))
28
29 files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080030
Jingwen Chen33832f92021-01-24 22:55:54 -050031 if mode == QueryView {
Jingwen Chen73850672020-12-14 08:25:34 -050032 // These files are only used for queryview.
33 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
34
35 for bzlFileName, ruleShim := range ruleShims {
36 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
37 }
38 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080039 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080040
Jingwen Chen33832f92021-01-24 22:55:54 -050041 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080042
43 return files
44}
45
Jingwen Chen40067de2021-01-26 21:58:43 -050046func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080047 files := make([]BazelFile, 0, len(buildToTargets))
48 for _, dir := range android.SortedStringKeys(buildToTargets) {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080049 targets := buildToTargets[dir]
50 sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
Jingwen Chen40067de2021-01-26 21:58:43 -050051 content := soongModuleLoad
52 if mode == Bp2Build {
Jingwen Chen1c231732021-02-05 09:38:15 -050053 content = `# This file was automatically generated by bp2build for the Bazel migration project.
54# Feel free to edit or test it, but do *not* check it into your version control system.`
55 content += "\n\n"
56 content += "package(default_visibility = [\"//visibility:public\"])"
57 content += "\n\n"
58 content += targets.LoadStatements()
Liz Kammer2dd9ca42020-11-25 16:06:39 -080059 }
Jingwen Chen40067de2021-01-26 21:58:43 -050060 if content != "" {
61 // If there are load statements, add a couple of newlines.
62 content += "\n\n"
63 }
64 content += targets.String()
Jingwen Chenbb483cb2021-02-08 23:13:54 -050065 files = append(files, newFile(dir, "BUILD", content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080066 }
67 return files
68}
69
70func newFile(dir, basename, content string) BazelFile {
71 return BazelFile{
72 Dir: dir,
73 Basename: basename,
74 Contents: content,
75 }
76}
77
78const (
79 bazelRulesSubDir = "build/bazel/queryview_rules"
80
81 // additional files:
82 // * workspace file
83 // * base BUILD file
84 // * rules BUILD file
85 // * rules providers.bzl file
86 // * rules soong_module.bzl file
87 numAdditionalFiles = 5
88)
89
90var (
91 // Certain module property names are blocklisted/ignored here, for the reasons commented.
92 ignoredPropNames = map[string]bool{
93 "name": true, // redundant, since this is explicitly generated for every target
94 "from": true, // reserved keyword
95 "in": true, // reserved keyword
Jingwen Chen88ae4082021-02-24 19:55:50 -050096 "size": true, // reserved for tests
Liz Kammer2dd9ca42020-11-25 16:06:39 -080097 "arch": true, // interface prop type is not supported yet.
98 "multilib": true, // interface prop type is not supported yet.
99 "target": true, // interface prop type is not supported yet.
100 "visibility": true, // Bazel has native visibility semantics. Handle later.
101 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
102 }
103)
104
105func shouldGenerateAttribute(prop string) bool {
106 return !ignoredPropNames[prop]
107}
108
109func shouldSkipStructField(field reflect.StructField) bool {
110 if field.PkgPath != "" {
111 // Skip unexported fields. Some properties are
112 // internal to Soong only, and these fields do not have PkgPath.
113 return true
114 }
115 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
116 // but cannot be set in a .bp file
117 if proptools.HasTag(field, "blueprint", "mutated") {
118 return true
119 }
120 return false
121}
122
123// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
124// testonly = True, forcing other rules that depend on _test rules to also be
125// marked as testonly = True. This semantic constraint is not present in Soong.
126// To work around, rename "*_test" rules to "*_test_".
127func canonicalizeModuleType(moduleName string) string {
128 if strings.HasSuffix(moduleName, "_test") {
129 return moduleName + "_"
130 }
131
132 return moduleName
133}