Add feature declaration tests
And fix an error where we added previously unseen action_names to the dictionary of familiar ACTION_NAMES, so later when we would encounter them, we would treat them as variables, not as string literals
eg
env_set {
action = "a"
}
would translate to
env_set(
actions = [a],
)
which is, obviously wrong.
Issue #5380
PiperOrigin-RevId: 232817515
diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go
index c05e99c..bd373f1 100644
--- a/tools/migration/crosstool_to_starlark_lib.go
+++ b/tools/migration/crosstool_to_starlark_lib.go
@@ -434,7 +434,6 @@
actionName = strings.Replace(actionName, "+", "p", -1)
actionName = strings.Replace(actionName, ".", "_", -1)
actionName = strings.Replace(actionName, "-", "_", -1)
- actionNames[actionName] = actionName
}
stringAction, err := parseAction(action, 1)
if err != nil {
diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go
index 0090ce8..bcbc997 100644
--- a/tools/migration/crosstool_to_starlark_lib_test.go
+++ b/tools/migration/crosstool_to_starlark_lib_test.go
@@ -1158,14 +1158,14 @@
)
toolchainNameInDictA := getCToolchain("4", "cpuC", "compilerA",
[]string{
- getActionConfig([]string{"action_name: 'c++-executable'", "config_name: 'c++-executable'"}),
+ getActionConfig([]string{"action_name: 'c++-compile'", "config_name: 'c++-compile'"}),
},
)
toolchainNameInDictB := getCToolchain("5", "cpuC", "compilerB",
[]string{
getActionConfig([]string{
- "action_name: 'c++-executable'",
- "config_name: 'c++-executable'",
+ "action_name: 'c++-compile'",
+ "config_name: 'c++-compile'",
"tool {",
" tool_path: '/a/b/c'",
"}",
@@ -1258,12 +1258,12 @@
toolchains: []string{toolchainNameInDictA, toolchainNameInDictB},
expectedText: `
if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"):
- cpp_executable_action = action_config(
- action_name = "c++-executable",
+ cpp_compile_action = action_config(
+ action_name = ACTION_NAMES.cpp_compile,
tools = [tool(path = "/a/b/c")],
)
elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA"):
- cpp_executable_action = action_config(action_name = "c++-executable")`},
+ cpp_compile_action = action_config(action_name = ACTION_NAMES.cpp_compile)`},
{
toolchains: []string{toolchainComplexActionConfig},
expectedText: `
@@ -1325,3 +1325,206 @@
}
}
}
+
+func TestFeatureDeclaration(t *testing.T) {
+ toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{})
+ toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{})
+
+ toolchainSimpleFeatureA1 := getCToolchain("3", "cpuB", "compilerB",
+ []string{
+ getFeature([]string{"name: 'Feature-c++.a'", "enabled: true"}),
+ },
+ )
+ toolchainSimpleFeatureA2 := getCToolchain("4", "cpuC", "compilerA",
+ []string{
+ getFeature([]string{"name: 'Feature-c++.a'"}),
+ },
+ )
+ toolchainComplexFeature := getCToolchain("5", "cpuC", "compilerC",
+ []string{
+ getFeature([]string{
+ "name: 'complex-feature'",
+ "enabled: true",
+ "flag_set {",
+ " action: 'c++-compile'", // in ACTION_NAMES
+ " action: 'something-else'", // not in ACTION_NAMES
+ " flag_group {",
+ " flag: 'a'",
+ " flag: '%b'",
+ " iterate_over: 'c'",
+ " expand_if_all_available: 'd'",
+ " expand_if_none_available: 'e'",
+ " expand_if_true: 'f'",
+ " expand_if_false: 'g'",
+ " expand_if_equal {",
+ " variable: 'var'",
+ " value: 'val'",
+ " }",
+ " }",
+ " flag_group {",
+ " flag_group {",
+ " flag: 'a'",
+ " }",
+ " }",
+ "}",
+ "flag_set {", // all_compile_actions
+ " action: 'c-compile'",
+ " action: 'c++-compile'",
+ " action: 'linkstamp-compile'",
+ " action: 'assemble'",
+ " action: 'preprocess-assemble'",
+ " action: 'c++-header-parsing'",
+ " action: 'c++-module-compile'",
+ " action: 'c++-module-codegen'",
+ " action: 'clif-match'",
+ " action: 'lto-backend'",
+ "}",
+ "flag_set {", // all_cpp_compile_actions
+ " action: 'c++-compile'",
+ " action: 'linkstamp-compile'",
+ " action: 'c++-header-parsing'",
+ " action: 'c++-module-compile'",
+ " action: 'c++-module-codegen'",
+ " action: 'clif-match'",
+ "}",
+ "flag_set {", // all_link_actions
+ " action: 'c++-link-executable'",
+ " action: 'c++-link-dynamic-library'",
+ " action: 'c++-link-nodeps-dynamic-library'",
+ "}",
+ "flag_set {", // all_cpp_compile_actions + all_link_actions
+ " action: 'c++-compile'",
+ " action: 'linkstamp-compile'",
+ " action: 'c++-header-parsing'",
+ " action: 'c++-module-compile'",
+ " action: 'c++-module-codegen'",
+ " action: 'clif-match'",
+ " action: 'c++-link-executable'",
+ " action: 'c++-link-dynamic-library'",
+ " action: 'c++-link-nodeps-dynamic-library'",
+ "}",
+ "flag_set {", // all_link_actions + something else
+ " action: 'c++-link-executable'",
+ " action: 'c++-link-dynamic-library'",
+ " action: 'c++-link-nodeps-dynamic-library'",
+ " action: 'some.unknown-c++.action'",
+ "}",
+ "env_set {",
+ " action: 'a'",
+ " env_entry {",
+ " key: 'k'",
+ " value: 'v'",
+ " }",
+ " with_feature {",
+ " feature: 'a'",
+ " }",
+ "}",
+ "env_set {",
+ " action: 'c-compile'",
+ "}",
+ "env_set {", // all_compile_actions
+ " action: 'c-compile'",
+ " action: 'c++-compile'",
+ " action: 'linkstamp-compile'",
+ " action: 'assemble'",
+ " action: 'preprocess-assemble'",
+ " action: 'c++-header-parsing'",
+ " action: 'c++-module-compile'",
+ " action: 'c++-module-codegen'",
+ " action: 'clif-match'",
+ " action: 'lto-backend'",
+ "}",
+ "requires {",
+ " feature: 'a'",
+ " feature: 'b'",
+ "}",
+ "implies: 'a'",
+ "implies: 'b'",
+ "provides: 'c'",
+ "provides: 'd'",
+ }),
+ },
+ )
+
+ testCases := []struct {
+ toolchains []string
+ expectedText string
+ }{
+ {
+ toolchains: []string{toolchainEmpty1, toolchainEmpty2},
+ expectedText: `
+ features = []
+`},
+ {
+ toolchains: []string{toolchainEmpty1, toolchainSimpleFeatureA1},
+ expectedText: `
+ feature_cpp_a_feature = feature(name = "Feature-c++.a", enabled = True)`},
+ {
+ toolchains: []string{toolchainSimpleFeatureA1, toolchainSimpleFeatureA2},
+ expectedText: `
+ if (ctx.attr.cpu == "cpuC"):
+ feature_cpp_a_feature = feature(name = "Feature-c++.a")
+ elif (ctx.attr.cpu == "cpuB"):
+ feature_cpp_a_feature = feature(name = "Feature-c++.a", enabled = True)`},
+ {
+ toolchains: []string{toolchainComplexFeature},
+ expectedText: `
+ complex_feature_feature = feature(
+ name = "complex-feature",
+ enabled = True,
+ flag_sets = [
+ flag_set(
+ actions = [ACTION_NAMES.cpp_compile, "something-else"],
+ flag_groups = [
+ flag_group(
+ flags = ["a", "%b"],
+ iterate_over = "c",
+ expand_if_available = "d",
+ expand_if_not_available = "e",
+ expand_if_true = "f",
+ expand_if_false = "g",
+ expand_if_equal = variable_with_value(name = "var", value = "val"),
+ ),
+ flag_group(flag_groups = [flag_group(flags = ["a"])]),
+ ],
+ ),
+ flag_set(actions = all_compile_actions),
+ flag_set(actions = all_cpp_compile_actions),
+ flag_set(actions = all_link_actions),
+ flag_set(
+ actions = all_cpp_compile_actions +
+ all_link_actions,
+ ),
+ flag_set(
+ actions = all_link_actions +
+ ["some.unknown-c++.action"],
+ ),
+ ],
+ env_sets = [
+ env_set(
+ actions = ["a"],
+ env_entries = [env_entry(key = "k", value = "v")],
+ with_features = [with_feature_set(features = ["a"])],
+ ),
+ env_set(actions = [ACTION_NAMES.c_compile]),
+ env_set(actions = all_compile_actions),
+ ],
+ requires = [feature_set(features = ["a", "b"])],
+ implies = ["a", "b"],
+ provides = ["c", "d"],
+ )`}}
+
+ for _, tc := range testCases {
+ crosstool := makeCrosstool(tc.toolchains)
+ got, err := Transform(crosstool)
+ if err != nil {
+ t.Fatalf("CROSSTOOL conversion failed: %v", err)
+ }
+ if !strings.Contains(got, tc.expectedText) {
+ t.Errorf("Failed to correctly declare a feature, expected to contain:\n%v\n",
+ tc.expectedText)
+ t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n",
+ strings.Join(tc.toolchains, "\n"), got)
+ }
+ }
+}