1/* 2Package crosstooltostarlarklib provides the Transform method 3for conversion of a CROSSTOOL file to a Starlark rule. 4 5https://github.com/bazelbuild/bazel/issues/5380 6*/ 7package crosstooltostarlarklib 8 9import ( 10 "bytes" 11 "errors" 12 "fmt" 13 "sort" 14 "strings" 15 16 crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" 17) 18 19// CToolchainIdentifier is what we'll use to differ between CToolchains 20// If a CToolchain can be distinguished from the other CToolchains 21// by only one of the fields (eg if cpu is different for each CToolchain 22// then only that field will be set. 23type CToolchainIdentifier struct { 24 cpu string 25 compiler string 26} 27 28// Writes the load statement for the cc_toolchain_config_lib 29func getCcToolchainConfigHeader() string { 30 return `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", 31 "action_config", 32 "artifact_name_pattern", 33 "env_entry", 34 "env_set", 35 "feature", 36 "feature_set", 37 "flag_group", 38 "flag_set", 39 "make_variable", 40 "tool", 41 "tool_path", 42 "variable_with_value", 43 "with_feature_set", 44) 45` 46} 47 48var allCompileActions = []string{ 49 "c-compile", 50 "c++-compile", 51 "linkstamp-compile", 52 "assemble", 53 "preprocess-assemble", 54 "c++-header-parsing", 55 "c++-module-compile", 56 "c++-module-codegen", 57 "clif-match", 58 "lto-backend", 59} 60 61var allCppCompileActions = []string{ 62 "c++-compile", 63 "linkstamp-compile", 64 "c++-header-parsing", 65 "c++-module-compile", 66 "c++-module-codegen", 67 "clif-match", 68} 69 70var preprocessorCompileActions = []string{ 71 "c-compile", 72 "c++-compile", 73 "linkstamp-compile", 74 "preprocess-assemble", 75 "c++-header-parsing", 76 "c++-module-compile", 77 "clif-match", 78} 79 80var codegenCompileActions = []string{ 81 "c-compile", 82 "c++-compile", 83 "linkstamp-compile", 84 "assemble", 85 "preprocess-assemble", 86 "c++-module-codegen", 87 "lto-backend", 88} 89 90var allLinkActions = []string{ 91 "c++-link-executable", 92 "c++-link-dynamic-library", 93 "c++-link-nodeps-dynamic-library", 94} 95 96var actionNames = map[string]string{ 97 "c-compile": "ACTION_NAMES.c_compile", 98 "c++-compile": "ACTION_NAMES.cpp_compile", 99 "linkstamp-compile": "ACTION_NAMES.linkstamp_compile", 100 "cc-flags-make-variable": "ACTION_NAMES.cc_flags_make_variable", 101 "c++-module-codegen": "ACTION_NAMES.cpp_module_codegen", 102 "c++-header-parsing": "ACTION_NAMES.cpp_header_parsing", 103 "c++-module-compile": "ACTION_NAMES.cpp_module_compile", 104 "assemble": "ACTION_NAMES.assemble", 105 "preprocess-assemble": "ACTION_NAMES.preprocess_assemble", 106 "lto-indexing": "ACTION_NAMES.lto_indexing", 107 "lto-backend": "ACTION_NAMES.lto_backend", 108 "c++-link-executable": "ACTION_NAMES.cpp_link_executable", 109 "c++-link-dynamic-library": "ACTION_NAMES.cpp_link_dynamic_library", 110 "c++-link-nodeps-dynamic-library": "ACTION_NAMES.cpp_link_nodeps_dynamic_library", 111 "c++-link-static-library": "ACTION_NAMES.cpp_link_static_library", 112 "strip": "ACTION_NAMES.strip", 113 "objc-compile": "ACTION_NAMES.objc_compile", 114 "objc++-compile": "ACTION_NAMES.objcpp_compile", 115 "clif-match": "ACTION_NAMES.clif_match", 116// "objcopy_embed_data": "ACTION_NAMES.objcopy_embed_data", // copybara-comment-this-out-please 117// "ld_embed_data": "ACTION_NAMES.ld_embed_data", // copybara-comment-this-out-please 118} 119 120func getLoadActionsStmt() string { 121 return "load(\"@bazel_tools//tools/build_defs/cc:action_names.bzl\", \"ACTION_NAMES\")\n\n" 122} 123 124// Returns a map {toolchain_identifier : CToolchainIdentifier} 125func toolchainToCToolchainIdentifier( 126 crosstool *crosstoolpb.CrosstoolRelease) map[string]CToolchainIdentifier { 127 cpuToCompiler := make(map[string][]string) 128 compilerToCPU := make(map[string][]string) 129 var cpus []string 130 var compilers []string 131 var identifiers []string 132 res := make(map[string]CToolchainIdentifier) 133 for _, cToolchain := range crosstool.GetToolchain() { 134 cpu := cToolchain.GetTargetCpu() 135 compiler := cToolchain.GetCompiler() 136 137 cpuToCompiler[cpu] = append(cpuToCompiler[cpu], compiler) 138 compilerToCPU[compiler] = append(compilerToCPU[compiler], cpu) 139 140 cpus = append(cpus, cToolchain.GetTargetCpu()) 141 compilers = append(compilers, cToolchain.GetCompiler()) 142 identifiers = append(identifiers, cToolchain.GetToolchainIdentifier()) 143 } 144 145 for i := range cpus { 146 if len(cpuToCompiler[cpus[i]]) == 1 { 147 // if cpu is unique among CToolchains, we don't need the compiler field 148 res[identifiers[i]] = CToolchainIdentifier{cpu: cpus[i], compiler: ""} 149 } else { 150 res[identifiers[i]] = CToolchainIdentifier{ 151 cpu: cpus[i], 152 compiler: compilers[i], 153 } 154 } 155 } 156 return res 157} 158 159func getConditionStatementForCToolchainIdentifier(identifier CToolchainIdentifier) string { 160 if identifier.compiler != "" { 161 return fmt.Sprintf( 162 "ctx.attr.cpu == \"%s\" and ctx.attr.compiler == \"%s\"", 163 identifier.cpu, 164 identifier.compiler) 165 } 166 return fmt.Sprintf("ctx.attr.cpu == \"%s\"", identifier.cpu) 167} 168 169func isArrayPrefix(prefix []string, arr []string) bool { 170 if len(prefix) > len(arr) { 171 return false 172 } 173 for i := 0; i < len(prefix); i++ { 174 if arr[i] != prefix[i] { 175 return false 176 } 177 } 178 return true 179} 180 181func isAllCompileActions(actions []string) (bool, []string) { 182 if isArrayPrefix(allCompileActions, actions) { 183 return true, actions[len(allCompileActions):] 184 } 185 return false, actions 186} 187 188func isAllCppCompileActions(actions []string) (bool, []string) { 189 if isArrayPrefix(allCppCompileActions, actions) { 190 return true, actions[len(allCppCompileActions):] 191 } 192 return false, actions 193} 194 195func isPreprocessorCompileActions(actions []string) (bool, []string) { 196 if isArrayPrefix(preprocessorCompileActions, actions) { 197 return true, actions[len(preprocessorCompileActions):] 198 } 199 return false, actions 200} 201 202func isCodegenCompileActions(actions []string) (bool, []string) { 203 if isArrayPrefix(codegenCompileActions, actions) { 204 return true, actions[len(codegenCompileActions):] 205 } 206 return false, actions 207} 208 209func isAllLinkActions(actions []string) (bool, []string) { 210 if isArrayPrefix(allLinkActions, actions) { 211 return true, actions[len(allLinkActions):] 212 } 213 return false, actions 214} 215 216func getActionNames(actions []string) []string { 217 var res []string 218 for _, el := range actions { 219 if name, ok := actionNames[el]; ok { 220 res = append(res, name) 221 } else { 222 res = append(res, "\""+el+"\"") 223 } 224 } 225 return res 226} 227 228func getListOfActions(name string, depth int) string { 229 var res []string 230 if name == "all_compile_actions" { 231 res = getActionNames(allCompileActions) 232 } else if name == "all_cpp_compile_actions" { 233 res = getActionNames(allCppCompileActions) 234 } else if name == "preprocessor_compile_actions" { 235 res = getActionNames(preprocessorCompileActions) 236 } else if name == "codegen_compile_actions" { 237 res = getActionNames(codegenCompileActions) 238 } else if name == "all_link_actions" { 239 res = getActionNames(allLinkActions) 240 } 241 stmt := fmt.Sprintf("%s%s = %s\n\n", getTabs(depth), 242 name, makeStringArr(res, depth /* isPlainString= */, false)) 243 return stmt 244} 245 246func processActions(actions []string, depth int) []string { 247 var res []string 248 var ok bool 249 initLen := len(actions) 250 if ok, actions = isAllCompileActions(actions); ok { 251 res = append(res, "all_compile_actions") 252 } 253 if ok, actions = isAllCppCompileActions(actions); ok { 254 res = append(res, "all_cpp_compile_actions") 255 } 256 if ok, actions = isPreprocessorCompileActions(actions); ok { 257 res = append(res, "preprocessor_compile_actions") 258 } 259 if ok, actions = isCodegenCompileActions(actions); ok { 260 res = append(res, "codegen_actions") 261 } 262 if ok, actions = isAllLinkActions(actions); ok { 263 res = append(res, "all_link_actions") 264 } 265 if len(actions) != 0 { 266 actions = getActionNames(actions) 267 newDepth := depth + 1 268 if len(actions) != initLen { 269 newDepth++ 270 } 271 res = append(res, makeStringArr(actions, newDepth /* isPlainString= */, false)) 272 } 273 return res 274} 275 276func getUniqueValues(arr []string) []string { 277 valuesSet := make(map[string]bool) 278 for _, val := range arr { 279 valuesSet[val] = true 280 } 281 var uniques []string 282 for val, _ := range valuesSet { 283 uniques = append(uniques, val) 284 } 285 sort.Strings(uniques) 286 return uniques 287} 288 289func getRule(cToolchainIdentifiers map[string]CToolchainIdentifier, 290 allowedCompilers []string) string { 291 cpus := make(map[string]bool) 292 shouldUseCompilerAttribute := false 293 for _, val := range cToolchainIdentifiers { 294 cpus[val.cpu] = true 295 if val.compiler != "" { 296 shouldUseCompilerAttribute = true 297 } 298 } 299 300 var cpuValues []string 301 for cpu := range cpus { 302 cpuValues = append(cpuValues, cpu) 303 } 304 305 var args []string 306 sort.Strings(cpuValues) 307 args = append(args, 308 fmt.Sprintf( 309 `"cpu": attr.string(mandatory=True, values=["%s"]),`, 310 strings.Join(cpuValues, "\", \""))) 311 if shouldUseCompilerAttribute { 312 // If there are two CToolchains that share the cpu we need the compiler attribute 313 // for our cc_toolchain_config rule. 314 allowedCompilers = getUniqueValues(allowedCompilers) 315 args = append(args, 316 fmt.Sprintf(`"compiler": attr.string(mandatory=True, values=["%s"]),`, 317 strings.Join(allowedCompilers, "\", \""))) 318 } 319 return fmt.Sprintf(`cc_toolchain_config = rule( 320 implementation = _impl, 321 attrs = { 322 %s 323 }, 324 provides = [CcToolchainConfigInfo], 325 executable = True, 326) 327`, strings.Join(args, "\n ")) 328} 329 330func getImplHeader() string { 331 return "def _impl(ctx):\n" 332} 333 334func getStringStatement(crosstool *crosstoolpb.CrosstoolRelease, 335 cToolchainIdentifiers map[string]CToolchainIdentifier, field string, 336 depth int) string { 337 338 identifiers := getToolchainIdentifiers(crosstool) 339 var fieldValues []string 340 if field == "toolchain_identifier" { 341 fieldValues = getToolchainIdentifiers(crosstool) 342 } else if field == "host_system_name" { 343 fieldValues = getHostSystemNames(crosstool) 344 } else if field == "target_system_name" { 345 fieldValues = getTargetSystemNames(crosstool) 346 } else if field == "target_cpu" { 347 fieldValues = getTargetCpus(crosstool) 348 } else if field == "target_libc" { 349 fieldValues = getTargetLibcs(crosstool) 350 } else if field == "compiler" { 351 fieldValues = getCompilers(crosstool) 352 } else if field == "abi_version" { 353 fieldValues = getAbiVersions(crosstool) 354 } else if field == "abi_libc_version" { 355 fieldValues = getAbiLibcVersions(crosstool) 356 } else if field == "cc_target_os" { 357 fieldValues = getCcTargetOss(crosstool) 358 } else if field == "builtin_sysroot" { 359 fieldValues = getBuiltinSysroots(crosstool) 360 } 361 362 mappedValuesToIds := getMappedStringValuesToIdentifiers(identifiers, fieldValues) 363 return getAssignmentStatement(field, mappedValuesToIds, crosstool, 364 cToolchainIdentifiers, depth /* isPlainString= */, true /* shouldFail= */, true) 365} 366 367func getFeatures(crosstool *crosstoolpb.CrosstoolRelease) ( 368 map[string][]string, map[string]map[string][]string, error) { 369 featureNameToFeature := make(map[string]map[string][]string) 370 toolchainToFeatures := make(map[string][]string) 371 for _, toolchain := range crosstool.GetToolchain() { 372 id := toolchain.GetToolchainIdentifier() 373 if len(toolchain.GetFeature()) == 0 { 374 toolchainToFeatures[id] = []string{} 375 } 376 for _, feature := range toolchain.GetFeature() { 377 featureName := strings.ToLower(feature.GetName()) + "_feature" 378 featureName = strings.Replace(featureName, "+", "p", -1) 379 featureName = strings.Replace(featureName, ".", "_", -1) 380 featureName = strings.Replace(featureName, "-", "_", -1) 381 stringFeature, err := parseFeature(feature, 1) 382 if err != nil { 383 return nil, nil, fmt.Errorf( 384 "Error in feature '%s': %v", feature.GetName(), err) 385 } 386 if _, ok := featureNameToFeature[featureName]; !ok { 387 featureNameToFeature[featureName] = make(map[string][]string) 388 } 389 featureNameToFeature[featureName][stringFeature] = append( 390 featureNameToFeature[featureName][stringFeature], id) 391 toolchainToFeatures[id] = append(toolchainToFeatures[id], featureName) 392 } 393 } 394 return toolchainToFeatures, featureNameToFeature, nil 395} 396 397func getFeaturesDeclaration(crosstool *crosstoolpb.CrosstoolRelease, 398 cToolchainIdentifiers map[string]CToolchainIdentifier, 399 featureNameToFeature map[string]map[string][]string, depth int) string { 400 var res []string 401 for featureName, featureStringToID := range featureNameToFeature { 402 res = append(res, 403 getAssignmentStatement( 404 featureName, 405 featureStringToID, 406 crosstool, 407 cToolchainIdentifiers, 408 depth, 409 /* isPlainString= */ false, 410 /* shouldFail= */ false)) 411 } 412 return strings.Join(res, "") 413} 414 415func getFeaturesStmt(cToolchainIdentifiers map[string]CToolchainIdentifier, 416 toolchainToFeatures map[string][]string, depth int) string { 417 var res []string 418 arrToIdentifier := make(map[string][]string) 419 for id, features := range toolchainToFeatures { 420 arrayString := strings.Join(features, "{arrayFieldDelimiter}") 421 arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) 422 } 423 res = append(res, 424 getStringArrStatement( 425 "features", 426 arrToIdentifier, 427 cToolchainIdentifiers, 428 depth, 429 /* isPlainString= */ false)) 430 return strings.Join(res, "\n") 431} 432 433func getActions(crosstool *crosstoolpb.CrosstoolRelease) ( 434 map[string][]string, map[string]map[string][]string, error) { 435 actionNameToAction := make(map[string]map[string][]string) 436 toolchainToActions := make(map[string][]string) 437 for _, toolchain := range crosstool.GetToolchain() { 438 id := toolchain.GetToolchainIdentifier() 439 var actionName string 440 if len(toolchain.GetActionConfig()) == 0 { 441 toolchainToActions[id] = []string{} 442 } 443 for _, action := range toolchain.GetActionConfig() { 444 if aName, ok := actionNames[action.GetActionName()]; ok { 445 actionName = aName 446 } else { 447 actionName = strings.ToLower(action.GetActionName()) 448 actionName = strings.Replace(actionName, "+", "p", -1) 449 actionName = strings.Replace(actionName, ".", "_", -1) 450 actionName = strings.Replace(actionName, "-", "_", -1) 451 } 452 stringAction, err := parseAction(action, 1) 453 if err != nil { 454 return nil, nil, fmt.Errorf( 455 "Error in action_config '%s': %v", action.GetActionName(), err) 456 } 457 if _, ok := actionNameToAction[actionName]; !ok { 458 actionNameToAction[actionName] = make(map[string][]string) 459 } 460 actionNameToAction[actionName][stringAction] = append( 461 actionNameToAction[actionName][stringAction], id) 462 toolchainToActions[id] = append( 463 toolchainToActions[id], 464 strings.TrimPrefix(strings.ToLower(actionName), "action_names.")+"_action") 465 } 466 } 467 return toolchainToActions, actionNameToAction, nil 468} 469 470func getActionConfigsDeclaration( 471 crosstool *crosstoolpb.CrosstoolRelease, 472 cToolchainIdentifiers map[string]CToolchainIdentifier, 473 actionNameToAction map[string]map[string][]string, depth int) string { 474 var res []string 475 for actionName, actionStringToID := range actionNameToAction { 476 variableName := strings.TrimPrefix(strings.ToLower(actionName), "action_names.") + "_action" 477 res = append(res, 478 getAssignmentStatement( 479 variableName, 480 actionStringToID, 481 crosstool, 482 cToolchainIdentifiers, 483 depth, 484 /* isPlainString= */ false, 485 /* shouldFail= */ false)) 486 } 487 return strings.Join(res, "") 488} 489 490func getActionConfigsStmt( 491 cToolchainIdentifiers map[string]CToolchainIdentifier, 492 toolchainToActions map[string][]string, depth int) string { 493 var res []string 494 arrToIdentifier := make(map[string][]string) 495 for id, actions := range toolchainToActions { 496 var arrayString string 497 arrayString = strings.Join(actions, "{arrayFieldDelimiter}") 498 arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) 499 } 500 res = append(res, 501 getStringArrStatement( 502 "action_configs", 503 arrToIdentifier, 504 cToolchainIdentifiers, 505 depth, 506 /* isPlainString= */ false)) 507 return strings.Join(res, "\n") 508} 509 510func parseAction(action *crosstoolpb.CToolchain_ActionConfig, depth int) (string, error) { 511 actionName := action.GetActionName() 512 aName := "" 513 if val, ok := actionNames[actionName]; ok { 514 aName = val 515 } else { 516 aName = "\"" + action.GetActionName() + "\"" 517 } 518 name := fmt.Sprintf("action_name = %s", aName) 519 fields := []string{name} 520 if action.GetEnabled() { 521 fields = append(fields, "enabled = True") 522 } 523 if len(action.GetFlagSet()) != 0 { 524 flagSets, err := parseFlagSets(action.GetFlagSet(), depth+1) 525 if err != nil { 526 return "", err 527 } 528 fields = append(fields, "flag_sets = "+flagSets) 529 } 530 if len(action.GetImplies()) != 0 { 531 implies := "implies = " + 532 makeStringArr(action.GetImplies(), depth+1 /* isPlainString= */, true) 533 fields = append(fields, implies) 534 } 535 if len(action.GetTool()) != 0 { 536 tools := "tools = " + parseTools(action.GetTool(), depth+1) 537 fields = append(fields, tools) 538 } 539 return createObject("action_config", fields, depth), nil 540} 541 542func getStringArrStatement(attr string, arrValToIds map[string][]string, 543 cToolchainIdentifiers map[string]CToolchainIdentifier, depth int, plainString bool) string { 544 var b bytes.Buffer 545 if len(arrValToIds) == 0 { 546 b.WriteString(fmt.Sprintf("%s%s = []\n", getTabs(depth), attr)) 547 } else if len(arrValToIds) == 1 { 548 for value := range arrValToIds { 549 var arr []string 550 if value == "" { 551 arr = []string{} 552 } else if value == "None" { 553 b.WriteString(fmt.Sprintf("%s%s = None\n", getTabs(depth), attr)) 554 break 555 } else { 556 arr = strings.Split(value, "{arrayFieldDelimiter}") 557 } 558 b.WriteString( 559 fmt.Sprintf( 560 "%s%s = %s\n", 561 getTabs(depth), 562 attr, 563 makeStringArr(arr, depth+1, plainString))) 564 break 565 } 566 } else { 567 first := true 568 var keys []string 569 for k := range arrValToIds { 570 keys = append(keys, k) 571 } 572 sort.Strings(keys) 573 for _, value := range keys { 574 ids := arrValToIds[value] 575 branch := "elif" 576 if first { 577 branch = "if" 578 } 579 first = false 580 var arr []string 581 if value == "" { 582 arr = []string{} 583 } else if value == "None" { 584 b.WriteString( 585 getIfStatement( 586 branch, ids, attr, "None", cToolchainIdentifiers, 587 depth /* isPlainString= */, true)) 588 continue 589 } else { 590 arr = strings.Split(value, "{arrayFieldDelimiter}") 591 } 592 b.WriteString( 593 getIfStatement(branch, ids, attr, 594 makeStringArr(arr, depth+1, plainString), 595 cToolchainIdentifiers, depth /* isPlainString= */, false)) 596 } 597 b.WriteString(fmt.Sprintf("%selse:\n%sfail(\"Unreachable\")\n", getTabs(depth), getTabs(depth+1))) 598 } 599 b.WriteString("\n") 600 return b.String() 601} 602 603func getStringArr(crosstool *crosstoolpb.CrosstoolRelease, 604 cToolchainIdentifiers map[string]CToolchainIdentifier, attr string, depth int) string { 605 var res []string 606 arrToIdentifier := make(map[string][]string) 607 for _, toolchain := range crosstool.GetToolchain() { 608 id := toolchain.GetToolchainIdentifier() 609 arrayString := strings.Join(getArrField(attr, toolchain), "{arrayFieldDelimiter}") 610 arrToIdentifier[arrayString] = append(arrToIdentifier[arrayString], id) 611 } 612 statement := getStringArrStatement(attr, arrToIdentifier, cToolchainIdentifiers, depth /* isPlainString= */, true) 613 res = append(res, statement) 614 return strings.Join(res, "\n") 615} 616 617func getArrField(attr string, toolchain *crosstoolpb.CToolchain) []string { 618 var arr []string 619 if attr == "cxx_builtin_include_directories" { 620 arr = toolchain.GetCxxBuiltinIncludeDirectory() 621 } 622 return arr 623} 624 625func getTabs(depth int) string { 626 var res string 627 for i := 0; i < depth; i++ { 628 res = res + " " 629 } 630 return res 631} 632 633func createObject(objtype string, fields []string, depth int) string { 634 if len(fields) == 0 { 635 return objtype + "()" 636 } 637 singleLine := objtype + "(" + strings.Join(fields, ", ") + ")" 638 if len(singleLine) < 60 { 639 return singleLine 640 } 641 return objtype + 642 "(\n" + 643 getTabs(depth+1) + 644 strings.Join(fields, ",\n"+getTabs(depth+1)) + 645 ",\n" + getTabs(depth) + 646 ")" 647} 648 649func getArtifactNamePatterns(crosstool *crosstoolpb.CrosstoolRelease, 650 cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { 651 var res []string 652 artifactToIds := make(map[string][]string) 653 for _, toolchain := range crosstool.GetToolchain() { 654 artifactNamePatterns := parseArtifactNamePatterns( 655 toolchain.GetArtifactNamePattern(), 656 depth) 657 artifactToIds[artifactNamePatterns] = append( 658 artifactToIds[artifactNamePatterns], 659 toolchain.GetToolchainIdentifier()) 660 } 661 res = append(res, 662 getAssignmentStatement( 663 "artifact_name_patterns", 664 artifactToIds, 665 crosstool, 666 cToolchainIdentifiers, 667 depth, 668 /* isPlainString= */ false, 669 /* shouldFail= */ true)) 670 return strings.Join(res, "\n") 671} 672 673func parseArtifactNamePatterns( 674 artifactNamePatterns []*crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string { 675 var res []string 676 for _, pattern := range artifactNamePatterns { 677 res = append(res, parseArtifactNamePattern(pattern, depth+1)) 678 } 679 return makeStringArr(res, depth /* isPlainString= */, false) 680} 681 682func parseArtifactNamePattern( 683 artifactNamePattern *crosstoolpb.CToolchain_ArtifactNamePattern, depth int) string { 684 categoryName := fmt.Sprintf("category_name = \"%s\"", artifactNamePattern.GetCategoryName()) 685 prefix := fmt.Sprintf("prefix = \"%s\"", artifactNamePattern.GetPrefix()) 686 extension := fmt.Sprintf("extension = \"%s\"", artifactNamePattern.GetExtension()) 687 fields := []string{categoryName, prefix, extension} 688 return createObject("artifact_name_pattern", fields, depth) 689} 690 691func parseFeature(feature *crosstoolpb.CToolchain_Feature, depth int) (string, error) { 692 name := fmt.Sprintf("name = \"%s\"", feature.GetName()) 693 694 fields := []string{name} 695 if feature.GetEnabled() { 696 fields = append(fields, "enabled = True") 697 } 698 699 if len(feature.GetFlagSet()) > 0 { 700 flagSets, err := parseFlagSets(feature.GetFlagSet(), depth+1) 701 if err != nil { 702 return "", err 703 } 704 fields = append(fields, "flag_sets = "+flagSets) 705 } 706 if len(feature.GetEnvSet()) > 0 { 707 envSets := "env_sets = " + parseEnvSets(feature.GetEnvSet(), depth+1) 708 fields = append(fields, envSets) 709 } 710 if len(feature.GetRequires()) > 0 { 711 requires := "requires = " + parseFeatureSets(feature.GetRequires(), depth+1) 712 fields = append(fields, requires) 713 } 714 if len(feature.GetImplies()) > 0 { 715 implies := "implies = " + 716 makeStringArr(feature.GetImplies(), depth+1 /* isPlainString= */, true) 717 fields = append(fields, implies) 718 } 719 if len(feature.GetProvides()) > 0 { 720 provides := "provides = " + 721 makeStringArr(feature.GetProvides(), depth+1 /* isPlainString= */, true) 722 fields = append(fields, provides) 723 } 724 return createObject("feature", fields, depth), nil 725} 726 727func parseFlagSets(flagSets []*crosstoolpb.CToolchain_FlagSet, depth int) (string, error) { 728 var res []string 729 for _, flagSet := range flagSets { 730 parsedFlagset, err := parseFlagSet(flagSet, depth+1) 731 if err != nil { 732 return "", err 733 } 734 res = append(res, parsedFlagset) 735 } 736 return makeStringArr(res, depth /* isPlainString= */, false), nil 737} 738 739func parseFlagSet(flagSet *crosstoolpb.CToolchain_FlagSet, depth int) (string, error) { 740 var fields []string 741 if len(flagSet.GetAction()) > 0 { 742 actionArr := processActions(flagSet.GetAction(), depth) 743 actions := "actions = " + strings.Join(actionArr, " +\n"+getTabs(depth+2)) 744 fields = append(fields, actions) 745 } 746 if len(flagSet.GetFlagGroup()) > 0 { 747 flagGroups, err := parseFlagGroups(flagSet.GetFlagGroup(), depth+1) 748 if err != nil { 749 return "", err 750 } 751 fields = append(fields, "flag_groups = "+flagGroups) 752 } 753 if len(flagSet.GetWithFeature()) > 0 { 754 withFeatures := "with_features = " + 755 parseWithFeatureSets(flagSet.GetWithFeature(), depth+1) 756 fields = append(fields, withFeatures) 757 } 758 return createObject("flag_set", fields, depth), nil 759} 760 761func parseFlagGroups(flagGroups []*crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) { 762 var res []string 763 for _, flagGroup := range flagGroups { 764 flagGroupString, err := parseFlagGroup(flagGroup, depth+1) 765 if err != nil { 766 return "", err 767 } 768 res = append(res, flagGroupString) 769 } 770 return makeStringArr(res, depth /* isPlainString= */, false), nil 771} 772 773func parseFlagGroup(flagGroup *crosstoolpb.CToolchain_FlagGroup, depth int) (string, error) { 774 var res []string 775 if len(flagGroup.GetFlag()) != 0 { 776 res = append(res, "flags = "+makeStringArr(flagGroup.GetFlag(), depth+1, true)) 777 } 778 if flagGroup.GetIterateOver() != "" { 779 res = append(res, fmt.Sprintf("iterate_over = \"%s\"", flagGroup.GetIterateOver())) 780 } 781 if len(flagGroup.GetFlagGroup()) != 0 { 782 flagGroupString, err := parseFlagGroups(flagGroup.GetFlagGroup(), depth+1) 783 if err != nil { 784 return "", err 785 } 786 res = append(res, "flag_groups = "+flagGroupString) 787 } 788 if len(flagGroup.GetExpandIfAllAvailable()) > 1 { 789 return "", errors.New("Flag group must not have more than one 'expand_if_all_available' field") 790 } 791 if len(flagGroup.GetExpandIfAllAvailable()) != 0 { 792 res = append(res, 793 fmt.Sprintf( 794 "expand_if_available = \"%s\"", 795 flagGroup.GetExpandIfAllAvailable()[0])) 796 } 797 if len(flagGroup.GetExpandIfNoneAvailable()) > 1 { 798 return "", errors.New("Flag group must not have more than one 'expand_if_none_available' field") 799 } 800 if len(flagGroup.GetExpandIfNoneAvailable()) != 0 { 801 res = append(res, 802 fmt.Sprintf( 803 "expand_if_not_available = \"%s\"", 804 flagGroup.GetExpandIfNoneAvailable()[0])) 805 } 806 if flagGroup.GetExpandIfTrue() != "" { 807 res = append(res, fmt.Sprintf("expand_if_true = \"%s\"", 808 flagGroup.GetExpandIfTrue())) 809 } 810 if flagGroup.GetExpandIfFalse() != "" { 811 res = append(res, fmt.Sprintf("expand_if_false = \"%s\"", 812 flagGroup.GetExpandIfFalse())) 813 } 814 if flagGroup.GetExpandIfEqual() != nil { 815 res = append(res, 816 "expand_if_equal = "+parseVariableWithValue( 817 flagGroup.GetExpandIfEqual(), depth+1)) 818 } 819 return createObject("flag_group", res, depth), nil 820} 821 822func parseVariableWithValue(variable *crosstoolpb.CToolchain_VariableWithValue, depth int) string { 823 variableName := fmt.Sprintf("name = \"%s\"", variable.GetVariable()) 824 value := fmt.Sprintf("value = \"%s\"", variable.GetValue()) 825 return createObject("variable_with_value", []string{variableName, value}, depth) 826} 827 828func getToolPaths(crosstool *crosstoolpb.CrosstoolRelease, 829 cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { 830 var res []string 831 toolPathsToIds := make(map[string][]string) 832 for _, toolchain := range crosstool.GetToolchain() { 833 toolPaths := parseToolPaths(toolchain.GetToolPath(), depth) 834 toolPathsToIds[toolPaths] = append( 835 toolPathsToIds[toolPaths], 836 toolchain.GetToolchainIdentifier()) 837 } 838 res = append(res, 839 getAssignmentStatement( 840 "tool_paths", 841 toolPathsToIds, 842 crosstool, 843 cToolchainIdentifiers, 844 depth, 845 /* isPlainString= */ false, 846 /* shouldFail= */ true)) 847 return strings.Join(res, "\n") 848} 849 850func parseToolPaths(toolPaths []*crosstoolpb.ToolPath, depth int) string { 851 var res []string 852 for _, toolPath := range toolPaths { 853 res = append(res, parseToolPath(toolPath, depth+1)) 854 } 855 return makeStringArr(res, depth /* isPlainString= */, false) 856} 857 858func parseToolPath(toolPath *crosstoolpb.ToolPath, depth int) string { 859 name := fmt.Sprintf("name = \"%s\"", toolPath.GetName()) 860 path := toolPath.GetPath() 861 if path == "" { 862 path = "NOT_USED" 863 } 864 path = fmt.Sprintf("path = \"%s\"", path) 865 return createObject("tool_path", []string{name, path}, depth) 866} 867 868func getMakeVariables(crosstool *crosstoolpb.CrosstoolRelease, 869 cToolchainIdentifiers map[string]CToolchainIdentifier, depth int) string { 870 var res []string 871 makeVariablesToIds := make(map[string][]string) 872 for _, toolchain := range crosstool.GetToolchain() { 873 makeVariables := parseMakeVariables(toolchain.GetMakeVariable(), depth) 874 makeVariablesToIds[makeVariables] = append( 875 makeVariablesToIds[makeVariables], 876 toolchain.GetToolchainIdentifier()) 877 } 878 res = append(res, 879 getAssignmentStatement( 880 "make_variables", 881 makeVariablesToIds, 882 crosstool, 883 cToolchainIdentifiers, 884 depth, 885 /* isPlainString= */ false, 886 /* shouldFail= */ true)) 887 return strings.Join(res, "\n") 888} 889 890func parseMakeVariables(makeVariables []*crosstoolpb.MakeVariable, depth int) string { 891 var res []string 892 for _, makeVariable := range makeVariables { 893 res = append(res, parseMakeVariable(makeVariable, depth+1)) 894 } 895 return makeStringArr(res, depth /* isPlainString= */, false) 896} 897 898func parseMakeVariable(makeVariable *crosstoolpb.MakeVariable, depth int) string { 899 name := fmt.Sprintf("name = \"%s\"", makeVariable.GetName()) 900 value := fmt.Sprintf("value = \"%s\"", makeVariable.GetValue()) 901 return createObject("make_variable", []string{name, value}, depth) 902} 903 904func parseTools(tools []*crosstoolpb.CToolchain_Tool, depth int) string { 905 var res []string 906 for _, tool := range tools { 907 res = append(res, parseTool(tool, depth+1)) 908 } 909 return makeStringArr(res, depth /* isPlainString= */, false) 910} 911 912func parseTool(tool *crosstoolpb.CToolchain_Tool, depth int) string { 913 toolPath := "path = \"NOT_USED\"" 914 if tool.GetToolPath() != "" { 915 toolPath = fmt.Sprintf("path = \"%s\"", tool.GetToolPath()) 916 } 917 fields := []string{toolPath} 918 if len(tool.GetWithFeature()) != 0 { 919 withFeatures := "with_features = " + parseWithFeatureSets(tool.GetWithFeature(), depth+1) 920 fields = append(fields, withFeatures) 921 } 922 if len(tool.GetExecutionRequirement()) != 0 { 923 executionRequirements := "execution_requirements = " + 924 makeStringArr(tool.GetExecutionRequirement(), depth+1 /* isPlainString= */, true) 925 fields = append(fields, executionRequirements) 926 } 927 return createObject("tool", fields, depth) 928} 929 930func parseEnvEntries(envEntries []*crosstoolpb.CToolchain_EnvEntry, depth int) string { 931 var res []string 932 for _, envEntry := range envEntries { 933 res = append(res, parseEnvEntry(envEntry, depth+1)) 934 } 935 return makeStringArr(res, depth /* isPlainString= */, false) 936} 937 938func parseEnvEntry(envEntry *crosstoolpb.CToolchain_EnvEntry, depth int) string { 939 key := fmt.Sprintf("key = \"%s\"", envEntry.GetKey()) 940 value := fmt.Sprintf("value = \"%s\"", envEntry.GetValue()) 941 return createObject("env_entry", []string{key, value}, depth) 942} 943 944func parseWithFeatureSets(withFeatureSets []*crosstoolpb.CToolchain_WithFeatureSet, 945 depth int) string { 946 var res []string 947 for _, withFeature := range withFeatureSets { 948 res = append(res, parseWithFeatureSet(withFeature, depth+1)) 949 } 950 return makeStringArr(res, depth /* isPlainString= */, false) 951} 952 953func parseWithFeatureSet(withFeature *crosstoolpb.CToolchain_WithFeatureSet, 954 depth int) string { 955 var fields []string 956 if len(withFeature.GetFeature()) != 0 { 957 features := "features = " + 958 makeStringArr(withFeature.GetFeature(), depth+1 /* isPlainString= */, true) 959 fields = append(fields, features) 960 } 961 if len(withFeature.GetNotFeature()) != 0 { 962 notFeatures := "not_features = " + 963 makeStringArr(withFeature.GetNotFeature(), depth+1 /* isPlainString= */, true) 964 fields = append(fields, notFeatures) 965 } 966 return createObject("with_feature_set", fields, depth) 967} 968 969func parseEnvSets(envSets []*crosstoolpb.CToolchain_EnvSet, depth int) string { 970 var res []string 971 for _, envSet := range envSets { 972 envSetString := parseEnvSet(envSet, depth+1) 973 res = append(res, envSetString) 974 } 975 return makeStringArr(res, depth /* isPlainString= */, false) 976} 977 978func parseEnvSet(envSet *crosstoolpb.CToolchain_EnvSet, depth int) string { 979 actionsStatement := processActions(envSet.GetAction(), depth) 980 actions := "actions = " + strings.Join(actionsStatement, " +\n"+getTabs(depth+2)) 981 fields := []string{actions} 982 if len(envSet.GetEnvEntry()) != 0 { 983 envEntries := "env_entries = " + parseEnvEntries(envSet.GetEnvEntry(), depth+1) 984 fields = append(fields, envEntries) 985 } 986 if len(envSet.GetWithFeature()) != 0 { 987 withFeatures := "with_features = " + parseWithFeatureSets(envSet.GetWithFeature(), depth+1) 988 fields = append(fields, withFeatures) 989 } 990 return createObject("env_set", fields, depth) 991} 992 993func parseFeatureSets(featureSets []*crosstoolpb.CToolchain_FeatureSet, depth int) string { 994 var res []string 995 for _, featureSet := range featureSets { 996 res = append(res, parseFeatureSet(featureSet, depth+1)) 997 } 998 return makeStringArr(res, depth /* isPlainString= */, false) 999} 1000 1001func parseFeatureSet(featureSet *crosstoolpb.CToolchain_FeatureSet, depth int) string { 1002 features := "features = " + 1003 makeStringArr(featureSet.GetFeature(), depth+1 /* isPlainString= */, true) 1004 return createObject("feature_set", []string{features}, depth) 1005} 1006 1007// Takes in a list of string elements and returns a string that represents 1008// an array : 1009// [ 1010// "element1", 1011// "element2", 1012// ] 1013// The isPlainString argument tells us whether the input elements should be 1014// treated as string (eg, flags), or not (eg, variable names) 1015func makeStringArr(arr []string, depth int, isPlainString bool) string { 1016 if len(arr) == 0 { 1017 return "[]" 1018 } 1019 var escapedArr []string 1020 for _, el := range arr { 1021 if isPlainString { 1022 escapedArr = append(escapedArr, strings.Replace(el, "\"", "\\\"", -1)) 1023 } else { 1024 escapedArr = append(escapedArr, el) 1025 } 1026 } 1027 addQuote := "" 1028 if isPlainString { 1029 addQuote = "\"" 1030 } 1031 singleLine := "[" + addQuote + strings.Join(escapedArr, addQuote+", "+addQuote) + addQuote + "]" 1032 if len(singleLine) < 60 { 1033 return singleLine 1034 } 1035 return "[\n" + 1036 getTabs(depth+1) + 1037 addQuote + 1038 strings.Join(escapedArr, addQuote+",\n"+getTabs(depth+1)+addQuote) + 1039 addQuote + 1040 ",\n" + 1041 getTabs(depth) + 1042 "]" 1043} 1044 1045// Returns a string that represents a value assignment 1046// (eg if ctx.attr.cpu == "linux": 1047// compiler = "llvm" 1048// elif ctx.attr.cpu == "windows": 1049// compiler = "mingw" 1050// else: 1051// fail("Unreachable") 1052func getAssignmentStatement(field string, valToIds map[string][]string, 1053 crosstool *crosstoolpb.CrosstoolRelease, 1054 toCToolchainIdentifier map[string]CToolchainIdentifier, 1055 depth int, isPlainString, shouldFail bool) string { 1056 var b bytes.Buffer 1057 if len(valToIds) <= 1 { 1058 // if there is only one possible value for this field, we don't need if statements 1059 for val := range valToIds { 1060 if val != "None" && isPlainString { 1061 val = "\"" + val + "\"" 1062 } 1063 b.WriteString(fmt.Sprintf("%s%s = %s\n", getTabs(depth), field, val)) 1064 break 1065 } 1066 } else { 1067 first := true 1068 var keys []string 1069 for k := range valToIds { 1070 keys = append(keys, k) 1071 } 1072 sort.Strings(keys) 1073 for _, value := range keys { 1074 ids := valToIds[value] 1075 branch := "elif" 1076 if first { 1077 branch = "if" 1078 } 1079 b.WriteString( 1080 getIfStatement(branch, ids, field, value, 1081 toCToolchainIdentifier, depth, isPlainString)) 1082 first = false 1083 } 1084 if shouldFail { 1085 b.WriteString( 1086 fmt.Sprintf( 1087 "%selse:\n%sfail(\"Unreachable\")\n", 1088 getTabs(depth), getTabs(depth+1))) 1089 } else { 1090 b.WriteString( 1091 fmt.Sprintf( 1092 "%selse:\n%s%s = None\n", 1093 getTabs(depth), getTabs(depth+1), field)) 1094 } 1095 } 1096 b.WriteString("\n") 1097 return b.String() 1098} 1099 1100func getCPUToCompilers(identifiers []CToolchainIdentifier) map[string][]string { 1101 res := make(map[string][]string) 1102 for _, identifier := range identifiers { 1103 if identifier.compiler != "" { 1104 res[identifier.cpu] = append(res[identifier.cpu], identifier.compiler) 1105 } 1106 } 1107 return res 1108} 1109 1110func getIfStatement(ifOrElseIf string, identifiers []string, field, val string, 1111 toCToolchainIdentifier map[string]CToolchainIdentifier, depth int, 1112 isPlainString bool) string { 1113 usedStmts := make(map[string]bool) 1114 if val != "None" && isPlainString { 1115 val = "\"" + val + "\"" 1116 } 1117 var cToolchainIdentifiers []CToolchainIdentifier 1118 for _, value := range toCToolchainIdentifier { 1119 cToolchainIdentifiers = append(cToolchainIdentifiers, value) 1120 } 1121 cpuToCompilers := getCPUToCompilers(cToolchainIdentifiers) 1122 countCpus := make(map[string]int) 1123 var conditions []string 1124 for _, id := range identifiers { 1125 identifier := toCToolchainIdentifier[id] 1126 stmt := getConditionStatementForCToolchainIdentifier(identifier) 1127 if _, ok := usedStmts[stmt]; !ok { 1128 conditions = append(conditions, stmt) 1129 usedStmts[stmt] = true 1130 if identifier.compiler != "" { 1131 countCpus[identifier.cpu]++ 1132 } 1133 } 1134 } 1135 1136 var compressedConditions []string 1137 usedStmtsOptimized := make(map[string]bool) 1138 for _, id := range identifiers { 1139 identifier := toCToolchainIdentifier[id] 1140 var stmt string 1141 if _, ok := countCpus[identifier.cpu]; ok { 1142 if countCpus[identifier.cpu] == len(cpuToCompilers[identifier.cpu]) { 1143 stmt = getConditionStatementForCToolchainIdentifier( 1144 CToolchainIdentifier{cpu: identifier.cpu, compiler: ""}) 1145 } else { 1146 stmt = getConditionStatementForCToolchainIdentifier(identifier) 1147 } 1148 } else { 1149 stmt = getConditionStatementForCToolchainIdentifier(identifier) 1150 } 1151 if _, ok := usedStmtsOptimized[stmt]; !ok { 1152 compressedConditions = append(compressedConditions, stmt) 1153 usedStmtsOptimized[stmt] = true 1154 } 1155 } 1156 1157 sort.Strings(compressedConditions) 1158 val = strings.Join(strings.Split(val, "\n"+getTabs(depth)), "\n"+getTabs(depth+1)) 1159 return fmt.Sprintf(`%s%s %s: 1160%s%s = %s 1161`, getTabs(depth), 1162 ifOrElseIf, 1163 "("+strings.Join(compressedConditions, "\n"+getTabs(depth+1)+"or ")+")", 1164 getTabs(depth+1), 1165 field, 1166 val) 1167} 1168 1169func getToolchainIdentifiers(crosstool *crosstoolpb.CrosstoolRelease) []string { 1170 var res []string 1171 for _, toolchain := range crosstool.GetToolchain() { 1172 res = append(res, toolchain.GetToolchainIdentifier()) 1173 } 1174 return res 1175} 1176 1177func getHostSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string { 1178 var res []string 1179 for _, toolchain := range crosstool.GetToolchain() { 1180 res = append(res, toolchain.GetHostSystemName()) 1181 } 1182 return res 1183} 1184 1185func getTargetSystemNames(crosstool *crosstoolpb.CrosstoolRelease) []string { 1186 var res []string 1187 for _, toolchain := range crosstool.GetToolchain() { 1188 res = append(res, toolchain.GetTargetSystemName()) 1189 } 1190 return res 1191} 1192 1193func getTargetCpus(crosstool *crosstoolpb.CrosstoolRelease) []string { 1194 var res []string 1195 for _, toolchain := range crosstool.GetToolchain() { 1196 res = append(res, toolchain.GetTargetCpu()) 1197 } 1198 return res 1199} 1200 1201func getTargetLibcs(crosstool *crosstoolpb.CrosstoolRelease) []string { 1202 var res []string 1203 for _, toolchain := range crosstool.GetToolchain() { 1204 res = append(res, toolchain.GetTargetLibc()) 1205 } 1206 return res 1207} 1208 1209func getCompilers(crosstool *crosstoolpb.CrosstoolRelease) []string { 1210 var res []string 1211 for _, toolchain := range crosstool.GetToolchain() { 1212 res = append(res, toolchain.GetCompiler()) 1213 } 1214 return res 1215} 1216 1217func getAbiVersions(crosstool *crosstoolpb.CrosstoolRelease) []string { 1218 var res []string 1219 for _, toolchain := range crosstool.GetToolchain() { 1220 res = append(res, toolchain.GetAbiVersion()) 1221 } 1222 return res 1223} 1224 1225func getAbiLibcVersions(crosstool *crosstoolpb.CrosstoolRelease) []string { 1226 var res []string 1227 for _, toolchain := range crosstool.GetToolchain() { 1228 res = append(res, toolchain.GetAbiLibcVersion()) 1229 } 1230 return res 1231} 1232 1233func getCcTargetOss(crosstool *crosstoolpb.CrosstoolRelease) []string { 1234 var res []string 1235 for _, toolchain := range crosstool.GetToolchain() { 1236 targetOS := "None" 1237 if toolchain.GetCcTargetOs() != "" { 1238 targetOS = toolchain.GetCcTargetOs() 1239 } 1240 res = append(res, targetOS) 1241 } 1242 return res 1243} 1244 1245func getBuiltinSysroots(crosstool *crosstoolpb.CrosstoolRelease) []string { 1246 var res []string 1247 for _, toolchain := range crosstool.GetToolchain() { 1248 sysroot := "None" 1249 if toolchain.GetBuiltinSysroot() != "" { 1250 sysroot = toolchain.GetBuiltinSysroot() 1251 } 1252 res = append(res, sysroot) 1253 } 1254 return res 1255} 1256 1257func getMappedStringValuesToIdentifiers(identifiers, fields []string) map[string][]string { 1258 res := make(map[string][]string) 1259 for i := range identifiers { 1260 res[fields[i]] = append(res[fields[i]], identifiers[i]) 1261 } 1262 return res 1263} 1264 1265func getReturnStatement() string { 1266 return ` 1267 out = ctx.actions.declare_file(ctx.label.name) 1268 ctx.actions.write(out, "Fake executable") 1269 return [ 1270 cc_common.create_cc_toolchain_config_info( 1271 ctx = ctx, 1272 features = features, 1273 action_configs = action_configs, 1274 artifact_name_patterns = artifact_name_patterns, 1275 cxx_builtin_include_directories = cxx_builtin_include_directories, 1276 toolchain_identifier = toolchain_identifier, 1277 host_system_name = host_system_name, 1278 target_system_name = target_system_name, 1279 target_cpu = target_cpu, 1280 target_libc = target_libc, 1281 compiler = compiler, 1282 abi_version = abi_version, 1283 abi_libc_version = abi_libc_version, 1284 tool_paths = tool_paths, 1285 make_variables = make_variables, 1286 builtin_sysroot = builtin_sysroot, 1287 cc_target_os = cc_target_os 1288 ), 1289 DefaultInfo( 1290 executable = out, 1291 ), 1292 ] 1293` 1294} 1295 1296// Transform writes a cc_toolchain_config rule functionally equivalent to the 1297// CROSSTOOL file. 1298func Transform(crosstool *crosstoolpb.CrosstoolRelease) (string, error) { 1299 var b bytes.Buffer 1300 1301 cToolchainIdentifiers := toolchainToCToolchainIdentifier(crosstool) 1302 1303 toolchainToFeatures, featureNameToFeature, err := getFeatures(crosstool) 1304 if err != nil { 1305 return "", err 1306 } 1307 1308 toolchainToActions, actionNameToAction, err := getActions(crosstool) 1309 if err != nil { 1310 return "", err 1311 } 1312 1313 header := getCcToolchainConfigHeader() 1314 if _, err := b.WriteString(header); err != nil { 1315 return "", err 1316 } 1317 1318 loadActionsStmt := getLoadActionsStmt() 1319 if _, err := b.WriteString(loadActionsStmt); err != nil { 1320 return "", err 1321 } 1322 1323 implHeader := getImplHeader() 1324 if _, err := b.WriteString(implHeader); err != nil { 1325 return "", err 1326 } 1327 1328 stringFields := []string{ 1329 "toolchain_identifier", 1330 "host_system_name", 1331 "target_system_name", 1332 "target_cpu", 1333 "target_libc", 1334 "compiler", 1335 "abi_version", 1336 "abi_libc_version", 1337 "cc_target_os", 1338 "builtin_sysroot", 1339 } 1340 1341 for _, stringField := range stringFields { 1342 stmt := getStringStatement(crosstool, cToolchainIdentifiers, stringField, 1) 1343 if _, err := b.WriteString(stmt); err != nil { 1344 return "", err 1345 } 1346 } 1347 1348 listsOfActions := []string{ 1349 "all_compile_actions", 1350 "all_cpp_compile_actions", 1351 "preprocessor_compile_actions", 1352 "codegen_compile_actions", 1353 "all_link_actions", 1354 } 1355 1356 for _, listOfActions := range listsOfActions { 1357 actions := getListOfActions(listOfActions, 1) 1358 if _, err := b.WriteString(actions); err != nil { 1359 return "", err 1360 } 1361 } 1362 1363 actionConfigDeclaration := getActionConfigsDeclaration( 1364 crosstool, cToolchainIdentifiers, actionNameToAction, 1) 1365 if _, err := b.WriteString(actionConfigDeclaration); err != nil { 1366 return "", err 1367 } 1368 1369 actionConfigStatement := getActionConfigsStmt( 1370 cToolchainIdentifiers, toolchainToActions, 1) 1371 if _, err := b.WriteString(actionConfigStatement); err != nil { 1372 return "", err 1373 } 1374 1375 featureDeclaration := getFeaturesDeclaration( 1376 crosstool, cToolchainIdentifiers, featureNameToFeature, 1) 1377 if _, err := b.WriteString(featureDeclaration); err != nil { 1378 return "", err 1379 } 1380 1381 featuresStatement := getFeaturesStmt( 1382 cToolchainIdentifiers, toolchainToFeatures, 1) 1383 if _, err := b.WriteString(featuresStatement); err != nil { 1384 return "", err 1385 } 1386 1387 includeDirectories := getStringArr( 1388 crosstool, cToolchainIdentifiers, "cxx_builtin_include_directories", 1) 1389 if _, err := b.WriteString(includeDirectories); err != nil { 1390 return "", err 1391 } 1392 1393 artifactNamePatterns := getArtifactNamePatterns( 1394 crosstool, cToolchainIdentifiers, 1) 1395 if _, err := b.WriteString(artifactNamePatterns); err != nil { 1396 return "", err 1397 } 1398 1399 makeVariables := getMakeVariables(crosstool, cToolchainIdentifiers, 1) 1400 if _, err := b.WriteString(makeVariables); err != nil { 1401 return "", err 1402 } 1403 1404 toolPaths := getToolPaths(crosstool, cToolchainIdentifiers, 1) 1405 if _, err := b.WriteString(toolPaths); err != nil { 1406 return "", err 1407 } 1408 1409 if _, err := b.WriteString(getReturnStatement()); err != nil { 1410 return "", err 1411 } 1412 1413 rule := getRule(cToolchainIdentifiers, getCompilers(crosstool)) 1414 if _, err := b.WriteString(rule); err != nil { 1415 return "", err 1416 } 1417 1418 return b.String(), nil 1419} 1420