blob: ab8412758019bec807948f459ad5a687870c15e4 [file] [log] [blame]
Cindy Linc06b4ea2022-01-27 18:13:04 +00001# Copyright 2022 The Chromium OS Authors. All rights reserved.
2# 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
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000033def build_shell_bool_style_args(parser: commandline.ArgumentParser,
34 name: str,
35 default_val: bool,
36 help_str: str,
37 deprecation_note: str,
38 alternate_name: Optional[str] = None) -> None:
39 """Build the shell boolean input argument equivalent.
Alex Kleina39dc982022-02-03 12:13:14 -070040
Ram Chandrasekarbaa89632022-02-11 23:22:09 +000041 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.
55
56 Args:
57 parser: The parser to update.
58 name: The input argument name. This will be used as 'dest' variable name.
59 default_val: The default value to assign.
60 help_str: The help string for the input argument.
61 deprecation_note: A deprecation note to use.
62 alternate_name: Alternate argument to be used after deprecation.
63 """
64 arg = f'--{name}'
65 shell_narg = f'--no{name}'
66 py_narg = f'--no-{name}'
67 alt_arg = f'--{alternate_name}' if alternate_name else None
68 alt_py_narg = f'--no-{alternate_name}' if alternate_name else None
69 default_val_str = f'{help_str} (Default: %(default)s).'
70
71 if alternate_name:
72 parser.add_argument(
73 alt_arg,
74 action='store_true',
75 default=default_val,
76 dest=name,
77 help=default_val_str)
78 parser.add_argument(
79 alt_py_narg,
80 action='store_false',
81 dest=name,
82 help="Don't " + help_str.lower())
83
84 parser.add_argument(
85 arg,
86 action='store_true',
87 default=default_val,
88 dest=name,
89 deprecated=deprecation_note % alt_arg if alternate_name else None,
90 help=default_val_str if not alternate_name else argparse.SUPPRESS)
91 parser.add_argument(
92 shell_narg,
93 action='store_false',
94 dest=name,
95 deprecated=deprecation_note %
96 (alt_py_narg if alternate_name else py_narg),
97 help=argparse.SUPPRESS)
98
99 if not alternate_name:
100 parser.add_argument(
101 py_narg,
102 action='store_false',
103 dest=name,
104 help="Don't " + help_str.lower())
105
106
107def get_parser() -> commandline.ArgumentParser:
108 """Creates the cmdline argparser, populates the options and description.
109
110 Returns:
111 Argument parser.
112 """
113 deprecation_note = 'Argument will be removed July, 2022. Use %s instead.'
114 parser = commandline.ArgumentParser(description=__doc__)
115
116 # TODO(rchandrasekar): Check if the board input is set.
117 # Don't proceed if not set.
118 parser.add_argument(
Alex Klein78a4bc02022-04-14 15:59:52 -0600119 '-b',
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000120 '--board',
Alex Klein78a4bc02022-04-14 15:59:52 -0600121 '--build-target',
122 dest='board',
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000123 default=cros_build_lib.GetDefaultBoard(),
124 help='The board to build packages for.')
125
126 build_shell_bool_style_args(
127 parser, 'usepkg', True, 'Use binary packages to bootstrap when possible.',
128 deprecation_note)
129 build_shell_bool_style_args(
130 parser, 'usepkgonly', False,
131 'Use binary packages only to bootstrap; abort if any are missing.',
132 deprecation_note)
133 build_shell_bool_style_args(parser, 'workon', True,
134 'Force-build workon packages.', deprecation_note)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000135 build_shell_bool_style_args(
136 parser, 'withrevdeps', True,
137 'Calculate reverse dependencies on changed ebuilds.', deprecation_note)
138 build_shell_bool_style_args(
139 parser, 'cleanbuild', False,
140 'Perform a clean build; delete sysroot if it exists before building.',
141 deprecation_note)
142 build_shell_bool_style_args(
143 parser, 'pretend', False,
144 'Pretend building packages, just display which packages would have '
145 'been installed.', deprecation_note)
146
147 # The --sysroot flag specifies the environment variables ROOT and PKGDIR.
148 # This allows fetching and emerging of all packages to specified sysroot.
149 # Note that --sysroot will setup the board normally in /build/$BOARD, if
150 # it's not setup yet. It also expects the toolchain to already be installed
151 # in the sysroot.
152 # --usepkgonly and --norebuild are required, because building is not
153 # supported when board_root is set.
154 parser.add_argument(
155 '--sysroot', type='path', help='Emerge packages to sysroot.')
156 parser.add_argument(
157 '--board_root',
158 type='path',
159 dest='sysroot',
160 deprecated=deprecation_note % '--sysroot',
161 help=argparse.SUPPRESS)
162
163 # CPU Governor related options.
164 group = parser.add_argument_group('CPU Governor Options')
165 build_shell_bool_style_args(
166 group, 'autosetgov', False,
167 "Automatically set cpu governor to 'performance'.", deprecation_note)
168 build_shell_bool_style_args(
169 group,
170 'autosetgov_sticky',
171 False,
172 'Remember --autosetgov setting for future runs.',
173 deprecation_note,
174 alternate_name='autosetgov-sticky')
175
176 # Chrome building related options.
177 group = parser.add_argument_group('Chrome Options')
178 build_shell_bool_style_args(
179 group,
180 'use_any_chrome',
181 True,
182 "Use any Chrome prebuilt available, even if the prebuilt doesn't "
183 'match exactly.',
184 deprecation_note,
185 alternate_name='use-any-chrome')
186 build_shell_bool_style_args(
187 group, 'internal', False,
188 'Build the internal version of chrome(set the chrome_internal USE flag).',
189 deprecation_note)
190 build_shell_bool_style_args(
191 group, 'chrome', False, 'Ensure chrome instead of chromium. Alias for '
192 '--internal --no-use-any-chrome.', deprecation_note)
193
194 # Setup board related options.
195 group = parser.add_argument_group('Setup Board Config Options')
196 build_shell_bool_style_args(
197 group,
198 'skip_chroot_upgrade',
199 False,
200 'Skip the automatic chroot upgrade; use with care.',
201 deprecation_note,
202 alternate_name='skip-chroot-upgrade')
203 build_shell_bool_style_args(
204 group,
205 'skip_toolchain_update',
206 False,
207 'Skip automatic toolchain update',
208 deprecation_note,
209 alternate_name='skip-toolchain-update')
210 build_shell_bool_style_args(
211 group,
212 'skip_setup_board',
213 False,
214 'Skip running setup_board. Implies '
215 '--skip-chroot-upgrade --skip-toolchain-update.',
216 deprecation_note,
217 alternate_name='skip-setup-board')
218
219 # Image Type selection related options.
220 group = parser.add_argument_group('Image Type Options')
221 build_shell_bool_style_args(group, 'withdev', True,
222 'Build useful developer friendly utilities.',
223 deprecation_note)
224 build_shell_bool_style_args(
225 group, 'withdebug', True,
226 'Build debug versions of Chromium-OS-specific packages.',
227 deprecation_note)
228 build_shell_bool_style_args(group, 'withfactory', True,
229 'Build factory installer.', deprecation_note)
230 build_shell_bool_style_args(group, 'withtest', True,
231 'Build packages required for testing.',
232 deprecation_note)
233 build_shell_bool_style_args(group, 'withautotest', True,
234 'Build autotest client code.', deprecation_note)
235 build_shell_bool_style_args(group, 'withdebugsymbols', False,
236 'Install the debug symbols for all packages.',
237 deprecation_note)
238
239 # Advanced Options.
240 group = parser.add_argument_group('Advanced Options')
241 group.add_argument(
242 '--accept-licenses', help='Licenses to append to the accept list.')
243 group.add_argument(
244 '--accept_licenses',
245 deprecated=deprecation_note % '--accept-licenses',
246 help=argparse.SUPPRESS)
247 build_shell_bool_style_args(group, 'eclean', True,
248 'Run eclean to delete old binpkgs.',
249 deprecation_note)
250 group.add_argument(
251 '--jobs',
252 type=int,
253 default=os.cpu_count(),
254 help='Number of packages to build in parallel. '
255 '(Default: %(default)s)')
256 build_shell_bool_style_args(group, 'rebuild', True,
257 'Automatically rebuild dependencies.',
258 deprecation_note)
259 # TODO(b/218522717): Remove the --nonorebuild argument support.
260 group.add_argument(
261 '--nonorebuild',
262 action='store_true',
263 dest='rebuild',
264 deprecated=deprecation_note % '--rebuild',
265 help=argparse.SUPPRESS)
266 build_shell_bool_style_args(group, 'expandedbinhosts', True,
267 'Allow expanded binhost inheritance.',
268 deprecation_note)
269 # The --reuse-pkgs-from-local-boards flag tells Portage to share binary
270 # packages between boards that are built locally, so that the total time
271 # required to build several boards is reduced. This flag is only useful
272 # when you are not able to use remote binary packages, since remote binary
273 # packages are usually more up to date than anything you have locally.
274 build_shell_bool_style_args(
275 group,
276 'reuse_pkgs_from_local_boards',
277 False,
278 'Bootstrap from local packages instead of remote packages.',
279 deprecation_note,
280 alternate_name='reuse-pkgs-from-local-boards')
281
282 # --run-goma option is designed to be used on bots.
283 # If you're trying to build packages with goma in your local dev env, this is
284 # *not* the option you're looking for. Please see comments below.
285 # This option; 1) starts goma, 2) builds packages (expecting that goma is
286 # used), then 3) stops goma explicitly.
287 # 4) is a request from the goma team, so that stats/logs can be taken.
288 # Note: GOMA_DIR and GOMA_SERVICE_ACCOUNT_JSON_FILE are expected to be passed
289 # via env var.
290 #
291 # In local dev env cases, compiler_proxy is expected to keep running.
292 # In such a case;
293 # $ python ${GOMA_DIR}/goma_ctl.py ensure_start
294 # $ ./build_packages (... and options without --run-goma ...)
295 # is an expected commandline sequence. If you set --run-goma flag while
296 # compiler_proxy is already running, the existing compiler_proxy will be
297 # stopped.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000298 build_shell_bool_style_args(
299 group,
300 'run_goma',
301 False,
302 'If set to true, (re)starts goma, builds packages, and then stops goma..',
303 deprecation_note,
304 alternate_name='run-goma')
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000305 # This option is for building chrome remotely.
306 # 1) starts reproxy 2) builds chrome with reproxy and 3) stops reproxy so
307 # logs/stats can be collected.
308 # Note: RECLIENT_DIR and REPROXY_CFG env var will be deprecated July, 2022.
309 # Use --reclient-dir and --reproxy-cfg input options instead.
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000310 build_shell_bool_style_args(
311 group, 'run_remoteexec', False,
312 'If set to true, starts RBE reproxy, builds packages, and then stops '
313 'reproxy.', deprecation_note)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000314
315 parser.add_argument('packages', nargs='*', help='Packages to build.')
316 return parser
317
318
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000319def parse_args(argv: List[str]) -> Tuple[commandline.ArgumentParser,
320 commandline.ArgumentNamespace]:
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000321 """Parse and validate CLI arguments.
322
323 Args:
324 argv: Arguments passed via CLI.
325
326 Returns:
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000327 Tuple having the below two,
328 Argument Parser
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000329 Validated argument namespace.
330 """
331 parser = get_parser()
332 opts = parser.parse_args(argv)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000333
334 if opts.chrome:
335 opts.internal_chrome = True
336 opts.use_any_chrome = False
337
Cindy Lin317083d2022-03-14 17:07:25 +0000338 opts.setup_board_run_config = sysroot.SetupBoardRunConfig(
339 force=opts.cleanbuild,
340 usepkg=opts.usepkg,
341 jobs=opts.jobs,
342 quiet=True,
343 update_toolchain=not opts.skip_toolchain_update,
344 upgrade_chroot=not opts.skip_chroot_upgrade,
345 local_build=opts.reuse_pkgs_from_local_boards,
346 expanded_binhost_inheritance=opts.expandedbinhosts)
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000347 opts.build_run_config = sysroot.BuildPackagesRunConfig(
348 usepkg=opts.usepkg,
349 install_debug_symbols=opts.withdebugsymbols,
350 packages=opts.packages,
351 use_goma=opts.run_goma,
352 use_remoteexec=opts.run_remoteexec,
353 incremental_build=opts.withrevdeps,
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000354 dryrun=opts.pretend,
355 usepkgonly=opts.usepkgonly,
356 workon=opts.workon,
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000357 install_auto_test=opts.withautotest,
358 autosetgov=opts.autosetgov,
359 autosetgov_sticky=opts.autosetgov_sticky,
360 use_any_chrome=opts.use_any_chrome,
361 internal_chrome=opts.internal,
362 clean_build=opts.cleanbuild,
363 eclean=opts.eclean,
364 rebuild_dep=opts.rebuild,
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000365 jobs=opts.jobs,
366 local_pkg=opts.reuse_pkgs_from_local_boards,
367 dev_image=opts.withdev,
368 factory_image=opts.withfactory,
369 test_image=opts.withtest,
Cindy Lin317083d2022-03-14 17:07:25 +0000370 debug_version=opts.withdebug)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000371 opts.Freeze()
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000372 return parser, opts
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000373
374
Cindy Linb7f89a42022-05-23 16:50:00 +0000375@timer.timed('Elapsed time (build_packages)')
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000376def main(argv: Optional[List[str]] = None) -> Optional[int]:
377 commandline.RunInsideChroot()
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000378 parser, opts = parse_args(argv)
Ram Chandrasekarbaa89632022-02-11 23:22:09 +0000379
Ram Chandrasekarbdec0f02022-02-24 01:20:17 +0000380 # If the opts.board is not set, then it means user hasn't specified a default
381 # board in 'src/scripts/.default_board' and didn't specify it as input
382 # argument.
383 if not opts.board:
384 parser.error('--board is required')
385
Cindy Lin7487daa2022-02-23 04:14:10 +0000386 build_target = build_target_lib.BuildTarget(
Alex Klein78a4bc02022-04-14 15:59:52 -0600387 opts.board, build_root=opts.sysroot)
388 board_root = sysroot_lib.Sysroot(build_target.root)
Cindy Lin7487daa2022-02-23 04:14:10 +0000389
Cindy Linc06b4ea2022-01-27 18:13:04 +0000390 try:
Cindy Lin317083d2022-03-14 17:07:25 +0000391 # TODO(xcl): Update run_configs to have a common base set of configs for
392 # setup_board and build_packages.
393 if not opts.skip_setup_board:
394 sysroot.SetupBoard(
395 build_target,
396 accept_licenses=opts.accept_licenses,
397 run_configs=opts.setup_board_run_config)
Cindy Lin7487daa2022-02-23 04:14:10 +0000398 sysroot.BuildPackages(build_target, board_root, opts.build_run_config)
399 except sysroot_lib.PackageInstallError as e:
Alex Kleinfba23ba2022-02-03 11:58:48 -0700400 try:
401 request = urllib.request.urlopen(
402 'https://chromiumos-status.appspot.com/current?format=raw')
403 logging.notice('Tree Status: %s', request.read().decode())
404 except urllib.error.HTTPError:
405 pass
Cindy Linc06b4ea2022-01-27 18:13:04 +0000406 cros_build_lib.Die(e)