1package bp2build 2 3import ( 4 "android/soong/android" 5 "android/soong/cc/config" 6 "fmt" 7 "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 20func 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 29func CreateBazelFiles( 30 ruleShims map[string]RuleShim, 31 buildToTargets map[string]BazelTargets, 32 mode CodegenMode) []BazelFile { 33 34 var files []BazelFile 35 36 if mode == QueryView { 37 // Write top level WORKSPACE. 38 files = append(files, newFile("", "WORKSPACE", "")) 39 40 // 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 45 // 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))) 52 } 53 54 files = append(files, createBuildFiles(buildToTargets, mode)...) 55 56 return files 57} 58 59func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { 60 files := make([]BazelFile, 0, len(buildToTargets)) 61 for _, dir := range android.SortedStringKeys(buildToTargets) { 62 if mode == Bp2Build && !android.ShouldWriteBuildFileForDir(dir) { 63 fmt.Printf("[bp2build] Not writing generated BUILD file for dir: '%s'\n", dir) 64 continue 65 } 66 targets := buildToTargets[dir] 67 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 }) 75 content := soongModuleLoad 76 if mode == Bp2Build { 77 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() 83 } 84 if content != "" { 85 // If there are load statements, add a couple of newlines. 86 content += "\n\n" 87 } 88 content += targets.String() 89 files = append(files, newFile(dir, GeneratedBuildFileName, content)) 90 } 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 120 "size": true, // reserved for tests 121 "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} 158