blob: d8af3bd9657b53c08a4d249cfdad6eee097a7a70 [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.
378 # Note: GOMA_DIR and GOMA_SERVICE_ACCOUNT_JSON_FILE are expected to be passed
379 # via env var.
380 #
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,
392 "If set to true, (re)starts goma, builds packages, and then stops goma..",
393 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,
443 backtrack=opts.backtrack,
444 )
445 opts.build_run_config = sysroot.BuildPackagesRunConfig(
446 usepkg=opts.usepkg,
447 install_debug_symbols=opts.withdebugsymbols,
448 packages=opts.packages,
449 use_goma=opts.run_goma,
450 use_remoteexec=opts.run_remoteexec,
451 incremental_build=opts.withrevdeps,
452 dryrun=opts.pretend,
453 usepkgonly=opts.usepkgonly,
454 workon=opts.workon,
455 install_auto_test=opts.withautotest,
456 autosetgov=opts.autosetgov,
457 autosetgov_sticky=opts.autosetgov_sticky,
458 use_any_chrome=opts.use_any_chrome,
459 internal_chrome=opts.internal,
460 clean_build=opts.cleanbuild,
461 eclean=opts.eclean,
462 rebuild_dep=opts.rebuild,
463 jobs=opts.jobs,
464 local_pkg=opts.reuse_pkgs_from_local_boards,
465 dev_image=opts.withdev,
466 factory_image=opts.withfactory,
467 test_image=opts.withtest,
468 debug_version=opts.withdebug,
469 backtrack=opts.backtrack,
470 )
471 opts.Freeze()
472 return parser, opts
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000473
474
Alex Klein1699fab2022-09-08 08:46:06 -0600475@timer.timed("Elapsed time (build_packages)")
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000476def main(argv: Optional[List[str]] = None) -> Optional[int]:
Alex Klein1699fab2022-09-08 08:46:06 -0600477 commandline.RunInsideChroot()
478 parser, opts = parse_args(argv)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000479
Alex Klein1699fab2022-09-08 08:46:06 -0600480 # If the opts.board is not set, then it means user hasn't specified a default
481 # board in 'src/scripts/.default_board' and didn't specify it as input
482 # argument.
483 if not opts.board:
484 parser.error("--board is required")
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000485
Alex Klein1699fab2022-09-08 08:46:06 -0600486 build_target = build_target_lib.BuildTarget(
487 opts.board, build_root=opts.sysroot
488 )
489 board_root = sysroot_lib.Sysroot(build_target.root)
Cindy Lin7487daa2022-02-23 04:14:10 +0000490
Alex Kleinfba23ba2022-02-03 11:58:48 -0700491 try:
Alex Klein1699fab2022-09-08 08:46:06 -0600492 # TODO(xcl): Update run_configs to have a common base set of configs for
493 # setup_board and build_packages.
494 if not opts.skip_setup_board:
495 sysroot.SetupBoard(
496 build_target,
497 accept_licenses=opts.accept_licenses,
498 run_configs=opts.setup_board_run_config,
499 )
500 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)