Skip to content

Conversation

@Meinersbur
Copy link
Member

@Meinersbur Meinersbur commented Nov 6, 2025

Allow the main llvm-project repository to contain the buildbot builder instructions, instead of storing them in llvm-zorg. Use polly-x86_64-linux-test-suite as a first test demonstration. The corresponding llvm-zorg PR is llvm/llvm-zorg#648.

Advantages are:

  • Are easier to make on the llvm-project repository. There are more reviewers than for the llvm-zorg repository
  • Buildbot changes can be made in the same PR with changes that require updating the buildbot, e.g. changing the name of a CMake option.
  • Some builders store a CMake cache file in the llvm-project repository for the reasons above. However, the number of changes that can be made with a CMake cache file alone are limited

Compared to AnnotatedBuilder, advantages are:

  • Reproducing a buildbot configuration locally made easy: just execute the script in-place. No llvm-zorg, local buildbot worker, or buildbot master needed.
  • Same for testing a change of a builder before landing it in llvm-zorg. Doing so wuth an AnnotatedBuilder requires two llvm-zorg checkouts: One for making the change of the builder script itself, which then is pushed to a private llvm-zorg branch on GitHub, and a second that is modified to fetch that branch instead of https://github.com/llvm/llvm-zorg/tree/main.
  • The AnnotatedBuilder scripts are located in the llvm-zorg repository and the buildbot-workers always checkout the top-of-trunk. This means that a buildbot configuration is split over three checkouts:
    • The checkout of llvm-zorg that the buildbot-master is running, which us updated only manually
    • The checkout of llvm-zorg by the buildbot-worker fetches; always the top-of-trunk and connot be selected using the buildbot master's "Rebuild" feature, .i.e may not match the revision of llvm-project that is executed such as the CMake cache files located there.
    • The checkout of llvm-project to be tested

The goal is to move as much as possible into the llvm-project repository such that there cannot be a mismatch between checkouts of the different repository. Ideally, the buildbot-master only needs to be updated+restarted for adding/removing workers, not for build configuration changes.

Add annotated builder

Test of Polly builder

run fix

Don't clobber twice
@github-actions
Copy link

github-actions bot commented Nov 6, 2025

⚠️ Python code formatter, darker found issues in your code. ⚠️

You can test this locally with the following command:
darker --check --diff -r origin/main...HEAD .ci/buildbot/worker.py polly/ci/polly-x86_64-linux-test-suite.py

⚠️
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing origin/main to the base branch/commit you want to compare against.
⚠️

View the diff from darker here.
--- .ci/buildbot/worker.py	2025-11-08 00:32:27.000000 +0000
+++ .ci/buildbot/worker.py	2025-11-08 00:35:46.038611 +0000
@@ -14,38 +14,34 @@
 import subprocess
 import sys
 from contextlib import contextmanager
 
 
-
-
-
-
 def cmake_pjoin(*args):
     """
     Join paths like safe_pjoin, but replace backslashes with forward
     slashes on platforms where they are path separators. This prevents
     CMake from choking when trying to decode what it thinks are escape
     sequences in filenames.
     """
     result = safe_pjoin(*args)
-    if os.sep == '\\':
-        return result.replace('\\', '/')
+    if os.sep == "\\":
+        return result.replace("\\", "/")
     else:
         return result
 
 
 def report(msg):
-    sys.stderr.write(msg + '\n')
+    sys.stderr.write(msg + "\n")
     sys.stderr.flush()
 
 
 def report_run_cmd(cmd, shell=False, *args, **kwargs):
     """
     Print a command, then executes it using subprocess.check_call.
     """
-    report('Running: %s' % ((cmd if shell else shquote_cmd(cmd)),))
+    report("Running: %s" % ((cmd if shell else shquote_cmd(cmd)),))
     sys.stderr.flush()
     subprocess.check_call(cmd, shell=shell, *args, **kwargs)
 
 
 def mkdirp(path):
@@ -85,50 +81,50 @@
     else:
         return os.path.join(dirname, *args)
 
 
 def _shquote_impl(txt, escaped_chars, quoted_chars):
-    quoted = re.sub(escaped_chars, r'\\\1', txt)
+    quoted = re.sub(escaped_chars, r"\\\1", txt)
     if len(quoted) == len(txt) and not quoted_chars.search(txt):
         return txt
     else:
         return '"' + quoted + '"'
 
 
 _SHQUOTE_POSIX_ESCAPEDCHARS = re.compile(r'(["`$\\])')
