• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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