| #!/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 __init__(self, args): | |
| self.args = args | |
| 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, | |
| ) | |
| if self.args.rc: | |
| self.suffix = f"-rc{self.args.rc}" | |
| if self.args.git: | |
| self.suffix = "git" | |
| 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})", | |
| 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("--git", action="store_true", help="Git 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() | |
| if args.rc and args.git: | |
| raise RuntimeError("Can't specify --git and --rc at the same time!") | |
| verstr = args.version | |
| # parse the version string. | |
| # 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 / "cmake" / "Modules" / "LLVMVersion.cmake", CMakeProcessor(args)), | |
| # Lit configuration | |
| ( | |
| "llvm/utils/lit/lit/__init__.py", | |
| LitProcessor(args), | |
| ), | |
| # IR2Vec Python Bindings configuration | |
| ( | |
| "llvm/tools/llvm-ir2vec/Bindings/python/ir2vec/__init__.py", | |
| LitProcessor(args), | |
| ), | |
| # mlgo-utils configuration | |
| ( | |
| "llvm/utils/mlgo-utils/mlgo/__init__.py", | |
| LitProcessor(args), | |
| ), | |
| # GN build system | |
| ( | |
| "llvm/utils/gn/secondary/llvm/version.gni", | |
| GNIProcessor(args), | |
| ), | |
| ( | |
| "libcxx/include/__config", | |
| LibCXXProcessor(args), | |
| ), | |
| ) | |
| for f, processor in files_to_update: | |
| processor.process_file(source_root / Path(f), version) |