xref: /aosp_15_r20/external/boringssl/src/util/util.bzl (revision 8fb009dc861624b67b6cdb62ea21f0f22d0c584b)
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