blob: 0a627b17a38650b79daea10c7606c56febafdc06 [file] [log] [blame]
Scott Toddd0a06292020-01-24 14:41:50 -08001#!/usr/bin/env python3
2# Copyright 2020 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# This script assists with converting from Bazel BUILD files to CMakeLists.txt.
17#
18# Bazel BUILD files should, where possible, be written to use simple features
19# that can be directly evaluated and avoid more advanced features like
20# variables, list comprehensions, etc.
21#
22# Generated CMake files will be similar in structure to their source BUILD
23# files by using the functions in build_tools/cmake/ that imitate corresponding
24# Bazel rules (e.g. cc_library -> iree_cc_library.cmake).
25#
26# For usage, see:
Geoffrey Martin-Nobleb9aa31f2020-02-04 13:24:14 -080027# python3 build_tools/bazel_to_cmake/bazel_to_cmake.py --help
Scott Toddd0a06292020-01-24 14:41:50 -080028
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -080029# pylint: disable=missing-docstring
30# pylint: disable=invalid-name
31# pylint: disable=unused-argument
32# pylint: disable=exec-used
33
Scott Toddd0a06292020-01-24 14:41:50 -080034import argparse
Scott Toddd0a06292020-01-24 14:41:50 -080035import datetime
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -080036import itertools
Scott Toddd0a06292020-01-24 14:41:50 -080037import os
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -080038import re
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -080039import textwrap
40
41import bazel_to_cmake_targets
Scott Toddd0a06292020-01-24 14:41:50 -080042
43repo_root = None
44
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -080045EDIT_BLOCKING_PATTERN = re.compile(
Geoffrey Martin-Noblec9784d62020-02-18 13:49:49 -080046 r"bazel[\s_]*to[\s_]*cmake[\s_]*:?[\s_]*do[\s_]*not[\s_]*edit",
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -080047 flags=re.IGNORECASE)
48
Scott Toddd0a06292020-01-24 14:41:50 -080049
50def parse_arguments():
51 global repo_root
52
53 parser = argparse.ArgumentParser(
54 description="Bazel to CMake conversion helper.")
55 parser.add_argument(
56 "--preview",
57 help="Prints results instead of writing files",
58 action="store_true",
59 default=False)
Geoffrey Martin-Noblef26a05a2020-03-06 13:09:25 -080060 # TODO(b/149926655): Invert the default to be strict and rename this flag.
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -080061 parser.add_argument(
62 "--strict",
63 help="Does not try to generate files where it cannot convert completely",
64 action="store_true",
65 default=False)
Scott Toddd0a06292020-01-24 14:41:50 -080066
67 # Specify only one of these (defaults to --root_dir=iree).
68 group = parser.add_mutually_exclusive_group()
69 group.add_argument(
70 "--dir",
71 help="Converts the BUILD file in the given directory",
72 default=None)
73 group.add_argument(
74 "--root_dir",
75 help="Converts all BUILD files under a root directory (defaults to iree/)",
76 default="iree")
77
78 # TODO(scotttodd): --check option that returns success/failure depending on
79 # if files match the converted versions
80
81 args = parser.parse_args()
82
83 # --dir takes precedence over --root_dir.
84 # They are mutually exclusive, but the default value is still set.
85 if args.dir:
86 args.root_dir = None
87
88 return args
89
90
91def setup_environment():
92 """Sets up some environment globals."""
93 global repo_root
94
95 # Determine the repository root (two dir-levels up).
96 repo_root = os.path.dirname(
97 os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
98
99
100class BuildFileFunctions(object):
101 """Object passed to `exec` that has handlers for BUILD file functions."""
102
103 def __init__(self, converter):
104 self.converter = converter
Geoffrey Martin-Noble2b09fce2020-02-25 12:03:55 -0800105 # TODO(gcmn): Do this in a less hard-coded way
106 self.PLATFORM_VULKAN_DEPS = []
107 self.PLATFORM_VULKAN_TEST_DEPS = ["//iree/testing:gtest_main"]
108 self.FLATBUFFER_SUPPORTS_REFLECTIONS = False
109 self.PLATFORM_VULKAN_LOADER_COPTS = []
Geoffrey Martin-Noble1029c892020-02-27 15:37:08 -0800110 self.IREE_DRIVER_MODULES = [
Geoffrey Martin-Noble1029c892020-02-27 15:37:08 -0800111 # TODO(b/142004903): enable when Dawn HAL implementation is functional
112 # "//iree/hal/dawn:dawn_driver_module",
113 "//iree/hal/vmla:vmla_driver_module",
114 "//iree/hal/vulkan:vulkan_driver_module",
115 "//iree/hal/llvmjit:llvmjit_driver_module",
116 ]
Scott Toddd0a06292020-01-24 14:41:50 -0800117
118 # ------------------------------------------------------------------------- #
119 # Conversion utilities, written to reduce boilerplate and allow for reuse #
120 # between similar rule conversions (e.g. cc_library and cc_binary). #
121 # ------------------------------------------------------------------------- #
122
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800123 def _convert_name_block(self, name):
Scott Toddd0a06292020-01-24 14:41:50 -0800124 # NAME
125 # rule_name
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700126 return f" NAME\n {name}\n"
Scott Toddd0a06292020-01-24 14:41:50 -0800127
Marius Brehler855a4192020-02-20 10:45:52 -0800128 def _convert_out_block(self, out):
129 # OUT
130 # out_name
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700131 return f" OUT\n {out}\n"
Marius Brehler855a4192020-02-20 10:45:52 -0800132
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800133 def _convert_cc_namespace_block(self, cc_namespace):
Scott Toddd0a06292020-01-24 14:41:50 -0800134 # CC_NAMESPACE
135 # "cc_namespace"
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800136 if not cc_namespace:
137 return ""
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700138 return f' CC_NAMESPACE\n "{cc_namespace}"\n'
Scott Toddd0a06292020-01-24 14:41:50 -0800139
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800140 def _convert_cpp_namespace_block(self, cpp_namespace):
Marius Brehlerfa765802020-01-27 11:53:39 -0800141 # CPP_NAMESPACE
142 # "cpp_namespace"
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700143 if not cpp_namespace:
144 return ""
145 return f' CPP_NAMESPACE\n "{cpp_namespace}"\n'
Marius Brehlerfa765802020-01-27 11:53:39 -0800146
Scott Todd90b44f72020-03-03 16:44:14 -0800147 def _convert_flags_block(self, flags):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700148 flags_list = "\n".join([f' "{flag}"' for flag in flags])
149 return f" FLAGS\n{flags_list}\n"
Scott Toddd0a06292020-01-24 14:41:50 -0800150
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800151 def _convert_translate_tool_block(self, translate_tool):
Ben Vanikd572ef62020-03-26 12:15:16 -0700152 if translate_tool and translate_tool != "//iree/tools:iree-translate":
Marius Brehlerfa765802020-01-27 11:53:39 -0800153 # Bazel `//iree/base` -> CMake `iree::base`
154 # Bazel `//iree/base:api` -> CMake `iree::base::api`
Geoffrey Martin-Noblec9784d62020-02-18 13:49:49 -0800155 translate_tool = translate_tool.replace("//iree", "iree") # iree/base:api
Marius Brehlerfa765802020-01-27 11:53:39 -0800156 translate_tool = translate_tool.replace(":", "_") # iree/base::api
157 translate_tool = translate_tool.replace("/", "_") # iree::base::api
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700158 return f" TRANSLATE_TOOL\n {translate_tool}\n"
Marius Brehlerfa765802020-01-27 11:53:39 -0800159 else:
160 return ""
161
Scott Toddd0a06292020-01-24 14:41:50 -0800162 def _convert_option_block(self, option, option_value):
163 if option_value:
164 # Note: this is a truthiness check as well as an existence check, i.e.
165 # Bazel `testonly = False` will be handled correctly by this condition.
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700166 return f" {option}\n"
Scott Toddd0a06292020-01-24 14:41:50 -0800167 else:
168 return ""
169
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800170 def _convert_alwayslink_block(self, alwayslink):
171 return self._convert_option_block("ALWAYSLINK", alwayslink)
Scott Toddd0a06292020-01-24 14:41:50 -0800172
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800173 def _convert_testonly_block(self, testonly):
174 return self._convert_option_block("TESTONLY", testonly)
Scott Toddd0a06292020-01-24 14:41:50 -0800175
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800176 def _convert_flatten_block(self, flatten):
177 return self._convert_option_block("FLATTEN", flatten)
Marius Brehlerfa765802020-01-27 11:53:39 -0800178
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800179 def _convert_file_list_block(self, list_name, files):
Scott Toddd0a06292020-01-24 14:41:50 -0800180 # list_name
181 # "file_1.h"
182 # "file_2.h"
183 # "file_3.h"
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700184 if not files:
185 return ""
186 files_list = "\n".join([f' "{file}"' for file in files])
187 return f" {list_name}\n{files_list}\n"
Scott Toddd0a06292020-01-24 14:41:50 -0800188
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800189 def _convert_hdrs_block(self, hdrs):
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800190 return self._convert_file_list_block("HDRS", hdrs)
Scott Toddd0a06292020-01-24 14:41:50 -0800191
Marius Brehler2a53ec92020-01-29 14:48:49 -0800192 def _convert_textual_hdrs_block(self, textual_hdrs):
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800193 return self._convert_file_list_block("TEXTUAL_HDRS", textual_hdrs)
Marius Brehler2a53ec92020-01-29 14:48:49 -0800194
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800195 def _convert_srcs_block(self, srcs):
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800196 return self._convert_file_list_block("SRCS", srcs)
Scott Toddd0a06292020-01-24 14:41:50 -0800197
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800198 def _convert_src_block(self, src):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700199 return f' SRC\n "{src}"\n'
Scott Toddd0a06292020-01-24 14:41:50 -0800200
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800201 def _convert_cc_file_output_block(self, cc_file_output):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700202 return f' CC_FILE_OUTPUT\n "{cc_file_output}"\n'
Marius Brehlerfa765802020-01-27 11:53:39 -0800203
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800204 def _convert_h_file_output_block(self, h_file_output):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700205 return f' H_FILE_OUTPUT\n "{h_file_output}"\n'
Marius Brehlerfa765802020-01-27 11:53:39 -0800206
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800207 def _convert_td_file_block(self, td_file):
Marius Brehlerfa765802020-01-27 11:53:39 -0800208 if td_file.startswith("//iree"):
209 # Bazel `//iree/dir/td_file.td`
210 # -> CMake `${IREE_ROOT_DIR}/iree/dir/td_file.td
211 # Bazel `//iree/dir/IR:td_file.td`
212 # -> CMake `${IREE_ROOT_DIR}/iree/dir/IR/td_file.td
Geoffrey Martin-Noblec9784d62020-02-18 13:49:49 -0800213 td_file = td_file.replace("//iree", "${IREE_ROOT_DIR}/iree")
Marius Brehlerfa765802020-01-27 11:53:39 -0800214 td_file = td_file.replace(":", "/")
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700215 return f' TD_FILE\n "{td_file}"\n'
Marius Brehlerfa765802020-01-27 11:53:39 -0800216
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800217 def _convert_tbl_outs_block(self, tbl_outs):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700218 outs_list = "\n".join([f" {flag} {value}" for flag, value in tbl_outs])
219 return f" OUTS\n{outs_list}\n"
Marius Brehlerfa765802020-01-27 11:53:39 -0800220
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800221 def _convert_tblgen_block(self, tblgen):
Marius Brehlerfa765802020-01-27 11:53:39 -0800222 if tblgen.endswith("iree-tblgen"):
223 return " TBLGEN\n IREE\n"
224 else:
225 return ""
226
Scott Toddd0a06292020-01-24 14:41:50 -0800227 def _convert_target(self, target):
Marius Brehler5ae825d2020-01-30 11:17:11 -0800228 if target.startswith(":") and target.endswith(("_gen", "Gen")):
229 # Files created by gentbl have to be included as source and header files
230 # and not as a dependency. Adding these targets to the dependencies list,
231 # results in linkage failures if the library including the gentbl dep is
232 # marked as ALWAYSLINK.
233 # This drops deps in the local namespace ending with '_gen' and 'Gen'
Marius Brehler19c069d2020-01-31 16:22:29 -0800234 target = [""]
Marius Brehler5ae825d2020-01-30 11:17:11 -0800235 elif not target.startswith(("//iree", ":")):
Scott Toddd0a06292020-01-24 14:41:50 -0800236 # External target, call helper method for special case handling.
237 target = bazel_to_cmake_targets.convert_external_target(target)
238 else:
Marius Brehler5ae825d2020-01-30 11:17:11 -0800239 # Bazel `:api` -> CMake `::api`
Scott Toddd0a06292020-01-24 14:41:50 -0800240 # Bazel `//iree/base` -> CMake `iree::base`
241 # Bazel `//iree/base:api` -> CMake `iree::base::api`
Geoffrey Martin-Noblec9784d62020-02-18 13:49:49 -0800242 target = target.replace("//iree", "iree") # iree/base:api
Marius Brehler5ae825d2020-01-30 11:17:11 -0800243 target = target.replace(":", "::") # iree/base::api or ::api
Scott Toddd0a06292020-01-24 14:41:50 -0800244 target = target.replace("/", "::") # iree::base::api
Marius Brehler19c069d2020-01-31 16:22:29 -0800245 target = [target]
Scott Toddd0a06292020-01-24 14:41:50 -0800246 return target
247
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800248 def _convert_target_list_block(self, list_name, targets):
249 if not targets:
Scott Toddd0a06292020-01-24 14:41:50 -0800250 return ""
251
252 # DEPS
253 # package1::target1
254 # package1::target2
255 # package2::target
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800256 targets = [self._convert_target(t) for t in targets]
Marius Brehler19c069d2020-01-31 16:22:29 -0800257 # Flatten lists
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800258 targets = list(itertools.chain.from_iterable(targets))
Geoffrey Martin-Nobleff6c6d62020-02-18 11:22:43 -0800259 # Remove duplicates
260 targets = set(targets)
261 # Remove Falsey (None and empty string) values
262 targets = filter(None, targets)
263 # Sort the targets and convert to a list
264 targets = sorted(targets)
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700265 target_list_string = "\n".join([f" {target}" for target in targets])
266 return f" {list_name}\n{target_list_string}\n"
Geoffrey Martin-Noblefe39a192020-02-18 10:53:21 -0800267
268 def _convert_data_block(self, data):
269 return self._convert_target_list_block("DATA", data)
270
271 def _convert_deps_block(self, deps):
272 return self._convert_target_list_block("DEPS", deps)
Scott Toddd0a06292020-01-24 14:41:50 -0800273
Marius Brehler4242b732020-02-10 19:05:48 -0800274 def _convert_flatc_args_block(self, flatc_args):
275 if not flatc_args:
276 return ""
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700277 flatc_args = "\n".join([f' "{flatc_arg}"' for flatc_arg in flatc_args])
278 return f" FLATC_ARGS\n{flatc_args}\n"
Marius Brehler4242b732020-02-10 19:05:48 -0800279
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800280 def _convert_unimplemented_function(self, function, details=""):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700281 message = f"Unimplemented {function}: {details}"
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800282 if not self.converter.first_error:
283 self.converter.first_error = NotImplementedError(message)
Geoffrey Martin-Noblef26a05a2020-03-06 13:09:25 -0800284 # Avoid submitting the raw results from non-strict runs. These are still
285 # useful but are generally not safe to submit as-is. An upstream check
286 # prevents changes with this phrase from being submitted.
287 # Written as separate literals to avoid the check triggering here.
288 submit_blocker = "DO" + " NOT" + " SUBMIT."
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700289 self.converter.body += f"# {submit_blocker} {message}\n"
Scott Toddd0a06292020-01-24 14:41:50 -0800290
291 # ------------------------------------------------------------------------- #
292 # Function handlers that convert BUILD definitions to CMake definitions. #
293 # #
294 # Names and signatures must match 1:1 with those expected in BUILD files. #
295 # Each function that may be found in a BUILD file must be listed here. #
296 # ------------------------------------------------------------------------- #
297
298 def load(self, *args):
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800299 # No mapping to CMake, ignore.
Scott Toddd0a06292020-01-24 14:41:50 -0800300 pass
301
302 def package(self, **kwargs):
303 # No mapping to CMake, ignore.
304 pass
305
306 def iree_build_test(self, **kwargs):
307 pass
308
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800309 def filegroup(self, name, **kwargs):
Scott Toddd0a06292020-01-24 14:41:50 -0800310 # Not implemented yet. Might be a no-op, or may want to evaluate the srcs
311 # attribute and pass them along to any targets that depend on the filegroup.
312 # Cross-package dependencies and complicated globs could be hard to handle.
Geoffrey Martin-Noblefaa30be2020-02-25 16:37:59 -0800313
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800314 # We have a bunch of filegroups that just contain TD files. CMake doesn't
315 # model this at all, so we'll just hardcode this special case.
Geoffrey Martin-Noblefaa30be2020-02-25 16:37:59 -0800316 # TODO(gcmn): Handle this robustly
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800317 if name == "td_files":
Geoffrey Martin-Noblefaa30be2020-02-25 16:37:59 -0800318 return
319
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800320 self._convert_unimplemented_function("filegroup", name)
Scott Toddd0a06292020-01-24 14:41:50 -0800321
Geoffrey Martin-Noble2b09fce2020-02-25 12:03:55 -0800322 def sh_binary(self, name, **kwargs):
323 self._convert_unimplemented_function("sh_binary", name)
324
Scott Toddd0a06292020-01-24 14:41:50 -0800325 def exports_files(self, *args, **kwargs):
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800326 # No mapping to CMake, ignore.
Scott Toddd0a06292020-01-24 14:41:50 -0800327 pass
328
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800329 def glob(self, include, exclude=None, exclude_directories=1):
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800330 if exclude_directories != 1:
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800331 self._convert_unimplemented_function("glob", "with exclude_directories")
Geoffrey Martin-Noble632d04a2020-03-16 07:53:05 -0700332 if exclude:
333 self._convert_unimplemented_function("glob", "with exclude")
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800334
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800335 glob_vars = []
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800336 for pattern in include:
337 if "**" in pattern:
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800338 # bazel's glob has some specific restrictions about crossing package
339 # boundaries. We have no uses of recursive globs. Rather than try to
340 # emulate them or silently give different behavior, just error out.
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800341 # See https://docs.bazel.build/versions/master/be/functions.html#glob
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800342 raise NotImplementedError("Recursive globs not supported")
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800343 # Bazel `*.mlir` glob -> CMake Variable `_GLOB_X_MLIR`
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700344 var = "_GLOB_" + pattern.replace("*", "X").replace(".", "_").upper()
345 glob_vars.append(f"${{{var}}}") # {{ / }} are the escapes for { / }
346 self.converter.body += f"file(GLOB {var} CONFIGURE_DEPENDS {pattern})\n"
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800347 return glob_vars
Scott Toddd0a06292020-01-24 14:41:50 -0800348
Geoffrey Martin-Noble2b09fce2020-02-25 12:03:55 -0800349 # TODO(gcmn) implement these types of functions in a less hard-coded way
350 def platform_trampoline_deps(self, basename, path="base"):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700351 return [f"//iree/{path}/internal:{basename}_internal"]
Geoffrey Martin-Noble2b09fce2020-02-25 12:03:55 -0800352
353 def select(self, d):
354 self._convert_unimplemented_function("select", str(d))
355 return d["//conditions:default"]
356
Scott Toddd0a06292020-01-24 14:41:50 -0800357 def config_setting(self, **kwargs):
358 # No mapping to CMake, ignore.
359 pass
360
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800361 def cc_library(self,
362 name,
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800363 hdrs=None,
364 textual_hdrs=None,
365 srcs=None,
Scott Todd633148d2020-03-09 10:53:56 -0700366 data=None,
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800367 deps=None,
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800368 alwayslink=False,
369 testonly=False,
Geoffrey Martin-Nobleb8cbe342020-03-02 11:28:35 -0800370 linkopts=None,
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800371 **kwargs):
Geoffrey Martin-Nobleb8cbe342020-03-02 11:28:35 -0800372 if linkopts:
373 self._convert_unimplemented_function("linkopts")
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800374 name_block = self._convert_name_block(name)
375 hdrs_block = self._convert_hdrs_block(hdrs)
Marius Brehler2a53ec92020-01-29 14:48:49 -0800376 textual_hdrs_block = self._convert_textual_hdrs_block(textual_hdrs)
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800377 srcs_block = self._convert_srcs_block(srcs)
Scott Todd633148d2020-03-09 10:53:56 -0700378 data_block = self._convert_data_block(data)
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800379 deps_block = self._convert_deps_block(deps)
380 alwayslink_block = self._convert_alwayslink_block(alwayslink)
381 testonly_block = self._convert_testonly_block(testonly)
Scott Toddd0a06292020-01-24 14:41:50 -0800382
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700383 self.converter.body += (f"iree_cc_library(\n"
384 f"{name_block}"
385 f"{hdrs_block}"
386 f"{textual_hdrs_block}"
387 f"{srcs_block}"
388 f"{data_block}"
389 f"{deps_block}"
390 f"{alwayslink_block}"
391 f"{testonly_block}"
392 f" PUBLIC\n)\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800393
Scott Todd633148d2020-03-09 10:53:56 -0700394 def cc_test(self, name, hdrs=None, srcs=None, data=None, deps=None, **kwargs):
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800395 name_block = self._convert_name_block(name)
396 hdrs_block = self._convert_hdrs_block(hdrs)
397 srcs_block = self._convert_srcs_block(srcs)
Scott Todd633148d2020-03-09 10:53:56 -0700398 data_block = self._convert_data_block(data)
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800399 deps_block = self._convert_deps_block(deps)
Scott Toddd0a06292020-01-24 14:41:50 -0800400
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700401 self.converter.body += (f"iree_cc_test(\n"
402 f"{name_block}"
403 f"{hdrs_block}"
404 f"{srcs_block}"
405 f"{data_block}"
406 f"{deps_block}"
407 f")\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800408
Geoffrey Martin-Noblede994422020-03-04 11:25:22 -0800409 def cc_binary(self,
410 name,
411 srcs=None,
Scott Todd633148d2020-03-09 10:53:56 -0700412 data=None,
Geoffrey Martin-Noblede994422020-03-04 11:25:22 -0800413 deps=None,
414 linkopts=None,
415 testonly=False,
416 **kwargs):
Geoffrey Martin-Nobleb8cbe342020-03-02 11:28:35 -0800417 if linkopts:
418 self._convert_unimplemented_function("linkopts")
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800419 name_block = self._convert_name_block(name)
Marius Brehler855a4192020-02-20 10:45:52 -0800420 out_block = self._convert_out_block(name)
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800421 srcs_block = self._convert_srcs_block(srcs)
Scott Todd633148d2020-03-09 10:53:56 -0700422 data_block = self._convert_data_block(data)
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800423 deps_block = self._convert_deps_block(deps)
Geoffrey Martin-Noblede994422020-03-04 11:25:22 -0800424 testonly_block = self._convert_testonly_block(testonly)
Scott Toddd0a06292020-01-24 14:41:50 -0800425
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700426 self.converter.body += (f"iree_cc_binary(\n"
427 f"{name_block}"
428 f"{out_block}"
429 f"{srcs_block}"
430 f"{data_block}"
431 f"{deps_block}"
432 f"{testonly_block}"
433 f")\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800434
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800435 def cc_embed_data(self,
436 name,
437 srcs,
438 cc_file_output,
439 h_file_output,
440 cpp_namespace=None,
441 strip_prefix=None,
442 flatten=False,
443 identifier=None,
444 **kwargs):
445 if identifier:
Geoffrey Martin-Nobled6b31c02020-02-04 17:22:16 -0800446 self._convert_unimplemented_function("cc_embed_data",
447 name + " has identifier")
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800448 name_block = self._convert_name_block(name)
449 srcs_block = self._convert_srcs_block(srcs)
450 cc_file_output_block = self._convert_cc_file_output_block(cc_file_output)
451 h_file_output_block = self._convert_h_file_output_block(h_file_output)
452 namespace_block = self._convert_cpp_namespace_block(cpp_namespace)
453 flatten_block = self._convert_flatten_block(flatten)
Marius Brehlerfa765802020-01-27 11:53:39 -0800454
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700455 self.converter.body += (f"iree_cc_embed_data(\n"
456 f"{name_block}"
457 f"{srcs_block}"
458 f"{cc_file_output_block}"
459 f"{h_file_output_block}"
460 f"{namespace_block}"
461 f"{flatten_block}"
462 f" PUBLIC\n)\n\n")
Marius Brehlerfa765802020-01-27 11:53:39 -0800463
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800464 def spirv_kernel_cc_library(self, name, srcs):
465 name_block = self._convert_name_block(name)
466 srcs_block = self._convert_srcs_block(srcs)
Scott Toddd0a06292020-01-24 14:41:50 -0800467
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700468 self.converter.body += (f"iree_spirv_kernel_cc_library(\n"
469 f"{name_block}"
470 f"{srcs_block}"
471 f")\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800472
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800473 def iree_bytecode_module(self,
474 name,
475 src,
Scott Todd90b44f72020-03-03 16:44:14 -0800476 flags=["-iree-mlir-to-vm-bytecode-module"],
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800477 translate_tool="//iree/tools:iree-translate",
478 cc_namespace=None):
479 name_block = self._convert_name_block(name)
480 src_block = self._convert_src_block(src)
481 namespace_block = self._convert_cc_namespace_block(cc_namespace)
482 translate_tool_block = self._convert_translate_tool_block(translate_tool)
Scott Todd90b44f72020-03-03 16:44:14 -0800483 flags_block = self._convert_flags_block(flags)
Scott Toddd0a06292020-01-24 14:41:50 -0800484
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700485 self.converter.body += (f"iree_bytecode_module(\n"
486 f"{name_block}"
487 f"{src_block}"
488 f"{namespace_block}"
489 f"{translate_tool_block}"
490 f"{flags_block}"
491 f" PUBLIC\n)\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800492
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800493 def iree_flatbuffer_cc_library(self, name, srcs, flatc_args=None):
Marius Brehler4242b732020-02-10 19:05:48 -0800494 name_block = self._convert_name_block(name)
495 srcs_block = self._convert_srcs_block(srcs)
496 flatc_args_block = self._convert_flatc_args_block(flatc_args)
497
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700498 self.converter.body += (f"flatbuffer_cc_library(\n"
499 f"{name_block}"
500 f"{srcs_block}"
501 f"{flatc_args_block}"
502 f" PUBLIC\n)\n\n")
Marius Brehler4242b732020-02-10 19:05:48 -0800503
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800504 def gentbl(self,
505 name,
506 tblgen,
507 td_file,
508 tbl_outs,
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800509 td_srcs=None,
510 td_includes=None,
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800511 strip_include_prefix=None,
512 test=False):
513 name_block = self._convert_name_block(name)
514 tblgen_block = self._convert_tblgen_block(tblgen)
515 td_file_block = self._convert_td_file_block(td_file)
516 outs_block = self._convert_tbl_outs_block(tbl_outs)
Scott Toddd0a06292020-01-24 14:41:50 -0800517
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700518 self.converter.body += (f"iree_tablegen_library(\n"
519 f"{name_block}"
520 f"{td_file_block}"
521 f"{outs_block}"
522 f"{tblgen_block}"
523 f")\n\n")
Scott Toddd0a06292020-01-24 14:41:50 -0800524
Lei Zhang22f0e242020-03-30 12:09:20 -0700525 def iree_tablegen_doc(self,
526 name,
527 tblgen,
528 td_file,
529 tbl_outs,
530 td_srcs=None,
531 td_includes=None,
532 strip_include_prefix=None):
533 name_block = self._convert_name_block(name)
534 tblgen_block = self._convert_tblgen_block(tblgen)
535 td_file_block = self._convert_td_file_block(td_file)
536 outs_block = self._convert_tbl_outs_block(tbl_outs)
537
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700538 self.converter.body += (f"iree_tablegen_doc(\n"
539 f"{name_block}"
540 f"{td_file_block}"
541 f"{outs_block}"
542 f"{tblgen_block}"
543 f")\n\n")
Lei Zhang22f0e242020-03-30 12:09:20 -0700544
Geoffrey Martin-Noblefe8389b2020-01-28 15:00:09 -0800545 def iree_lit_test_suite(self, name, srcs, data, **kwargs):
546 name_block = self._convert_name_block(name)
547 srcs_block = self._convert_srcs_block(srcs)
548 data_block = self._convert_data_block(data)
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800549
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700550 self.converter.body += (f"iree_lit_test_suite(\n"
551 f"{name_block}"
552 f"{srcs_block}"
553 f"{data_block}"
554 f")\n\n")
Geoffrey Martin-Noble252cdbb2020-01-28 10:26:25 -0800555
Scott Toddd0a06292020-01-24 14:41:50 -0800556
557class Converter(object):
558 """Conversion state tracking and full file template substitution."""
559
560 def __init__(self, directory_path, rel_build_file_path):
561 self.body = ""
562 self.directory_path = directory_path
563 self.rel_build_file_path = rel_build_file_path
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800564 self.first_error = None
Scott Toddd0a06292020-01-24 14:41:50 -0800565
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800566 def convert(self, copyright_line):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700567 converted_file = (f"{copyright_line}\n"
568 f"{self.apache_license}\n\n"
569 f"iree_add_all_subdirs()\n\n"
570 f"{self.body}")
Scott Toddd0a06292020-01-24 14:41:50 -0800571
572 # Cleanup newline characters. This is more convenient than ensuring all
573 # conversions are careful with where they insert newlines.
574 converted_file = converted_file.replace("\n\n\n", "\n")
575 converted_file = converted_file.rstrip() + "\n"
576
577 return converted_file
578
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700579 apache_license = textwrap.dedent("""\
Scott Toddd0a06292020-01-24 14:41:50 -0800580 #
581 # Licensed under the Apache License, Version 2.0 (the "License");
582 # you may not use this file except in compliance with the License.
583 # You may obtain a copy of the License at
584 #
585 # https://www.apache.org/licenses/LICENSE-2.0
586 #
587 # Unless required by applicable law or agreed to in writing, software
588 # distributed under the License is distributed on an "AS IS" BASIS,
589 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
590 # See the License for the specific language governing permissions and
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700591 # limitations under the License.""")
Scott Toddd0a06292020-01-24 14:41:50 -0800592
593
594def GetDict(obj):
595 ret = {}
596 for k in dir(obj):
597 if not k.startswith("_"):
598 ret[k] = getattr(obj, k)
599 return ret
600
601
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800602def convert_directory_tree(root_directory_path, write_files, strict):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700603 print(f"convert_directory_tree: {root_directory_path}")
Geoffrey Martin-Noble1b4ac812020-03-09 11:21:03 -0700604 for root, _, _ in os.walk(root_directory_path):
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800605 convert_directory(root, write_files, strict)
Scott Toddd0a06292020-01-24 14:41:50 -0800606
607
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800608def convert_directory(directory_path, write_files, strict):
Scott Toddd0a06292020-01-24 14:41:50 -0800609 if not os.path.isdir(directory_path):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700610 raise FileNotFoundError(f"Cannot find directory '{directory_path}'")
Scott Toddd0a06292020-01-24 14:41:50 -0800611
612 build_file_path = os.path.join(directory_path, "BUILD")
613 cmakelists_file_path = os.path.join(directory_path, "CMakeLists.txt")
614
615 if not os.path.isfile(build_file_path):
616 # No Bazel BUILD file in this directory to convert, skip.
617 return
618
619 global repo_root
620 rel_build_file_path = os.path.relpath(build_file_path, repo_root)
621 rel_cmakelists_file_path = os.path.relpath(cmakelists_file_path, repo_root)
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700622 print(f"Converting {rel_build_file_path} to {rel_cmakelists_file_path}")
Scott Toddd0a06292020-01-24 14:41:50 -0800623
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800624 cmake_file_exists = os.path.isfile(cmakelists_file_path)
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700625 copyright_line = f"# Copyright {datetime.date.today().year} Google LLC"
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800626 write_allowed = write_files
627 if cmake_file_exists:
628 with open(cmakelists_file_path) as f:
629 for i, line in enumerate(f):
630 if line.startswith("# Copyright"):
631 copyright_line = line.rstrip()
632 if EDIT_BLOCKING_PATTERN.search(line):
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700633 print(f" {rel_cmakelists_file_path} already exists, and "
634 f"line {i + 1}: '{line.strip()}' prevents edits. "
635 "Falling back to preview")
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800636 write_allowed = False
637
638 if write_allowed:
Scott Toddd0a06292020-01-24 14:41:50 -0800639 # TODO(scotttodd): Attempt to merge instead of overwrite?
640 # Existing CMakeLists.txt may have special logic that should be preserved
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800641 if cmake_file_exists:
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700642 print(f" {rel_cmakelists_file_path} already exists; overwriting")
Scott Toddd0a06292020-01-24 14:41:50 -0800643 else:
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700644 print(f" {rel_cmakelists_file_path} does not exist yet; creating")
Scott Toddd0a06292020-01-24 14:41:50 -0800645 print("")
646
647 with open(build_file_path, "rt") as build_file:
648 build_file_code = compile(build_file.read(), build_file_path, "exec")
649 converter = Converter(directory_path, rel_build_file_path)
650 try:
651 exec(build_file_code, GetDict(BuildFileFunctions(converter)))
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800652 converted_text = converter.convert(copyright_line)
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800653 if strict and converter.first_error:
Geoffrey Martin-Nobleea9c6832020-02-29 20:26:35 -0800654 raise converter.first_error # pylint: disable=raising-bad-type
Geoffrey Martin-Noble2a36c382020-01-28 15:04:30 -0800655 if write_allowed:
Scott Toddd0a06292020-01-24 14:41:50 -0800656 with open(cmakelists_file_path, "wt") as cmakelists_file:
657 cmakelists_file.write(converted_text)
658 else:
659 print(converted_text)
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800660 except (NameError, NotImplementedError) as e:
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700661 print(f"Failed to convert {rel_build_file_path}.", end=" ")
662 print("Missing a rule handler in bazel_to_cmake.py?")
663 print(f" Reason: `{type(e).__name__}: {e}`")
Scott Toddd0a06292020-01-24 14:41:50 -0800664 except KeyError as e:
Phoenix Meadowlark01bbb6c2020-03-30 14:20:11 -0700665 print(f"Failed to convert {rel_build_file_path}.", end=" ")
666 print("Missing a conversion in bazel_to_cmake_targets.py?")
667 print(f" Reason: `{type(e).__name__}: {e}`")
Scott Toddd0a06292020-01-24 14:41:50 -0800668
669
670def main(args):
671 """Runs Bazel to CMake conversion."""
672 global repo_root
673
674 write_files = not args.preview
675
676 if args.root_dir:
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800677 convert_directory_tree(
678 os.path.join(repo_root, args.root_dir), write_files, args.strict)
Scott Toddd0a06292020-01-24 14:41:50 -0800679 elif args.dir:
Geoffrey Martin-Noblef7be55a2020-01-28 17:47:42 -0800680 convert_directory(
681 os.path.join(repo_root, args.dir), write_files, args.strict)
Scott Toddd0a06292020-01-24 14:41:50 -0800682
683
684if __name__ == "__main__":
685 setup_environment()
686 main(parse_arguments())