[llvm] [CI] Add Python Script for Computing Projects/Runtimes to Test (PR #132634)

Aiden Grossman via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 23 13:41:27 PDT 2025


https://github.com/boomanaiden154 created https://github.com/llvm/llvm-project/pull/132634

This patch adds a python script, compute_projects, and associated unit
tests for computing the projects and runtimes that need to be tested in
premerge. Rewriting in Python opens up a couple new
improvements/opportunities:
1. I personally find python to be much easier to work with than shell
   scripts for tasks like this. Particularly it becomes a lot easier to
   work with paths with proper array support.
2. Unit testing becomes easier which makes it a lot easier to reason
   about behavior changes, especially in review.
3. Most of the configuration is now setup in some dictionaries, which
   makes changes much easier to apply for most of the common changes.

This preserves the behavior of the existing premerge scripts as much as
possible.


>From bd6b2f917f9f43328874789ac03259d2dad71552 Mon Sep 17 00:00:00 2001
From: Aiden Grossman <aidengrossman at google.com>
Date: Sun, 23 Mar 2025 20:41:17 +0000
Subject: [PATCH] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20initia?=
 =?UTF-8?q?l=20version?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Created using spr 1.3.4
---
 .ci/compute_projects.py      | 166 +++++++++++++++++++++++++++++++++++
 .ci/compute_projects_test.py | 130 +++++++++++++++++++++++++++
 2 files changed, 296 insertions(+)
 create mode 100644 .ci/compute_projects.py
 create mode 100644 .ci/compute_projects_test.py

diff --git a/.ci/compute_projects.py b/.ci/compute_projects.py
new file mode 100644
index 0000000000000..c669e89faf946
--- /dev/null
+++ b/.ci/compute_projects.py
@@ -0,0 +1,166 @@
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+"""Computes the list of projects that need to be tested from a diff.
+
+Does some things, spits out a list of projects.
+"""
+
+from collections.abc import Set
+import pathlib
+import platform
+import sys
+
+PROJECT_DEPENDENCIES = {
+    "llvm": set(),
+    "clang": {"llvm"},
+    "bolt": {"clang", "lld", "llvm"},
+    "clang-tools-extra": {"clang", "llvm"},
+    "compiler-rt": {"clang", "lld"},
+    "libc": {"clang", "lld"},
+    "openmp": {"clang", "lld"},
+    "flang": {"llvm", "clang"},
+    "lldb": {"llvm", "clang"},
+    "libclc": {"llvm", "clang"},
+    "lld": {"llvm"},
+    "mlir": {"llvm"},
+    "polly": {"llvm"},
+}
+
+DEPENDENTS_TO_TEST = {
+    "llvm": {"bolt", "clang", "clang-tools-extra", "lld", "lldb", "mlir", "polly"},
+    "lld": {"bolt", "cross-project-tests"},
+    "clang": {"clang-tools-extra", "compiler-rt", "cross-project-tests"},
+    "clang-tools-extra": {"libc"},
+    "mlir": {"flang"},
+}
+
+DEPENDENT_RUNTIMES_TO_TEST = {"clang": {"libcxx", "libcxxabi", "libunwind"}}
+
+EXCLUDE_LINUX = {
+    "cross-project-tests",  # Tests are failing.
+    "openmp",  # https://github.com/google/llvm-premerge-checks/issues/410
+}
+
+EXCLUDE_WINDOWS = {
+    "cross-project-tests",  # Tests are failing.
+    "compiler-rt",  # Tests are taking too long.
+    "openmp",  # Does not detect perl installation.
+    "libc",  # No Windows Support.
+    "lldb",  # Custom environment requirements.
+    "bolt",  # No Windows Support.
+}
+
+PROJECT_CHECK_TARGETS = {
+    "clang-tools-extra": "check-clang-tools",
+    "compiler-rt": "check-compiler-rt",
+    "cross-project-tests": "check-cross-project",
+    "libcxx": "check-cxx",
+    "libcxxabi": "check-cxxabi",
+    "libunwind": "check-unwind",
+    "lldb": "check-lldb",
+    "llvm": "check-llvm",
+    "clang": "check-clang",
+    "bolt": "check-bolt",
+    "lld": "check-lld",
+    "flang": "check-flang",
+    "libc": "check-libc",
+    "lld": "check-lld",
+    "lldb": "check-lldb",
+    "mlir": "check-mlir",
+    "openmp": "check-openmp",
+    "polly": "check-polly",
+}
+
+
+def _add_dependencies(projects: Set[str]) -> Set[str]:
+    projects_with_dependents = set(projects)
+    current_projects_count = 0
+    while current_projects_count != len(projects_with_dependents):
+        current_projects_count = len(projects_with_dependents)
+        for project in list(projects_with_dependents):
+            if project not in PROJECT_DEPENDENCIES:
+                continue
+            projects_with_dependents.update(PROJECT_DEPENDENCIES[project])
+    return projects_with_dependents
+
+
+def _compute_projects_to_test(modified_projects: Set[str], platform: str) -> Set[str]:
+    """Computes the list of projects that should be passed to LLVM_ENABLE_PROJECTS"""
+    projects_to_test = set(modified_projects)
+    for modified_project in modified_projects:
+        if modified_project not in DEPENDENTS_TO_TEST:
+            continue
+        projects_to_test.update(DEPENDENTS_TO_TEST[modified_project])
+    if platform == "Linux":
+        for to_exclude in EXCLUDE_LINUX:
+            if to_exclude in projects_to_test:
+                projects_to_test.remove(to_exclude)
+    elif platform == "Windows":
+        for to_exclude in EXCLUDE_WINDOWS:
+            if to_exclude in projects_to_test:
+                projects_to_test.remove(to_exclude)
+    else:
+        raise ValueError("Unexpected platform.")
+    return projects_to_test
+
+
+def _compute_projects_to_build(projects_to_test: Set[str]) -> Set[str]:
+    return _add_dependencies(projects_to_test)
+
+
+def _compute_project_check_targets(projects_to_test: Set[str]) -> Set[str]:
+    """blah blah blah"""
+    check_targets = set()
+    for project_to_test in projects_to_test:
+        if project_to_test not in PROJECT_CHECK_TARGETS:
+            continue
+        check_targets.add(PROJECT_CHECK_TARGETS[project_to_test])
+    return check_targets
+
+
+def _compute_runtimes_to_test(projects_to_test: Set[str]) -> Set[str]:
+    """blah blah blah"""
+    runtimes_to_test = set()
+    for project_to_test in projects_to_test:
+        if project_to_test not in DEPENDENT_RUNTIMES_TO_TEST:
+            continue
+        runtimes_to_test.update(DEPENDENT_RUNTIMES_TO_TEST[project_to_test])
+    return runtimes_to_test
+
+
+def _compute_runtime_check_targets(runtimes_to_test: Set[str]) -> Set[str]:
+    """blah blah blah"""
+    check_targets = set()
+    for runtime_to_test in runtimes_to_test:
+        check_targets.add(PROJECT_CHECK_TARGETS[runtime_to_test])
+    return check_targets
+
+
+def _get_modified_projects(modified_files: list[str]) -> Set[str]:
+    """blah blah blah"""
+    modified_projects = set()
+    for modified_file in modified_files:
+        modified_projects.add(pathlib.Path(modified_file).parts[0])
+    return modified_projects
+
+
+def get_env_variables(modified_files: list[str], platform: str) -> Set[str]:
+    modified_projects = _get_modified_projects(modified_files)
+    projects_to_test = _compute_projects_to_test(modified_projects, platform)
+    projects_to_build = _compute_projects_to_build(projects_to_test)
+    projects_check_targets = _compute_project_check_targets(projects_to_test)
+    runtimes_to_test = _compute_runtimes_to_test(projects_to_test)
+    runtimes_check_targets = _compute_runtime_check_targets(runtimes_to_test)
+    return {
+        "projects_to_build": ";".join(sorted(projects_to_build)),
+        "project_check_targets": " ".join(sorted(projects_check_targets)),
+        "runtimes_to_build": ";".join(sorted(runtimes_to_test)),
+        "runtimes_check_targets": " ".join(sorted(runtimes_check_targets)),
+    }
+
+
+if __name__ == "__main__":
+    env_variables = get_env_variables(sys.stdin.readlines(), platform.system())
+    for env_variable in env_variables:
+        print(f"{env_variable}={env_variables[env_variable]}")
diff --git a/.ci/compute_projects_test.py b/.ci/compute_projects_test.py
new file mode 100644
index 0000000000000..b12ad69adf15a
--- /dev/null
+++ b/.ci/compute_projects_test.py
@@ -0,0 +1,130 @@
+# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+# See https://llvm.org/LICENSE.txt for license information.
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+"""Does some stuff."""
+
+import unittest
+
+import compute_projects
+
+
+class TestComputeProjects(unittest.TestCase):
+    def test_llvm(self):
+        env_variables = compute_projects.get_env_variables(
+            ["llvm/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(
+            env_variables["projects_to_build"],
+            "bolt;clang;clang-tools-extra;lld;lldb;llvm;mlir;polly",
+        )
+        self.assertEqual(
+            env_variables["project_check_targets"],
+            "check-bolt check-clang check-clang-tools check-lld check-lldb check-llvm check-mlir check-polly",
+        )
+        self.assertEqual(
+            env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind"
+        )
+        self.assertEqual(
+            env_variables["runtimes_check_targets"],
+            "check-cxx check-cxxabi check-unwind",
+        )
+
+    def test_llvm_windows(self):
+        env_variables = compute_projects.get_env_variables(
+            ["llvm/CMakeLists.txt"], "Windows"
+        )
+        self.assertEqual(
+            env_variables["projects_to_build"],
+            "clang;clang-tools-extra;lld;llvm;mlir;polly",
+        )
+        self.assertEqual(
+            env_variables["project_check_targets"],
+            "check-clang check-clang-tools check-lld check-llvm check-mlir check-polly",
+        )
+        self.assertEqual(
+            env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind"
+        )
+        self.assertEqual(
+            env_variables["runtimes_check_targets"],
+            "check-cxx check-cxxabi check-unwind",
+        )
+
+    def test_clang(self):
+        env_variables = compute_projects.get_env_variables(
+            ["clang/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(
+            env_variables["projects_to_build"],
+            "clang;clang-tools-extra;compiler-rt;lld;llvm",
+        )
+        self.assertEqual(
+            env_variables["project_check_targets"],
+            "check-clang check-clang-tools check-compiler-rt",
+        )
+        self.assertEqual(
+            env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind"
+        )
+        self.assertEqual(
+            env_variables["runtimes_check_targets"],
+            "check-cxx check-cxxabi check-unwind",
+        )
+
+    def test_clang_windows(self):
+        env_variables = compute_projects.get_env_variables(
+            ["clang/CMakeLists.txt"], "Windows"
+        )
+        self.assertEqual(
+            env_variables["projects_to_build"], "clang;clang-tools-extra;llvm"
+        )
+        self.assertEqual(
+            env_variables["project_check_targets"], "check-clang check-clang-tools"
+        )
+        self.assertEqual(
+            env_variables["runtimes_to_build"], "libcxx;libcxxabi;libunwind"
+        )
+        self.assertEqual(
+            env_variables["runtimes_check_targets"],
+            "check-cxx check-cxxabi check-unwind",
+        )
+
+    def test_bolt(self):
+        env_variables = compute_projects.get_env_variables(
+            ["bolt/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(env_variables["projects_to_build"], "bolt;clang;lld;llvm")
+        self.assertEqual(env_variables["project_check_targets"], "check-bolt")
+        self.assertEqual(env_variables["runtimes_to_build"], "")
+        self.assertEqual(env_variables["runtimes_check_targets"], "")
+
+    def test_lldb(self):
+        env_variables = compute_projects.get_env_variables(
+            ["lldb/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(env_variables["projects_to_build"], "clang;lldb;llvm")
+        self.assertEqual(env_variables["project_check_targets"], "check-lldb")
+        self.assertEqual(env_variables["runtimes_to_build"], "")
+        self.assertEqual(env_variables["runtimes_check_targets"], "")
+
+    def test_mlir(self):
+        env_variables = compute_projects.get_env_variables(
+            ["mlir/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(env_variables["projects_to_build"], "clang;flang;llvm;mlir")
+        self.assertEqual(
+            env_variables["project_check_targets"], "check-flang check-mlir"
+        )
+        self.assertEqual(env_variables["runtimes_to_build"], "")
+        self.assertEqual(env_variables["runtimes_check_targets"], "")
+
+    def test_flang(self):
+        env_variables = compute_projects.get_env_variables(
+            ["flang/CMakeLists.txt"], "Linux"
+        )
+        self.assertEqual(env_variables["projects_to_build"], "clang;flang;llvm")
+        self.assertEqual(env_variables["project_check_targets"], "check-flang")
+        self.assertEqual(env_variables["runtimes_to_build"], "")
+        self.assertEqual(env_variables["runtimes_check_targets"], "")
+
+
+if __name__ == "__main__":
+    unittest.main()



More information about the llvm-commits mailing list