2020-11-26 01:06:39 +01:00
|
|
|
package bp2build
|
|
|
|
|
|
|
|
import (
|
|
|
|
"android/soong/android"
|
|
|
|
"reflect"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
)
|
|
|
|
|
|
|
|
type BazelFile struct {
|
|
|
|
Dir string
|
|
|
|
Basename string
|
|
|
|
Contents string
|
|
|
|
}
|
|
|
|
|
|
|
|
func CreateBazelFiles(
|
|
|
|
ruleShims map[string]RuleShim,
|
2021-01-27 03:58:43 +01:00
|
|
|
buildToTargets map[string]BazelTargets,
|
2021-01-25 04:55:54 +01:00
|
|
|
mode CodegenMode) []BazelFile {
|
2020-11-26 01:06:39 +01:00
|
|
|
files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles)
|
|
|
|
|
|
|
|
// Write top level files: WORKSPACE and BUILD. These files are empty.
|
|
|
|
files = append(files, newFile("", "WORKSPACE", ""))
|
|
|
|
// Used to denote that the top level directory is a package.
|
|
|
|
files = append(files, newFile("", "BUILD", ""))
|
|
|
|
|
|
|
|
files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
|
|
|
|
|
2021-01-25 04:55:54 +01:00
|
|
|
if mode == QueryView {
|
2020-12-14 14:25:34 +01:00
|
|
|
// 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)))
|
2020-11-26 01:06:39 +01:00
|
|
|
}
|
|
|
|
|
2021-01-25 04:55:54 +01:00
|
|
|
files = append(files, createBuildFiles(buildToTargets, mode)...)
|
2020-11-26 01:06:39 +01:00
|
|
|
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
2021-01-27 03:58:43 +01:00
|
|
|
func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
|
2020-11-26 01:06:39 +01:00
|
|
|
files := make([]BazelFile, 0, len(buildToTargets))
|
|
|
|
for _, dir := range android.SortedStringKeys(buildToTargets) {
|
2021-01-27 03:58:43 +01:00
|
|
|
targets := buildToTargets[dir]
|
|
|
|
sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
|
2020-11-26 01:06:39 +01:00
|
|
|
content := soongModuleLoad
|
2021-01-25 04:55:54 +01:00
|
|
|
if mode == Bp2Build {
|
2021-02-05 15:38:15 +01:00
|
|
|
content = `# This file was automatically generated by bp2build for the Bazel migration project.
|
|
|
|
# Feel free to edit or test it, but do *not* check it into your version control system.`
|
|
|
|
content += "\n\n"
|
|
|
|
content += "package(default_visibility = [\"//visibility:public\"])"
|
|
|
|
content += "\n\n"
|
|
|
|
content += targets.LoadStatements()
|
2020-12-14 14:25:34 +01:00
|
|
|
}
|
2021-01-27 03:58:43 +01:00
|
|
|
if content != "" {
|
|
|
|
// If there are load statements, add a couple of newlines.
|
2020-11-26 01:06:39 +01:00
|
|
|
content += "\n\n"
|
|
|
|
}
|
2021-01-27 03:58:43 +01:00
|
|
|
content += targets.String()
|
2021-02-09 05:13:54 +01:00
|
|
|
files = append(files, newFile(dir, "BUILD", content))
|
2020-11-26 01:06:39 +01:00
|
|
|
}
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
func newFile(dir, basename, content string) BazelFile {
|
|
|
|
return BazelFile{
|
|
|
|
Dir: dir,
|
|
|
|
Basename: basename,
|
|
|
|
Contents: content,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
bazelRulesSubDir = "build/bazel/queryview_rules"
|
|
|
|
|
|
|
|
// additional files:
|
|
|
|
// * workspace file
|
|
|
|
// * base BUILD file
|
|
|
|
// * rules BUILD file
|
|
|
|
// * rules providers.bzl file
|
|
|
|
// * rules soong_module.bzl file
|
|
|
|
numAdditionalFiles = 5
|
|
|
|
)
|
|
|
|
|
|
|
|
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
|
2021-02-25 01:55:50 +01:00
|
|
|
"size": true, // reserved for tests
|
2020-11-26 01:06:39 +01:00
|
|
|
"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.
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
func shouldGenerateAttribute(prop string) bool {
|
|
|
|
return !ignoredPropNames[prop]
|
|
|
|
}
|
|
|
|
|
|
|
|
func shouldSkipStructField(field reflect.StructField) bool {
|
|
|
|
if field.PkgPath != "" {
|
|
|
|
// 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
|
|
|
|
}
|