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 handle_mixed_c_cxx( 87 name, 88 copts, 89 deps, 90 internal_hdrs, 91 includes, 92 linkopts, 93 srcs, 94 testonly): 95 """ 96 Works around https://github.com/bazelbuild/bazel/issues/22041. Determines 97 whether a target contains C, C++, or both. If the target is multi-language, 98 the C sources are split into a separate library. Returns a tuple of updated 99 (copts, deps, srcs) to apply. 100 """ 101 has_c, has_cxx = False, False 102 for src in srcs: 103 if src.endswith(".c"): 104 has_c = True 105 elif src.endswith(".cc"): 106 has_cxx = True 107 108 # If a target has both C and C++, we need to split it in two. 109 if has_c and has_cxx: 110 srcs_c = [src for src in srcs if src.endswith(".c") or src.endswith(".h")] 111 name_c = name + "_c" 112 cc_library( 113 name = name_c, 114 srcs = srcs_c + internal_hdrs, 115 copts = copts + boringssl_copts_c, 116 includes = includes, 117 # This target only exists to be linked into the main library, so 118 # always link it statically. 119 linkstatic = True, 120 linkopts = linkopts, 121 deps = deps, 122 testonly = testonly, 123 ) 124 125 # Build the remainder as a C++-only target. 126 deps += [":" + name_c] 127 srcs = [src for src in srcs if not src.endswith(".c")] 128 has_c = False 129 130 if has_c: 131 copts += boringssl_copts_c 132 else: 133 copts += boringssl_copts_cxx 134 135 return copts, deps, srcs 136 137def handle_asm_srcs(asm_srcs): 138 if not asm_srcs: 139 return [] 140 141 # By default, the C files will expect assembly files, if any, to be linked 142 # in with the build. This default can be flipped with -DOPENSSL_NO_ASM. If 143 # building in a configuration where we have no assembly optimizations, 144 # -DOPENSSL_NO_ASM has no effect, and either value is fine. 145 # 146 # Like C files, assembly files are wrapped in #ifdef (or NASM equivalent), 147 # so it is safe to include a file for the wrong platform in the build. It 148 # will just output an empty object file. However, we need some platform 149 # selectors to distinguish between gas or NASM syntax. 150 # 151 # For all non-Windows platforms, we use gas assembly syntax and can assume 152 # any GCC-compatible toolchain includes a gas-compatible assembler. 153 # 154 # For Windows, we use NASM on x86 and x86_64 and gas, specifically 155 # clang-assembler, on aarch64. We have not yet added NASM support to this 156 # build, and would need to detect MSVC vs clang-cl for aarch64 so, for now, 157 # we just disable assembly on Windows across the board. 158 # 159 # This select and the corresponding one in boringssl_copts_common must be 160 # kept in sync. 161 # 162 # TODO(https://crbug.com/boringssl/531): Enable assembly for Windows. 163 return select({ 164 "@platforms//os:windows": [], 165 "//conditions:default": asm_srcs, 166 }) 167 168def linkstatic_kwargs(linkstatic): 169 # Although Bazel's documentation says linkstatic defaults to True or False 170 # for the various target types, this is not true. The defaults differ by 171 # platform non-Windows and True on Windows. There is now way to request the 172 # default except to omit the parameter, so we must use kwargs. 173 kwargs = {} 174 if linkstatic != None: 175 kwargs["linkstatic"] = linkstatic 176 return kwargs 177 178def bssl_cc_library( 179 name, 180 asm_srcs = [], 181 copts = [], 182 deps = [], 183 hdrs = [], 184 includes = [], 185 internal_hdrs = [], 186 linkopts = [], 187 linkstatic = None, 188 srcs = [], 189 testonly = False, 190 visibility = []): 191 copts, deps, srcs = handle_mixed_c_cxx( 192 name = name, 193 copts = copts, 194 deps = deps, 195 internal_hdrs = hdrs + internal_hdrs, 196 includes = includes, 197 linkopts = linkopts, 198 srcs = srcs, 199 testonly = testonly, 200 ) 201 202 # BoringSSL's notion of internal headers are slightly different from 203 # Bazel's. libcrypto's internal headers may be used by libssl, but they 204 # cannot be used outside the library. To express this, we make separate 205 # internal and external targets. This impact's Bazel's layering check. 206 name_internal = name 207 if visibility: 208 name_internal = name + "_internal" 209 210 cc_library( 211 name = name_internal, 212 srcs = srcs + handle_asm_srcs(asm_srcs), 213 hdrs = hdrs + internal_hdrs, 214 copts = copts, 215 includes = includes, 216 linkopts = linkopts, 217 deps = deps, 218 testonly = testonly, 219 **linkstatic_kwargs(linkstatic) 220 ) 221 222 if visibility: 223 cc_library( 224 name = name, 225 hdrs = hdrs, 226 deps = [":" + name_internal], 227 visibility = visibility, 228 ) 229 230def bssl_cc_binary( 231 name, 232 srcs = [], 233 asm_srcs = [], 234 copts = [], 235 includes = [], 236 linkstatic = None, 237 linkopts = [], 238 deps = [], 239 testonly = False, 240 visibility = []): 241 copts, deps, srcs = handle_mixed_c_cxx( 242 name = name, 243 copts = copts, 244 deps = deps, 245 internal_hdrs = [], 246 includes = includes, 247 linkopts = linkopts, 248 srcs = srcs, 249 testonly = testonly, 250 ) 251 252 cc_binary( 253 name = name, 254 srcs = srcs + handle_asm_srcs(asm_srcs), 255 copts = copts, 256 includes = includes, 257 linkopts = linkopts, 258 deps = deps, 259 testonly = testonly, 260 visibility = visibility, 261 **linkstatic_kwargs(linkstatic) 262 ) 263 264def bssl_cc_test( 265 name, 266 srcs = [], 267 asm_srcs = [], 268 data = [], 269 size = "medium", 270 internal_hdrs = [], 271 copts = [], 272 includes = [], 273 linkopts = [], 274 linkstatic = None, 275 deps = [], 276 shard_count = None): 277 copts, deps, srcs = handle_mixed_c_cxx( 278 name = name, 279 copts = copts, 280 deps = deps, 281 internal_hdrs = [], 282 includes = includes, 283 linkopts = linkopts, 284 srcs = srcs, 285 testonly = True, 286 ) 287 288 cc_test( 289 name = name, 290 data = data, 291 deps = deps, 292 srcs = srcs + handle_asm_srcs(asm_srcs), 293 copts = copts, 294 includes = includes, 295 linkopts = linkopts, 296 shard_count = shard_count, 297 size = size, 298 **linkstatic_kwargs(linkstatic) 299 ) 300