1# Copyright (c) 2024, Google Inc. 2# 3# Permission to use, copy, modify, and/or distribute this software for any 4# purpose with or without fee is hereby granted, provided that the above 5# copyright notice and this permission notice appear in all copies. 6# 7# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 10# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 12# OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 13# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 15load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") 16 17# Configure C, C++, and common flags for GCC-compatible toolchains. 18# 19# TODO(davidben): Can we remove some of these? In Bazel, are warnings the 20# toolchain or project's responsibility? -fno-common did not become default 21# until https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85678. 22gcc_copts = [ 23 # This list of warnings should match those in the top-level CMakeLists.txt. 24 "-Wall", 25 "-Werror", 26 "-Wformat=2", 27 "-Wsign-compare", 28 "-Wmissing-field-initializers", 29 "-Wwrite-strings", 30 "-Wshadow", 31 "-fno-common", 32] 33 34gcc_copts_cxx = [ 35 "-Wmissing-declarations", 36] 37 38gcc_copts_c = [ 39 "-Wmissing-prototypes", 40 "-Wold-style-definition", 41 "-Wstrict-prototypes", 42] 43 44boringssl_copts_common = select({ 45 # This condition and the asm_srcs_used one below must be kept in sync. 46 "@platforms//os:windows": ["-DOPENSSL_NO_ASM"], 47 "//conditions:default": [], 48}) + select({ 49 # We assume that non-Windows builds use a GCC-compatible toolchain and that 50 # Windows builds do not. 51 # 52 # TODO(davidben): Should these be querying something in @bazel_tools? 53 # Unfortunately, @bazel_tools is undocumented. See 54 # https://github.com/bazelbuild/bazel/issues/14914 55 "@platforms//os:windows": [], 56 "//conditions:default": gcc_copts, 57}) + select({ 58 # This is needed on glibc systems to get rwlock in pthreads, but it should 59 # not be set on Apple platforms or FreeBSD, where it instead disables APIs 60 # we use. 61 # See compat(5), sys/cdefs.h, and https://crbug.com/boringssl/471 62 "@platforms//os:linux": ["-D_XOPEN_SOURCE=700"], 63 # Without WIN32_LEAN_AND_MEAN, <windows.h> pulls in wincrypt.h, which 64 # conflicts with our <openssl/x509.h>. 65 "@platforms//os:windows": ["-DWIN32_LEAN_AND_MEAN", "-utf-8"], 66 "//conditions:default": [], 67}) 68 69# We do not specify the C++ version here because Bazel expects C++ version 70# to come from the top-level toolchain. The concern is that different C++ 71# versions may cause ABIs, notably Abseil's, to change. 72boringssl_copts_cxx = boringssl_copts_common + select({ 73 "@platforms//os:windows": [], 74 "//conditions:default": gcc_copts_cxx, 75}) 76 77# We specify the C version because Bazel projects often do not remember to 78# specify the C version. We do not expect ABIs to vary by C versions, at least 79# for our code or the headers we include, so configure the C version inside the 80# library. If Bazel's C/C++ version handling improves, we may reconsider this. 81boringssl_copts_c = boringssl_copts_common + select({ 82 "@platforms//os:windows": ["/std:c11"], 83 "//conditions:default": ["-std=c11"] + gcc_copts_c, 84}) 85 86def linkstatic_kwargs(linkstatic): 87 # Although Bazel's documentation says linkstatic defaults to True or False 88 # for the various target types, this is not true. The defaults differ by 89 # platform non-Windows and True on Windows. There is now way to request the 90 # default except to omit the parameter, so we must use kwargs. 91 kwargs = {} 92 if linkstatic != None: 93 kwargs["linkstatic"] = linkstatic 94 return kwargs 95 96def handle_mixed_c_cxx( 97 name, 98 copts, 99 deps, 100 internal_hdrs, 101 includes, 102 linkopts, 103 linkstatic, 104 srcs, 105 testonly, 106 alwayslink): 107 """ 108 Works around https://github.com/bazelbuild/bazel/issues/22041. Determines 109 whether a target contains C, C++, or both. If the target is multi-language, 110 the C sources are split into a separate library. Returns a tuple of updated 111 (copts, deps, srcs) to apply. 112 """ 113 has_c, has_cxx = False, False 114 for src in srcs: 115 if src.endswith(".c"): 116 has_c = True 117 elif src.endswith(".cc"): 118 has_cxx = True 119 120 # If a target has both C and C++, we need to split it in two. 121 if has_c and has_cxx: 122 # Pull the C++ files out. 123 srcs_cxx = [src for src in srcs if src.endswith(".cc") or src.endswith(".h")] 124 name_cxx = name + "_cxx" 125 cc_library( 126 name = name_cxx, 127 srcs = srcs_cxx + internal_hdrs, 128 copts = copts + boringssl_copts_cxx, 129 includes = includes, 130 linkopts = linkopts, 131 deps = deps, 132 testonly = testonly, 133 alwayslink = alwayslink, 134 **linkstatic_kwargs(linkstatic), 135 ) 136 137 # Build the remainder as a C-only target. 138 deps = deps + [":" + name_cxx] 139 srcs = [src for src in srcs if not src.endswith(".cc")] 140 has_cxx = False 141 142 if has_c: 143 copts = copts + boringssl_copts_c 144 else: 145 copts = copts + boringssl_copts_cxx 146 147 return copts, deps, srcs 148 149def handle_asm_srcs(asm_srcs): 150 if not asm_srcs: 151 return [] 152 153 # By default, the C files will expect assembly files, if any, to be linked 154 # in with the build. This default can be flipped with -DOPENSSL_NO_ASM. If 155 # building in a configuration where we have no assembly optimizations, 156 # -DOPENSSL_NO_ASM has no effect, and either value is fine. 157 # 158 # Like C files, assembly files are wrapped in #ifdef (or NASM equivalent), 159 # so it is safe to include a file for the wrong platform in the build. It 160 # will just output an empty object file. However, we need some platform 161 # selectors to distinguish between gas or NASM syntax. 162 # 163 # For all non-Windows platforms, we use gas assembly syntax and can assume 164 # any GCC-compatible toolchain includes a gas-compatible assembler. 165 # 166 # For Windows, we use NASM on x86 and x86_64 and gas, specifically 167 # clang-assembler, on aarch64. We have not yet added NASM support to this 168 # build, and would need to detect MSVC vs clang-cl for aarch64 so, for now, 169 # we just disable assembly on Windows across the board. 170 # 171 # This select and the corresponding one in boringssl_copts_common must be 172 # kept in sync. 173 # 174 # TODO(https://crbug.com/boringssl/531): Enable assembly for Windows. 175 return select({ 176 "@platforms//os:windows": [], 177 "//conditions:default": asm_srcs, 178 }) 179 180def bssl_cc_library( 181 name, 182 asm_srcs = [], 183 copts = [], 184 deps = [], 185 hdrs = [], 186 includes = [], 187 internal_hdrs = [], 188 linkopts = [], 189 linkstatic = None, 190 srcs = [], 191 testonly = False, 192 alwayslink = False, 193 visibility = []): 194 copts, deps, srcs = handle_mixed_c_cxx( 195 name = name, 196 copts = copts, 197 deps = deps, 198 internal_hdrs = hdrs + internal_hdrs, 199 includes = includes, 200 linkopts = linkopts, 201 # Ideally we would set linkstatic = True to statically link the helper 202 # library into main cc_library. But Bazel interprets linkstatic such 203 # that, if A(test, linkshared) -> B(library) -> C(library, linkstatic), 204 # C will be statically linked into A, not B. This is probably to avoid 205 # diamond dependency problems but means linkstatic does not help us make 206 # this function transparent. Instead, just pass along the linkstatic 207 # nature of the main library. 208 linkstatic = linkstatic, 209 srcs = srcs, 210 testonly = testonly, 211 alwayslink = alwayslink, 212 ) 213 214 # BoringSSL's notion of internal headers are slightly different from 215 # Bazel's. libcrypto's internal headers may be used by libssl, but they 216 # cannot be used outside the library. To express this, we make separate 217 # internal and external targets. This impact's Bazel's layering check. 218 name_internal = name 219 if visibility: 220 name_internal = name + "_internal" 221 222 cc_library( 223 name = name_internal, 224 srcs = srcs + handle_asm_srcs(asm_srcs), 225 hdrs = hdrs + internal_hdrs, 226 copts = copts, 227 includes = includes, 228 linkopts = linkopts, 229 deps = deps, 230 testonly = testonly, 231 alwayslink = alwayslink, 232 **linkstatic_kwargs(linkstatic) 233 ) 234 235 if visibility: 236 cc_library( 237 name = name, 238 hdrs = hdrs, 239 deps = [":" + name_internal], 240 visibility = visibility, 241 ) 242 243def bssl_cc_binary( 244 name, 245 srcs = [], 246 asm_srcs = [], 247 copts = [], 248 includes = [], 249 linkstatic = None, 250 linkopts = [], 251 deps = [], 252 testonly = False, 253 visibility = []): 254 copts, deps, srcs = handle_mixed_c_cxx( 255 name = name, 256 copts = copts, 257 deps = deps, 258 internal_hdrs = [], 259 includes = includes, 260 # If it weren't for https://github.com/bazelbuild/bazel/issues/22041, 261 # the split library be part of `srcs` and linked statically. Set 262 # linkstatic to match. 263 linkstatic = True, 264 linkopts = linkopts, 265 srcs = srcs, 266 testonly = testonly, 267 # TODO(davidben): Should this be alwayslink = True? How does Bazel treat 268 # the real cc_binary.srcs? 269 alwayslink = False, 270 ) 271 272 cc_binary( 273 name = name, 274 srcs = srcs + handle_asm_srcs(asm_srcs), 275 copts = copts, 276 includes = includes, 277 linkopts = linkopts, 278 deps = deps, 279 testonly = testonly, 280 visibility = visibility, 281 **linkstatic_kwargs(linkstatic) 282 ) 283 284def bssl_cc_test( 285 name, 286 srcs = [], 287 asm_srcs = [], 288 data = [], 289 size = "medium", 290 copts = [], 291 includes = [], 292 linkopts = [], 293 linkstatic = None, 294 deps = [], 295 shard_count = None): 296 copts, deps, srcs = handle_mixed_c_cxx( 297 name = name, 298 copts = copts, 299 deps = deps, 300 internal_hdrs = [], 301 includes = includes, 302 # If it weren't for https://github.com/bazelbuild/bazel/issues/22041, 303 # the split library be part of `srcs` and linked statically. Set 304 # linkstatic to match. 305 linkstatic = True, 306 linkopts = linkopts, 307 srcs = srcs, 308 testonly = True, 309 # If any sources get extracted, they must always be linked, otherwise 310 # tests will be dropped. 311 alwayslink = True, 312 ) 313 314 cc_test( 315 name = name, 316 data = data, 317 deps = deps, 318 srcs = srcs + handle_asm_srcs(asm_srcs), 319 copts = copts, 320 includes = includes, 321 linkopts = linkopts, 322 shard_count = shard_count, 323 size = size, 324 **linkstatic_kwargs(linkstatic) 325 ) 326