#!/usr/bin/env python3 # This script bumps the version of LLVM in *all* the different places where # it needs to be defined. Which is quite a few. import sys import argparse import packaging.version from pathlib import Path import re from typing import Optional class Processor: def process_line(self, line: str) -> str: raise NotImplementedError() def process_file(self, fpath: Path, version: packaging.version.Version) -> None: self.version = version self.major, self.minor, self.patch, self.suffix = ( version.major, version.minor, version.micro, version.pre, ) data = fpath.read_text() new_data = [] for line in data.splitlines(True): nline = self.process_line(line) # Print the failing line just to inform the user. if nline != line: print(f"{fpath.name}: {line.strip()} -> {nline.strip()}") new_data.append(nline) fpath.write_text("".join(new_data), newline="\n") # Return a string from the version class # optionally include the suffix (-rcX) def version_str( self, version: Optional[packaging.version.Version] = None, include_suffix: bool = True, ) -> str: if version is None: version = self.version ver = f"{version.major}.{version.minor}.{version.micro}" if include_suffix and version.pre: ver += f"-{version.pre[0]}{version.pre[1]}" return ver # llvm/CMakeLists.txt class CMakeProcessor(Processor): def process_line(self, line: str) -> str: nline = line # LLVM_VERSION_SUFFIX should be set to -rcX or be blank if we are # building a final version. if "set(LLVM_VERSION_SUFFIX" in line: if self.suffix: nline = re.sub( r"set\(LLVM_VERSION_SUFFIX(.*)\)", f"set(LLVM_VERSION_SUFFIX -{self.suffix[0]}{self.suffix[1]})", line, ) else: nline = re.sub( r"set\(LLVM_VERSION_SUFFIX(.*)\)", f"set(LLVM_VERSION_SUFFIX)", line ) # Check the rest of the LLVM_VERSION_ lines. elif "set(LLVM_VERSION_" in line: for c, cver in ( ("MAJOR", self.major), ("MINOR", self.minor), ("PATCH", self.patch), ): nline = re.sub( rf"set\(LLVM_VERSION_{c} (\d+)", rf"set(LLVM_VERSION_{c} {cver}", line, ) if nline != line: break return nline # GN build system class GNIProcessor(Processor): def process_line(self, line: str) -> str: if "llvm_version_" in line: for c, cver in ( ("major", self.major), ("minor", self.minor), ("patch", self.patch), ): nline = re.sub( rf"llvm_version_{c} = \d+", f"llvm_version_{c} = {cver}", line ) if nline != line: return nline return line # LIT python file, a simple tuple class LitProcessor(Processor): def process_line(self, line: str) -> str: if "__versioninfo__" in line: nline = re.sub( rf"__versioninfo__(.*)\((\d+), (\d+), (\d+)\)", f"__versioninfo__\\1({self.major}, {self.minor}, {self.patch})", line, ) return nline return line # Handle libc++ config header class LibCXXProcessor(Processor): def process_line(self, line: str) -> str: # match #define _LIBCPP_VERSION 160000 in a relaxed way match = re.match(r".*\s_LIBCPP_VERSION\s+(\d{6})$", line) if match: verstr = f"{str(self.major).zfill(2)}{str(self.minor).zfill(2)}{str(self.patch).zfill(2)}" nline = re.sub( rf"_LIBCPP_VERSION (\d+)", f"_LIBCPP_VERSION {verstr}", line, ) return nline return line if __name__ == "__main__": parser = argparse.ArgumentParser( usage="Call this script with a version and it will bump the version for you" ) parser.add_argument("version", help="Version to bump to, e.g. 15.0.1", default=None) parser.add_argument("--rc", default=None, type=int, help="RC version") parser.add_argument( "-s", "--source-root", default=None, help="LLVM source root (/path/llvm-project). Defaults to the llvm-project the script is located in.", ) args = parser.parse_args() verstr = args.version if args.rc: verstr += f"-rc{args.rc}" # parse the version string with distutils. # note that -rc will end up as version.pre here # since it's a prerelease version = packaging.version.parse(verstr) # Find llvm-project root source_root = Path(__file__).resolve().parents[3] if args.source_root: source_root = Path(args.source_root).resolve() files_to_update = ( # Main CMakeLists. (source_root / "llvm" / "CMakeLists.txt", CMakeProcessor()), # Lit configuration ( "llvm/utils/lit/lit/__init__.py", LitProcessor(), ), # GN build system ( "llvm/utils/gn/secondary/llvm/version.gni", GNIProcessor(), ), ( "libcxx/include/__config", LibCXXProcessor(), ), ) for f, processor in files_to_update: processor.process_file(source_root / Path(f), version)