blob: 20b156f118ebaf639c34459651586c99a1bc7326 [file] [log] [blame]
Mike Frysingerf1ba7ad2022-09-12 05:42:57 -04001# Copyright 2022 The ChromiumOS Authors
Cindy Linc06b4ea2022-01-27 18:13:04 +00002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""build_packages updates the set of binary packages needed by Chrome OS.
6
7The build_packages process cross compiles all packages that have been
8updated into the given sysroot and builds binary packages as a side-effect.
9The output packages will be used by the build_image script to create a
10bootable Chrome OS image.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000011
12If packages are specified in cli, only build those specific packages and any
13dependencies they might need.
14
15For the fastest builds, use --nowithautotest --noworkon.
Cindy Linc06b4ea2022-01-27 18:13:04 +000016"""
17
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000018import argparse
Alex Kleinfba23ba2022-02-03 11:58:48 -070019import logging
Cindy Linc06b4ea2022-01-27 18:13:04 +000020import os
Mike Frysinger807d8282022-04-28 22:45:17 -040021from typing import List, Optional, Tuple
Alex Kleinfba23ba2022-02-03 11:58:48 -070022import urllib.error
23import urllib.request
Cindy Linc06b4ea2022-01-27 18:13:04 +000024
Cindy Lin7487daa2022-02-23 04:14:10 +000025from chromite.lib import build_target_lib
Alex Kleina39dc982022-02-03 12:13:14 -070026from chromite.lib import commandline
Cindy Linc06b4ea2022-01-27 18:13:04 +000027from chromite.lib import cros_build_lib
Cindy Lin7487daa2022-02-23 04:14:10 +000028from chromite.lib import sysroot_lib
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +000029from chromite.service import sysroot
Cindy Linb7f89a42022-05-23 16:50:00 +000030from chromite.utils import timer
Cindy Linc06b4ea2022-01-27 18:13:04 +000031
32
Alex Klein1699fab2022-09-08 08:46:06 -060033def build_shell_bool_style_args(
34 parser: commandline.ArgumentParser,
35 name: str,
36 default_val: bool,
37 help_str: str,
38 deprecation_note: str,
39 alternate_name: Optional[str] = None,
40) -> None:
41 """Build the shell boolean input argument equivalent.
Alex Kleina39dc982022-02-03 12:13:14 -070042
Alex Klein1699fab2022-09-08 08:46:06 -060043 There are two cases which we will need to handle,
44 case 1: A shell boolean arg, which doesn't need to be re-worded in python.
45 case 2: A shell boolean arg, which needs to be re-worded in python.
46 Example below.
47 For Case 1, for a given input arg name 'argA', we create three python
48 arguments.
49 --argA, --noargA, --no-argA. The arguments --argA and --no-argA will be
50 retained after deprecating --noargA.
51 For Case 2, for a given input arg name 'arg_A' we need to use alternate
52 argument name 'arg-A'. we create four python arguments in this case.
53 --arg_A, --noarg_A, --arg-A, --no-arg-A. The first two arguments will be
54 deprecated later.
55 TODO(b/218522717): Remove the creation of --noargA in case 1 and --arg_A and
56 --noarg_A in case 2.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000057
Alex Klein1699fab2022-09-08 08:46:06 -060058 Args:
59 parser: The parser to update.
60 name: The input argument name. This will be used as 'dest' variable name.
61 default_val: The default value to assign.
62 help_str: The help string for the input argument.
63 deprecation_note: A deprecation note to use.
64 alternate_name: Alternate argument to be used after deprecation.
65 """
66 arg = f"--{name}"
67 shell_narg = f"--no{name}"
68 py_narg = f"--no-{name}"
69 alt_arg = f"--{alternate_name}" if alternate_name else None
70 alt_py_narg = f"--no-{alternate_name}" if alternate_name else None
71 default_val_str = f"{help_str} (Default: %(default)s)."
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000072
Alex Klein1699fab2022-09-08 08:46:06 -060073 if alternate_name:
74 parser.add_argument(
75 alt_arg,
76 action="store_true",
77 default=default_val,
78 dest=name,
79 help=default_val_str,
80 )
81 parser.add_argument(
82 alt_py_narg,
83 action="store_false",
84 dest=name,
85 help="Don't " + help_str.lower(),
86 )
87
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000088 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060089 arg,
90 action="store_true",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000091 default=default_val,
92 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -060093 deprecated=deprecation_note % alt_arg if alternate_name else None,
94 help=default_val_str if not alternate_name else argparse.SUPPRESS,
95 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000096 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060097 shell_narg,
98 action="store_false",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000099 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -0600100 deprecated=deprecation_note % alt_py_narg
101 if alternate_name
102 else py_narg,
103 help=argparse.SUPPRESS,
104 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000105
Alex Klein1699fab2022-09-08 08:46:06 -0600106 if not alternate_name:
107 parser.add_argument(
108 py_narg,
109 action="store_false",
110 dest=name,
111 help="Don't " + help_str.lower(),
112 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000113
114
115def get_parser() -> commandline.ArgumentParser:
Alex Klein1699fab2022-09-08 08:46:06 -0600116 """Creates the cmdline argparser, populates the options and description.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000117
Alex Klein1699fab2022-09-08 08:46:06 -0600118 Returns:
119 Argument parser.
120 """
121 deprecation_note = "Argument will be removed July, 2022. Use %s instead."
122 parser = commandline.ArgumentParser(description=__doc__)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000123
Alex Klein1699fab2022-09-08 08:46:06 -0600124 parser.add_argument(
125 "-b",
126 "--board",
127 "--build-target",
128 dest="board",
129 default=cros_build_lib.GetDefaultBoard(),
130 help="The board to build packages for.",
131 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000132
Alex Klein1699fab2022-09-08 08:46:06 -0600133 build_shell_bool_style_args(
134 parser,
135 "usepkg",
136 True,
137 "Use binary packages to bootstrap when possible.",
138 deprecation_note,
139 )
140 build_shell_bool_style_args(
141 parser,
142 "usepkgonly",
143 False,
144 "Use binary packages only to bootstrap; abort if any are missing.",
145 deprecation_note,
146 )
147 build_shell_bool_style_args(
148 parser, "workon", True, "Force-build workon packages.", deprecation_note
149 )
150 build_shell_bool_style_args(
151 parser,
152 "withrevdeps",
153 True,
154 "Calculate reverse dependencies on changed ebuilds.",
155 deprecation_note,
156 )
157 build_shell_bool_style_args(
158 parser,
159 "cleanbuild",
160 False,
161 "Perform a clean build; delete sysroot if it exists before building.",
162 deprecation_note,
163 )
164 build_shell_bool_style_args(
165 parser,
166 "pretend",
167 False,
168 "Pretend building packages, just display which packages would have "
169 "been installed.",
170 deprecation_note,
171 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000172
Alex Klein1699fab2022-09-08 08:46:06 -0600173 # The --sysroot flag specifies the environment variables ROOT and PKGDIR.
174 # This allows fetching and emerging of all packages to specified sysroot.
175 # Note that --sysroot will setup the board normally in /build/$BOARD, if
176 # it's not setup yet. It also expects the toolchain to already be installed
177 # in the sysroot.
178 # --usepkgonly and --norebuild are required, because building is not
179 # supported when board_root is set.
180 parser.add_argument(
181 "--sysroot", type="path", help="Emerge packages to sysroot."
182 )
183 parser.add_argument(
184 "--board_root",
185 type="path",
186 dest="sysroot",
187 deprecated=deprecation_note % "--sysroot",
188 help=argparse.SUPPRESS,
189 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000190
Alex Klein1699fab2022-09-08 08:46:06 -0600191 # CPU Governor related options.
192 group = parser.add_argument_group("CPU Governor Options")
193 build_shell_bool_style_args(
194 group,
195 "autosetgov",
196 False,
197 "Automatically set cpu governor to 'performance'.",
198 deprecation_note,
199 )
200 build_shell_bool_style_args(
201 group,
202 "autosetgov_sticky",
203 False,
204 "Remember --autosetgov setting for future runs.",
205 deprecation_note,
206 alternate_name="autosetgov-sticky",
207 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000208
Alex Klein1699fab2022-09-08 08:46:06 -0600209 # Chrome building related options.
210 group = parser.add_argument_group("Chrome Options")
211 build_shell_bool_style_args(
212 group,
213 "use_any_chrome",
214 True,
215 "Use any Chrome prebuilt available, even if the prebuilt doesn't "
216 "match exactly.",
217 deprecation_note,
218 alternate_name="use-any-chrome",
219 )
220 build_shell_bool_style_args(
221 group,
222 "internal",
223 False,
224 "Build the internal version of chrome(set the chrome_internal USE flag).",
225 deprecation_note,
226 )
227 build_shell_bool_style_args(
228 group,
229 "chrome",
230 False,
231 "Ensure chrome instead of chromium. Alias for "
232 "--internal --no-use-any-chrome.",
233 deprecation_note,
234 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000235
Alex Klein1699fab2022-09-08 08:46:06 -0600236 # Setup board related options.
237 group = parser.add_argument_group("Setup Board Config Options")
238 build_shell_bool_style_args(
239 group,
240 "skip_chroot_upgrade",
241 False,
242 "Skip the automatic chroot upgrade; use with care.",
243 deprecation_note,
244 alternate_name="skip-chroot-upgrade",
245 )
246 build_shell_bool_style_args(
247 group,
248 "skip_toolchain_update",
249 False,
250 "Skip automatic toolchain update",
251 deprecation_note,
252 alternate_name="skip-toolchain-update",
253 )
254 build_shell_bool_style_args(
255 group,
256 "skip_setup_board",
257 False,
258 "Skip running setup_board. Implies "
259 "--skip-chroot-upgrade --skip-toolchain-update.",
260 deprecation_note,
261 alternate_name="skip-setup-board",
262 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000263
Alex Klein1699fab2022-09-08 08:46:06 -0600264 # Image Type selection related options.
265 group = parser.add_argument_group("Image Type Options")
266 build_shell_bool_style_args(
267 group,
268 "withdev",
269 True,
270 "Build useful developer friendly utilities.",
271 deprecation_note,
272 )
273 build_shell_bool_style_args(
274 group,
275 "withdebug",
276 True,
277 "Build debug versions of Chromium-OS-specific packages.",
278 deprecation_note,
279 )
280 build_shell_bool_style_args(
281 group, "withfactory", True, "Build factory installer.", deprecation_note
282 )
283 build_shell_bool_style_args(
284 group,
285 "withtest",
286 True,
287 "Build packages required for testing.",
288 deprecation_note,
289 )
290 build_shell_bool_style_args(
291 group,
292 "withautotest",
293 True,
294 "Build autotest client code.",
295 deprecation_note,
296 )
297 build_shell_bool_style_args(
298 group,
299 "withdebugsymbols",
300 False,
301 "Install the debug symbols for all packages.",
302 deprecation_note,
303 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000304
Alex Klein1699fab2022-09-08 08:46:06 -0600305 # Advanced Options.
306 group = parser.add_argument_group("Advanced Options")
307 group.add_argument(
308 "--accept-licenses", help="Licenses to append to the accept list."
309 )
310 group.add_argument(
311 "--accept_licenses",
312 deprecated=deprecation_note % "--accept-licenses",
313 help=argparse.SUPPRESS,
314 )
315 build_shell_bool_style_args(
316 group,
317 "eclean",
318 True,
319 "Run eclean to delete old binpkgs.",
320 deprecation_note,
321 )
322 group.add_argument(
323 "--jobs",
324 type=int,
325 default=os.cpu_count(),
326 help="Number of packages to build in parallel. "
327 "(Default: %(default)s)",
328 )
329 build_shell_bool_style_args(
330 group,
331 "rebuild",
332 True,
333 "Automatically rebuild dependencies.",
334 deprecation_note,
335 )
336 # TODO(b/218522717): Remove the --nonorebuild argument support.
337 group.add_argument(
338 "--nonorebuild",
339 action="store_true",
340 dest="rebuild",
341 deprecated=deprecation_note % "--rebuild",
342 help=argparse.SUPPRESS,
343 )
344 build_shell_bool_style_args(
345 group,
346 "expandedbinhosts",
347 True,
348 "Allow expanded binhost inheritance.",
349 deprecation_note,
350 )
351 group.add_argument(
352 "--backtrack",
353 type=int,
354 default=sysroot.BACKTRACK_DEFAULT,
355 help="See emerge --backtrack.",
356 )
Alex Klein062d7282022-07-28 09:03:26 -0600357
Alex Klein1699fab2022-09-08 08:46:06 -0600358 # The --reuse-pkgs-from-local-boards flag tells Portage to share binary
359 # packages between boards that are built locally, so that the total time
360 # required to build several boards is reduced. This flag is only useful
361 # when you are not able to use remote binary packages, since remote binary
362 # packages are usually more up to date than anything you have locally.
363 build_shell_bool_style_args(
364 group,
365 "reuse_pkgs_from_local_boards",
366 False,
367 "Bootstrap from local packages instead of remote packages.",
368 deprecation_note,
369 alternate_name="reuse-pkgs-from-local-boards",
370 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000371
Alex Klein1699fab2022-09-08 08:46:06 -0600372 # --run-goma option is designed to be used on bots.
373 # If you're trying to build packages with goma in your local dev env, this is
374 # *not* the option you're looking for. Please see comments below.
375 # This option; 1) starts goma, 2) builds packages (expecting that goma is
376 # used), then 3) stops goma explicitly.
377 # 4) is a request from the goma team, so that stats/logs can be taken.
Fumitoshi Ukai00becd42023-01-13 12:51:26 +0900378 # Note: GOMA_DIR is expected to be passed via env var.
Alex Klein1699fab2022-09-08 08:46:06 -0600379 #
380 # In local dev env cases, compiler_proxy is expected to keep running.
381 # In such a case;
382 # $ python ${GOMA_DIR}/goma_ctl.py ensure_start
383 # $ build_packages (... and options without --run-goma ...)
384 # is an expected commandline sequence. If you set --run-goma flag while
385 # compiler_proxy is already running, the existing compiler_proxy will be
386 # stopped.
387 build_shell_bool_style_args(
388 group,
389 "run_goma",
390 False,
391 "If set to true, (re)starts goma, builds packages, and then stops goma..",
392 deprecation_note,
393 alternate_name="run-goma",
394 )
395 # This option is for building chrome remotely.
396 # 1) starts reproxy 2) builds chrome with reproxy and 3) stops reproxy so
397 # logs/stats can be collected.
398 # Note: RECLIENT_DIR and REPROXY_CFG env var will be deprecated July, 2022.
399 # Use --reclient-dir and --reproxy-cfg input options instead.
400 build_shell_bool_style_args(
401 group,
402 "run_remoteexec",
403 False,
404 "If set to true, starts RBE reproxy, builds packages, and then stops "
405 "reproxy.",
406 deprecation_note,
407 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000408
Alex Klein1699fab2022-09-08 08:46:06 -0600409 parser.add_argument("packages", nargs="*", help="Packages to build.")
410 return parser
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000411
412
Alex Klein1699fab2022-09-08 08:46:06 -0600413def parse_args(
414 argv: List[str],
415) -> Tuple[commandline.ArgumentParser, commandline.ArgumentNamespace]:
416 """Parse and validate CLI arguments.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000417
Alex Klein1699fab2022-09-08 08:46:06 -0600418 Args:
419 argv: Arguments passed via CLI.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000420
Alex Klein1699fab2022-09-08 08:46:06 -0600421 Returns:
422 Tuple having the below two,
423 Argument Parser
424 Validated argument namespace.
425 """
426 parser = get_parser()
427 opts = parser.parse_args(argv)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000428
Alex Klein1699fab2022-09-08 08:46:06 -0600429 if opts.chrome:
430 opts.internal_chrome = True
431 opts.use_any_chrome = False
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000432
Alex Klein1699fab2022-09-08 08:46:06 -0600433 opts.setup_board_run_config = sysroot.SetupBoardRunConfig(
434 force=opts.cleanbuild,
435 usepkg=opts.usepkg,
436 jobs=opts.jobs,
437 quiet=True,
438 update_toolchain=not opts.skip_toolchain_update,
439 upgrade_chroot=not opts.skip_chroot_upgrade,
440 local_build=opts.reuse_pkgs_from_local_boards,
441 expanded_binhost_inheritance=opts.expandedbinhosts,
442 backtrack=opts.backtrack,
443 )
444 opts.build_run_config = sysroot.BuildPackagesRunConfig(
445 usepkg=opts.usepkg,
446 install_debug_symbols=opts.withdebugsymbols,
447 packages=opts.packages,
448 use_goma=opts.run_goma,
449 use_remoteexec=opts.run_remoteexec,
450 incremental_build=opts.withrevdeps,
451 dryrun=opts.pretend,
452 usepkgonly=opts.usepkgonly,
453 workon=opts.workon,
454 install_auto_test=opts.withautotest,
455 autosetgov=opts.autosetgov,
456 autosetgov_sticky=opts.autosetgov_sticky,
457 use_any_chrome=opts.use_any_chrome,
458 internal_chrome=opts.internal,
459 clean_build=opts.cleanbuild,
460 eclean=opts.eclean,
461 rebuild_dep=opts.rebuild,
462 jobs=opts.jobs,
463 local_pkg=opts.reuse_pkgs_from_local_boards,
464 dev_image=opts.withdev,
465 factory_image=opts.withfactory,
466 test_image=opts.withtest,
467 debug_version=opts.withdebug,
468 backtrack=opts.backtrack,
469 )
470 opts.Freeze()
471 return parser, opts
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000472
473
Alex Klein1699fab2022-09-08 08:46:06 -0600474@timer.timed("Elapsed time (build_packages)")
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000475def main(argv: Optional[List[str]] = None) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600476 commandline.RunInsideChroot()
477 parser, opts = parse_args(argv)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000478
Alex Klein1699fab2022-09-08 08:46:06 -0600479 # If the opts.board is not set, then it means user hasn't specified a default
480 # board in 'src/scripts/.default_board' and didn't specify it as input
481 # argument.
482 if not opts.board:
483 parser.error("--board is required")
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000484
Alex Klein1699fab2022-09-08 08:46:06 -0600485 build_target = build_target_lib.BuildTarget(
486 opts.board, build_root=opts.sysroot
487 )
488 board_root = sysroot_lib.Sysroot(build_target.root)
Cindy Lin7487daa2022-02-23 04:14:10 +0000489
Alex Kleinfba23ba2022-02-03 11:58:48 -0700490 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600491 # TODO(xcl): Update run_configs to have a common base set of configs for
492 # setup_board and build_packages.
493 if not opts.skip_setup_board:
494 sysroot.SetupBoard(
495 build_target,
496 accept_licenses=opts.accept_licenses,
497 run_configs=opts.setup_board_run_config,
498 )
499 sysroot.BuildPackages(build_target, board_root, opts.build_run_config)
500 except sysroot_lib.PackageInstallError as e:
501 try:
502 with urllib.request.urlopen(
503 "https://chromiumos-status.appspot.com/current?format=raw"
Sergey Frolov7cf6c0b2022-06-06 16:47:44 -0600504 ) as request:
Alex Klein1699fab2022-09-08 08:46:06 -0600505 logging.notice("Tree Status: %s", request.read().decode())
506 except urllib.error.HTTPError:
507 pass
508 cros_build_lib.Die(e)