From eeed2a9ab71625938674e91137dfd1d9a1e65a83 Mon Sep 17 00:00:00 2001 From: Googler Date: Tue, 8 Oct 2024 05:34:58 -0700 Subject: [PATCH] Remove crostool migration tools The migration to .bzl configured toolchains happened a long time ago and the conversion tools from proto files are not needed anymore. This also cleans up rules_cc dependencies to build those tools. And unblock me around the import of py_proto_library, which is not needed anymore. PiperOrigin-RevId: 683582749 Change-Id: I9a56d9e3f9089f7434708a2cfefdd4f12d186658 --- .bazelci/presubmit.yml | 2 - WORKSPACE | 67 - third_party/BUILD | 1 - .../bazelbuild/bazel/src/main/protobuf/BUILD | 30 - .../src/main/protobuf/crosstool_config.proto | 548 ----- third_party/six.BUILD | 16 - tools/migration/BUILD | 144 -- .../cc_toolchain_config_comparator.bzl | 53 - .../convert_crosstool_to_starlark.go | 101 - tools/migration/crosstool_query.py | 53 - tools/migration/crosstool_to_starlark_lib.go | 1419 ------------- .../crosstool_to_starlark_lib_test.go | 1756 ---------------- tools/migration/ctoolchain_comparator.py | 127 -- tools/migration/ctoolchain_comparator_lib.py | 523 ----- .../ctoolchain_comparator_lib_test.py | 1821 ----------------- tools/migration/ctoolchain_compare.bzl | 49 - .../migration/legacy_fields_migration_lib.py | 564 ----- .../legacy_fields_migration_lib_test.py | 1240 ----------- tools/migration/legacy_fields_migrator.py | 69 - 19 files changed, 8583 deletions(-) delete mode 100644 third_party/BUILD delete mode 100644 third_party/com/github/bazelbuild/bazel/src/main/protobuf/BUILD delete mode 100644 third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config.proto delete mode 100644 third_party/six.BUILD delete mode 100644 tools/migration/BUILD delete mode 100644 tools/migration/cc_toolchain_config_comparator.bzl delete mode 100644 tools/migration/convert_crosstool_to_starlark.go delete mode 100644 tools/migration/crosstool_query.py delete mode 100644 tools/migration/crosstool_to_starlark_lib.go delete mode 100644 tools/migration/crosstool_to_starlark_lib_test.go delete mode 100644 tools/migration/ctoolchain_comparator.py delete mode 100644 tools/migration/ctoolchain_comparator_lib.py delete mode 100644 tools/migration/ctoolchain_comparator_lib_test.py delete mode 100644 tools/migration/ctoolchain_compare.bzl delete mode 100644 tools/migration/legacy_fields_migration_lib.py delete mode 100644 tools/migration/legacy_fields_migration_lib_test.py delete mode 100644 tools/migration/legacy_fields_migrator.py diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 8d7899d..9fbb3ed 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -16,7 +16,6 @@ x_defaults: - "//examples/my_c_archive:all" - "//examples/my_c_compile:all" - "//examples/write_cc_toolchain_cpu:all" - - "//tools/migration:all" - "//tests/..." test_flags: - "--test_timeout=120" @@ -29,7 +28,6 @@ x_defaults: - "//examples/my_c_archive:all" - "//examples/my_c_compile:all" - "//examples/write_cc_toolchain_cpu:all" - - "//tools/migration:all" - "//tests/..." buildifier: diff --git a/WORKSPACE b/WORKSPACE index a4587d5..9501829 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -11,34 +11,6 @@ http_archive( ], ) -http_archive( - name = "com_google_googletest", - sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2", - strip_prefix = "googletest-release-1.12.1", - urls = [ - "https://mirror.bazel.build/github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz", - "https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz", - ], -) - -http_archive( - name = "io_abseil_py", - sha256 = "0fb3a4916a157eb48124ef309231cecdfdd96ff54adf1660b39c0d4a9790a2c0", - strip_prefix = "abseil-py-1.4.0", - urls = [ - "https://github.com/abseil/abseil-py/archive/refs/tags/v1.4.0.tar.gz", - ], -) - -http_archive( - name = "io_bazel_rules_go", - sha256 = "91585017debb61982f7054c9688857a2ad1fd823fc3f9cb05048b0025c47d023", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", - "https://github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", - ], -) - http_archive( name = "platforms", sha256 = "218efe8ee736d26a3572663b374a253c012b716d8af0c07e842e82f238a0a7ee", @@ -48,49 +20,10 @@ http_archive( ], ) -http_archive( - name = "py_mock", - patch_cmds = [ - "mkdir -p py/mock", - "mv mock.py py/mock/__init__.py", - """echo 'licenses(["notice"])' > BUILD""", - "touch py/BUILD", - """echo 'py_library(name = "mock", srcs = ["__init__.py"], visibility = ["//visibility:public"],)' > py/mock/BUILD""", - ], - sha256 = "b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f", - strip_prefix = "mock-1.0.1", - urls = [ - "https://mirror.bazel.build/pypi.python.org/packages/source/m/mock/mock-1.0.1.tar.gz", - "https://pypi.python.org/packages/source/m/mock/mock-1.0.1.tar.gz", - ], -) - -http_archive( - name = "rules_proto", - sha256 = "9a0503631679e9ab4e27d891ea60fee3e86a85654ea2048cae25516171dd260e", - strip_prefix = "rules_proto-e51f588e5932966ab9e63e0b0f6de6f740cf04c4", - urls = [ - "https://mirror.bazel.build/github.com/bazelbuild/rules_proto/archive/e51f588e5932966ab9e63e0b0f6de6f740cf04c4.tar.gz", - "https://github.com/bazelbuild/rules_proto/archive/e51f588e5932966ab9e63e0b0f6de6f740cf04c4.tar.gz", - ], -) - load("@bazel_skylib//:workspace.bzl", "bazel_skylib_workspace") bazel_skylib_workspace() -load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") - -go_rules_dependencies() - -go_register_toolchains(version = "1.20.5") - -load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") - -rules_proto_dependencies() - -rules_proto_toolchains() - http_archive( name = "rules_testing", sha256 = "02c62574631876a4e3b02a1820cb51167bb9cdcdea2381b2fa9d9b8b11c407c4", diff --git a/third_party/BUILD b/third_party/BUILD deleted file mode 100644 index 0c41157..0000000 --- a/third_party/BUILD +++ /dev/null @@ -1 +0,0 @@ -# Intentionally empty, only there to make //third_party a package. diff --git a/third_party/com/github/bazelbuild/bazel/src/main/protobuf/BUILD b/third_party/com/github/bazelbuild/bazel/src/main/protobuf/BUILD deleted file mode 100644 index c08e13b..0000000 --- a/third_party/com/github/bazelbuild/bazel/src/main/protobuf/BUILD +++ /dev/null @@ -1,30 +0,0 @@ -load("@com_google_protobuf//:protobuf.bzl", "py_proto_library") -load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") -load("@rules_proto//proto:defs.bzl", "proto_library") - -licenses(["notice"]) # Apache 2.0 - -py_proto_library( - name = "crosstool_config_py_pb2", - srcs = ["crosstool_config.proto"], - visibility = [ - "//tools/migration:__pkg__", - ], -) - -proto_library( - name = "crosstool_config_pb2", - srcs = ["crosstool_config.proto"], - visibility = [ - "//tools/migration:__pkg__", - ], -) - -go_proto_library( - name = "crosstool_config_go_proto", - importpath = "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto", - proto = ":crosstool_config_pb2", - visibility = [ - "//tools/migration:__pkg__", - ], -) diff --git a/third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config.proto b/third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config.proto deleted file mode 100644 index 45ad1e5..0000000 --- a/third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config.proto +++ /dev/null @@ -1,548 +0,0 @@ -// Copyright 2014 The Bazel Authors. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -// File format for Blaze to configure Crosstool releases. - -syntax = "proto2"; - -package com.google.devtools.build.lib.view.config.crosstool; - -// option java_api_version = 2; // copybara-comment-this-out-please -option java_package = "com.google.devtools.build.lib.view.config.crosstool"; - -// A description of a toolchain, which includes all the tools generally expected -// to be available for building C/C++ targets, based on the GNU C compiler. -// -// System and cpu names are two overlapping concepts, which need to be both -// supported at this time. The cpu name is the blaze command-line name for the -// target system. The most common values are 'k8' and 'piii'. The system name is -// a more generic identification of the executable system, based on the names -// used by the GNU C compiler. -// -// Typically, the system name contains an identifier for the cpu (e.g. x86_64 or -// alpha), an identifier for the machine (e.g. pc, or unknown), and an -// identifier for the operating system (e.g. cygwin or linux-gnu). Typical -// examples are 'x86_64-unknown-linux-gnu' and 'i686-unknown-cygwin'. -// -// The system name is used to determine if a given machine can execute a given -// executable. In particular, it is used to check if the compilation products of -// a toolchain can run on the host machine. -message CToolchain { - // A group of correlated flags. Supports parametrization via variable - // expansion. - // - // To expand a variable of list type, flag_group has to be annotated with - // `iterate_over` message. Then all nested flags or flag_groups will be - // expanded repeatedly for each element of the list. - // - // For example: - // flag_group { - // iterate_over: 'include_path' - // flag: '-I' - // flag: '%{include_path}' - // } - // ... will get expanded to -I /to/path1 -I /to/path2 ... for each - // include_path /to/pathN. - // - // To expand a variable of structure type, use dot-notation, e.g.: - // flag_group { - // iterate_over: "libraries_to_link" - // flag_group { - // iterate_over: "libraries_to_link.libraries" - // flag: "-L%{libraries_to_link.libraries.directory}" - // } - // } - // - // Flag groups can be nested; if they are, the flag group must only contain - // other flag groups (no flags) so the order is unambiguously specified. - // In order to expand a variable of nested lists, 'iterate_over' can be used. - // - // For example: - // flag_group { - // iterate_over: 'object_files' - // flag_group { flag: '--start-lib' } - // flag_group { - // iterate_over: 'object_files' - // flag: '%{object_files}' - // } - // flag_group { flag: '--end-lib' } - // } - // ... will get expanded to - // --start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib - // with %{object_files} being a variable of nested list type - // [['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...]. - // - // TODO(bazel-team): Write more elaborate documentation and add a link to it. - message FlagGroup { - repeated string flag = 1; - - repeated FlagGroup flag_group = 2; - - optional string iterate_over = 3; - - repeated string expand_if_all_available = 4; - - repeated string expand_if_none_available = 5; - - optional string expand_if_true = 6; - - optional string expand_if_false = 7; - - optional VariableWithValue expand_if_equal = 8; - } - - message VariableWithValue { - required string variable = 1; - - required string value = 2; - } - - // A key/value pair to be added as an environment variable. The value of - // this pair is expanded in the same way as is described in FlagGroup. - // The key remains an unexpanded string literal. - message EnvEntry { - required string key = 1; - required string value = 2; - repeated string expand_if_all_available = 3; - } - - // A set of features; used to support logical 'and' when specifying feature - // requirements in Feature. - message FeatureSet { - repeated string feature = 1; - } - - // A set of positive and negative features. This stanza will - // evaluate to true when every 'feature' is enabled, and every - // 'not_feature' is not enabled. - message WithFeatureSet { - repeated string feature = 1; - repeated string not_feature = 2; - } - - // A set of flags that are expanded in the command line for specific actions. - message FlagSet { - // The actions this flag set applies to; each flag set must specify at - // least one action. - repeated string action = 1; - - // The flags applied via this flag set. - repeated FlagGroup flag_group = 2; - - // A list of feature sets defining when this flag set gets applied. The - // flag set will be applied when any one of the feature sets evaluate to - // true. (That is, when when every 'feature' is enabled, and every - // 'not_feature' is not enabled.) - // - // If 'with_feature' is omitted, the flag set will be applied - // unconditionally for every action specified. - repeated WithFeatureSet with_feature = 3; - - // Deprecated (https://github.com/bazelbuild/bazel/issues/7008) - use - // expand_if_all_available in flag_group - // - // A list of build variables that this feature set needs, but which are - // allowed to not be set. If any of the build variables listed is not - // set, the feature set will not be expanded. - // - // NOTE: Consider alternatives before using this; usually tools should - // consistently create the same set of files, even if empty; use this - // only for backwards compatibility with already existing behavior in tools - // that are currently not worth changing. - repeated string expand_if_all_available = 4; - } - - // A set of environment variables that are expanded in the command line for - // specific actions. - message EnvSet { - // The actions this env set applies to; each env set must specify at - // least one action. - repeated string action = 1; - - // The environment variables applied via this env set. - repeated EnvEntry env_entry = 2; - - // A list of feature sets defining when this env set gets applied. The - // env set will be applied when any one of the feature sets evaluate to - // true. (That is, when when every 'feature' is enabled, and every - // 'not_feature' is not enabled.) - // - // If 'with_feature' is omitted, the env set will be applied - // unconditionally for every action specified. - repeated WithFeatureSet with_feature = 3; - } - - // Contains all flag specifications for one feature. - // Next ID: 8 - message Feature { - // The feature's name. Feature names are generally defined by Bazel; it is - // possible to introduce a feature without a change to Bazel by adding a - // 'feature' section to the toolchain and adding the corresponding string as - // feature in the BUILD file. - optional string name = 1; - - // If 'true', this feature is enabled unless a rule type explicitly marks it - // as unsupported. Such features cannot be turned off from within a BUILD - // file or the command line. - optional bool enabled = 7; - - // If the given feature is enabled, the flag sets will be applied for the - // actions in the modes that they are specified for. - repeated FlagSet flag_set = 2; - - // If the given feature is enabled, the env sets will be applied for the - // actions in the modes that they are specified for. - repeated EnvSet env_set = 6; - - // A list of feature sets defining when this feature is supported by the - // toolchain. The feature is supported if any of the feature sets fully - // apply, that is, when all features of a feature set are enabled. - // - // If 'requires' is omitted, the feature is supported independently of which - // other features are enabled. - // - // Use this for example to filter flags depending on the build mode - // enabled (opt / fastbuild / dbg). - repeated FeatureSet requires = 3; - - // A list of features or action configs that are automatically enabled when - // this feature is enabled. If any of the implied features or action configs - // cannot be enabled, this feature will (silently) not be enabled either. - repeated string implies = 4; - - // A list of names this feature conflicts with. - // A feature cannot be enabled if: - // - 'provides' contains the name of a different feature or action config - // that we want to enable. - // - 'provides' contains the same value as a 'provides' in a different - // feature or action config that we want to enable. - // - // Use this in order to ensure that incompatible features cannot be - // accidentally activated at the same time, leading to hard to diagnose - // compiler errors. - repeated string provides = 5; - } - - // Describes a tool associated with a crosstool action config. - message Tool { - // Describes the origin of a path. - enum PathOrigin { - // Indicates that `tool_path` is relative to the location of the - // crosstool. For legacy reasons, absolute paths are als0 allowed here. - CROSSTOOL_PACKAGE = 0; - - // Indicates that `tool_path` is an absolute path. - // This is enforced by Bazel. - FILESYSTEM_ROOT = 1; - - // Indicates that `tool_path` is relative to the current workspace's - // exec root. - WORKSPACE_ROOT = 2; - } - - // Path to the tool, relative to the location of the crosstool. - required string tool_path = 1; - - // Origin of `tool_path`. - // Optional only for legacy reasons. New crosstools should set this value! - optional PathOrigin tool_path_origin = 4 [default = CROSSTOOL_PACKAGE]; - - // A list of feature sets defining when this tool is applicable. The tool - // will used when any one of the feature sets evaluate to true. (That is, - // when when every 'feature' is enabled, and every 'not_feature' is not - // enabled.) - // - // If 'with_feature' is omitted, the tool will apply for any feature - // configuration. - repeated WithFeatureSet with_feature = 2; - - // Requirements on the execution environment for the execution of this tool, - // to be passed as out-of-band "hints" to the execution backend. - // Ex. "requires-darwin" - repeated string execution_requirement = 3; - } - - // The name for an artifact of a given category of input or output artifacts - // to an action. - message ArtifactNamePattern { - // The category of artifacts that this selection applies to. This field - // is compared against a list of categories defined in bazel. Example - // categories include "linked_output" or "debug_symbols". An error is thrown - // if no category is matched. - required string category_name = 1; - // The prefix and extension for creating the artifact for this selection. - // They are used to create an artifact name based on the target name. - required string prefix = 2; - required string extension = 3; - } - - // An action config corresponds to a blaze action, and allows selection of - // a tool based on activated features. Action configs come in two varieties: - // automatic (the blaze action will exist whether or not the action config - // is activated) and attachable (the blaze action will be added to the - // action graph only if the action config is activated). - // - // Action config activation occurs by the same semantics as features: a - // feature can 'require' or 'imply' an action config in the same way that it - // would another feature. - // Next ID: 9 - message ActionConfig { - // The name other features will use to activate this action config. Can - // be the same as action_name. - required string config_name = 1; - - // The name of the blaze action that this config applies to, ex. 'c-compile' - // or 'c-module-compile'. - required string action_name = 2; - - // If 'true', this feature is enabled unless a rule type explicitly marks it - // as unsupported. Such action_configs cannot be turned off from within a - // BUILD file or the command line. - optional bool enabled = 8; - - // The tool applied to the action will be the first Tool with a feature - // set that matches the feature configuration. An error will be thrown - // if no tool matches a provided feature configuration - for that reason, - // it's a good idea to provide a default tool with an empty feature set. - repeated Tool tool = 3; - - // If the given action config is enabled, the flag sets will be applied - // to the corresponding action. - repeated FlagSet flag_set = 4; - - // If the given action config is enabled, the env sets will be applied - // to the corresponding action. - repeated EnvSet env_set = 5; - - // A list of feature sets defining when this action config - // is supported by the toolchain. The action config is supported if any of - // the feature sets fully apply, that is, when all features of a - // feature set are enabled. - // - // If 'requires' is omitted, the action config is supported independently - // of which other features are enabled. - // - // Use this for example to filter actions depending on the build - // mode enabled (opt / fastbuild / dbg). - repeated FeatureSet requires = 6; - - // A list of features or action configs that are automatically enabled when - // this action config is enabled. If any of the implied features or action - // configs cannot be enabled, this action config will (silently) - // not be enabled either. - repeated string implies = 7; - } - - repeated Feature feature = 50; - repeated ActionConfig action_config = 53; - repeated ArtifactNamePattern artifact_name_pattern = 54; - - // The unique identifier of the toolchain within the crosstool release. It - // must be possible to use this as a directory name in a path. - // It has to match the following regex: [a-zA-Z_][\.\- \w]* - required string toolchain_identifier = 1; - - // A basic toolchain description. - required string host_system_name = 2; - required string target_system_name = 3; - required string target_cpu = 4; - required string target_libc = 5; - required string compiler = 6; - - required string abi_version = 7; - required string abi_libc_version = 8; - - // Tool locations. Relative paths are resolved relative to the configuration - // file directory. - // NOTE: DEPRECATED. Prefer specifying an ActionConfig for the action that - // needs the tool. - // TODO(b/27903698) migrate to ActionConfig. - repeated ToolPath tool_path = 9; - - // Feature flags. - // TODO(bazel-team): Sink those into 'Feature' instances. - // Legacy field, ignored by Bazel. - optional bool supports_gold_linker = 10 [default = false]; - // Legacy field, ignored by Bazel. - optional bool supports_thin_archives = 11 [default = false]; - // Legacy field, use 'supports_start_end_lib' feature instead. - optional bool supports_start_end_lib = 28 [default = false]; - // Legacy field, use 'supports_interface_shared_libraries' instead. - optional bool supports_interface_shared_objects = 32 [default = false]; - // Legacy field, use 'static_link_cpp_runtimes' feature instead. - optional bool supports_embedded_runtimes = 40 [default = false]; - // If specified, Blaze finds statically linked / dynamically linked runtime - // libraries in the declared crosstool filegroup. Otherwise, Blaze - // looks in "[static|dynamic]-runtime-libs-$TARGET_CPU". - // Deprecated, see https://github.com/bazelbuild/bazel/issues/6942 - optional string static_runtimes_filegroup = 45; - // Deprecated, see https://github.com/bazelbuild/bazel/issues/6942 - optional string dynamic_runtimes_filegroup = 46; - // Legacy field, ignored by Bazel. - optional bool supports_incremental_linker = 41 [default = false]; - // Legacy field, ignored by Bazel. - optional bool supports_normalizing_ar = 26 [default = false]; - // Legacy field, use 'per_object_debug_info' feature instead. - optional bool supports_fission = 43 [default = false]; - // Legacy field, ignored by Bazel. - optional bool supports_dsym = 51 [default = false]; - // Legacy field, use 'supports_pic' feature instead - optional bool needsPic = 12 [default = false]; - - // Compiler flags for C/C++/Asm compilation. - repeated string compiler_flag = 13; - // Additional compiler flags for C++ compilation. - repeated string cxx_flag = 14; - // Additional unfiltered compiler flags for C/C++/Asm compilation. - // These are not subject to nocopt filtering in cc_* rules. - // Note: These flags are *not* applied to objc/objc++ compiles. - repeated string unfiltered_cxx_flag = 25; - // Linker flags. - repeated string linker_flag = 15; - // Additional linker flags when linking dynamic libraries. - repeated string dynamic_library_linker_flag = 27; - // Additional test-only linker flags. - repeated string test_only_linker_flag = 49; - // Objcopy flags for embedding files into binaries. - repeated string objcopy_embed_flag = 16; - // Ld flags for embedding files into binaries. This is used by filewrapper - // since it calls ld directly and needs to know what -m flag to pass. - repeated string ld_embed_flag = 23; - // Ar flags for combining object files into archives. If this is not set, it - // defaults to "rcsD". - // TODO(b/37271982): Remove after blaze with ar action_config release - repeated string ar_flag = 47; - // Legacy field, ignored by Bazel. - repeated string ar_thin_archives_flag = 48; - // Legacy field, ignored by Bazel. - repeated string gcc_plugin_compiler_flag = 34; - - // Additional compiler and linker flags depending on the compilation mode. - repeated CompilationModeFlags compilation_mode_flags = 17; - - // Additional linker flags depending on the linking mode. - repeated LinkingModeFlags linking_mode_flags = 18; - - // Legacy field, ignored by Bazel. - repeated string gcc_plugin_header_directory = 19; - // Legacy field, ignored by Bazel. - repeated string mao_plugin_header_directory = 20; - - // Make variables that are made accessible to rules. - repeated MakeVariable make_variable = 21; - - // Built-in include directories for C++ compilation. These should be the exact - // paths used by the compiler, and are generally relative to the exec root. - // The paths used by the compiler can be determined by 'gcc -Wp,-v some.c'. - // We currently use the C++ paths also for C compilation, which is safe as - // long as there are no name clashes between C++ and C header files. - // - // Relative paths are resolved relative to the configuration file directory. - // - // If the compiler has --sysroot support, then these paths should use - // %sysroot% rather than the include path, and specify the sysroot attribute - // in order to give blaze the information necessary to make the correct - // replacements. - repeated string cxx_builtin_include_directory = 22; - - // The built-in sysroot. If this attribute is not present, blaze does not - // allow using a different sysroot, i.e. through the --grte_top option. Also - // see the documentation above. - optional string builtin_sysroot = 24; - - // Legacy field, ignored by Bazel. - optional string default_python_top = 29; - // Legacy field, ignored by Bazel. - optional string default_python_version = 30; - // Legacy field, ignored by Bazel. - optional bool python_preload_swigdeps = 42; - - // The default GRTE to use. This should be a label, and gets the same - // treatment from Blaze as the --grte_top option. This setting is only used in - // the absence of an explicit --grte_top option. If unset, Blaze will not pass - // -sysroot by default. The local part must be 'everything', i.e., - // '//some/label:everything'. There can only be one GRTE library per package, - // because the compiler expects the directory as a parameter of the -sysroot - // option. - // This may only be set to a non-empty value if builtin_sysroot is also set! - optional string default_grte_top = 31; - - // Legacy field, ignored by Bazel. - repeated string debian_extra_requires = 33; - - // Legacy field, ignored by Bazel. Only there for compatibility with - // things internal to Google. - optional string cc_target_os = 55; - - // Next free id: 56 -} - -message ToolPath { - required string name = 1; - required string path = 2; -} - -enum CompilationMode { - FASTBUILD = 1; - DBG = 2; - OPT = 3; - // This value is ignored and should not be used in new files. - COVERAGE = 4; -} - -message CompilationModeFlags { - required CompilationMode mode = 1; - repeated string compiler_flag = 2; - repeated string cxx_flag = 3; - // Linker flags that are added when compiling in a certain mode. - repeated string linker_flag = 4; -} - -enum LinkingMode { - FULLY_STATIC = 1; - MOSTLY_STATIC = 2; - DYNAMIC = 3; - MOSTLY_STATIC_LIBRARIES = 4; -} - -message LinkingModeFlags { - required LinkingMode mode = 1; - repeated string linker_flag = 2; -} - -message MakeVariable { - required string name = 1; - required string value = 2; -} - -message DefaultCpuToolchain { - required string cpu = 1; - required string toolchain_identifier = 2; -} - -// An entire crosstool release, containing the version number, and a set of -// toolchains. -message CrosstoolRelease { - // The major and minor version of the crosstool release. - required string major_version = 1; - required string minor_version = 2; - - // Legacy field, ignored by Bazel. - optional string default_target_cpu = 3; - // Legacy field, ignored by Bazel. - repeated DefaultCpuToolchain default_toolchain = 4; - - // All the toolchains in this release. - repeated CToolchain toolchain = 5; -} diff --git a/third_party/six.BUILD b/third_party/six.BUILD deleted file mode 100644 index 19433c2..0000000 --- a/third_party/six.BUILD +++ /dev/null @@ -1,16 +0,0 @@ -# Description: -# Six provides simple utilities for wrapping over differences between Python 2 -# and Python 3. - -load("@rules_python//python:defs.bzl", "py_library") - -licenses(["notice"]) # MIT - -exports_files(["LICENSE"]) - -py_library( - name = "six", - srcs = ["six.py"], - srcs_version = "PY2AND3", - visibility = ["//visibility:public"], -) diff --git a/tools/migration/BUILD b/tools/migration/BUILD deleted file mode 100644 index 1550c15..0000000 --- a/tools/migration/BUILD +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test") -load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test") - -package(default_visibility = ["//visibility:public"]) - -licenses(["notice"]) - -py_binary( - name = "legacy_fields_migrator", - srcs = ["legacy_fields_migrator.py"], - python_version = "PY3", - deps = [ - ":legacy_fields_migration_lib", - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - "@io_abseil_py//absl:app", - "@io_abseil_py//absl/flags", - #internal proto upb dep, - ], -) - -py_library( - name = "legacy_fields_migration_lib", - srcs = ["legacy_fields_migration_lib.py"], - deps = [ - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - ], -) - -py_test( - name = "legacy_fields_migration_lib_test", - srcs = ["legacy_fields_migration_lib_test.py"], - python_version = "PY3", - deps = [ - ":legacy_fields_migration_lib", - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - ], -) - -py_binary( - name = "crosstool_query", - srcs = ["crosstool_query.py"], - python_version = "PY3", - deps = [ - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - "@io_abseil_py//absl:app", - "@io_abseil_py//absl/flags", - #internal proto upb dep, - ], -) - -py_binary( - name = "ctoolchain_comparator", - srcs = ["ctoolchain_comparator.py"], - python_version = "PY3", - deps = [ - ":ctoolchain_comparator_lib", - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - "@io_abseil_py//absl:app", - "@io_abseil_py//absl/flags", - #internal proto upb dep, - ], -) - -py_library( - name = "ctoolchain_comparator_lib", - srcs = ["ctoolchain_comparator_lib.py"], - deps = [ - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - ], -) - -py_test( - name = "ctoolchain_comparator_lib_test", - srcs = ["ctoolchain_comparator_lib_test.py"], - python_version = "PY3", - deps = [ - ":ctoolchain_comparator_lib", - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_py_pb2", - "@py_mock//py/mock", - ], -) - -go_binary( - name = "convert_crosstool_to_starlark", - srcs = ["convert_crosstool_to_starlark.go"], - deps = [ - ":crosstooltostarlarklib", - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto", - "@com_github_golang_protobuf//proto:go_default_library", - ], -) - -go_library( - name = "crosstooltostarlarklib", - srcs = ["crosstool_to_starlark_lib.go"], - importpath = "tools/migration/crosstooltostarlarklib", - deps = ["//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto"], -) - -go_test( - name = "crosstooltostarlarklib_test", - size = "small", - srcs = ["crosstool_to_starlark_lib_test.go"], - embed = [":crosstooltostarlarklib"], - deps = [ - "//third_party/com/github/bazelbuild/bazel/src/main/protobuf:crosstool_config_go_proto", - "@com_github_golang_protobuf//proto:go_default_library", - ], -) - -filegroup( - name = "bazel_osx_p4deps", - srcs = [ - "BUILD", - "ctoolchain_compare.bzl", - ], -) - -bzl_library( - name = "ctoolchain_compare_bzl", - srcs = ["ctoolchain_compare.bzl"], - visibility = ["//visibility:private"], -) - -bzl_library( - name = "cc_toolchain_config_comparator_bzl", - srcs = ["cc_toolchain_config_comparator.bzl"], - visibility = ["//visibility:private"], -) diff --git a/tools/migration/cc_toolchain_config_comparator.bzl b/tools/migration/cc_toolchain_config_comparator.bzl deleted file mode 100644 index 66746b3..0000000 --- a/tools/migration/cc_toolchain_config_comparator.bzl +++ /dev/null @@ -1,53 +0,0 @@ -"""A test rule that compares two C++ toolchain configuration rules in proto format.""" - -def _impl(ctx): - first_toolchain_config_proto = ctx.actions.declare_file( - ctx.label.name + "_first_toolchain_config.proto", - ) - ctx.actions.write( - first_toolchain_config_proto, - ctx.attr.first[CcToolchainConfigInfo].proto, - ) - - second_toolchain_config_proto = ctx.actions.declare_file( - ctx.label.name + "_second_toolchain_config.proto", - ) - ctx.actions.write( - second_toolchain_config_proto, - ctx.attr.second[CcToolchainConfigInfo].proto, - ) - - script = ("%s --before='%s' --after='%s'" % ( - ctx.executable._comparator.short_path, - first_toolchain_config_proto.short_path, - second_toolchain_config_proto.short_path, - )) - test_executable = ctx.actions.declare_file(ctx.label.name) - ctx.actions.write(test_executable, script, is_executable = True) - - runfiles = ctx.runfiles(files = [first_toolchain_config_proto, second_toolchain_config_proto]) - runfiles = runfiles.merge(ctx.attr._comparator[DefaultInfo].default_runfiles) - - return DefaultInfo(runfiles = runfiles, executable = test_executable) - -cc_toolchain_config_compare_test = rule( - implementation = _impl, - attrs = { - "first": attr.label( - mandatory = True, - providers = [CcToolchainConfigInfo], - doc = "A C++ toolchain config rule", - ), - "second": attr.label( - mandatory = True, - providers = [CcToolchainConfigInfo], - doc = "A C++ toolchain config rule", - ), - "_comparator": attr.label( - default = ":ctoolchain_comparator", - executable = True, - cfg = "exec", - ), - }, - test = True, -) diff --git a/tools/migration/convert_crosstool_to_starlark.go b/tools/migration/convert_crosstool_to_starlark.go deleted file mode 100644 index 2c31456..0000000 --- a/tools/migration/convert_crosstool_to_starlark.go +++ /dev/null @@ -1,101 +0,0 @@ -/* -The convert_crosstool_to_starlark script takes in a CROSSTOOL file and -generates a Starlark rule. - -See https://github.com/bazelbuild/bazel/issues/5380 - -Example usage: -bazel run \ -@rules_cc//tools/migration:convert_crosstool_to_starlark -- \ ---crosstool=/path/to/CROSSTOOL \ ---output_location=/path/to/cc_config.bzl -*/ -package main - -import ( - "flag" - "fmt" - "io/ioutil" - "os" - "os/user" - "path" - "strings" - - // Google internal base/go package, commented out by copybara - "log" - crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" - "github.com/golang/protobuf/proto" - - "tools/migration/crosstooltostarlarklib" -) - -var ( - crosstoolLocation = flag.String( - "crosstool", "", "Location of the CROSSTOOL file") - outputLocation = flag.String( - "output_location", "", "Location of the output .bzl file") -) - -func toAbsolutePath(pathString string) (string, error) { - usr, err := user.Current() - if err != nil { - return "", err - } - homeDir := usr.HomeDir - - if strings.HasPrefix(pathString, "~") { - return path.Join(homeDir, pathString[1:]), nil - } - - if path.IsAbs(pathString) { - return pathString, nil - } - - workingDirectory := os.Getenv("BUILD_WORKING_DIRECTORY") - return path.Join(workingDirectory, pathString), nil -} - -func main() { - flag.Parse() - - if *crosstoolLocation == "" { - log.Fatalf("Missing mandatory argument 'crosstool'") - } - crosstoolPath, err := toAbsolutePath(*crosstoolLocation) - if err != nil { - log.Fatalf("Error while resolving CROSSTOOL location:", err) - } - - if *outputLocation == "" { - log.Fatalf("Missing mandatory argument 'output_location'") - } - outputPath, err := toAbsolutePath(*outputLocation) - if err != nil { - log.Fatalf("Error resolving output location:", err) - } - - in, err := ioutil.ReadFile(crosstoolPath) - if err != nil { - log.Fatalf("Error reading CROSSTOOL file:", err) - } - crosstool := &crosstoolpb.CrosstoolRelease{} - if err := proto.UnmarshalText(string(in), crosstool); err != nil { - log.Fatalf("Failed to parse CROSSTOOL:", err) - } - - file, err := os.Create(outputPath) - if err != nil { - log.Fatalf("Error creating output file:", err) - } - defer file.Close() - - rule, err := crosstooltostarlarklib.Transform(crosstool) - if err != nil { - log.Fatalf("Error converting CROSSTOOL to a Starlark rule:", err) - } - - if _, err := file.WriteString(rule); err != nil { - log.Fatalf("Error converting CROSSTOOL to a Starlark rule:", err) - } - fmt.Println("Success!") -} diff --git a/tools/migration/crosstool_query.py b/tools/migration/crosstool_query.py deleted file mode 100644 index af3f7fa..0000000 --- a/tools/migration/crosstool_query.py +++ /dev/null @@ -1,53 +0,0 @@ -"""Script to make automated CROSSTOOL refactorings easier. - -This script reads the CROSSTOOL file and allows for querying of its fields. -""" - -from absl import app -from absl import flags -from google.protobuf import text_format -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 - -flags.DEFINE_string("crosstool", None, "CROSSTOOL file path to be queried") -flags.DEFINE_string("identifier", None, - "Toolchain identifier to specify toolchain.") -flags.DEFINE_string("print_field", None, "Field to be printed to stdout.") - - -def main(unused_argv): - crosstool = crosstool_config_pb2.CrosstoolRelease() - - crosstool_filename = flags.FLAGS.crosstool - identifier = flags.FLAGS.identifier - print_field = flags.FLAGS.print_field - - if not crosstool_filename: - raise app.UsageError("ERROR crosstool unspecified") - if not identifier: - raise app.UsageError("ERROR identifier unspecified") - - if not print_field: - raise app.UsageError("ERROR print_field unspecified") - - with open(crosstool_filename, "r") as f: - text = f.read() - text_format.Merge(text, crosstool) - - toolchain_found = False - for toolchain in crosstool.toolchain: - if toolchain.toolchain_identifier == identifier: - toolchain_found = True - if not print_field: - continue - for field, value in toolchain.ListFields(): - if print_field == field.name: - print value - - if not toolchain_found: - print "toolchain_identifier %s not found, valid values are:" % identifier - for toolchain in crosstool.toolchain: - print " " + toolchain.toolchain_identifier - - -if __name__ == "__main__": - app.run(main) diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go deleted file mode 100644 index 15f5c12..0000000 --- a/tools/migration/crosstool_to_starlark_lib.go +++ /dev/null @@ -1,1419 +0,0 @@ -/* -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("@rules_cc//cc: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(\"@rules_cc//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 -} diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go deleted file mode 100644 index 63d9736..0000000 --- a/tools/migration/crosstool_to_starlark_lib_test.go +++ /dev/null @@ -1,1756 +0,0 @@ -package crosstooltostarlarklib - -import ( - "fmt" - "strings" - "testing" - - "log" - crosstoolpb "third_party/com/github/bazelbuild/bazel/src/main/protobuf/crosstool_config_go_proto" - "github.com/golang/protobuf/proto" -) - -func makeCToolchainString(lines []string) string { - return fmt.Sprintf(`toolchain { - %s -}`, strings.Join(lines, "\n ")) -} - -func makeCrosstool(CToolchains []string) *crosstoolpb.CrosstoolRelease { - crosstool := &crosstoolpb.CrosstoolRelease{} - requiredFields := []string{ - "major_version: '0'", - "minor_version: '0'", - "default_target_cpu: 'cpu'", - } - CToolchains = append(CToolchains, requiredFields...) - if err := proto.UnmarshalText(strings.Join(CToolchains, "\n"), crosstool); err != nil { - log.Fatalf("Failed to parse CROSSTOOL:", err) - } - return crosstool -} - -func getSimpleCToolchain(id string) string { - lines := []string{ - "toolchain_identifier: 'id-" + id + "'", - "host_system_name: 'host-" + id + "'", - "target_system_name: 'target-" + id + "'", - "target_cpu: 'cpu-" + id + "'", - "compiler: 'compiler-" + id + "'", - "target_libc: 'libc-" + id + "'", - "abi_version: 'version-" + id + "'", - "abi_libc_version: 'libc_version-" + id + "'", - } - return makeCToolchainString(lines) -} - -func getCToolchain(id, cpu, compiler string, extraLines []string) string { - lines := []string{ - "toolchain_identifier: '" + id + "'", - "host_system_name: 'host'", - "target_system_name: 'target'", - "target_cpu: '" + cpu + "'", - "compiler: '" + compiler + "'", - "target_libc: 'libc'", - "abi_version: 'version'", - "abi_libc_version: 'libc_version'", - } - lines = append(lines, extraLines...) - return makeCToolchainString(lines) -} - -func TestStringFieldsConditionStatement(t *testing.T) { - toolchain1 := getSimpleCToolchain("1") - toolchain2 := getSimpleCToolchain("2") - toolchains := []string{toolchain1, toolchain2} - crosstool := makeCrosstool(toolchains) - - testCases := []struct { - field string - expectedText string - }{ - {field: "toolchain_identifier", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - toolchain_identifier = "id-1" - elif (ctx.attr.cpu == "cpu-2"): - toolchain_identifier = "id-2" - else: - fail("Unreachable")`}, - {field: "host_system_name", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - host_system_name = "host-1" - elif (ctx.attr.cpu == "cpu-2"): - host_system_name = "host-2" - else: - fail("Unreachable")`}, - {field: "target_system_name", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - target_system_name = "target-1" - elif (ctx.attr.cpu == "cpu-2"): - target_system_name = "target-2" - else: - fail("Unreachable")`}, - {field: "target_cpu", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - target_cpu = "cpu-1" - elif (ctx.attr.cpu == "cpu-2"): - target_cpu = "cpu-2" - else: - fail("Unreachable")`}, - {field: "target_libc", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - target_libc = "libc-1" - elif (ctx.attr.cpu == "cpu-2"): - target_libc = "libc-2" - else: - fail("Unreachable")`}, - {field: "compiler", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - compiler = "compiler-1" - elif (ctx.attr.cpu == "cpu-2"): - compiler = "compiler-2" - else: - fail("Unreachable")`}, - {field: "abi_version", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - abi_version = "version-1" - elif (ctx.attr.cpu == "cpu-2"): - abi_version = "version-2" - else: - fail("Unreachable")`}, - {field: "abi_libc_version", - expectedText: ` - if (ctx.attr.cpu == "cpu-1"): - abi_libc_version = "libc_version-1" - elif (ctx.attr.cpu == "cpu-2"): - abi_libc_version = "libc_version-2" - else: - fail("Unreachable")`}} - - got, err := Transform(crosstool) - if err != nil { - t.Fatalf("CROSSTOOL conversion failed: %v", err) - } - - failed := false - for _, tc := range testCases { - if !strings.Contains(got, tc.expectedText) { - t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - failed = true - } - } - if failed { - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(toolchains, "\n"), got) - } -} - -func TestConditionsSameCpu(t *testing.T) { - toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainAB := getCToolchain("2", "cpuA", "compilerB", []string{}) - toolchains := []string{toolchainAA, toolchainAB} - crosstool := makeCrosstool(toolchains) - - testCases := []struct { - field string - expectedText string - }{ - {field: "toolchain_identifier", - expectedText: ` - if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): - toolchain_identifier = "1" - elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): - toolchain_identifier = "2" - else: - fail("Unreachable")`}, - {field: "host_system_name", - expectedText: ` - host_system_name = "host"`}, - {field: "target_system_name", - expectedText: ` - target_system_name = "target"`}, - {field: "target_cpu", - expectedText: ` - target_cpu = "cpuA"`}, - {field: "target_libc", - expectedText: ` - target_libc = "libc"`}, - {field: "compiler", - expectedText: ` - if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): - compiler = "compilerA" - elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): - compiler = "compilerB" - else: - fail("Unreachable")`}, - {field: "abi_version", - expectedText: ` - abi_version = "version"`}, - {field: "abi_libc_version", - expectedText: ` - abi_libc_version = "libc_version"`}} - - got, err := Transform(crosstool) - if err != nil { - t.Fatalf("CROSSTOOL conversion failed: %v", err) - } - - failed := false - for _, tc := range testCases { - if !strings.Contains(got, tc.expectedText) { - t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - failed = true - } - } - if failed { - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(toolchains, "\n"), got) - } -} - -func TestConditionsSameCompiler(t *testing.T) { - toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchains := []string{toolchainAA, toolchainBA} - crosstool := makeCrosstool(toolchains) - - testCases := []struct { - field string - expectedText string - }{ - {field: "toolchain_identifier", - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - toolchain_identifier = "1" - elif (ctx.attr.cpu == "cpuB"): - toolchain_identifier = "2" - else: - fail("Unreachable")`}, - {field: "target_cpu", - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - target_cpu = "cpuA" - elif (ctx.attr.cpu == "cpuB"): - target_cpu = "cpuB" - else: - fail("Unreachable")`}, - {field: "compiler", - expectedText: ` - compiler = "compilerA"`}} - - got, err := Transform(crosstool) - if err != nil { - t.Fatalf("CROSSTOOL conversion failed: %v", err) - } - - failed := false - for _, tc := range testCases { - if !strings.Contains(got, tc.expectedText) { - t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - failed = true - } - } - if failed { - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(toolchains, "\n"), got) - } -} - -func TestNonMandatoryStrings(t *testing.T) { - toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{"cc_target_os: 'osA'"}) - toolchainBB := getCToolchain("2", "cpuB", "compilerB", []string{}) - toolchains := []string{toolchainAA, toolchainBB} - crosstool := makeCrosstool(toolchains) - - testCases := []struct { - field string - expectedText string - }{ - {field: "cc_target_os", - expectedText: ` - if (ctx.attr.cpu == "cpuB"): - cc_target_os = None - elif (ctx.attr.cpu == "cpuA"): - cc_target_os = "osA" - else: - fail("Unreachable")`}, - {field: "builtin_sysroot", - expectedText: ` - builtin_sysroot = None`}} - - got, err := Transform(crosstool) - if err != nil { - t.Fatalf("CROSSTOOL conversion failed: %v", err) - } - - failed := false - for _, tc := range testCases { - if !strings.Contains(got, tc.expectedText) { - t.Errorf("Failed to correctly convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - failed = true - } - } - if failed { - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(toolchains, "\n"), got) - } -} - -func TestBuiltinIncludeDirectories(t *testing.T) { - toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainCA := getCToolchain("3", "cpuC", "compilerA", - []string{"cxx_builtin_include_directory: 'dirC'"}) - toolchainCB := getCToolchain("4", "cpuC", "compilerB", - []string{"cxx_builtin_include_directory: 'dirC'", - "cxx_builtin_include_directory: 'dirB'"}) - toolchainDA := getCToolchain("5", "cpuD", "compilerA", - []string{"cxx_builtin_include_directory: 'dirC'"}) - - toolchainsEmpty := []string{toolchainAA, toolchainBA} - - toolchainsOneNonempty := []string{toolchainAA, toolchainBA, toolchainCA} - - toolchainsSameNonempty := []string{toolchainCA, toolchainDA} - - allToolchains := []string{toolchainAA, toolchainBA, toolchainCA, toolchainCB, toolchainDA} - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "cxx_builtin_include_directories", - toolchains: toolchainsEmpty, - expectedText: ` - cxx_builtin_include_directories = []`}, - {field: "cxx_builtin_include_directories", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - cxx_builtin_include_directories = [] - elif (ctx.attr.cpu == "cpuC"): - cxx_builtin_include_directories = ["dirC"] - else: - fail("Unreachable")`}, - {field: "cxx_builtin_include_directories", - toolchains: toolchainsSameNonempty, - expectedText: ` - cxx_builtin_include_directories = ["dirC"]`}, - {field: "cxx_builtin_include_directories", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - cxx_builtin_include_directories = [] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuD"): - cxx_builtin_include_directories = ["dirC"] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - cxx_builtin_include_directories = ["dirC", "dirB"]`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func TestMakeVariables(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainA1 := getCToolchain("3", "cpuC", "compilerA", - []string{"make_variable {name: 'A', value: 'a/b/c'}"}) - toolchainA2 := getCToolchain("4", "cpuC", "compilerB", - []string{"make_variable {name: 'A', value: 'a/b/c'}"}) - toolchainAB := getCToolchain("5", "cpuC", "compilerC", - []string{"make_variable {name: 'A', value: 'a/b/c'}", - "make_variable {name: 'B', value: 'a/b/c'}"}) - toolchainBA := getCToolchain("6", "cpuD", "compilerA", - []string{"make_variable {name: 'B', value: 'a/b/c'}", - "make_variable {name: 'A', value: 'a b c'}"}) - - toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} - - toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} - - toolchainsSameNonempty := []string{toolchainA1, toolchainA2} - - toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} - - allToolchains := []string{ - toolchainEmpty1, - toolchainEmpty2, - toolchainA1, - toolchainA2, - toolchainAB, - toolchainBA, - } - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "make_variables", - toolchains: toolchainsEmpty, - expectedText: ` - make_variables = []`}, - {field: "make_variables", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - make_variables = [] - elif (ctx.attr.cpu == "cpuC"): - make_variables = [make_variable(name = "A", value = "a/b/c")] - else: - fail("Unreachable")`}, - {field: "make_variables", - toolchains: toolchainsSameNonempty, - expectedText: ` - make_variables = [make_variable(name = "A", value = "a/b/c")]`}, - {field: "make_variables", - toolchains: toolchainsDifferentOrder, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - make_variables = [ - make_variable(name = "A", value = "a/b/c"), - make_variable(name = "B", value = "a/b/c"), - ] - elif (ctx.attr.cpu == "cpuD"): - make_variables = [ - make_variable(name = "B", value = "a/b/c"), - make_variable(name = "A", value = "a b c"), - ] - else: - fail("Unreachable")`}, - {field: "make_variables", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): - make_variables = [ - make_variable(name = "A", value = "a/b/c"), - make_variable(name = "B", value = "a/b/c"), - ] - elif (ctx.attr.cpu == "cpuD"): - make_variables = [ - make_variable(name = "B", value = "a/b/c"), - make_variable(name = "A", value = "a b c"), - ] - elif (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - make_variables = [] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - make_variables = [make_variable(name = "A", value = "a/b/c")] - else: - fail("Unreachable")`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func TestToolPaths(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainA1 := getCToolchain("3", "cpuC", "compilerA", - []string{"tool_path {name: 'A', path: 'a/b/c'}"}) - toolchainA2 := getCToolchain("4", "cpuC", "compilerB", - []string{"tool_path {name: 'A', path: 'a/b/c'}"}) - toolchainAB := getCToolchain("5", "cpuC", "compilerC", - []string{"tool_path {name: 'A', path: 'a/b/c'}", - "tool_path {name: 'B', path: 'a/b/c'}"}) - toolchainBA := getCToolchain("6", "cpuD", "compilerA", - []string{"tool_path {name: 'B', path: 'a/b/c'}", - "tool_path {name: 'A', path: 'a/b/c'}"}) - - toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} - - toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} - - toolchainsSameNonempty := []string{toolchainA1, toolchainA2} - - toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} - - allToolchains := []string{ - toolchainEmpty1, - toolchainEmpty2, - toolchainA1, - toolchainA2, - toolchainAB, - toolchainBA, - } - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "tool_paths", - toolchains: toolchainsEmpty, - expectedText: ` - tool_paths = []`}, - {field: "tool_paths", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - tool_paths = [] - elif (ctx.attr.cpu == "cpuC"): - tool_paths = [tool_path(name = "A", path = "a/b/c")] - else: - fail("Unreachable")`}, - {field: "tool_paths", - toolchains: toolchainsSameNonempty, - expectedText: ` - tool_paths = [tool_path(name = "A", path = "a/b/c")]`}, - {field: "tool_paths", - toolchains: toolchainsDifferentOrder, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - tool_paths = [ - tool_path(name = "A", path = "a/b/c"), - tool_path(name = "B", path = "a/b/c"), - ] - elif (ctx.attr.cpu == "cpuD"): - tool_paths = [ - tool_path(name = "B", path = "a/b/c"), - tool_path(name = "A", path = "a/b/c"), - ] - else: - fail("Unreachable")`}, - {field: "tool_paths", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): - tool_paths = [ - tool_path(name = "A", path = "a/b/c"), - tool_path(name = "B", path = "a/b/c"), - ] - elif (ctx.attr.cpu == "cpuD"): - tool_paths = [ - tool_path(name = "B", path = "a/b/c"), - tool_path(name = "A", path = "a/b/c"), - ] - elif (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - tool_paths = [] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - tool_paths = [tool_path(name = "A", path = "a/b/c")] - else: - fail("Unreachable")`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func getArtifactNamePattern(lines []string) string { - return fmt.Sprintf(`artifact_name_pattern { - %s -}`, strings.Join(lines, "\n ")) -} - -func TestArtifactNamePatterns(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainA1 := getCToolchain("3", "cpuC", "compilerA", - []string{ - getArtifactNamePattern([]string{ - "category_name: 'A'", - "prefix: 'p'", - "extension: '.exe'"}), - }, - ) - toolchainA2 := getCToolchain("4", "cpuC", "compilerB", - []string{ - getArtifactNamePattern([]string{ - "category_name: 'A'", - "prefix: 'p'", - "extension: '.exe'"}), - }, - ) - toolchainAB := getCToolchain("5", "cpuC", "compilerC", - []string{ - getArtifactNamePattern([]string{ - "category_name: 'A'", - "prefix: 'p'", - "extension: '.exe'"}), - getArtifactNamePattern([]string{ - "category_name: 'B'", - "prefix: 'p'", - "extension: '.exe'"}), - }, - ) - toolchainBA := getCToolchain("6", "cpuD", "compilerA", - []string{ - getArtifactNamePattern([]string{ - "category_name: 'B'", - "prefix: 'p'", - "extension: '.exe'"}), - getArtifactNamePattern([]string{ - "category_name: 'A'", - "prefix: 'p'", - "extension: '.exe'"}), - }, - ) - toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} - - toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} - - toolchainsSameNonempty := []string{toolchainA1, toolchainA2} - - toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} - - allToolchains := []string{ - toolchainEmpty1, - toolchainEmpty2, - toolchainA1, - toolchainA2, - toolchainAB, - toolchainBA, - } - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "artifact_name_patterns", - toolchains: toolchainsEmpty, - expectedText: ` - artifact_name_patterns = []`}, - {field: "artifact_name_patterns", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - ] - elif (ctx.attr.cpu == "cpuA"): - artifact_name_patterns = [] - else: - fail("Unreachable")`}, - {field: "artifact_name_patterns", - toolchains: toolchainsSameNonempty, - expectedText: ` - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - ]`}, - {field: "artifact_name_patterns", - toolchains: toolchainsDifferentOrder, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - artifact_name_pattern( - category_name = "B", - prefix = "p", - extension = ".exe", - ), - ] - elif (ctx.attr.cpu == "cpuD"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "B", - prefix = "p", - extension = ".exe", - ), - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - ] - else: - fail("Unreachable")`}, - {field: "artifact_name_patterns", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - artifact_name_pattern( - category_name = "B", - prefix = "p", - extension = ".exe", - ), - ] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - ] - elif (ctx.attr.cpu == "cpuD"): - artifact_name_patterns = [ - artifact_name_pattern( - category_name = "B", - prefix = "p", - extension = ".exe", - ), - artifact_name_pattern( - category_name = "A", - prefix = "p", - extension = ".exe", - ), - ] - elif (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - artifact_name_patterns = [] - else: - fail("Unreachable")`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func getFeature(lines []string) string { - return fmt.Sprintf(`feature { - %s -}`, strings.Join(lines, "\n ")) -} - -func TestFeatureListAssignment(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainA1 := getCToolchain("3", "cpuC", "compilerA", - []string{getFeature([]string{"name: 'A'"})}, - ) - toolchainA2 := getCToolchain("4", "cpuC", "compilerB", - []string{getFeature([]string{"name: 'A'"})}, - ) - toolchainAB := getCToolchain("5", "cpuC", "compilerC", - []string{ - getFeature([]string{"name: 'A'"}), - getFeature([]string{"name: 'B'"}), - }, - ) - toolchainBA := getCToolchain("6", "cpuD", "compilerA", - []string{ - getFeature([]string{"name: 'B'"}), - getFeature([]string{"name: 'A'"}), - }, - ) - toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} - - toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} - - toolchainsSameNonempty := []string{toolchainA1, toolchainA2} - - toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} - - allToolchains := []string{ - toolchainEmpty1, - toolchainEmpty2, - toolchainA1, - toolchainA2, - toolchainAB, - toolchainBA, - } - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "features", - toolchains: toolchainsEmpty, - expectedText: ` - features = []`}, - {field: "features", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - features = [] - elif (ctx.attr.cpu == "cpuC"): - features = [a_feature] - else: - fail("Unreachable")`}, - {field: "features", - toolchains: toolchainsSameNonempty, - expectedText: ` - features = [a_feature]`}, - {field: "features", - toolchains: toolchainsDifferentOrder, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - features = [a_feature, b_feature] - elif (ctx.attr.cpu == "cpuD"): - features = [b_feature, a_feature] - else: - fail("Unreachable")`}, - {field: "features", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - features = [] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - features = [a_feature] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): - features = [a_feature, b_feature] - elif (ctx.attr.cpu == "cpuD"): - features = [b_feature, a_feature] - else: - fail("Unreachable")`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func getActionConfig(lines []string) string { - return fmt.Sprintf(`action_config { - %s -}`, strings.Join(lines, "\n ")) -} - -func TestActionConfigListAssignment(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainA1 := getCToolchain("3", "cpuC", "compilerA", - []string{ - getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), - }, - ) - toolchainA2 := getCToolchain("4", "cpuC", "compilerB", - []string{ - getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), - }, - ) - toolchainAB := getCToolchain("5", "cpuC", "compilerC", - []string{ - getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), - getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}), - }, - ) - toolchainBA := getCToolchain("6", "cpuD", "compilerA", - []string{ - getActionConfig([]string{"action_name: 'B'", "config_name: 'B'"}), - getActionConfig([]string{"action_name: 'A'", "config_name: 'A'"}), - }, - ) - toolchainsEmpty := []string{toolchainEmpty1, toolchainEmpty2} - - toolchainsOneNonempty := []string{toolchainEmpty1, toolchainA1} - - toolchainsSameNonempty := []string{toolchainA1, toolchainA2} - - toolchainsDifferentOrder := []string{toolchainAB, toolchainBA} - - allToolchains := []string{ - toolchainEmpty1, - toolchainEmpty2, - toolchainA1, - toolchainA2, - toolchainAB, - toolchainBA, - } - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "action_configs", - toolchains: toolchainsEmpty, - expectedText: ` - action_configs = []`}, - {field: "action_configs", - toolchains: toolchainsOneNonempty, - expectedText: ` - if (ctx.attr.cpu == "cpuA"): - action_configs = [] - elif (ctx.attr.cpu == "cpuC"): - action_configs = [a_action] - else: - fail("Unreachable")`}, - {field: "action_configs", - toolchains: toolchainsSameNonempty, - expectedText: ` - action_configs = [a_action]`}, - {field: "action_configs", - toolchains: toolchainsDifferentOrder, - expectedText: ` - if (ctx.attr.cpu == "cpuC"): - action_configs = [a_action, b_action] - elif (ctx.attr.cpu == "cpuD"): - action_configs = [b_action, a_action] - else: - fail("Unreachable")`}, - {field: "action_configs", - toolchains: allToolchains, - expectedText: ` - if (ctx.attr.cpu == "cpuA" - or ctx.attr.cpu == "cpuB"): - action_configs = [] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerA" - or ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - action_configs = [a_action] - elif (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerC"): - action_configs = [a_action, b_action] - elif (ctx.attr.cpu == "cpuD"): - action_configs = [b_action, a_action] - else: - fail("Unreachable")`}} - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func TestAllAndNoneAvailableErrorsWhenMoreThanOneElement(t *testing.T) { - toolchainFeatureAllAvailable := getCToolchain("1", "cpu", "compiler", - []string{getFeature([]string{ - "name: 'A'", - "flag_set {", - " action: 'A'", - " flag_group {", - " flag: 'f'", - " expand_if_all_available: 'e1'", - " expand_if_all_available: 'e2'", - " }", - "}", - })}, - ) - toolchainFeatureNoneAvailable := getCToolchain("1", "cpu", "compiler", - []string{getFeature([]string{ - "name: 'A'", - "flag_set {", - " action: 'A'", - " flag_group {", - " flag: 'f'", - " expand_if_none_available: 'e1'", - " expand_if_none_available: 'e2'", - " }", - "}", - })}, - ) - toolchainActionConfigAllAvailable := getCToolchain("1", "cpu", "compiler", - []string{getActionConfig([]string{ - "config_name: 'A'", - "action_name: 'A'", - "flag_set {", - " action: 'A'", - " flag_group {", - " flag: 'f'", - " expand_if_all_available: 'e1'", - " expand_if_all_available: 'e2'", - " }", - "}", - })}, - ) - toolchainActionConfigNoneAvailable := getCToolchain("1", "cpu", "compiler", - []string{getActionConfig([]string{ - "config_name: 'A'", - "action_name: 'A'", - "flag_set {", - " action: 'A'", - " flag_group {", - " flag: 'f'", - " expand_if_none_available: 'e1'", - " expand_if_none_available: 'e2'", - " }", - "}", - })}, - ) - - testCases := []struct { - field string - toolchain string - expectedText string - }{ - {field: "features", - toolchain: toolchainFeatureAllAvailable, - expectedText: "Error in feature 'A': Flag group must not have more " + - "than one 'expand_if_all_available' field"}, - {field: "features", - toolchain: toolchainFeatureNoneAvailable, - expectedText: "Error in feature 'A': Flag group must not have more " + - "than one 'expand_if_none_available' field"}, - {field: "action_configs", - toolchain: toolchainActionConfigAllAvailable, - expectedText: "Error in action_config 'A': Flag group must not have more " + - "than one 'expand_if_all_available' field"}, - {field: "action_configs", - toolchain: toolchainActionConfigNoneAvailable, - expectedText: "Error in action_config 'A': Flag group must not have more " + - "than one 'expand_if_none_available' field"}, - } - - for _, tc := range testCases { - crosstool := makeCrosstool([]string{tc.toolchain}) - _, err := Transform(crosstool) - if err == nil || !strings.Contains(err.Error(), tc.expectedText) { - t.Errorf("Expected error: %s, got: %v", tc.expectedText, err) - } - } -} - -func TestFeaturesAndActionConfigsSetToNoneWhenAllOptionsAreExausted(t *testing.T) { - toolchainFeatureAEnabled := getCToolchain("1", "cpuA", "compilerA", - []string{getFeature([]string{"name: 'A'", "enabled: true"})}, - ) - toolchainFeatureADisabled := getCToolchain("2", "cpuA", "compilerB", - []string{getFeature([]string{"name: 'A'", "enabled: false"})}, - ) - - toolchainWithoutFeatureA := getCToolchain("3", "cpuA", "compilerC", []string{}) - - toolchainActionConfigAEnabled := getCToolchain("4", "cpuA", "compilerD", - []string{getActionConfig([]string{ - "config_name: 'A'", - "action_name: 'A'", - "enabled: true", - })}) - - toolchainActionConfigADisabled := getCToolchain("5", "cpuA", "compilerE", - []string{getActionConfig([]string{ - "config_name: 'A'", - "action_name: 'A'", - })}) - - toolchainWithoutActionConfigA := getCToolchain("6", "cpuA", "compilerF", []string{}) - - testCases := []struct { - field string - toolchains []string - expectedText string - }{ - {field: "features", - toolchains: []string{ - toolchainFeatureAEnabled, toolchainFeatureADisabled, toolchainWithoutFeatureA}, - expectedText: ` - if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerB"): - a_feature = feature(name = "A") - elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerA"): - a_feature = feature(name = "A", enabled = True) - else: - a_feature = None -`}, - {field: "action_config", - toolchains: []string{ - toolchainActionConfigAEnabled, toolchainActionConfigADisabled, toolchainWithoutActionConfigA}, - expectedText: ` - if (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerE"): - a_action = action_config(action_name = "A") - elif (ctx.attr.cpu == "cpuA" and ctx.attr.compiler == "compilerD"): - a_action = action_config(action_name = "A", enabled = True) - else: - a_action = None -`}, - } - - 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 convert '%s' field, expected to contain:\n%v\n", - tc.field, tc.expectedText) - t.Fatalf("Tested CROSSTOOL:\n%v\n\nGenerated rule:\n%v\n", - strings.Join(tc.toolchains, "\n"), got) - } - } -} - -func TestActionConfigDeclaration(t *testing.T) { - toolchainEmpty1 := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainEmpty2 := getCToolchain("2", "cpuB", "compilerA", []string{}) - - toolchainNameNotInDict := getCToolchain("3", "cpBC", "compilerB", - []string{ - getActionConfig([]string{"action_name: 'A-B.C'", "config_name: 'A-B.C'"}), - }, - ) - toolchainNameInDictA := getCToolchain("4", "cpuC", "compilerA", - []string{ - getActionConfig([]string{"action_name: 'c++-compile'", "config_name: 'c++-compile'"}), - }, - ) - toolchainNameInDictB := getCToolchain("5", "cpuC", "compilerB", - []string{ - getActionConfig([]string{ - "action_name: 'c++-compile'", - "config_name: 'c++-compile'", - "tool {", - " tool_path: '/a/b/c'", - "}", - }), - }, - ) - toolchainComplexActionConfig := getCToolchain("6", "cpuC", "compilerC", - []string{ - getActionConfig([]string{ - "action_name: 'action-complex'", - "config_name: 'action-complex'", - "enabled: true", - "tool {", - " tool_path: '/a/b/c'", - " with_feature {", - " feature: 'a'", - " feature: 'b'", - " not_feature: 'c'", - " not_feature: 'd'", - " }", - " with_feature{", - " feature: 'e'", - " }", - " execution_requirement: 'a'", - "}", - "tool {", - " tool_path: ''", - "}", - "flag_set {", - " 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 {", - " with_feature {", - " feature: 'a'", - " feature: 'b'", - " not_feature: 'c'", - " not_feature: 'd'", - " }", - "}", - "env_set {", - " action: 'a'", - " env_entry {", - " key: 'k'", - " value: 'v'", - " }", - " with_feature {", - " feature: 'a'", - " }", - "}", - "requires {", - " feature: 'a'", - " feature: 'b'", - "}", - "implies: 'a'", - "implies: 'b'", - }), - }, - ) - - testCases := []struct { - toolchains []string - expectedText string - }{ - { - toolchains: []string{toolchainEmpty1, toolchainEmpty2}, - expectedText: ` - action_configs = []`}, - { - toolchains: []string{toolchainEmpty1, toolchainNameNotInDict}, - expectedText: ` - a_b_c_action = action_config(action_name = "A-B.C")`}, - { - toolchains: []string{toolchainNameInDictA, toolchainNameInDictB}, - expectedText: ` - if (ctx.attr.cpu == "cpuC" and ctx.attr.compiler == "compilerB"): - 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_compile_action = action_config(action_name = ACTION_NAMES.cpp_compile)`}, - { - toolchains: []string{toolchainComplexActionConfig}, - expectedText: ` - action_complex_action = action_config( - action_name = "action-complex", - enabled = True, - flag_sets = [ - flag_set( - 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( - with_features = [ - with_feature_set( - features = ["a", "b"], - not_features = ["c", "d"], - ), - ], - ), - ], - implies = ["a", "b"], - tools = [ - tool( - path = "/a/b/c", - with_features = [ - with_feature_set( - features = ["a", "b"], - not_features = ["c", "d"], - ), - with_feature_set(features = ["e"]), - ], - execution_requirements = ["a"], - ), - tool(path = "NOT_USED"), - ], - )`}} - - 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 an action_config, 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) - } - } -} - -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) - } - } -} - -func TestRule(t *testing.T) { - simpleToolchain := getSimpleCToolchain("simple") - expected := `load("@rules_cc//cc: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", -) -load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") - -def _impl(ctx): - toolchain_identifier = "id-simple" - - host_system_name = "host-simple" - - target_system_name = "target-simple" - - target_cpu = "cpu-simple" - - target_libc = "libc-simple" - - compiler = "compiler-simple" - - abi_version = "version-simple" - - abi_libc_version = "libc_version-simple" - - cc_target_os = None - - builtin_sysroot = None - - all_compile_actions = [ - ACTION_NAMES.c_compile, - ACTION_NAMES.cpp_compile, - ACTION_NAMES.linkstamp_compile, - ACTION_NAMES.assemble, - ACTION_NAMES.preprocess_assemble, - ACTION_NAMES.cpp_header_parsing, - ACTION_NAMES.cpp_module_compile, - ACTION_NAMES.cpp_module_codegen, - ACTION_NAMES.clif_match, - ACTION_NAMES.lto_backend, - ] - - all_cpp_compile_actions = [ - ACTION_NAMES.cpp_compile, - ACTION_NAMES.linkstamp_compile, - ACTION_NAMES.cpp_header_parsing, - ACTION_NAMES.cpp_module_compile, - ACTION_NAMES.cpp_module_codegen, - ACTION_NAMES.clif_match, - ] - - preprocessor_compile_actions = [ - ACTION_NAMES.c_compile, - ACTION_NAMES.cpp_compile, - ACTION_NAMES.linkstamp_compile, - ACTION_NAMES.preprocess_assemble, - ACTION_NAMES.cpp_header_parsing, - ACTION_NAMES.cpp_module_compile, - ACTION_NAMES.clif_match, - ] - - codegen_compile_actions = [ - ACTION_NAMES.c_compile, - ACTION_NAMES.cpp_compile, - ACTION_NAMES.linkstamp_compile, - ACTION_NAMES.assemble, - ACTION_NAMES.preprocess_assemble, - ACTION_NAMES.cpp_module_codegen, - ACTION_NAMES.lto_backend, - ] - - all_link_actions = [ - ACTION_NAMES.cpp_link_executable, - ACTION_NAMES.cpp_link_dynamic_library, - ACTION_NAMES.cpp_link_nodeps_dynamic_library, - ] - - action_configs = [] - - features = [] - - cxx_builtin_include_directories = [] - - artifact_name_patterns = [] - - make_variables = [] - - tool_paths = [] - - - 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, - ), - ] -cc_toolchain_config = rule( - implementation = _impl, - attrs = { - "cpu": attr.string(mandatory=True, values=["cpu-simple"]), - }, - provides = [CcToolchainConfigInfo], - executable = True, -) -` - crosstool := makeCrosstool([]string{simpleToolchain}) - got, err := Transform(crosstool) - if err != nil { - t.Fatalf("CROSSTOOL conversion failed: %v", err) - } - if got != expected { - t.Fatalf("Expected:\n%v\nGot:\n%v\nTested CROSSTOOL:\n%v", - expected, got, simpleToolchain) - } -} - -func TestAllowedCompilerValues(t *testing.T) { - toolchainAA := getCToolchain("1", "cpuA", "compilerA", []string{}) - toolchainBA := getCToolchain("2", "cpuB", "compilerA", []string{}) - toolchainBB := getCToolchain("3", "cpuB", "compilerB", []string{}) - toolchainCC := getCToolchain("4", "cpuC", "compilerC", []string{}) - - testCases := []struct { - toolchains []string - expectedText string - }{ - { - toolchains: []string{toolchainAA, toolchainBA}, - expectedText: ` -cc_toolchain_config = rule( - implementation = _impl, - attrs = { - "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]), - }, - provides = [CcToolchainConfigInfo], - executable = True, -) -`}, - { - toolchains: []string{toolchainBA, toolchainBB}, - expectedText: ` -cc_toolchain_config = rule( - implementation = _impl, - attrs = { - "cpu": attr.string(mandatory=True, values=["cpuB"]), - "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]), - }, - provides = [CcToolchainConfigInfo], - executable = True, -) -`}, - { - toolchains: []string{toolchainAA, toolchainBA, toolchainBB}, - expectedText: ` -cc_toolchain_config = rule( - implementation = _impl, - attrs = { - "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB"]), - "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB"]), - }, - provides = [CcToolchainConfigInfo], - executable = True, -) -`}, - { - toolchains: []string{toolchainAA, toolchainBA, toolchainBB, toolchainCC}, - expectedText: ` -cc_toolchain_config = rule( - implementation = _impl, - attrs = { - "cpu": attr.string(mandatory=True, values=["cpuA", "cpuB", "cpuC"]), - "compiler": attr.string(mandatory=True, values=["compilerA", "compilerB", "compilerC"]), - }, - provides = [CcToolchainConfigInfo], - executable = True, -) -`}} - - 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 the rule, 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) - } - } -} diff --git a/tools/migration/ctoolchain_comparator.py b/tools/migration/ctoolchain_comparator.py deleted file mode 100644 index 5143e02..0000000 --- a/tools/migration/ctoolchain_comparator.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -r"""A script that compares 2 CToolchains from proto format. - -This script accepts two files in either a CROSSTOOL proto text format or a -CToolchain proto text format. It then locates the CToolchains with the given -toolchain_identifier and checks if the resulting CToolchain objects in Java -are the same. - -Example usage: - -bazel run \ -@rules_cc//tools/migration:ctoolchain_comparator -- \ ---before=/path/to/CROSSTOOL1 \ ---after=/path/to/CROSSTOOL2 \ ---toolchain_identifier=id -""" - -import os -from absl import app -from absl import flags -from google.protobuf import text_format -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 -from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains - -flags.DEFINE_string( - "before", None, - ("A text proto file containing the relevant CTooclchain before the change, " - "either a CROSSTOOL file or a single CToolchain proto text")) -flags.DEFINE_string( - "after", None, - ("A text proto file containing the relevant CToolchain after the change, " - "either a CROSSTOOL file or a single CToolchain proto text")) -flags.DEFINE_string("toolchain_identifier", None, - "The identifier of the CToolchain that is being compared.") -flags.mark_flag_as_required("before") -flags.mark_flag_as_required("after") - - -def _to_absolute_path(path): - path = os.path.expanduser(path) - if os.path.isabs(path): - return path - else: - if "BUILD_WORKING_DIRECTORY" in os.environ: - return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) - else: - return path - - -def _find_toolchain(crosstool, toolchain_identifier): - for toolchain in crosstool.toolchain: - if toolchain.toolchain_identifier == toolchain_identifier: - return toolchain - return None - - -def _read_crosstool_or_ctoolchain_proto(input_file, toolchain_identifier=None): - """Reads a proto file and finds the CToolchain with the given identifier.""" - with open(input_file, "r") as f: - text = f.read() - crosstool_release = crosstool_config_pb2.CrosstoolRelease() - c_toolchain = crosstool_config_pb2.CToolchain() - try: - text_format.Merge(text, crosstool_release) - if toolchain_identifier is None: - print("CROSSTOOL proto needs a 'toolchain_identifier' specified in " - "order to be able to select the right toolchain for comparison.") - return None - toolchain = _find_toolchain(crosstool_release, toolchain_identifier) - if toolchain is None: - print(("Cannot find a CToolchain with an identifier '%s' in CROSSTOOL " - "file") % toolchain_identifier) - return None - return toolchain - except text_format.ParseError as crosstool_error: - try: - text_format.Merge(text, c_toolchain) - if (toolchain_identifier is not None and - c_toolchain.toolchain_identifier != toolchain_identifier): - print(("Expected CToolchain with identifier '%s', got CToolchain with " - "identifier '%s'" % (toolchain_identifier, - c_toolchain.toolchain_identifier))) - return None - return c_toolchain - except text_format.ParseError as toolchain_error: - print(("Error parsing file '%s':" % input_file)) # pylint: disable=superfluous-parens - print("Attempt to parse it as a CROSSTOOL proto:") # pylint: disable=superfluous-parens - print(crosstool_error) # pylint: disable=superfluous-parens - print("Attempt to parse it as a CToolchain proto:") # pylint: disable=superfluous-parens - print(toolchain_error) # pylint: disable=superfluous-parens - return None - - -def main(unused_argv): - - before_file = _to_absolute_path(flags.FLAGS.before) - after_file = _to_absolute_path(flags.FLAGS.after) - toolchain_identifier = flags.FLAGS.toolchain_identifier - - toolchain_before = _read_crosstool_or_ctoolchain_proto( - before_file, toolchain_identifier) - toolchain_after = _read_crosstool_or_ctoolchain_proto(after_file, - toolchain_identifier) - - if not toolchain_before or not toolchain_after: - print("There was an error getting the required toolchains.") - exit(1) - - found_difference = compare_ctoolchains(toolchain_before, toolchain_after) - if found_difference: - exit(1) - - -if __name__ == "__main__": - app.run(main) diff --git a/tools/migration/ctoolchain_comparator_lib.py b/tools/migration/ctoolchain_comparator_lib.py deleted file mode 100644 index eb47305..0000000 --- a/tools/migration/ctoolchain_comparator_lib.py +++ /dev/null @@ -1,523 +0,0 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -"""Module providing compare_ctoolchains function. - -compare_ctoolchains takes in two parsed CToolchains and compares them -""" - - -def _print_difference(field_name, before_value, after_value): - if not before_value and after_value: - print(("Difference in '%s' field:\nValue before change is not set\n" - "Value after change is set to '%s'") % (field_name, after_value)) - elif before_value and not after_value: - print(("Difference in '%s' field:\nValue before change is set to '%s'\n" - "Value after change is not set") % (field_name, before_value)) - else: - print(("Difference in '%s' field:\nValue before change:\t'%s'\n" - "Value after change:\t'%s'\n") % (field_name, before_value, - after_value)) - - -def _array_to_string(arr, ordered=False): - if not arr: - return "[]" - elif len(arr) == 1: - return "[" + list(arr)[0] + "]" - if not ordered: - return "[\n\t%s\n]" % "\n\t".join(arr) - else: - return "[\n\t%s\n]" % "\n\t".join(sorted(list(arr))) - - -def _check_with_feature_set_equivalence(before, after): - before_set = set() - after_set = set() - for el in before: - before_set.add((str(set(el.feature)), str(set(el.not_feature)))) - for el in after: - after_set.add((str(set(el.feature)), str(set(el.not_feature)))) - return before_set == after_set - - -def _check_tool_equivalence(before, after): - """Compares two "CToolchain.Tool"s.""" - if before.tool_path == "NOT_USED": - before.tool_path = "" - if after.tool_path == "NOT_USED": - after.tool_path = "" - if before.tool_path != after.tool_path: - return False - if set(before.execution_requirement) != set(after.execution_requirement): - return False - if not _check_with_feature_set_equivalence(before.with_feature, - after.with_feature): - return False - return True - - -def _check_flag_group_equivalence(before, after): - """Compares two "CToolchain.FlagGroup"s.""" - if before.flag != after.flag: - return False - if before.expand_if_true != after.expand_if_true: - return False - if before.expand_if_false != after.expand_if_false: - return False - if set(before.expand_if_all_available) != set(after.expand_if_all_available): - return False - if set(before.expand_if_none_available) != set( - after.expand_if_none_available): - return False - if before.iterate_over != after.iterate_over: - return False - if before.expand_if_equal != after.expand_if_equal: - return False - if len(before.flag_group) != len(after.flag_group): - return False - for (flag_group_before, flag_group_after) in zip(before.flag_group, - after.flag_group): - if not _check_flag_group_equivalence(flag_group_before, flag_group_after): - return False - return True - - -def _check_flag_set_equivalence(before, after, in_action_config=False): - """Compares two "CToolchain.FlagSet"s.""" - # ActionConfigs in proto format do not have a 'FlagSet.action' field set. - # Instead, when construction the Java ActionConfig object, we set the - # flag_set.action field to the action name. This currently causes the - # CcToolchainConfigInfo.proto to generate a CToolchain.ActionConfig that still - # has the action name in the FlagSet.action field, therefore we don't compare - # the FlagSet.action field when comparing flag_sets that belong to an - # ActionConfig. - if not in_action_config and set(before.action) != set(after.action): - return False - if not _check_with_feature_set_equivalence(before.with_feature, - after.with_feature): - return False - if len(before.flag_group) != len(after.flag_group): - return False - for (flag_group_before, flag_group_after) in zip(before.flag_group, - after.flag_group): - if not _check_flag_group_equivalence(flag_group_before, flag_group_after): - return False - return True - - -def _check_action_config_equivalence(before, after): - """Compares two "CToolchain.ActionConfig"s.""" - if before.config_name != after.config_name: - return False - if before.action_name != after.action_name: - return False - if before.enabled != after.enabled: - return False - if len(before.tool) != len(after.tool): - return False - for (tool_before, tool_after) in zip(before.tool, after.tool): - if not _check_tool_equivalence(tool_before, tool_after): - return False - if before.implies != after.implies: - return False - if len(before.flag_set) != len(after.flag_set): - return False - for (flag_set_before, flag_set_after) in zip(before.flag_set, after.flag_set): - if not _check_flag_set_equivalence(flag_set_before, flag_set_after, True): - return False - return True - - -def _check_env_set_equivalence(before, after): - """Compares two "CToolchain.EnvSet"s.""" - if set(before.action) != set(after.action): - return False - if not _check_with_feature_set_equivalence(before.with_feature, - after.with_feature): - return False - if before.env_entry != after.env_entry: - return False - return True - - -def _check_feature_equivalence(before, after): - """Compares two "CToolchain.Feature"s.""" - if before.name != after.name: - return False - if before.enabled != after.enabled: - return False - if len(before.flag_set) != len(after.flag_set): - return False - for (flag_set_before, flag_set_after) in zip(before.flag_set, after.flag_set): - if not _check_flag_set_equivalence(flag_set_before, flag_set_after): - return False - if len(before.env_set) != len(after.env_set): - return False - for (env_set_before, env_set_after) in zip(before.env_set, after.env_set): - if not _check_env_set_equivalence(env_set_before, env_set_after): - return False - if len(before.requires) != len(after.requires): - return False - for (requires_before, requires_after) in zip(before.requires, after.requires): - if set(requires_before.feature) != set(requires_after.feature): - return False - if before.implies != after.implies: - return False - if before.provides != after.provides: - return False - return True - - -def _compare_features(features_before, features_after): - """Compares two "CToolchain.FlagFeature" lists.""" - feature_name_to_feature_before = {} - feature_name_to_feature_after = {} - for feature in features_before: - feature_name_to_feature_before[feature.name] = feature - for feature in features_after: - feature_name_to_feature_after[feature.name] = feature - - feature_names_before = set(feature_name_to_feature_before.keys()) - feature_names_after = set(feature_name_to_feature_after.keys()) - - before_after_diff = feature_names_before - feature_names_after - after_before_diff = feature_names_after - feature_names_before - - diff_string = "Difference in 'feature' field:" - found_difference = False - if before_after_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List before change contains entries for the following features " - "that the list after the change doesn't:\n%s") % _array_to_string( - before_after_diff, ordered=True)) - if after_before_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List after change contains entries for the following features " - "that the list before the change doesn't:\n%s") % _array_to_string( - after_before_diff, ordered=True)) - - names_before = [feature.name for feature in features_before] - names_after = [feature.name for feature in features_after] - if names_before != names_after: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("Features not in right order:\n" - "* List of features before change:\t%s" - "* List of features before change:\t%s") % - (_array_to_string(names_before), _array_to_string(names_after))) - for name in feature_name_to_feature_before: - feature_before = feature_name_to_feature_before[name] - feature_after = feature_name_to_feature_after.get(name, None) - if feature_after and not _check_feature_equivalence(feature_before, - feature_after): - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* Feature '%s' differs before and after the change:\n" - "Value before change:\n%s\n" - "Value after change:\n%s") % (name, str(feature_before), - str(feature_after))) - if found_difference: - print("") # pylint: disable=superfluous-parens - return found_difference - - -def _compare_action_configs(action_configs_before, action_configs_after): - """Compares two "CToolchain.ActionConfig" lists.""" - action_name_to_action_before = {} - action_name_to_action_after = {} - for action_config in action_configs_before: - action_name_to_action_before[action_config.config_name] = action_config - for action_config in action_configs_after: - action_name_to_action_after[action_config.config_name] = action_config - - config_names_before = set(action_name_to_action_before.keys()) - config_names_after = set(action_name_to_action_after.keys()) - - before_after_diff = config_names_before - config_names_after - after_before_diff = config_names_after - config_names_before - - diff_string = "Difference in 'action_config' field:" - found_difference = False - if before_after_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List before change contains entries for the following " - "action_configs that the list after the change doesn't:\n%s") % - _array_to_string(before_after_diff, ordered=True)) - if after_before_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List after change contains entries for the following " - "action_configs that the list before the change doesn't:\n%s") % - _array_to_string(after_before_diff, ordered=True)) - - names_before = [config.config_name for config in action_configs_before] - names_after = [config.config_name for config in action_configs_after] - if names_before != names_after: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("Action configs not in right order:\n" - "* List of action configs before change:\t%s" - "* List of action_configs before change:\t%s") % - (_array_to_string(names_before), _array_to_string(names_after))) - for name in config_names_before: - action_config_before = action_name_to_action_before[name] - action_config_after = action_name_to_action_after.get(name, None) - if action_config_after and not _check_action_config_equivalence( - action_config_before, action_config_after): - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* Action config '%s' differs before and after the change:\n" - "Value before change:\n%s\n" - "Value after change:\n%s") % (name, str(action_config_before), - str(action_config_after))) - if found_difference: - print("") # pylint: disable=superfluous-parens - return found_difference - - -def _compare_tool_paths(tool_paths_before, tool_paths_after): - """Compares two "CToolchain.ToolPath" lists.""" - tool_to_path_before = {} - tool_to_path_after = {} - for tool_path in tool_paths_before: - tool_to_path_before[tool_path.name] = ( - tool_path.path if tool_path.path != "NOT_USED" else "") - for tool_path in tool_paths_after: - tool_to_path_after[tool_path.name] = ( - tool_path.path if tool_path.path != "NOT_USED" else "") - - tool_names_before = set(tool_to_path_before.keys()) - tool_names_after = set(tool_to_path_after.keys()) - - before_after_diff = tool_names_before - tool_names_after - after_before_diff = tool_names_after - tool_names_before - - diff_string = "Difference in 'tool_path' field:" - found_difference = False - if before_after_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List before change contains entries for the following tools " - "that the list after the change doesn't:\n%s") % _array_to_string( - before_after_diff, ordered=True)) - if after_before_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List after change contains entries for the following tools that " - "the list before the change doesn't:\n%s") % _array_to_string( - after_before_diff, ordered=True)) - - for tool in tool_to_path_before: - path_before = tool_to_path_before[tool] - path_after = tool_to_path_after.get(tool, None) - if path_after and path_after != path_before: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* Path for tool '%s' differs before and after the change:\n" - "Value before change:\t'%s'\n" - "Value after change:\t'%s'") % (tool, path_before, path_after)) - if found_difference: - print("") # pylint: disable=superfluous-parens - return found_difference - - -def _compare_make_variables(make_variables_before, make_variables_after): - """Compares two "CToolchain.MakeVariable" lists.""" - name_to_variable_before = {} - name_to_variable_after = {} - for variable in make_variables_before: - name_to_variable_before[variable.name] = variable.value - for variable in make_variables_after: - name_to_variable_after[variable.name] = variable.value - - variable_names_before = set(name_to_variable_before.keys()) - variable_names_after = set(name_to_variable_after.keys()) - - before_after_diff = variable_names_before - variable_names_after - after_before_diff = variable_names_after - variable_names_before - - diff_string = "Difference in 'make_variable' field:" - found_difference = False - if before_after_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List before change contains entries for the following variables " - "that the list after the change doesn't:\n%s") % _array_to_string( - before_after_diff, ordered=True)) - if after_before_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List after change contains entries for the following variables " - "that the list before the change doesn't:\n%s") % _array_to_string( - after_before_diff, ordered=True)) - - for variable in name_to_variable_before: - value_before = name_to_variable_before[variable] - value_after = name_to_variable_after.get(variable, None) - if value_after and value_after != value_before: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print( - ("* Value for variable '%s' differs before and after the change:\n" - "Value before change:\t'%s'\n" - "Value after change:\t'%s'") % (variable, value_before, value_after)) - if found_difference: - print("") # pylint: disable=superfluous-parens - return found_difference - - -def _compare_cxx_builtin_include_directories(directories_before, - directories_after): - if directories_before != directories_after: - print(("Difference in 'cxx_builtin_include_directory' field:\n" - "List of elements before change:\n%s\n" - "List of elements after change:\n%s\n") % - (_array_to_string(directories_before), - _array_to_string(directories_after))) - return True - return False - - -def _compare_artifact_name_patterns(artifact_name_patterns_before, - artifact_name_patterns_after): - """Compares two "CToolchain.ArtifactNamePattern" lists.""" - category_to_values_before = {} - category_to_values_after = {} - for name_pattern in artifact_name_patterns_before: - category_to_values_before[name_pattern.category_name] = ( - name_pattern.prefix, name_pattern.extension) - for name_pattern in artifact_name_patterns_after: - category_to_values_after[name_pattern.category_name] = ( - name_pattern.prefix, name_pattern.extension) - - category_names_before = set(category_to_values_before.keys()) - category_names_after = set(category_to_values_after.keys()) - - before_after_diff = category_names_before - category_names_after - after_before_diff = category_names_after - category_names_before - - diff_string = "Difference in 'artifact_name_pattern' field:" - found_difference = False - if before_after_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List before change contains entries for the following categories " - "that the list after the change doesn't:\n%s") % _array_to_string( - before_after_diff, ordered=True)) - if after_before_diff: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* List after change contains entries for the following categories " - "that the list before the change doesn't:\n%s") % _array_to_string( - after_before_diff, ordered=True)) - - for category in category_to_values_before: - value_before = category_to_values_before[category] - value_after = category_to_values_after.get(category, None) - if value_after and value_after != value_before: - if not found_difference: - print(diff_string) # pylint: disable=superfluous-parens - found_difference = True - print(("* Value for category '%s' differs before and after the change:\n" - "Value before change:\tprefix:'%s'\textension:'%s'\n" - "Value after change:\tprefix:'%s'\textension:'%s'") % - (category, value_before[0], value_before[1], value_after[0], - value_after[1])) - if found_difference: - print("") # pylint: disable=superfluous-parens - return found_difference - - -def compare_ctoolchains(toolchain_before, toolchain_after): - """Compares two CToolchains.""" - found_difference = False - if (toolchain_before.toolchain_identifier != - toolchain_after.toolchain_identifier): - _print_difference("toolchain_identifier", - toolchain_before.toolchain_identifier, - toolchain_after.toolchain_identifier) - if toolchain_before.host_system_name != toolchain_after.host_system_name: - _print_difference("host_system_name", toolchain_before.host_system_name, - toolchain_after.host_system_name) - found_difference = True - if toolchain_before.target_system_name != toolchain_after.target_system_name: - _print_difference("target_system_name", toolchain_before.target_system_name, - toolchain_after.target_system_name) - found_difference = True - if toolchain_before.target_cpu != toolchain_after.target_cpu: - _print_difference("target_cpu", toolchain_before.target_cpu, - toolchain_after.target_cpu) - found_difference = True - if toolchain_before.target_libc != toolchain_after.target_libc: - _print_difference("target_libc", toolchain_before.target_libc, - toolchain_after.target_libc) - found_difference = True - if toolchain_before.compiler != toolchain_after.compiler: - _print_difference("compiler", toolchain_before.compiler, - toolchain_after.compiler) - found_difference = True - if toolchain_before.abi_version != toolchain_after.abi_version: - _print_difference("abi_version", toolchain_before.abi_version, - toolchain_after.abi_version) - found_difference = True - if toolchain_before.abi_libc_version != toolchain_after.abi_libc_version: - _print_difference("abi_libc_version", toolchain_before.abi_libc_version, - toolchain_after.abi_libc_version) - found_difference = True - if toolchain_before.cc_target_os != toolchain_after.cc_target_os: - _print_difference("cc_target_os", toolchain_before.cc_target_os, - toolchain_after.cc_target_os) - found_difference = True - if toolchain_before.builtin_sysroot != toolchain_after.builtin_sysroot: - _print_difference("builtin_sysroot", toolchain_before.builtin_sysroot, - toolchain_after.builtin_sysroot) - found_difference = True - found_difference = _compare_features( - toolchain_before.feature, toolchain_after.feature) or found_difference - found_difference = _compare_action_configs( - toolchain_before.action_config, - toolchain_after.action_config) or found_difference - found_difference = _compare_tool_paths( - toolchain_before.tool_path, toolchain_after.tool_path) or found_difference - found_difference = _compare_cxx_builtin_include_directories( - toolchain_before.cxx_builtin_include_directory, - toolchain_after.cxx_builtin_include_directory) or found_difference - found_difference = _compare_make_variables( - toolchain_before.make_variable, - toolchain_after.make_variable) or found_difference - found_difference = _compare_artifact_name_patterns( - toolchain_before.artifact_name_pattern, - toolchain_after.artifact_name_pattern) or found_difference - if not found_difference: - print("No difference") # pylint: disable=superfluous-parens - return found_difference diff --git a/tools/migration/ctoolchain_comparator_lib_test.py b/tools/migration/ctoolchain_comparator_lib_test.py deleted file mode 100644 index 1a3a270..0000000 --- a/tools/migration/ctoolchain_comparator_lib_test.py +++ /dev/null @@ -1,1821 +0,0 @@ -# Copyright 2018 The Bazel Authors. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import unittest - -from py import mock - -from google.protobuf import text_format -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 -from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains - -try: - # Python 2 - from cStringIO import StringIO -except ImportError: - # Python 3 - from io import StringIO - - -def make_toolchain(toolchain_proto): - toolchain = crosstool_config_pb2.CToolchain() - text_format.Merge(toolchain_proto, toolchain) - return toolchain - - -class CtoolchainComparatorLibTest(unittest.TestCase): - - def test_string_fields(self): - first = make_toolchain(""" - toolchain_identifier: "first-id" - host_system_name: "first-host" - target_system_name: "first-target" - target_cpu: "first-cpu" - target_libc: "first-libc" - compiler: "first-compiler" - abi_version: "first-abi" - abi_libc_version: "first-abi-libc" - builtin_sysroot: "sysroot" - """) - second = make_toolchain(""" - toolchain_identifier: "second-id" - host_system_name: "second-host" - target_system_name: "second-target" - target_cpu: "second-cpu" - target_libc: "second-libc" - compiler: "second-compiler" - abi_version: "second-abi" - abi_libc_version: "second-abi-libc" - cc_target_os: "os" - """) - error_toolchain_identifier = ( - "Difference in 'toolchain_identifier' field:\n" - "Value before change:\t'first-id'\n" - "Value after change:\t'second-id'\n" - ) - error_host_system_name = ( - "Difference in 'host_system_name' field:\n" - "Value before change:\t'first-host'\n" - "Value after change:\t'second-host'\n" - ) - error_target_system_name = ( - "Difference in 'target_system_name' field:\n" - "Value before change:\t'first-target'\n" - "Value after change:\t'second-target'\n" - ) - error_target_cpu = ( - "Difference in 'target_cpu' field:\n" - "Value before change:\t'first-cpu'\n" - "Value after change:\t'second-cpu'\n" - ) - error_target_libc = ( - "Difference in 'target_libc' field:\n" - "Value before change:\t'first-libc'\n" - "Value after change:\t'second-libc'\n" - ) - error_compiler = ( - "Difference in 'compiler' field:\n" - "Value before change:\t'first-compiler'\n" - "Value after change:\t'second-compiler'\n" - ) - error_abi_version = ( - "Difference in 'abi_version' field:\n" - "Value before change:\t'first-abi'\n" - "Value after change:\t'second-abi'\n" - ) - error_abi_libc_version = ( - "Difference in 'abi_libc_version' field:\n" - "Value before change:\t'first-abi-libc'\n" - "Value after change:\t'second-abi-libc'\n" - ) - error_builtin_sysroot = ( - "Difference in 'builtin_sysroot' field:\n" - "Value before change is set to 'sysroot'\n" - "Value after change is not set\n" - ) - error_cc_target_os = ( - "Difference in 'cc_target_os' field:\n" - "Value before change is not set\n" - "Value after change is set to 'os'\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_toolchain_identifier, mock_stdout.getvalue()) - self.assertIn(error_host_system_name, mock_stdout.getvalue()) - self.assertIn(error_target_system_name, mock_stdout.getvalue()) - self.assertIn(error_target_cpu, mock_stdout.getvalue()) - self.assertIn(error_target_libc, mock_stdout.getvalue()) - self.assertIn(error_compiler, mock_stdout.getvalue()) - self.assertIn(error_abi_version, mock_stdout.getvalue()) - self.assertIn(error_abi_libc_version, mock_stdout.getvalue()) - self.assertIn(error_builtin_sysroot, mock_stdout.getvalue()) - self.assertIn(error_cc_target_os, mock_stdout.getvalue()) - - def test_tool_path(self): - first = make_toolchain(""" - tool_path { - name: "only_first" - path: "/a/b/c" - } - tool_path { - name: "paths_differ" - path: "/path/first" - } - """) - second = make_toolchain(""" - tool_path { - name: "paths_differ" - path: "/path/second" - } - tool_path { - name: "only_second_1" - path: "/a/b/c" - } - tool_path { - name: "only_second_2" - path: "/a/b/c" - } - """) - error_only_first = ( - "* List before change contains entries for the " - "following tools that the list after the change " - "doesn't:\n[only_first]\n" - ) - error_only_second = ( - "* List after change contains entries for the " - "following tools that the list before the change " - "doesn't:\n" - "[\n" - "\tonly_second_1\n" - "\tonly_second_2\n" - "]\n" - ) - error_paths_differ = ( - "* Path for tool 'paths_differ' differs before and " - "after the change:\n" - "Value before change:\t'/path/first'\n" - "Value after change:\t'/path/second'\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_only_first, mock_stdout.getvalue()) - self.assertIn(error_only_second, mock_stdout.getvalue()) - self.assertIn(error_paths_differ, mock_stdout.getvalue()) - - def test_make_variable(self): - first = make_toolchain(""" - make_variable { - name: "only_first" - value: "val" - } - make_variable { - name: "value_differs" - value: "first_value" - } - """) - second = make_toolchain(""" - make_variable { - name: "value_differs" - value: "second_value" - } - make_variable { - name: "only_second_1" - value: "val" - } - make_variable { - name: "only_second_2" - value: "val" - } - """) - error_only_first = ( - "* List before change contains entries for the " - "following variables that the list after the " - "change doesn't:\n[only_first]\n" - ) - error_only_second = ( - "* List after change contains entries for the " - "following variables that the list before the " - "change doesn't:\n" - "[\n" - "\tonly_second_1\n" - "\tonly_second_2\n" - "]\n" - ) - error_value_differs = ( - "* Value for variable 'value_differs' differs before" - " and after the change:\n" - "Value before change:\t'first_value'\n" - "Value after change:\t'second_value'\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_only_first, mock_stdout.getvalue()) - self.assertIn(error_only_second, mock_stdout.getvalue()) - self.assertIn(error_value_differs, mock_stdout.getvalue()) - - def test_cxx_builtin_include_directories(self): - first = make_toolchain(""" - cxx_builtin_include_directory: "a/b/c" - cxx_builtin_include_directory: "d/e/f" - """) - second = make_toolchain(""" - cxx_builtin_include_directory: "d/e/f" - cxx_builtin_include_directory: "a/b/c" - """) - expect_error = ( - "Difference in 'cxx_builtin_include_directory' field:\n" - "List of elements before change:\n" - "[\n" - "\ta/b/c\n" - "\td/e/f\n" - "]\n" - "List of elements after change:\n" - "[\n" - "\td/e/f\n" - "\ta/b/c\n" - "]\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(expect_error, mock_stdout.getvalue()) - - def test_artifact_name_pattern(self): - first = make_toolchain(""" - artifact_name_pattern { - category_name: 'object_file' - prefix: '' - extension: '.obj1' - } - artifact_name_pattern { - category_name: 'executable' - prefix: 'first' - extension: '.exe' - } - artifact_name_pattern { - category_name: 'dynamic_library' - prefix: '' - extension: '.dll' - } - """) - second = make_toolchain(""" - artifact_name_pattern { - category_name: 'object_file' - prefix: '' - extension: '.obj2' - } - artifact_name_pattern { - category_name: 'static_library' - prefix: '' - extension: '.lib' - } - artifact_name_pattern { - category_name: 'executable' - prefix: 'second' - extension: '.exe' - } - artifact_name_pattern { - category_name: 'interface_library' - prefix: '' - extension: '.if.lib' - } - """) - error_only_first = ( - "* List before change contains entries for the " - "following categories that the list after the " - "change doesn't:\n[dynamic_library]\n" - ) - error_only_second = ( - "* List after change contains entries for the " - "following categories that the list before the " - "change doesn't:\n" - "[\n" - "\tinterface_library\n" - "\tstatic_library\n" - "]\n" - ) - error_extension_differs = ( - "* Value for category 'object_file' differs " - "before and after the change:\n" - "Value before change:" - "\tprefix:''" - "\textension:'.obj1'\n" - "Value after change:" - "\tprefix:''" - "\textension:'.obj2'\n" - ) - error_prefix_differs = ( - "* Value for category 'executable' differs " - "before and after the change:\n" - "Value before change:" - "\tprefix:'first'" - "\textension:'.exe'\n" - "Value after change:" - "\tprefix:'second'" - "\textension:'.exe'\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_only_first, mock_stdout.getvalue()) - self.assertIn(error_only_second, mock_stdout.getvalue()) - self.assertIn(error_extension_differs, mock_stdout.getvalue()) - self.assertIn(error_prefix_differs, mock_stdout.getvalue()) - - def test_features_not_ordered(self): - first = make_toolchain(""" - feature { - name: 'feature1' - } - feature { - name: 'feature2' - } - """) - second = make_toolchain(""" - feature { - name: 'feature2' - } - feature { - name: 'feature1' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("Features not in right order", mock_stdout.getvalue()) - - def test_features_missing(self): - first = make_toolchain(""" - feature { - name: 'feature1' - } - """) - second = make_toolchain(""" - feature { - name: 'feature2' - } - """) - error_only_first = ( - "* List before change contains entries for the " - "following features that the list after the " - "change doesn't:\n[feature1]\n" - ) - error_only_second = ( - "* List after change contains entries for the " - "following features that the list before the " - "change doesn't:\n[feature2]\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_only_first, mock_stdout.getvalue()) - self.assertIn(error_only_second, mock_stdout.getvalue()) - - def test_feature_enabled(self): - first = make_toolchain(""" - feature { - name: 'feature' - enabled: true - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - enabled: false - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - - def test_feature_provides(self): - first = make_toolchain(""" - feature { - name: 'feature' - provides: 'a' - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - provides: 'b' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_provides_preserves_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - provides: 'a' - provides: 'b' - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - provides: 'b' - provides: 'a' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_implies(self): - first = make_toolchain(""" - feature { - name: 'feature' - implies: 'a' - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_implies_preserves_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - implies: 'a' - implies: 'b' - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - implies: 'b' - implies: 'a' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_requires_preserves_list_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature1' - } - requires: { - feature: 'feature2' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature2' - } - requires: { - feature: 'feature1' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_requires_ignores_required_features_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature1' - feature: 'feature2' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature2' - feature: 'feature1' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_feature_requires_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature1' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - requires: { - feature: 'feature2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_action_config_ignores_requires(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - requires: { - feature: 'feature1' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - requires: { - feature: 'feature2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_env_set_actions_differ(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set { - action: 'a1' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set: { - action: 'a1' - action: 'a2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_env_set_ignores_actions_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set { - action: 'a2' - action: 'a1' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set: { - action: 'a1' - action: 'a2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_env_set_env_entries_not_ordered(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'k1' - value: 'v1' - } - env_entry { - key: 'k2' - value: 'v2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'k2' - value: 'v2' - } - env_entry { - key: 'k1' - value: 'v1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_env_set_env_entries_differ(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'k1' - value: 'value_first' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'k1' - value: 'value_second' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_feature_preserves_env_set_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'first' - value: 'first' - } - } - env_set { - env_entry { - key: 'second' - value: 'second' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set { - env_entry { - key: 'second' - value: 'second' - } - } - env_set { - env_entry { - key: 'first' - value: 'first' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after the change:", - mock_stdout.getvalue(), - ) - - def test_action_config_ignores_env_set(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - env_set { - env_entry { - key: 'k1' - value: 'value_first' - } - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - env_set { - env_entry { - key: 'k1' - value: 'value_second' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_env_set_ignores_with_feature_set_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set{ - with_feature { - feature: 'feature1' - } - with_feature { - not_feature: 'feature2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set { - with_feature { - not_feature: 'feature2' - } - with_feature { - feature: 'feature1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_env_set_ignores_with_feature_set_lists_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - env_set{ - with_feature { - feature: 'feature1' - feature: 'feature2' - not_feature: 'not_feature1' - not_feature: 'not_feature2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - env_set{ - with_feature { - feature: 'feature2' - feature: 'feature1' - not_feature: 'not_feature2' - not_feature: 'not_feature1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_set_ignores_actions_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set { - action: 'a1' - action: 'a2' - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set { - action: 'a2' - action: 'a1' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_action_config_flag_set_actions_ignored(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - flag_set { - action: 'a1' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - flag_set { - action: 'a2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_set_ignores_with_feature_set_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set { - with_feature { - feature: 'feature1' - } - with_feature { - not_feature: 'feature2' - } - } - } - action_config { - config_name: 'config' - flag_set { - with_feature { - feature: 'feature1' - } - with_feature { - not_feature: 'feature2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set { - with_feature { - not_feature: 'feature2' - } - with_feature { - feature: 'feature1' - } - } - } - action_config { - config_name: 'config' - flag_set { - with_feature { - not_feature: 'feature2' - } - with_feature { - feature: 'feature1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_set_ignores_with_feature_set_lists_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - with_feature { - feature: 'feature1' - feature: 'feature2' - not_feature: 'not_feature1' - not_feature: 'not_feature2' - } - } - } - action_config { - config_name: 'config' - flag_set{ - with_feature { - feature: 'feature1' - feature: 'feature2' - not_feature: 'not_feature1' - not_feature: 'not_feature2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - with_feature { - feature: 'feature2' - feature: 'feature1' - not_feature: 'not_feature2' - not_feature: 'not_feature1' - } - } - } - action_config { - config_name: 'config' - flag_set{ - with_feature { - feature: 'feature2' - feature: 'feature1' - not_feature: 'not_feature2' - not_feature: 'not_feature1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_set_preserves_flag_group_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set { - flag_group { - flag: 'a' - } - flag_group { - flag: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set { - flag_group { - flag: 'a' - } - flag_group { - flag: 'b' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set { - flag_group { - flag: 'b' - } - flag_group { - flag: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set { - flag_group { - flag: 'b' - } - flag_group { - flag: 'a' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_preserves_flags_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - flag: 'flag1' - flag: 'flag2' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - flag: 'flag1' - flag: 'flag2' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - flag: 'flag2' - flag: 'flag1' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - flag: 'flag2' - flag: 'flag1' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_iterate_over_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - iterate_over: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - iterate_over: 'a' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - iterate_over: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - iterate_over: 'b' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_expand_if_true_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_true: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_true: 'a' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_true: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_true: 'b' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_expand_if_false_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_false: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_false: 'a' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_false: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_false: 'b' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_expand_if_all_available_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_all_available: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_all_available: 'a' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_all_available: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_all_available: 'b' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_expand_if_none_available_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_none_available: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_none_available: 'a' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_none_available: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_none_available: 'b' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_expand_if_all_available_ignores_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_all_available: 'a' - expand_if_all_available: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_all_available: 'a' - expand_if_all_available: 'b' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_all_available: 'b' - expand_if_all_available: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_all_available: 'b' - expand_if_all_available: 'a' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_group_expand_if_none_available_ignores_order(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_none_available: 'a' - expand_if_none_available: 'b' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_none_available: 'a' - expand_if_none_available: 'b' - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_none_available: 'b' - expand_if_none_available: 'a' - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_none_available: 'b' - expand_if_none_available: 'a' - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_flag_group_expand_if_equal_differs(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_equal { - variable: 'first' - value: 'val' - } - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_equal { - variable: 'first' - value: 'val' - } - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - expand_if_equal { - variable: 'second' - value: 'val' - } - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - expand_if_equal { - variable: 'second' - value: 'val' - } - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_flag_group_flag_groups_differ(self): - first = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - flag_group { - flag: 'a' - flag: 'b' - } - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - flag_group { - flag: 'a' - flag: 'b' - } - } - } - } - """) - second = make_toolchain(""" - feature { - name: 'feature' - flag_set{ - flag_group { - flag_group { - flag: 'b' - flag: 'a' - } - } - } - } - action_config { - config_name: 'config' - flag_set{ - flag_group { - flag_group { - flag: 'b' - flag: 'a' - } - } - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Feature 'feature' differs before and after", mock_stdout.getvalue() - ) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_configs_not_ordered(self): - first = make_toolchain(""" - action_config { - config_name: 'action1' - } - action_config { - config_name: 'action2' - } - """) - second = make_toolchain(""" - action_config { - config_name: 'action2' - } - action_config { - config_name: 'action1' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("Action configs not in right order", mock_stdout.getvalue()) - - def test_action_configs_missing(self): - first = make_toolchain(""" - action_config { - config_name: 'action1' - } - """) - second = make_toolchain(""" - action_config { - config_name: 'action2' - } - """) - error_only_first = ( - "* List before change contains entries for the " - "following action_configs that the list after the " - "change doesn't:\n[action1]\n" - ) - error_only_second = ( - "* List after change contains entries for the " - "following action_configs that the list before the " - "change doesn't:\n[action2]\n" - ) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn(error_only_first, mock_stdout.getvalue()) - self.assertIn(error_only_second, mock_stdout.getvalue()) - - def test_action_config_enabled(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - enabled: true - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - enabled: false - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_config_action_name(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - action_name: 'config1' - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - action_name: 'config2' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_config_tool_tool_path_differs(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - tool { - tool_path: 'path1' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - tool { - tool_path: 'path2' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_config_tool_execution_requirements_differ(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - tool { - execution_requirement: 'a' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - tool { - execution_requirement: 'b' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_config_tool_execution_requirements_ignores_order(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - tool { - execution_requirement: 'a' - execution_requirement: 'b' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - tool { - execution_requirement: 'b' - execution_requirement: 'a' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_action_config_implies_differs(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - implies: 'a' - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - implies: 'b' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_action_config_implies_preserves_order(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - implies: 'a' - implies: 'b' - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - implies: 'b' - implies: 'a' - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn( - "* Action config 'config' differs before and after", - mock_stdout.getvalue(), - ) - - def test_unused_tool_path(self): - first = make_toolchain(""" - tool_path { - name: "empty" - path: "" - } - """) - second = make_toolchain(""" - tool_path { - name: "empty" - path: "NOT_USED" - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - def test_unused_tool_path_in_tool(self): - first = make_toolchain(""" - action_config { - config_name: 'config' - tool { - tool_path: '' - } - } - """) - second = make_toolchain(""" - action_config { - config_name: 'config' - tool { - tool_path: 'NOT_USED' - } - } - """) - mock_stdout = StringIO() - with mock.patch("sys.stdout", mock_stdout): - compare_ctoolchains(first, second) - self.assertIn("No difference", mock_stdout.getvalue()) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/migration/ctoolchain_compare.bzl b/tools/migration/ctoolchain_compare.bzl deleted file mode 100644 index a9632af..0000000 --- a/tools/migration/ctoolchain_compare.bzl +++ /dev/null @@ -1,49 +0,0 @@ -"""A test rule that compares two CToolchains in proto format.""" - -def _impl(ctx): - toolchain_config_proto = ctx.actions.declare_file(ctx.label.name + "_toolchain_config.proto") - ctx.actions.write( - toolchain_config_proto, - ctx.attr.toolchain_config[CcToolchainConfigInfo].proto, - ) - - script = ("%s --before='%s' --after='%s' --toolchain_identifier='%s'" % ( - ctx.executable._comparator.short_path, - ctx.file.crosstool.short_path, - toolchain_config_proto.short_path, - ctx.attr.toolchain_identifier, - )) - test_executable = ctx.actions.declare_file(ctx.label.name) - ctx.actions.write(test_executable, script, is_executable = True) - - runfiles = ctx.runfiles(files = [toolchain_config_proto, ctx.file.crosstool]) - runfiles = runfiles.merge(ctx.attr._comparator[DefaultInfo].default_runfiles) - - return DefaultInfo(runfiles = runfiles, executable = test_executable) - -cc_toolchains_compare_test = rule( - implementation = _impl, - attrs = { - "crosstool": attr.label( - mandatory = True, - allow_single_file = True, - doc = "Location of the CROSSTOOL file", - ), - "toolchain_config": attr.label( - mandatory = True, - providers = [CcToolchainConfigInfo], - doc = ("Starlark rule that replaces the CROSSTOOL file functionality " + - "for the CToolchain with the given identifier"), - ), - "toolchain_identifier": attr.string( - mandatory = True, - doc = "identifier of the CToolchain that is being compared", - ), - "_comparator": attr.label( - default = ":ctoolchain_comparator", - executable = True, - cfg = "exec", - ), - }, - test = True, -) diff --git a/tools/migration/legacy_fields_migration_lib.py b/tools/migration/legacy_fields_migration_lib.py deleted file mode 100644 index 6107f92..0000000 --- a/tools/migration/legacy_fields_migration_lib.py +++ /dev/null @@ -1,564 +0,0 @@ -"""Module providing migrate_legacy_fields function. - -migrate_legacy_fields takes parsed CROSSTOOL proto and migrates it (inplace) to -use only the features. - -Tracking issue: https://github.com/bazelbuild/bazel/issues/5187 - -Since C++ rules team is working on migrating CROSSTOOL from text proto into -Starlark, we advise CROSSTOOL owners to wait for the CROSSTOOL -> Starlark -migrator before they invest too much time into fixing their pipeline. Tracking -issue for the Starlark effort is -https://github.com/bazelbuild/bazel/issues/5380. -""" - -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 - -ALL_CC_COMPILE_ACTIONS = [ - "assemble", "preprocess-assemble", "linkstamp-compile", "c-compile", - "c++-compile", "c++-header-parsing", "c++-module-compile", - "c++-module-codegen", "lto-backend", "clif-match" -] - -ALL_OBJC_COMPILE_ACTIONS = [ - "objc-compile", "objc++-compile" -] - -ALL_CXX_COMPILE_ACTIONS = [ - action for action in ALL_CC_COMPILE_ACTIONS - if action not in ["c-compile", "preprocess-assemble", "assemble"] -] - -ALL_CC_LINK_ACTIONS = [ - "c++-link-executable", "c++-link-dynamic-library", - "c++-link-nodeps-dynamic-library" -] - -ALL_OBJC_LINK_ACTIONS = [ - "objc-executable", "objc++-executable", -] - -DYNAMIC_LIBRARY_LINK_ACTIONS = [ - "c++-link-dynamic-library", "c++-link-nodeps-dynamic-library" -] - -NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS = ["c++-link-nodeps-dynamic-library"] - -TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS = ["c++-link-dynamic-library"] - -TRANSITIVE_LINK_ACTIONS = ["c++-link-executable", "c++-link-dynamic-library"] - -CC_LINK_EXECUTABLE = ["c++-link-executable"] - - -def compile_actions(toolchain): - """Returns compile actions for cc or objc rules.""" - if _is_objc_toolchain(toolchain): - return ALL_CC_COMPILE_ACTIONS + ALL_OBJC_COMPILE_ACTIONS - else: - return ALL_CC_COMPILE_ACTIONS - -def link_actions(toolchain): - """Returns link actions for cc or objc rules.""" - if _is_objc_toolchain(toolchain): - return ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS - else: - return ALL_CC_LINK_ACTIONS - - -def executable_link_actions(toolchain): - """Returns transitive link actions for cc or objc rules.""" - if _is_objc_toolchain(toolchain): - return CC_LINK_EXECUTABLE + ALL_OBJC_LINK_ACTIONS - else: - return CC_LINK_EXECUTABLE - - -def _is_objc_toolchain(toolchain): - return any(ac.action_name == "objc-compile" for ac in toolchain.action_config) - -# Map converting from LinkingMode to corresponding feature name -LINKING_MODE_TO_FEATURE_NAME = { - "FULLY_STATIC": "fully_static_link", - "MOSTLY_STATIC": "static_linking_mode", - "DYNAMIC": "dynamic_linking_mode", - "MOSTLY_STATIC_LIBRARIES": "static_linking_mode_nodeps_library", -} - -def migrate_legacy_fields(crosstool): - """Migrates parsed crosstool (inplace) to not use legacy fields.""" - crosstool.ClearField("default_toolchain") - for toolchain in crosstool.toolchain: - _ = [_migrate_expand_if_all_available(f) for f in toolchain.feature] - _ = [_migrate_expand_if_all_available(ac) for ac in toolchain.action_config] - _ = [_migrate_repeated_expands(f) for f in toolchain.feature] - _ = [_migrate_repeated_expands(ac) for ac in toolchain.action_config] - - if (toolchain.dynamic_library_linker_flag or - _contains_dynamic_flags(toolchain)) and not _get_feature( - toolchain, "supports_dynamic_linker"): - feature = toolchain.feature.add() - feature.name = "supports_dynamic_linker" - feature.enabled = True - - if toolchain.supports_start_end_lib and not _get_feature( - toolchain, "supports_start_end_lib"): - feature = toolchain.feature.add() - feature.name = "supports_start_end_lib" - feature.enabled = True - - if toolchain.supports_interface_shared_objects and not _get_feature( - toolchain, "supports_interface_shared_libraries"): - feature = toolchain.feature.add() - feature.name = "supports_interface_shared_libraries" - feature.enabled = True - - if toolchain.supports_embedded_runtimes and not _get_feature( - toolchain, "static_link_cpp_runtimes"): - feature = toolchain.feature.add() - feature.name = "static_link_cpp_runtimes" - feature.enabled = True - - if toolchain.needsPic and not _get_feature(toolchain, "supports_pic"): - feature = toolchain.feature.add() - feature.name = "supports_pic" - feature.enabled = True - - if toolchain.supports_fission and not _get_feature( - toolchain, "per_object_debug_info"): - # feature { - # name: "per_object_debug_info" - # enabled: true - # flag_set { - # action: "assemble" - # action: "preprocess-assemble" - # action: "c-compile" - # action: "c++-compile" - # action: "c++-module-codegen" - # action: "lto-backend" - # flag_group { - # expand_if_all_available: 'is_using_fission'", - # flag: "-gsplit-dwarf" - # } - # } - # } - feature = toolchain.feature.add() - feature.name = "per_object_debug_info" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = [ - "c-compile", "c++-compile", "c++-module-codegen", "assemble", - "preprocess-assemble", "lto-backend" - ] - flag_group = flag_set.flag_group.add() - flag_group.expand_if_all_available[:] = ["is_using_fission"] - flag_group.flag[:] = ["-gsplit-dwarf"] - - if toolchain.objcopy_embed_flag and not _get_feature( - toolchain, "objcopy_embed_flags"): - feature = toolchain.feature.add() - feature.name = "objcopy_embed_flags" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = ["objcopy_embed_data"] - flag_group = flag_set.flag_group.add() - flag_group.flag[:] = toolchain.objcopy_embed_flag - - action_config = toolchain.action_config.add() - action_config.action_name = "objcopy_embed_data" - action_config.config_name = "objcopy_embed_data" - action_config.enabled = True - tool = action_config.tool.add() - tool.tool_path = _find_tool_path(toolchain, "objcopy") - - if toolchain.ld_embed_flag and not _get_feature( - toolchain, "ld_embed_flags"): - feature = toolchain.feature.add() - feature.name = "ld_embed_flags" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = ["ld_embed_data"] - flag_group = flag_set.flag_group.add() - flag_group.flag[:] = toolchain.ld_embed_flag - - action_config = toolchain.action_config.add() - action_config.action_name = "ld_embed_data" - action_config.config_name = "ld_embed_data" - action_config.enabled = True - tool = action_config.tool.add() - tool.tool_path = _find_tool_path(toolchain, "ld") - - - # Create default_link_flags feature for linker_flag - flag_sets = _extract_legacy_link_flag_sets_for(toolchain) - if flag_sets: - if _get_feature(toolchain, "default_link_flags"): - continue - if _get_feature(toolchain, "legacy_link_flags"): - for f in toolchain.feature: - if f.name == "legacy_link_flags": - f.ClearField("flag_set") - feature = f - _rename_feature_in_toolchain(toolchain, "legacy_link_flags", - "default_link_flags") - break - else: - feature = _prepend_feature(toolchain) - feature.name = "default_link_flags" - feature.enabled = True - _add_flag_sets(feature, flag_sets) - - # Create default_compile_flags feature for compiler_flag, cxx_flag - flag_sets = _extract_legacy_compile_flag_sets_for(toolchain) - if flag_sets and not _get_feature(toolchain, "default_compile_flags"): - if _get_feature(toolchain, "legacy_compile_flags"): - for f in toolchain.feature: - if f.name == "legacy_compile_flags": - f.ClearField("flag_set") - feature = f - _rename_feature_in_toolchain(toolchain, "legacy_compile_flags", - "default_compile_flags") - break - else: - feature = _prepend_feature(toolchain) - feature.enabled = True - feature.name = "default_compile_flags" - _add_flag_sets(feature, flag_sets) - - # Unfiltered cxx flags have to have their own special feature. - # "unfiltered_compile_flags" is a well-known (by Bazel) feature name that is - # excluded from nocopts filtering. - if toolchain.unfiltered_cxx_flag: - # If there already is a feature named unfiltered_compile_flags, the - # crosstool is already migrated for unfiltered_compile_flags - if _get_feature(toolchain, "unfiltered_compile_flags"): - for f in toolchain.feature: - if f.name == "unfiltered_compile_flags": - for flag_set in f.flag_set: - for flag_group in flag_set.flag_group: - if flag_group.iterate_over == "unfiltered_compile_flags": - flag_group.ClearField("iterate_over") - flag_group.ClearField("expand_if_all_available") - flag_group.ClearField("flag") - flag_group.flag[:] = toolchain.unfiltered_cxx_flag - else: - if not _get_feature(toolchain, "user_compile_flags"): - feature = toolchain.feature.add() - feature.name = "user_compile_flags" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = compile_actions(toolchain) - flag_group = flag_set.flag_group.add() - flag_group.expand_if_all_available[:] = ["user_compile_flags"] - flag_group.iterate_over = "user_compile_flags" - flag_group.flag[:] = ["%{user_compile_flags}"] - - if not _get_feature(toolchain, "sysroot"): - sysroot_actions = compile_actions(toolchain) + link_actions(toolchain) - sysroot_actions.remove("assemble") - feature = toolchain.feature.add() - feature.name = "sysroot" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = sysroot_actions - flag_group = flag_set.flag_group.add() - flag_group.expand_if_all_available[:] = ["sysroot"] - flag_group.flag[:] = ["--sysroot=%{sysroot}"] - - feature = toolchain.feature.add() - feature.name = "unfiltered_compile_flags" - feature.enabled = True - flag_set = feature.flag_set.add() - flag_set.action[:] = compile_actions(toolchain) - flag_group = flag_set.flag_group.add() - flag_group.flag[:] = toolchain.unfiltered_cxx_flag - - # clear fields - toolchain.ClearField("debian_extra_requires") - toolchain.ClearField("gcc_plugin_compiler_flag") - toolchain.ClearField("ar_flag") - toolchain.ClearField("ar_thin_archives_flag") - toolchain.ClearField("gcc_plugin_header_directory") - toolchain.ClearField("mao_plugin_header_directory") - toolchain.ClearField("supports_normalizing_ar") - toolchain.ClearField("supports_thin_archives") - toolchain.ClearField("supports_incremental_linker") - toolchain.ClearField("supports_dsym") - toolchain.ClearField("supports_gold_linker") - toolchain.ClearField("default_python_top") - toolchain.ClearField("default_python_version") - toolchain.ClearField("python_preload_swigdeps") - toolchain.ClearField("needsPic") - toolchain.ClearField("compilation_mode_flags") - toolchain.ClearField("linking_mode_flags") - toolchain.ClearField("unfiltered_cxx_flag") - toolchain.ClearField("ld_embed_flag") - toolchain.ClearField("objcopy_embed_flag") - toolchain.ClearField("supports_start_end_lib") - toolchain.ClearField("supports_interface_shared_objects") - toolchain.ClearField("supports_fission") - toolchain.ClearField("supports_embedded_runtimes") - toolchain.ClearField("compiler_flag") - toolchain.ClearField("cxx_flag") - toolchain.ClearField("linker_flag") - toolchain.ClearField("dynamic_library_linker_flag") - toolchain.ClearField("static_runtimes_filegroup") - toolchain.ClearField("dynamic_runtimes_filegroup") - - # Enable features that were previously enabled by Bazel - default_features = [ - "dependency_file", "random_seed", "module_maps", "module_map_home_cwd", - "header_module_compile", "include_paths", "pic", "preprocessor_define" - ] - for feature_name in default_features: - feature = _get_feature(toolchain, feature_name) - if feature: - feature.enabled = True - - -def _find_tool_path(toolchain, tool_name): - """Returns the tool path of the tool with the given name.""" - for tool in toolchain.tool_path: - if tool.name == tool_name: - return tool.path - return None - - -def _add_flag_sets(feature, flag_sets): - """Add flag sets into a feature.""" - for flag_set in flag_sets: - with_feature = flag_set[0] - actions = flag_set[1] - flags = flag_set[2] - expand_if_all_available = flag_set[3] - not_feature = None - if len(flag_set) >= 5: - not_feature = flag_set[4] - flag_set = feature.flag_set.add() - if with_feature is not None: - flag_set.with_feature.add().feature[:] = [with_feature] - if not_feature is not None: - flag_set.with_feature.add().not_feature[:] = [not_feature] - flag_set.action[:] = actions - flag_group = flag_set.flag_group.add() - flag_group.expand_if_all_available[:] = expand_if_all_available - flag_group.flag[:] = flags - return feature - - -def _extract_legacy_compile_flag_sets_for(toolchain): - """Get flag sets for default_compile_flags feature.""" - result = [] - if toolchain.compiler_flag: - result.append( - [None, compile_actions(toolchain), toolchain.compiler_flag, []]) - - # Migrate compiler_flag from compilation_mode_flags - for cmf in toolchain.compilation_mode_flags: - mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() - # coverage mode has been a noop since a while - if mode == "coverage": - continue - - if (cmf.compiler_flag or - cmf.cxx_flag) and not _get_feature(toolchain, mode): - feature = toolchain.feature.add() - feature.name = mode - - if cmf.compiler_flag: - result.append([mode, compile_actions(toolchain), cmf.compiler_flag, []]) - - if toolchain.cxx_flag: - result.append([None, ALL_CXX_COMPILE_ACTIONS, toolchain.cxx_flag, []]) - - # Migrate compiler_flag/cxx_flag from compilation_mode_flags - for cmf in toolchain.compilation_mode_flags: - mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() - # coverage mode has been a noop since a while - if mode == "coverage": - continue - - if cmf.cxx_flag: - result.append([mode, ALL_CXX_COMPILE_ACTIONS, cmf.cxx_flag, []]) - - return result - - -def _extract_legacy_link_flag_sets_for(toolchain): - """Get flag sets for default_link_flags feature.""" - result = [] - - # Migrate linker_flag - if toolchain.linker_flag: - result.append([None, link_actions(toolchain), toolchain.linker_flag, []]) - - # Migrate linker_flags from compilation_mode_flags - for cmf in toolchain.compilation_mode_flags: - mode = crosstool_config_pb2.CompilationMode.Name(cmf.mode).lower() - # coverage mode has beed a noop since a while - if mode == "coverage": - continue - - if cmf.linker_flag and not _get_feature(toolchain, mode): - feature = toolchain.feature.add() - feature.name = mode - - if cmf.linker_flag: - result.append([mode, link_actions(toolchain), cmf.linker_flag, []]) - - # Migrate linker_flags from linking_mode_flags - for lmf in toolchain.linking_mode_flags: - mode = crosstool_config_pb2.LinkingMode.Name(lmf.mode) - feature_name = LINKING_MODE_TO_FEATURE_NAME.get(mode) - # if the feature is already there, we don't migrate, lmf is not used - if _get_feature(toolchain, feature_name): - continue - - if lmf.linker_flag: - feature = toolchain.feature.add() - feature.name = feature_name - if mode == "DYNAMIC": - result.append( - [None, NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS, lmf.linker_flag, []]) - result.append([ - None, - TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS, - lmf.linker_flag, - [], - "static_link_cpp_runtimes", - ]) - result.append([ - feature_name, - executable_link_actions(toolchain), lmf.linker_flag, [] - ]) - elif mode == "MOSTLY_STATIC": - result.append( - [feature_name, - CC_LINK_EXECUTABLE, lmf.linker_flag, []]) - else: - result.append( - [feature_name, - link_actions(toolchain), lmf.linker_flag, []]) - - if toolchain.dynamic_library_linker_flag: - result.append([ - None, DYNAMIC_LIBRARY_LINK_ACTIONS, - toolchain.dynamic_library_linker_flag, [] - ]) - - if toolchain.test_only_linker_flag: - result.append([ - None, - link_actions(toolchain), toolchain.test_only_linker_flag, - ["is_cc_test"] - ]) - - return result - - -def _prepend_feature(toolchain): - """Create a new feature and make it be the first in the toolchain.""" - features = toolchain.feature - toolchain.ClearField("feature") - new_feature = toolchain.feature.add() - toolchain.feature.extend(features) - return new_feature - - -def _get_feature(toolchain, name): - """Returns feature with a given name or None.""" - for feature in toolchain.feature: - if feature.name == name: - return feature - return None - - -def _migrate_expand_if_all_available(message): - """Move expand_if_all_available field to flag_groups.""" - for flag_set in message.flag_set: - if flag_set.expand_if_all_available: - for flag_group in flag_set.flag_group: - new_vars = ( - flag_group.expand_if_all_available[:] + - flag_set.expand_if_all_available[:]) - flag_group.expand_if_all_available[:] = new_vars - flag_set.ClearField("expand_if_all_available") - - -def _migrate_repeated_expands(message): - """Replace repeated legacy fields with nesting.""" - todo_queue = [] - for flag_set in message.flag_set: - todo_queue.extend(flag_set.flag_group) - while todo_queue: - flag_group = todo_queue.pop() - todo_queue.extend(flag_group.flag_group) - if len(flag_group.expand_if_all_available) <= 1 and len( - flag_group.expand_if_none_available) <= 1: - continue - - current_children = flag_group.flag_group - current_flags = flag_group.flag - flag_group.ClearField("flag_group") - flag_group.ClearField("flag") - - new_flag_group = flag_group.flag_group.add() - new_flag_group.flag_group.extend(current_children) - new_flag_group.flag.extend(current_flags) - - if len(flag_group.expand_if_all_available) > 1: - expands_to_move = flag_group.expand_if_all_available[1:] - flag_group.expand_if_all_available[:] = [ - flag_group.expand_if_all_available[0] - ] - new_flag_group.expand_if_all_available.extend(expands_to_move) - - if len(flag_group.expand_if_none_available) > 1: - expands_to_move = flag_group.expand_if_none_available[1:] - flag_group.expand_if_none_available[:] = [ - flag_group.expand_if_none_available[0] - ] - new_flag_group.expand_if_none_available.extend(expands_to_move) - - todo_queue.append(new_flag_group) - todo_queue.append(flag_group) - - -def _contains_dynamic_flags(toolchain): - for lmf in toolchain.linking_mode_flags: - mode = crosstool_config_pb2.LinkingMode.Name(lmf.mode) - if mode == "DYNAMIC": - return True - return False - - -def _rename_feature_in_toolchain(toolchain, from_name, to_name): - for f in toolchain.feature: - _rename_feature_in(f, from_name, to_name) - for a in toolchain.action_config: - _rename_feature_in(a, from_name, to_name) - - -def _rename_feature_in(msg, from_name, to_name): - if from_name in msg.implies: - msg.implies.remove(from_name) - for requires in msg.requires: - if from_name in requires.feature: - requires.feature.remove(from_name) - requires.feature.extend([to_name]) - for flag_set in msg.flag_set: - for with_feature in flag_set.with_feature: - if from_name in with_feature.feature: - with_feature.feature.remove(from_name) - with_feature.feature.extend([to_name]) - if from_name in with_feature.not_feature: - with_feature.not_feature.remove(from_name) - with_feature.not_feature.extend([to_name]) - for env_set in msg.env_set: - for with_feature in env_set.with_feature: - if from_name in with_feature.feature: - with_feature.feature.remove(from_name) - with_feature.feature.extend([to_name]) - if from_name in with_feature.not_feature: - with_feature.not_feature.remove(from_name) - with_feature.not_feature.extend([to_name]) diff --git a/tools/migration/legacy_fields_migration_lib_test.py b/tools/migration/legacy_fields_migration_lib_test.py deleted file mode 100644 index 93972cc..0000000 --- a/tools/migration/legacy_fields_migration_lib_test.py +++ /dev/null @@ -1,1240 +0,0 @@ -import unittest -from google.protobuf import text_format -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 -from tools.migration.legacy_fields_migration_lib import ALL_CC_COMPILE_ACTIONS -from tools.migration.legacy_fields_migration_lib import ALL_OBJC_COMPILE_ACTIONS -from tools.migration.legacy_fields_migration_lib import ALL_CXX_COMPILE_ACTIONS -from tools.migration.legacy_fields_migration_lib import ALL_CC_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import ALL_OBJC_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import DYNAMIC_LIBRARY_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import TRANSITIVE_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS -from tools.migration.legacy_fields_migration_lib import CC_LINK_EXECUTABLE -from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields - - -def assert_has_feature(self, toolchain, name): - self.assertTrue(any(feature.name == name for feature in toolchain.feature)) - - -def make_crosstool(string): - crosstool = crosstool_config_pb2.CrosstoolRelease() - text_format.Merge("major_version: '123' minor_version: '456'", crosstool) - toolchain = crosstool.toolchain.add() - text_format.Merge(string, toolchain) - return crosstool - - -def migrate_to_string(crosstool): - migrate_legacy_fields(crosstool) - return to_string(crosstool) - - -def to_string(crosstool): - return text_format.MessageToString(crosstool) - - -class LegacyFieldsMigrationLibTest(unittest.TestCase): - - def test_deletes_fields(self): - crosstool = make_crosstool(""" - debian_extra_requires: 'debian-1' - gcc_plugin_compiler_flag: 'gcc_plugin_compiler_flag-1' - ar_flag: 'ar_flag-1' - ar_thin_archives_flag: 'ar_thin_archives_flag-1' - gcc_plugin_header_directory: 'gcc_plugin_header_directory-1' - mao_plugin_header_directory: 'mao_plugin_header_directory-1' - default_python_top: 'default_python_top-1' - default_python_version: 'default_python_version-1' - python_preload_swigdeps: false - supports_normalizing_ar: false - supports_thin_archives: false - supports_incremental_linker: false - supports_dsym: false - supports_gold_linker: false - needsPic: false - supports_start_end_lib: false - supports_interface_shared_objects: false - supports_fission: false - supports_embedded_runtimes: false - static_runtimes_filegroup: 'yolo' - dynamic_runtimes_filegroup: 'yolo' - """) - output = migrate_to_string(crosstool) - self.assertNotIn("debian_extra_requires", output) - self.assertNotIn("gcc_plugin_compiler_flag", output) - self.assertNotIn("ar_flag", output) - self.assertNotIn("ar_thin_archives_flag", output) - self.assertNotIn("gcc_plugin_header_directory", output) - self.assertNotIn("mao_plugin_header_directory", output) - self.assertNotIn("supports_normalizing_ar", output) - self.assertNotIn("supports_thin_archives", output) - self.assertNotIn("supports_incremental_linker", output) - self.assertNotIn("supports_dsym", output) - self.assertNotIn("default_python_top", output) - self.assertNotIn("default_python_version", output) - self.assertNotIn("python_preload_swigdeps", output) - self.assertNotIn("supports_gold_linker", output) - self.assertNotIn("needsPic", output) - self.assertNotIn("supports_start_end_lib", output) - self.assertNotIn("supports_interface_shared_objects", output) - self.assertNotIn("supports_fission", output) - self.assertNotIn("supports_embedded_runtimes", output) - self.assertNotIn("static_runtimes_filegroup", output) - self.assertNotIn("dynamic_runtimes_filegroup", output) - - def test_deletes_default_toolchains(self): - crosstool = make_crosstool("") - crosstool.default_toolchain.add() - self.assertEqual(len(crosstool.default_toolchain), 1) - migrate_legacy_fields(crosstool) - self.assertEqual(len(crosstool.default_toolchain), 0) - - def test_replace_legacy_compile_flags(self): - crosstool = make_crosstool(""" - feature { name: 'foo' } - feature { name: 'legacy_compile_flags' } - compiler_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compiler_flag), 0) - self.assertEqual(output.feature[0].name, "foo") - self.assertEqual(output.feature[1].name, "default_compile_flags") - self.assertEqual(output.feature[1].flag_set[0].action, - ALL_CC_COMPILE_ACTIONS) - self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, - ["clang-flag-1"]) - - def test_replace_legacy_compile_flags_in_action_configs(self): - crosstool = make_crosstool(""" - feature { - name: 'foo' - implies: 'legacy_compile_flags' - requires: { feature: 'legacy_compile_flags' } - flag_set { - with_feature { feature: 'legacy_compile_flags' } - with_feature { not_feature: 'legacy_compile_flags' } - } - env_set { - with_feature { feature: 'legacy_compile_flags' } - with_feature { not_feature: 'legacy_compile_flags' } - } - } - feature { name: 'legacy_compile_flags' } - action_config { - action_name: 'foo' - config_name: 'foo' - implies: 'legacy_compile_flags' - requires: { feature: 'legacy_compile_flags' } - flag_set { - with_feature { feature: 'legacy_compile_flags' } - with_feature { not_feature: 'legacy_compile_flags' } - } - env_set { - with_feature { feature: 'legacy_compile_flags' } - with_feature { not_feature: 'legacy_compile_flags' } - } - } - compiler_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.action_config[0].action_name, "foo") - self.assertEqual(output.action_config[0].implies, []) - self.assertEqual(output.action_config[0].requires[0].feature, - ["default_compile_flags"]) - self.assertEqual( - output.action_config[0].flag_set[0].with_feature[0].feature, - ["default_compile_flags"]) - self.assertEqual( - output.action_config[0].flag_set[0].with_feature[1].not_feature, - ["default_compile_flags"]) - self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature, - ["default_compile_flags"]) - self.assertEqual( - output.action_config[0].env_set[0].with_feature[1].not_feature, - ["default_compile_flags"]) - self.assertEqual(output.feature[0].name, "foo") - self.assertEqual(output.feature[0].implies, []) - self.assertEqual(output.feature[0].requires[0].feature, - ["default_compile_flags"]) - self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature, - ["default_compile_flags"]) - self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature, - ["default_compile_flags"]) - self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature, - ["default_compile_flags"]) - self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature, - ["default_compile_flags"]) - - def test_replace_legacy_link_flags(self): - crosstool = make_crosstool(""" - feature { name: 'foo' } - feature { name: 'legacy_link_flags' } - linker_flag: 'ld-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compiler_flag), 0) - self.assertEqual(output.feature[0].name, "foo") - self.assertEqual(output.feature[1].name, "default_link_flags") - self.assertEqual(output.feature[1].flag_set[0].action, ALL_CC_LINK_ACTIONS) - self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, - ["ld-flag-1"]) - - def test_replace_legacy_link_flags_in_action_configs(self): - crosstool = make_crosstool(""" - feature { - name: 'foo' - implies: 'legacy_link_flags' - requires: { feature: 'legacy_link_flags' } - flag_set { - with_feature { feature: 'legacy_link_flags' } - with_feature { not_feature: 'legacy_link_flags' } - } - env_set { - with_feature { feature: 'legacy_link_flags' } - with_feature { not_feature: 'legacy_link_flags' } - } - } - feature { name: 'legacy_link_flags' } - action_config { - action_name: 'foo' - config_name: 'foo' - implies: 'legacy_link_flags' - requires: { feature: 'legacy_link_flags' } - flag_set { - with_feature { feature: 'legacy_link_flags' } - with_feature { not_feature: 'legacy_link_flags' } - } - env_set { - with_feature { feature: 'legacy_link_flags' } - with_feature { not_feature: 'legacy_link_flags' } - } - } - linker_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.action_config[0].action_name, "foo") - self.assertEqual(output.action_config[0].implies, []) - self.assertEqual(output.action_config[0].requires[0].feature, - ["default_link_flags"]) - self.assertEqual( - output.action_config[0].flag_set[0].with_feature[0].feature, - ["default_link_flags"]) - self.assertEqual( - output.action_config[0].flag_set[0].with_feature[1].not_feature, - ["default_link_flags"]) - self.assertEqual(output.action_config[0].env_set[0].with_feature[0].feature, - ["default_link_flags"]) - self.assertEqual( - output.action_config[0].env_set[0].with_feature[1].not_feature, - ["default_link_flags"]) - self.assertEqual(output.feature[0].name, "foo") - self.assertEqual(output.feature[0].implies, []) - self.assertEqual(output.feature[0].requires[0].feature, - ["default_link_flags"]) - self.assertEqual(output.feature[0].flag_set[0].with_feature[0].feature, - ["default_link_flags"]) - self.assertEqual(output.feature[0].flag_set[0].with_feature[1].not_feature, - ["default_link_flags"]) - self.assertEqual(output.feature[0].env_set[0].with_feature[0].feature, - ["default_link_flags"]) - self.assertEqual(output.feature[0].env_set[0].with_feature[1].not_feature, - ["default_link_flags"]) - - - def test_migrate_compiler_flags(self): - crosstool = make_crosstool(""" - compiler_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compiler_flag), 0) - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["clang-flag-1"]) - - def test_migrate_compiler_flags_for_objc(self): - crosstool = make_crosstool(""" - action_config { action_name: "objc-compile" } - compiler_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compiler_flag), 0) - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS + ALL_OBJC_COMPILE_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["clang-flag-1"]) - - def test_migrate_cxx_flags(self): - crosstool = make_crosstool(""" - cxx_flag: 'clang-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.cxx_flag), 0) - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].action, - ALL_CXX_COMPILE_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["clang-flag-1"]) - - def test_compiler_flag_come_before_cxx_flags(self): - crosstool = make_crosstool(""" - compiler_flag: 'clang-flag-1' - cxx_flag: 'clang-flag-2' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_COMPILE_ACTIONS) - self.assertEqual(output.feature[0].flag_set[1].action, - ALL_CXX_COMPILE_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["clang-flag-1"]) - self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, - ["clang-flag-2"]) - - def test_migrate_linker_flags(self): - crosstool = make_crosstool(""" - linker_flag: 'linker-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.linker_flag), 0) - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[0].flag_set[0].action, ALL_CC_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["linker-flag-1"]) - - def test_migrate_dynamic_library_linker_flags(self): - crosstool = make_crosstool(""" - dynamic_library_linker_flag: 'linker-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.dynamic_library_linker_flag), 0) - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[0].flag_set[0].action, - DYNAMIC_LIBRARY_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["linker-flag-1"]) - - def test_compilation_mode_flags(self): - crosstool = make_crosstool(""" - compiler_flag: "compile-flag-1" - cxx_flag: "cxx-flag-1" - linker_flag: "linker-flag-1" - compilation_mode_flags { - mode: OPT - compiler_flag: "opt-flag-1" - cxx_flag: "opt-flag-2" - linker_flag: "opt-flag-3" - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compilation_mode_flags), 0) - assert_has_feature(self, output, "opt") - - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[1].name, "default_link_flags") - - # flag set for compiler_flag fields - self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["compile-flag-1"]) - - # flag set for compiler_flag from compilation_mode_flags - self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1) - self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], - "opt") - self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, - ["opt-flag-1"]) - - # flag set for cxx_flag fields - self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 0) - self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, - ["cxx-flag-1"]) - - # flag set for cxx_flag from compilation_mode_flags - self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 1) - self.assertEqual(output.feature[0].flag_set[3].with_feature[0].feature[0], - "opt") - self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag, - ["opt-flag-2"]) - - # default_link_flags, flag set for linker_flag - self.assertEqual(len(output.feature[1].flag_set[0].with_feature), 0) - self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, - ["linker-flag-1"]) - - # default_link_flags, flag set for linker_flag from - # compilation_mode_flags - self.assertEqual(len(output.feature[1].flag_set[1].with_feature), 1) - self.assertEqual(output.feature[1].flag_set[1].with_feature[0].feature[0], - "opt") - self.assertEqual(output.feature[1].flag_set[1].flag_group[0].flag, - ["opt-flag-3"]) - - def test_linking_mode_flags(self): - crosstool = make_crosstool(""" - linker_flag: "linker-flag-1" - compilation_mode_flags { - mode: DBG - linker_flag: "dbg-flag-1" - } - linking_mode_flags { - mode: MOSTLY_STATIC - linker_flag: "mostly-static-flag-1" - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.compilation_mode_flags), 0) - self.assertEqual(len(output.linking_mode_flags), 0) - - # flag set for linker_flag - self.assertEqual(len(output.feature[0].flag_set[0].with_feature), 0) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["linker-flag-1"]) - - # flag set for compilation_mode_flags - self.assertEqual(len(output.feature[0].flag_set[1].with_feature), 1) - self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], - "dbg") - self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, - ["dbg-flag-1"]) - - # flag set for linking_mode_flags - self.assertEqual(len(output.feature[0].flag_set[2].with_feature), 1) - self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE) - self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0], - "static_linking_mode") - self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, - ["mostly-static-flag-1"]) - - def test_coverage_compilation_mode_ignored(self): - crosstool = make_crosstool(""" - compilation_mode_flags { - mode: COVERAGE - compiler_flag: "coverage-flag-1" - cxx_flag: "coverage-flag-2" - linker_flag: "coverage-flag-3" - } - """) - output = migrate_to_string(crosstool) - self.assertNotIn("compilation_mode_flags", output) - self.assertNotIn("coverage-flag-1", output) - self.assertNotIn("coverage-flag-2", output) - self.assertNotIn("coverage-flag-3", output) - self.assertNotIn("COVERAGE", output) - - def test_supports_dynamic_linker_when_dynamic_library_linker_flag_is_used( - self): - crosstool = make_crosstool(""" - dynamic_library_linker_flag: "foo" - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[1].name, "supports_dynamic_linker") - self.assertEqual(output.feature[1].enabled, True) - - def test_supports_dynamic_linker_is_added_when_DYNAMIC_present(self): - crosstool = make_crosstool(""" - linking_mode_flags { - mode: DYNAMIC - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_dynamic_linker") - self.assertEqual(output.feature[0].enabled, True) - - def test_supports_dynamic_linker_is_not_added_when_present(self): - crosstool = make_crosstool(""" - feature { name: "supports_dynamic_linker" enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_dynamic_linker") - self.assertEqual(output.feature[0].enabled, False) - - def test_all_linker_flag_ordering(self): - crosstool = make_crosstool(""" - linker_flag: 'linker-flag-1' - compilation_mode_flags { - mode: OPT - linker_flag: 'cmf-flag-2' - } - linking_mode_flags { - mode: MOSTLY_STATIC - linker_flag: 'lmf-flag-3' - } - linking_mode_flags { - mode: DYNAMIC - linker_flag: 'lmf-dynamic-flag-4' - } - dynamic_library_linker_flag: 'dl-flag-5' - test_only_linker_flag: 'to-flag-6' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].action[:], ALL_CC_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], - ["linker-flag-1"]) - - self.assertEqual(output.feature[0].flag_set[1].action[:], ALL_CC_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[1].with_feature[0].feature[0], - "opt") - self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, - ["cmf-flag-2"]) - - self.assertEqual(output.feature[0].flag_set[2].action, CC_LINK_EXECUTABLE) - self.assertEqual(output.feature[0].flag_set[2].with_feature[0].feature[0], - "static_linking_mode") - self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, - ["lmf-flag-3"]) - - self.assertEqual(len(output.feature[0].flag_set[3].with_feature), 0) - self.assertEqual(output.feature[0].flag_set[3].flag_group[0].flag, - ["lmf-dynamic-flag-4"]) - self.assertEqual(output.feature[0].flag_set[3].action, - NODEPS_DYNAMIC_LIBRARY_LINK_ACTIONS) - - self.assertEqual( - output.feature[0].flag_set[4].with_feature[0].not_feature[0], - "static_link_cpp_runtimes") - self.assertEqual(output.feature[0].flag_set[4].flag_group[0].flag, - ["lmf-dynamic-flag-4"]) - self.assertEqual(output.feature[0].flag_set[4].action, - TRANSITIVE_DYNAMIC_LIBRARY_LINK_ACTIONS) - - self.assertEqual(output.feature[0].flag_set[5].with_feature[0].feature[0], - "dynamic_linking_mode") - self.assertEqual(output.feature[0].flag_set[5].flag_group[0].flag, - ["lmf-dynamic-flag-4"]) - self.assertEqual(output.feature[0].flag_set[5].action, - CC_LINK_EXECUTABLE) - - self.assertEqual(output.feature[0].flag_set[6].flag_group[0].flag, - ["dl-flag-5"]) - self.assertEqual(output.feature[0].flag_set[6].action, - DYNAMIC_LIBRARY_LINK_ACTIONS) - - self.assertEqual(output.feature[0].flag_set[7].flag_group[0].flag, - ["to-flag-6"]) - self.assertEqual(output.feature[0].flag_set[7].action, ALL_CC_LINK_ACTIONS) - self.assertEqual( - output.feature[0].flag_set[7].flag_group[0].expand_if_all_available, - ["is_cc_test"]) - - def test_all_linker_flag_objc_actions(self): - crosstool = make_crosstool(""" - action_config { action_name: "objc-compile" } - linker_flag: 'linker-flag-1' - compilation_mode_flags { - mode: OPT - linker_flag: 'cmf-flag-2' - } - linking_mode_flags { - mode: MOSTLY_STATIC - linker_flag: 'lmf-flag-3' - } - dynamic_library_linker_flag: 'dl-flag-5' - test_only_linker_flag: 'to-flag-6' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[0].flag_set[0].action[:], - ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[1].action[:], - ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[2].action[:], - CC_LINK_EXECUTABLE) - self.assertEqual(output.feature[0].flag_set[3].action[:], - DYNAMIC_LIBRARY_LINK_ACTIONS) - self.assertEqual(output.feature[0].flag_set[4].action[:], - ALL_CC_LINK_ACTIONS + ALL_OBJC_LINK_ACTIONS) - - def test_linking_mode_features_are_not_added_when_present(self): - crosstool = make_crosstool(""" - linking_mode_flags { - mode: DYNAMIC - linker_flag: 'dynamic-flag' - } - linking_mode_flags { - mode: FULLY_STATIC - linker_flag: 'fully-static-flag' - } - linking_mode_flags { - mode: MOSTLY_STATIC - linker_flag: 'mostly-static-flag' - } - linking_mode_flags { - mode: MOSTLY_STATIC_LIBRARIES - linker_flag: 'mostly-static-libraries-flag' - } - feature { name: "static_linking_mode" } - feature { name: "dynamic_linking_mode" } - feature { name: "static_linking_mode_nodeps_library" } - feature { name: "fully_static_link" } - """) - output = migrate_to_string(crosstool) - self.assertNotIn("linking_mode_flags", output) - self.assertNotIn("DYNAMIC", output) - self.assertNotIn("MOSTLY_STATIC", output) - self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output) - self.assertNotIn("MOSTLY_STATIC_LIBRARIES", output) - self.assertNotIn("dynamic-flag", output) - self.assertNotIn("fully-static-flag", output) - self.assertNotIn("mostly-static-flag", output) - self.assertNotIn("mostly-static-libraries-flag", output) - - def test_unfiltered_require_user_compile_flags_and_sysroot(self): - crosstool = make_crosstool(""" - feature { name: 'preexisting_feature' } - unfiltered_cxx_flag: 'unfiltered-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - # all these features are added after features that are already present in - # the crosstool - self.assertEqual(output.feature[0].name, "preexisting_feature") - self.assertEqual(output.feature[1].name, "user_compile_flags") - self.assertEqual(output.feature[2].name, "sysroot") - self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") - - def test_user_compile_flags_not_migrated_when_present(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - feature { name: 'user_compile_flags' } - feature { name: 'preexisting_feature' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "user_compile_flags") - self.assertEqual(output.feature[1].name, "preexisting_feature") - self.assertEqual(output.feature[2].name, "sysroot") - self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") - - def test_sysroot_not_migrated_when_present(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - feature { name: 'sysroot' } - feature { name: 'preexisting_feature' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "sysroot") - self.assertEqual(output.feature[1].name, "preexisting_feature") - self.assertEqual(output.feature[2].name, "user_compile_flags") - self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") - - def test_user_compile_flags(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "user_compile_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].action, - ALL_CC_COMPILE_ACTIONS) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, - ["user_compile_flags"]) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].iterate_over, - "user_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["%{user_compile_flags}"]) - - def test_sysroot(self): - sysroot_actions = ALL_CC_COMPILE_ACTIONS + ALL_CC_LINK_ACTIONS - sysroot_actions.remove("assemble") - self.assertTrue("assemble" not in sysroot_actions) - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[1].name, "sysroot") - self.assertEqual(output.feature[1].enabled, True) - self.assertEqual(output.feature[1].flag_set[0].action, sysroot_actions) - self.assertEqual( - output.feature[1].flag_set[0].flag_group[0].expand_if_all_available, - ["sysroot"]) - self.assertEqual(output.feature[1].flag_set[0].flag_group[0].flag, - ["--sysroot=%{sysroot}"]) - - def test_unfiltered_compile_flags_is_not_added_when_already_present(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - feature { name: 'something_else' } - feature { name: 'unfiltered_compile_flags' } - feature { name: 'something_else_2' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(output.feature[1].name, "unfiltered_compile_flags") - self.assertEqual(len(output.feature[1].flag_set), 0) - self.assertEqual(output.feature[2].name, "something_else_2") - - def test_unfiltered_compile_flags_is_not_edited_if_old_variant_present(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - feature { - name: 'unfiltered_compile_flags' - flag_set { - action: 'c-compile' - flag_group { - flag: 'foo-flag-1' - } - } - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "unfiltered_compile_flags") - self.assertEqual(len(output.feature[0].flag_set), 1) - self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"]) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["foo-flag-1"]) - - def test_use_of_unfiltered_compile_flags_var_is_removed_and_replaced(self): - crosstool = make_crosstool(""" - unfiltered_cxx_flag: 'unfiltered-flag-1' - feature { - name: 'unfiltered_compile_flags' - flag_set { - action: 'c-compile' - flag_group { - flag: 'foo-flag-1' - } - } - flag_set { - action: 'c++-compile' - flag_group { - flag: 'bar-flag-1' - } - flag_group { - expand_if_all_available: 'unfiltered_compile_flags' - iterate_over: 'unfiltered_compile_flags' - flag: '%{unfiltered_compile_flags}' - } - flag_group { - flag: 'bar-flag-2' - } - } - flag_set { - action: 'c-compile' - flag_group { - flag: 'foo-flag-2' - } - } - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "unfiltered_compile_flags") - self.assertEqual(output.feature[0].flag_set[0].action, ["c-compile"]) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["foo-flag-1"]) - self.assertEqual(output.feature[0].flag_set[1].action, ["c++-compile"]) - self.assertEqual(output.feature[0].flag_set[1].flag_group[0].flag, - ["bar-flag-1"]) - self.assertEqual(output.feature[0].flag_set[1].flag_group[1].flag, - ["unfiltered-flag-1"]) - self.assertEqual(output.feature[0].flag_set[1].flag_group[2].flag, - ["bar-flag-2"]) - self.assertEqual(output.feature[0].flag_set[2].action, ["c-compile"]) - self.assertEqual(output.feature[0].flag_set[2].flag_group[0].flag, - ["foo-flag-2"]) - - def test_unfiltered_compile_flags_is_added_at_the_end(self): - crosstool = make_crosstool(""" - feature { name: 'something_else' } - unfiltered_cxx_flag: 'unfiltered-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(output.feature[1].name, "user_compile_flags") - self.assertEqual(output.feature[2].name, "sysroot") - self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") - self.assertEqual(output.feature[3].flag_set[0].action, - ALL_CC_COMPILE_ACTIONS) - self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag, - ["unfiltered-flag-1"]) - - def test_unfiltered_compile_flags_are_not_added_for_objc(self): - crosstool = make_crosstool(""" - action_config { action_name: "obc-compile" } - feature { name: 'something_else' } - unfiltered_cxx_flag: 'unfiltered-flag-1' - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[3].name, "unfiltered_compile_flags") - self.assertEqual(output.feature[3].flag_set[0].action, - ALL_CC_COMPILE_ACTIONS) - self.assertEqual(output.feature[3].flag_set[0].flag_group[0].flag, - ["unfiltered-flag-1"]) - - def test_default_link_flags_is_added_first(self): - crosstool = make_crosstool(""" - linker_flag: 'linker-flag-1' - feature { name: 'something_else' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_link_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["linker-flag-1"]) - - def test_default_link_flags_is_not_added_when_already_present(self): - crosstool = make_crosstool(""" - linker_flag: 'linker-flag-1' - feature { name: 'something_else' } - feature { name: 'default_link_flags' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(output.feature[1].name, "default_link_flags") - - def test_default_compile_flags_is_not_added_when_no_reason_to(self): - crosstool = make_crosstool(""" - feature { name: 'something_else' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(len(output.feature), 1) - - def test_default_compile_flags_is_first(self): - crosstool = make_crosstool(""" - compiler_flag: 'compiler-flag-1' - feature { name: 'something_else' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "default_compile_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag, - ["compiler-flag-1"]) - - def test_default_compile_flags_not_added_when_present(self): - crosstool = make_crosstool(""" - compiler_flag: 'compiler-flag-1' - feature { name: 'something_else' } - feature { name: 'default_compile_flags' } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(output.feature[1].name, "default_compile_flags") - self.assertEqual(len(output.feature[1].flag_set), 0) - - def test_supports_start_end_lib_migrated(self): - crosstool = make_crosstool("supports_start_end_lib: true") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_start_end_lib") - self.assertEqual(output.feature[0].enabled, True) - - def test_supports_start_end_lib_not_migrated_on_false(self): - crosstool = make_crosstool("supports_start_end_lib: false") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.feature), 0) - - def test_supports_start_end_lib_not_migrated_when_already_present(self): - crosstool = make_crosstool(""" - supports_start_end_lib: true - feature { name: "supports_start_end_lib" enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_start_end_lib") - self.assertEqual(output.feature[0].enabled, False) - - def test_supports_interface_shared_libraries_migrated(self): - crosstool = make_crosstool("supports_interface_shared_objects: true") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, - "supports_interface_shared_libraries") - self.assertEqual(output.feature[0].enabled, True) - - def test_supports_interface_shared_libraries_not_migrated_on_false(self): - crosstool = make_crosstool("supports_interface_shared_objects: false") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.feature), 0) - - def test_supports_interface_shared_libraries_not_migrated_when_present(self): - crosstool = make_crosstool(""" - supports_interface_shared_objects: true - feature { - name: "supports_interface_shared_libraries" - enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, - "supports_interface_shared_libraries") - self.assertEqual(output.feature[0].enabled, False) - - def test_supports_embedded_runtimes_migrated(self): - crosstool = make_crosstool("supports_embedded_runtimes: true") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes") - self.assertEqual(output.feature[0].enabled, True) - - def test_supports_embedded_runtimes_not_migrated_on_false(self): - crosstool = make_crosstool("supports_embedded_runtimes: false") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.feature), 0) - - def test_supports_embedded_runtimes_not_migrated_when_already_present(self): - crosstool = make_crosstool(""" - supports_embedded_runtimes: true - feature { name: "static_link_cpp_runtimes" enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "static_link_cpp_runtimes") - self.assertEqual(output.feature[0].enabled, False) - - def test_needs_pic_migrated(self): - crosstool = make_crosstool("needsPic: true") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_pic") - self.assertEqual(output.feature[0].enabled, True) - - def test_needs_pic_not_migrated_on_false(self): - crosstool = make_crosstool("needsPic: false") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.feature), 0) - - def test_needs_pic_not_migrated_when_already_present(self): - crosstool = make_crosstool(""" - needsPic: true - feature { name: "supports_pic" enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "supports_pic") - self.assertEqual(output.feature[0].enabled, False) - - def test_supports_fission_migrated(self): - crosstool = make_crosstool("supports_fission: true") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "per_object_debug_info") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, - ["is_using_fission"]) - - def test_supports_fission_not_migrated_on_false(self): - crosstool = make_crosstool("supports_fission: false") - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(len(output.feature), 0) - - def test_supports_fission_not_migrated_when_already_present(self): - crosstool = make_crosstool(""" - supports_fission: true - feature { name: "per_object_debug_info" enabled: false } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "per_object_debug_info") - self.assertEqual(output.feature[0].enabled, False) - - def test_migrating_objcopy_embed_flag(self): - crosstool = make_crosstool(""" - tool_path { name: "objcopy" path: "foo/objcopy" } - objcopy_embed_flag: "a" - objcopy_embed_flag: "b" - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "objcopy_embed_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].action[:], - ["objcopy_embed_data"]) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], - ["a", "b"]) - self.assertEqual(len(output.objcopy_embed_flag), 0) - self.assertEqual(output.action_config[0].action_name, "objcopy_embed_data") - self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/objcopy") - - def test_not_migrating_objcopy_embed_flag_when_feature_present(self): - crosstool = make_crosstool(""" - objcopy_embed_flag: "a" - objcopy_embed_flag: "b" - feature { name: "objcopy_embed_flags" } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "objcopy_embed_flags") - self.assertEqual(output.feature[0].enabled, False) - - def test_migrating_ld_embed_flag(self): - crosstool = make_crosstool(""" - tool_path { name: "ld" path: "foo/ld" } - ld_embed_flag: "a" - ld_embed_flag: "b" - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "ld_embed_flags") - self.assertEqual(output.feature[0].enabled, True) - self.assertEqual(output.feature[0].flag_set[0].action[:], ["ld_embed_data"]) - self.assertEqual(output.feature[0].flag_set[0].flag_group[0].flag[:], - ["a", "b"]) - self.assertEqual(len(output.ld_embed_flag), 0) - self.assertEqual(output.action_config[0].action_name, "ld_embed_data") - self.assertEqual(output.action_config[0].tool[0].tool_path, "foo/ld") - - def test_not_migrating_objcopy_embed_flag_when_feature_present(self): - crosstool = make_crosstool(""" - objcopy_embed_flag: "a" - objcopy_embed_flag: "b" - feature { name: "objcopy_embed_flags" } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.feature[0].name, "objcopy_embed_flags") - self.assertEqual(output.feature[0].enabled, False) - - def test_migrate_expand_if_all_available_from_flag_sets(self): - crosstool = make_crosstool(""" - action_config { - action_name: 'something' - config_name: 'something' - flag_set { - expand_if_all_available: 'foo' - flag_group { - flag: '%{foo}' - } - flag_group { - flag: 'bar' - } - } - } - feature { - name: 'something_else' - flag_set { - action: 'c-compile' - expand_if_all_available: 'foo' - flag_group { - flag: '%{foo}' - } - flag_group { - flag: 'bar' - } - } - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.action_config[0].action_name, "something") - self.assertEqual(len(output.action_config[0].flag_set), 1) - self.assertEqual( - len(output.action_config[0].flag_set[0].expand_if_all_available), 0) - self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[0] - .expand_if_all_available, ["foo"]) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[1] - .expand_if_all_available, ["foo"]) - - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(len(output.feature[0].flag_set), 1) - self.assertEqual( - len(output.feature[0].flag_set[0].expand_if_all_available), 0) - self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, - ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].expand_if_all_available, - ["foo"]) - - def test_enable_previously_default_features(self): - default_features = [ - "dependency_file", "random_seed", "module_maps", "module_map_home_cwd", - "header_module_compile", "include_paths", "pic", "preprocessor_define" - ] - crosstool = make_crosstool(""" - feature { name: "dependency_file" } - feature { name: "random_seed" } - feature { name: "module_maps" } - feature { name: "module_map_home_cwd" } - feature { name: "header_module_compile" } - feature { name: "include_paths" } - feature { name: "pic" } - feature { name: "preprocessor_define" } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - for i in range(0, 8): - self.assertEqual(output.feature[i].name, default_features[i]) - self.assertTrue(output.feature[i].enabled) - - def test_migrate_repeated_expand_if_all_available_from_flag_groups(self): - crosstool = make_crosstool(""" - action_config { - action_name: 'something' - config_name: 'something' - flag_set { - flag_group { - expand_if_all_available: 'foo' - expand_if_all_available: 'bar' - flag: '%{foo}' - } - flag_group { - expand_if_none_available: 'foo' - expand_if_none_available: 'bar' - flag: 'bar' - } - } - } - feature { - name: 'something_else' - flag_set { - action: 'c-compile' - flag_group { - expand_if_all_available: 'foo' - expand_if_all_available: 'bar' - flag: '%{foo}' - } - flag_group { - expand_if_none_available: 'foo' - expand_if_none_available: 'bar' - flag: 'bar' - } - } - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - self.assertEqual(output.action_config[0].action_name, "something") - self.assertEqual(len(output.action_config[0].flag_set), 1) - self.assertEqual( - len(output.action_config[0].flag_set[0].expand_if_all_available), 0) - self.assertEqual(len(output.action_config[0].flag_set[0].flag_group), 2) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[0] - .expand_if_all_available, ["foo"]) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[0].flag_group[0] - .expand_if_all_available, ["bar"]) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[1] - .expand_if_none_available, ["foo"]) - self.assertEqual( - output.action_config[0].flag_set[0].flag_group[1].flag_group[0] - .expand_if_none_available, ["bar"]) - - self.assertEqual(output.feature[0].name, "something_else") - self.assertEqual(len(output.feature[0].flag_set), 1) - self.assertEqual( - len(output.feature[0].flag_set[0].expand_if_all_available), 0) - self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].expand_if_all_available, - ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].flag_group[0] - .expand_if_all_available, ["bar"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].expand_if_none_available, - ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0] - .expand_if_none_available, ["bar"]) - - def test_migrate_repeated_expands_from_nested_flag_groups(self): - crosstool = make_crosstool(""" - feature { - name: 'something' - flag_set { - action: 'c-compile' - flag_group { - flag_group { - expand_if_all_available: 'foo' - expand_if_all_available: 'bar' - flag: '%{foo}' - } - } - flag_group { - flag_group { - expand_if_all_available: 'foo' - expand_if_all_available: 'bar' - expand_if_none_available: 'foo' - expand_if_none_available: 'bar' - flag: '%{foo}' - } - } - } - } - """) - migrate_legacy_fields(crosstool) - output = crosstool.toolchain[0] - - self.assertEqual(output.feature[0].name, "something") - self.assertEqual(len(output.feature[0].flag_set[0].flag_group), 2) - self.assertEqual( - len(output.feature[0].flag_set[0].flag_group[0].expand_if_all_available - ), 0) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].flag_group[0] - .expand_if_all_available, ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0] - .expand_if_all_available, ["bar"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[0].flag_group[0].flag_group[0] - .flag, ["%{foo}"]) - - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0] - .expand_if_all_available, ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0] - .expand_if_none_available, ["foo"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] - .expand_if_none_available, ["bar"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] - .expand_if_all_available, ["bar"]) - self.assertEqual( - output.feature[0].flag_set[0].flag_group[1].flag_group[0].flag_group[0] - .flag, ["%{foo}"]) - - -if __name__ == "__main__": - unittest.main() diff --git a/tools/migration/legacy_fields_migrator.py b/tools/migration/legacy_fields_migrator.py deleted file mode 100644 index cc1bb41..0000000 --- a/tools/migration/legacy_fields_migrator.py +++ /dev/null @@ -1,69 +0,0 @@ -"""Script migrating legacy CROSSTOOL fields into features. - -This script migrates the CROSSTOOL to use only the features to describe C++ -command lines. It is intended to be added as a last step of CROSSTOOL generation -pipeline. Since it doesn't retain comments, we assume CROSSTOOL owners will want -to migrate their pipeline manually. -""" - -# Tracking issue: https://github.com/bazelbuild/bazel/issues/5187 -# -# Since C++ rules team is working on migrating CROSSTOOL from text proto into -# Starlark, we advise CROSSTOOL owners to wait for the CROSSTOOL -> Starlark -# migrator before they invest too much time into fixing their pipeline. Tracking -# issue for the Starlark effort is -# https://github.com/bazelbuild/bazel/issues/5380. - -from absl import app -from absl import flags -from google.protobuf import text_format -from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 -from tools.migration.legacy_fields_migration_lib import migrate_legacy_fields -import os - -flags.DEFINE_string("input", None, "Input CROSSTOOL file to be migrated") -flags.DEFINE_string("output", None, - "Output path where to write migrated CROSSTOOL.") -flags.DEFINE_boolean("inline", None, "Overwrite --input file") - - -def main(unused_argv): - crosstool = crosstool_config_pb2.CrosstoolRelease() - - input_filename = flags.FLAGS.input - output_filename = flags.FLAGS.output - inline = flags.FLAGS.inline - - if not input_filename: - raise app.UsageError("ERROR --input unspecified") - if not output_filename and not inline: - raise app.UsageError("ERROR --output unspecified and --inline not passed") - if output_filename and inline: - raise app.UsageError("ERROR both --output and --inline passed") - - with open(to_absolute_path(input_filename), "r") as f: - input_text = f.read() - - text_format.Merge(input_text, crosstool) - - migrate_legacy_fields(crosstool) - output_text = text_format.MessageToString(crosstool) - - resolved_output_filename = to_absolute_path( - input_filename if inline else output_filename) - with open(resolved_output_filename, "w") as f: - f.write(output_text) - -def to_absolute_path(path): - path = os.path.expanduser(path) - if os.path.isabs(path): - return path - else: - if "BUILD_WORKING_DIRECTORY" in os.environ: - return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) - else: - return path - - -if __name__ == "__main__": - app.run(main)