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