209 lines · python
1#!/usr/bin/env python32 3# This script bumps the version of LLVM in *all* the different places where4# it needs to be defined. Which is quite a few.5 6import sys7import argparse8import packaging.version9from pathlib import Path10import re11from typing import Optional12 13 14class Processor:15 def __init__(self, args):16 self.args = args17 18 def process_line(self, line: str) -> str:19 raise NotImplementedError()20 21 def process_file(self, fpath: Path, version: packaging.version.Version) -> None:22 self.version = version23 self.major, self.minor, self.patch, self.suffix = (24 version.major,25 version.minor,26 version.micro,27 version.pre,28 )29 30 if self.args.rc:31 self.suffix = f"-rc{self.args.rc}"32 33 if self.args.git:34 self.suffix = "git"35 36 data = fpath.read_text()37 new_data = []38 39 for line in data.splitlines(True):40 nline = self.process_line(line)41 42 # Print the failing line just to inform the user.43 if nline != line:44 print(f"{fpath.name}: {line.strip()} -> {nline.strip()}")45 46 new_data.append(nline)47 48 fpath.write_text("".join(new_data), newline="\n")49 50 # Return a string from the version class51 # optionally include the suffix (-rcX)52 def version_str(53 self,54 version: Optional[packaging.version.Version] = None,55 include_suffix: bool = True,56 ) -> str:57 if version is None:58 version = self.version59 60 ver = f"{version.major}.{version.minor}.{version.micro}"61 if include_suffix and version.pre:62 ver += f"-{version.pre[0]}{version.pre[1]}"63 return ver64 65 66# llvm/CMakeLists.txt67class CMakeProcessor(Processor):68 def process_line(self, line: str) -> str:69 nline = line70 71 # LLVM_VERSION_SUFFIX should be set to -rcX or be blank if we are72 # building a final version.73 if "set(LLVM_VERSION_SUFFIX" in line:74 if self.suffix:75 nline = re.sub(76 r"set\(LLVM_VERSION_SUFFIX(.*)\)",77 f"set(LLVM_VERSION_SUFFIX {self.suffix})",78 line,79 )80 else:81 nline = re.sub(82 r"set\(LLVM_VERSION_SUFFIX(.*)\)", f"set(LLVM_VERSION_SUFFIX)", line83 )84 85 # Check the rest of the LLVM_VERSION_ lines.86 elif "set(LLVM_VERSION_" in line:87 for c, cver in (88 ("MAJOR", self.major),89 ("MINOR", self.minor),90 ("PATCH", self.patch),91 ):92 nline = re.sub(93 rf"set\(LLVM_VERSION_{c} (\d+)",94 rf"set(LLVM_VERSION_{c} {cver}",95 line,96 )97 if nline != line:98 break99 100 return nline101 102 103# GN build system104class GNIProcessor(Processor):105 def process_line(self, line: str) -> str:106 if "llvm_version_" in line:107 for c, cver in (108 ("major", self.major),109 ("minor", self.minor),110 ("patch", self.patch),111 ):112 nline = re.sub(113 rf"llvm_version_{c} = \d+", f"llvm_version_{c} = {cver}", line114 )115 if nline != line:116 return nline117 118 return line119 120 121# LIT python file, a simple tuple122class LitProcessor(Processor):123 def process_line(self, line: str) -> str:124 if "__versioninfo__" in line:125 nline = re.sub(126 rf"__versioninfo__(.*)\((\d+), (\d+), (\d+)\)",127 f"__versioninfo__\\1({self.major}, {self.minor}, {self.patch})",128 line,129 )130 return nline131 return line132 133 134# Handle libc++ config header135class LibCXXProcessor(Processor):136 def process_line(self, line: str) -> str:137 # match #define _LIBCPP_VERSION 160000 in a relaxed way138 match = re.match(r".*\s_LIBCPP_VERSION\s+(\d{6})$", line)139 if match:140 verstr = f"{str(self.major).zfill(2)}{str(self.minor).zfill(2)}{str(self.patch).zfill(2)}"141 142 nline = re.sub(143 rf"_LIBCPP_VERSION (\d+)",144 f"_LIBCPP_VERSION {verstr}",145 line,146 )147 return nline148 return line149 150 151if __name__ == "__main__":152 parser = argparse.ArgumentParser(153 usage="Call this script with a version and it will bump the version for you"154 )155 parser.add_argument("version", help="Version to bump to, e.g. 15.0.1", default=None)156 parser.add_argument("--rc", default=None, type=int, help="RC version")157 parser.add_argument("--git", action="store_true", help="Git version")158 parser.add_argument(159 "-s",160 "--source-root",161 default=None,162 help="LLVM source root (/path/llvm-project). Defaults to the llvm-project the script is located in.",163 )164 165 args = parser.parse_args()166 167 if args.rc and args.git:168 raise RuntimeError("Can't specify --git and --rc at the same time!")169 170 verstr = args.version171 172 # parse the version string.173 # note that -rc will end up as version.pre here174 # since it's a prerelease175 version = packaging.version.parse(verstr)176 177 # Find llvm-project root178 source_root = Path(__file__).resolve().parents[3]179 180 if args.source_root:181 source_root = Path(args.source_root).resolve()182 183 files_to_update = (184 # Main CMakeLists.185 (source_root / "cmake" / "Modules" / "LLVMVersion.cmake", CMakeProcessor(args)),186 # Lit configuration187 (188 "llvm/utils/lit/lit/__init__.py",189 LitProcessor(args),190 ),191 # mlgo-utils configuration192 (193 "llvm/utils/mlgo-utils/mlgo/__init__.py",194 LitProcessor(args),195 ),196 # GN build system197 (198 "llvm/utils/gn/secondary/llvm/version.gni",199 GNIProcessor(args),200 ),201 (202 "libcxx/include/__config",203 LibCXXProcessor(args),204 ),205 )206 207 for f, processor in files_to_update:208 processor.process_file(source_root / Path(f), version)209