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( |
| 232 | clean = False, |
| 233 | jobs = None, |
| 234 | extra_configure_args = None, |
| 235 | compare_last_2_stages = True, |
| 236 | env = None): |
| 237 | |
| 238 | # Set defaults |
| 239 | if jobs is None: |
| 240 | jobs = "%(jobs)s" |
| 241 | |
| 242 | if extra_configure_args is None: |
| 243 | extra_configure_args = [] |
| 244 | |
| 245 | # Make sure CMAKE_INSTALL_PREFIX and -G are not specified |
| 246 | # in the extra_configure_args. We set them internally as needed. |
| 247 | # TODO: assert extra_configure_args. |
| 248 | install_prefix_specified = any(a.startswith('-DCMAKE_INSTALL_PREFIX=') for a in extra_configure_args) |
| 249 | assert True, "Please do not explicitly specify the install prefix for multi-stage build." |
| 250 | |
| 251 | # Prepare environmental variables. Set here all env we want everywhere. |
| 252 | merged_env = { |
| 253 | 'TERM' : 'dumb' # Be cautious and disable color output from all tools. |
| 254 | } |
| 255 | if env is not None: |
| 256 | # Overwrite pre-set items with the given ones, so user can set anything. |
| 257 | merged_env.update(env) |
| 258 | |
| 259 | f = LLVMBuildFactory( |
| 260 | depends_on_projects=['llvm', 'clang', 'lld'], |
| 261 | llvm_srcdir="llvm.src", |
| 262 | stage_objdirs=[ |
| 263 | "build/stage1", |
| 264 | "build/stage2", |
| 265 | "build/stage3", |
| 266 | "build/stage4", |
| 267 | ], |
| 268 | stage_installdirs=[ |
| 269 | "install/stage1", |
| 270 | "install/stage2", |
| 271 | "install/stage3", |
| 272 | "install/stage4", |
| 273 | ], |
| 274 | staged_compiler_idx = 1) |
| 275 | |
| 276 | cleanBuildRequested = lambda step: step.build.getProperty("clean") or clean |
| 277 | |
| 278 | # Do a clean checkout if requested. |
| 279 | f.addStep(RemoveDirectory(name='clean-src-dir', |
| 280 | dir=f.llvm_srcdir, |
| 281 | haltOnFailure=False, |
| 282 | flunkOnFailure=False, |
| 283 | doStepIf=cleanBuildRequested, |
| 284 | )) |
| 285 | |
| 286 | # Get the source code. |
| 287 | f.addSVNSteps() |
| 288 | |
| 289 | # Build with the system compiler first |
| 290 | _addSteps4SystemCompiler(f, |
| 291 | stage_idx=0, |
| 292 | clean=cleanBuildRequested, |
| 293 | jobs=jobs, |
| 294 | extra_configure_args=extra_configure_args, |
| 295 | env=merged_env) |
| 296 | |
| 297 | # Then build the compiler we would use for the bootstrap. |
| 298 | _addSteps4StagedCompiler(f, |
| 299 | stage_idx=1, |
| 300 | withLTOSupport=True, |
| 301 | jobs=jobs, |
| 302 | extra_configure_args=extra_configure_args, |
| 303 | env=merged_env) |
| 304 | |
| 305 | # Build all the remaining stages with exactly the same configuration. |
| 306 | |
| 307 | # Set proper compile and link flags. |
| 308 | CmakeCommand.appendFlags(extra_configure_args, [ |
| 309 | ('-DCMAKE_CXX_FLAGS=', ['-flto']), |
| 310 | ('-DCMAKE_EXE_LINKER_FLAGS=', ['-flto', '-fuse-ld=lld']), |
| 311 | ('-DCMAKE_MODULE_LINKER_FLAGS=', ['-flto', '-fuse-ld=lld']), |
| 312 | ('-DCMAKE_SHARED_LINKER_FLAGS=', ['-flto', '-fuse-ld=lld']), |
| 313 | ]) |
| 314 | |
| 315 | # The rest are test stages, which depend on the staged compiler we are ultimately after. |
| 316 | s = f.staged_compiler_idx + 1 |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame^] | 317 | staged_install = f.stage_installdirs[f.staged_compiler_idx] |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 318 | for i in range(s, len(f.stage_objdirs[s:]) + s): |
| 319 | configure_args = extra_configure_args[:] |
| 320 | |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame^] | 321 | configure_args.append( |
| 322 | WithProperties( |
| 323 | "-DCMAKE_AR=%(workdir)s/" + staged_install + "/bin/llvm-ar" |
| 324 | )) |
| 325 | configure_args.append( |
| 326 | WithProperties( |
| 327 | "-DCMAKE_RANLIB=%(workdir)s/" + staged_install + "/bin/llvm-ranlib" |
| 328 | )) |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 329 | |
| 330 | _addSteps4StagedCompiler(f, |
| 331 | stage_idx=i, |
| 332 | use_stage_idx=f.staged_compiler_idx, |
| 333 | jobs=jobs, |
| 334 | extra_configure_args=configure_args, |
| 335 | env=merged_env) |
| 336 | |
| 337 | if compare_last_2_stages: |
| 338 | # Compare the compilers built on the last 2 stages if requested. |
| 339 | diff_command = [ |
| 340 | "diff", |
| 341 | "-q", |
Galina Kistanova | b3ff275 | 2016-08-15 19:35:56 +0000 | [diff] [blame^] | 342 | f.stage_installdirs[-2] + "/bin/clang", |
| 343 | f.stage_installdirs[-1] + "/bin/clang", |
Galina Kistanova | 1e2edfc | 2016-08-08 22:08:21 +0000 | [diff] [blame] | 344 | ] |
| 345 | f.addStep( |
| 346 | ShellCommand( |
| 347 | name="compare-compilers", |
| 348 | description=[ |
| 349 | "compare", |
| 350 | "stage%d" % (len(f.stage_installdirs)-1), |
| 351 | "and", |
| 352 | "stage%d" % len(f.stage_installdirs), |
| 353 | "compilers", |
| 354 | ], |
| 355 | haltOnFailure=True, |
| 356 | command=WithProperties(" ".join(diff_command)), |
| 357 | workdir=".", |
| 358 | env=merged_env |
| 359 | ) |
| 360 | ) |
| 361 | |
| 362 | return f |