diff --git a/bazel/check_deps/BUILD b/bazel/check_deps/BUILD index 8036552ea6c5..7064e036d686 100644 --- a/bazel/check_deps/BUILD +++ b/bazel/check_deps/BUILD @@ -4,62 +4,19 @@ load("@mypy_integration//:mypy.bzl", "mypy_test") -# This filegroup should contain all the non-test C++ rules in the repository to -# enable dependency checking. It can be regenerated by running the following -# query command: +# The filegroups establishing root rules for `genquery` invocations can be +# updated by running: # # ``` -# bazelisk query 'kind("cc.* rule", attr(testonly, 0, //...))' +# ./bazel/check_deps/update_roots.py # ``` filegroup( name = "non_test_cc_rules", data = [ - "//common:check", - "//common:indirect_value", - "//common:ostream", - "//common:string_helpers", "//executable_semantics", - "//executable_semantics/ast", - "//executable_semantics/ast:class_definition", - "//executable_semantics/ast:declaration", - "//executable_semantics/ast:expression", - "//executable_semantics/ast:library_name", - "//executable_semantics/ast:member", - "//executable_semantics/ast:paren_contents", - "//executable_semantics/ast:pattern", - "//executable_semantics/ast:source_location", - "//executable_semantics/ast:statement", - "//executable_semantics/common:arena", - "//executable_semantics/common:error", - "//executable_semantics/common:nonnull", - "//executable_semantics/interpreter", - "//executable_semantics/interpreter:address", - "//executable_semantics/interpreter:dictionary", - "//executable_semantics/interpreter:exec_program", - "//executable_semantics/interpreter:field_path", - "//executable_semantics/interpreter:heap", - "//executable_semantics/interpreter:stack", - "//executable_semantics/interpreter:type_checker", - "//executable_semantics/syntax", - "//executable_semantics/syntax:bison_wrap", "//migrate_cpp/cpp_refactoring", - "//migrate_cpp/cpp_refactoring:fn_inserter", - "//migrate_cpp/cpp_refactoring:for_range", - "//migrate_cpp/cpp_refactoring:matcher", - "//migrate_cpp/cpp_refactoring:var_decl", - "//toolchain/diagnostics:diagnostic_emitter", "//toolchain/diagnostics:null_diagnostics", - "//toolchain/driver", "//toolchain/driver:carbon", - "//toolchain/lexer:character_set", - "//toolchain/lexer:numeric_literal", - "//toolchain/lexer:string_literal", - "//toolchain/lexer:token_kind", - "//toolchain/lexer:tokenized_buffer", - "//toolchain/parser:parse_node_kind", - "//toolchain/parser:parse_tree", - "//toolchain/parser:precedence", - "//toolchain/source:source_buffer", ], ) @@ -85,3 +42,16 @@ mypy_test( include_imports = True, deps = [":check_non_test_cc_deps"], ) + +# Note that this script expects to be run directly and not via Bazel as it in +# turn invokes Bazel. +py_binary( + name = "update_roots", + srcs = ["update_roots.py"], +) + +mypy_test( + name = "update_roots_mypy_test", + include_imports = True, + deps = [":update_roots"], +) diff --git a/bazel/check_deps/update_roots.py b/bazel/check_deps/update_roots.py new file mode 100755 index 000000000000..76816c5a4c50 --- /dev/null +++ b/bazel/check_deps/update_roots.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 + +"""Update the roots of the Carbon build used for dependency checking. + +The dependency checking cannot use wildcard queries, so we use them here and +then create lists of relevant roots in the build file. +""" + +__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 os +import shutil +import subprocess +import sys +from pathlib import Path + +# Change the working directory to the repository root so that the remaining +# operations reliably operate relative to that root. +os.chdir(Path(__file__).parent.parent) +directory = Path.cwd() + +# Use the `BAZEL` environment variable if present. If not, then try to use +# `bazelisk` and then `bazel`. +bazel = os.environ.get("BAZEL") +if not bazel: + bazel = "bazelisk" + if not shutil.which(bazel): + bazel = "bazel" + if not shutil.which(bazel): + sys.exit("Unable to run Bazel") + +# Use the `BUILDOZER` environment variable if present. If not, then try to use +# `buildozer`. +buildozer = os.environ.get("BUILDOZER") +if not buildozer: + buildozer = "buildozer" + if not shutil.which(buildozer): + sys.exit("Unable to run Buildozer") + +print("Compute non-test C++ root targets...") +non_test_cc_roots_query = subprocess.run( + [ + bazel, + "query", + "--noshow_progress", + "--noimplicit_deps", + "--notool_deps", + "--output=minrank", + ( + 'let non_tests = kind("cc.* rule", attr(testonly, 0, //...))' + ' in kind("cc.* rule", deps($non_tests))' + ), + ], + check=True, + stdout=subprocess.PIPE, + universal_newlines=True, +).stdout +ranked_targets = [line.split() for line in non_test_cc_roots_query.splitlines()] +roots = [target for rank, target in ranked_targets if int(rank) == 0] +print("Found roots:\n%s" % "\n".join(roots)) + +print("Replace non-test C++ roots in the BUILD file...") +buildozer_run = subprocess.run( + [ + buildozer, + "remove data", + ] + + ["add data '%s'" % root for root in roots] + + ["//bazel/check_deps:non_test_cc_rules"], +) +if buildozer_run.returncode == 3: + print("No changes needed!") +else: + buildozer_run.check_returncode() + print("Successfully updated roots in the BUILD file!") diff --git a/executable_semantics/ast/BUILD b/executable_semantics/ast/BUILD index d36c2604fa8c..ed85e312b78f 100644 --- a/executable_semantics/ast/BUILD +++ b/executable_semantics/ast/BUILD @@ -2,10 +2,7 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -package(default_visibility = [ - "//bazel/check_deps:__pkg__", - "//executable_semantics:__subpackages__", -]) +package(default_visibility = ["//executable_semantics:__subpackages__"]) cc_library( name = "ast", diff --git a/executable_semantics/common/BUILD b/executable_semantics/common/BUILD index 1c58953f1b91..565774afbaeb 100644 --- a/executable_semantics/common/BUILD +++ b/executable_semantics/common/BUILD @@ -2,10 +2,7 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -package(default_visibility = [ - "//bazel/check_deps:__pkg__", - "//executable_semantics:__subpackages__", -]) +package(default_visibility = ["//executable_semantics:__subpackages__"]) cc_library( name = "arena", diff --git a/executable_semantics/interpreter/BUILD b/executable_semantics/interpreter/BUILD index 0fda71102108..3e92b1383a19 100644 --- a/executable_semantics/interpreter/BUILD +++ b/executable_semantics/interpreter/BUILD @@ -2,10 +2,7 @@ # Exceptions. See /LICENSE for license information. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -package(default_visibility = [ - "//bazel/check_deps:__pkg__", - "//executable_semantics:__pkg__", -]) +package(default_visibility = ["//executable_semantics:__pkg__"]) # These currently have to be a single build rule because of a dependency cycle # in printing. diff --git a/executable_semantics/syntax/BUILD b/executable_semantics/syntax/BUILD index 92cc2025d7fd..e0f654c0eac5 100644 --- a/executable_semantics/syntax/BUILD +++ b/executable_semantics/syntax/BUILD @@ -4,10 +4,7 @@ load("@mypy_integration//:mypy.bzl", "mypy_test") -package(default_visibility = [ - "//bazel/check_deps:__pkg__", - "//executable_semantics:__pkg__", -]) +package(default_visibility = ["//executable_semantics:__pkg__"]) cc_library( name = "bison_wrap",