-_SHQUOTE_POSIX_QUOTEDCHARS = re.compile('[|&;<>()\' \t\n]')
+_SHQUOTE_POSIX_QUOTEDCHARS = re.compile("[|&;<>()' \t\n]")
 
 
 def shquote_posix(txt):
     """Return txt, appropriately quoted for POSIX shells."""
-    return _shquote_impl(
-        txt, _SHQUOTE_POSIX_ESCAPEDCHARS, _SHQUOTE_POSIX_QUOTEDCHARS)
+    return _shquote_impl(txt, _SHQUOTE_POSIX_ESCAPEDCHARS, _SHQUOTE_POSIX_QUOTEDCHARS)
 
 
 _SHQUOTE_WINDOWS_ESCAPEDCHARS = re.compile(r'(["\\])')
-_SHQUOTE_WINDOWS_QUOTEDCHARS = re.compile('[ \t\n]')
+_SHQUOTE_WINDOWS_QUOTEDCHARS = re.compile("[ \t\n]")
 
 
 def shquote_windows(txt):
     """Return txt, appropriately quoted for Windows's cmd.exe."""
     return _shquote_impl(
-        txt.replace('%', '%%'),
-        _SHQUOTE_WINDOWS_ESCAPEDCHARS, _SHQUOTE_WINDOWS_QUOTEDCHARS)
+        txt.replace("%", "%%"),
+        _SHQUOTE_WINDOWS_ESCAPEDCHARS,
+        _SHQUOTE_WINDOWS_QUOTEDCHARS,
+    )
 
 
 def shquote(txt):
     """Return txt, appropriately quoted for use in a shell command."""
-    if os.name in set(('nt', 'os2', 'ce')):
+    if os.name in set(("nt", "os2", "ce")):
         return shquote_windows(txt)
     else:
         return shquote_posix(txt)
 
 
 def shquote_cmd(cmd):
     """Convert a list of shell arguments to an appropriately quoted string."""
-    return ' '.join(map(shquote, cmd))
-
+    return " ".join(map(shquote, cmd))
 
 
 def clean_dir(path):
     """
     Removes directory at path (and all its subdirectories) if it exists,
@@ -148,28 +144,28 @@
     slashes on platforms where they are path separators. This prevents
     CMake from choking when trying to decode what it thinks are escape
     sequences in filenames.
     """
     result = safe_pjoin(*args)
-    if os.sep == '\\':
-        return result.replace('\\', '/')
+    if os.sep == "\\":
+        return result.replace("\\", "/")
     else:
         return result
 
 
 def report(msg):
-    sys.stderr.write(msg + '\n')
+    sys.stderr.write(msg + "\n")
     sys.stderr.flush()
 
 
 def report_run_cmd(cmd, shell=False, *args, **kwargs):
     """
     Print a command, then executes it using subprocess.check_call.
     """
-    report('Running: %s' % ((cmd if shell else shquote_cmd(cmd)),))
+    report("Running: %s" % ((cmd if shell else shquote_cmd(cmd)),))
     sys.stderr.flush()
-    subprocess.check_call([str(c) for c in  cmd], shell=shell, *args, **kwargs)
+    subprocess.check_call([str(c) for c in cmd], shell=shell, *args, **kwargs)
 
 
 def mkdirp(path):
     """Create directory path if it does not already exist."""
     try:
@@ -207,60 +203,59 @@
     else:
         return os.path.join(dirname, *args)
 
 
 def _shquote_impl(txt, escaped_chars, quoted_chars):
-    quoted = re.sub(escaped_chars, r'\\\1', txt)
+    quoted = re.sub(escaped_chars, r"\\\1", txt)
     if len(quoted) == len(txt) and not quoted_chars.search(txt):
         return txt
     else:
         return '"' + quoted + '"'
 
 
 _SHQUOTE_POSIX_ESCAPEDCHARS = re.compile(r'(["`$\\])')
-_SHQUOTE_POSIX_QUOTEDCHARS = re.compile('[|&;<>()\' \t\n]')
+_SHQUOTE_POSIX_QUOTEDCHARS = re.compile("[|&;<>()' \t\n]")
 
 
 def shquote_posix(txt):
     """Return txt, appropriately quoted for POSIX shells."""
