From 65ac59eb2ae8d697ab522b9a9e30d7d9e1956720 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Wed, 3 Nov 2021 12:53:54 -0700 Subject: [PATCH] Add a script to compute minimal roots for check_deps. (#932) This avoids needing to have nearly as many rules here which should reduce its churn. I've tested that this reaches the exact same set of transitive dependencies. Note, only the last commit here is new. --- bazel/check_deps/BUILD | 62 ++++++-------------- bazel/check_deps/update_roots.py | 79 ++++++++++++++++++++++++++ executable_semantics/ast/BUILD | 5 +- executable_semantics/common/BUILD | 5 +- executable_semantics/interpreter/BUILD | 5 +- executable_semantics/syntax/BUILD | 5 +- 6 files changed, 99 insertions(+), 62 deletions(-) create mode 100755 bazel/check_deps/update_roots.py 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",