mirror of
https://github.com/bazelbuild/rules_cc
synced 2024-11-30 22:41:22 +00:00
2312d72134
When cpu value is not enough to distinguish between two toolchains, we use the compiler value. In that case, the user needs to specify the compiler value for all cc_toolchain_config rules, even for the ones with unique cpu. This cl fixes the allowed values in the compiler attribute to account for the values from unique toolchains. Issue #5380 RELNOTES: None. PiperOrigin-RevId: 239396228
1420 lines
43 KiB
Go
1420 lines
43 KiB
Go
/*
|
|
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
|
|
}
|