-    return _shquote_impl(
-        txt, _SHQUOTE_POSIX_ESCAPEDCHARS, _SHQUOTE_POSIX_QUOTEDCHARS)
+    return _shquote_impl(txt, _SHQUOTE_POSIX_ESCAPEDCHARS, _SHQUOTE_POSIX_QUOTEDCHARS)
 
 
 _SHQUOTE_WINDOWS_ESCAPEDCHARS = re.compile(r'(["\\])')
-_SHQUOTE_WINDOWS_QUOTEDCHARS = re.compile('[ \t\n]')
+_SHQUOTE_WINDOWS_QUOTEDCHARS = re.compile("[ \t\n]")
 
 
 def shquote_windows(txt):
     """Return txt, appropriately quoted for Windows's cmd.exe."""
     return _shquote_impl(
-        txt.replace('%', '%%'),
-        _SHQUOTE_WINDOWS_ESCAPEDCHARS, _SHQUOTE_WINDOWS_QUOTEDCHARS)
+        txt.replace("%", "%%"),
+        _SHQUOTE_WINDOWS_ESCAPEDCHARS,
+        _SHQUOTE_WINDOWS_QUOTEDCHARS,
+    )
 
 
 def shquote(txt):
     """Return txt, appropriately quoted for use in a shell command."""
-    if os.name in set(('nt', 'os2', 'ce')):
+    if os.name in set(("nt", "os2", "ce")):
         return shquote_windows(txt)
     else:
         return shquote_posix(txt)
 
 
 def shquote_cmd(cmd):
     """Convert a list of shell arguments to an appropriately quoted string."""
-    return ' '.join(map(shquote, cmd))
+    return " ".join(map(shquote, cmd))
 
 
 def relative_if_possible(path, relative_to):
-        path = os.path.normpath(path)
-        try:
-            result = os.path.relpath(path, start=relative_to)
-            return result if result else path
-        except Exception:
-            return  path
-
-
+    path = os.path.normpath(path)
+    try:
+        result = os.path.relpath(path, start=relative_to)
+        return result if result else path
+    except Exception:
+        return path
 
 
 def first_true(*args):
     for a in args:
         if a:
@@ -274,187 +269,210 @@
             return a
     return None
 
 
 class Worker:
-    def __init__(self,args,clean,clobber,workdir,jobs,cachefile,llvmsrcroot):
-        self.args=args
-        self.clean =clean
-        self.clobber=clobber
-        self.workdir=workdir
-        self.jobs=jobs
-        self.cachefile =cachefile
-        self.llvmsrcroot=llvmsrcroot
+    def __init__(self, args, clean, clobber, workdir, jobs, cachefile, llvmsrcroot):
+        self.args = args
+        self.clean = clean
+        self.clobber = clobber
+        self.workdir = workdir
+        self.jobs = jobs
+        self.cachefile = cachefile
+        self.llvmsrcroot = llvmsrcroot
 
     def in_llvmsrc(self, path):
         return os.path.join(self.llvmsrcroot, path)
 
     def in_workdir(self, path):
         return os.path.join(self.workdir, path)
 
     @contextmanager
     def step(self, step_name, halt_on_fail=False):
-        with step(step_name,halt_on_fail=halt_on_fail) as s:
+        with step(step_name, halt_on_fail=halt_on_fail) as s:
             yield s
 
     def run_cmake(self, cmakeargs):
-        report_run_cmd(['cmake', *cmakeargs])
+        report_run_cmd(["cmake", *cmakeargs])
 
     def run_ninja(args, targets, ccache_stats=False, **kwargs):
-        cmd = ['ninja', *targets]
+        cmd = ["ninja", *targets]
         if args.jobs:
-            args .append(f'-j{args.jobs}')
+            args.append(f"-j{args.jobs}")
         if ccache_stats:
-                report_run_cmd(['ccache', '-z'])
+            report_run_cmd(["ccache", "-z"])
         report_run_cmd(cmd, **kwargs)
         if ccache_stats:
-                report_run_cmd(['ccache', '-sv'])
-
-    def checkout (self,giturl, sourcepath):
-            return checkout(giturl, sourcepath)
-
- 
-
-
+            report_run_cmd(["ccache", "-sv"])
+
+    def checkout(self, giturl, sourcepath):
+        return checkout(giturl, sourcepath)
 
 
 @contextmanager
