diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index 812a245d2..2d6bcb89d 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -96,31 +96,25 @@ func init() { pctx.SourcePathVariable("Arm64GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/aarch64/aarch64-linux-android-${arm64GccVersion}") - pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " ")) - pctx.StaticVariable("Arm64Lldflags", strings.Join(arm64Lldflags, " ")) + exportStringListStaticVariable("Arm64Ldflags", arm64Ldflags) + exportStringListStaticVariable("Arm64Lldflags", arm64Lldflags) - pctx.StaticVariable("Arm64Cflags", strings.Join(arm64Cflags, " ")) - pctx.StaticVariable("Arm64Cppflags", strings.Join(arm64Cppflags, " ")) + exportStringListStaticVariable("Arm64Cflags", arm64Cflags) + exportStringListStaticVariable("Arm64Cppflags", arm64Cppflags) + + exportedStringListDictVars.Set("Arm64ArchVariantCflags", arm64ArchVariantCflags) + exportedStringListDictVars.Set("Arm64CpuVariantCflags", arm64CpuVariantCflags) pctx.StaticVariable("Arm64Armv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " ")) pctx.StaticVariable("Arm64Armv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " ")) pctx.StaticVariable("Arm64Armv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " ")) pctx.StaticVariable("Arm64Armv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " ")) - pctx.StaticVariable("Arm64CortexA53Cflags", - strings.Join(arm64CpuVariantCflags["cortex-a53"], " ")) - - pctx.StaticVariable("Arm64CortexA55Cflags", - strings.Join(arm64CpuVariantCflags["cortex-a55"], " ")) - - pctx.StaticVariable("Arm64KryoCflags", - strings.Join(arm64CpuVariantCflags["kryo"], " ")) - - pctx.StaticVariable("Arm64ExynosM1Cflags", - strings.Join(arm64CpuVariantCflags["exynos-m1"], " ")) - - pctx.StaticVariable("Arm64ExynosM2Cflags", - strings.Join(arm64CpuVariantCflags["exynos-m2"], " ")) + pctx.StaticVariable("Arm64CortexA53Cflags", strings.Join(arm64CpuVariantCflags["cortex-a53"], " ")) + pctx.StaticVariable("Arm64CortexA55Cflags", strings.Join(arm64CpuVariantCflags["cortex-a55"], " ")) + pctx.StaticVariable("Arm64KryoCflags", strings.Join(arm64CpuVariantCflags["kryo"], " ")) + pctx.StaticVariable("Arm64ExynosM1Cflags", strings.Join(arm64CpuVariantCflags["exynos-m1"], " ")) + pctx.StaticVariable("Arm64ExynosM2Cflags", strings.Join(arm64CpuVariantCflags["exynos-m2"], " ")) } var ( diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go index b5afe408f..0fe5e6883 100644 --- a/cc/config/arm_device.go +++ b/cc/config/arm_device.go @@ -188,6 +188,9 @@ func init() { exportStringListStaticVariable("ArmArmCflags", armArmCflags) exportStringListStaticVariable("ArmThumbCflags", armThumbCflags) + exportedStringListDictVars.Set("ArmArchVariantCflags", armArchVariantCflags) + exportedStringListDictVars.Set("ArmCpuVariantCflags", armCpuVariantCflags) + // Clang arch variant cflags exportStringListStaticVariable("ArmArmv7ACflags", armArchVariantCflags["armv7-a"]) exportStringListStaticVariable("ArmArmv7ANeonCflags", armArchVariantCflags["armv7-a-neon"]) diff --git a/cc/config/bp2build.go b/cc/config/bp2build.go index e7e94a8a1..d19f5ac8e 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 } diff --git a/cc/config/bp2build_test.go b/cc/config/bp2build_test.go index a4745e609..883597ad3 100644 --- a/cc/config/bp2build_test.go +++ b/cc/config/bp2build_test.go @@ -115,3 +115,143 @@ func TestExpandVars(t *testing.T) { }) } } + +func TestBazelToolchainVars(t *testing.T) { + testCases := []struct { + name string + vars []bazelVarExporter + expectedOut string + }{ + { + name: "exports strings", + vars: []bazelVarExporter{ + exportedStringVariables{ + "a": "b", + "c": "d", + }, + }, + expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT. + +_a = "b" + +_c = "d" + +constants = struct( + a = _a, + c = _c, +)`, + }, + { + name: "exports string lists", + vars: []bazelVarExporter{ + exportedStringListVariables{ + "a": []string{"b1", "b2"}, + "c": []string{"d1", "d2"}, + }, + }, + expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT. + +_a = [ + "b1", + "b2", +] + +_c = [ + "d1", + "d2", +] + +constants = struct( + a = _a, + c = _c, +)`, + }, + { + name: "exports string lists dicts", + vars: []bazelVarExporter{ + exportedStringListDictVariables{ + "a": map[string][]string{"b1": []string{"b2"}}, + "c": map[string][]string{"d1": []string{"d2"}}, + }, + }, + expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT. + +_a = { + "b1": [ + "b2", + ], +} + +_c = { + "d1": [ + "d2", + ], +} + +constants = struct( + a = _a, + c = _c, +)`, + }, + { + name: "sorts across types", + vars: []bazelVarExporter{ + exportedStringVariables{ + "b": "b-val", + "d": "d-val", + }, + exportedStringListVariables{ + "c": []string{"c-val"}, + "e": []string{"e-val"}, + }, + exportedStringListDictVariables{ + "a": map[string][]string{"a1": []string{"a2"}}, + "f": map[string][]string{"f1": []string{"f2"}}, + }, + }, + expectedOut: `# GENERATED FOR BAZEL FROM SOONG. DO NOT EDIT. + +_a = { + "a1": [ + "a2", + ], +} + +_b = "b-val" + +_c = [ + "c-val", +] + +_d = "d-val" + +_e = [ + "e-val", +] + +_f = { + "f1": [ + "f2", + ], +} + +constants = struct( + a = _a, + b = _b, + c = _c, + d = _d, + e = _e, + f = _f, +)`, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + out := bazelToolchainVars(tc.vars...) + if out != tc.expectedOut { + t.Errorf("Expected \n%s, got \n%s", tc.expectedOut, out) + } + }) + } +} diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go index c4f47a724..00f07ff26 100644 --- a/cc/config/x86_64_device.go +++ b/cc/config/x86_64_device.go @@ -77,6 +77,14 @@ var ( "popcnt": []string{"-mpopcnt"}, "aes_ni": []string{"-maes"}, } + + x86_64DefaultArchVariantFeatures = []string{ + "ssse3", + "sse4", + "sse4_1", + "sse4_2", + "popcnt", + } ) const ( @@ -84,37 +92,38 @@ const ( ) func init() { - android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64, - "ssse3", - "sse4", - "sse4_1", - "sse4_2", - "popcnt") + android.RegisterDefaultArchVariantFeatures(android.Android, android.X86_64, x86_64DefaultArchVariantFeatures...) + exportedStringListVars.Set("X86_64DefaultArchVariantFeatures", x86_64DefaultArchVariantFeatures) pctx.StaticVariable("x86_64GccVersion", x86_64GccVersion) pctx.SourcePathVariable("X86_64GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86_64GccVersion}") - pctx.StaticVariable("X86_64ToolchainCflags", "-m64") - pctx.StaticVariable("X86_64ToolchainLdflags", "-m64") + exportStringListStaticVariable("X86_64ToolchainCflags", []string{"-m64"}) + exportStringListStaticVariable("X86_64ToolchainLdflags", []string{"-m64"}) - pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " ")) - pctx.StaticVariable("X86_64Lldflags", strings.Join(x86_64Ldflags, " ")) + exportStringListStaticVariable("X86_64Ldflags", x86_64Ldflags) + exportStringListStaticVariable("X86_64Lldflags", x86_64Ldflags) // Clang cflags - pctx.StaticVariable("X86_64Cflags", strings.Join(x86_64Cflags, " ")) - pctx.StaticVariable("X86_64Cppflags", strings.Join(x86_64Cppflags, " ")) + exportStringListStaticVariable("X86_64Cflags", x86_64Cflags) + exportStringListStaticVariable("X86_64Cppflags", x86_64Cppflags) // Yasm flags - pctx.StaticVariable("X86_64YasmFlags", "-f elf64 -m amd64") + exportStringListStaticVariable("X86_64YasmFlags", []string{ + "-f elf64", + "-m amd64", + }) // Extended cflags + exportedStringListDictVars.Set("X86_64ArchVariantCflags", x86_64ArchVariantCflags) + exportedStringListDictVars.Set("X86_64ArchFeatureCflags", x86_64ArchFeatureCflags) + // Architecture variant cflags for variant, cflags := range x86_64ArchVariantCflags { - pctx.StaticVariable("X86_64"+variant+"VariantCflags", - strings.Join(cflags, " ")) + pctx.StaticVariable("X86_64"+variant+"VariantCflags", strings.Join(cflags, " ")) } } diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go index 5e510a494..29f059303 100644 --- a/cc/config/x86_device.go +++ b/cc/config/x86_device.go @@ -97,25 +97,29 @@ func init() { pctx.SourcePathVariable("X86GccRoot", "prebuilts/gcc/${HostPrebuiltTag}/x86/x86_64-linux-android-${x86GccVersion}") - pctx.StaticVariable("X86ToolchainCflags", "-m32") - pctx.StaticVariable("X86ToolchainLdflags", "-m32") + exportStringListStaticVariable("X86ToolchainCflags", []string{"-m32"}) + exportStringListStaticVariable("X86ToolchainLdflags", []string{"-m32"}) - pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " ")) - pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " ")) + exportStringListStaticVariable("X86Ldflags", x86Ldflags) + exportStringListStaticVariable("X86Lldflags", x86Ldflags) // Clang cflags - pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " ")) - pctx.StaticVariable("X86Cppflags", strings.Join(x86Cppflags, " ")) + exportStringListStaticVariable("X86Cflags", x86Cflags) + exportStringListStaticVariable("X86Cppflags", x86Cppflags) // Yasm flags - pctx.StaticVariable("X86YasmFlags", "-f elf32 -m x86") + exportStringListStaticVariable("X86YasmFlags", []string{ + "-f elf32", + "-m x86", + }) // Extended cflags + exportedStringListDictVars.Set("X86ArchVariantCflags", x86ArchVariantCflags) + exportedStringListDictVars.Set("X86ArchFeatureCflags", x86ArchFeatureCflags) // Architecture variant cflags for variant, cflags := range x86ArchVariantCflags { - pctx.StaticVariable("X86"+variant+"VariantCflags", - strings.Join(cflags, " ")) + pctx.StaticVariable("X86"+variant+"VariantCflags", strings.Join(cflags, " ")) } }