blob: cdfb38b14d317ebc60fe4df921b300d077b03bc0 [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,
20 buildToTargets map[string][]BazelTarget) []BazelFile {
21 files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
22
23 // Write top level files: WORKSPACE and BUILD. These files are empty.
24 files = append(files, newFile("", "WORKSPACE", ""))
25 // Used to denote that the top level directory is a package.
26 files = append(files, newFile("", "BUILD", ""))
27
28 files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
29 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
30
31 for bzlFileName, ruleShim := range ruleShims {
32 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
33 }
34 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
35
36 files = append(files, createBuildFiles(buildToTargets)...)
37
38 return files
39}
40
41func createBuildFiles(buildToTargets map[string][]BazelTarget) []BazelFile {
42 files := make([]BazelFile, 0, len(buildToTargets))
43 for _, dir := range android.SortedStringKeys(buildToTargets) {
44 content := soongModuleLoad
45 targets := buildToTargets[dir]
46 sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
47 for _, t := range targets {
48 content += "\n\n"
49 content += t.content
50 }
51 files = append(files, newFile(dir, "BUILD.bazel", content))
52 }
53 return files
54}
55
56func newFile(dir, basename, content string) BazelFile {
57 return BazelFile{
58 Dir: dir,
59 Basename: basename,
60 Contents: content,
61 }
62}
63
64const (
65 bazelRulesSubDir = "build/bazel/queryview_rules"
66
67 // additional files:
68 // * workspace file
69 // * base BUILD file
70 // * rules BUILD file
71 // * rules providers.bzl file
72 // * rules soong_module.bzl file
73 numAdditionalFiles = 5
74)
75
76var (
77 // Certain module property names are blocklisted/ignored here, for the reasons commented.
78 ignoredPropNames = map[string]bool{
79 "name": true, // redundant, since this is explicitly generated for every target
80 "from": true, // reserved keyword
81 "in": true, // reserved keyword
82 "arch": true, // interface prop type is not supported yet.
83 "multilib": true, // interface prop type is not supported yet.
84 "target": true, // interface prop type is not supported yet.
85 "visibility": true, // Bazel has native visibility semantics. Handle later.
86 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
87 }
88)
89
90func shouldGenerateAttribute(prop string) bool {
91 return !ignoredPropNames[prop]
92}
93
94func shouldSkipStructField(field reflect.StructField) bool {
95 if field.PkgPath != "" {
96 // Skip unexported fields. Some properties are
97 // internal to Soong only, and these fields do not have PkgPath.
98 return true
99 }
100 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
101 // but cannot be set in a .bp file
102 if proptools.HasTag(field, "blueprint", "mutated") {
103 return true
104 }
105 return false
106}
107
108// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
109// testonly = True, forcing other rules that depend on _test rules to also be
110// marked as testonly = True. This semantic constraint is not present in Soong.
111// To work around, rename "*_test" rules to "*_test_".
112func canonicalizeModuleType(moduleName string) string {
113 if strings.HasSuffix(moduleName, "_test") {
114 return moduleName + "_"
115 }
116
117 return moduleName
118}