-def run(scriptname, llvmsrcroot, parser=None ,clobberpaths=[], workerjobs=None):
-    for k,v in os.environ.items():
+def run(scriptname, llvmsrcroot, parser=None, clobberpaths=[], workerjobs=None):
+    for k, v in os.environ.items():
         print(f"{k}={v}")
 
-    os.environ['NINJA_STATUS'] = "[%p/%es :: %u->%r->%f (of %t)] "
-
-    jobs_default = first_true(  os.environ.get('BUILDBOT_JOBS') , workerjobs )
-
-
+    os.environ["NINJA_STATUS"] = "[%p/%es :: %u->%r->%f (of %t)] "
+
+    jobs_default = first_true(os.environ.get("BUILDBOT_JOBS"), workerjobs)
 
     stem = pathlib.Path(scriptname).stem
 
-
-    parser =  parser or argparse.ArgumentParser(allow_abbrev=True, description="Run the buildbot builder configuration; when executed without arguments, builds the llvm-project checkout this file is in, using cwd to write all files")
-    parser.add_argument('--jobs', '-j', default=jobs_default, help='Override the number of default jobs')
-    parser.add_argument('--clean', type=bool, default=os.environ.get('BUILDBOT_CLEAN') , help='Whether to delete source-, build-, and install-dirs (i.e. remove any files leftover from a previous run, if any) before running')
-    parser.add_argument('--clobber', type=bool, default=os.environ.get('BUILDBOT_CLOBBER') or os.environ.get('BUILDBOT_CLEAN_OBJ'), help='Whether to delete build- and install-dirs before running')
-    parser.add_argument('--workdir', default=f'{stem}.workdir', help="Use this dir as workdir")
-    parser.add_argument('--cachefile', default=relative_if_possible(pathlib.Path(scriptname).with_suffix('.cmake'), llvmsrcroot), help='CMake cache seed')
+    parser = parser or argparse.ArgumentParser(
+        allow_abbrev=True,
+        description="Run the buildbot builder configuration; when executed without arguments, builds the llvm-project checkout this file is in, using cwd to write all files",
+    )
+    parser.add_argument(
+        "--jobs", "-j", default=jobs_default, help="Override the number of default jobs"
+    )
+    parser.add_argument(
+        "--clean",
+        type=bool,
+        default=os.environ.get("BUILDBOT_CLEAN"),
+        help="Whether to delete source-, build-, and install-dirs (i.e. remove any files leftover from a previous run, if any) before running",
+    )
+    parser.add_argument(
+        "--clobber",
+        type=bool,
+        default=os.environ.get("BUILDBOT_CLOBBER")
+        or os.environ.get("BUILDBOT_CLEAN_OBJ"),
+        help="Whether to delete build- and install-dirs before running",
+    )
+    parser.add_argument(
+        "--workdir", default=f"{stem}.workdir", help="Use this dir as workdir"
+    )
+    parser.add_argument(
+        "--cachefile",
+        default=relative_if_possible(
+            pathlib.Path(scriptname).with_suffix(".cmake"), llvmsrcroot
+        ),
+        help="CMake cache seed",
+    )
     args = parser.parse_args()
 
-    print("cwd:",os.getcwd())
-
-    workdir =  args.workdir
+    print("cwd:", os.getcwd())
+
+    workdir = args.workdir
     clobber = args.clobber
     cachefile = os.path.join(llvmsrcroot, args.cachefile)
     oldcwd = os.getcwd()
 
-
-    prevcachepath = os.path.join(workdir, 'prevcache.cmake')
+    prevcachepath = os.path.join(workdir, "prevcache.cmake")
     if cachefile and os.path.exists(prevcachepath):
         # Force clobber if cache file has changed; a new cachefile does not override entries already present in CMakeCache.txt
-        if   not filecmp.cmp( os.path.join(llvmsrcroot, args.cachefile), prevcachepath, shallow=False):
+        if not filecmp.cmp(
+            os.path.join(llvmsrcroot, args.cachefile), prevcachepath, shallow=False
+        ):
             clobber = True
-        #shutil.copyfile(cachefile)
-
-    w = Worker(args, clean=args.clean , clobber=clobber, workdir=workdir, jobs=args.jobs, cachefile=cachefile, llvmsrcroot=llvmsrcroot)
-
-    #if workdir:
+        # shutil.copyfile(cachefile)
+
+    w = Worker(
+        args,
+        clean=args.clean,
+        clobber=clobber,
+        workdir=workdir,
+        jobs=args.jobs,
+        cachefile=cachefile,
+        llvmsrcroot=llvmsrcroot,
+    )
+
+    # if workdir:
     if args.clean:
