Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 1 | """This is the main tool for handling llvm builds, bisects etc.""" |
| 2 | |
| 3 | import os |
Diana Picus | adb07c4 | 2017-11-22 16:12:57 +0100 | [diff] [blame] | 4 | from sys import argv |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 5 | from sys import exit |
| 6 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 7 | from modules.llvm import LLVMBuildConfig |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 8 | from modules.llvm import LLVMSubproject |
| 9 | from modules.llvm import LLVMSourceConfig |
Diana Picus | b368cb6 | 2018-01-23 16:41:59 +0100 | [diff] [blame] | 10 | from modules.llvm import run_test_suite |
Diana Picus | f73abbf | 2018-01-26 07:06:20 +0100 | [diff] [blame] | 11 | from modules.llvm import setup_test_suite |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 12 | from modules.utils import CommandPrinter |
| 13 | from modules.utils import CommandRunner |
Diana Picus | 5ad5542 | 2017-12-14 17:57:10 +0100 | [diff] [blame] | 14 | from modules.utils import get_remote_branch |
| 15 | from modules.utils import push_branch |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 16 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 17 | from linaropy.cd import cd |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 18 | from linaropy.git.clone import Clone |
| 19 | from linaropy.proj import Proj |
| 20 | |
| 21 | from argparse import Action, ArgumentParser, RawTextHelpFormatter |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 22 | from functools import partial |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 23 | |
| 24 | |
| 25 | def die(message, config_to_dump=None): |
| 26 | """Print an error message and exit.""" |
Diana Picus | b430760 | 2017-04-05 19:48:39 +0200 | [diff] [blame] | 27 | print(message) |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 28 | |
| 29 | if config_to_dump is not None: |
| 30 | dump_config(config_to_dump) |
| 31 | |
| 32 | exit(1) |
| 33 | |
Diana Picus | 3d1a301 | 2017-03-14 17:38:32 +0100 | [diff] [blame] | 34 | |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 35 | def dump_config(config): |
| 36 | """Dump the list of projects that are enabled in the given config.""" |
| 37 | |
Diana Picus | b430760 | 2017-04-05 19:48:39 +0200 | [diff] [blame] | 38 | print("Projects linked:") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 39 | enabled = config.get_enabled_subprojects() |
| 40 | if not enabled: |
Diana Picus | b430760 | 2017-04-05 19:48:39 +0200 | [diff] [blame] | 41 | print("none") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 42 | else: |
| 43 | for subproj in sorted(enabled): |
Diana Picus | b430760 | 2017-04-05 19:48:39 +0200 | [diff] [blame] | 44 | print(" + {}".format(subproj)) |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 45 | |
| 46 | |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 47 | def subproj_to_repo_map(subprojs, proj, reposRoot, dry=False): |
| 48 | """Get a dictionary mapping each subproject in subprojs to its repo.""" |
| 49 | subprojsToRepos = {} |
| 50 | repo = None |
| 51 | for subproj in subprojs: |
| 52 | if not dry: |
| 53 | repo = Clone(proj, os.path.join(reposRoot, subproj)) |
| 54 | subprojsToRepos[subproj] = repo |
| 55 | |
| 56 | return subprojsToRepos |
| 57 | |
| 58 | |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 59 | def projects(args): |
| 60 | """Add/remove subprojects based on the values in args.""" |
| 61 | |
| 62 | proj = Proj() |
Diana Picus | 3d1a301 | 2017-03-14 17:38:32 +0100 | [diff] [blame] | 63 | |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 64 | llvm_worktree_root = args.sources |
Diana Picus | 81089db | 2017-05-05 22:26:49 +0200 | [diff] [blame] | 65 | llvm_repos_root = args.repos |
Diana Picus | b1dbcba | 2018-02-07 01:33:17 +0100 | [diff] [blame] | 66 | config = LLVMSourceConfig(proj, llvm_worktree_root, dry=False) |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 67 | |
| 68 | if not args.add and not args.remove: |
| 69 | # Nothing to change, just print the current configuration |
| 70 | dump_config(config) |
| 71 | exit(0) |
| 72 | |
| 73 | to_add = {} |
| 74 | if args.add: |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 75 | to_add = subproj_to_repo_map(args.add, proj, llvm_repos_root) |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 76 | |
| 77 | try: |
| 78 | config.update(to_add, args.remove) |
| 79 | except (EnvironmentError, ValueError) as exc: |
| 80 | die("Failed to update subprojects because:\n{}".format(str(exc))) |
| 81 | |
| 82 | dump_config(config) |
| 83 | |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 84 | |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 85 | def push_current_branch(args): |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 86 | """Push current branch to origin.""" |
| 87 | |
| 88 | proj = Proj() |
| 89 | |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 90 | llvm_worktree_root = args.sources |
Diana Picus | b1dbcba | 2018-02-07 01:33:17 +0100 | [diff] [blame] | 91 | config = LLVMSourceConfig(proj, llvm_worktree_root, dry=False) |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 92 | |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 93 | llvm_worktree = Clone(proj, llvm_worktree_root) |
| 94 | local_branch = llvm_worktree.getbranch() |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 95 | |
| 96 | try: |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 97 | remote_branch = get_remote_branch(llvm_worktree, local_branch) |
| 98 | config.for_each_enabled(partial(push_branch, proj, local_branch, |
| 99 | remote_branch)) |
| 100 | print("Pushed to {}".format(remote_branch)) |
| 101 | except (EnvironmentError, RuntimeError) as exc: |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 102 | die("Failed to push branch because: " + str(exc) + str(exc.__cause__)) |
| 103 | |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 104 | |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 105 | def cmake_flags_from_args(defs): |
| 106 | """ |
| 107 | Get a list of valid CMake flags from the input VAR=VALUE list. |
| 108 | This boils down to just adding -D in front of each of them. |
| 109 | """ |
| 110 | return ["-D{}".format(v) for v in defs] |
| 111 | |
| 112 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 113 | def configure_build(args): |
| 114 | """Configure a given build directory.""" |
| 115 | |
| 116 | proj = Proj() |
| 117 | |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 118 | llvm_worktree_root = args.sources |
Diana Picus | b1dbcba | 2018-02-07 01:33:17 +0100 | [diff] [blame] | 119 | sourceConfig = LLVMSourceConfig(proj, llvm_worktree_root, args.dry) |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 120 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 121 | if args.dry: |
| 122 | consumer = CommandPrinter() |
| 123 | else: |
| 124 | if not os.path.exists(args.build): |
| 125 | os.makedirs(args.build) |
| 126 | consumer = CommandRunner() |
| 127 | |
Diana Picus | 6b1935f | 2018-02-07 16:44:11 +0100 | [diff] [blame] | 128 | buildConfig = LLVMBuildConfig(sourceConfig, args.build, consumer) |
| 129 | |
| 130 | if args.defs: |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 131 | args.defs = cmake_flags_from_args(args.defs) |
Diana Picus | 6b1935f | 2018-02-07 16:44:11 +0100 | [diff] [blame] | 132 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 133 | try: |
Diana Picus | 6b1935f | 2018-02-07 16:44:11 +0100 | [diff] [blame] | 134 | buildConfig.cmake(args.defs, args.generator) |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 135 | except RuntimeError as exc: |
| 136 | die("Failed to configure {} because:\n{}".format(args.build, str(exc))) |
| 137 | |
| 138 | |
Diana Picus | 37126b8 | 2018-01-19 16:14:26 +0100 | [diff] [blame] | 139 | def run_build(args): |
| 140 | """Run a build command in a given directory.""" |
| 141 | build_dir = args.build |
| 142 | |
| 143 | if args.dry: |
| 144 | consumer = CommandPrinter() |
| 145 | else: |
| 146 | consumer = CommandRunner() |
| 147 | |
| 148 | try: |
Diana Picus | 6b1935f | 2018-02-07 16:44:11 +0100 | [diff] [blame] | 149 | LLVMBuildConfig(None, args.build, consumer).build(args.flags) |
Diana Picus | 37126b8 | 2018-01-19 16:14:26 +0100 | [diff] [blame] | 150 | except RuntimeError as exc: |
| 151 | die("Failed to build {} because:\n{}".format(args.build, str(exc))) |
| 152 | |
| 153 | |
Diana Picus | f73abbf | 2018-01-26 07:06:20 +0100 | [diff] [blame] | 154 | def setup_the_test_suite(args): |
| 155 | """Setup a sandbox for the test-suite.""" |
| 156 | if args.dry: |
| 157 | consumer = CommandPrinter() |
| 158 | else: |
| 159 | consumer = CommandRunner() |
| 160 | |
| 161 | try: |
| 162 | setup_test_suite(consumer, args.sandbox, args.lnt) |
| 163 | except RuntimeError as exc: |
| 164 | die("Failed to setup the test-suite because:\n{}".format(str(exc))) |
| 165 | |
| 166 | |
Diana Picus | b368cb6 | 2018-01-23 16:41:59 +0100 | [diff] [blame] | 167 | def run_the_test_suite(args): |
| 168 | """Run the test-suite in a given sandbox.""" |
| 169 | if args.dry: |
| 170 | consumer = CommandPrinter() |
| 171 | else: |
| 172 | consumer = CommandRunner() |
| 173 | |
| 174 | compilers = ["--cc={}".format(args.cc)] |
| 175 | if args.cxx: |
| 176 | compilers.append("--cxx={}".format(args.cxx)) |
| 177 | |
| 178 | try: |
| 179 | run_test_suite(consumer, args.sandbox, args.testsuite, args.lit, |
| 180 | compilers + args.flags) |
| 181 | except RuntimeError as exc: |
| 182 | die("Failed to run the test-suite because:\n{}".format(str(exc))) |
| 183 | |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 184 | |
| 185 | def build_and_test(args): |
| 186 | """ |
| 187 | Build a set of LLVM subprojects, in one or two stages, with or without a |
| 188 | test-suite run. |
| 189 | """ |
| 190 | |
| 191 | proj = Proj() |
| 192 | |
| 193 | dryRun = args.dry |
Diana Picus | fcfc628 | 2018-02-14 18:50:24 +0100 | [diff] [blame] | 194 | llvmRepos = args.repos |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 195 | llvmWorktreeRoot = args.sources |
| 196 | |
| 197 | stage1BuildDir = args.stage1 |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 198 | stage1Subprojs = args.stage1Subprojs |
| 199 | stage1Defs = cmake_flags_from_args(args.stage1Defs) |
| 200 | stage1BuildFlags = args.stage1BuildFlags |
| 201 | |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 202 | stage2BuildDir = args.stage2 |
Diana Picus | 6cdb516 | 2018-02-15 05:29:46 +0100 | [diff] [blame] | 203 | stage2Subprojs = args.stage2Subprojs |
| 204 | stage2Defs = cmake_flags_from_args(args.stage2Defs) |
| 205 | stage2BuildFlags = args.stage2BuildFlags |
Diana Picus | fcfc628 | 2018-02-14 18:50:24 +0100 | [diff] [blame] | 206 | |
| 207 | enableTestSuite = args.enableTestSuite |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 208 | sandboxDir = args.sandbox |
Diana Picus | 49ee93a | 2018-02-15 05:52:34 +0100 | [diff] [blame] | 209 | testSuiteFlags = args.testSuiteFlags |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 210 | |
| 211 | if dryRun: |
| 212 | consumer = CommandPrinter() |
| 213 | else: |
| 214 | consumer = CommandRunner() |
| 215 | |
| 216 | try: |
| 217 | sourceConfig = LLVMSourceConfig(proj, llvmWorktreeRoot, args.dry) |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 218 | if stage1Subprojs: |
| 219 | # FIXME: Decide whether or not we want to remove anything that isn't |
| 220 | # in stage1Subprojs (in case there are already some enabled |
| 221 | # subprojects in the source config). |
| 222 | sourceConfig.update( |
| 223 | subproj_to_repo_map(stage1Subprojs, proj, llvmRepos, |
| 224 | args.dry), |
| 225 | []) |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 226 | |
| 227 | if not dryRun and not os.path.exists(stage1BuildDir): |
| 228 | os.makedirs(stage1BuildDir) |
| 229 | |
| 230 | buildConfig1 = LLVMBuildConfig(sourceConfig, stage1BuildDir, consumer) |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 231 | buildConfig1.cmake(stage1Defs, "Ninja") |
| 232 | buildConfig1.build(stage1BuildFlags) |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 233 | testedBuildDir = stage1BuildDir |
| 234 | |
| 235 | if stage2BuildDir is not None: |
Diana Picus | 6cdb516 | 2018-02-15 05:29:46 +0100 | [diff] [blame] | 236 | if stage2Subprojs: |
| 237 | toAdd = list(set(stage2Subprojs) - set(stage1Subprojs)) |
| 238 | toRemove = list(set(stage1Subprojs) - set(stage2Subprojs)) |
| 239 | sourceConfig.update( |
| 240 | subproj_to_repo_map(toAdd, proj, llvmRepos, args.dry), |
| 241 | toRemove) |
| 242 | |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 243 | if not dryRun and not os.path.exists(stage2BuildDir): |
| 244 | os.makedirs(stage2BuildDir) |
| 245 | |
| 246 | buildConfig2 = LLVMBuildConfig(sourceConfig, stage2BuildDir, |
| 247 | consumer) |
| 248 | |
| 249 | # TODO: Make sure clang is actually built in this config (preferably |
| 250 | # before reaching this point) |
| 251 | buildConfig2.cmake( |
Diana Picus | 6cdb516 | 2018-02-15 05:29:46 +0100 | [diff] [blame] | 252 | stage2Defs + [ |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 253 | "-DCMAKE_C_COMPILER={}/bin/clang".format(stage1BuildDir), |
| 254 | "-DCMAKE_CXX_COMPILER={}/bin/clang++".format(stage1BuildDir)], |
| 255 | "Ninja") |
Diana Picus | 6cdb516 | 2018-02-15 05:29:46 +0100 | [diff] [blame] | 256 | buildConfig2.build(stage2BuildFlags) |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 257 | testedBuildDir = stage2BuildDir |
| 258 | |
Diana Picus | fcfc628 | 2018-02-14 18:50:24 +0100 | [diff] [blame] | 259 | if enableTestSuite: |
| 260 | testSuiteDir = os.path.join(llvmRepos, "test-suite") |
| 261 | lntDir = os.path.join(llvmRepos, "lnt") |
| 262 | |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 263 | setup_test_suite(consumer, sandboxDir, lntDir) |
| 264 | |
| 265 | # TODO: Make sure clang is actually built in this config (preferably |
| 266 | # before reaching this point) |
| 267 | lit = os.path.join(testedBuildDir, "bin", "llvm-lit") |
| 268 | clang = os.path.join(testedBuildDir, "bin", "clang") |
| 269 | run_test_suite(consumer, sandboxDir, testSuiteDir, lit, |
Diana Picus | 49ee93a | 2018-02-15 05:52:34 +0100 | [diff] [blame] | 270 | ["--cc={}".format(clang)] + testSuiteFlags) |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 271 | |
| 272 | except RuntimeError as exc: |
| 273 | die("Failed because:\n{}".format(str(exc))) |
| 274 | |
| 275 | |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 276 | ########################################################################## |
| 277 | # Command line parsing # |
| 278 | ########################################################################## |
| 279 | |
| 280 | # If we decide we want shorthands for the subprojects, we can append to this |
| 281 | # list |
Diana Picus | b430760 | 2017-04-05 19:48:39 +0200 | [diff] [blame] | 282 | valid_subprojects = list(LLVMSubproject.get_all_subprojects().keys()) |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 283 | |
| 284 | options = ArgumentParser(formatter_class=RawTextHelpFormatter) |
Diana Picus | adb07c4 | 2017-11-22 16:12:57 +0100 | [diff] [blame] | 285 | subcommands = options.add_subparsers(dest="subcommand") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 286 | |
| 287 | # Subcommand for adding / removing subprojects |
Diana Picus | 36317e8 | 2017-10-31 15:35:24 +0100 | [diff] [blame] | 288 | projs = subcommands.add_parser( |
| 289 | "projects", help="Add/remove LLVM subprojects.\n" |
| 290 | "Adding a subproject will create a worktree for it " |
| 291 | "somewhere in the LLVM source tree, on the same git " |
| 292 | "branch as LLVM itself.\n" |
| 293 | "Removing a subproject will remove the worktree, but " |
| 294 | "not the underlying git branch.") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 295 | projs.set_defaults(run_command=projects) |
| 296 | |
| 297 | # TODO: Overwriting previous values is not necessarily what users expect (so for |
| 298 | # instance --add S1 S2 --remove S3 --add S4 would lead to adding only S4). We |
| 299 | # can do better by using action='append', which would create a list (of lists? |
| 300 | # or of lists and scalars?) that we can flatten to obtain all the values passed |
| 301 | # by the user. |
| 302 | projs.add_argument( |
| 303 | '-a', '--add', |
| 304 | nargs='+', |
| 305 | choices=valid_subprojects, |
| 306 | metavar='subproject', |
Diana Picus | 36317e8 | 2017-10-31 15:35:24 +0100 | [diff] [blame] | 307 | help="Enable given subprojects. Valid values are:\n\t{}\n".format( |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 308 | "\n\t".join(valid_subprojects))) |
| 309 | projs.add_argument( |
| 310 | '-r', '--remove', |
| 311 | nargs='+', |
| 312 | choices=valid_subprojects, |
| 313 | metavar='subproject', |
Diana Picus | 36317e8 | 2017-10-31 15:35:24 +0100 | [diff] [blame] | 314 | help="Disable given subprojects.") |
Diana Picus | adb07c4 | 2017-11-22 16:12:57 +0100 | [diff] [blame] | 315 | projs.add_argument( |
| 316 | '--repos', |
| 317 | help="Path to the directory containing the repositories for all LLVM " |
| 318 | "subprojects.") |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 319 | projs.add_argument( |
| 320 | '--source-dir', |
| 321 | dest='sources', |
| 322 | required=True, |
| 323 | help="Path to the directory containing the LLVM worktree that we're adding " |
| 324 | "or removing subprojects from.") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 325 | |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 326 | # Subcommand for pushing the current branch to origin |
| 327 | push = subcommands.add_parser( |
| 328 | "push", |
Diana Picus | 36317e8 | 2017-10-31 15:35:24 +0100 | [diff] [blame] | 329 | help="Push current branch to origin linaro-local/<user>/<branch>, " |
| 330 | "for all enabled subprojects.") |
Diana Picus | 95226d4 | 2017-11-01 13:16:54 +0100 | [diff] [blame] | 331 | push.set_defaults(run_command=push_current_branch) |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 332 | push.add_argument( |
| 333 | '--source-dir', |
| 334 | dest='sources', |
| 335 | required=True, |
| 336 | help="Path to the directory containing the LLVM worktree.") |
Diana Picus | efc7bda | 2017-06-09 19:14:08 +0200 | [diff] [blame] | 337 | |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 338 | # Subcommand for configuring a build directory |
| 339 | configure = subcommands.add_parser( |
| 340 | 'configure', |
| 341 | help="Run CMake in the given build directory.") |
| 342 | configure.add_argument( |
Diana Picus | 9f75686 | 2017-12-20 10:35:08 +0100 | [diff] [blame] | 343 | '--source-dir', |
| 344 | dest='sources', |
| 345 | required=True, |
| 346 | help="Path to the sources directory. It should contain an LLVM worktree.") |
| 347 | configure.add_argument( |
Diana Picus | 052b7d3 | 2017-11-24 16:19:41 +0100 | [diff] [blame] | 348 | '--build-dir', |
| 349 | dest='build', |
| 350 | required=True, |
| 351 | help="Path to the build directory. It will be created if it does not exist") |
| 352 | configure.add_argument( |
| 353 | '--cmake-generator', |
| 354 | dest='generator', |
| 355 | default='Ninja', |
| 356 | help="CMake generator to use (default is Ninja).") |
| 357 | configure.add_argument( |
| 358 | '--cmake-def', |
| 359 | dest='defs', |
| 360 | metavar='VAR=VALUE', |
| 361 | default=[], |
| 362 | action='append', |
| 363 | # We add the -D in front of the variable ourselves because the argument |
| 364 | # parsing gets confused otherwise (and quoting doesn't help). |
| 365 | help="Additional CMake definitions, e.g. CMAKE_BUILD_TYPE=Release." |
| 366 | "May be passed several times. The -D is added automatically.") |
| 367 | configure.add_argument( |
| 368 | '-n', '--dry-run', |
| 369 | dest='dry', |
| 370 | action='store_true', |
| 371 | default=False, |
| 372 | help="Print the CMake command instead of executing it.") |
| 373 | configure.set_defaults(run_command=configure_build) |
| 374 | |
Diana Picus | 37126b8 | 2018-01-19 16:14:26 +0100 | [diff] [blame] | 375 | # Subcommand for building a target |
| 376 | build = subcommands.add_parser( |
| 377 | 'build', |
| 378 | help="Run a build command in the given directory." |
| 379 | "The build command can be either a 'ninja' or a 'make' command, depending " |
| 380 | "on what the build directory contains. First, we look for a 'build.ninja' " |
| 381 | "file. If that is not found, we look for a 'Makefile'. If that is not " |
| 382 | "found either, the script fails.") |
| 383 | build.add_argument( |
| 384 | '--build-dir', |
| 385 | dest='build', |
| 386 | required=True, |
| 387 | help="Path to the build directory. It must have already been configured.") |
| 388 | build.add_argument( |
| 389 | '-n', '--dry-run', |
| 390 | dest='dry', |
| 391 | action='store_true', |
| 392 | default=False, |
| 393 | help="Print the build command instead of executing it.") |
| 394 | build.add_argument( |
| 395 | '--build-flag', |
| 396 | dest='flags', |
| 397 | metavar='FLAG', |
| 398 | default=[], |
| 399 | action='append', |
| 400 | help="Additional flags for the build command (e.g. targets to build). " |
| 401 | "May be passed several times. If your flag starts with a '-', use " |
| 402 | "'--build-flag=-FLAG' to pass it.") |
| 403 | build.set_defaults(run_command=run_build) |
| 404 | |
Diana Picus | f73abbf | 2018-01-26 07:06:20 +0100 | [diff] [blame] | 405 | # Subcommand for setting up the test-suite |
| 406 | setupTestSuite = subcommands.add_parser( |
| 407 | 'setup-test-suite', |
| 408 | help="Prepare a sandbox for running the test-suite.") |
| 409 | setupTestSuite.add_argument( |
| 410 | '--sandbox', |
| 411 | required=True, |
| 412 | help="Path where we should setup the sandbox.") |
| 413 | setupTestSuite.add_argument( |
| 414 | '--lnt', |
| 415 | required=True, |
| 416 | help="Path to the LNT sources.") |
| 417 | setupTestSuite.add_argument( |
| 418 | '-n', '--dry-run', |
| 419 | dest='dry', |
| 420 | action='store_true', |
| 421 | default=False, |
| 422 | help="Print the commands instead of executing them.") |
| 423 | setupTestSuite.set_defaults(run_command=setup_the_test_suite) |
| 424 | |
Diana Picus | b368cb6 | 2018-01-23 16:41:59 +0100 | [diff] [blame] | 425 | # Subcommand for running the test-suite |
| 426 | runTestSuite = subcommands.add_parser( |
| 427 | 'run-test-suite', |
| 428 | help="Run the test-suite in the given sandbox.") |
| 429 | runTestSuite.add_argument( |
| 430 | '--sandbox', |
| 431 | required=True, |
| 432 | help="Path to the sandbox. It must point to a virtualenv with a LNT setup.") |
| 433 | runTestSuite.add_argument( |
| 434 | '--test-suite', |
| 435 | dest="testsuite", |
| 436 | required=True, |
| 437 | help="Path to the test-suite repo.") |
| 438 | runTestSuite.add_argument( |
| 439 | '--use-lit', |
| 440 | dest="lit", |
| 441 | required=True, |
| 442 | help="Path to llvm-lit.") |
| 443 | runTestSuite.add_argument( |
| 444 | '--lnt-flag', |
| 445 | dest='flags', |
| 446 | metavar='FLAG', |
| 447 | default=[], |
| 448 | action='append', |
| 449 | help="Additional flags to be passed to LNT when running the test-suite." |
| 450 | "May be passed several times. If your flag starts with a '-', use " |
| 451 | "'--lnt-flag=-FLAG' to pass it.") |
| 452 | runTestSuite.add_argument( |
| 453 | # We can pass --cc through the --lnt-flag interface, but we generally won't |
| 454 | # want to test the system compiler, so force the user to be specific. |
| 455 | '--cc', |
| 456 | required=True, |
| 457 | help="The path to the C compiler that we're testing.") |
| 458 | runTestSuite.add_argument( |
| 459 | # For symmetry, we also provide a --cxx argument, but this one isn't |
| 460 | # required since LNT tries to guess it based on the value of --cc. |
| 461 | '--cxx', |
| 462 | required=False, |
| 463 | help="The path to the C++ compiler that we're testing.") |
| 464 | runTestSuite.add_argument( |
| 465 | '-n', '--dry-run', |
| 466 | dest='dry', |
| 467 | action='store_true', |
| 468 | default=False, |
| 469 | help="Print the commands instead of executing them.") |
| 470 | runTestSuite.set_defaults(run_command=run_the_test_suite) |
| 471 | |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 472 | buildAndTest = subcommands.add_parser( |
| 473 | 'build-and-test', # TODO: This really needs a better name... |
Diana Picus | fec612c | 2018-02-19 19:14:00 +0100 | [diff] [blame^] | 474 | fromfile_prefix_chars='@', |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 475 | help="Run complex build scenarios with one or two stages of clang and " |
| 476 | "optionally a test-suite run. This should be flexible enough to allow " |
| 477 | "us to reproduce any buildbot configuration, but it can obviously be " |
| 478 | "used for other purposes as well.") |
| 479 | buildAndTest.set_defaults(run_command=build_and_test) |
| 480 | buildAndTest.add_argument( |
Diana Picus | fcfc628 | 2018-02-14 18:50:24 +0100 | [diff] [blame] | 481 | '--repos-dir', |
| 482 | dest='repos', |
| 483 | required=True, |
| 484 | help="Path to the root directory containing the repositories for LLVM and " |
| 485 | "the other subprojects.") |
| 486 | buildAndTest.add_argument( |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 487 | '--source-dir', |
| 488 | dest='sources', |
| 489 | required=True, |
| 490 | help="Path to the directory containing the LLVM worktree that we're going " |
| 491 | "to build from.") |
| 492 | buildAndTest.add_argument( |
| 493 | '--stage1-build-dir', |
| 494 | dest='stage1', |
| 495 | required=True, |
| 496 | help="Path to the build directory for stage 1.") |
| 497 | buildAndTest.add_argument( |
Diana Picus | 2c58083 | 2018-02-14 14:51:00 +0100 | [diff] [blame] | 498 | '--stage1-subproject', |
| 499 | dest='stage1Subprojs', |
| 500 | metavar='SUBPROJ', |
| 501 | choices=valid_subprojects, |
| 502 | default=[], |
| 503 | action='append', |
| 504 | help="Subprojects to enable for stage 1 of the build. Can be passed " |
| 505 | "multiple times. Valid values for the subproject are: {}. " |
| 506 | "If this is a 2-stage build, the same subprojects will be used for " |
| 507 | "both stages unless other subprojects are explicitly requested for " |
| 508 | "stage 2.".format(" ".join(valid_subprojects))) |
| 509 | buildAndTest.add_argument( |
| 510 | '--stage1-cmake-def', |
| 511 | dest='stage1Defs', |
| 512 | metavar='VAR=VALUE', |
| 513 | default=[], |
| 514 | action='append', |
| 515 | help="Additional CMake definitions for stage 1, e.g. " |
| 516 | "CMAKE_BUILD_TYPE=Release. Can be passed multiple times. " |
| 517 | "The -D is added automatically. Does not affect stage 2.") |
| 518 | buildAndTest.add_argument( |
| 519 | '--stage1-build-flag', |
| 520 | dest='stage1BuildFlags', |
| 521 | metavar='FLAG', |
| 522 | default=[], |
| 523 | action='append', |
| 524 | help="Additional flags for the stage 1 build command (e.g. targets to " |
| 525 | "build). Can be passed multiple times. If your flag starts with " |
| 526 | "a '-', use '--stage1-build-flag=-FLAG' to pass it. " |
| 527 | "Does not affect stage 2.") |
| 528 | buildAndTest.add_argument( |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 529 | '--stage2-build-dir', |
| 530 | dest='stage2', |
| 531 | help="Path to the build directory for stage 2.") |
| 532 | buildAndTest.add_argument( |
Diana Picus | 6cdb516 | 2018-02-15 05:29:46 +0100 | [diff] [blame] | 533 | '--stage2-subproject', |
| 534 | dest='stage2Subprojs', |
| 535 | metavar='SUBPROJ', |
| 536 | choices=valid_subprojects, |
| 537 | default=[], |
| 538 | action='append', |
| 539 | help="Subprojects to enable for stage 2 of the build. Can be passed " |
| 540 | "multiple times. Valid values for the subproject are: {}. " |
| 541 | "If this is a 2-stage build, the same subprojects will be used for " |
| 542 | "both stages unless other subprojects are explicitly requested for " |
| 543 | "stage 2.".format(" ".join(valid_subprojects))) |
| 544 | buildAndTest.add_argument( |
| 545 | '--stage2-cmake-def', |
| 546 | dest='stage2Defs', |
| 547 | metavar='VAR=VALUE', |
| 548 | default=[], |
| 549 | action='append', |
| 550 | help="Additional CMake definitions for stage 2, e.g. " |
| 551 | "CMAKE_BUILD_TYPE=Release. Can be passed multiple times. " |
| 552 | "The -D is added automatically.") |
| 553 | buildAndTest.add_argument( |
| 554 | '--stage2-build-flag', |
| 555 | dest='stage2BuildFlags', |
| 556 | metavar='FLAG', |
| 557 | default=[], |
| 558 | action='append', |
| 559 | help="Additional flags for the stage 2 build command (e.g. targets to " |
| 560 | "build). Can be passed multiple times. If your flag starts with " |
| 561 | "a '-', use '--stage2-build-flag=-FLAG' to pass it.") |
| 562 | buildAndTest.add_argument( |
Diana Picus | fcfc628 | 2018-02-14 18:50:24 +0100 | [diff] [blame] | 563 | "--enable-test-suite", |
| 564 | dest='enableTestSuite', |
| 565 | action='store_true', |
| 566 | default=False, |
| 567 | help="Whether or not to run the test-suite with the last compiler built.") |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 568 | buildAndTest.add_argument( |
| 569 | "--sandbox", |
| 570 | help="Path to the sandbox where the test-suite should be setup.") |
| 571 | buildAndTest.add_argument( |
Diana Picus | 49ee93a | 2018-02-15 05:52:34 +0100 | [diff] [blame] | 572 | '--lnt-flag', |
| 573 | dest='testSuiteFlags', |
| 574 | metavar='FLAG', |
| 575 | default=[], |
| 576 | action='append', |
| 577 | help="Additional flags to be passed to LNT when running the test-suite." |
| 578 | "May be passed several times. If your flag starts with a '-', use " |
| 579 | "'--lnt-flag=-FLAG' to pass it.") |
| 580 | buildAndTest.add_argument( |
Diana Picus | b03e508 | 2018-02-05 12:36:49 +0100 | [diff] [blame] | 581 | '-n', '--dry-run', |
| 582 | dest='dry', |
| 583 | action='store_true', |
| 584 | default=False, |
| 585 | help="Print the commands instead of executing them.") |
| 586 | |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 587 | args = options.parse_args() |
Diana Picus | adb07c4 | 2017-11-22 16:12:57 +0100 | [diff] [blame] | 588 | if args.subcommand == "projects" and args.add and not args.repos: |
| 589 | projs.error( |
| 590 | "When adding a subproject you must also pass the --repos argument") |
Diana Picus | 3b2ef82 | 2016-10-13 16:53:18 +0300 | [diff] [blame] | 591 | args.run_command(args) |