blob: 94e7d05dac08e6df0ad15b2ef9772ac7efb1b7b4 [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,
Alex Kleind7197402023-04-05 13:05:29 -0600224 "Build the internal version of chrome (set the chrome_internal USE "
225 "flag).",
Alex Klein1699fab2022-09-08 08:46:06 -0600226 deprecation_note,
227 )
228 build_shell_bool_style_args(
229 group,
230 "chrome",
231 False,
232 "Ensure chrome instead of chromium. Alias for "
233 "--internal --no-use-any-chrome.",
234 deprecation_note,
235 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000236
Alex Klein1699fab2022-09-08 08:46:06 -0600237 # Setup board related options.
238 group = parser.add_argument_group("Setup Board Config Options")
239 build_shell_bool_style_args(
240 group,
241 "skip_chroot_upgrade",
242 False,
243 "Skip the automatic chroot upgrade; use with care.",
244 deprecation_note,
245 alternate_name="skip-chroot-upgrade",
246 )
247 build_shell_bool_style_args(
248 group,
249 "skip_toolchain_update",
250 False,
251 "Skip automatic toolchain update",
252 deprecation_note,
253 alternate_name="skip-toolchain-update",
254 )
255 build_shell_bool_style_args(
256 group,
257 "skip_setup_board",
258 False,
259 "Skip running setup_board. Implies "
260 "--skip-chroot-upgrade --skip-toolchain-update.",
261 deprecation_note,
262 alternate_name="skip-setup-board",
263 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000264
Alex Klein1699fab2022-09-08 08:46:06 -0600265 # Image Type selection related options.
266 group = parser.add_argument_group("Image Type Options")
267 build_shell_bool_style_args(
268 group,
269 "withdev",
270 True,
271 "Build useful developer friendly utilities.",
272 deprecation_note,
273 )
274 build_shell_bool_style_args(
275 group,
276 "withdebug",
277 True,
278 "Build debug versions of Chromium-OS-specific packages.",
279 deprecation_note,
280 )
281 build_shell_bool_style_args(
282 group, "withfactory", True, "Build factory installer.", deprecation_note
283 )
284 build_shell_bool_style_args(
285 group,
286 "withtest",
287 True,
288 "Build packages required for testing.",
289 deprecation_note,
290 )
291 build_shell_bool_style_args(
292 group,
293 "withautotest",
294 True,
295 "Build autotest client code.",
296 deprecation_note,
297 )
298 build_shell_bool_style_args(
299 group,
300 "withdebugsymbols",
301 False,
302 "Install the debug symbols for all packages.",
303 deprecation_note,
304 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000305
Alex Klein1699fab2022-09-08 08:46:06 -0600306 # Advanced Options.
307 group = parser.add_argument_group("Advanced Options")
308 group.add_argument(
309 "--accept-licenses", help="Licenses to append to the accept list."
310 )
311 group.add_argument(
312 "--accept_licenses",
313 deprecated=deprecation_note % "--accept-licenses",
314 help=argparse.SUPPRESS,
315 )
316 build_shell_bool_style_args(
317 group,
318 "eclean",
319 True,
320 "Run eclean to delete old binpkgs.",
321 deprecation_note,
322 )
323 group.add_argument(
324 "--jobs",
325 type=int,
326 default=os.cpu_count(),
327 help="Number of packages to build in parallel. "
328 "(Default: %(default)s)",
329 )
330 build_shell_bool_style_args(
331 group,
332 "rebuild",
333 True,
334 "Automatically rebuild dependencies.",
335 deprecation_note,
336 )
337 # TODO(b/218522717): Remove the --nonorebuild argument support.
338 group.add_argument(
339 "--nonorebuild",
340 action="store_true",
341 dest="rebuild",
342 deprecated=deprecation_note % "--rebuild",
343 help=argparse.SUPPRESS,
344 )
345 build_shell_bool_style_args(
346 group,
347 "expandedbinhosts",
348 True,
349 "Allow expanded binhost inheritance.",
350 deprecation_note,
351 )
352 group.add_argument(
353 "--backtrack",
354 type=int,
355 default=sysroot.BACKTRACK_DEFAULT,
356 help="See emerge --backtrack.",
357 )
Alex Klein062d7282022-07-28 09:03:26 -0600358
Alex Klein1699fab2022-09-08 08:46:06 -0600359 # The --reuse-pkgs-from-local-boards flag tells Portage to share binary
360 # packages between boards that are built locally, so that the total time
361 # required to build several boards is reduced. This flag is only useful
362 # when you are not able to use remote binary packages, since remote binary
363 # packages are usually more up to date than anything you have locally.
364 build_shell_bool_style_args(
365 group,
366 "reuse_pkgs_from_local_boards",
367 False,
368 "Bootstrap from local packages instead of remote packages.",
369 deprecation_note,
370 alternate_name="reuse-pkgs-from-local-boards",
371 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000372
Alex Klein1699fab2022-09-08 08:46:06 -0600373 # --run-goma option is designed to be used on bots.
Alex Kleind7197402023-04-05 13:05:29 -0600374 # If you're trying to build packages with goma in your local dev env, this
375 # is *not* the option you're looking for. Please see comments below.
Alex Klein1699fab2022-09-08 08:46:06 -0600376 # This option; 1) starts goma, 2) builds packages (expecting that goma is
377 # used), then 3) stops goma explicitly.
378 # 4) is a request from the goma team, so that stats/logs can be taken.
Fumitoshi Ukai00becd42023-01-13 12:51:26 +0900379 # Note: GOMA_DIR is expected to be passed via env var.
Alex Klein1699fab2022-09-08 08:46:06 -0600380 #
381 # In local dev env cases, compiler_proxy is expected to keep running.
382 # In such a case;
383 # $ python ${GOMA_DIR}/goma_ctl.py ensure_start
384 # $ build_packages (... and options without --run-goma ...)
385 # is an expected commandline sequence. If you set --run-goma flag while
386 # compiler_proxy is already running, the existing compiler_proxy will be
387 # stopped.
388 build_shell_bool_style_args(
389 group,
390 "run_goma",
391 False,
Alex Kleind7197402023-04-05 13:05:29 -0600392 "When set, (re)starts goma, builds packages, and then stops goma.",
Alex Klein1699fab2022-09-08 08:46:06 -0600393 deprecation_note,
394 alternate_name="run-goma",
395 )
396 # This option is for building chrome remotely.
397 # 1) starts reproxy 2) builds chrome with reproxy and 3) stops reproxy so
398 # logs/stats can be collected.
399 # Note: RECLIENT_DIR and REPROXY_CFG env var will be deprecated July, 2022.
400 # Use --reclient-dir and --reproxy-cfg input options instead.
401 build_shell_bool_style_args(
402 group,
403 "run_remoteexec",
404 False,
405 "If set to true, starts RBE reproxy, builds packages, and then stops "
406 "reproxy.",
407 deprecation_note,
408 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000409
Alex Klein1699fab2022-09-08 08:46:06 -0600410 parser.add_argument("packages", nargs="*", help="Packages to build.")
411 return parser
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000412
413
Alex Klein1699fab2022-09-08 08:46:06 -0600414def parse_args(
415 argv: List[str],
416) -> Tuple[commandline.ArgumentParser, commandline.ArgumentNamespace]:
417 """Parse and validate CLI arguments.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000418
Alex Klein1699fab2022-09-08 08:46:06 -0600419 Args:
420 argv: Arguments passed via CLI.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000421
Alex Klein1699fab2022-09-08 08:46:06 -0600422 Returns:
423 Tuple having the below two,
424 Argument Parser
425 Validated argument namespace.
426 """
427 parser = get_parser()
428 opts = parser.parse_args(argv)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000429
Alex Klein1699fab2022-09-08 08:46:06 -0600430 if opts.chrome:
431 opts.internal_chrome = True
432 opts.use_any_chrome = False
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000433
Alex Klein1699fab2022-09-08 08:46:06 -0600434 opts.setup_board_run_config = sysroot.SetupBoardRunConfig(
435 force=opts.cleanbuild,
436 usepkg=opts.usepkg,
437 jobs=opts.jobs,
438 quiet=True,
439 update_toolchain=not opts.skip_toolchain_update,
440 upgrade_chroot=not opts.skip_chroot_upgrade,
441 local_build=opts.reuse_pkgs_from_local_boards,
442 expanded_binhost_inheritance=opts.expandedbinhosts,
Cindy Linadc610a2023-05-23 18:46:12 +0000443 use_cq_prebuilts=opts.usepkg,
Alex Klein1699fab2022-09-08 08:46:06 -0600444 backtrack=opts.backtrack,
445 )
446 opts.build_run_config = sysroot.BuildPackagesRunConfig(
447 usepkg=opts.usepkg,
448 install_debug_symbols=opts.withdebugsymbols,
449 packages=opts.packages,
450 use_goma=opts.run_goma,
451 use_remoteexec=opts.run_remoteexec,
452 incremental_build=opts.withrevdeps,
453 dryrun=opts.pretend,
454 usepkgonly=opts.usepkgonly,
455 workon=opts.workon,
456 install_auto_test=opts.withautotest,
457 autosetgov=opts.autosetgov,
458 autosetgov_sticky=opts.autosetgov_sticky,
459 use_any_chrome=opts.use_any_chrome,
460 internal_chrome=opts.internal,
461 clean_build=opts.cleanbuild,
462 eclean=opts.eclean,
463 rebuild_dep=opts.rebuild,
464 jobs=opts.jobs,
465 local_pkg=opts.reuse_pkgs_from_local_boards,
466 dev_image=opts.withdev,
467 factory_image=opts.withfactory,
468 test_image=opts.withtest,
469 debug_version=opts.withdebug,
470 backtrack=opts.backtrack,
471 )
472 opts.Freeze()
473 return parser, opts
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000474
475
Alex Klein1699fab2022-09-08 08:46:06 -0600476@timer.timed("Elapsed time (build_packages)")
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000477def main(argv: Optional[List[str]] = None) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600478 commandline.RunInsideChroot()
479 parser, opts = parse_args(argv)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000480
Alex Kleind7197402023-04-05 13:05:29 -0600481 # If the opts.board is not set, then it means user hasn't specified a
482 # default board in 'src/scripts/.default_board' and didn't specify it as
483 # input argument.
Alex Klein1699fab2022-09-08 08:46:06 -0600484 if not opts.board:
485 parser.error("--board is required")
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000486
Alex Klein1699fab2022-09-08 08:46:06 -0600487 build_target = build_target_lib.BuildTarget(
488 opts.board, build_root=opts.sysroot
489 )
490 board_root = sysroot_lib.Sysroot(build_target.root)
Cindy Lin7487daa2022-02-23 04:14:10 +0000491
Alex Kleinfba23ba2022-02-03 11:58:48 -0700492 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600493 # TODO(xcl): Update run_configs to have a common base set of configs for
494 # setup_board and build_packages.
495 if not opts.skip_setup_board:
496 sysroot.SetupBoard(
497 build_target,
498 accept_licenses=opts.accept_licenses,
499 run_configs=opts.setup_board_run_config,
500 )
Sergey Frolovf988de72023-03-06 20:05:21 -0700501
Alex Klein1699fab2022-09-08 08:46:06 -0600502 sysroot.BuildPackages(build_target, board_root, opts.build_run_config)
503 except sysroot_lib.PackageInstallError as e:
504 try:
505 with urllib.request.urlopen(
506 "https://chromiumos-status.appspot.com/current?format=raw"
Sergey Frolov7cf6c0b2022-06-06 16:47:44 -0600507 ) as request:
Alex Klein1699fab2022-09-08 08:46:06 -0600508 logging.notice("Tree Status: %s", request.read().decode())
509 except urllib.error.HTTPError:
510 pass
511 cros_build_lib.Die(e)