Skip to content

Add Bazel build with BoringSSL support#501

Open
BYVoid wants to merge 7 commits into
ClickHouse:masterfrom
BYVoid:bazel-and-boringssl
Open

Add Bazel build with BoringSSL support#501
BYVoid wants to merge 7 commits into
ClickHouse:masterfrom
BYVoid:bazel-and-boringssl

Conversation

@BYVoid
Copy link
Copy Markdown

@BYVoid BYVoid commented May 27, 2026

Summary

  • Adds a Bazel (bzlmod) build alongside the existing CMake build, so downstream Bazel projects can depend on clickhouse-cpp via the Bazel Central Registry without standing up CMake.
  • TLS is selectable via a build flag: --@clickhouse_cpp//:tls=boringssl|openssl (default: boringssl). Both come from BCR modules and are linked statically, keeping the build hermetic.
  • The two OpenSSL-only surfaces — SSL_CONF_* command API and SSL_read_ex — are gated behind a USE_BORINGSSL define in clickhouse/base/sslsocket.cpp, set only when building with the BoringSSL backend. When USE_BORINGSSL is undefined (CMake, or Bazel with tls=openssl) the original code paths are used unchanged.
  • A GitHub Actions workflow builds the Bazel target on Linux.
  • The CMake build is untouched.

What's added

File Purpose
MODULE.bazel Module declaration; deps: abseil-cpp, bazel_skylib, boringssl, cityhash, lz4, openssl, rules_cc, zstd (all latest on BCR)
MODULE.bazel.lock Pinned dep graph
BUILD.bazel :tls string flag + config settings; the public :clickhouse cc_library target
.github/workflows/bazel.yml CI: bazel build //:clickhouse on Linux
.gitignore Ignore bazel-* symlinks
clickhouse/base/sslsocket.cpp Ifdef-guarded BoringSSL compat patch

TLS backend selection

bazel build //:clickhouse                                  # BoringSSL (default)
bazel build //:clickhouse --@clickhouse_cpp//:tls=openssl  # OpenSSL from BCR

Implemented with a bazel_skylib string_flag + config_setting + select() on defines and deps. BoringSSL is the default because it builds reliably across platforms on BCR today and matches what many Bazel workspaces (gRPC, Envoy) already link. The same mechanism is the natural place for future build options (e.g. CH_MAP_BOOL_TO_UINT8).

sslsocket.cpp patch detail

Two #ifdef USE_BORINGSSL ... #else ... #endif regions:

  1. configureSSL() body — BoringSSL has no SSL_CONF_* API, so the commands cannot be applied. If SSLParams::configuration is non-empty, a one-time warning is printed to stderr pointing at the OpenSSL build option, instead of silently dropping potentially security-relevant settings.
  2. SSLSocketInput::DoRead() — under USE_BORINGSSL falls back to SSL_read with len clamped to INT_MAX. SSL_read_ex is an OpenSSL 3.0+ API not in BoringSSL.

Function signatures, declarations, SSLParams::ConfigurationType, validateParams, etc. all stay intact, so the public API is unchanged regardless of which TLS backend is linked.

Test plan

  • bazel build //:clickhouse (BoringSSL default) produces libclickhouse.a on darwin-arm64 (Bazel 9.1.1) and Linux.
  • bazel build //:clickhouse --@clickhouse_cpp//:tls=openssl builds OpenSSL 3.5.5 from source and links successfully.
  • GitHub Actions workflow covering the Bazel build on Linux.

Notes for reviewers

  • All Bazel dependencies come from BCR, including cityhash@1.0.2 (1.0.2 is the algorithm revision ClickHouse's wire checksums require). The contrib/ trees are untouched and still used by the CMake build.
  • Once merged, I plan to submit the module to the Bazel Central Registry so consumers can depend on it with a single bazel_dep.

@CLAassistant
Copy link
Copy Markdown

CLAassistant commented May 27, 2026

CLA assistant check
All committers have signed the CLA.

@BYVoid BYVoid force-pushed the bazel-and-boringssl branch from 5ff5053 to a2c545a Compare May 27, 2026 04:26
@BYVoid BYVoid marked this pull request as ready for review May 27, 2026 04:29
Copilot AI review requested due to automatic review settings May 27, 2026 04:29
@BYVoid BYVoid requested review from mzitnik and slabko as code owners May 27, 2026 04:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds Bazel (bzlmod) build support for clickhouse-cpp and adapts TLS codepaths to work with BoringSSL.

Changes:

  • Added MODULE.bazel with bzlmod deps (abseil, boringssl, lz4, zstd, rules_cc).
  • Added BUILD.bazel with :clickhouse cc_library and vendored :cityhash.
  • Updated TLS implementation to compile under BoringSSL by disabling SSL_CONF_* usage and using SSL_read instead of SSL_read_ex.

Reviewed changes

Copilot reviewed 3 out of 5 changed files in this pull request and generated 3 comments.

File Description
clickhouse/base/sslsocket.cpp Adds BoringSSL-specific branches for SSL configuration and reading APIs.
MODULE.bazel Introduces a bzlmod module definition and external deps for Bazel builds.
BUILD.bazel Adds Bazel targets to build/export the library and its vendored cityhash dependency.
.gitignore Ignores Bazel output symlinks/directories.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread BUILD.bazel
Comment thread clickhouse/base/sslsocket.cpp
Comment thread clickhouse/base/sslsocket.cpp
@BYVoid
Copy link
Copy Markdown
Author

BYVoid commented May 27, 2026

Why BoringSSL (and not OpenSSL) in this PR

A few people will probably ask why TLS goes through @boringssl rather than @openssl here. Some context:

  1. OpenSSL on BCR still has rough edges. The current OpenSSL modules don't build cleanly out of the box across all platforms/toolchains we tried, while @boringssl builds reliably with no extra rules.
  2. Single-TLS-in-process constraint. Many Bazel workspaces already link BoringSSL transitively (gRPC, Envoy, abseil-adjacent libs). Pulling in OpenSSL alongside leads to duplicate symbols, conflicting libssl/libcrypto initialization, and ODR violations. Picking BoringSSL keeps clickhouse-cpp compatible with that ecosystem without forcing consumers to fight their dep graph.

The USE_BORINGSSL define is intentionally a compile-time switch, not hardcoded behavior — the OpenSSL-only code paths are still present in sslsocket.cpp and active whenever USE_BORINGSSL is undefined (which is the case for the existing CMake build).

Follow-up: once OpenSSL's BCR story stabilizes, it's straightforward to add a Bazel config_setting (e.g. --@clickhouse_cpp//:tls=openssl|boringssl) that flips the defines and the deps between @openssl and @boringssl, letting consumers choose. Wanted to keep this PR scoped to a single working configuration first.

@slabko
Copy link
Copy Markdown
Contributor

slabko commented Jun 1, 2026

@BYVoid, thank you for your contribution!
I think this is a very good idea, indeed.

However, before we proceed, I’d like to clarify two things:

  1. Are you willing to help maintain the Bazel integration after merge? In particular, fixing Bazel dependency breakages, Bazel version issues, and compatibility reports from the users. I understand this cannot be a formal guarantee, but I want to avoid merging a build system that immediately becomes unowned.

  2. Could you add a GitHub Actions workflow that build and test the project. Linux-only is fine as a starting point.

@BYVoid
Copy link
Copy Markdown
Author

BYVoid commented Jun 1, 2026

Yes. I can help maintain the Bazel build support and probably submit it to https://registry.bazel.build/ in near future.

I will try to add a github worklow to cover the Bazel build.

Adds a Linux Bazel CI job that runs bazel build //... so the
bzlmod build is exercised on push and pull requests, mirroring the
existing CMake workflows.
@BYVoid
Copy link
Copy Markdown
Author

BYVoid commented Jun 1, 2026

@slabko I added a Github workflow. Can you grant me the permission to run it?

@slabko
Copy link
Copy Markdown
Contributor

slabko commented Jun 4, 2026

Hi @BYVoid,

I am trying to learn the basics of Bazel before we merge it. This is still in progress, but my plan is to merge it soon.

I have a couple of new questions:

  1. You included BoringSSL as a replacement for OpenSSL. I understand why that would be necessary. However, is there also an option to link to the system-bundled version of OpenSSL? This is usually more desirable on Linux, since the Linux distribution would take care of patching and updating it when needed. Similarly, on macOS, dynamically linking against a version of OpenSSL installed by Homebrew might be more desirable. In fact, this is how the library works now: it dynamically links to whatever version of OpenSSL is available on the system. How do people approach that with Bazel? Do they ever link against system-installed libraries?
  2. The same question applies to zstd, lz4, and Abseil. Abseil is only used for wide integers, such as 128-bit and 256-bit integers, and my plan is to remove any dependencies on Abseil and remove its parts components from the project. Instead, the library will provide access to raw data, so users can use whichever libraries they prefer. However, I think that with the way it is implemented right now, we can simply remove the dependency from the dependency list once the library is ready. Just a heads-up.
  3. The library has some options (like WITH_SYSTEM_CITYHASH, or CH_MAP_BOOL_TO_UINT8) that change how it is built and linked. I can see that you have chosen a very strict approach, which makes sense for now. However, how will we be able to introduce configuration and compatibility flags in the future?

@BYVoid
Copy link
Copy Markdown
Author

BYVoid commented Jun 4, 2026

Great questions! They all trace back to Bazel's core idea: hermetic builds. A Bazel build should depend only on declared, version-pinned inputs, never on whatever happens to be installed on the host. Everything is built from pinned sources and (typically) statically linked, so the same commit produces the same binary on any machine. This is also the prevailing convention on the Bazel Central Registry: modules build their dependencies from source and avoid system packages whenever possible. The ecosystem takes this idea quite far, even with efforts like hermetic-llvm that make the compiler toolchain itself a hermetic part of the build.

1. System OpenSSL: Linking system libraries is possible in Bazel but goes against this philosophy, so I'd rather not make it the default. Your concern about security patching is valid, but the Bazel ecosystem solves it differently: instead of relying on the distro to swap a shared library at runtime, the usual workflow is to bump the pinned version in MODULE.bazel and rebuild + redeploy. Tools like Renovate/Dependabot automate these version bumps, and BoringSSL itself is maintained by Google with timely BCR updates, so the patch latency is comparable in practice. Also, consumers who really want a system lib can already override @boringssl in their own MODULE.bazel, with no support needed from this library.

2. zstd/lz4/Abseil: same treatment, all pinned BCR modules. Thanks for the heads-up on Abseil! Once you remove it, the Bazel side is just deleting one line from MODULE.bazel and one from deps.

3. Build options: Bazel has user-defined flags for exactly this. See ccronexpr's BUILD.bazel for an example. Options like CH_MAP_BOOL_TO_UINT8 or a future tls=boringssl|openssl switch map naturally onto bool_flag + select(). I kept this PR single-configuration on purpose, and flags can be added incrementally.

Overall my suggestion: let the Bazel build stay hermetic. Since every dependency version is fully under control, many enterprise users actually prefer this model: the resulting binaries carry no expectations about what's installed on the host, which to some extent simplifies container (Docker) images, often down to a minimal base image plus the binary. For users who prefer system-installed dependencies, CMake remains the right tool. The two builds serve different philosophies, and that's fine. 🙂

BYVoid added 2 commits June 4, 2026 10:10
Adds --@clickhouse_cpp//:tls=boringssl|openssl (default: boringssl).
Both TLS implementations come from BCR modules and are linked
statically, keeping the build hermetic. USE_BORINGSSL and the TLS
deps are now switched via select() on the flag.
BoringSSL doesn't ship the SSL_CONF_* command API, so
SSLParams::configuration cannot be applied. Print a one-time warning
to stderr instead of silently dropping potentially security-relevant
settings, and point users at the OpenSSL build option.
@BYVoid
Copy link
Copy Markdown
Author

BYVoid commented Jun 4, 2026

@slabko I added a tls build flag.

BYVoid added 3 commits June 4, 2026 10:25
abseil-cpp 20260107.1 -> 20260526.0
boringssl 0.20260508.0 -> 0.20260526.0
rules_cc 0.2.18 -> 0.2.19
cityhash 1.0.2 is now available on the Bazel Central Registry, so the
Bazel build no longer compiles the vendored copy under
contrib/cityhash/. The contrib/ tree is still used by the CMake build.
Build matrix: {ubuntu-24.04, macos-latest} x {boringssl, openssl}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants