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