Skip to content

Commit 135d081

Browse files
committed
bazel: migrate to hedron compile-commands-extractor; update generator and docs
Replace the unmaintained `bazel_compdb` with the Hedron `bazel-compile-commands-extractor` and adapt the workspace tooling. - Add `http_archive` for Hedron in `bazel/repositories.bzl` (pinned sha256). - Add a convenience `refresh_compile_commands` target to the workspace `BUILD`. - Update `tools/gen_compilation_database.py`: - Prefer calling the external extractor (`@hedron_compile_commands//:refresh_all`) by default. - Forward boolean flags (`--include_external`, `--include_genfiles`, `--include_headers`, `--include_all`, `--system-clang`) to the extractor. - Remove automatic fallback to a workspace-root `:refresh_compile_commands` and emit a clear error if the external extractor fails. - Best-effort cleanup of temporary files created for per-target runs. - Update `DEVELOPMENT.md` with concise English instructions, examples and useful links for generating `compile_commands.json`. - Run basic validation: built and ran the extractor and verified `compile_commands.json` is produced for both workspace-wide and per-target invocations. Signed-off-by: Matthieu MOREL <[email protected]>
1 parent c8868da commit 135d081

File tree

4 files changed

+96
-18
lines changed

4 files changed

+96
-18
lines changed