-            with w.step(f'clean'):
-                clean_dir(workdir)
+        with w.step(f"clean"):
+            clean_dir(workdir)
     elif clobber:
-       with w.step(f'clobber'):
+        with w.step(f"clobber"):
             for d in clobberpaths:
-                    clean_dir(os.path.join(workdir, d))
+                clean_dir(os.path.join(workdir, d))
             os.path.unlink(prevcachepath)
 
     os.makedirs(workdir, exist_ok=True)
     os.chdir(workdir)
 
     # Remember used cachefile in case it changes
     if cachefile:
-        shutil.copy2(os.path.join(oldcwd,llvmsrcroot, args.cachefile), os.path.join(oldcwd, prevcachepath ))
+        shutil.copy2(
+            os.path.join(oldcwd, llvmsrcroot, args.cachefile),
+            os.path.join(oldcwd, prevcachepath),
+        )
 
     yield w
-    #else:
+    # else:
     #    with tempfile.TemporaryDirectory(prefix = stem) as tmpdir:
     #                os.chdir(tmpdir)
     #                yield Worker(args)
-
-
-
-
 
 
 @contextmanager
 def step(step_name, halt_on_fail=False):
     sys.stderr.flush()
     sys.stdout.flush()
-    report(f'@@@BUILD_STEP {step_name}@@@')
+    report(f"@@@BUILD_STEP {step_name}@@@")
     if halt_on_fail:
-        report('@@@HALT_ON_FAILURE@@@')
+        report("@@@HALT_ON_FAILURE@@@")
     try:
         yield
     except Exception as e:
         if isinstance(e, subprocess.CalledProcessError):
-            report(f'{e.cmd} exited with return code {e.returncode}.' )
-            report('@@@STEP_FAILURE@@@')
+            report(f"{e.cmd} exited with return code {e.returncode}.")
+            report("@@@STEP_FAILURE@@@")
         else:
             traceback.print_exc()
-            report('@@@STEP_EXCEPTION@@@')
+            report("@@@STEP_EXCEPTION@@@")
         if halt_on_fail:
             exit(1)
 
 
 def get_steps(makefile):
     try:
-        make_cmd = build_make_cmd(makefile, 'get-steps')
+        make_cmd = build_make_cmd(makefile, "get-steps")
         raw_steps = capture_cmd_stdout(make_cmd)
-        return raw_steps.decode('utf-8').split('\n')[:-1]
+        return raw_steps.decode("utf-8").split("\n")[:-1]
     except:
         return []
 
 
 def build_make_cmd(makefile, target, make_vars={}):
-    make_cmd = ['make', '-f', makefile]
+    make_cmd = ["make", "-f", makefile]
     if not target is None:
         make_cmd.append(target)
-    for k,v in make_vars.items():
+    for k, v in make_vars.items():
         make_cmd += ["{}={}".format(k, v)]
     return make_cmd
 
 
 def capture_cmd_stdout(cmd, **kwargs):
-    return subprocess.run(cmd, shell=False, check=True, stdout=subprocess.PIPE, **kwargs).stdout
+    return subprocess.run(
+        cmd, shell=False, check=True, stdout=subprocess.PIPE, **kwargs
+    ).stdout
 
 
 def run_command(cmd, **kwargs):
     report_run_cmd(cmd, **kwargs)
 
 
-
-
-
 def checkout(giturl, sourcepath):
     if not os.path.exists(sourcepath):
-        run_command(['git', 'clone', giturl, sourcepath])
+        run_command(["git", "clone", giturl, sourcepath])
 
     # Reset repository state no matter what there was before
-    run_command(['git', '-C', sourcepath, 'stash', '--all'])
-    run_command(['git', '-C', sourcepath, 'stash', 'clear'])
+    run_command(["git", "-C", sourcepath, "stash", "--all"])
+    run_command(["git", "-C", sourcepath, "stash", "clear"])
 
     # Fetch and checkout the newest
-    run_command(['git', '-C', sourcepath, 'fetch', 'origin'])
-    run_command(['git', '-C', sourcepath, 'checkout', 'origin/main', '--detach'])
-
-
-def clean_on_request(args, always=[],on_clobber=[],on_clean=[]):
+    run_command(["git", "-C", sourcepath, "fetch", "origin"])
+    run_command(["git", "-C", sourcepath, "checkout", "origin/main", "--detach"])
+
+
+def clean_on_request(args, always=[], on_clobber=[], on_clean=[]):
     cleanset = always
     if args.clobber or args.clean:
         # Clean implies clobber
         cleanset += on_clobber
