1package bp2build 2 3import ( 4 "reflect" 5 "strings" 6 7 "android/soong/android" 8 "github.com/google/blueprint/proptools" 9) 10 11type BazelFile struct { 12 Dir string 13 Basename string 14 Contents string 15} 16 17func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { 18 var files []BazelFile 19 20 if mode == QueryView { 21 // Write top level WORKSPACE. 22 files = append(files, newFile("", "WORKSPACE", "")) 23 24 // Used to denote that the top level directory is a package. 25 files = append(files, newFile("", GeneratedBuildFileName, "")) 26 27 files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, "")) 28 29 // These files are only used for queryview. 30 files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl)) 31 32 for bzlFileName, ruleShim := range ruleShims { 33 files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content)) 34 } 35 files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))) 36 } 37 38 files = append(files, createBuildFiles(buildToTargets, mode)...) 39 40 return files 41} 42 43func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { 44 files := make([]BazelFile, 0, len(buildToTargets)) 45 for _, dir := range android.SortedKeys(buildToTargets) { 46 targets := buildToTargets[dir] 47 targets.sort() 48 49 var content string 50 if mode == QueryView { 51 content = soongModuleLoad 52 } 53 if content != "" { 54 // If there are load statements, add a couple of newlines. 55 content += "\n\n" 56 } 57 content += targets.String() 58 files = append(files, newFile(dir, GeneratedBuildFileName, content)) 59 } 60 return files 61} 62 63func newFile(dir, basename, content string) BazelFile { 64 return BazelFile{ 65 Dir: dir, 66 Basename: basename, 67 Contents: content, 68 } 69} 70 71const ( 72 bazelRulesSubDir = "build/bazel/queryview_rules" 73) 74 75var ( 76 // Certain module property names are blocklisted/ignored here, for the reasons commented. 77 ignoredPropNames = map[string]bool{ 78 "name": true, // redundant, since this is explicitly generated for every target 79 "from": true, // reserved keyword 80 "in": true, // reserved keyword 81 "size": true, // reserved for tests 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 "for": true, // reserved keyword, b/233579439 88 "versions_with_info": true, // TODO(b/245730552) struct properties not fully supported 89 } 90) 91 92func shouldGenerateAttribute(prop string) bool { 93 return !ignoredPropNames[prop] 94} 95 96func shouldSkipStructField(field reflect.StructField) bool { 97 if field.PkgPath != "" && !field.Anonymous { 98 // Skip unexported fields. Some properties are 99 // internal to Soong only, and these fields do not have PkgPath. 100 return true 101 } 102 // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc. 103 // but cannot be set in a .bp file 104 if proptools.HasTag(field, "blueprint", "mutated") { 105 return true 106 } 107 return false 108} 109 110// FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as 111// testonly = True, forcing other rules that depend on _test rules to also be 112// marked as testonly = True. This semantic constraint is not present in Soong. 113// To work around, rename "*_test" rules to "*_test_". 114func canonicalizeModuleType(moduleName string) string { 115 if strings.HasSuffix(moduleName, "_test") { 116 return moduleName + "_" 117 } 118 119 return moduleName 120} 121