blob: cce0ef415ea2698636cbd665ebd284e13c4bbd00 [file] [log] [blame]
Diana Picus3b2ef822016-10-13 16:53:18 +03001"""This is the main tool for handling llvm builds, bisects etc."""
2
3import os
Diana Picusadb07c42017-11-22 16:12:57 +01004from sys import argv
Diana Picus3b2ef822016-10-13 16:53:18 +03005from sys import exit
6
Diana Picus37126b82018-01-19 16:14:26 +01007from modules.llvm import build_llvm
Diana Picus052b7d32017-11-24 16:19:41 +01008from modules.llvm import LLVMBuildConfig
Diana Picus95226d42017-11-01 13:16:54 +01009from modules.llvm import LLVMSubproject
10from modules.llvm import LLVMSourceConfig
Diana Picusb368cb62018-01-23 16:41:59 +010011from modules.llvm import run_test_suite
Diana Picusf73abbf2018-01-26 07:06:20 +010012from modules.llvm import setup_test_suite
Diana Picus052b7d32017-11-24 16:19:41 +010013from modules.utils import CommandPrinter
14from modules.utils import CommandRunner
Diana Picus5ad55422017-12-14 17:57:10 +010015from modules.utils import get_remote_branch
16from modules.utils import push_branch
Diana Picus95226d42017-11-01 13:16:54 +010017
Diana Picus052b7d32017-11-24 16:19:41 +010018from linaropy.cd import cd
Diana Picus3b2ef822016-10-13 16:53:18 +030019from linaropy.git.clone import Clone
20from linaropy.proj import Proj
21
22from argparse import Action, ArgumentParser, RawTextHelpFormatter
Diana Picusefc7bda2017-06-09 19:14:08 +020023from functools import partial
Diana Picus3b2ef822016-10-13 16:53:18 +030024
25
26def die(message, config_to_dump=None):
27 """Print an error message and exit."""
Diana Picusb4307602017-04-05 19:48:39 +020028 print(message)
Diana Picus3b2ef822016-10-13 16:53:18 +030029
30 if config_to_dump is not None:
31 dump_config(config_to_dump)
32
33 exit(1)
34
Diana Picus3d1a3012017-03-14 17:38:32 +010035
Diana Picus3b2ef822016-10-13 16:53:18 +030036def dump_config(config):
37 """Dump the list of projects that are enabled in the given config."""
38
Diana Picusb4307602017-04-05 19:48:39 +020039 print("Projects linked:")
Diana Picus3b2ef822016-10-13 16:53:18 +030040 enabled = config.get_enabled_subprojects()
41 if not enabled:
Diana Picusb4307602017-04-05 19:48:39 +020042 print("none")
Diana Picus3b2ef822016-10-13 16:53:18 +030043 else:
44 for subproj in sorted(enabled):
Diana Picusb4307602017-04-05 19:48:39 +020045 print(" + {}".format(subproj))
Diana Picus3b2ef822016-10-13 16:53:18 +030046
47
48def projects(args):
49 """Add/remove subprojects based on the values in args."""
50
51 proj = Proj()
Diana Picus3d1a3012017-03-14 17:38:32 +010052
Diana Picus9f756862017-12-20 10:35:08 +010053 llvm_worktree_root = args.sources
Diana Picus81089db2017-05-05 22:26:49 +020054 llvm_repos_root = args.repos
Diana Picus3b2ef822016-10-13 16:53:18 +030055 config = LLVMSourceConfig(proj, llvm_worktree_root)
56
57 if not args.add and not args.remove:
58 # Nothing to change, just print the current configuration
59 dump_config(config)
60 exit(0)
61
62 to_add = {}
63 if args.add:
64 for subproj in args.add:
65 repo = Clone(proj, os.path.join(llvm_repos_root, subproj))
66 to_add[subproj] = repo
67
68 try:
69 config.update(to_add, args.remove)
70 except (EnvironmentError, ValueError) as exc:
71 die("Failed to update subprojects because:\n{}".format(str(exc)))
72
73 dump_config(config)
74
Diana Picusefc7bda2017-06-09 19:14:08 +020075
Diana Picus95226d42017-11-01 13:16:54 +010076def push_current_branch(args):
Diana Picusefc7bda2017-06-09 19:14:08 +020077 """Push current branch to origin."""
78
79 proj = Proj()
80
Diana Picus9f756862017-12-20 10:35:08 +010081 llvm_worktree_root = args.sources
Diana Picusefc7bda2017-06-09 19:14:08 +020082 config = LLVMSourceConfig(proj, llvm_worktree_root)
83
Diana Picus95226d42017-11-01 13:16:54 +010084 llvm_worktree = Clone(proj, llvm_worktree_root)
85 local_branch = llvm_worktree.getbranch()
Diana Picusefc7bda2017-06-09 19:14:08 +020086
87 try:
Diana Picus95226d42017-11-01 13:16:54 +010088 remote_branch = get_remote_branch(llvm_worktree, local_branch)
89 config.for_each_enabled(partial(push_branch, proj, local_branch,
90 remote_branch))
91 print("Pushed to {}".format(remote_branch))
92 except (EnvironmentError, RuntimeError) as exc:
Diana Picusefc7bda2017-06-09 19:14:08 +020093 die("Failed to push branch because: " + str(exc) + str(exc.__cause__))
94
Diana Picus95226d42017-11-01 13:16:54 +010095
Diana Picus052b7d32017-11-24 16:19:41 +010096def configure_build(args):
97 """Configure a given build directory."""
98
99 proj = Proj()
100
Diana Picus9f756862017-12-20 10:35:08 +0100101 llvm_worktree_root = args.sources
Diana Picus052b7d32017-11-24 16:19:41 +0100102 sourceConfig = LLVMSourceConfig(proj, llvm_worktree_root)
103
104 buildConfig = LLVMBuildConfig(sourceConfig, args.build)
105
106 if args.defs:
107 args.defs = ["-D{}".format(v) for v in args.defs]
108
109 if args.dry:
110 consumer = CommandPrinter()
111 else:
112 if not os.path.exists(args.build):
113 os.makedirs(args.build)
114 consumer = CommandRunner()
115
116 try:
117 buildConfig.cmake(consumer, args.defs, args.generator)
118 except RuntimeError as exc:
119 die("Failed to configure {} because:\n{}".format(args.build, str(exc)))
120
121
Diana Picus37126b82018-01-19 16:14:26 +0100122def run_build(args):
123 """Run a build command in a given directory."""
124 build_dir = args.build
125
126 if args.dry:
127 consumer = CommandPrinter()
128 else:
129 consumer = CommandRunner()
130
131 try:
132 build_llvm(consumer, args.build, args.flags)
133 except RuntimeError as exc:
134 die("Failed to build {} because:\n{}".format(args.build, str(exc)))
135
136
Diana Picusf73abbf2018-01-26 07:06:20 +0100137def setup_the_test_suite(args):
138 """Setup a sandbox for the test-suite."""
139 if args.dry:
140 consumer = CommandPrinter()
141 else:
142 consumer = CommandRunner()
143
144 try:
145 setup_test_suite(consumer, args.sandbox, args.lnt)
146 except RuntimeError as exc:
147 die("Failed to setup the test-suite because:\n{}".format(str(exc)))
148
149
Diana Picusb368cb62018-01-23 16:41:59 +0100150def run_the_test_suite(args):
151 """Run the test-suite in a given sandbox."""
152 if args.dry:
153 consumer = CommandPrinter()
154 else:
155 consumer = CommandRunner()
156
157 compilers = ["--cc={}".format(args.cc)]
158 if args.cxx:
159 compilers.append("--cxx={}".format(args.cxx))
160
161 try:
162 run_test_suite(consumer, args.sandbox, args.testsuite, args.lit,
163 compilers + args.flags)
164 except RuntimeError as exc:
165 die("Failed to run the test-suite because:\n{}".format(str(exc)))
166
Diana Picus3b2ef822016-10-13 16:53:18 +0300167##########################################################################
168# Command line parsing #
169##########################################################################
170
171# If we decide we want shorthands for the subprojects, we can append to this
172# list
Diana Picusb4307602017-04-05 19:48:39 +0200173valid_subprojects = list(LLVMSubproject.get_all_subprojects().keys())
Diana Picus3b2ef822016-10-13 16:53:18 +0300174
175options = ArgumentParser(formatter_class=RawTextHelpFormatter)
Diana Picusadb07c42017-11-22 16:12:57 +0100176subcommands = options.add_subparsers(dest="subcommand")
Diana Picus3b2ef822016-10-13 16:53:18 +0300177
178# Subcommand for adding / removing subprojects
Diana Picus36317e82017-10-31 15:35:24 +0100179projs = subcommands.add_parser(
180 "projects", help="Add/remove LLVM subprojects.\n"
181 "Adding a subproject will create a worktree for it "
182 "somewhere in the LLVM source tree, on the same git "
183 "branch as LLVM itself.\n"
184 "Removing a subproject will remove the worktree, but "
185 "not the underlying git branch.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300186projs.set_defaults(run_command=projects)
187
188# TODO: Overwriting previous values is not necessarily what users expect (so for
189# instance --add S1 S2 --remove S3 --add S4 would lead to adding only S4). We
190# can do better by using action='append', which would create a list (of lists?
191# or of lists and scalars?) that we can flatten to obtain all the values passed
192# by the user.
193projs.add_argument(
194 '-a', '--add',
195 nargs='+',
196 choices=valid_subprojects,
197 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100198 help="Enable given subprojects. Valid values are:\n\t{}\n".format(
Diana Picus3b2ef822016-10-13 16:53:18 +0300199 "\n\t".join(valid_subprojects)))
200projs.add_argument(
201 '-r', '--remove',
202 nargs='+',
203 choices=valid_subprojects,
204 metavar='subproject',
Diana Picus36317e82017-10-31 15:35:24 +0100205 help="Disable given subprojects.")
Diana Picusadb07c42017-11-22 16:12:57 +0100206projs.add_argument(
207 '--repos',
208 help="Path to the directory containing the repositories for all LLVM "
209 "subprojects.")
Diana Picus9f756862017-12-20 10:35:08 +0100210projs.add_argument(
211 '--source-dir',
212 dest='sources',
213 required=True,
214 help="Path to the directory containing the LLVM worktree that we're adding "
215 "or removing subprojects from.")
Diana Picus3b2ef822016-10-13 16:53:18 +0300216
Diana Picusefc7bda2017-06-09 19:14:08 +0200217# Subcommand for pushing the current branch to origin
218push = subcommands.add_parser(
219 "push",
Diana Picus36317e82017-10-31 15:35:24 +0100220 help="Push current branch to origin linaro-local/<user>/<branch>, "
221 "for all enabled subprojects.")
Diana Picus95226d42017-11-01 13:16:54 +0100222push.set_defaults(run_command=push_current_branch)
Diana Picus9f756862017-12-20 10:35:08 +0100223push.add_argument(
224 '--source-dir',
225 dest='sources',
226 required=True,
227 help="Path to the directory containing the LLVM worktree.")
Diana Picusefc7bda2017-06-09 19:14:08 +0200228
Diana Picus052b7d32017-11-24 16:19:41 +0100229# Subcommand for configuring a build directory
230configure = subcommands.add_parser(
231 'configure',
232 help="Run CMake in the given build directory.")
233configure.add_argument(
Diana Picus9f756862017-12-20 10:35:08 +0100234 '--source-dir',
235 dest='sources',
236 required=True,
237 help="Path to the sources directory. It should contain an LLVM worktree.")
238configure.add_argument(
Diana Picus052b7d32017-11-24 16:19:41 +0100239 '--build-dir',
240 dest='build',
241 required=True,
242 help="Path to the build directory. It will be created if it does not exist")
243configure.add_argument(
244 '--cmake-generator',
245 dest='generator',
246 default='Ninja',
247 help="CMake generator to use (default is Ninja).")
248configure.add_argument(
249 '--cmake-def',
250 dest='defs',
251 metavar='VAR=VALUE',
252 default=[],
253 action='append',
254 # We add the -D in front of the variable ourselves because the argument
255 # parsing gets confused otherwise (and quoting doesn't help).
256 help="Additional CMake definitions, e.g. CMAKE_BUILD_TYPE=Release."
257 "May be passed several times. The -D is added automatically.")
258configure.add_argument(
259 '-n', '--dry-run',
260 dest='dry',
261 action='store_true',
262 default=False,
263 help="Print the CMake command instead of executing it.")
264configure.set_defaults(run_command=configure_build)
265
Diana Picus37126b82018-01-19 16:14:26 +0100266# Subcommand for building a target
267build = subcommands.add_parser(
268 'build',
269 help="Run a build command in the given directory."
270 "The build command can be either a 'ninja' or a 'make' command, depending "
271 "on what the build directory contains. First, we look for a 'build.ninja' "
272 "file. If that is not found, we look for a 'Makefile'. If that is not "
273 "found either, the script fails.")
274build.add_argument(
275 '--build-dir',
276 dest='build',
277 required=True,
278 help="Path to the build directory. It must have already been configured.")
279build.add_argument(
280 '-n', '--dry-run',
281 dest='dry',
282 action='store_true',
283 default=False,
284 help="Print the build command instead of executing it.")
285build.add_argument(
286 '--build-flag',
287 dest='flags',
288 metavar='FLAG',
289 default=[],
290 action='append',
291 help="Additional flags for the build command (e.g. targets to build). "
292 "May be passed several times. If your flag starts with a '-', use "
293 "'--build-flag=-FLAG' to pass it.")
294build.set_defaults(run_command=run_build)
295
Diana Picusf73abbf2018-01-26 07:06:20 +0100296# Subcommand for setting up the test-suite
297setupTestSuite = subcommands.add_parser(
298 'setup-test-suite',
299 help="Prepare a sandbox for running the test-suite.")
300setupTestSuite.add_argument(
301 '--sandbox',
302 required=True,
303 help="Path where we should setup the sandbox.")
304setupTestSuite.add_argument(
305 '--lnt',
306 required=True,
307 help="Path to the LNT sources.")
308setupTestSuite.add_argument(
309 '-n', '--dry-run',
310 dest='dry',
311 action='store_true',
312 default=False,
313 help="Print the commands instead of executing them.")
314setupTestSuite.set_defaults(run_command=setup_the_test_suite)
315
Diana Picusb368cb62018-01-23 16:41:59 +0100316# Subcommand for running the test-suite
317runTestSuite = subcommands.add_parser(
318 'run-test-suite',
319 help="Run the test-suite in the given sandbox.")
320runTestSuite.add_argument(
321 '--sandbox',
322 required=True,
323 help="Path to the sandbox. It must point to a virtualenv with a LNT setup.")
324runTestSuite.add_argument(
325 '--test-suite',
326 dest="testsuite",
327 required=True,
328 help="Path to the test-suite repo.")
329runTestSuite.add_argument(
330 '--use-lit',
331 dest="lit",
332 required=True,
333 help="Path to llvm-lit.")
334runTestSuite.add_argument(
335 '--lnt-flag',
336 dest='flags',
337 metavar='FLAG',
338 default=[],
339 action='append',
340 help="Additional flags to be passed to LNT when running the test-suite."
341 "May be passed several times. If your flag starts with a '-', use "
342 "'--lnt-flag=-FLAG' to pass it.")
343runTestSuite.add_argument(
344 # We can pass --cc through the --lnt-flag interface, but we generally won't
345 # want to test the system compiler, so force the user to be specific.
346 '--cc',
347 required=True,
348 help="The path to the C compiler that we're testing.")
349runTestSuite.add_argument(
350 # For symmetry, we also provide a --cxx argument, but this one isn't
351 # required since LNT tries to guess it based on the value of --cc.
352 '--cxx',
353 required=False,
354 help="The path to the C++ compiler that we're testing.")
355runTestSuite.add_argument(
356 '-n', '--dry-run',
357 dest='dry',
358 action='store_true',
359 default=False,
360 help="Print the commands instead of executing them.")
361runTestSuite.set_defaults(run_command=run_the_test_suite)
362
Diana Picus3b2ef822016-10-13 16:53:18 +0300363args = options.parse_args()
Diana Picusadb07c42017-11-22 16:12:57 +0100364if args.subcommand == "projects" and args.add and not args.repos:
365 projs.error(
366 "When adding a subproject you must also pass the --repos argument")
Diana Picus3b2ef822016-10-13 16:53:18 +0300367args.run_command(args)