Files
carbon-lang/scripts/create_compdb.py
T
Jon Ross-Perkins 6f6e46ef57 Migrate tree-sitter support to MODULE.bazel (#4783)
The WORKSPACE file is deprecated; support is already off by default, and
it'll be removed in the next major bazel release. Our main dependency is
tree-sitter, and I'm trying to address that here.

We're currently using https://github.com/elliottt/rules_tree_sitter, but
that hasn't been updated in a couple years, meaning it lacks
MODULE.bazel support. In the registry, there's
https://registry.bazel.build/modules/tree-sitter-bazel, but this is only
the *parser* libraries of tree-sitter, not the *generator*. I'm using it
for that much, at least.

For the *generator*, which transforms grammar.js to parser.c/h, I'm just
requiring a non-hermetic invocation (i.e., people who want to work on it
will need to install tree-sitter; see the README.md updates). I tried
running it manually, but parser.c is about 600 KB; pre-commit rejects
files that large and I don't think an exception makes sense to override
for this (it'd probably also grow substantially if the grammar were
updated to cover more syntax). In order to make the non-hermetic call
not break "bazel build //..." for most developers, I'm marking most
targets in the package as manual.

Note, I did look long and hard at using `aspect_rules_js`/`rules_nodejs`
to invoke npm. This took a lot of time, and I have a commit that's
mostly working, except I hit a point where it uses `declare_symlink`
which we disallow for compatibility reasons (commit "Lots of work for
figuring out rule_js uses declare_symlink" on the PR). As a consequence,
I think we can't use the primary supported ways to have hermetic npm
calls.

Also, `treesitter` -> `tree_sitter` because it's generally called
`tree-sitter`, two words. We even had a `treesitter/src/tree_sitter`
directory so it's a bit inconsistent.

As far as bugs here, the parser library breaks bazel queries, e.g. the
error:
```
ERROR: Evaluation of query "somepath(//..., @llvm-project//third-party/unittest:gtest)" failed: preloading transitive closure failed: no such package '@@[unknown repo 'platforms' requested from @@tree-sitter-bazel+]//': The repository '@@[unknown repo 'platforms' requested from @@tree-sitter-bazel+]' could not be resolved: No repository visible as '@platforms' from repository '@@tree-sitter-bazel+'
```

I'm just excluding tree_sitter from queries where I can to work around
the error.
2025-01-13 19:04:10 +00:00

71 lines
2.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""Create a compilation database for Clang tools like `clangd`.
If you want `clangd` to be able to index this project, run this script from
the workspace root to generate a rich compilation database. After the first
run, you should only need to run it if you encounter `clangd` problems, or if
you want `clangd` to build an up-to-date index of the entire project. Note
that in the latter case you may need to manually clear and rebuild clangd's
index after running this script.
Note that this script will build generated files in the Carbon project and
otherwise touch the Bazel build. It works to do the minimum amount necessary.
Once setup, generally subsequent builds, even of small parts of the project,
different configurations, or that hit errors won't disrupt things. But, if
you do hit errors, you can get things back to a good state by fixing the
build of generated files and re-running this script.
"""
__copyright__ = """
Part of the Carbon Language project, under the Apache License v2.0 with LLVM
Exceptions. See /LICENSE for license information.
SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
"""
import subprocess
import scripts_utils
def _build_generated_files(bazel: str) -> None:
print("Building the generated files so that tools can find them...")
# Collect the generated file labels. Include some rules which generate
# files but aren't classified as "generated file".
kinds_query = (
"filter("
' ".*\\.(h|cpp|cc|c|cxx|def|inc)$",'
# tree_sitter is excluded here because it causes the query to failure on
# `@platforms`.
' kind("generated file", deps(//... except //utils/tree_sitter/...))'
")"
)
generated_file_labels = subprocess.check_output(
[bazel, "query", "--keep_going", "--output=label", kinds_query],
stderr=subprocess.DEVNULL,
encoding="utf-8",
).splitlines()
print(f"Found {len(generated_file_labels)} generated files...")
# Directly build these labels so that indexing can find them. Allow this to
# fail in case there are build errors in the client, and just warn the user
# that they may be missing generated files.
subprocess.check_call(
[bazel, "build", "--keep_going"] + generated_file_labels
)
def main() -> None:
scripts_utils.chdir_repo_root()
bazel = scripts_utils.locate_bazel()
_build_generated_files(bazel)
print("Generating compile_commands.json (may take a few minutes)...")
subprocess.run([bazel, "run", "@hedron_compile_commands//:refresh_all"])
if __name__ == "__main__":
main()