Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 1 | from buildbot.steps.shell import ShellCommand |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 2 | from buildbot.steps.slave import RemoveDirectory |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 3 | from buildbot.process.properties import WithProperties |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 4 | |
| 5 | from zorg.buildbot.commands.CmakeCommand import CmakeCommand |
| 6 | from zorg.buildbot.commands.NinjaCommand import NinjaCommand |
| 7 | from zorg.buildbot.conditions.FileConditions import FileDoesNotExist |
| 8 | from zorg.buildbot.process.factory import LLVMBuildFactory |
| 9 | |
| 10 | def _addSteps4SystemCompiler( |
| 11 | f, |
| 12 | stage_idx = 0, |
| 13 | clean = True, |
| 14 | jobs = None, |
| 15 | extra_configure_args = None, |
| 16 | env = None): |
| 17 | |
| 18 | # Index is zero-based, so we want to use a human friendly number instead. |
| 19 | stage_num = stage_idx + 1 |
| 20 | |
| 21 | # Directories to use on this stage. |
| 22 | obj_dir = f.stage_objdirs[stage_idx] |
| 23 | src_dir = LLVMBuildFactory.pathRelativeToBuild(f.llvm_srcdir, obj_dir) |
| 24 | install_dir = LLVMBuildFactory.pathRelativeToBuild(f.stage_installdirs[stage_idx], obj_dir) |
| 25 | |
| 26 | # This stage could use incremental build. |
| 27 | # Clean stage1, only if requested. |
| 28 | f.addStep(RemoveDirectory(name='clean-%s-dir' % obj_dir, |
| 29 | dir=obj_dir, |
| 30 | haltOnFailure=False, |
| 31 | flunkOnFailure=False, |
| 32 | doStepIf=clean |
| 33 | )) |
| 34 | f.addStep(RemoveDirectory(name='clean-%s-dir' % f.stage_installdirs[stage_idx], |
| 35 | dir=f.stage_installdirs[stage_idx], |
| 36 | haltOnFailure=False, |
| 37 | flunkOnFailure=False, |
| 38 | doStepIf=clean |
| 39 | )) |
| 40 | |
| 41 | # Reconcile the cmake options for this stage. |
| 42 | |
| 43 | # Make a local copy of the configure args, as we are going to modify that. |
| 44 | if extra_configure_args: |
| 45 | cmake_args = extra_configure_args[:] |
| 46 | else: |
| 47 | cmake_args = list() |
| 48 | |
| 49 | # Set proper defaults. |
| 50 | CmakeCommand.applyDefaultOptions(cmake_args, [ |
| 51 | ('-DCMAKE_BUILD_TYPE=', 'Release'), |
| 52 | ('-DCLANG_BUILD_EXAMPLES=', 'OFF'), |
| 53 | ('-DLLVM_BUILD_TESTS=', 'ON'), |
| 54 | ('-DLLVM_ENABLE_ASSERTIONS=', 'OFF'), |
| 55 | ('-DLLVM_OPTIMIZED_TABLEGEN=', 'ON'), |
| 56 | # Do not expect warning free build by the system toolchain. |
| 57 | ('-DLLVM_ENABLE_WERROR=', 'OFF'), |
| 58 | ('-DCMAKE_COLOR_MAKEFILE=', 'OFF'), |
| 59 | ]) |
| 60 | |
| 61 | # Some options are required for this stage no matter what. |
| 62 | CmakeCommand.applyRequiredOptions(cmake_args, [ |
| 63 | ('-G', 'Unix Makefiles'), |
| 64 | ('-DCMAKE_INSTALL_PREFIX=', install_dir), |
| 65 | ]) |
| 66 | |
| 67 | # Note: On this stage we do not care of warnings, as we build with |
| 68 | # a system toolchain and cannot control the environment. |
| 69 | # Warnings are likely, and we ignore them. |
| 70 | |
| 71 | # Create configuration files with cmake |
| 72 | f.addStep(CmakeCommand(name="cmake-configure-stage%s" % stage_num, |
| 73 | description=["stage%s cmake configure" % stage_num], |
| 74 | haltOnFailure=True, |
| 75 | flunkOnWarnings=False, |
| 76 | options=cmake_args, |
| 77 | path=src_dir, |
| 78 | env=env, |
| 79 | workdir=obj_dir, |
| 80 | doStepIf=FileDoesNotExist("CMakeCache.txt"))) |
| 81 | |
| 82 | # Build clang by the system compiler |
| 83 | f.addStep(ShellCommand(name="build-stage%s-compiler"% stage_num, |
| 84 | command=['make', WithProperties("-j%s" % jobs), "-k"], |
| 85 | haltOnFailure=True, |
| 86 | flunkOnWarnings=False, |
| 87 | description=["build stage%s compiler" % stage_num], |
| 88 | env=env, |
| 89 | workdir=obj_dir)) |
| 90 | |
| 91 | # Test stage1 compiler |
| 92 | f.addStep(ShellCommand(name="test-stage%s-compiler"% stage_num, |
| 93 | command=["make", WithProperties("-j%s" % jobs), "check-all"], # or "check-llvm", "check-clang" |
| 94 | haltOnFailure=True, |
| 95 | flunkOnWarnings=False, |
| 96 | description=["test stage%s compiler" % stage_num], |
| 97 | env=env, |
| 98 | workdir=obj_dir)) |
| 99 | |
| 100 | # Install stage1 compiler |
| 101 | f.addStep(ShellCommand(name="install-stage%s-compiler"% stage_num, |
| 102 | command=["make", WithProperties("-j%s" % jobs), "install"], |
| 103 | haltOnFailure=True, |
| 104 | flunkOnWarnings=False, |
| 105 | description=["install stage%s compiler" % stage_num], |
| 106 | env=env, |
| 107 | workdir=obj_dir)) |
| 108 | |
| 109 | |
| 110 | def _addSteps4StagedCompiler( |
| 111 | f, |
| 112 | stage_idx = 1, |
| 113 | use_stage_idx = -1, |
| 114 | withLTOSupport = False, |
| 115 | jobs = None, |
| 116 | extra_configure_args = None, |
| 117 | env = None): |
| 118 | |
| 119 | if use_stage_idx < 0: |
| 120 | use_stage_idx = stage_idx - 1 |
| 121 | |
| 122 | # Index is zero-based, so we want to use a human friendly number instead. |
| 123 | stage_num = stage_idx + 1 |
| 124 | |
| 125 | # Directories to use on this stage. |
| 126 | obj_dir = f.stage_objdirs[stage_idx] |
| 127 | src_dir = LLVMBuildFactory.pathRelativeToBuild(f.llvm_srcdir, obj_dir) |
| 128 | install_dir = LLVMBuildFactory.pathRelativeToBuild(f.stage_installdirs[stage_idx], obj_dir) |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 129 | staged_install = f.stage_installdirs[use_stage_idx] |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 130 | |
| 131 | # Always do a clean build for the staged compiler. |
| 132 | f.addStep(RemoveDirectory(name='clean-%s-dir' % obj_dir, |
| 133 | dir=obj_dir, |
| 134 | haltOnFailure=False, |
| 135 | flunkOnFailure=False, |
| 136 | )) |
| 137 | |
| 138 | f.addStep(RemoveDirectory(name='clean-%s-dir' % f.stage_installdirs[stage_idx], |
| 139 | dir=f.stage_installdirs[stage_idx], |
| 140 | haltOnFailure=False, |
| 141 | flunkOnFailure=False, |
| 142 | )) |
| 143 | |
| 144 | # Reconcile the cmake options for this stage. |
| 145 | |
| 146 | # Make a local copy of the configure args, as we are going to modify that. |
| 147 | if extra_configure_args: |
| 148 | cmake_args = extra_configure_args[:] |
| 149 | else: |
| 150 | cmake_args = list() |
| 151 | |
| 152 | # Set proper defaults. |
| 153 | CmakeCommand.applyDefaultOptions(cmake_args, [ |
| 154 | ('-DCMAKE_BUILD_TYPE=', 'Release'), |
| 155 | ('-DCLANG_BUILD_EXAMPLES=', 'OFF'), |
| 156 | ('-DLLVM_BUILD_TESTS=', 'ON'), |
| 157 | ('-DLLVM_ENABLE_ASSERTIONS=', 'ON'), |
| 158 | ('-DLLVM_OPTIMIZED_TABLEGEN=', 'ON'), |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 159 | ]) |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 160 | if withLTOSupport: |
| 161 | CmakeCommand.applyDefaultOptions(cmake_args, [ |
| 162 | # LTO Plugin dependency: |
| 163 | ('-DLLVM_BINUTILS_INCDIR=', '/opt/binutils/include'), |
| 164 | ]) |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 165 | |
| 166 | # Some options are required for this stage no matter what. |
| 167 | CmakeCommand.applyRequiredOptions(cmake_args, [ |
| 168 | ('-G', 'Ninja'), |
| 169 | ('-DCMAKE_INSTALL_PREFIX=', install_dir), |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 170 | ]) |
| 171 | |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 172 | cmake_args.append( |
| 173 | WithProperties( |
| 174 | "-DCMAKE_CXX_COMPILER=%(workdir)s/" + staged_install + "/bin/clang++" |
| 175 | )) |
| 176 | cmake_args.append( |
| 177 | WithProperties( |
| 178 | "-DCMAKE_C_COMPILER=%(workdir)s/" + staged_install + "/bin/clang" |
| 179 | )) |
| 180 | |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 181 | # Create configuration files with cmake |
| 182 | f.addStep(CmakeCommand(name="cmake-configure-stage%s" % stage_num, |
| 183 | description=["stage%s cmake configure" % stage_num], |
| 184 | haltOnFailure=True, |
| 185 | options=cmake_args, |
| 186 | path=src_dir, |
| 187 | env=env, |
| 188 | workdir=obj_dir, |
| 189 | doStepIf=FileDoesNotExist("CMakeCache.txt") |
| 190 | )) |
| 191 | if withLTOSupport: |
| 192 | # Build LTO plugin if requested. |
| 193 | f.addStep(NinjaCommand(name="build-stage%s-LLVMgold.so" % stage_num, |
| 194 | targets=['lib/LLVMgold.so'], |
| 195 | haltOnFailure=True, |
| 196 | description=["stage%s build LLVMgold.so" % stage_num], |
| 197 | env=env, |
| 198 | workdir=obj_dir, |
| 199 | )) |
| 200 | |
| 201 | # Build clang by the staged compiler |
| 202 | f.addStep(NinjaCommand(name="build-stage%s-compiler" % stage_num, |
| 203 | haltOnFailure=True, |
| 204 | description=["build stage%s compiler" % stage_num], |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 205 | timeout=10800, # LTO could take time. |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 206 | env=env, |
| 207 | workdir=obj_dir, |
| 208 | )) |
| 209 | |
| 210 | # Test just built compiler |
| 211 | f.addStep(NinjaCommand(name="test-stage%s-compiler"% stage_num, |
| 212 | targets=["check-all"], |
| 213 | haltOnFailure=True, |
| 214 | description=["test stage%s compiler" % stage_num], |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 215 | timeout=10800, # LTO could take time. |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 216 | env=env, |
| 217 | workdir=obj_dir, |
| 218 | )) |
| 219 | |
| 220 | # Install just built compiler |
| 221 | f.addStep(NinjaCommand(name="install-stage%s-compiler"% stage_num, |
| 222 | targets=["install"], |
| 223 | haltOnFailure=True, |
| 224 | description=["install stage%s compiler" % stage_num], |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 225 | timeout=10800, # LTO could take time. |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 226 | env=env, |
| 227 | workdir=obj_dir, |
| 228 | )) |
| 229 | |
| 230 | |
| 231 | def getClangWithLTOBuildFactory( |
Galina Kistanova | 9a7a1b6 | 2016-10-16 05:02:20 +0000 | [diff] [blame] | 232 | depends_on_projects = None, |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 233 | clean = False, |
| 234 | jobs = None, |
| 235 | extra_configure_args = None, |
| 236 | compare_last_2_stages = True, |
Galina Kistanova | 83d12a9 | 2016-10-13 19:32:23 +0000 | [diff] [blame] | 237 | lto = None, # The string gets passed to -flto flag as is. Like -flto=thin. |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 238 | env = None): |
| 239 | |
| 240 | # Set defaults |
Galina Kistanova | 9a7a1b6 | 2016-10-16 05:02:20 +0000 | [diff] [blame] | 241 | if depends_on_projects: |
| 242 | depends_on_projects = list(depends_on_projects) |
| 243 | else: |
| 244 | # By default we link with LLD. |
| 245 | depends_on_projects = ['llvm', 'clang', 'lld'] |
| 246 | |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 247 | if jobs is None: |
| 248 | jobs = "%(jobs)s" |
| 249 | |
| 250 | if extra_configure_args is None: |
| 251 | extra_configure_args = [] |
Galina Kistanova | 17d6242 | 2016-10-20 18:41:02 +0000 | [diff] [blame^] | 252 | else: |
| 253 | extra_configure_args = list(extra_configure_args) |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 254 | |
| 255 | # Make sure CMAKE_INSTALL_PREFIX and -G are not specified |
| 256 | # in the extra_configure_args. We set them internally as needed. |
| 257 | # TODO: assert extra_configure_args. |
| 258 | install_prefix_specified = any(a.startswith('-DCMAKE_INSTALL_PREFIX=') for a in extra_configure_args) |
| 259 | assert True, "Please do not explicitly specify the install prefix for multi-stage build." |
| 260 | |
| 261 | # Prepare environmental variables. Set here all env we want everywhere. |
| 262 | merged_env = { |
| 263 | 'TERM' : 'dumb' # Be cautious and disable color output from all tools. |
| 264 | } |
| 265 | if env is not None: |
| 266 | # Overwrite pre-set items with the given ones, so user can set anything. |
| 267 | merged_env.update(env) |
| 268 | |
| 269 | f = LLVMBuildFactory( |
Galina Kistanova | 9a7a1b6 | 2016-10-16 05:02:20 +0000 | [diff] [blame] | 270 | depends_on_projects=depends_on_projects, |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 271 | llvm_srcdir="llvm.src", |
| 272 | stage_objdirs=[ |
| 273 | "build/stage1", |
| 274 | "build/stage2", |
| 275 | "build/stage3", |
| 276 | "build/stage4", |
| 277 | ], |
| 278 | stage_installdirs=[ |
| 279 | "install/stage1", |
| 280 | "install/stage2", |
| 281 | "install/stage3", |
| 282 | "install/stage4", |
| 283 | ], |
| 284 | staged_compiler_idx = 1) |
| 285 | |
| 286 | cleanBuildRequested = lambda step: step.build.getProperty("clean") or clean |
| 287 | |
| 288 | # Do a clean checkout if requested. |
| 289 | f.addStep(RemoveDirectory(name='clean-src-dir', |
| 290 | dir=f.llvm_srcdir, |
| 291 | haltOnFailure=False, |
| 292 | flunkOnFailure=False, |
| 293 | doStepIf=cleanBuildRequested, |
| 294 | )) |
| 295 | |
| 296 | # Get the source code. |
| 297 | f.addSVNSteps() |
| 298 | |
| 299 | # Build with the system compiler first |
| 300 | _addSteps4SystemCompiler(f, |
| 301 | stage_idx=0, |
| 302 | clean=cleanBuildRequested, |
| 303 | jobs=jobs, |
| 304 | extra_configure_args=extra_configure_args, |
| 305 | env=merged_env) |
| 306 | |
| 307 | # Then build the compiler we would use for the bootstrap. |
| 308 | _addSteps4StagedCompiler(f, |
| 309 | stage_idx=1, |
| 310 | withLTOSupport=True, |
| 311 | jobs=jobs, |
| 312 | extra_configure_args=extra_configure_args, |
| 313 | env=merged_env) |
| 314 | |
| 315 | # Build all the remaining stages with exactly the same configuration. |
| 316 | |
Galina Kistanova | 17d6242 | 2016-10-20 18:41:02 +0000 | [diff] [blame^] | 317 | CmakeCommand.applyRequiredOptions(extra_configure_args, [ |
| 318 | ('-DLLVM_ENABLE_LTO=', lto.upper() or 'ON'), |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 319 | ]) |
| 320 | |
Galina Kistanova | 17d6242 | 2016-10-20 18:41:02 +0000 | [diff] [blame^] | 321 | # If we build LLD, we would link with LLD. |
| 322 | # Otherwise we link with the system linker. |
| 323 | if 'lld' in depends_on_projects: |
| 324 | CmakeCommand.applyRequiredOptions(extra_configure_args, [ |
| 325 | ('-DLLVM_ENABLE_LLD=', 'ON'), |
| 326 | ]) |
| 327 | |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 328 | # The rest are test stages, which depend on the staged compiler we are ultimately after. |
| 329 | s = f.staged_compiler_idx + 1 |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 330 | staged_install = f.stage_installdirs[f.staged_compiler_idx] |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 331 | for i in range(s, len(f.stage_objdirs[s:]) + s): |
| 332 | configure_args = extra_configure_args[:] |
| 333 | |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 334 | configure_args.append( |
| 335 | WithProperties( |
| 336 | "-DCMAKE_AR=%(workdir)s/" + staged_install + "/bin/llvm-ar" |
| 337 | )) |
| 338 | configure_args.append( |
| 339 | WithProperties( |
| 340 | "-DCMAKE_RANLIB=%(workdir)s/" + staged_install + "/bin/llvm-ranlib" |
| 341 | )) |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 342 | |
| 343 | _addSteps4StagedCompiler(f, |
| 344 | stage_idx=i, |
| 345 | use_stage_idx=f.staged_compiler_idx, |
| 346 | jobs=jobs, |
| 347 | extra_configure_args=configure_args, |
| 348 | env=merged_env) |
| 349 | |
| 350 | if compare_last_2_stages: |
| 351 | # Compare the compilers built on the last 2 stages if requested. |
| 352 | diff_command = [ |
| 353 | "diff", |
| 354 | "-q", |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame] | 355 | f.stage_installdirs[-2] + "/bin/clang", |
| 356 | f.stage_installdirs[-1] + "/bin/clang", |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 357 | ] |
| 358 | f.addStep( |
| 359 | ShellCommand( |
| 360 | name="compare-compilers", |
| 361 | description=[ |
| 362 | "compare", |
| 363 | "stage%d" % (len(f.stage_installdirs)-1), |
| 364 | "and", |
| 365 | "stage%d" % len(f.stage_installdirs), |
| 366 | "compilers", |
| 367 | ], |
| 368 | haltOnFailure=True, |
| 369 | command=WithProperties(" ".join(diff_command)), |
| 370 | workdir=".", |
| 371 | env=merged_env |
| 372 | ) |
| 373 | ) |
| 374 | |
| 375 | return f |