Support exporting device arch toolchain info
Test: bp2build.sh
Bug: 187084665
Change-Id: I49e75f603accab519784dbaf25d85db0010587a3
diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go
index e7e94a8..d19f5ac 100644
--- a/cc/config/bp2build.go
+++ b/cc/config/bp2build.go
@@ -15,98 +15,182 @@
package config
import (
- "android/soong/android"
"fmt"
"regexp"
+ "sort"
"strings"
)
+const (
+ bazelIndent = 4
+)
+
+type bazelVarExporter interface {
+ asBazel(exportedStringVariables, exportedStringListVariables) []bazelConstant
+}
+
// Helpers for exporting cc configuration information to Bazel.
var (
// Map containing toolchain variables that are independent of the
// environment variables of the build.
- exportedStringListVars = exportedStringListVariables{}
- exportedStringVars = exportedStringVariables{}
+ exportedStringListVars = exportedStringListVariables{}
+ exportedStringVars = exportedStringVariables{}
+ exportedStringListDictVars = exportedStringListDictVariables{}
)
+// Ensure that string s has no invalid characters to be generated into the bzl file.
+func validateCharacters(s string) string {
+ for _, c := range []string{`\n`, `"`, `\`} {
+ if strings.Contains(s, c) {
+ panic(fmt.Errorf("%s contains illegal character %s", s, c))
+ }
+ }
+ return s
+}
+
+type bazelConstant struct {
+ variableName string
+ internalDefinition string
+}
+
type exportedStringVariables map[string]string
-type exportedStringListVariables map[string][]string
func (m exportedStringVariables) Set(k string, v string) {
m[k] = v
}
+func bazelIndention(level int) string {
+ return strings.Repeat(" ", level*bazelIndent)
+}
+
+func printBazelList(items []string, indentLevel int) string {
+ list := make([]string, 0, len(items)+2)
+ list = append(list, "[")
+ innerIndent := bazelIndention(indentLevel + 1)
+ for _, item := range items {
+ list = append(list, fmt.Sprintf(`%s"%s",`, innerIndent, item))
+ }
+ list = append(list, bazelIndention(indentLevel)+"]")
+ return strings.Join(list, "\n")
+}
+
+func (m exportedStringVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ for k, variableValue := range m {
+ expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
+ if len(expandedVar) > 1 {
+ panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
+ }
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: fmt.Sprintf(`"%s"`, validateCharacters(expandedVar[0])),
+ })
+ }
+ return ret
+}
+
// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
func exportStringStaticVariable(name string, value string) {
pctx.StaticVariable(name, value)
exportedStringVars.Set(name, value)
}
+type exportedStringListVariables map[string][]string
+
func (m exportedStringListVariables) Set(k string, v []string) {
m[k] = v
}
+func (m exportedStringListVariables) asBazel(stringScope exportedStringVariables, stringListScope exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ // For each exported variable, recursively expand elements in the variableValue
+ // list to ensure that interpolated variables are expanded according to their values
+ // in the variable scope.
+ for k, variableValue := range m {
+ var expandedVars []string
+ for _, v := range variableValue {
+ expandedVars = append(expandedVars, expandVar(v, stringScope, stringListScope)...)
+ }
+ // Assign the list as a bzl-private variable; this variable will be exported
+ // out through a constants struct later.
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: printBazelList(expandedVars, 0),
+ })
+ }
+ return ret
+}
+
// Convenience function to declare a static variable and export it to Bazel's cc_toolchain.
func exportStringListStaticVariable(name string, value []string) {
pctx.StaticVariable(name, strings.Join(value, " "))
exportedStringListVars.Set(name, value)
}
+type exportedStringListDictVariables map[string]map[string][]string
+
+func (m exportedStringListDictVariables) Set(k string, v map[string][]string) {
+ m[k] = v
+}
+
+func printBazelStringListDict(dict map[string][]string) string {
+ bazelDict := make([]string, 0, len(dict)+2)
+ bazelDict = append(bazelDict, "{")
+ for k, v := range dict {
+ bazelDict = append(bazelDict,
+ fmt.Sprintf(`%s"%s": %s,`, bazelIndention(1), k, printBazelList(v, 1)))
+ }
+ bazelDict = append(bazelDict, "}")
+ return strings.Join(bazelDict, "\n")
+}
+
+// Since dictionaries are not supported in Ninja, we do not expand variables for dictionaries
+func (m exportedStringListDictVariables) asBazel(_ exportedStringVariables, _ exportedStringListVariables) []bazelConstant {
+ ret := make([]bazelConstant, 0, len(m))
+ for k, dict := range m {
+ ret = append(ret, bazelConstant{
+ variableName: k,
+ internalDefinition: printBazelStringListDict(dict),
+ })
+ }
+ return ret
+}
+
// BazelCcToolchainVars generates bzl file content containing variables for
// Bazel's cc_toolchain configuration.
func BazelCcToolchainVars() string {
+ return bazelToolchainVars(
+ exportedStringListDictVars,
+ exportedStringListVars,
+ exportedStringVars)
+}
+
+func bazelToolchainVars(vars ...bazelVarExporter) string {
ret := "# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT.\n\n"
- // Ensure that string s has no invalid characters to be generated into the bzl file.
- validateCharacters := func(s string) string {
- for _, c := range []string{`\n`, `"`, `\`} {
- if strings.Contains(s, c) {
- panic(fmt.Errorf("%s contains illegal character %s", s, c))
- }
- }
- return s
+ results := []bazelConstant{}
+ for _, v := range vars {
+ results = append(results, v.asBazel(exportedStringVars, exportedStringListVars)...)
}
- // For each exported variable, recursively expand elements in the variableValue
- // list to ensure that interpolated variables are expanded according to their values
- // in the variable scope.
- for _, k := range android.SortedStringKeys(exportedStringListVars) {
- variableValue := exportedStringListVars[k]
- var expandedVars []string
- for _, v := range variableValue {
- expandedVars = append(expandedVars, expandVar(v, exportedStringVars, exportedStringListVars)...)
- }
- // Build the list for this variable.
- list := "["
- for _, flag := range expandedVars {
- list += fmt.Sprintf("\n \"%s\",", validateCharacters(flag))
- }
- list += "\n]"
- // Assign the list as a bzl-private variable; this variable will be exported
- // out through a constants struct later.
- ret += fmt.Sprintf("_%s = %s\n", k, list)
- ret += "\n"
- }
+ sort.Slice(results, func(i, j int) bool { return results[i].variableName < results[j].variableName })
- for _, k := range android.SortedStringKeys(exportedStringVars) {
- variableValue := exportedStringVars[k]
- expandedVar := expandVar(variableValue, exportedStringVars, exportedStringListVars)
- if len(expandedVar) > 1 {
- panic(fmt.Errorf("%s expands to more than one string value: %s", variableValue, expandedVar))
- }
- ret += fmt.Sprintf("_%s = \"%s\"\n", k, validateCharacters(expandedVar[0]))
- ret += "\n"
+ definitions := make([]string, 0, len(results))
+ constants := make([]string, 0, len(results))
+ for _, b := range results {
+ definitions = append(definitions,
+ fmt.Sprintf("_%s = %s", b.variableName, b.internalDefinition))
+ constants = append(constants,
+ fmt.Sprintf("%[1]s%[2]s = _%[2]s,", bazelIndention(1), b.variableName))
}
// Build the exported constants struct.
+ ret += strings.Join(definitions, "\n\n")
+ ret += "\n\n"
ret += "constants = struct(\n"
- for _, k := range android.SortedStringKeys(exportedStringVars) {
- ret += fmt.Sprintf(" %s = _%s,\n", k, k)
- }
- for _, k := range android.SortedStringKeys(exportedStringListVars) {
- ret += fmt.Sprintf(" %s = _%s,\n", k, k)
- }
- ret += ")"
+ ret += strings.Join(constants, "\n")
+ ret += "\n)"
+
return ret
}