rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 1 | # Copyright 2018 The Bazel Authors. All rights reserved. |
| 2 | # |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | r"""A script that compares 2 CToolchains from proto format. |
| 15 | |
| 16 | This script accepts two files in either a CROSSTOOL proto text format or a |
| 17 | CToolchain proto text format. It then locates the CToolchains with the given |
| 18 | toolchain_identifier and checks if the resulting CToolchain objects in Java |
| 19 | are the same. |
| 20 | |
| 21 | Example usage: |
| 22 | |
| 23 | bazel run \ |
| 24 | @rules_cc//tools/migration:ctoolchain_comparator -- \ |
| 25 | --before=/path/to/CROSSTOOL1 \ |
| 26 | --after=/path/to/CROSSTOOL2 \ |
| 27 | --toolchain_identifier=id |
| 28 | """ |
| 29 | |
| 30 | import os |
| 31 | from absl import app |
| 32 | from absl import flags |
| 33 | from google.protobuf import text_format |
| 34 | from third_party.com.github.bazelbuild.bazel.src.main.protobuf import crosstool_config_pb2 |
| 35 | from tools.migration.ctoolchain_comparator_lib import compare_ctoolchains |
| 36 | |
| 37 | flags.DEFINE_string( |
| 38 | "before", None, |
| 39 | ("A text proto file containing the relevant CTooclchain before the change, " |
| 40 | "either a CROSSTOOL file or a single CToolchain proto text")) |
| 41 | flags.DEFINE_string( |
| 42 | "after", None, |
| 43 | ("A text proto file containing the relevant CToolchain after the change, " |
| 44 | "either a CROSSTOOL file or a single CToolchain proto text")) |
| 45 | flags.DEFINE_string("toolchain_identifier", None, |
| 46 | "The identifier of the CToolchain that is being compared.") |
| 47 | flags.mark_flag_as_required("before") |
| 48 | flags.mark_flag_as_required("after") |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 49 | |
| 50 | |
| 51 | def _to_absolute_path(path): |
| 52 | path = os.path.expanduser(path) |
| 53 | if os.path.isabs(path): |
| 54 | return path |
| 55 | else: |
| 56 | if "BUILD_WORKING_DIRECTORY" in os.environ: |
| 57 | return os.path.join(os.environ["BUILD_WORKING_DIRECTORY"], path) |
| 58 | else: |
| 59 | return path |
| 60 | |
| 61 | |
| 62 | def _find_toolchain(crosstool, toolchain_identifier): |
| 63 | for toolchain in crosstool.toolchain: |
| 64 | if toolchain.toolchain_identifier == toolchain_identifier: |
| 65 | return toolchain |
| 66 | return None |
| 67 | |
| 68 | |
Googler | e68ae76 | 2019-08-09 05:42:58 -0700 | [diff] [blame] | 69 | def _read_crosstool_or_ctoolchain_proto(input_file, toolchain_identifier=None): |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 70 | """Reads a proto file and finds the CToolchain with the given identifier.""" |
| 71 | with open(input_file, "r") as f: |
| 72 | text = f.read() |
| 73 | crosstool_release = crosstool_config_pb2.CrosstoolRelease() |
| 74 | c_toolchain = crosstool_config_pb2.CToolchain() |
| 75 | try: |
| 76 | text_format.Merge(text, crosstool_release) |
Googler | e68ae76 | 2019-08-09 05:42:58 -0700 | [diff] [blame] | 77 | if toolchain_identifier is None: |
| 78 | print("CROSSTOOL proto needs a 'toolchain_identifier' specified in " |
| 79 | "order to be able to select the right toolchain for comparison.") |
| 80 | return None |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 81 | toolchain = _find_toolchain(crosstool_release, toolchain_identifier) |
| 82 | if toolchain is None: |
Googler | da4639b | 2019-01-18 11:20:12 -0800 | [diff] [blame] | 83 | print(("Cannot find a CToolchain with an identifier '%s' in CROSSTOOL " |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 84 | "file") % toolchain_identifier) |
| 85 | return None |
rosica | f64680e | 2019-01-18 07:37:01 -0800 | [diff] [blame] | 86 | return toolchain |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 87 | except text_format.ParseError as crosstool_error: |
| 88 | try: |
| 89 | text_format.Merge(text, c_toolchain) |
Googler | e68ae76 | 2019-08-09 05:42:58 -0700 | [diff] [blame] | 90 | if (toolchain_identifier is not None and |
| 91 | c_toolchain.toolchain_identifier != toolchain_identifier): |
Googler | da4639b | 2019-01-18 11:20:12 -0800 | [diff] [blame] | 92 | print(("Expected CToolchain with identifier '%s', got CToolchain with " |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 93 | "identifier '%s'" % (toolchain_identifier, |
| 94 | c_toolchain.toolchain_identifier))) |
| 95 | return None |
| 96 | return c_toolchain |
| 97 | except text_format.ParseError as toolchain_error: |
| 98 | print(("Error parsing file '%s':" % input_file)) # pylint: disable=superfluous-parens |
| 99 | print("Attempt to parse it as a CROSSTOOL proto:") # pylint: disable=superfluous-parens |
| 100 | print(crosstool_error) # pylint: disable=superfluous-parens |
| 101 | print("Attempt to parse it as a CToolchain proto:") # pylint: disable=superfluous-parens |
| 102 | print(toolchain_error) # pylint: disable=superfluous-parens |
| 103 | return None |
| 104 | |
| 105 | |
| 106 | def main(unused_argv): |
| 107 | |
| 108 | before_file = _to_absolute_path(flags.FLAGS.before) |
| 109 | after_file = _to_absolute_path(flags.FLAGS.after) |
| 110 | toolchain_identifier = flags.FLAGS.toolchain_identifier |
| 111 | |
| 112 | toolchain_before = _read_crosstool_or_ctoolchain_proto( |
| 113 | before_file, toolchain_identifier) |
| 114 | toolchain_after = _read_crosstool_or_ctoolchain_proto(after_file, |
| 115 | toolchain_identifier) |
| 116 | |
| 117 | if not toolchain_before or not toolchain_after: |
Googler | da4639b | 2019-01-18 11:20:12 -0800 | [diff] [blame] | 118 | print("There was an error getting the required toolchains.") |
| 119 | exit(1) |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 120 | |
rosica | f64680e | 2019-01-18 07:37:01 -0800 | [diff] [blame] | 121 | found_difference = compare_ctoolchains(toolchain_before, toolchain_after) |
| 122 | if found_difference: |
| 123 | exit(1) |
rosica | 175f81c | 2019-01-08 14:29:28 +0100 | [diff] [blame] | 124 | |
| 125 | |
| 126 | if __name__ == "__main__": |
| 127 | app.run(main) |