-    if  args.clean:
+    if args.clean:
         cleanset += on_clean
 
     for d in cleanset:
-        with step(f'delete-{os.path.basename(d)}'):
-          clean_dir(d)
-
+        with step(f"delete-{os.path.basename(d)}"):
+            clean_dir(d)
--- polly/ci/polly-x86_64-linux-test-suite.py	2025-11-08 00:32:27.000000 +0000
+++ polly/ci/polly-x86_64-linux-test-suite.py	2025-11-08 00:35:46.073705 +0000
@@ -5,62 +5,74 @@
 import pathlib
 
 # Adapt to location in source tree
 llvmsrcroot = os.path.normpath(f"{__file__}/../../..")
 
-sys.path.insert(0, os.path.join(llvmsrcroot, '.ci/buildbot'))
+sys.path.insert(0, os.path.join(llvmsrcroot, ".ci/buildbot"))
 import worker
 
 
-
 llvmbuilddir = "llvm.build"
-llvminstalldir = 'llvm.install'
+llvminstalldir = "llvm.install"
 testsuitesrcdir = "testsuite.src"
 testsuitebuilddir = "testsuite.build"
 
-with worker.run(scriptname=__file__,llvmsrcroot=llvmsrcroot,clobberpaths = [llvmbuilddir,testsuitebuilddir, llvminstalldir]) as w:
-    with w.step('configure-llvm', halt_on_fail=True):
-        cmakeargs =[
-            '-S',  w.in_llvmsrc( 'llvm'),
-            '-B', llvmbuilddir,
-            '-G', 'Ninja',
-            '-C',  w.in_llvmsrc( w.cachefile),
-            f'-DCMAKE_INSTALL_PREFIX={llvminstalldir}'
+with worker.run(
+    scriptname=__file__,
+    llvmsrcroot=llvmsrcroot,
+    clobberpaths=[llvmbuilddir, testsuitebuilddir, llvminstalldir],
+) as w:
+    with w.step("configure-llvm", halt_on_fail=True):
+        cmakeargs = [
+            "-S",
+            w.in_llvmsrc("llvm"),
+            "-B",
+            llvmbuilddir,
+            "-G",
+            "Ninja",
+            "-C",
+            w.in_llvmsrc(w.cachefile),
+            f"-DCMAKE_INSTALL_PREFIX={llvminstalldir}",
         ]
         if w.jobs:
-            cmakeargs.append(      f'-DLLVM_LIT_ARGS=-sv;-j{w.jobs}')
+            cmakeargs.append(f"-DLLVM_LIT_ARGS=-sv;-j{w.jobs}")
         w.run_cmake(cmakeargs)
 
-    with w.step('build-llvm', halt_on_fail=True):
-        w.run_ninja(['-C', llvmbuilddir], ccache_stats=True)
+    with w.step("build-llvm", halt_on_fail=True):
+        w.run_ninja(["-C", llvmbuilddir], ccache_stats=True)
 
-    with w.step('check-polly'):
-        w.run_ninja(['-C', llvmbuilddir, 'check-polly'])
+    with w.step("check-polly"):
+        w.run_ninja(["-C", llvmbuilddir, "check-polly"])
 
-    with w.step('install-llvm', halt_on_fail=True):
-        w.run_ninja(['-C', llvmbuilddir, 'install'], ccache_stats=True)
+    with w.step("install-llvm", halt_on_fail=True):
+        w.run_ninja(["-C", llvmbuilddir, "install"], ccache_stats=True)
 
-    with w. step('checkout-testsuite', halt_on_fail=True):
-        w. checkout('https://github.com/llvm/llvm-test-suite',testsuitesrcdir)
+    with w.step("checkout-testsuite", halt_on_fail=True):
+        w.checkout("https://github.com/llvm/llvm-test-suite", testsuitesrcdir)
 
-    with w.step('configure-testsuite', halt_on_fail=True):
-        jobsarg =  f';-j{w.jobs}' if w.jobs else ''
-        w.run_cmake(['cmake',
-            '-S', testsuitesrcdir,
-            '-B', testsuitebuilddir,
-            '-G', 'Ninja',
-            '-DCMAKE_BUILD_TYPE=Release',
-            f'-DCMAKE_C_COMPILER={os.path.abspath(llvminstalldir)}/bin/clang',
-            f'-DCMAKE_CXX_COMPILER={os.path.abspath(llvminstalldir)}/bin/clang++',
-            f'-DTEST_SUITE_LIT={os.path.abspath(llvmbuilddir)}/bin/llvm-lit',
-            f'-DTEST_SUITE_LLVM_SIZE={os.path.abspath(llvmbuilddir)}/bin/llvm-size',
-            "-DTEST_SUITE_EXTRA_C_FLAGS=-Wno-unused-command-line-argument -mllvm -polly",
-            "-DTEST_SUITE_EXTRA_CXX_FLAGS=-Wno-unused-command-line-argument -mllvm -polly",
-            '-DLLVM_LIT_ARGS=-sv{jobsarg};-o;report.json'
-        ])
+    with w.step("configure-testsuite", halt_on_fail=True):
+        jobsarg = f";-j{w.jobs}" if w.jobs else ""
+        w.run_cmake(
+            [
+                "cmake",
+                "-S",
+                testsuitesrcdir,
+                "-B",
+                testsuitebuilddir,
+                "-G",
+                "Ninja",
+                "-DCMAKE_BUILD_TYPE=Release",
+                f"-DCMAKE_C_COMPILER={os.path.abspath(llvminstalldir)}/bin/clang",
+                f"-DCMAKE_CXX_COMPILER={os.path.abspath(llvminstalldir)}/bin/clang++",
+                f"-DTEST_SUITE_LIT={os.path.abspath(llvmbuilddir)}/bin/llvm-lit",
+                f"-DTEST_SUITE_LLVM_SIZE={os.path.abspath(llvmbuilddir)}/bin/llvm-size",
+                "-DTEST_SUITE_EXTRA_C_FLAGS=-Wno-unused-command-line-argument -mllvm -polly",
+                "-DTEST_SUITE_EXTRA_CXX_FLAGS=-Wno-unused-command-line-argument -mllvm -polly",
+                "-DLLVM_LIT_ARGS=-sv{jobsarg};-o;report.json",
+            ]
+        )
 
-    with w.step('build-testsuite', halt_on_fail=True):
-        w. run_ninja( ['-C', testsuitebuilddir], ccache_stats=True)
+    with w.step("build-testsuite", halt_on_fail=True):
+        w.run_ninja(["-C", testsuitebuilddir], ccache_stats=True)
 
-    with w.step('check-testsuite'):
-        w.run_ninja( ['-C', testsuitebuilddir, 'check'])
-
+    with w.step("check-testsuite"):
+        w.run_ninja(["-C", testsuitebuilddir, "check"])

@Meinersbur Meinersbur requested a review from jplehr November 6, 2025 17:21
@Meinersbur
Copy link
Member Author

Meinersbur commented Nov 6, 2025

@jplehr First draft about the proposed move of the build instruction next to the CMake cache. I know you had an RFC where to locate the script, but I forgot where the location was. Will update after first feedback.

A proof-of-concept buildbot master with worker using this change is running here: http://meinersbur.de:8011/#/builders/143. That particular builder has not run for a long time, it is expected to be failing. It is also useful to test a failing step.

@jplehr
Copy link
Contributor

jplehr commented Nov 7, 2025

@Meinersbur thank you for putting time/work into this!

I agree with the advantages you listed. We have found ourselves more than once in the situation that we needed to coordinate changes across repos, or where a configuration in llvm-zorg was not updated properly. Moving the test scripts in-tree solves this issue, as you mentioned, because the changes can be included into the original PR and reviewed together.
IMHO this is similar to how pre-merge scripts are handled, they also live in-tree.

I think I mostly discussed where to put files within the scope of the offload project. There we thought about putting the project-specific scripts into offload/ci. Which is probably a project-specific decision anyway. I also do not have a very strong opinion here.

IIRC that discussion did not consider common infra, so I appreciate that you include it here. I don't know if we should aim to add it to the existing .ci folder? While the things inside that directory are currently pre-merge only FWICT, it might be a good place as opposed to create another hidden top-level folder.

@jplehr jplehr requested a review from Kewen12 November 7, 2025 08:28
Rework common logic

No ccache stats for checks

indention fix

diagnostic print

Again print debugging

Print cwd

remove debg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants