Custom Bazel rules (wd_* macros) for C++, TypeScript, Rust, Cap'n Proto, and test orchestration. Uses bzlmod (MODULE.bazel), not WORKSPACE. This is build system definitions, NOT build output (bazel-bin/).
| Rule | Purpose |
|---|---|
wd_cc_library.bzl |
Wraps cc_library; strip_include_prefix="/src", arch-specific CPU flags (CRC32C) |
wd_cc_binary.bzl |
Wraps cc_binary; macOS dead-strip linkopts |
wd_cc_embed.bzl |
Binary/text data -> C++ via C23 #embed; auto-detects text vs binary by extension |
wd_cc_benchmark.bzl |
Google Benchmark wrapper; generates CSV report genrule |
wd_test.bzl |
.wd-test config test runner; generates up to 3 variants per test |
kj_test.bzl |
C++ unit test wrapper; also generates test variants |
wpt_test.bzl |
Web Platform Tests; generates JS runner + .wd-test config from WPT tree; delegates to wd_test |
wd_ts_bundle.bzl |
TypeScript compilation + JS bundle generation |
wd_js_bundle.bzl |
JS bundle -> Cap'n Proto Modules.Bundle embedding via generated .capnp |
wd_capnp_library.bzl |
Cap'n Proto schema compilation |
wd_rust_crate.bzl / wd_rust_binary.bzl |
Rust build rules; apply //build/rust:lints to every crate, test code excepted |
wd_rust_compile_test.bzl |
Rust compile tests checked against //~ ERROR annotations; harness in rust/compile_test_harness/ |
lint_test.bzl |
ESLint integration |
//tools/clang-tidy:workerd-lint |
Custom clang-tidy plugin (source: tools/clang-tidy/workerd-lint.c++); ships several custom checks |
Conventions:
- Test tags:
off-by-default,requires-container-engine,no-asan,no-coverage - Variant generation controllable per-test via
generate_*_variantbooleans BUILD.*files: overlay build files for third-party deps (sqlite3, zlib, simdutf, pyodide, wpt)
//tools/clang-tidy:workerd-lint builds a shared-object clang-tidy plugin
that adds workerd-specific static checks:
jsg-visit-for-gc: flags JSG resource types whose visitable fields (jsg::Ref,jsg::JsRef,jsg::V8Ref,jsg::Function,jsg::Promise,jsg::Value, etc., pluskj::Maybe/Array/Vector/OneOfandjsg::Optionalwrappers thereof) are missing fromvisitForGc().workerd-angled-includes- requires includes of workers/capnproto code from different directories to use angled bracketsworkerd-consume: flags calls to methods annotated withWD_CONSUMEwhen the call is made directly throughkj::Ptrinstead of throughconsume(kj::mv(ptr))->method(...).workerd-legacy-stream-alloc: flags direct allocation of the legacy C++ReadableStream/WritableStream(js.alloc<ReadableStream>(...),js.allocAccounted<...>,jsg::alloc<...>) anywhere other than insideJsReadableStream::create()/JsWritableStream::create(), the dispatch points that select the stream implementation by thetypescript_implemented_streamscompatibility flag. The legacy implementation's own internals and tests of the legacy implementation suppress it withNOLINT(workerd-legacy-stream-alloc)plus a comment explaining why the allocation has to be legacy.workerd-promise-ignore-result- warns on superfluousignoreResult()calls: on promises that are immediatelyco_awaited, and oncapnp::Request::send()results, which should usesendIgnoringResult()insteadworkerd-unsafe-continuation-capture: flags lambdas passed to async sinks (e.g.kj::Promise::then) that capture bare references, raw pointers, or non-owning views.
Usage:
- Run via
just clang-tidy <target>(e.g.,just clang-tidy //src/workerd/api/...). - Plugin sources live in
tools/clang-tidy/: one.h/.c++pair per check, registered inworkerd-lint.c++, built as acc_shared_librarytarget//tools/clang-tidy:workerd-lint. Each check has a<check>-test.shrunner driving<check>-positive-test.c++/<check>-negative-test.c++fixtures (bazel test //tools/clang-tidy/...). The sources are also exported viaexports_filesso downstream projects can rebuild against their own clang/LLVM headers. - The clang-tidy binary itself is published to
cloudflare/workerd-toolsreleases (seedeps/build_deps.jsonc, entriesclang_tidy_*); the matching*_dev.tar.xzarchive provides the clang/LLVM headers needed to build the plugin out-of-tree. Available for Linux amd64/arm64 and macOS arm64; a single archive (linux-amd64) serves all platforms since the AST-matching plugin doesn't depend on the arch-specific config macros that vary. - Wrapper script
build/tools/clang_tidy/clang_tidy_wrapper.shloads the plugin via--load=. - Suppress an intentional non-visit with
// NOLINT(jsg-visit-for-gc)plus a comment explaining why the field is safe to skip (seesrc/workerd/api/streams/queue.hforByteQueue::Entry::store).
Some checks produce many warnings on existing code and need incremental rollout.
The CHECK_PATH_FILTERS dict in build/tools/clang_tidy/check_path_filters.bzl
supports this:
- Add the check to
.clang-tidyChecks list - Add an entry to
CHECK_PATH_FILTERSwith an empty list (runs nowhere) - Add file paths as they are cleaned up
- Remove the entry once fully rolled out (runs everywhere)
Example:
CHECK_PATH_FILTERS = {
"workerd-unsafe-continuation-capture": [
"src/workerd/io",
"src/workerd/api",
],
}Path prefixes match all files under that directory (src/workerd/io
matches src/workerd/io/foo.c++ and src/workerd/io/subdir/bar.c++).
To run a filtered check everywhere during development:
bazel build --config=clang-tidy-unsafe-continuation-capture //src/...Lives in deps/. Uses jsonc manifests + codegen:
deps.jsonc,build_deps.jsonc,shared_deps.jsonc— dependency specificationsupdate-deps.py [dep_name]— fetches latest versions, computes hashes, regeneratesgen/MODULE.bazel fragmentsgen/— autogenerated; do not hand-edit*.MODULE.bazel(e.g.,rust.MODULE.bazel,v8.MODULE.bazel) — included by rootMODULE.bazelworkerd-v8/— separate Bazel module wrapping V8 dependency
Pyodide package metadata lives in build/python_metadata.bzl; the checked-in, pre-filtered
package lock files live in src/pyodide/python-lock/.