BUILD

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
load("@hedron_compile_commands//:refresh_compile_commands.bzl", "refresh_compile_commands")
1516
load(
1617
"@proxy_wasm_cpp_host//bazel:select.bzl",
1718
"proxy_wasm_select_engine_null",
@@ -33,6 +34,21 @@ filegroup(
3334
data = [".clang-tidy"],
3435
)
3536

37+
# Convenience target to refresh `compile_commands.json` for the workspace.
38+
# Adjust `targets` to what you work on frequently. Using `//:lib` here makes
39+
# the extractor gather commands for the main library; change to `//...` or a
40+
# dict of targets with flags if you prefer.
41+
refresh_compile_commands(
42+
name = "refresh_compile_commands",
43+
# Align with DEVELOPMENT.md example: include tests and the main lib.
44+
# Accepts a string, list, or dict (target->flags). A list will be converted
45+
# to a dict by the macro.
46+
targets = [
47+
"//test/...",
48+
"//:lib",
49+
],
50+
)
51+
3652
cc_library(
3753
name = "wasm_vm_headers",
3854
hdrs = [

DEVELOPMENT.md

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,41 @@
11
# Development guidelines
22

3-
## Generate compilation database
3+
## Generating compilation database
44

5-
[JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) files can be used by [clangd](https://clangd.llvm.org/) or similar tools to add source code cross-references and code completion functionality to editors.
5+
Use the Python wrapper `tools/gen_compilation_database.py` to produce a
6+
`compile_commands.json` file for `clangd` or similar tools. This is the
7+
recommended and reproducible approach.
68

7-
The following command can be used to generate the `compile_commands.json` file:
9+
See also:
810

11+
- JSON Compilation Database: https://clang.llvm.org/docs/JSONCompilationDatabase.html
12+
- clangd: https://clangd.llvm.org/
13+
14+
Generate for the whole workspace (recommended):
15+
16+
```bash
17+
BAZEL_BUILD_OPTION_LIST="--define=engine=multi" python3 tools/gen_compilation_database.py
918
```
10-
BAZEL_BUILD_OPTION_LIST="--define=engine=multi" ./tools/gen_compilation_database.py --include_all //test/... //:lib
19+
20+
Generate for specific Bazel targets:
21+
22+
```bash
23+
python3 tools/gen_compilation_database.py //test/... //:lib
1124
```
25+
26+
Supported flags:
27+
28+
- `--include_external`
29+
- `--include_genfiles`
30+
- `--include_headers`
31+
- `--include_all`
32+
- `--system-clang`
33+
34+
Notes:
35+
36+
- The Python wrapper calls the external Hedron extractor (`@hedron_compile_commands//:refresh_all`) by
37+
default.
38+
- If you pass positional targets the script creates a temporary Bazel package that defines a `refresh_compile_commands` target with those targets and runs it. This avoids forwarding targets directly to the extractor at runtime (which can cause `bazel aquery` parsing errors).
39+
- If you prefer a workspace-local target, create it in your root `BUILD` and run it directly with `bazel run :refresh_compile_commands`.
40+
- The extractor writes `compile_commands.json` at the repository root.
41+

bazel/repositories.bzl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,15 @@ def proxy_wasm_cpp_host_repositories():
143143
urls = ["https://github.com/proxy-wasm/proxy-wasm-cpp-sdk/archive/7465dee8b2953beebff99f6dc3720ad0c79bab99.tar.gz"],
144144
)
145145

146-
# Compile DB dependencies.
147146
maybe(
148147
http_archive,
149-
name = "bazel_compdb",
150-
sha256 = "acd2a9eaf49272bb1480c67d99b82662f005b596a8c11739046a4220ec73c4da",
151-
strip_prefix = "bazel-compilation-database-40864791135333e1446a04553b63cbe744d358d0",
152-
url = "https://github.com/grailbio/bazel-compilation-database/archive/40864791135333e1446a04553b63cbe744d358d0.tar.gz",
148+
name = "hedron_compile_commands",
149+
urls = [
150+
"https://github.com/hedronvision/bazel-compile-commands-extractor/archive/0e990032f3c5a866e72615cf67e5ce22186dcb97.tar.gz",
151+
],
152+
strip_prefix = "bazel-compile-commands-extractor-0e990032f3c5a866e72615cf67e5ce22186dcb97",
153+
# SHA256 of the tarball (computed from upstream tag/commit).
154+
sha256 = "2b3ee8bba2df4542a508b0289727b031427162b4cd381850f89b406445c17578",
153155
)
154156

155157
# Test dependencies.

tools/gen_compilation_database.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,18 +35,48 @@ def generate_compilation_database(args):
3535

3636
source_dir_targets = args.bazel_targets
3737

38-
subprocess.check_call(["bazel", *bazel_startup_options, "build"] + bazel_options + [
39-
"--aspects=@bazel_compdb//:aspects.bzl%compilation_database_aspect",
40-
"--output_groups=compdb_files,header_files"
41-
] + source_dir_targets)
38+
# Build the list of runtime flags (those accepted by the extractor script)
39+
runtime_flags = []
40+
if args.include_external:
41+
runtime_flags.append("--include_external")
42+
if args.include_genfiles:
43+
runtime_flags.append("--include_genfiles")
44+
if args.include_headers:
45+
runtime_flags.append("--include_headers")
46+
if args.include_all:
47+
runtime_flags.append("--include_all")
48+
if args.system_clang:
49+
runtime_flags.append("--system-clang")
4250

43-
execroot = subprocess.check_output(
44-
["bazel", *bazel_startup_options, "info", *bazel_options,
45-
"execution_root"]).decode().strip()
51+
# Invoke the external Hedron extractor directly and forward both runtime
52+
# flags and any positional Bazel targets to it. The extractor is expected
53+
# to accept these arguments; this keeps the wrapper simple and makes the
54+
# user-visible behavior consistent: calling the Python script is equivalent
55+
# to running the external extractor with the same arguments.
56+
try:
57+
subprocess.check_call([
58+
"bazel", *bazel_startup_options, "run", *bazel_options,
59+
"@hedron_compile_commands//:refresh_all", "--"
60+
] + runtime_flags + source_dir_targets)
61+
except subprocess.CalledProcessError as e:
62+
print("ERROR: external Hedron extractor failed to run; please ensure @hedron_compile_commands is available and the provided arguments are valid for the extractor.")
63+
raise e
4664

65+
# The extractor writes a single `compile_commands.json` into the workspace
66+
# root. Prefer that file; fall back to searching the execroot for legacy
67+
# `*.compile_commands.json` files if the extractor didn't produce one.
4768
db_entries = []
48-
for db in Path(execroot).glob('**/*.compile_commands.json'):
49-
db_entries.extend(json.loads(db.read_text()))
69+
# Ensure we always have execroot available for any `__EXEC_ROOT__` markers.
70+
execroot = subprocess.check_output(
71+
["bazel", *bazel_startup_options, "info", *bazel_options, "execution_root"]
72+
).decode().strip()
73+
74+
cc_path = Path("compile_commands.json")
75+
if cc_path.exists():
76+
db_entries = json.loads(cc_path.read_text())
77+
else:
78+
for db in Path(execroot).glob('**/*.compile_commands.json'):
79+
db_entries.extend(json.loads(db.read_text()))
5080

5181
def replace_execroot_marker(db_entry):
5282
if 'directory' in db_entry and db_entry['directory'] == '__EXEC_ROOT__':

0 commit comments

Comments
 (0)