xref: /aosp_15_r20/external/toolchain-utils/build_chromeos.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#
4# Copyright 2020 The ChromiumOS Authors
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8"""Script to checkout the ChromeOS source.
9
10This script sets up the ChromeOS source in the given directory, matching a
11particular release of ChromeOS.
12"""
13
14
15__author__ = (
16    "[email protected] (Ahmad Sharif) "
17    "[email protected] (Luis Lozano) "
18    "[email protected] (Raymes Khoury) "
19    "[email protected] (Han Shen)"
20)
21
22import argparse
23import os
24import sys
25
26from cros_utils import command_executer
27from cros_utils import logger
28from cros_utils import misc
29
30
31def Usage(parser, message):
32    print("ERROR: %s" % message)
33    parser.print_help()
34    sys.exit(0)
35
36
37def Main(argv):
38    """Build ChromeOS."""
39    # Common initializations
40    cmd_executer = command_executer.GetCommandExecuter()
41
42    parser = argparse.ArgumentParser()
43    parser.add_argument(
44        "--chromeos_root",
45        dest="chromeos_root",
46        help="Target directory for ChromeOS installation.",
47    )
48    parser.add_argument(
49        "--clobber_chroot",
50        dest="clobber_chroot",
51        action="store_true",
52        help="Delete the chroot and start fresh",
53        default=False,
54    )
55    parser.add_argument(
56        "--clobber_board",
57        dest="clobber_board",
58        action="store_true",
59        help="Delete the board and start fresh",
60        default=False,
61    )
62    parser.add_argument(
63        "--rebuild",
64        dest="rebuild",
65        action="store_true",
66        help="Rebuild all board packages except the toolchain.",
67        default=False,
68    )
69    parser.add_argument(
70        "--cflags",
71        dest="cflags",
72        default="",
73        help="CFLAGS for the ChromeOS packages",
74    )
75    parser.add_argument(
76        "--cxxflags",
77        dest="cxxflags",
78        default="",
79        help="CXXFLAGS for the ChromeOS packages",
80    )
81    parser.add_argument(
82        "--ldflags",
83        dest="ldflags",
84        default="",
85        help="LDFLAGS for the ChromeOS packages",
86    )
87    parser.add_argument(
88        "--board", dest="board", help="ChromeOS target board, e.g. x86-generic"
89    )
90    parser.add_argument(
91        "--package", dest="package", help="The package needs to be built"
92    )
93    parser.add_argument(
94        "--label",
95        dest="label",
96        help="Optional label symlink to point to build dir.",
97    )
98    parser.add_argument(
99        "--dev",
100        dest="dev",
101        default=False,
102        action="store_true",
103        help=(
104            "Make the final image in dev mode (eg writable, "
105            "more space on image). Defaults to False."
106        ),
107    )
108    parser.add_argument(
109        "--debug",
110        dest="debug",
111        default=False,
112        action="store_true",
113        help=(
114            'Optional. Build chrome browser with "-g -O0". '
115            "Notice, this also turns on '--dev'. "
116            "Defaults to False."
117        ),
118    )
119    parser.add_argument(
120        "--env", dest="env", default="", help="Env to pass to build_packages."
121    )
122    parser.add_argument(
123        "--vanilla",
124        dest="vanilla",
125        default=False,
126        action="store_true",
127        help="Use default ChromeOS toolchain.",
128    )
129    parser.add_argument(
130        "--vanilla_image",
131        dest="vanilla_image",
132        default=False,
133        action="store_true",
134        help=(
135            "Use prebuild packages for building the image. "
136            "It also implies the --vanilla option is set."
137        ),
138    )
139
140    options = parser.parse_args(argv[1:])
141
142    if options.chromeos_root is None:
143        Usage(parser, "--chromeos_root must be set")
144    options.chromeos_root = os.path.expanduser(options.chromeos_root)
145    scripts_dir = os.path.join(options.chromeos_root, "src", "scripts")
146    if not os.path.isdir(scripts_dir):
147        Usage(
148            parser,
149            "--chromeos_root must be set up first. Use setup_chromeos.py",
150        )
151
152    if options.board is None:
153        Usage(parser, "--board must be set")
154
155    if options.debug:
156        options.dev = True
157
158    build_packages_env = options.env
159    if build_packages_env.find("EXTRA_BOARD_FLAGS=") != -1:
160        logger.GetLogger().LogFatal(
161            (
162                'Passing "EXTRA_BOARD_FLAGS" in "--env" is not supported. '
163                "This flags is used internally by this script. "
164                "Contact the author for more detail."
165            )
166        )
167
168    if options.rebuild:
169        build_packages_env += " EXTRA_BOARD_FLAGS=-e"
170        # EXTRA_BOARD_FLAGS=-e should clean up the object files for the chrome
171        # browser but it doesn't. So do it here.
172        misc.RemoveChromeBrowserObjectFiles(
173            options.chromeos_root, options.board
174        )
175
176    # Build with afdo_use by default.
177    # To change the default use --env="USE=-afdo_use".
178    build_packages_env = misc.MergeEnvStringWithDict(
179        build_packages_env, {"USE": "chrome_internal afdo_use -cros-debug"}
180    )
181
182    build_packages_command = misc.GetBuildPackagesCommand(
183        board=options.board, usepkg=options.vanilla_image, debug=options.debug
184    )
185
186    if options.package:
187        build_packages_command += " {0}".format(options.package)
188
189    build_image_command = misc.GetBuildImageCommand(options.board, options.dev)
190
191    if options.vanilla or options.vanilla_image:
192        command = misc.GetSetupBoardCommand(
193            options.board,
194            usepkg=options.vanilla_image,
195            force=options.clobber_board,
196        )
197        command += "; " + build_packages_env + " " + build_packages_command
198        command += "&& " + build_packages_env + " " + build_image_command
199        ret = cmd_executer.ChrootRunCommand(options.chromeos_root, command)
200        return ret
201
202    # Setup board
203    if (
204        not os.path.isdir(
205            options.chromeos_root + "/chroot/build/" + options.board
206        )
207        or options.clobber_board
208    ):
209        # Run build_tc.py from binary package
210        ret = cmd_executer.ChrootRunCommand(
211            options.chromeos_root,
212            misc.GetSetupBoardCommand(
213                options.board, force=options.clobber_board
214            ),
215        )
216        logger.GetLogger().LogFatalIf(ret, "setup_board failed")
217    else:
218        logger.GetLogger().LogOutput(
219            "Did not setup_board " "because it already exists"
220        )
221
222    if options.debug:
223        # Perform 2-step build_packages to build a debug chrome browser.
224
225        # Firstly, build everything that chromeos-chrome depends on normally.
226        if options.rebuild:
227            # Give warning about "--rebuild" and "--debug". Under this combination,
228            # only dependencies of "chromeos-chrome" get rebuilt.
229            logger.GetLogger().LogWarning(
230                '--rebuild" does not correctly re-build every package when '
231                '"--debug" is enabled. '
232            )
233
234            # Replace EXTRA_BOARD_FLAGS=-e with "-e --onlydeps"
235            build_packages_env = build_packages_env.replace(
236                "EXTRA_BOARD_FLAGS=-e", 'EXTRA_BOARD_FLAGS="-e --onlydeps"'
237            )
238        else:
239            build_packages_env += " EXTRA_BOARD_FLAGS=--onlydeps"
240
241        ret = cmd_executer.ChrootRunCommand(
242            options.chromeos_root,
243            'CFLAGS="$(portageq-%s envvar CFLAGS) %s" '
244            'CXXFLAGS="$(portageq-%s envvar CXXFLAGS) %s" '
245            'LDFLAGS="$(portageq-%s envvar LDFLAGS) %s" '
246            "CHROME_ORIGIN=SERVER_SOURCE "
247            "%s "
248            "%s --skip_chroot_upgrade"
249            "chromeos-chrome"
250            % (
251                options.board,
252                options.cflags,
253                options.board,
254                options.cxxflags,
255                options.board,
256                options.ldflags,
257                build_packages_env,
258                build_packages_command,
259            ),
260        )
261
262        logger.GetLogger().LogFatalIf(
263            ret,
264            "build_packages failed while trying to build chromeos-chrome deps.",
265        )
266
267        # Secondly, build chromeos-chrome using debug mode.
268        # Replace '--onlydeps' with '--nodeps'.
269        if options.rebuild:
270            build_packages_env = build_packages_env.replace(
271                'EXTRA_BOARD_FLAGS="-e --onlydeps"',
272                "EXTRA_BOARD_FLAGS=--nodeps",
273            )
274        else:
275            build_packages_env = build_packages_env.replace(
276                "EXTRA_BOARD_FLAGS=--onlydeps", "EXTRA_BOARD_FLAGS=--nodeps"
277            )
278        ret = cmd_executer.ChrootRunCommand(
279            options.chromeos_root,
280            'CFLAGS="$(portageq-%s envvar CFLAGS) %s" '
281            'CXXFLAGS="$(portageq-%s envvar CXXFLAGS) %s" '
282            'LDFLAGS="$(portageq-%s envvar LDFLAGS) %s" '
283            "CHROME_ORIGIN=SERVER_SOURCE BUILDTYPE=Debug "
284            "%s "
285            "%s --skip_chroot_upgrade"
286            "chromeos-chrome"
287            % (
288                options.board,
289                options.cflags,
290                options.board,
291                options.cxxflags,
292                options.board,
293                options.ldflags,
294                build_packages_env,
295                build_packages_command,
296            ),
297        )
298        logger.GetLogger().LogFatalIf(
299            ret,
300            "build_packages failed while trying to build debug chromeos-chrome.",
301        )
302
303        # Now, we have built chromeos-chrome and all dependencies.
304        # Finally, remove '-e' from EXTRA_BOARD_FLAGS,
305        # otherwise, chromeos-chrome gets rebuilt.
306        build_packages_env = build_packages_env.replace(
307            "EXTRA_BOARD_FLAGS=--nodeps", ""
308        )
309
310        # Up to now, we have a debug built chromos-chrome browser.
311        # Fall through to build the rest of the world.
312
313    # Build packages
314    ret = cmd_executer.ChrootRunCommand(
315        options.chromeos_root,
316        'CFLAGS="$(portageq-%s envvar CFLAGS) %s" '
317        'CXXFLAGS="$(portageq-%s envvar CXXFLAGS) %s" '
318        'LDFLAGS="$(portageq-%s envvar LDFLAGS) %s" '
319        "CHROME_ORIGIN=SERVER_SOURCE "
320        "%s "
321        "%s --skip_chroot_upgrade"
322        % (
323            options.board,
324            options.cflags,
325            options.board,
326            options.cxxflags,
327            options.board,
328            options.ldflags,
329            build_packages_env,
330            build_packages_command,
331        ),
332    )
333
334    logger.GetLogger().LogFatalIf(ret, "build_packages failed")
335    if options.package:
336        return 0
337    # Build image
338    ret = cmd_executer.ChrootRunCommand(
339        options.chromeos_root, build_packages_env + " " + build_image_command
340    )
341
342    logger.GetLogger().LogFatalIf(ret, "build_image failed")
343
344    flags_file_name = "flags.txt"
345    flags_file_path = "%s/src/build/images/%s/latest/%s" % (
346        options.chromeos_root,
347        options.board,
348        flags_file_name,
349    )
350    with open(flags_file_path, "w", encoding="utf-8") as flags_file:
351        flags_file.write("CFLAGS=%s\n" % options.cflags)
352        flags_file.write("CXXFLAGS=%s\n" % options.cxxflags)
353        flags_file.write("LDFLAGS=%s\n" % options.ldflags)
354
355    if options.label:
356        image_dir_path = "%s/src/build/images/%s/latest" % (
357            options.chromeos_root,
358            options.board,
359        )
360        real_image_dir_path = os.path.realpath(image_dir_path)
361        command = "ln -sf -T %s %s/%s" % (
362            os.path.basename(real_image_dir_path),
363            os.path.dirname(real_image_dir_path),
364            options.label,
365        )
366
367        ret = cmd_executer.RunCommand(command)
368        logger.GetLogger().LogFatalIf(
369            ret, "Failed to apply symlink label %s" % options.label
370        )
371
372    return ret
373
374
375if __name__ == "__main__":
376    retval = Main(sys.argv)
377    sys.exit(retval)
378