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 }