Carve compile_commands.json out of Bazel build graphs for clangd-style
tooling, licensed under Apache-2.0. Carve is a clean-slate C++23
replacement for the
maintained helly25 fork of Hedron's bazel-compile-commands-extractor.
(Note that the original Hedron repository is no longer maintained.)
Working, pre-release. All three layers are implemented and tested - Layer A
(carve refresh), Layer B (bazel run //:refresh), and Layer C (the
cc_carve_aspect aspect emitting per-action shards) - along with the refresh,
aggregate, shard, and prune subcommands. Not yet published to the Bazel
Central Registry; the release tooling is in place. See
CARVE_DESIGN.md for the architecture and
docs/IMPLEMENTATION_PLAN.md for milestone status.
- Walks Bazel's action graph via
bazel aquery. - Filters to C/C++/Objective-C/CUDA compile actions.
- Resolves each action's header set in-process via clang's
DependencyScanningTool. - De-Bazels each compile command so clangd can introspect it without Bazel-specific environment.
- Writes an atomic
compile_commands.jsonplus a persistent sidecar cache that skips re-scanning unchanged actions on re-refresh.
A working CDB does not require a full build; clangd resolves most headers
itself. Generated headers, however, must exist on disk for the scan to resolve
them - codegen-heavy targets may need a build first. Sub-second incremental
refresh on large monorepos is a Layer C (aspect) property: Layers A/B re-run
bazel aquery each time and so pay the graph-query cost regardless of edit
size. See CARVE_DESIGN.md section 3.1.
# Refresh the whole repo's compilation database (writes compile_commands.json to
# the workspace root). This is the carve_refresh rule (Layer B).
bazel run //:refresh
# Or drive the binary directly (Layer A), choosing targets/output on the CLI.
bazel run //:carve -- refresh --targets=//foo/... --output=compile_commands.jsonIn a consumer workspace, depend on carve in MODULE.bazel (once it is published
to the Bazel Central Registry):
bazel_dep(name = "mboworks_carve", version = "0.1.1")
# The official LLVM static archives contain LLVM bitcode, so select the
# matching compiler as well as its C++ standard library.
bazel_dep(name = "toolchains_llvm", version = "1.9.0")
llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm")
llvm.toolchain(
name = "llvm_toolchain",
llvm_version = "22.1.8",
stdlib = {
"": "builtin-libc++",
"linux-aarch64": "stdc++",
"linux-x86_64": "stdc++",
},
)
use_repo(llvm, "llvm_toolchain")
register_toolchains("@llvm_toolchain//:all")Carve links LLVM's prebuilt dependency-scanning libraries. Copy
carve.bazelrc into the consumer workspace and import it from
the workspace .bazelrc so Carve is compiled as C++23 with its required LLVM
link settings and warning policy:
try-import %workspace%/carve.bazelrc
The fragment is part of every source archive. The consumer registers the
matching toolchain because toolchains_llvm 1.9.0 only permits its toolchain
extension in the root module. Bazel's include() likewise cannot load a
fragment from an external repository, so this stanza cannot live inside Carve.
The checked-in examples/bcr module is the authoritative
consumer example used by both source-archive CI and the optional BCR
presubmit.
Then add the rule from a BUILD file:
load("@mboworks_carve//rules:carve.bzl", "carve_refresh")
carve_refresh(name = "refresh", targets = ["//..."])carve_refresh is a bazel run target, not a build artifact: carve invokes
bazel aquery, and spawning bazel inside a build action is the nested-bazel
trap. For huge repos there is also Layer C - cc_carve_aspect +
carve_aspect_refresh (rules/cc_carve_aspect.bzl, rules/carve.bzl) schedule
one individually-cacheable shard per compile action and aggregate them.
- Bazel 9.1+
- Clang 22.x (LLVM 22.1.8); root development uses
toolchains_llvm 1.9.0,
while
scan_depsdownloads and links the matching static Clang/LLVM archives - A consumer toolchain using LLVM 22.1.8 with libstdc++ on Linux or libc++ on macOS, matching the official LLVM distributions
- Apple Silicon / x86_64 Linux supported; Windows planned
Copyright M. Boerger, the MBO Works authors. Licensed under the Apache License 2.0; see LICENSE for details.