blob: 6107433ff8503f2383cc0ace9ea381de07f46371 [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
Sergey Frolovf988de72023-03-06 20:05:21 -070026from chromite.lib import chromite_config
Alex Kleina39dc982022-02-03 12:13:14 -070027from chromite.lib import commandline
Cindy Linc06b4ea2022-01-27 18:13:04 +000028from chromite.lib import cros_build_lib
Cindy Lin7487daa2022-02-23 04:14:10 +000029from chromite.lib import sysroot_lib
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +000030from chromite.service import sysroot
Cindy Linb7f89a42022-05-23 16:50:00 +000031from chromite.utils import timer
Cindy Linc06b4ea2022-01-27 18:13:04 +000032
33
Alex Klein1699fab2022-09-08 08:46:06 -060034def build_shell_bool_style_args(
35 parser: commandline.ArgumentParser,
36 name: str,
37 default_val: bool,
38 help_str: str,
39 deprecation_note: str,
40 alternate_name: Optional[str] = None,
41) -> None:
42 """Build the shell boolean input argument equivalent.
Alex Kleina39dc982022-02-03 12:13:14 -070043
Alex Klein1699fab2022-09-08 08:46:06 -060044 There are two cases which we will need to handle,
45 case 1: A shell boolean arg, which doesn't need to be re-worded in python.
46 case 2: A shell boolean arg, which needs to be re-worded in python.
47 Example below.
48 For Case 1, for a given input arg name 'argA', we create three python
49 arguments.
50 --argA, --noargA, --no-argA. The arguments --argA and --no-argA will be
51 retained after deprecating --noargA.
52 For Case 2, for a given input arg name 'arg_A' we need to use alternate
53 argument name 'arg-A'. we create four python arguments in this case.
54 --arg_A, --noarg_A, --arg-A, --no-arg-A. The first two arguments will be
55 deprecated later.
56 TODO(b/218522717): Remove the creation of --noargA in case 1 and --arg_A and
57 --noarg_A in case 2.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000058
Alex Klein1699fab2022-09-08 08:46:06 -060059 Args:
60 parser: The parser to update.
61 name: The input argument name. This will be used as 'dest' variable name.
62 default_val: The default value to assign.
63 help_str: The help string for the input argument.
64 deprecation_note: A deprecation note to use.
65 alternate_name: Alternate argument to be used after deprecation.
66 """
67 arg = f"--{name}"
68 shell_narg = f"--no{name}"
69 py_narg = f"--no-{name}"
70 alt_arg = f"--{alternate_name}" if alternate_name else None
71 alt_py_narg = f"--no-{alternate_name}" if alternate_name else None
72 default_val_str = f"{help_str} (Default: %(default)s)."
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000073
Alex Klein1699fab2022-09-08 08:46:06 -060074 if alternate_name:
75 parser.add_argument(
76 alt_arg,
77 action="store_true",
78 default=default_val,
79 dest=name,
80 help=default_val_str,
81 )
82 parser.add_argument(
83 alt_py_narg,
84 action="store_false",
85 dest=name,
86 help="Don't " + help_str.lower(),
87 )
88
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000089 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060090 arg,
91 action="store_true",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000092 default=default_val,
93 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -060094 deprecated=deprecation_note % alt_arg if alternate_name else None,
95 help=default_val_str if not alternate_name else argparse.SUPPRESS,
96 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000097 parser.add_argument(
Alex Klein1699fab2022-09-08 08:46:06 -060098 shell_narg,
99 action="store_false",
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000100 dest=name,
Alex Klein1699fab2022-09-08 08:46:06 -0600101 deprecated=deprecation_note % alt_py_narg
102 if alternate_name
103 else py_narg,
104 help=argparse.SUPPRESS,
105 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000106
Alex Klein1699fab2022-09-08 08:46:06 -0600107 if not alternate_name:
108 parser.add_argument(
109 py_narg,
110 action="store_false",
111 dest=name,
112 help="Don't " + help_str.lower(),
113 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000114
115
116def get_parser() -> commandline.ArgumentParser:
Alex Klein1699fab2022-09-08 08:46:06 -0600117 """Creates the cmdline argparser, populates the options and description.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000118
Alex Klein1699fab2022-09-08 08:46:06 -0600119 Returns:
120 Argument parser.
121 """
122 deprecation_note = "Argument will be removed July, 2022. Use %s instead."
123 parser = commandline.ArgumentParser(description=__doc__)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000124
Alex Klein1699fab2022-09-08 08:46:06 -0600125 parser.add_argument(
126 "-b",
127 "--board",
128 "--build-target",
129 dest="board",
130 default=cros_build_lib.GetDefaultBoard(),
131 help="The board to build packages for.",
132 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000133
Alex Klein1699fab2022-09-08 08:46:06 -0600134 build_shell_bool_style_args(
135 parser,
136 "usepkg",
137 True,
138 "Use binary packages to bootstrap when possible.",
139 deprecation_note,
140 )
141 build_shell_bool_style_args(
142 parser,
143 "usepkgonly",
144 False,
145 "Use binary packages only to bootstrap; abort if any are missing.",
146 deprecation_note,
147 )
148 build_shell_bool_style_args(
149 parser, "workon", True, "Force-build workon packages.", deprecation_note
150 )
151 build_shell_bool_style_args(
152 parser,
153 "withrevdeps",
154 True,
155 "Calculate reverse dependencies on changed ebuilds.",
156 deprecation_note,
157 )
158 build_shell_bool_style_args(
159 parser,
160 "cleanbuild",
161 False,
162 "Perform a clean build; delete sysroot if it exists before building.",
163 deprecation_note,
164 )
165 build_shell_bool_style_args(
166 parser,
167 "pretend",
168 False,
169 "Pretend building packages, just display which packages would have "
170 "been installed.",
171 deprecation_note,
172 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000173
Alex Klein1699fab2022-09-08 08:46:06 -0600174 # The --sysroot flag specifies the environment variables ROOT and PKGDIR.
175 # This allows fetching and emerging of all packages to specified sysroot.
176 # Note that --sysroot will setup the board normally in /build/$BOARD, if
177 # it's not setup yet. It also expects the toolchain to already be installed
178 # in the sysroot.
179 # --usepkgonly and --norebuild are required, because building is not
180 # supported when board_root is set.
181 parser.add_argument(
182 "--sysroot", type="path", help="Emerge packages to sysroot."
183 )
184 parser.add_argument(
185 "--board_root",
186 type="path",
187 dest="sysroot",
188 deprecated=deprecation_note % "--sysroot",
189 help=argparse.SUPPRESS,
190 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000191
Alex Klein1699fab2022-09-08 08:46:06 -0600192 # CPU Governor related options.
193 group = parser.add_argument_group("CPU Governor Options")
194 build_shell_bool_style_args(
195 group,
196 "autosetgov",
197 False,
198 "Automatically set cpu governor to 'performance'.",
199 deprecation_note,
200 )
201 build_shell_bool_style_args(
202 group,
203 "autosetgov_sticky",
204 False,
205 "Remember --autosetgov setting for future runs.",
206 deprecation_note,
207 alternate_name="autosetgov-sticky",
208 )
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000209
Alex Klein1699fab2022-09-08 08:46:06 -0600210 # Chrome building related options.
211 group = parser.add_argument_group("Chrome Options")
212 build_shell_bool_style_args(
213 group,
214 "use_any_chrome",
215 True,
216 "Use any Chrome prebuilt available, even if the prebuilt doesn't "
217 "match exactly.",
218 deprecation_note,
219 alternate_name="use-any-chrome",
220 )
221 build_shell_bool_style_args(
222 group,
223 "internal",
224 False,
225 "Build the internal version of chrome(set the chrome_internal USE flag).",
226 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.
374 # If you're trying to build packages with goma in your local dev env, this is
375 # *not* the option you're looking for. Please see comments below.
376 # 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,
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 )
Sergey Frolovf988de72023-03-06 20:05:21 -0700500
501 if os.path.isfile(chromite_config.AUTO_COP_CONFIG):
502 cop_command = [
503 "cros",
504 "clean-outdated-pkgs",
505 f"--board={opts.board}",
506 ]
507 # Set check=False to allow cop to fail.
508 cros_build_lib.sudo_run(
509 cop_command,
510 preserve_env=True,
511 check=False,
512 )
513
Alex Klein1699fab2022-09-08 08:46:06 -0600514 sysroot.BuildPackages(build_target, board_root, opts.build_run_config)
515 except sysroot_lib.PackageInstallError as e:
516 try:
517 with urllib.request.urlopen(
518 "https://chromiumos-status.appspot.com/current?format=raw"
Sergey Frolov7cf6c0b2022-06-06 16:47:44 -0600519 ) as request:
Alex Klein1699fab2022-09-08 08:46:06 -0600520 logging.notice("Tree Status: %s", request.read().decode())
521 except urllib.error.HTTPError:
522 pass
523 cros_build_lib.Die(e)