Просмотр исходного кода

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.
Chandler Carruth 4 лет назад
Родитель
Сommit
65ac59eb2a

+ 16 - 46
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"],
+)

+ 79 - 0
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!")

+ 1 - 4
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",

+ 1 - 4
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",

+ 1 - 4
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.

+ 1 - 4
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",