blob: d34a4ba9bd7ce47d71c569299ced6d2d3096597d [file] [log] [blame]
Liz Kammer2dd9ca42020-11-25 16:06:39 -08001package bp2build
2
3import (
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -04004 "fmt"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08005 "reflect"
Liz Kammer2dd9ca42020-11-25 16:06:39 -08006 "strings"
7
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux447f6c92021-08-31 20:30:36 +00008 "android/soong/android"
9 "android/soong/cc/config"
10
Liz Kammer2dd9ca42020-11-25 16:06:39 -080011 "github.com/google/blueprint/proptools"
12)
13
14type BazelFile struct {
15 Dir string
16 Basename string
17 Contents string
18}
19
Jingwen Chen61174502021-09-17 08:40:45 +000020func CreateSoongInjectionFiles(metrics CodegenMetrics) []BazelFile {
Jingwen Chenbf61afb2021-05-06 13:31:18 +000021 var files []BazelFile
22
Jingwen Chenc63677b2021-06-17 05:43:19 +000023 files = append(files, newFile("cc_toolchain", GeneratedBuildFileName, "")) // Creates a //cc_toolchain package.
Jingwen Chenbf61afb2021-05-06 13:31:18 +000024 files = append(files, newFile("cc_toolchain", "constants.bzl", config.BazelCcToolchainVars()))
25
Jingwen Chen61174502021-09-17 08:40:45 +000026 files = append(files, newFile("metrics", "converted_modules.txt", strings.Join(metrics.convertedModules, "\n")))
Jingwen Chenc63677b2021-06-17 05:43:19 +000027
Jingwen Chenbf61afb2021-05-06 13:31:18 +000028 return files
29}
30
Jingwen Chen61174502021-09-17 08:40:45 +000031func convertedModules(convertedModules []string) string {
32 return strings.Join(convertedModules, "\n")
Jingwen Chenc63677b2021-06-17 05:43:19 +000033}
34
Liz Kammer2dd9ca42020-11-25 16:06:39 -080035func CreateBazelFiles(
36 ruleShims map[string]RuleShim,
Jingwen Chen40067de2021-01-26 21:58:43 -050037 buildToTargets map[string]BazelTargets,
Jingwen Chen33832f92021-01-24 22:55:54 -050038 mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080039
Jingwen Chen6c309cd2021-04-01 07:11:11 +000040 var files []BazelFile
Liz Kammer2dd9ca42020-11-25 16:06:39 -080041
Jingwen Chen33832f92021-01-24 22:55:54 -050042 if mode == QueryView {
Jingwen Chen6c309cd2021-04-01 07:11:11 +000043 // Write top level WORKSPACE.
44 files = append(files, newFile("", "WORKSPACE", ""))
45
Jingwen Chen12b4c272021-03-10 02:05:59 -050046 // Used to denote that the top level directory is a package.
47 files = append(files, newFile("", GeneratedBuildFileName, ""))
48
49 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
50
Jingwen Chen73850672020-12-14 08:25:34 -050051 // These files are only used for queryview.
52 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl))
53
54 for bzlFileName, ruleShim := range ruleShims {
55 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content))
56 }
57 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims)))
Liz Kammer2dd9ca42020-11-25 16:06:39 -080058 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080059
Jingwen Chen33832f92021-01-24 22:55:54 -050060 files = append(files, createBuildFiles(buildToTargets, mode)...)
Liz Kammer2dd9ca42020-11-25 16:06:39 -080061
62 return files
63}
64
Jingwen Chen40067de2021-01-26 21:58:43 -050065func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
Liz Kammer2dd9ca42020-11-25 16:06:39 -080066 files := make([]BazelFile, 0, len(buildToTargets))
67 for _, dir := range android.SortedStringKeys(buildToTargets) {
Rupert Shuttleworth00960792021-05-12 21:20:13 -040068 if mode == Bp2Build && android.ShouldKeepExistingBuildFileForDir(dir) {
Rupert Shuttleworth2a4fc3e2021-04-21 07:10:09 -040069 fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir)
70 continue
71 }
Liz Kammer2dd9ca42020-11-25 16:06:39 -080072 targets := buildToTargets[dir]
Jingwen Chen49109762021-05-25 05:16:48 +000073 targets.sort()
74
75 var content string
Jingwen Chen40067de2021-01-26 21:58:43 -050076 if mode == Bp2Build {
Jingwen Chen49109762021-05-25 05:16:48 +000077 content = `# READ THIS FIRST:
78# This file was automatically generated by bp2build for the Bazel migration project.
79# Feel free to edit or test it, but do *not* check it into your version control system.
80`
81 if targets.hasHandcraftedTargets() {
82 // For BUILD files with both handcrafted and generated targets,
83 // don't hardcode actual content, like package() declarations.
84 // Leave that responsibility to the checked-in BUILD file
85 // instead.
86 content += `# This file contains generated targets and handcrafted targets that are manually managed in the source tree.`
87 } else {
88 // For fully-generated BUILD files, hardcode the default visibility.
89 content += "package(default_visibility = [\"//visibility:public\"])"
90 }
91 content += "\n"
Jingwen Chen1c231732021-02-05 09:38:15 -050092 content += targets.LoadStatements()
Jingwen Chen49109762021-05-25 05:16:48 +000093 } else if mode == QueryView {
94 content = soongModuleLoad
Liz Kammer2dd9ca42020-11-25 16:06:39 -080095 }
Jingwen Chen40067de2021-01-26 21:58:43 -050096 if content != "" {
97 // If there are load statements, add a couple of newlines.
98 content += "\n\n"
99 }
100 content += targets.String()
Liz Kammerba3ea162021-02-17 13:22:03 -0500101 files = append(files, newFile(dir, GeneratedBuildFileName, content))
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800102 }
103 return files
104}
105
106func newFile(dir, basename, content string) BazelFile {
107 return BazelFile{
108 Dir: dir,
109 Basename: basename,
110 Contents: content,
111 }
112}
113
114const (
115 bazelRulesSubDir = "build/bazel/queryview_rules"
116
117 // additional files:
118 // * workspace file
119 // * base BUILD file
120 // * rules BUILD file
121 // * rules providers.bzl file
122 // * rules soong_module.bzl file
123 numAdditionalFiles = 5
124)
125
126var (
127 // Certain module property names are blocklisted/ignored here, for the reasons commented.
128 ignoredPropNames = map[string]bool{
129 "name": true, // redundant, since this is explicitly generated for every target
130 "from": true, // reserved keyword
131 "in": true, // reserved keyword
Jingwen Chen88ae4082021-02-24 19:55:50 -0500132 "size": true, // reserved for tests
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800133 "arch": true, // interface prop type is not supported yet.
134 "multilib": true, // interface prop type is not supported yet.
135 "target": true, // interface prop type is not supported yet.
136 "visibility": true, // Bazel has native visibility semantics. Handle later.
137 "features": true, // There is already a built-in attribute 'features' which cannot be overridden.
138 }
139)
140
141func shouldGenerateAttribute(prop string) bool {
142 return !ignoredPropNames[prop]
143}
144
145func shouldSkipStructField(field reflect.StructField) bool {
Liz Kammer7a210ac2021-09-22 15:52:58 -0400146 if field.PkgPath != "" && !field.Anonymous {
Liz Kammer2dd9ca42020-11-25 16:06:39 -0800147 // Skip unexported fields. Some properties are
148 // internal to Soong only, and these fields do not have PkgPath.
149 return true
150 }
151 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc
152 // but cannot be set in a .bp file
153 if proptools.HasTag(field, "blueprint", "mutated") {
154 return true
155 }
156 return false
157}
158
159// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as
160// testonly = True, forcing other rules that depend on _test rules to also be
161// marked as testonly = True. This semantic constraint is not present in Soong.
162// To work around, rename "*_test" rules to "*_test_".
163func canonicalizeModuleType(moduleName string) string {
164 if strings.HasSuffix(moduleName, "_test") {
165 return moduleName + "_"
166 }
167
168 return moduleName
169}