aboutsummaryrefslogtreecommitdiff
path: root/tools/migration/crosstool_to_starlark_lib.go
diff options
context:
space:
mode:
Diffstat (limited to 'tools/migration/crosstool_to_starlark_lib.go')
-rw-r--r--tools/migration/crosstool_to_starlark_lib.go1419
1 files changed, 1419 insertions, 0 deletions
diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go
new file mode 100644
index 0000000..4403a4b
--- /dev/null
+++ b/tools/migration/crosstool_to_starlark_lib.go
@@ -0,0 +1,1419 @@
+/*
+Package crosstooltostarlarklib provides the Transform method
+for conversion of a CROSSTOOL file to a Starlark rule.
+
+https://github.com/bazelbuild/bazel/issues/5380
+*/
+package crosstooltostarlarklib
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "sort"
+ "strings"
+
+ crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto"
+)
+
+// CToolchainIdentifier is what we'll use to differ between CToolchains
+// If a CToolchain can be distinguished from the other CToolchains
+// by only one of the fields (eg if cpu is different for each CToolchain
+// then only that field will be set.
+type CToolchainIdentifier struct {
+ cpu string
+ compiler string
+}
+
+// Writes the load statement for the cc_toolchain_config_lib
+func getCcToolchainConfigHeader() string {
+ return `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl",
+ "action_config",
+ "artifact_name_pattern",
+ "env_entry",
+ "env_set",
+ "feature",
+ "feature_set",
+ "flag_group",
+ "flag_set",
+ "make_variable",
+ "tool",
+ "tool_path",
+ "variable_with_value",
+ "with_feature_set",
+)
+`
+}
+
+var allCompileActions = []string{
+ "c-compile",
+ "c++-compile",
+ "linkstamp-compile",
+ "assemble",
+ "preprocess-assemble",
+ "c++-header-parsing",
+ "c++-module-compile",
+ "c++-module-codegen",
+ "clif-match",
+ "lto-backend",
+}
+
+var allCppCompileActions = []string{
+ "c++-compile",
+ "linkstamp-compile",
+ "c++-header-parsing",
+ "c++-module-compile",
+ "c++-module-codegen",
+ "clif-match",
+}
+
+var preprocessorCompileActions = []string{
+ "c-compile",
+ "c++-compile",
+ "linkstamp-compile",
+ "preprocess-assemble",
+ "c++-header-parsing",
+ "c++-module-compile",
+ "clif-match",
+}
+
+var codegenCompileActions = []string{
+ "c-compile",
+ "c++-compile",
+ "linkstamp-compile",
+ "assemble",
+ "preprocess-assemble",
+ "c++-module-codegen",
+ "lto-backend",
+}
+
+var allLinkActions = []string{
+ "c++-link-executable",
+ "c++-link-dynamic-library",
+ "c++-link-nodeps-dynamic-library",
+}
+
+var actionNames = map[string]string{
+ "c-compile": "ACTION_NAMES.c_compile",
+ "c++-compile": "ACTION_NAMES.cpp_compile",
+ "linkstamp-compile": "ACTION_NAMES.linkstamp_compile",
+ "cc-flags-make-variable": "ACTION_NAMES.cc_flags_make_variable",
+ "c++-module-codegen": "ACTION_NAMES.cpp_module_codegen",
+ "c++-header-parsing": "ACTION_NAMES.cpp_header_parsing",
+ "c++-module-compile": "ACTION_NAMES.cpp_module_compile",
+ "assemble": "ACTION_NAMES.assemble",
+ "preprocess-assemble": "ACTION_NAMES.preprocess_assemble",
+ "lto-indexing": "ACTION_NAMES.lto_indexing",
+ "lto-backend": "ACTION_NAMES.lto_backend",
+ "c++-link-executable": "ACTION_NAMES.cpp_link_executable",
+ "c++-link-dynamic-library": "ACTION_NAMES.cpp_link_dynamic_library",
+ "c++-link-nodeps-dynamic-library": "ACTION_NAMES.cpp_link_nodeps_dynamic_library",
+ "c++-link-static-library": "ACTION_NAMES.cpp_link_static_library",
+ "strip": "ACTION_NAMES.strip",
+ "objc-compile": "ACTION_NAMES.objc_compile",
+ "objc++-compile": "ACTION_NAMES.objcpp_compile",
+ "clif-match": "ACTION_NAMES.clif_match",
+// "objcopy_embed_data": "ACTION_NAMES.objcopy_embed_data", // copybara-comment-this-out-please
+// "ld_embed_data": "ACTION_NAMES.ld_embed_data", // copybara-comment-this-out-please
+}
+
+func getLoadActionsStmt() string {
+ return "load(\"@bazel_tools//tools/build_defs/cc:action_names.bzl\", \"ACTION_NAMES\")\n\n"
+}
+
+// Returns a map {toolchain_identifier : CToolchainIdentifier}
+func toolchainToCToolchainIdentifier(
+ crosstool *crosstoolpb.CrosstoolRelease) map[string]CToolchainIdentifier {
+ cpuToCompiler := make(map[string][]string)
+ compilerToCPU := make(map[string][]string)
+ var cpus []string
+ var compilers []string
+ var identifiers []string
+ res := make(map[string]CToolchainIdentifier)
+ for _, cToolchain := range crosstool.GetToolchain() {
+ cpu := cToolchain.GetTargetCpu()
+ compiler := cToolchain.GetCompiler()
+
+ cpuToCompiler[cpu] = append(cpuToCompiler[cpu], compiler)
+ compilerToCPU[compiler] = append(compilerToCPU[compiler], cpu)
+
+ cpus = append(cpus, cToolchain.GetTargetCpu())
+ compilers = append(compilers, cToolchain.GetCompiler())
+ identifiers = append(identifiers, cToolchain.GetToolchainIdentifier())
+ }
+
+ for i := range cpus {
+ if len(cpuToCompiler[cpus[i]]) == 1 {
+ // if cpu is unique among CToolchains, we don't need the compiler field
+ res[identifiers[i]] = CToolchainIdentifier{cpu: cpus[i], compiler: ""}
+ } else {
+ res[identifiers[i]] = CToolchainIdentifier{
+ cpu: cpus[i],
+ compiler: compilers[i],
+ }
+ }
+ }
+ return res
+}
+
+func getConditionStatementForCToolchainIdentifier(identifier CToolchainIdentifier) string {
+ if identifier.compiler != "" {
+ return fmt.Sprintf(
+ "ctx.attr.cpu == \"%s\" and ctx.attr.compiler == \"%s\"",
+ identifier.cpu,
+ identifier.compiler)
+ }
+ return fmt.Sprintf("ctx.attr.cpu == \"%s\"", identifier.cpu)
+}
+
+func isArrayPrefix(prefix []string, arr []string) bool {
+ if len(prefix) > len(arr) {
+ return false
+ }
+ for i := 0; i < len(prefix); i++ {
+ if arr[i] != prefix[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func isAllCompileActions(actions []string) (bool, []string) {
+ if isArrayPrefix(allCompileActions, actions) {
+ return true, actions[len(allCompileActions):]
+ }
+ return false, actions
+}
+
+func isAllCppCompileActions(actions []string) (bool, []string) {
+ if isArrayPrefix(allCppCompileActions, actions) {
+ return true, actions[len(allCppCompileActions):]
+ }
+ return false, actions
+}
+
+func isPreprocessorCompileActions(actions []string) (bool, []string) {
+ if isArrayPrefix(preprocessorCompileActions, actions) {
+ return true, actions[len(preprocessorCompileActions):]
+ }
+ return false, actions
+}
+
+func isCodegenCompileActions(actions []string) (bool, []string) {
+ if isArrayPrefix(codegenCompileActions, actions) {
+ return true, actions[len(codegenCompileActions):]
+ }
+ return false, actions
+}
+
+func isAllLinkActions(actions []string) (bool, []string) {
+ if isArrayPrefix(allLinkActions, actions) {
+ return true, actions[len(allLinkActions):]
+ }
+ return false, actions
+}
+
+func getActionNames(actions []string) []string {
+ var res []string
+ for _, el := range actions {
+ if name, ok := actionNames[el]; ok {
+ res = append(res, name)
+ } else {
+ res = append(res, "\""+el+"\"")
+ }
+ }
+ return res
+}
+
+func getListOfActions(name string, depth int) string {
+ var res []string
+ if name == "all_compile_actions" {
+ res = getActionNames(allCompileActions)
+ } else if name == "all_cpp_compile_actions" {
+ res = getActionNames(allCppCompileActions)
+ } else if name == "preprocessor_compile_actions" {
+ res = getActionNames(preprocessorCompileActions)
+ } else if name == "codegen_compile_actions" {
+ res = getActionNames(codegenCompileActions)
+ } else if name == "all_link_actions" {
+ res = getActionNames(allLinkActions)
+ }
+ stmt := fmt.Sprintf("%s%s = %s\n\n", getTabs(depth),
+ name, makeStringArr(res, depth /* isPlainString= */, false))
+ return stmt
+}
+
+func processActions(actions []string, depth int) []string {
+ var res []string
+ var ok bool
+ initLen := len(actions)
+ if ok, actions = isAllCompileActions(actions); ok {
+ res = append(res, "all_compile_actions")
+ }
+ if ok, actions = isAllCppCompileActions(actions); ok {
+ res = append(res, "all_cpp_compile_actions")
+ }
+ if ok, actions = isPreprocessorCompileActions(actions); ok {
+ res = append(res, "preprocessor_compile_actions")
+ }
+ if ok, actions = isCodegenCompileActions(actions); ok {
+ res = append(res, "codegen_actions")
+ }
+ if ok, actions = isAllLinkActions(actions); ok {
+ res = append(res, "all_link_actions")
+ }
+ if len(actions) != 0 {
+ actions = getActionNames(actions)
+ newDepth := depth + 1
+ if len(actions) != initLen {
+ newDepth++
+ }
+ res = append(res, makeStringArr(actions, newDepth /* isPlainString= */, false))
+ }
+ return res
+}
+
+func getUniqueValues(arr []string) []string {
+ valuesSet := make(map[string]bool)
+ for _, val := range arr {
+ valuesSet[val] = true
+ }
+ var uniques []string
+ for val, _ := range valuesSet {
+ uniques = append(uniques, val)
+ }
+ sort.Strings(uniques)
+ return uniques
+}
+
+func getRule(cToolchainIdentifiers map[string]CToolchainIdentifier,
+ allowedCompilers []string) string {
+ cpus := make(map[string]bool)
+ shouldUseCompilerAttribute := false
+ for _, val := range cToolchainIdentifiers {
+ cpus[val.cpu] = true
+ if val.compiler != "" {
+ shouldUseCompilerAttribute = true
+ }
+ }
+
+ var cpuValues []string
+ for cpu := range cpus {
+ cpuValues = append(cpuValues, cpu)
+ }
+
+ var args []string
+ sort.Strings(cpuValues)
+ args = append(args,
+ fmt.Sprintf(
+ `"cpu": attr.string(mandatory=True, values=["%s"]),`,
+ strings.Join(cpuValues, "\", \"")))
+ if shouldUseCompilerAttribute {
+ // If there are two CToolchains that share the cpu we need the compiler attribute
+ // for our cc_toolchain_config rule.
+ allowedCompilers = getUniqueValues(allowedCompilers)
+ args = append(args,
+ fmt.Sprintf(`"compiler": attr.string(mandatory=True, values=["%s"]),`,
+ strings.Join(allowedCompilers, "\", \"")))
+ }
+ return fmt.Sprintf(`cc_toolchain_config = rule(
+ implementation = _impl,
+ attrs = {
+ %s
+ },
+ provides = [CcToolchainConfigInfo],
+ executable = True,
+)
+`, strings.Join(args, "\n "))
+}
+
+func getImplHeader() string {
+ return "def _impl(ctx):\n"
+}
+
+func getStringStatement(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, field string,
+ depth int) string {
+
+ identifiers := getToolchainIdentifiers(crosstool)
+ var fieldValues []string
+ if field == "toolchain_identifier" {
+ fieldValues = getToolchainIdentifiers(crosstool)
+ } else if field == "host_system_name" {
+ fieldValues = getHostSystemNames(crosstool)
+ } else if field == "target_system_name" {
+ fieldValues = getTargetSystemNames(crosstool)
+ } else if field == "target_cpu" {
+ fieldValues = getTargetCpus(crosstool)
+ } else if field == "target_libc" {
+ fieldValues = getTargetLibcs(crosstool)
+ } else if field == "compiler" {
+ fieldValues = getCompilers(crosstool)
+ } else if field == "abi_version" {
+ fieldValues = getAbiVersions(crosstool)
+ } else if field == "abi_libc_version" {
+ fieldValues = getAbiLibcVersions(crosstool)
+ } else if field == "cc_target_os" {
+ fieldValues = getCcTargetOss(crosstool)
+ } else if field == "builtin_sysroot" {
+ fieldValues = getBuiltinSysroots(crosstool)
+ }
+
+ mappedValuesToIds := getMappedStringValuesToIdentifiers(identifiers, fieldValues)
+ return getAssignmentStatement(field, mappedValuesToIds, crosstool,
+ cToolchainIdentifiers, depth /* isPlainString= */, true /* shouldFail= */, true)
+}
+
+func getFeatures(crosstool *crosstoolpb.CrosstoolRelease) (
+ map[string][]string, map[string]map[string][]string, error) {
+ featureNameToFeature := make(map[string]map[string][]string)
+ toolchainToFeatures := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ id := toolchain.GetToolchainIdentifier()
+ if len(toolchain.GetFeature()) == 0 {
+ toolchainToFeatures[id] = []string{}
+ }
+ for _, feature := range toolchain.GetFeature() {
+ featureName := strings.ToLower(feature.GetName()) + "_feature"
+ featureName = strings.Replace(featureName, "+", "p", -1)
+ featureName = strings.Replace(featureName, ".", "_", -1)
+ featureName = strings.Replace(featureName, "-", "_", -1)
+ stringFeature, err := parseFeature(feature, 1)
+ if err != nil {
+ return nil, nil, fmt.Errorf(
+ "Error in feature '%s': %v", feature.GetName(), err)
+ }
+ if _, ok := featureNameToFeature[featureName]; !ok {
+ featureNameToFeature[featureName] = make(map[string][]string)
+ }
+ featureNameToFeature[featureName][stringFeature] = append(
+ featureNameToFeature[featureName][stringFeature], id)
+ toolchainToFeatures[id] = append(toolchainToFeatures[id], featureName)
+ }
+ }
+ return toolchainToFeatures, featureNameToFeature, nil
+}
+
+func getFeaturesDeclaration(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier,
+ featureNameToFeature map[string]map[string][]string, depth int) string {
+ var res []string
+ for featureName, featureStringToID := range featureNameToFeature {
+ res = append(res,
+ getAssignmentStatement(
+ featureName,
+ featureStringToID,
+ crosstool,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false,
+ /* shouldFail= */ false))
+ }
+ return strings.Join(res, "")
+}
+
+func getFeaturesStmt(cToolchainIdentifiers map[string]CToolchainIdentifier,
+ toolchainToFeatures map[string][]string, depth int) string {
+ var res []string
+ arrToIdentifier := make(map[string][]string)
+ for id, features := range toolchainToFeatures {
+ arrayString := strings.Join(features, "{arrayFieldDelimiter}")
+ arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id)
+ }
+ res = append(res,
+ getStringArrStatement(
+ "features",
+ arrToIdentifier,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false))
+ return strings.Join(res, "\n")
+}
+
+func getActions(crosstool *crosstoolpb.CrosstoolRelease) (
+ map[string][]string, map[string]map[string][]string, error) {
+ actionNameToAction := make(map[string]map[string][]string)
+ toolchainToActions := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ id := toolchain.GetToolchainIdentifier()
+ var actionName string
+ if len(toolchain.GetActionConfig()) == 0 {
+ toolchainToActions[id] = []string{}
+ }
+ for _, action := range toolchain.GetActionConfig() {
+ if aName, ok := actionNames[action.GetActionName()]; ok {
+ actionName = aName
+ } else {
+ actionName = strings.ToLower(action.GetActionName())
+ actionName = strings.Replace(actionName, "+", "p", -1)
+ actionName = strings.Replace(actionName, ".", "_", -1)
+ actionName = strings.Replace(actionName, "-", "_", -1)
+ }
+ stringAction, err := parseAction(action, 1)
+ if err != nil {
+ return nil, nil, fmt.Errorf(
+ "Error in action_config '%s': %v", action.GetActionName(), err)
+ }
+ if _, ok := actionNameToAction[actionName]; !ok {
+ actionNameToAction[actionName] = make(map[string][]string)
+ }
+ actionNameToAction[actionName][stringAction] = append(
+ actionNameToAction[actionName][stringAction], id)
+ toolchainToActions[id] = append(
+ toolchainToActions[id],
+ strings.TrimPrefix(strings.ToLower(actionName), "action_names.")+"_action")
+ }
+ }
+ return toolchainToActions, actionNameToAction, nil
+}
+
+func getActionConfigsDeclaration(
+ crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier,
+ actionNameToAction map[string]map[string][]string, depth int) string {
+ var res []string
+ for actionName, actionStringToID := range actionNameToAction {
+ variableName := strings.TrimPrefix(strings.ToLower(actionName), "action_names.") + "_action"
+ res = append(res,
+ getAssignmentStatement(
+ variableName,
+ actionStringToID,
+ crosstool,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false,
+ /* shouldFail= */ false))
+ }
+ return strings.Join(res, "")
+}
+
+func getActionConfigsStmt(
+ cToolchainIdentifiers map[string]CToolchainIdentifier,
+ toolchainToActions map[string][]string, depth int) string {
+ var res []string
+ arrToIdentifier := make(map[string][]string)
+ for id, actions := range toolchainToActions {
+ var arrayString string
+ arrayString = strings.Join(actions, "{arrayFieldDelimiter}")
+ arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id)
+ }
+ res = append(res,
+ getStringArrStatement(
+ "action_configs",
+ arrToIdentifier,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false))
+ return strings.Join(res, "\n")
+}
+
+func parseAction(action *crosstoolpb.CToolchain_ActionConfig, depth int) (string, error) {
+ actionName := action.GetActionName()
+ aName := ""
+ if val, ok := actionNames[actionName]; ok {
+ aName = val
+ } else {
+ aName = "\"" + action.GetActionName() + "\""
+ }
+ name := fmt.Sprintf("action_name = %s", aName)
+ fields := []string{name}
+ if action.GetEnabled() {
+ fields = append(fields, "enabled = True")
+ }
+ if len(action.GetFlagSet()) != 0 {
+ flagSets, err := parseFlagSets(action.GetFlagSet(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_sets = "+flagSets)
+ }
+ if len(action.GetImplies()) != 0 {
+ implies := "implies = " +
+ makeStringArr(action.GetImplies(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, implies)
+ }
+ if len(action.GetTool()) != 0 {
+ tools := "tools = " + parseTools(action.GetTool(), depth+1)
+ fields = append(fields, tools)
+ }
+ return createObject("action_config", fields, depth), nil
+}
+
+func getStringArrStatement(attr string, arrValToIds map[string][]string,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, depth int, plainString bool) string {
+ var b bytes.Buffer
+ if len(arrValToIds) == 0 {
+ b.WriteString(fmt.Sprintf("%s%s = []\n", getTabs(depth), attr))
+ } else if len(arrValToIds) == 1 {
+ for value := range arrValToIds {
+ var arr []string
+ if value == "" {
+ arr = []string{}
+ } else if value == "None" {
+ b.WriteString(fmt.Sprintf("%s%s = None\n", getTabs(depth), attr))
+ break
+ } else {
+ arr = strings.Split(value, "{arrayFieldDelimiter}")
+ }
+ b.WriteString(
+ fmt.Sprintf(
+ "%s%s = %s\n",
+ getTabs(depth),
+ attr,
+ makeStringArr(arr, depth+1, plainString)))
+ break
+ }
+ } else {
+ first := true
+ var keys []string
+ for k := range arrValToIds {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, value := range keys {
+ ids := arrValToIds[value]
+ branch := "elif"
+ if first {
+ branch = "if"
+ }
+ first = false
+ var arr []string
+ if value == "" {
+ arr = []string{}
+ } else if value == "None" {
+ b.WriteString(
+ getIfStatement(
+ branch, ids, attr, "None", cToolchainIdentifiers,
+ depth /* isPlainString= */, true))
+ continue
+ } else {
+ arr = strings.Split(value, "{arrayFieldDelimiter}")
+ }
+ b.WriteString(
+ getIfStatement(branch, ids, attr,
+ makeStringArr(arr, depth+1, plainString),
+ cToolchainIdentifiers, depth /* isPlainString= */, false))
+ }
+ b.WriteString(fmt.Sprintf("%selse:\n%sfail(\"Unreachable\")\n", getTabs(depth), getTabs(depth+1)))
+ }
+ b.WriteString("\n")
+ return b.String()
+}
+
+func getStringArr(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, attr string, depth int) string {
+ var res []string
+ arrToIdentifier := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ id := toolchain.GetToolchainIdentifier()
+ arrayString := strings.Join(getArrField(attr, toolchain), "{arrayFieldDelimiter}")
+ arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id)
+ }
+ statement := getStringArrStatement(attr, arrToIdentifier, cToolchainIdentifiers, depth /* isPlainString= */, true)
+ res = append(res, statement)
+ return strings.Join(res, "\n")
+}
+
+func getArrField(attr string, toolchain *crosstoolpb.CToolchain) []string {
+ var arr []string
+ if attr == "cxx_builtin_include_directories" {
+ arr = toolchain.GetCxxBuiltinIncludeDirectory()
+ }
+ return arr
+}
+
+func getTabs(depth int) string {
+ var res string
+ for i := 0; i < depth; i++ {
+ res = res + " "
+ }
+ return res
+}
+
+func createObject(objtype string, fields []string, depth int) string {
+ if len(fields) == 0 {
+ return objtype + "()"
+ }
+ singleLine := objtype + "(" + strings.Join(fields, ", ") + ")"
+ if len(singleLine) < 60 {
+ return singleLine
+ }
+ return objtype +
+ "(\n" +
+ getTabs(depth+1) +
+ strings.Join(fields, ",\n"+getTabs(depth+1)) +
+ ",\n" + getTabs(depth) +
+ ")"
+}
+
+func getArtifactNamePatterns(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string {
+ var res []string
+ artifactToIds := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ artifactNamePatterns := parseArtifactNamePatterns(
+ toolchain.GetArtifactNamePattern(),
+ depth)
+ artifactToIds[artifactNamePatterns] = append(
+ artifactToIds[artifactNamePatterns],
+ toolchain.GetToolchainIdentifier())
+ }
+ res = append(res,
+ getAssignmentStatement(
+ "artifact_name_patterns",
+ artifactToIds,
+ crosstool,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false,
+ /* shouldFail= */ true))
+ return strings.Join(res, "\n")
+}
+
+func parseArtifactNamePatterns(
+ artifactNamePatterns []*crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string {
+ var res []string
+ for _, pattern := range artifactNamePatterns {
+ res = append(res, parseArtifactNamePattern(pattern, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseArtifactNamePattern(
+ artifactNamePattern *crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string {
+ categoryName := fmt.Sprintf("category_name = \"%s\"", artifactNamePattern.GetCategoryName())
+ prefix := fmt.Sprintf("prefix = \"%s\"", artifactNamePattern.GetPrefix())
+ extension := fmt.Sprintf("extension = \"%s\"", artifactNamePattern.GetExtension())
+ fields := []string{categoryName, prefix, extension}
+ return createObject("artifact_name_pattern", fields, depth)
+}
+
+func parseFeature(feature *crosstoolpb.CToolchain_Feature, depth int) (string, error) {
+ name := fmt.Sprintf("name = \"%s\"", feature.GetName())
+
+ fields := []string{name}
+ if feature.GetEnabled() {
+ fields = append(fields, "enabled = True")
+ }
+
+ if len(feature.GetFlagSet()) > 0 {
+ flagSets, err := parseFlagSets(feature.GetFlagSet(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_sets = "+flagSets)
+ }
+ if len(feature.GetEnvSet()) > 0 {
+ envSets := "env_sets = " + parseEnvSets(feature.GetEnvSet(), depth+1)
+ fields = append(fields, envSets)
+ }
+ if len(feature.GetRequires()) > 0 {
+ requires := "requires = " + parseFeatureSets(feature.GetRequires(), depth+1)
+ fields = append(fields, requires)
+ }
+ if len(feature.GetImplies()) > 0 {
+ implies := "implies = " +
+ makeStringArr(feature.GetImplies(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, implies)
+ }
+ if len(feature.GetProvides()) > 0 {
+ provides := "provides = " +
+ makeStringArr(feature.GetProvides(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, provides)
+ }
+ return createObject("feature", fields, depth), nil
+}
+
+func parseFlagSets(flagSets []*crosstoolpb.CToolchain_FlagSet, depth int) (string, error) {
+ var res []string
+ for _, flagSet := range flagSets {
+ parsedFlagset, err := parseFlagSet(flagSet, depth+1)
+ if err != nil {
+ return "", err
+ }
+ res = append(res, parsedFlagset)
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false), nil
+}
+
+func parseFlagSet(flagSet *crosstoolpb.CToolchain_FlagSet, depth int) (string, error) {
+ var fields []string
+ if len(flagSet.GetAction()) > 0 {
+ actionArr := processActions(flagSet.GetAction(), depth)
+ actions := "actions = " + strings.Join(actionArr, " +\n"+getTabs(depth+2))
+ fields = append(fields, actions)
+ }
+ if len(flagSet.GetFlagGroup()) > 0 {
+ flagGroups, err := parseFlagGroups(flagSet.GetFlagGroup(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ fields = append(fields, "flag_groups = "+flagGroups)
+ }
+ if len(flagSet.GetWithFeature()) > 0 {
+ withFeatures := "with_features = " +
+ parseWithFeatureSets(flagSet.GetWithFeature(), depth+1)
+ fields = append(fields, withFeatures)
+ }
+ return createObject("flag_set", fields, depth), nil
+}
+
+func parseFlagGroups(flagGroups []*crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) {
+ var res []string
+ for _, flagGroup := range flagGroups {
+ flagGroupString, err := parseFlagGroup(flagGroup, depth+1)
+ if err != nil {
+ return "", err
+ }
+ res = append(res, flagGroupString)
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false), nil
+}
+
+func parseFlagGroup(flagGroup *crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) {
+ var res []string
+ if len(flagGroup.GetFlag()) != 0 {
+ res = append(res, "flags = "+makeStringArr(flagGroup.GetFlag(), depth+1, true))
+ }
+ if flagGroup.GetIterateOver() != "" {
+ res = append(res, fmt.Sprintf("iterate_over = \"%s\"", flagGroup.GetIterateOver()))
+ }
+ if len(flagGroup.GetFlagGroup()) != 0 {
+ flagGroupString, err := parseFlagGroups(flagGroup.GetFlagGroup(), depth+1)
+ if err != nil {
+ return "", err
+ }
+ res = append(res, "flag_groups = "+flagGroupString)
+ }
+ if len(flagGroup.GetExpandIfAllAvailable()) > 1 {
+ return "", errors.New("Flag group must not have more than one 'expand_if_all_available' field")
+ }
+ if len(flagGroup.GetExpandIfAllAvailable()) != 0 {
+ res = append(res,
+ fmt.Sprintf(
+ "expand_if_available = \"%s\"",
+ flagGroup.GetExpandIfAllAvailable()[0]))
+ }
+ if len(flagGroup.GetExpandIfNoneAvailable()) > 1 {
+ return "", errors.New("Flag group must not have more than one 'expand_if_none_available' field")
+ }
+ if len(flagGroup.GetExpandIfNoneAvailable()) != 0 {
+ res = append(res,
+ fmt.Sprintf(
+ "expand_if_not_available = \"%s\"",
+ flagGroup.GetExpandIfNoneAvailable()[0]))
+ }
+ if flagGroup.GetExpandIfTrue() != "" {
+ res = append(res, fmt.Sprintf("expand_if_true = \"%s\"",
+ flagGroup.GetExpandIfTrue()))
+ }
+ if flagGroup.GetExpandIfFalse() != "" {
+ res = append(res, fmt.Sprintf("expand_if_false = \"%s\"",
+ flagGroup.GetExpandIfFalse()))
+ }
+ if flagGroup.GetExpandIfEqual() != nil {
+ res = append(res,
+ "expand_if_equal = "+parseVariableWithValue(
+ flagGroup.GetExpandIfEqual(), depth+1))
+ }
+ return createObject("flag_group", res, depth), nil
+}
+
+func parseVariableWithValue(variable *crosstoolpb.CToolchain_VariableWithValue, depth int) string {
+ variableName := fmt.Sprintf("name = \"%s\"", variable.GetVariable())
+ value := fmt.Sprintf("value = \"%s\"", variable.GetValue())
+ return createObject("variable_with_value", []string{variableName, value}, depth)
+}
+
+func getToolPaths(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string {
+ var res []string
+ toolPathsToIds := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ toolPaths := parseToolPaths(toolchain.GetToolPath(), depth)
+ toolPathsToIds[toolPaths] = append(
+ toolPathsToIds[toolPaths],
+ toolchain.GetToolchainIdentifier())
+ }
+ res = append(res,
+ getAssignmentStatement(
+ "tool_paths",
+ toolPathsToIds,
+ crosstool,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false,
+ /* shouldFail= */ true))
+ return strings.Join(res, "\n")
+}
+
+func parseToolPaths(toolPaths []*crosstoolpb.ToolPath, depth int) string {
+ var res []string
+ for _, toolPath := range toolPaths {
+ res = append(res, parseToolPath(toolPath, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseToolPath(toolPath *crosstoolpb.ToolPath, depth int) string {
+ name := fmt.Sprintf("name = \"%s\"", toolPath.GetName())
+ path := toolPath.GetPath()
+ if path == "" {
+ path = "NOT_USED"
+ }
+ path = fmt.Sprintf("path = \"%s\"", path)
+ return createObject("tool_path", []string{name, path}, depth)
+}
+
+func getMakeVariables(crosstool *crosstoolpb.CrosstoolRelease,
+ cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string {
+ var res []string
+ makeVariablesToIds := make(map[string][]string)
+ for _, toolchain := range crosstool.GetToolchain() {
+ makeVariables := parseMakeVariables(toolchain.GetMakeVariable(), depth)
+ makeVariablesToIds[makeVariables] = append(
+ makeVariablesToIds[makeVariables],
+ toolchain.GetToolchainIdentifier())
+ }
+ res = append(res,
+ getAssignmentStatement(
+ "make_variables",
+ makeVariablesToIds,
+ crosstool,
+ cToolchainIdentifiers,
+ depth,
+ /* isPlainString= */ false,
+ /* shouldFail= */ true))
+ return strings.Join(res, "\n")
+}
+
+func parseMakeVariables(makeVariables []*crosstoolpb.MakeVariable, depth int) string {
+ var res []string
+ for _, makeVariable := range makeVariables {
+ res = append(res, parseMakeVariable(makeVariable, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseMakeVariable(makeVariable *crosstoolpb.MakeVariable, depth int) string {
+ name := fmt.Sprintf("name = \"%s\"", makeVariable.GetName())
+ value := fmt.Sprintf("value = \"%s\"", makeVariable.GetValue())
+ return createObject("make_variable", []string{name, value}, depth)
+}
+
+func parseTools(tools []*crosstoolpb.CToolchain_Tool, depth int) string {
+ var res []string
+ for _, tool := range tools {
+ res = append(res, parseTool(tool, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseTool(tool *crosstoolpb.CToolchain_Tool, depth int) string {
+ toolPath := "path = \"NOT_USED\""
+ if tool.GetToolPath() != "" {
+ toolPath = fmt.Sprintf("path = \"%s\"", tool.GetToolPath())
+ }
+ fields := []string{toolPath}
+ if len(tool.GetWithFeature()) != 0 {
+ withFeatures := "with_features = " + parseWithFeatureSets(tool.GetWithFeature(), depth+1)
+ fields = append(fields, withFeatures)
+ }
+ if len(tool.GetExecutionRequirement()) != 0 {
+ executionRequirements := "execution_requirements = " +
+ makeStringArr(tool.GetExecutionRequirement(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, executionRequirements)
+ }
+ return createObject("tool", fields, depth)
+}
+
+func parseEnvEntries(envEntries []*crosstoolpb.CToolchain_EnvEntry, depth int) string {
+ var res []string
+ for _, envEntry := range envEntries {
+ res = append(res, parseEnvEntry(envEntry, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseEnvEntry(envEntry *crosstoolpb.CToolchain_EnvEntry, depth int) string {
+ key := fmt.Sprintf("key = \"%s\"", envEntry.GetKey())
+ value := fmt.Sprintf("value = \"%s\"", envEntry.GetValue())
+ return createObject("env_entry", []string{key, value}, depth)
+}
+
+func parseWithFeatureSets(withFeatureSets []*crosstoolpb.CToolchain_WithFeatureSet,
+ depth int) string {
+ var res []string
+ for _, withFeature := range withFeatureSets {
+ res = append(res, parseWithFeatureSet(withFeature, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseWithFeatureSet(withFeature *crosstoolpb.CToolchain_WithFeatureSet,
+ depth int) string {
+ var fields []string
+ if len(withFeature.GetFeature()) != 0 {
+ features := "features = " +
+ makeStringArr(withFeature.GetFeature(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, features)
+ }
+ if len(withFeature.GetNotFeature()) != 0 {
+ notFeatures := "not_features = " +
+ makeStringArr(withFeature.GetNotFeature(), depth+1 /* isPlainString= */, true)
+ fields = append(fields, notFeatures)
+ }
+ return createObject("with_feature_set", fields, depth)
+}
+
+func parseEnvSets(envSets []*crosstoolpb.CToolchain_EnvSet, depth int) string {
+ var res []string
+ for _, envSet := range envSets {
+ envSetString := parseEnvSet(envSet, depth+1)
+ res = append(res, envSetString)
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseEnvSet(envSet *crosstoolpb.CToolchain_EnvSet, depth int) string {
+ actionsStatement := processActions(envSet.GetAction(), depth)
+ actions := "actions = " + strings.Join(actionsStatement, " +\n"+getTabs(depth+2))
+ fields := []string{actions}
+ if len(envSet.GetEnvEntry()) != 0 {
+ envEntries := "env_entries = " + parseEnvEntries(envSet.GetEnvEntry(), depth+1)
+ fields = append(fields, envEntries)
+ }
+ if len(envSet.GetWithFeature()) != 0 {
+ withFeatures := "with_features = " + parseWithFeatureSets(envSet.GetWithFeature(), depth+1)
+ fields = append(fields, withFeatures)
+ }
+ return createObject("env_set", fields, depth)
+}
+
+func parseFeatureSets(featureSets []*crosstoolpb.CToolchain_FeatureSet, depth int) string {
+ var res []string
+ for _, featureSet := range featureSets {
+ res = append(res, parseFeatureSet(featureSet, depth+1))
+ }
+ return makeStringArr(res, depth /* isPlainString= */, false)
+}
+
+func parseFeatureSet(featureSet *crosstoolpb.CToolchain_FeatureSet, depth int) string {
+ features := "features = " +
+ makeStringArr(featureSet.GetFeature(), depth+1 /* isPlainString= */, true)
+ return createObject("feature_set", []string{features}, depth)
+}
+
+// Takes in a list of string elements and returns a string that represents
+// an array :
+// [
+// "element1",
+// "element2",
+// ]
+// The isPlainString argument tells us whether the input elements should be
+// treated as string (eg, flags), or not (eg, variable names)
+func makeStringArr(arr []string, depth int, isPlainString bool) string {
+ if len(arr) == 0 {
+ return "[]"
+ }
+ var escapedArr []string
+ for _, el := range arr {
+ if isPlainString {
+ escapedArr = append(escapedArr, strings.Replace(el, "\"", "\\\"", -1))
+ } else {
+ escapedArr = append(escapedArr, el)
+ }
+ }
+ addQuote := ""
+ if isPlainString {
+ addQuote = "\""
+ }
+ singleLine := "[" + addQuote + strings.Join(escapedArr, addQuote+", "+addQuote) + addQuote + "]"
+ if len(singleLine) < 60 {
+ return singleLine
+ }
+ return "[\n" +
+ getTabs(depth+1) +
+ addQuote +
+ strings.Join(escapedArr, addQuote+",\n"+getTabs(depth+1)+addQuote) +
+ addQuote +
+ ",\n" +
+ getTabs(depth) +
+ "]"
+}
+
+// Returns a string that represents a value assignment
+// (eg if ctx.attr.cpu == "linux":
+// compiler = "llvm"
+// elif ctx.attr.cpu == "windows":
+// compiler = "mingw"
+// else:
+// fail("Unreachable")
+func getAssignmentStatement(field string, valToIds map[string][]string,
+ crosstool *crosstoolpb.CrosstoolRelease,
+ toCToolchainIdentifier map[string]CToolchainIdentifier,
+ depth int, isPlainString, shouldFail bool) string {
+ var b bytes.Buffer
+ if len(valToIds) <= 1 {
+ // if there is only one possible value for this field, we don't need if statements
+ for val := range valToIds {
+ if val != "None" && isPlainString {
+ val = "\"" + val + "\""
+ }
+ b.WriteString(fmt.Sprintf("%s%s = %s\n", getTabs(depth), field, val))
+ break
+ }
+ } else {
+ first := true
+ var keys []string
+ for k := range valToIds {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, value := range keys {
+ ids := valToIds[value]
+ branch := "elif"
+ if first {
+ branch = "if"
+ }
+ b.WriteString(
+ getIfStatement(branch, ids, field, value,
+ toCToolchainIdentifier, depth, isPlainString))
+ first = false
+ }
+ if shouldFail {
+ b.WriteString(
+ fmt.Sprintf(
+ "%selse:\n%sfail(\"Unreachable\")\n",
+ getTabs(depth), getTabs(depth+1)))
+ } else {
+ b.WriteString(
+ fmt.Sprintf(
+ "%selse:\n%s%s = None\n",
+ getTabs(depth), getTabs(depth+1), field))
+ }
+ }
+ b.WriteString("\n")
+ return b.String()
+}
+
+func getCPUToCompilers(identifiers []CToolchainIdentifier) map[string][]string {
+ res := make(map[string][]string)
+ for _, identifier := range identifiers {
+ if identifier.compiler != "" {
+ res[identifier.cpu] = append(res[identifier.cpu], identifier.compiler)
+ }
+ }
+ return res
+}
+
+func getIfStatement(ifOrElseIf string, identifiers []string, field, val string,
+ toCToolchainIdentifier map[string]CToolchainIdentifier, depth int,
+ isPlainString bool) string {
+ usedStmts := make(map[string]bool)
+ if val != "None" && isPlainString {
+ val = "\"" + val + "\""
+ }
+ var cToolchainIdentifiers []CToolchainIdentifier
+ for _, value := range toCToolchainIdentifier {
+ cToolchainIdentifiers = append(cToolchainIdentifiers, value)
+ }
+ cpuToCompilers := getCPUToCompilers(cToolchainIdentifiers)
+ countCpus := make(map[string]int)
+ var conditions []string
+ for _, id := range identifiers {
+ identifier := toCToolchainIdentifier[id]
+ stmt := getConditionStatementForCToolchainIdentifier(identifier)
+ if _, ok := usedStmts[stmt]; !ok {
+ conditions = append(conditions, stmt)
+ usedStmts[stmt] = true
+ if identifier.compiler != "" {
+ countCpus[identifier.cpu]++
+ }
+ }
+ }
+
+ var compressedConditions []string
+ usedStmtsOptimized := make(map[string]bool)
+ for _, id := range identifiers {
+ identifier := toCToolchainIdentifier[id]
+ var stmt string
+ if _, ok := countCpus[identifier.cpu]; ok {
+ if countCpus[identifier.cpu] == len(cpuToCompilers[identifier.cpu]) {
+ stmt = getConditionStatementForCToolchainIdentifier(
+ CToolchainIdentifier{cpu: identifier.cpu, compiler: ""})
+ } else {
+ stmt = getConditionStatementForCToolchainIdentifier(identifier)
+ }
+ } else {
+ stmt = getConditionStatementForCToolchainIdentifier(identifier)
+ }
+ if _, ok := usedStmtsOptimized[stmt]; !ok {
+ compressedConditions = append(compressedConditions, stmt)
+ usedStmtsOptimized[stmt] = true
+ }
+ }
+
+ sort.Strings(compressedConditions)
+ val = strings.Join(strings.Split(val, "\n"+getTabs(depth)), "\n"+getTabs(depth+1))
+ return fmt.Sprintf(`%s%s %s:
+%s%s = %s
+`, getTabs(depth),
+ ifOrElseIf,
+ "("+strings.Join(compressedConditions, "\n"+getTabs(depth+1)+"or ")+")",
+ getTabs(depth+1),
+ field,
+ val)
+}
+
+func getToolchainIdentifiers(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetToolchainIdentifier())
+ }
+ return res
+}
+
+func getHostSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetHostSystemName())
+ }
+ return res
+}
+
+func getTargetSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetTargetSystemName())
+ }
+ return res
+}
+
+func getTargetCpus(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetTargetCpu())
+ }
+ return res
+}
+
+func getTargetLibcs(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetTargetLibc())
+ }
+ return res
+}
+
+func getCompilers(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetCompiler())
+ }
+ return res
+}
+
+func getAbiVersions(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetAbiVersion())
+ }
+ return res
+}
+
+func getAbiLibcVersions(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ res = append(res, toolchain.GetAbiLibcVersion())
+ }
+ return res
+}
+
+func getCcTargetOss(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ targetOS := "None"
+ if toolchain.GetCcTargetOs() != "" {
+ targetOS = toolchain.GetCcTargetOs()
+ }
+ res = append(res, targetOS)
+ }
+ return res
+}
+
+func getBuiltinSysroots(crosstool *crosstoolpb.CrosstoolRelease) []string {
+ var res []string
+ for _, toolchain := range crosstool.GetToolchain() {
+ sysroot := "None"
+ if toolchain.GetBuiltinSysroot() != "" {
+ sysroot = toolchain.GetBuiltinSysroot()
+ }
+ res = append(res, sysroot)
+ }
+ return res
+}
+
+func getMappedStringValuesToIdentifiers(identifiers, fields []string) map[string][]string {
+ res := make(map[string][]string)
+ for i := range identifiers {
+ res[fields[i]] = append(res[fields[i]], identifiers[i])
+ }
+ return res
+}
+
+func getReturnStatement() string {
+ return `
+ out = ctx.actions.declare_file(ctx.label.name)
+ ctx.actions.write(out, "Fake executable")
+ return [
+ cc_common.create_cc_toolchain_config_info(
+ ctx = ctx,
+ features = features,
+ action_configs = action_configs,
+ artifact_name_patterns = artifact_name_patterns,
+ cxx_builtin_include_directories = cxx_builtin_include_directories,
+ toolchain_identifier = toolchain_identifier,
+ host_system_name = host_system_name,
+ target_system_name = target_system_name,
+ target_cpu = target_cpu,
+ target_libc = target_libc,
+ compiler = compiler,
+ abi_version = abi_version,
+ abi_libc_version = abi_libc_version,
+ tool_paths = tool_paths,
+ make_variables = make_variables,
+ builtin_sysroot = builtin_sysroot,
+ cc_target_os = cc_target_os
+ ),
+ DefaultInfo(
+ executable = out,
+ ),
+ ]
+`
+}
+
+// Transform writes a cc_toolchain_config rule functionally equivalent to the
+// CROSSTOOL file.
+func Transform(crosstool *crosstoolpb.CrosstoolRelease) (string, error) {
+ var b bytes.Buffer
+
+ cToolchainIdentifiers := toolchainToCToolchainIdentifier(crosstool)
+
+ toolchainToFeatures, featureNameToFeature, err := getFeatures(crosstool)
+ if err != nil {
+ return "", err
+ }
+
+ toolchainToActions, actionNameToAction, err := getActions(crosstool)
+ if err != nil {
+ return "", err
+ }
+
+ header := getCcToolchainConfigHeader()
+ if _, err := b.WriteString(header); err != nil {
+ return "", err
+ }
+
+ loadActionsStmt := getLoadActionsStmt()
+ if _, err := b.WriteString(loadActionsStmt); err != nil {
+ return "", err
+ }
+
+ implHeader := getImplHeader()
+ if _, err := b.WriteString(implHeader); err != nil {
+ return "", err
+ }
+
+ stringFields := []string{
+ "toolchain_identifier",
+ "host_system_name",
+ "target_system_name",
+ "target_cpu",
+ "target_libc",
+ "compiler",
+ "abi_version",
+ "abi_libc_version",
+ "cc_target_os",
+ "builtin_sysroot",
+ }
+
+ for _, stringField := range stringFields {
+ stmt := getStringStatement(crosstool, cToolchainIdentifiers, stringField, 1)
+ if _, err := b.WriteString(stmt); err != nil {
+ return "", err
+ }
+ }
+
+ listsOfActions := []string{
+ "all_compile_actions",
+ "all_cpp_compile_actions",
+ "preprocessor_compile_actions",
+ "codegen_compile_actions",
+ "all_link_actions",
+ }
+
+ for _, listOfActions := range listsOfActions {
+ actions := getListOfActions(listOfActions, 1)
+ if _, err := b.WriteString(actions); err != nil {
+ return "", err
+ }
+ }
+
+ actionConfigDeclaration := getActionConfigsDeclaration(
+ crosstool, cToolchainIdentifiers, actionNameToAction, 1)
+ if _, err := b.WriteString(actionConfigDeclaration); err != nil {
+ return "", err
+ }
+
+ actionConfigStatement := getActionConfigsStmt(
+ cToolchainIdentifiers, toolchainToActions, 1)
+ if _, err := b.WriteString(actionConfigStatement); err != nil {
+ return "", err
+ }
+
+ featureDeclaration := getFeaturesDeclaration(
+ crosstool, cToolchainIdentifiers, featureNameToFeature, 1)
+ if _, err := b.WriteString(featureDeclaration); err != nil {
+ return "", err
+ }
+
+ featuresStatement := getFeaturesStmt(
+ cToolchainIdentifiers, toolchainToFeatures, 1)
+ if _, err := b.WriteString(featuresStatement); err != nil {
+ return "", err
+ }
+
+ includeDirectories := getStringArr(
+ crosstool, cToolchainIdentifiers, "cxx_builtin_include_directories", 1)
+ if _, err := b.WriteString(includeDirectories); err != nil {
+ return "", err
+ }
+
+ artifactNamePatterns := getArtifactNamePatterns(
+ crosstool, cToolchainIdentifiers, 1)
+ if _, err := b.WriteString(artifactNamePatterns); err != nil {
+ return "", err
+ }
+
+ makeVariables := getMakeVariables(crosstool, cToolchainIdentifiers, 1)
+ if _, err := b.WriteString(makeVariables); err != nil {
+ return "", err
+ }
+
+ toolPaths := getToolPaths(crosstool, cToolchainIdentifiers, 1)
+ if _, err := b.WriteString(toolPaths); err != nil {
+ return "", err
+ }
+
+ if _, err := b.WriteString(getReturnStatement()); err != nil {
+ return "", err
+ }
+
+ rule := getRule(cToolchainIdentifiers, getCompilers(crosstool))
+ if _, err := b.WriteString(rule); err != nil {
+ return "", err
+ }
+
+ return b.String(), nil
+}