| package bp2build |
| |
| import ( |
| "reflect" |
| "strings" |
| |
| "android/soong/android" |
| "github.com/google/blueprint/proptools" |
| ) |
| |
| type BazelFile struct { |
| Dir string |
| Basename string |
| Contents string |
| } |
| |
| func CreateBazelFiles(ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { |
| var files []BazelFile |
| |
| if mode == QueryView { |
| // Write top level WORKSPACE. |
| files = append(files, newFile("", "WORKSPACE", "")) |
| |
| // Used to denote that the top level directory is a package. |
| files = append(files, newFile("", GeneratedBuildFileName, "")) |
| |
| files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, "")) |
| |
| // These files are only used for queryview. |
| files = append(files, newFile(bazelRulesSubDir, "providers.bzl", providersBzl)) |
| |
| for bzlFileName, ruleShim := range ruleShims { |
| files = append(files, newFile(bazelRulesSubDir, bzlFileName+".bzl", ruleShim.content)) |
| } |
| files = append(files, newFile(bazelRulesSubDir, "soong_module.bzl", generateSoongModuleBzl(ruleShims))) |
| } |
| |
| files = append(files, createBuildFiles(buildToTargets, mode)...) |
| |
| return files |
| } |
| |
| func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { |
| files := make([]BazelFile, 0, len(buildToTargets)) |
| for _, dir := range android.SortedKeys(buildToTargets) { |
| targets := buildToTargets[dir] |
| targets.sort() |
| |
| var content string |
| if mode == QueryView { |
| content = soongModuleLoad |
| } |
| if content != "" { |
| // If there are load statements, add a couple of newlines. |
| content += "\n\n" |
| } |
| content += targets.String() |
| files = append(files, newFile(dir, GeneratedBuildFileName, content)) |
| } |
| return files |
| } |
| |
| func newFile(dir, basename, content string) BazelFile { |
| return BazelFile{ |
| Dir: dir, |
| Basename: basename, |
| Contents: content, |
| } |
| } |
| |
| const ( |
| bazelRulesSubDir = "build/bazel/queryview_rules" |
| ) |
| |
| var ( |
| // Certain module property names are blocklisted/ignored here, for the reasons commented. |
| ignoredPropNames = map[string]bool{ |
| "name": true, // redundant, since this is explicitly generated for every target |
| "from": true, // reserved keyword |
| "in": true, // reserved keyword |
| "size": true, // reserved for tests |
| "arch": true, // interface prop type is not supported yet. |
| "multilib": true, // interface prop type is not supported yet. |
| "target": true, // interface prop type is not supported yet. |
| "visibility": true, // Bazel has native visibility semantics. Handle later. |
| "features": true, // There is already a built-in attribute 'features' which cannot be overridden. |
| "for": true, // reserved keyword, b/233579439 |
| "versions_with_info": true, // TODO(b/245730552) struct properties not fully supported |
| } |
| ) |
| |
| func shouldGenerateAttribute(prop string) bool { |
| return !ignoredPropNames[prop] |
| } |
| |
| func shouldSkipStructField(field reflect.StructField) bool { |
| if field.PkgPath != "" && !field.Anonymous { |
| // Skip unexported fields. Some properties are |
| // internal to Soong only, and these fields do not have PkgPath. |
| return true |
| } |
| // fields with tag `blueprint:"mutated"` are exported to enable modification in mutators, etc. |
| // but cannot be set in a .bp file |
| if proptools.HasTag(field, "blueprint", "mutated") { |
| return true |
| } |
| return false |
| } |
| |
| // FIXME(b/168089390): In Bazel, rules ending with "_test" needs to be marked as |
| // testonly = True, forcing other rules that depend on _test rules to also be |
| // marked as testonly = True. This semantic constraint is not present in Soong. |
| // To work around, rename "*_test" rules to "*_test_". |
| func canonicalizeModuleType(moduleName string) string { |
| if strings.HasSuffix(moduleName, "_test") { |
| return moduleName + "_" |
| } |
| |
| return moduleName |
| } |