1#!/usr/bin/python 2# 3# Copyright (c) 2009-2021, Google LLC 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions are met: 8# * Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# * Redistributions in binary form must reproduce the above copyright 11# notice, this list of conditions and the following disclaimer in the 12# documentation and/or other materials provided with the distribution. 13# * Neither the name of Google LLC nor the 14# names of its contributors may be used to endorse or promote products 15# derived from this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20# DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY 21# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28"""A tool to convert {WORKSPACE, BUILD} -> CMakeLists.txt. 29 30This tool is very upb-specific at the moment, and should not be seen as a 31generic Bazel -> CMake converter. 32""" 33 34from __future__ import absolute_import 35from __future__ import division 36from __future__ import print_function 37 38import sys 39import textwrap 40import os 41 42def StripFirstChar(deps): 43 return [dep[1:] for dep in deps] 44 45def IsSourceFile(name): 46 return name.endswith(".c") or name.endswith(".cc") 47 48class BuildFileFunctions(object): 49 def __init__(self, converter): 50 self.converter = converter 51 52 def _add_deps(self, kwargs, keyword=""): 53 if "deps" not in kwargs: 54 return 55 self.converter.toplevel += "target_link_libraries(%s%s\n %s)\n" % ( 56 kwargs["name"], 57 keyword, 58 "\n ".join(StripFirstChar(kwargs["deps"])) 59 ) 60 61 def load(self, *args): 62 pass 63 64 def cc_library(self, **kwargs): 65 if kwargs["name"].endswith("amalgamation"): 66 return 67 if kwargs["name"] == "upbc_generator": 68 return 69 if kwargs["name"] == "lupb": 70 return 71 if "testonly" in kwargs: 72 return 73 files = kwargs.get("srcs", []) + kwargs.get("hdrs", []) 74 found_files = [] 75 pregenerated_files = [ 76 "CMakeLists.txt", "descriptor.upb.h", "descriptor.upb.c" 77 ] 78 for file in files: 79 if os.path.basename(file) in pregenerated_files: 80 found_files.append("../cmake/" + file) 81 else: 82 found_files.append("../" + file) 83 84 if list(filter(IsSourceFile, files)): 85 # Has sources, make this a normal library. 86 self.converter.toplevel += "add_library(%s\n %s)\n" % ( 87 kwargs["name"], 88 "\n ".join(found_files) 89 ) 90 self._add_deps(kwargs) 91 else: 92 # Header-only library, have to do a couple things differently. 93 # For some info, see: 94 # http://mariobadr.com/creating-a-header-only-library-with-cmake.html 95 self.converter.toplevel += "add_library(%s INTERFACE)\n" % ( 96 kwargs["name"] 97 ) 98 self._add_deps(kwargs, " INTERFACE") 99 100 def cc_binary(self, **kwargs): 101 pass 102 103 def cc_test(self, **kwargs): 104 # Disable this until we properly support upb_proto_library(). 105 # self.converter.toplevel += "add_executable(%s\n %s)\n" % ( 106 # kwargs["name"], 107 # "\n ".join(kwargs["srcs"]) 108 # ) 109 # self.converter.toplevel += "add_test(NAME %s COMMAND %s)\n" % ( 110 # kwargs["name"], 111 # kwargs["name"], 112 # ) 113 114 # if "data" in kwargs: 115 # for data_dep in kwargs["data"]: 116 # self.converter.toplevel += textwrap.dedent("""\ 117 # add_custom_command( 118 # TARGET %s POST_BUILD 119 # COMMAND ${CMAKE_COMMAND} -E copy 120 # ${CMAKE_SOURCE_DIR}/%s 121 # ${CMAKE_CURRENT_BINARY_DIR}/%s)\n""" % ( 122 # kwargs["name"], data_dep, data_dep 123 # )) 124 125 # self._add_deps(kwargs) 126 pass 127 128 def cc_fuzz_test(self, **kwargs): 129 pass 130 131 def pkg_files(self, **kwargs): 132 pass 133 134 def py_library(self, **kwargs): 135 pass 136 137 def py_binary(self, **kwargs): 138 pass 139 140 def lua_proto_library(self, **kwargs): 141 pass 142 143 def sh_test(self, **kwargs): 144 pass 145 146 def make_shell_script(self, **kwargs): 147 pass 148 149 def exports_files(self, files, **kwargs): 150 pass 151 152 def proto_library(self, **kwargs): 153 pass 154 155 def cc_proto_library(self, **kwargs): 156 pass 157 158 def staleness_test(self, **kwargs): 159 pass 160 161 def upb_amalgamation(self, **kwargs): 162 pass 163 164 def upb_proto_library(self, **kwargs): 165 pass 166 167 def upb_proto_library_copts(self, **kwargs): 168 pass 169 170 def upb_proto_reflection_library(self, **kwargs): 171 pass 172 173 def upb_proto_srcs(self, **kwargs): 174 pass 175 176 def genrule(self, **kwargs): 177 pass 178 179 def config_setting(self, **kwargs): 180 pass 181 182 def upb_fasttable_enabled(self, **kwargs): 183 pass 184 185 def select(self, arg_dict): 186 return [] 187 188 def glob(self, *args, **kwargs): 189 return [] 190 191 def licenses(self, *args): 192 pass 193 194 def filegroup(self, **kwargs): 195 pass 196 197 def map_dep(self, arg): 198 return arg 199 200 def package_group(self, **kwargs): 201 pass 202 203 def bool_flag(self, **kwargs): 204 pass 205 206 def bootstrap_upb_proto_library(self, **kwargs): 207 pass 208 209 def bootstrap_cc_library(self, **kwargs): 210 pass 211 212 213class WorkspaceFileFunctions(object): 214 def __init__(self, converter): 215 self.converter = converter 216 217 def load(self, *args, **kwargs): 218 pass 219 220 def workspace(self, **kwargs): 221 self.converter.prelude += "project(%s)\n" % (kwargs["name"]) 222 self.converter.prelude += "set(CMAKE_C_STANDARD 99)\n" 223 224 def maybe(self, rule, **kwargs): 225 if kwargs["name"] == "utf8_range": 226 self.converter.utf8_range_commit = kwargs["commit"] 227 pass 228 229 def http_archive(self, **kwargs): 230 pass 231 232 def git_repository(self, **kwargs): 233 pass 234 235 def new_git_repository(self, **kwargs): 236 pass 237 238 def bazel_version_repository(self, **kwargs): 239 pass 240 241 def protobuf_deps(self): 242 pass 243 244 def utf8_range_deps(self): 245 pass 246 247 def pip_parse(self, **kwargs): 248 pass 249 250 def rules_fuzzing_dependencies(self): 251 pass 252 253 def rules_fuzzing_init(self): 254 pass 255 256 def rules_pkg_dependencies(self): 257 pass 258 259 def system_python(self, **kwargs): 260 pass 261 262 def register_system_python(self, **kwargs): 263 pass 264 265 def register_toolchains(self, toolchain): 266 pass 267 268 def python_source_archive(self, **kwargs): 269 pass 270 271 def python_nuget_package(self, **kwargs): 272 pass 273 274 def install_deps(self): 275 pass 276 277 def fuzzing_py_install_deps(self): 278 pass 279 280 def googletest_deps(self): 281 pass 282 283 284class Converter(object): 285 def __init__(self): 286 self.prelude = "" 287 self.toplevel = "" 288 self.if_lua = "" 289 self.utf8_range_commit = "" 290 291 def convert(self): 292 return self.template % { 293 "prelude": converter.prelude, 294 "toplevel": converter.toplevel, 295 "utf8_range_commit": converter.utf8_range_commit, 296 } 297 298 template = textwrap.dedent("""\ 299 # This file was generated from BUILD using tools/make_cmakelists.py. 300 301 cmake_minimum_required(VERSION 3.1) 302 303 if(${CMAKE_VERSION} VERSION_LESS 3.12) 304 cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) 305 else() 306 cmake_policy(VERSION 3.12) 307 endif() 308 309 cmake_minimum_required (VERSION 3.0) 310 cmake_policy(SET CMP0048 NEW) 311 312 %(prelude)s 313 314 # Prevent CMake from setting -rdynamic on Linux (!!). 315 SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") 316 SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") 317 318 # Set default build type. 319 if(NOT CMAKE_BUILD_TYPE) 320 message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") 321 set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING 322 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." 323 FORCE) 324 endif() 325 326 # When using Ninja, compiler output won't be colorized without this. 327 include(CheckCXXCompilerFlag) 328 CHECK_CXX_COMPILER_FLAG(-fdiagnostics-color=always SUPPORTS_COLOR_ALWAYS) 329 if(SUPPORTS_COLOR_ALWAYS) 330 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") 331 endif() 332 333 # Implement ASAN/UBSAN options 334 if(UPB_ENABLE_ASAN) 335 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") 336 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") 337 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") 338 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") 339 endif() 340 341 if(UPB_ENABLE_UBSAN) 342 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") 343 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") 344 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address") 345 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=address") 346 endif() 347 348 include_directories(..) 349 include_directories(../cmake) 350 include_directories(${CMAKE_CURRENT_BINARY_DIR}) 351 352 if(NOT TARGET utf8_range) 353 if(EXISTS ../external/utf8_range) 354 # utf8_range is already installed 355 include_directories(../external/utf8_range) 356 else() 357 include(FetchContent) 358 FetchContent_Declare( 359 utf8_range 360 GIT_REPOSITORY "https://github.com/protocolbuffers/utf8_range.git" 361 GIT_TAG "%(utf8_range_commit)s" 362 ) 363 FetchContent_GetProperties(utf8_range) 364 if(NOT utf8_range_POPULATED) 365 FetchContent_Populate(utf8_range) 366 include_directories(${utf8_range_SOURCE_DIR}) 367 endif() 368 endif() 369 endif() 370 371 if(APPLE) 372 set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup -flat_namespace") 373 elseif(UNIX) 374 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id") 375 endif() 376 377 enable_testing() 378 379 %(toplevel)s 380 381 """) 382 383data = {} 384converter = Converter() 385 386def GetDict(obj): 387 ret = {} 388 ret["UPB_DEFAULT_COPTS"] = [] # HACK 389 ret["UPB_DEFAULT_CPPOPTS"] = [] # HACK 390 for k in dir(obj): 391 if not k.startswith("_"): 392 ret[k] = getattr(obj, k); 393 return ret 394 395globs = GetDict(converter) 396 397workspace_dict = GetDict(WorkspaceFileFunctions(converter)) 398exec(open("bazel/workspace_deps.bzl").read(), workspace_dict) 399exec(open("WORKSPACE").read(), workspace_dict) 400exec(open("BUILD").read(), GetDict(BuildFileFunctions(converter))) 401 402with open(sys.argv[1], "w") as f: 403 f.write(converter.convert()) 404