blob: f7e12f1f4f33a3ba40106d73407dd44be1528781 [file] [log] [blame]
Ryan Cui6290f032012-11-20 15:44:43 -08001# Copyright (c) 2012 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"""Generates a sysroot tarball for building a specific package.
6
7Meant for use after setup_board and build_packages have been run.
8"""
9
10import os
11
Mike Frysinger06a51c82021-04-06 11:39:17 -040012from chromite.lib import build_target_lib
Mike Frysinger807d8282022-04-28 22:45:17 -040013from chromite.lib import commandline
Aviv Keshetb7519e12016-10-04 00:50:00 -070014from chromite.lib import constants
Ryan Cui6290f032012-11-20 15:44:43 -080015from chromite.lib import cros_build_lib
Ryan Cui6290f032012-11-20 15:44:43 -080016from chromite.lib import osutils
17from chromite.lib import sudo
Bertrand SIMONNETa5d8b552015-03-25 16:03:34 -070018from chromite.lib import sysroot_lib
Alex Klein8212d492018-08-27 07:47:23 -060019from chromite.lib import toolchain
Ryan Cui6290f032012-11-20 15:44:43 -080020
Mike Frysinger807d8282022-04-28 22:45:17 -040021
Alex Klein1699fab2022-09-08 08:46:06 -060022DEFAULT_NAME = "sysroot_%(package)s.tar.xz"
23PACKAGE_SEPARATOR = "/"
24SYSROOT = "sysroot"
Ryan Cui6290f032012-11-20 15:44:43 -080025
26
27def ParseCommandLine(argv):
Alex Klein1699fab2022-09-08 08:46:06 -060028 """Parse args, and run environment-independent checks."""
29 parser = commandline.ArgumentParser(description=__doc__)
30 parser.add_argument(
31 "--board", required=True, help="The board to generate the sysroot for."
32 )
33 parser.add_argument(
34 "--package",
35 required=True,
36 help="The packages to generate the sysroot for.",
37 )
38 parser.add_argument(
39 "--deps-only",
40 action="store_true",
41 default=False,
42 help="Build dependencies only.",
43 )
44 parser.add_argument(
45 "--out-dir",
46 type="path",
47 required=True,
48 help="Directory to place the generated tarball.",
49 )
50 parser.add_argument(
51 "--out-file",
52 default=DEFAULT_NAME,
53 help="The name to give to the tarball. " "Defaults to %(default)s.",
54 )
55 options = parser.parse_args(argv)
Ryan Cui6290f032012-11-20 15:44:43 -080056
Alex Klein1699fab2022-09-08 08:46:06 -060057 options.out_file %= {
58 "package": options.package.split()[0].replace(PACKAGE_SEPARATOR, "_"),
59 }
Ryan Cui6290f032012-11-20 15:44:43 -080060
Alex Klein1699fab2022-09-08 08:46:06 -060061 return options
Ryan Cui6290f032012-11-20 15:44:43 -080062
63
64class GenerateSysroot(object):
Alex Klein1699fab2022-09-08 08:46:06 -060065 """Wrapper for generation functionality."""
Ryan Cui6290f032012-11-20 15:44:43 -080066
Alex Klein1699fab2022-09-08 08:46:06 -060067 PARALLEL_EMERGE = os.path.join(
68 constants.CHROMITE_BIN_DIR, "parallel_emerge"
69 )
Ryan Cui6290f032012-11-20 15:44:43 -080070
Alex Klein1699fab2022-09-08 08:46:06 -060071 def __init__(self, sysroot, options):
72 """Initialize
Ryan Cui6290f032012-11-20 15:44:43 -080073
Alex Klein1699fab2022-09-08 08:46:06 -060074 Args:
75 sysroot: Path to sysroot.
76 options: Parsed options.
77 """
78 self.sysroot = sysroot
79 self.options = options
80 self.extra_env = {
81 "ROOT": self.sysroot,
82 "USE": os.environ.get("USE", ""),
83 }
David James78d2e942013-07-31 15:34:45 -070084
Alex Klein1699fab2022-09-08 08:46:06 -060085 def _Emerge(self, *args, **kwargs):
86 """Emerge the given packages using parallel_emerge."""
87 cmd = [
88 self.PARALLEL_EMERGE,
89 "--board=%s" % self.options.board,
90 "--usepkgonly",
91 "--noreplace",
92 ] + list(args)
93 kwargs.setdefault("extra_env", self.extra_env)
94 cros_build_lib.sudo_run(cmd, **kwargs)
Ryan Cui6290f032012-11-20 15:44:43 -080095
Alex Klein1699fab2022-09-08 08:46:06 -060096 def _WriteConfig(self, sysroot):
97 sysroot.WriteConfig(
98 sysroot.GenerateBoardSetupConfig(self.options.board)
99 )
100 # For the config to be correctly read, a stub make.conf is needed.
101 # pylint: disable=protected-access
102 make_conf_path = os.path.join(self.sysroot, sysroot_lib._MAKE_CONF)
103 assert not os.path.exists(make_conf_path), "Expecting an empty sysroot."
104 osutils.WriteFile(
105 os.path.join(make_conf_path),
106 "source make.conf.board_setup",
107 makedirs=True,
108 sudo=True,
109 )
Sloan Johnsona85640f2021-10-01 22:32:40 +0000110
Alex Klein1699fab2022-09-08 08:46:06 -0600111 def _InstallToolchain(self):
112 # Create the sysroot's config.
113 sysroot = sysroot_lib.Sysroot(self.sysroot)
114 self._WriteConfig(sysroot)
115 toolchain.InstallToolchain(sysroot, configure=False)
Ryan Cui6290f032012-11-20 15:44:43 -0800116
Alex Klein1699fab2022-09-08 08:46:06 -0600117 def _InstallKernelHeaders(self):
118 self._Emerge("sys-kernel/linux-headers")
Ryan Cui6290f032012-11-20 15:44:43 -0800119
Alex Klein1699fab2022-09-08 08:46:06 -0600120 def _InstallBuildDependencies(self):
121 # Calculate buildtime deps that are not runtime deps.
122 raw_sysroot = build_target_lib.get_default_sysroot_path(
123 self.options.board
124 )
125 packages = []
126 if not self.options.deps_only:
127 packages = self.options.package.split()
128 else:
129 for pkg in self.options.package.split():
130 cmd = ["qdepends", "-q", "-C", pkg]
131 output = cros_build_lib.run(
132 cmd,
133 extra_env={"ROOT": raw_sysroot},
134 capture_output=True,
135 encoding="utf-8",
136 ).stdout
David James78d2e942013-07-31 15:34:45 -0700137
Alex Klein1699fab2022-09-08 08:46:06 -0600138 if output.count("\n") > 1:
139 raise AssertionError(
140 "Too many packages matched for given pattern"
141 )
David James78d2e942013-07-31 15:34:45 -0700142
Alex Klein1699fab2022-09-08 08:46:06 -0600143 # qdepend outputs "package: deps", so only grab the deps.
144 deps = output.partition(":")[2].split()
145 packages.extend(deps)
146 # Install the required packages.
147 if packages:
148 self._Emerge(*packages)
Ryan Cui6290f032012-11-20 15:44:43 -0800149
Alex Klein1699fab2022-09-08 08:46:06 -0600150 def _CreateTarball(self):
151 tarball_path = os.path.join(self.options.out_dir, self.options.out_file)
152 cros_build_lib.CreateTarball(tarball_path, self.sysroot, sudo=True)
Ryan Cui6290f032012-11-20 15:44:43 -0800153
Alex Klein1699fab2022-09-08 08:46:06 -0600154 def Perform(self):
155 """Generate the sysroot."""
156 self._InstallToolchain()
157 self._InstallKernelHeaders()
158 self._InstallBuildDependencies()
159 self._CreateTarball()
Ryan Cui6290f032012-11-20 15:44:43 -0800160
161
162def FinishParsing(options):
Alex Klein1699fab2022-09-08 08:46:06 -0600163 """Run environment dependent checks on parsed args."""
164 target = os.path.join(options.out_dir, options.out_file)
165 if os.path.exists(target):
166 cros_build_lib.Die("Output file %r already exists." % target)
Ryan Cui6290f032012-11-20 15:44:43 -0800167
Alex Klein1699fab2022-09-08 08:46:06 -0600168 if not os.path.isdir(options.out_dir):
169 cros_build_lib.Die(
170 "Non-existent directory %r specified for --out-dir"
171 % options.out_dir
172 )
Ryan Cui6290f032012-11-20 15:44:43 -0800173
174
175def main(argv):
Alex Klein1699fab2022-09-08 08:46:06 -0600176 options = ParseCommandLine(argv)
177 FinishParsing(options)
Ryan Cui6290f032012-11-20 15:44:43 -0800178
Alex Klein1699fab2022-09-08 08:46:06 -0600179 cros_build_lib.AssertInsideChroot()
Ryan Cui6290f032012-11-20 15:44:43 -0800180
Alex Klein1699fab2022-09-08 08:46:06 -0600181 with sudo.SudoKeepAlive(ttyless_sudo=False):
182 with osutils.TempDir(set_global=True, sudo_rm=True) as tempdir:
183 sysroot = os.path.join(tempdir, SYSROOT)
184 os.mkdir(sysroot)
185 GenerateSysroot(sysroot, options).Perform()