blob: 60af9c2f599be0401efb72400159970ec5a5297f [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
Aviv Keshetb7519e12016-10-04 00:50:00 -070013from chromite.lib import constants
Ryan Cui6290f032012-11-20 15:44:43 -080014from chromite.lib import cros_build_lib
15from chromite.lib import commandline
16from 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
21DEFAULT_NAME = 'sysroot_%(package)s.tar.xz'
22PACKAGE_SEPARATOR = '/'
23SYSROOT = 'sysroot'
24
25
26def ParseCommandLine(argv):
27 """Parse args, and run environment-independent checks."""
28 parser = commandline.ArgumentParser(description=__doc__)
29 parser.add_argument('--board', required=True,
Alex Klein8212d492018-08-27 07:47:23 -060030 help='The board to generate the sysroot for.')
Ryan Cui6290f032012-11-20 15:44:43 -080031 parser.add_argument('--package', required=True,
Alex Klein8212d492018-08-27 07:47:23 -060032 help='The packages to generate the sysroot for.')
Manoj Gupta2c2a2a22018-02-12 13:13:32 -080033 parser.add_argument('--deps-only', action='store_true',
34 default=False,
35 help='Build dependencies only.')
Michael Spang46c52fb2015-05-28 00:20:18 -040036 parser.add_argument('--out-dir', type='path', required=True,
Ryan Cui6290f032012-11-20 15:44:43 -080037 help='Directory to place the generated tarball.')
Mike Frysinger8557a292017-08-15 11:23:51 -040038 parser.add_argument('--out-file', default=DEFAULT_NAME,
39 help='The name to give to the tarball. '
40 'Defaults to %(default)s.')
Ryan Cui6290f032012-11-20 15:44:43 -080041 options = parser.parse_args(argv)
42
Mike Frysinger8557a292017-08-15 11:23:51 -040043 options.out_file %= {
Manoj Gupta2c2a2a22018-02-12 13:13:32 -080044 'package': options.package.split()[0].replace(PACKAGE_SEPARATOR, '_'),
Mike Frysinger8557a292017-08-15 11:23:51 -040045 }
Ryan Cui6290f032012-11-20 15:44:43 -080046
47 return options
48
49
50class GenerateSysroot(object):
51 """Wrapper for generation functionality."""
52
53 PARALLEL_EMERGE = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
54
55 def __init__(self, sysroot, options):
56 """Initialize
57
Mike Frysinger02e1e072013-11-10 22:11:34 -050058 Args:
Ryan Cui6290f032012-11-20 15:44:43 -080059 sysroot: Path to sysroot.
60 options: Parsed options.
61 """
62 self.sysroot = sysroot
63 self.options = options
David James78d2e942013-07-31 15:34:45 -070064 self.extra_env = {'ROOT': self.sysroot, 'USE': os.environ.get('USE', '')}
65
66 def _Emerge(self, *args, **kwargs):
67 """Emerge the given packages using parallel_emerge."""
68 cmd = [self.PARALLEL_EMERGE, '--board=%s' % self.options.board,
69 '--usepkgonly', '--noreplace'] + list(args)
70 kwargs.setdefault('extra_env', self.extra_env)
Mike Frysinger45602c72019-09-22 02:15:11 -040071 cros_build_lib.sudo_run(cmd, **kwargs)
Ryan Cui6290f032012-11-20 15:44:43 -080072
Sloan Johnsona85640f2021-10-01 22:32:40 +000073 def _WriteConfig(self, sysroot):
74 sysroot.WriteConfig(sysroot.GenerateBoardSetupConfig(self.options.board))
75 # For the config to be correctly read, a stub make.conf is needed.
76 # pylint: disable=protected-access
77 make_conf_path = os.path.join(self.sysroot, sysroot_lib._MAKE_CONF)
78 assert not os.path.exists(make_conf_path), 'Expecting an empty sysroot.'
79 osutils.WriteFile(os.path.join(make_conf_path),
80 'source make.conf.board_setup', makedirs=True, sudo=True)
81
Ryan Cui6290f032012-11-20 15:44:43 -080082 def _InstallToolchain(self):
Bertrand SIMONNETa5d8b552015-03-25 16:03:34 -070083 # Create the sysroot's config.
Bertrand SIMONNETe2cec3f2015-04-06 16:12:54 -070084 sysroot = sysroot_lib.Sysroot(self.sysroot)
Sloan Johnsona85640f2021-10-01 22:32:40 +000085 self._WriteConfig(sysroot)
Alex Klein8212d492018-08-27 07:47:23 -060086 toolchain.InstallToolchain(sysroot, configure=False)
Ryan Cui6290f032012-11-20 15:44:43 -080087
88 def _InstallKernelHeaders(self):
David James78d2e942013-07-31 15:34:45 -070089 self._Emerge('sys-kernel/linux-headers')
Ryan Cui6290f032012-11-20 15:44:43 -080090
91 def _InstallBuildDependencies(self):
David James78d2e942013-07-31 15:34:45 -070092 # Calculate buildtime deps that are not runtime deps.
Mike Frysinger06a51c82021-04-06 11:39:17 -040093 raw_sysroot = build_target_lib.get_default_sysroot_path(self.options.board)
Manoj Gupta2c2a2a22018-02-12 13:13:32 -080094 packages = []
95 if not self.options.deps_only:
96 packages = self.options.package.split()
97 else:
98 for pkg in self.options.package.split():
99 cmd = ['qdepends', '-q', '-C', pkg]
Mike Frysinger45602c72019-09-22 02:15:11 -0400100 output = cros_build_lib.run(
Mike Frysingerc04ddb92019-12-09 21:19:47 -0500101 cmd, extra_env={'ROOT': raw_sysroot}, capture_output=True,
102 encoding='utf-8').stdout
David James78d2e942013-07-31 15:34:45 -0700103
Manoj Gupta2c2a2a22018-02-12 13:13:32 -0800104 if output.count('\n') > 1:
105 raise AssertionError('Too many packages matched for given pattern')
David James78d2e942013-07-31 15:34:45 -0700106
Manoj Gupta2c2a2a22018-02-12 13:13:32 -0800107 # qdepend outputs "package: deps", so only grab the deps.
108 deps = output.partition(':')[2].split()
109 packages.extend(deps)
110 # Install the required packages.
111 if packages:
112 self._Emerge(*packages)
Ryan Cui6290f032012-11-20 15:44:43 -0800113
114 def _CreateTarball(self):
Eliot Courtney93f76212020-10-22 11:16:33 +0900115 tarball_path = os.path.join(self.options.out_dir, self.options.out_file)
116 cros_build_lib.CreateTarball(tarball_path, self.sysroot, sudo=True)
Ryan Cui6290f032012-11-20 15:44:43 -0800117
118 def Perform(self):
119 """Generate the sysroot."""
120 self._InstallToolchain()
121 self._InstallKernelHeaders()
122 self._InstallBuildDependencies()
123 self._CreateTarball()
124
125
126def FinishParsing(options):
127 """Run environment dependent checks on parsed args."""
128 target = os.path.join(options.out_dir, options.out_file)
129 if os.path.exists(target):
130 cros_build_lib.Die('Output file %r already exists.' % target)
131
132 if not os.path.isdir(options.out_dir):
133 cros_build_lib.Die(
134 'Non-existent directory %r specified for --out-dir' % options.out_dir)
135
136
137def main(argv):
138 options = ParseCommandLine(argv)
139 FinishParsing(options)
140
Mike Frysinger8fd67dc2012-12-03 23:51:18 -0500141 cros_build_lib.AssertInsideChroot()
Ryan Cui6290f032012-11-20 15:44:43 -0800142
143 with sudo.SudoKeepAlive(ttyless_sudo=False):
David James4bc13702013-03-26 08:08:04 -0700144 with osutils.TempDir(set_global=True, sudo_rm=True) as tempdir:
Ryan Cui6290f032012-11-20 15:44:43 -0800145 sysroot = os.path.join(tempdir, SYSROOT)
146 os.mkdir(sysroot)
147 GenerateSysroot(sysroot, options).Perform()