blob: 69edb30cbf46b4e446dd8f640dd38760f0c160c9 [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
Jack Rosenthal769a0512023-05-25 18:04:50 -06005"""build_packages updates the set of binary packages needed by ChromiumOS.
Cindy Linc06b4ea2022-01-27 18:13:04 +00006
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
Jack Rosenthal769a0512023-05-25 18:04:50 -060010bootable ChromiumOS image.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000011
Jack Rosenthal769a0512023-05-25 18:04:50 -060012If packages are specified in the command line, only build those specific
13packages and any dependencies they might need.
Cindy Linc06b4ea2022-01-27 18:13:04 +000014"""
15
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000016import argparse
Alex Kleinfba23ba2022-02-03 11:58:48 -070017import logging
Cindy Linc06b4ea2022-01-27 18:13:04 +000018import os
Mike Frysinger807d8282022-04-28 22:45:17 -040019from typing import List, Optional, Tuple
Alex Kleinfba23ba2022-02-03 11:58:48 -070020import urllib.error
21import urllib.request
Cindy Linc06b4ea2022-01-27 18:13:04 +000022
Cindy Lin7487daa2022-02-23 04:14:10 +000023from chromite.lib import build_target_lib
Alex Kleina39dc982022-02-03 12:13:14 -070024from chromite.lib import commandline
Cindy Linc06b4ea2022-01-27 18:13:04 +000025from chromite.lib import cros_build_lib
Cindy Lin7487daa2022-02-23 04:14:10 +000026from chromite.lib import sysroot_lib
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +000027from chromite.service import sysroot
Cindy Linb7f89a42022-05-23 16:50:00 +000028from chromite.utils import timer
Cindy Linc06b4ea2022-01-27 18:13:04 +000029
30
Alex Klein1699fab2022-09-08 08:46:06 -060031def build_shell_bool_style_args(
32 parser: commandline.ArgumentParser,
33 name: str,
34 default_val: bool,
35 help_str: str,
36 deprecation_note: str,
37 alternate_name: Optional[str] = None,
38) -> None:
39 """Build the shell boolean input argument equivalent.
Alex Kleina39dc982022-02-03 12:13:14 -070040
Alex Klein1699fab2022-09-08 08:46:06 -060041 There are two cases which we will need to handle,
42 case 1: A shell boolean arg, which doesn't need to be re-worded in python.
43 case 2: A shell boolean arg, which needs to be re-worded in python.
44 Example below.
45 For Case 1, for a given input arg name 'argA', we create three python
46 arguments.
47 --argA, --noargA, --no-argA. The arguments --argA and --no-argA will be
48 retained after deprecating --noargA.
49 For Case 2, for a given input arg name 'arg_A' we need to use alternate
50 argument name 'arg-A'. we create four python arguments in this case.
51 --arg_A, --noarg_A, --arg-A, --no-arg-A. The first two arguments will be
52 deprecated later.
53 TODO(b/218522717): Remove the creation of --noargA in case 1 and --arg_A and
54 --noarg_A in case 2.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000055
Alex Klein1699fab2022-09-08 08:46:06 -060056 Args:
Trent Apted66736d82023-05-25 10:38:28 +100057 parser: The parser to update.
58 name: The input argument name. This will be used as 'dest' variable
59 name.
60 default_val: The default value to assign.
61 help_str: The help string for the input argument.
62 deprecation_note: A deprecation note to use.
63 alternate_name: Alternate argument to be used after deprecation.
Alex Klein1699fab2022-09-08 08:46:06 -060064 """
65 arg = f"--{name}"
66 shell_narg = f"--no{name}"
67 py_narg = f"--no-{name}"
68 alt_arg = f"--{alternate_name}" if alternate_name else None
69 alt_py_narg = f"--no-{alternate_name}" if alternate_name else None
70 default_val_str = f"{help_str} (Default: %(default)s)."
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000071
Alex Klein1699fab2022-09-08 08:46:06 -060072 if alternate_name:
73 parser.add_argument(
74 alt_arg,
75 action="store_true",
76 default=default_val,
77 dest=name,
78 help=default_val_str,
79 )
80 parser.add_argument(
81 alt_py_narg,
82 action="store_false",
83 dest=name,
84 help="Don't " + help_str.lower(),
85 )
86
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000087 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060088 arg,
89 action="store_true",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000090 default=default_val,
91 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -060092 deprecated=deprecation_note % alt_arg if alternate_name else None,
93 help=default_val_str if not alternate_name else argparse.SUPPRESS,
94 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000095 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060096 shell_narg,
97 action="store_false",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000098 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -060099 deprecated=deprecation_note % alt_py_narg
100 if alternate_name
101 else py_narg,
102 help=argparse.SUPPRESS,
103 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000104
Alex Klein1699fab2022-09-08 08:46:06 -0600105 if not alternate_name:
106 parser.add_argument(
107 py_narg,
108 action="store_false",
109 dest=name,
110 help="Don't " + help_str.lower(),
111 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000112
113
114def get_parser() -> commandline.ArgumentParser:
Alex Klein1699fab2022-09-08 08:46:06 -0600115 """Creates the cmdline argparser, populates the options and description.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000116
Alex Klein1699fab2022-09-08 08:46:06 -0600117 Returns:
Trent Apted66736d82023-05-25 10:38:28 +1000118 Argument parser.
Alex Klein1699fab2022-09-08 08:46:06 -0600119 """
120 deprecation_note = "Argument will be removed July, 2022. Use %s instead."
121 parser = commandline.ArgumentParser(description=__doc__)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000122
Alex Klein1699fab2022-09-08 08:46:06 -0600123 parser.add_argument(
124 "-b",
125 "--board",
126 "--build-target",
127 dest="board",
128 default=cros_build_lib.GetDefaultBoard(),
129 help="The board to build packages for.",
130 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000131
Alex Klein1699fab2022-09-08 08:46:06 -0600132 build_shell_bool_style_args(
133 parser,
134 "usepkg",
135 True,
136 "Use binary packages to bootstrap when possible.",
137 deprecation_note,
138 )
139 build_shell_bool_style_args(
140 parser,
141 "usepkgonly",
142 False,
143 "Use binary packages only to bootstrap; abort if any are missing.",
144 deprecation_note,
145 )
146 build_shell_bool_style_args(
147 parser, "workon", True, "Force-build workon packages.", deprecation_note
148 )
149 build_shell_bool_style_args(
150 parser,
151 "withrevdeps",
152 True,
153 "Calculate reverse dependencies on changed ebuilds.",
154 deprecation_note,
155 )
156 build_shell_bool_style_args(
157 parser,
158 "cleanbuild",
159 False,
160 "Perform a clean build; delete sysroot if it exists before building.",
161 deprecation_note,
162 )
163 build_shell_bool_style_args(
164 parser,
165 "pretend",
166 False,
167 "Pretend building packages, just display which packages would have "
168 "been installed.",
169 deprecation_note,
170 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000171
Alex Klein1699fab2022-09-08 08:46:06 -0600172 # The --sysroot flag specifies the environment variables ROOT and PKGDIR.
173 # This allows fetching and emerging of all packages to specified sysroot.
174 # Note that --sysroot will setup the board normally in /build/$BOARD, if
175 # it's not setup yet. It also expects the toolchain to already be installed
176 # in the sysroot.
177 # --usepkgonly and --norebuild are required, because building is not
178 # supported when board_root is set.
179 parser.add_argument(
180 "--sysroot", type="path", help="Emerge packages to sysroot."
181 )
182 parser.add_argument(
183 "--board_root",
184 type="path",
185 dest="sysroot",
186 deprecated=deprecation_note % "--sysroot",
187 help=argparse.SUPPRESS,
188 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000189
Alex Klein1699fab2022-09-08 08:46:06 -0600190 # CPU Governor related options.
191 group = parser.add_argument_group("CPU Governor Options")
192 build_shell_bool_style_args(
193 group,
194 "autosetgov",
195 False,
196 "Automatically set cpu governor to 'performance'.",
197 deprecation_note,
198 )
199 build_shell_bool_style_args(
200 group,
201 "autosetgov_sticky",
202 False,
203 "Remember --autosetgov setting for future runs.",
204 deprecation_note,
205 alternate_name="autosetgov-sticky",
206 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000207
Alex Klein1699fab2022-09-08 08:46:06 -0600208 # Chrome building related options.
209 group = parser.add_argument_group("Chrome Options")
210 build_shell_bool_style_args(
211 group,
212 "use_any_chrome",
213 True,
214 "Use any Chrome prebuilt available, even if the prebuilt doesn't "
215 "match exactly.",
216 deprecation_note,
217 alternate_name="use-any-chrome",
218 )
219 build_shell_bool_style_args(
220 group,
221 "internal",
222 False,
Alex Kleind7197402023-04-05 13:05:29 -0600223 "Build the internal version of chrome (set the chrome_internal USE "
224 "flag).",
Alex Klein1699fab2022-09-08 08:46:06 -0600225 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(),
Trent Apted66736d82023-05-25 10:38:28 +1000326 help="Number of packages to build in parallel. (Default: %(default)s)",
Alex Klein1699fab2022-09-08 08:46:06 -0600327 )
328 build_shell_bool_style_args(
329 group,
330 "rebuild",
331 True,
332 "Automatically rebuild dependencies.",
333 deprecation_note,
334 )
335 # TODO(b/218522717): Remove the --nonorebuild argument support.
336 group.add_argument(
337 "--nonorebuild",
338 action="store_true",
339 dest="rebuild",
340 deprecated=deprecation_note % "--rebuild",
341 help=argparse.SUPPRESS,
342 )
343 build_shell_bool_style_args(
344 group,
345 "expandedbinhosts",
346 True,
347 "Allow expanded binhost inheritance.",
348 deprecation_note,
349 )
350 group.add_argument(
351 "--backtrack",
352 type=int,
353 default=sysroot.BACKTRACK_DEFAULT,
354 help="See emerge --backtrack.",
355 )
Alex Klein062d7282022-07-28 09:03:26 -0600356
Alex Klein1699fab2022-09-08 08:46:06 -0600357 # The --reuse-pkgs-from-local-boards flag tells Portage to share binary
358 # packages between boards that are built locally, so that the total time
359 # required to build several boards is reduced. This flag is only useful
360 # when you are not able to use remote binary packages, since remote binary
361 # packages are usually more up to date than anything you have locally.
362 build_shell_bool_style_args(
363 group,
364 "reuse_pkgs_from_local_boards",
365 False,
366 "Bootstrap from local packages instead of remote packages.",
367 deprecation_note,
368 alternate_name="reuse-pkgs-from-local-boards",
369 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000370
Alex Klein1699fab2022-09-08 08:46:06 -0600371 # --run-goma option is designed to be used on bots.
Alex Kleind7197402023-04-05 13:05:29 -0600372 # If you're trying to build packages with goma in your local dev env, this
373 # is *not* the option you're looking for. Please see comments below.
Alex Klein1699fab2022-09-08 08:46:06 -0600374 # This option; 1) starts goma, 2) builds packages (expecting that goma is
375 # used), then 3) stops goma explicitly.
376 # 4) is a request from the goma team, so that stats/logs can be taken.
Fumitoshi Ukai00becd42023-01-13 12:51:26 +0900377 # Note: GOMA_DIR is expected to be passed via env var.
Alex Klein1699fab2022-09-08 08:46:06 -0600378 #
379 # In local dev env cases, compiler_proxy is expected to keep running.
380 # In such a case;
381 # $ python ${GOMA_DIR}/goma_ctl.py ensure_start
382 # $ build_packages (... and options without --run-goma ...)
383 # is an expected commandline sequence. If you set --run-goma flag while
384 # compiler_proxy is already running, the existing compiler_proxy will be
385 # stopped.
386 build_shell_bool_style_args(
387 group,
388 "run_goma",
389 False,
Alex Kleind7197402023-04-05 13:05:29 -0600390 "When set, (re)starts goma, builds packages, and then stops goma.",
Alex Klein1699fab2022-09-08 08:46:06 -0600391 deprecation_note,
392 alternate_name="run-goma",
393 )
394 # This option is for building chrome remotely.
395 # 1) starts reproxy 2) builds chrome with reproxy and 3) stops reproxy so
396 # logs/stats can be collected.
397 # Note: RECLIENT_DIR and REPROXY_CFG env var will be deprecated July, 2022.
398 # Use --reclient-dir and --reproxy-cfg input options instead.
399 build_shell_bool_style_args(
400 group,
401 "run_remoteexec",
402 False,
403 "If set to true, starts RBE reproxy, builds packages, and then stops "
404 "reproxy.",
405 deprecation_note,
406 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000407
Alex Klein1699fab2022-09-08 08:46:06 -0600408 parser.add_argument("packages", nargs="*", help="Packages to build.")
409 return parser
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000410
411
Alex Klein1699fab2022-09-08 08:46:06 -0600412def parse_args(
413 argv: List[str],
414) -> Tuple[commandline.ArgumentParser, commandline.ArgumentNamespace]:
415 """Parse and validate CLI arguments.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000416
Alex Klein1699fab2022-09-08 08:46:06 -0600417 Args:
Trent Apted66736d82023-05-25 10:38:28 +1000418 argv: Arguments passed via CLI.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000419
Alex Klein1699fab2022-09-08 08:46:06 -0600420 Returns:
Trent Apted66736d82023-05-25 10:38:28 +1000421 Tuple having the below two,
422 Argument Parser
423 Validated argument namespace.
Alex Klein1699fab2022-09-08 08:46:06 -0600424 """
425 parser = get_parser()
426 opts = parser.parse_args(argv)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000427
Alex Klein1699fab2022-09-08 08:46:06 -0600428 if opts.chrome:
429 opts.internal_chrome = True
430 opts.use_any_chrome = False
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000431
Alex Klein1699fab2022-09-08 08:46:06 -0600432 opts.setup_board_run_config = sysroot.SetupBoardRunConfig(
433 force=opts.cleanbuild,
434 usepkg=opts.usepkg,
435 jobs=opts.jobs,
436 quiet=True,
437 update_toolchain=not opts.skip_toolchain_update,
438 upgrade_chroot=not opts.skip_chroot_upgrade,
439 local_build=opts.reuse_pkgs_from_local_boards,
440 expanded_binhost_inheritance=opts.expandedbinhosts,
Cindy Linadc610a2023-05-23 18:46:12 +0000441 use_cq_prebuilts=opts.usepkg,
Alex Klein1699fab2022-09-08 08:46:06 -0600442 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 Kleind7197402023-04-05 13:05:29 -0600479 # If the opts.board is not set, then it means user hasn't specified a
480 # default board in 'src/scripts/.default_board' and didn't specify it as
481 # input argument.
Alex Klein1699fab2022-09-08 08:46:06 -0600482 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 )
Sergey Frolovf988de72023-03-06 20:05:21 -0700499
Alex Klein1699fab2022-09-08 08:46:06 -0600500 sysroot.BuildPackages(build_target, board_root, opts.build_run_config)
501 except sysroot_lib.PackageInstallError as e:
502 try:
503 with urllib.request.urlopen(
504 "https://chromiumos-status.appspot.com/current?format=raw"
Sergey Frolov7cf6c0b2022-06-06 16:47:44 -0600505 ) as request:
Alex Klein1699fab2022-09-08 08:46:06 -0600506 logging.notice("Tree Status: %s", request.read().decode())
507 except urllib.error.HTTPError:
508 pass
509 cros_build_lib.Die(e)