Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Geoffrey Martin-Noble | 552d3f8 | 2021-05-25 17:56:09 -0700 | [diff] [blame] | 2 | # Copyright 2020 The IREE Authors |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 3 | # |
Geoffrey Martin-Noble | 552d3f8 | 2021-05-25 17:56:09 -0700 | [diff] [blame] | 4 | # Licensed under the Apache License v2.0 with LLVM Exceptions. |
| 5 | # See https://llvm.org/LICENSE.txt for license information. |
| 6 | # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 7 | """This script assists with converting from Bazel BUILD files to CMakeLists.txt. |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 8 | |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 9 | Bazel BUILD files should, where possible, be written to use simple features |
| 10 | that can be directly evaluated and avoid more advanced features like |
| 11 | variables, list comprehensions, etc. |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 12 | |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 13 | Generated CMake files will be similar in structure to their source BUILD |
| 14 | files by using the functions in build_tools/cmake/ that imitate corresponding |
| 15 | Bazel rules (e.g. cc_library -> iree_cc_library.cmake). |
| 16 | |
| 17 | For usage, see: |
| 18 | python3 build_tools/bazel_to_cmake/bazel_to_cmake.py --help |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 19 | |
| 20 | Configuration |
| 21 | ------------- |
| 22 | When invoked, bazel_to_cmake will traverse up from the current directory until |
| 23 | it finds a ".bazel_to_cmake.cfg.py" file. This file both serves as a marker |
| 24 | for the repository root and provides repository specific configuration. |
| 25 | |
| 26 | The file is evaluated as a module and can have the following customizations: |
| 27 | |
| 28 | * DEFAULT_ROOT_DIRS: A list of root directory names that should be processed |
| 29 | (relative to the repository root) when invoked without a --repo_root or --dir. |
| 30 | * REPO_MAP: Mapping of canonical Bazel repo name (i.e. "@iree_core") to what it |
| 31 | is known as locally (most commonly the empty string). This is used in global |
| 32 | target rules to make sure that they work either in the defining or referencing |
| 33 | repository. |
| 34 | * CustomBuildFileFunctions: A class that extends |
| 35 | `bazel_to_cmake_converter.BuildFileFunctions` and injects globals for |
| 36 | processing the BUILD file. All symbols that do not start with "_" are |
| 37 | available. |
| 38 | * CustomTargetConverter: A class that extends |
| 39 | `bazel_to_cmake_targets.TargetConverter` and customizes target mapping. |
| 40 | Typically, this is used for purely local targets in leaf projects (as global |
| 41 | targets will be encoded in the main bazel_to_cmake_targets.py file). |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 42 | """ |
Geoffrey Martin-Noble | ea9c683 | 2020-02-29 20:26:35 -0800 | [diff] [blame] | 43 | # pylint: disable=missing-docstring |
Geoffrey Martin-Noble | ea9c683 | 2020-02-29 20:26:35 -0800 | [diff] [blame] | 44 | |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 45 | import argparse |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 46 | import datetime |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 47 | import importlib |
| 48 | import importlib.util |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 49 | import os |
Geoffrey Martin-Noble | 2a36c38 | 2020-01-28 15:04:30 -0800 | [diff] [blame] | 50 | import re |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 51 | import sys |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 52 | import textwrap |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 53 | import types |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 54 | from enum import Enum |
Geoffrey Martin-Noble | ea9c683 | 2020-02-29 20:26:35 -0800 | [diff] [blame] | 55 | |
Geoffrey Martin-Noble | bdeb1ab | 2020-03-31 13:27:14 -0700 | [diff] [blame] | 56 | import bazel_to_cmake_converter |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 57 | |
| 58 | repo_root = None |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 59 | repo_cfg = None |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 60 | |
Geoffrey Martin-Noble | 2a36c38 | 2020-01-28 15:04:30 -0800 | [diff] [blame] | 61 | EDIT_BLOCKING_PATTERN = re.compile( |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 62 | r"bazel[\s_]*to[\s_]*cmake[\s_]*:?[\s_]*do[\s_]*not[\s_]*edit", flags=re.IGNORECASE |
| 63 | ) |
Geoffrey Martin-Noble | 2a36c38 | 2020-01-28 15:04:30 -0800 | [diff] [blame] | 64 | |
Stella Laurenzo | be0f1e1 | 2023-04-03 13:34:38 -0700 | [diff] [blame] | 65 | PRESERVE_ABOVE_TAG = "### BAZEL_TO_CMAKE_PRESERVES_ALL_CONTENT_ABOVE_THIS_LINE ###" |
| 66 | PRESERVE_BELOW_TAG = "### BAZEL_TO_CMAKE_PRESERVES_ALL_CONTENT_BELOW_THIS_LINE ###" |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 67 | REPO_CFG_FILE = ".bazel_to_cmake.cfg.py" |
| 68 | REPO_CFG_MODULE_NAME = "bazel_to_cmake_repo_config" |
Geoffrey Martin-Noble | 98a806c | 2021-02-25 16:57:31 -0800 | [diff] [blame] | 69 | |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 70 | |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 71 | class Status(Enum): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 72 | UPDATED = 1 |
| 73 | NOOP = 2 |
| 74 | FAILED = 3 |
| 75 | SKIPPED = 4 |
| 76 | NO_BUILD_FILE = 5 |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 77 | |
| 78 | |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 79 | def parse_arguments(): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 80 | parser = argparse.ArgumentParser(description="Bazel to CMake conversion helper.") |
| 81 | parser.add_argument( |
| 82 | "--preview", |
| 83 | help="Prints results instead of writing files", |
| 84 | action="store_true", |
| 85 | default=False, |
| 86 | ) |
| 87 | parser.add_argument( |
| 88 | "--allow_partial_conversion", |
| 89 | help="Generates partial files, ignoring errors during conversion.", |
| 90 | action="store_true", |
| 91 | default=False, |
| 92 | ) |
| 93 | parser.add_argument( |
| 94 | "--verbosity", |
| 95 | "-v", |
| 96 | type=int, |
| 97 | default=0, |
| 98 | help="Specify verbosity level where higher verbosity emits more logging." |
| 99 | " 0 (default): Only output errors and summary statistics." |
| 100 | " 1: Also output the name of each directory as it's being processed and" |
| 101 | " whether the directory is skipped." |
| 102 | " 2: Also output when conversion was successful.", |
| 103 | ) |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 104 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 105 | # Specify only one of these (defaults to --root_dir=<main source dirs>). |
| 106 | group = parser.add_mutually_exclusive_group() |
| 107 | group.add_argument( |
| 108 | "--dir", help="Converts the BUILD file in the given directory", default=None |
| 109 | ) |
| 110 | default_root_dirs = ( |
| 111 | repo_cfg.DEFAULT_ROOT_DIRS if hasattr(repo_cfg, "DEFAULT_ROOT_DIRS") else [] |
| 112 | ) |
| 113 | group.add_argument( |
| 114 | "--root_dir", |
| 115 | nargs="+", |
| 116 | help="Converts all BUILD files under a root directory", |
| 117 | default=default_root_dirs, |
| 118 | ) |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 119 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 120 | args = parser.parse_args() |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 121 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 122 | # --dir takes precedence over --root_dir. |
| 123 | # They are mutually exclusive, but the default value is still set. |
| 124 | if args.dir: |
| 125 | args.root_dir = None |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 126 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 127 | return args |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 128 | |
| 129 | |
| 130 | def setup_environment(): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 131 | """Sets up some environment globals.""" |
| 132 | global repo_root |
| 133 | global repo_cfg |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 134 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 135 | # Scan up the directory tree for a repo config file. |
| 136 | check_dir = os.getcwd() |
| 137 | while not os.path.exists(os.path.join(check_dir, REPO_CFG_FILE)): |
| 138 | new_check_dir = os.path.dirname(check_dir) |
| 139 | if not new_check_dir or new_check_dir == check_dir: |
| 140 | print( |
| 141 | f"ERROR: Could not find {REPO_CFG_FILE} in a parent directory " |
| 142 | f"of {os.getcwd()}" |
| 143 | ) |
| 144 | sys.exit(1) |
| 145 | check_dir = new_check_dir |
| 146 | repo_root = check_dir |
| 147 | log(f"Using repo root {repo_root}") |
Stella Laurenzo | 6f24a2f | 2023-03-27 17:08:20 -0700 | [diff] [blame] | 148 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 149 | # Dynamically load the config file as a module. |
| 150 | orig_dont_write_bytecode = sys.dont_write_bytecode |
| 151 | sys.dont_write_bytecode = True # Don't generate __pycache__ dir |
| 152 | repo_cfg_path = os.path.join(repo_root, REPO_CFG_FILE) |
| 153 | spec = importlib.util.spec_from_file_location(REPO_CFG_MODULE_NAME, repo_cfg_path) |
| 154 | if spec and spec.loader: |
| 155 | repo_cfg = importlib.util.module_from_spec(spec) |
| 156 | sys.modules[REPO_CFG_MODULE_NAME] = repo_cfg |
| 157 | spec.loader.exec_module(repo_cfg) |
| 158 | sys.dont_write_bytecode = orig_dont_write_bytecode |
| 159 | else: |
| 160 | print(f"INTERNAL ERROR: Could not evaluate {repo_cfg_path} as module") |
| 161 | sys.exit(1) |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 162 | |
| 163 | |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 164 | def repo_relpath(path): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 165 | return os.path.relpath(path, repo_root).replace("\\", "/") |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 166 | |
| 167 | |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 168 | def log(string, *args, indent=0, **kwargs): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 169 | print( |
| 170 | textwrap.indent(string, prefix=(indent * " ")), *args, **kwargs, file=sys.stderr |
| 171 | ) |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 172 | |
| 173 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 174 | def convert_directories(directories, write_files, allow_partial_conversion, verbosity): |
| 175 | failure_dirs = [] |
| 176 | skip_count = 0 |
| 177 | success_count = 0 |
| 178 | noop_count = 0 |
| 179 | for directory in directories: |
| 180 | status = convert_directory( |
| 181 | directory, |
| 182 | write_files=write_files, |
| 183 | allow_partial_conversion=allow_partial_conversion, |
| 184 | verbosity=verbosity, |
| 185 | ) |
| 186 | if status == Status.FAILED: |
| 187 | failure_dirs.append(repo_relpath(directory)) |
| 188 | elif status == Status.SKIPPED: |
| 189 | skip_count += 1 |
| 190 | elif status == Status.UPDATED: |
| 191 | success_count += 1 |
| 192 | elif status == Status.NOOP: |
| 193 | noop_count += 1 |
Geoffrey Martin-Noble | d2cb996 | 2021-02-19 17:30:26 -0800 | [diff] [blame] | 194 | |
Geoffrey Martin-Noble | 0e34ffa | 2021-02-25 18:16:45 -0800 | [diff] [blame] | 195 | log( |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 196 | f"{success_count} CMakeLists.txt files were updated, {skip_count} were" |
| 197 | f" skipped, and {noop_count} required no change." |
| 198 | ) |
| 199 | if failure_dirs: |
| 200 | log( |
| 201 | f"ERROR: Encountered unexpected errors converting {len(failure_dirs)}" |
| 202 | " directories:" |
| 203 | ) |
| 204 | log("\n".join(failure_dirs), indent=2) |
| 205 | sys.exit(1) |
Geoffrey Martin-Noble | 0e34ffa | 2021-02-25 18:16:45 -0800 | [diff] [blame] | 206 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 207 | |
| 208 | def convert_directory(directory_path, write_files, allow_partial_conversion, verbosity): |
| 209 | if not os.path.isdir(directory_path): |
| 210 | raise FileNotFoundError(f"Cannot find directory '{directory_path}'") |
| 211 | |
| 212 | rel_dir_path = repo_relpath(directory_path) |
| 213 | if verbosity >= 1: |
| 214 | log(f"Processing {rel_dir_path}") |
| 215 | |
| 216 | # Scan for a BUILD file. |
| 217 | build_file_found = False |
| 218 | build_file_basenames = ["BUILD", "BUILD.bazel"] |
| 219 | for build_file_basename in build_file_basenames: |
| 220 | build_file_path = os.path.join(directory_path, build_file_basename) |
| 221 | |
| 222 | rel_build_file_path = repo_relpath(build_file_path) |
| 223 | if os.path.isfile(build_file_path): |
| 224 | build_file_found = True |
| 225 | break |
| 226 | cmakelists_file_path = os.path.join(directory_path, "CMakeLists.txt") |
| 227 | rel_cmakelists_file_path = repo_relpath(cmakelists_file_path) |
| 228 | |
| 229 | if not build_file_found: |
| 230 | return Status.NO_BUILD_FILE |
| 231 | |
| 232 | autogeneration_tag = f"Autogenerated by {repo_relpath(os.path.abspath(__file__))}" |
| 233 | |
| 234 | header = "\n".join( |
| 235 | ["#" * 80] |
| 236 | + [ |
| 237 | l.ljust(79) + "#" |
| 238 | for l in [ |
| 239 | f"# {autogeneration_tag} from", |
| 240 | f"# {rel_build_file_path}", |
| 241 | "#", |
| 242 | "# Use iree_cmake_extra_content from iree/build_defs.oss.bzl to add arbitrary", |
| 243 | "# CMake-only content.", |
| 244 | "#", |
| 245 | f"# To disable autogeneration for this file entirely, delete this header.", |
| 246 | ] |
| 247 | ] |
| 248 | + ["#" * 80] |
| 249 | ) |
| 250 | |
| 251 | old_lines = [] |
| 252 | possible_preserved_header_lines = [] |
| 253 | preserved_footer_lines = ["\n" + PRESERVE_BELOW_TAG + "\n"] |
| 254 | |
| 255 | # Read CMakeLists.txt and check if it has the auto-generated header. |
| 256 | found_preserve_below_tag = False |
| 257 | found_preserve_above_tag = False |
| 258 | if os.path.isfile(cmakelists_file_path): |
| 259 | found_autogeneration_tag = False |
| 260 | with open(cmakelists_file_path) as f: |
| 261 | old_lines = f.readlines() |
| 262 | |
| 263 | for line in old_lines: |
| 264 | if not found_preserve_above_tag: |
| 265 | possible_preserved_header_lines.append(line) |
| 266 | if not found_autogeneration_tag and autogeneration_tag in line: |
| 267 | found_autogeneration_tag = True |
| 268 | if not found_preserve_below_tag and PRESERVE_BELOW_TAG in line: |
| 269 | found_preserve_below_tag = True |
| 270 | elif not found_preserve_above_tag and PRESERVE_ABOVE_TAG in line: |
| 271 | found_preserve_above_tag = True |
| 272 | elif found_preserve_below_tag: |
| 273 | preserved_footer_lines.append(line) |
| 274 | if not found_autogeneration_tag: |
| 275 | if verbosity >= 1: |
| 276 | log(f"Skipped. Did not find autogeneration line.", indent=2) |
| 277 | return Status.SKIPPED |
| 278 | preserved_header = ( |
| 279 | "".join(possible_preserved_header_lines) if found_preserve_above_tag else "" |
| 280 | ) |
| 281 | preserved_footer = "".join(preserved_footer_lines) |
| 282 | |
| 283 | # Read the Bazel BUILD file and interpret it. |
| 284 | with open(build_file_path, "rt") as build_file: |
| 285 | build_file_contents = build_file.read() |
| 286 | if "bazel-to-cmake: skip" in build_file_contents: |
| 287 | return Status.SKIPPED |
| 288 | build_file_code = compile(build_file_contents, build_file_path, "exec") |
| 289 | try: |
| 290 | converted_build_file = bazel_to_cmake_converter.convert_build_file( |
| 291 | build_file_code, |
| 292 | repo_cfg=repo_cfg, |
| 293 | allow_partial_conversion=allow_partial_conversion, |
| 294 | ) |
| 295 | except (NameError, NotImplementedError) as e: |
| 296 | log( |
| 297 | f"ERROR generating {rel_dir_path}.\n" |
| 298 | f"Missing a rule handler in bazel_to_cmake_converter.py?\n" |
| 299 | f"Reason: `{type(e).__name__}: {e}`", |
| 300 | indent=2, |
| 301 | ) |
| 302 | return Status.FAILED |
| 303 | except KeyError as e: |
| 304 | log( |
| 305 | f"ERROR generating {rel_dir_path}.\n" |
| 306 | f"Missing a conversion in bazel_to_cmake_targets.py?\n" |
| 307 | f"Reason: `{type(e).__name__}: {e}`", |
| 308 | indent=2, |
| 309 | ) |
| 310 | return Status.FAILED |
| 311 | converted_content = ( |
| 312 | preserved_header + header + converted_build_file + preserved_footer |
| 313 | ) |
| 314 | if write_files: |
| 315 | with open(cmakelists_file_path, "wt") as cmakelists_file: |
| 316 | cmakelists_file.write(converted_content) |
| 317 | else: |
| 318 | print(converted_content, end="") |
| 319 | |
| 320 | if converted_content == "".join(old_lines): |
| 321 | if verbosity >= 2: |
| 322 | log(f"{rel_cmakelists_file_path} required no update", indent=2) |
| 323 | return Status.NOOP |
| 324 | |
Geoffrey Martin-Noble | 0e34ffa | 2021-02-25 18:16:45 -0800 | [diff] [blame] | 325 | if verbosity >= 2: |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 326 | log( |
| 327 | f"Successfly generated {rel_cmakelists_file_path}" |
| 328 | f" from {rel_build_file_path}", |
| 329 | indent=2, |
| 330 | ) |
| 331 | return Status.UPDATED |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 332 | |
| 333 | |
| 334 | def main(args): |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 335 | """Runs Bazel to CMake conversion.""" |
| 336 | global repo_root |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 337 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 338 | write_files = not args.preview |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 339 | |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 340 | if args.root_dir: |
| 341 | for root_dir in args.root_dir: |
| 342 | root_directory_path = os.path.join(repo_root, root_dir) |
| 343 | log(f"Converting directory tree rooted at: {root_directory_path}") |
| 344 | convert_directories( |
| 345 | (root for root, _, _ in os.walk(root_directory_path)), |
| 346 | write_files=write_files, |
| 347 | allow_partial_conversion=args.allow_partial_conversion, |
| 348 | verbosity=args.verbosity, |
| 349 | ) |
| 350 | elif args.dir: |
| 351 | convert_directories( |
| 352 | [os.path.join(repo_root, args.dir)], |
| 353 | write_files=write_files, |
| 354 | allow_partial_conversion=args.allow_partial_conversion, |
| 355 | verbosity=args.verbosity, |
| 356 | ) |
| 357 | else: |
| 358 | log( |
| 359 | f"ERROR: None of --root-dir, --dir arguments or DEFAULT_ROOT_DIRS in " |
| 360 | f".bazel_to_cmake.cfg.py: No conversion will be done" |
| 361 | ) |
| 362 | sys.exit(1) |
Scott Todd | d0a0629 | 2020-01-24 14:41:50 -0800 | [diff] [blame] | 363 | |
| 364 | |
| 365 | if __name__ == "__main__": |
Jakub Kuderski | be24f02 | 2023-06-21 14:44:18 -0400 | [diff] [blame^] | 366 | setup_environment() |
| 367 | main(parse_arguments()) |