Files
carbon-lang/scripts/forbid_llvm_googletest.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

60 lines
1.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Detects and prevents dependencies on LLVM's googletest.
Carbon uses googletest directly, and it's a significantly more recent version
than is provided by LLVM. Using both versions in the same binary leads to
problems, so this detects dependencies.
We also have some dependency checking at //bazel/check_deps. This is a separate
script because check_deps relies on being able to validate specific binaries
which change infrequently, whereas this effectively monitors all cc_test rules,
the set of which is expected to be altered more often.
"""
__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
_MESSAGE = """\
Dependencies on @llvm-project//llvm:gtest are forbidden, but a dependency path
was detected:
%s
Carbon uses GoogleTest through @googletest, which is a different
version than LLVM uses at @llvm-project//llvm:gtest. As a consequence,
dependencies on @llvm-project//llvm:gtest must be avoided.
"""
def main() -> None:
scripts_utils.chdir_repo_root()
args = [
scripts_utils.locate_bazel(),
"query",
"somepath("
# tree_sitter is excluded here because it causes the query to failure on
# `@platforms`.
+ "//... except //utils/tree_sitter/..., "
+ "@llvm-project//third-party/unittest:gtest)",
]
p = subprocess.run(
args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8"
)
if p.returncode != 0:
print(p.stderr)
exit(f"bazel query returned {p.returncode}")
if p.stdout:
exit(_MESSAGE % p.stdout)
print("Done!")
if __name__ == "__main__":
main()