Export variant/features via soong_injection

Test: build/bazel/ci/bp2build.sh
Change-Id: If70043dc9d020d5f4a243ba4b192b99c9c7e8563
diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go
index eca5161..73f65f5 100644
--- a/cc/config/bp2build.go
+++ b/cc/config/bp2build.go
@@ -38,6 +38,8 @@
 	exportedStringListVars     = exportedStringListVariables{}
 	exportedStringVars         = exportedStringVariables{}
 	exportedStringListDictVars = exportedStringListDictVariables{}
+	// Note: these can only contain references to other variables and must be printed last
+	exportedVariableReferenceDictVars = exportedVariableReferenceDictVariables{}
 
 	/// Maps containing variables that are dependent on the build config.
 	exportedConfigDependingVars = exportedConfigDependingVariables{}
@@ -62,6 +64,7 @@
 type bazelConstant struct {
 	variableName       string
 	internalDefinition string
+	sortLast           bool
 }
 
 type exportedStringVariables map[string]string
@@ -168,6 +171,36 @@
 	return ret
 }
 
+type exportedVariableReferenceDictVariables map[string]map[string]string
+
+func (m exportedVariableReferenceDictVariables) Set(k string, v map[string]string) {
+	m[k] = v
+}
+
+func (m exportedVariableReferenceDictVariables) asBazel(_ android.Config, _ exportedStringVariables,
+	_ exportedStringListVariables, _ exportedConfigDependingVariables) []bazelConstant {
+	ret := make([]bazelConstant, 0, len(m))
+	for n, dict := range m {
+		for k, v := range dict {
+			matches, err := variableReference(v)
+			if err != nil {
+				panic(err)
+			} else if !matches.matches {
+				panic(fmt.Errorf("Expected a variable reference, got %q", v))
+			} else if len(matches.fullVariableReference) != len(v) {
+				panic(fmt.Errorf("Expected only a variable reference, got %q", v))
+			}
+			dict[k] = "_" + matches.variable
+		}
+		ret = append(ret, bazelConstant{
+			variableName:       n,
+			internalDefinition: starlark_fmt.PrintDict(dict, 0),
+			sortLast:           true,
+		})
+	}
+	return ret
+}
+
 // BazelCcToolchainVars generates bzl file content containing variables for
 // Bazel's cc_toolchain configuration.
 func BazelCcToolchainVars(config android.Config) string {
@@ -175,7 +208,8 @@
 		config,
 		exportedStringListDictVars,
 		exportedStringListVars,
-		exportedStringVars)
+		exportedStringVars,
+		exportedVariableReferenceDictVars)
 }
 
 func bazelToolchainVars(config android.Config, vars ...bazelVarExporter) string {
@@ -186,7 +220,12 @@
 		results = append(results, v.asBazel(config, exportedStringVars, exportedStringListVars, exportedConfigDependingVars)...)
 	}
 
-	sort.Slice(results, func(i, j int) bool { return results[i].variableName < results[j].variableName })
+	sort.Slice(results, func(i, j int) bool {
+		if results[i].sortLast != results[j].sortLast {
+			return !results[i].sortLast
+		}
+		return results[i].variableName < results[j].variableName
+	})
 
 	definitions := make([]string, 0, len(results))
 	constants := make([]string, 0, len(results))
@@ -207,6 +246,32 @@
 	return ret
 }
 
+type match struct {
+	matches               bool
+	fullVariableReference string
+	variable              string
+}
+
+func variableReference(input string) (match, error) {
+	// e.g. "${ExternalCflags}"
+	r := regexp.MustCompile(`\${(?:config\.)?([a-zA-Z0-9_]+)}`)
+
+	matches := r.FindStringSubmatch(input)
+	if len(matches) == 0 {
+		return match{}, nil
+	}
+	if len(matches) != 2 {
+		return match{}, fmt.Errorf("Expected to only match 1 subexpression in %s, got %d", input, len(matches)-1)
+	}
+	return match{
+		matches:               true,
+		fullVariableReference: matches[0],
+		// Index 1 of FindStringSubmatch contains the subexpression match
+		// (variable name) of the capture group.
+		variable: matches[1],
+	}, nil
+}
+
 // expandVar recursively expand interpolated variables in the exportedVars scope.
 //
 // We're using a string slice to track the seen variables to avoid
@@ -216,8 +281,6 @@
 // interpolation stacks are deep (n > 1).
 func expandVar(config android.Config, toExpand string, stringScope exportedStringVariables,
 	stringListScope exportedStringListVariables, exportedVars exportedConfigDependingVariables) ([]string, error) {
-	// e.g. "${ExternalCflags}"
-	r := regexp.MustCompile(`\${([a-zA-Z0-9_]+)}`)
 
 	// Internal recursive function.
 	var expandVarInternal func(string, map[string]bool) (string, error)
@@ -225,20 +288,18 @@
 		var ret string
 		remainingString := toExpand
 		for len(remainingString) > 0 {
-			matches := r.FindStringSubmatch(remainingString)
-			if len(matches) == 0 {
+			matches, err := variableReference(remainingString)
+			if err != nil {
+				panic(err)
+			}
+			if !matches.matches {
 				return ret + remainingString, nil
 			}
-			if len(matches) != 2 {
-				panic(fmt.Errorf("Expected to only match 1 subexpression in %s, got %d", remainingString, len(matches)-1))
-			}
-			matchIndex := strings.Index(remainingString, matches[0])
+			matchIndex := strings.Index(remainingString, matches.fullVariableReference)
 			ret += remainingString[:matchIndex]
-			remainingString = remainingString[matchIndex+len(matches[0]):]
+			remainingString = remainingString[matchIndex+len(matches.fullVariableReference):]
 
-			// Index 1 of FindStringSubmatch contains the subexpression match
-			// (variable name) of the capture group.
-			variable := matches[1]
+			variable := matches.variable
 			// toExpand contains a variable.
 			if _, ok := seenVars[variable]; ok {
 				return ret, fmt.Errorf(