blob: 80baa243a9e99506fe1f912ab2fd063b40545cd7 [file] [log] [blame]
Mike Frysingere58c0e22017-10-04 15:43:30 -04001# -*- coding: utf-8 -*-
Zdenek Behan508dcce2011-12-05 15:39:32 +01002# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
Mike Frysinger750c5f52014-09-16 16:16:57 -04006"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01007
Mike Frysinger383367e2014-09-16 15:06:17 -04008from __future__ import print_function
9
Mike Frysinger3ed47722017-08-08 14:59:08 -040010import errno
Mike Frysinger35247af2012-11-16 18:58:06 -050011import glob
Mike Frysinger3ed47722017-08-08 14:59:08 -040012import hashlib
Mike Frysinger7ccee992012-06-01 21:27:59 -040013import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010014import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070015import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010016
Aviv Keshetb7519e12016-10-04 00:50:00 -070017from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050018from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080019from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070020from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070021from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050022from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080023from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050024
25# Needs to be after chromite imports.
26import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010027
Mike Frysinger31596002012-12-03 23:54:24 -050028if cros_build_lib.IsInsideChroot():
29 # Only import portage after we've checked that we're inside the chroot.
30 # Outside may not have portage, in which case the above may not happen.
31 # We'll check in main() if the operation needs portage.
Mike Frysinger27e21b72018-07-12 14:20:21 -040032 # pylint: disable=import-error
Mike Frysinger31596002012-12-03 23:54:24 -050033 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010034
35
Matt Tennantf1e30972012-03-02 16:30:07 -080036EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010037PACKAGE_STABLE = '[stable]'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010038
39CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070040ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010041STABLE_OVERLAY = '/usr/local/portage/stable'
42CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010043
44
Mike Frysinger66bfde52017-09-12 16:42:57 -040045# The exact list of host toolchain packages we care about. These are the
46# packages that bots/devs install only from binpkgs and rely on the SDK bot
47# (chromiumos-sdk) to validate+uprev.
48#
Mike Frysinger66bfde52017-09-12 16:42:57 -040049# We don't use crossdev to manage the host toolchain for us, especially since
50# we diverge significantly now (with llvm/clang/etc...), and we don't need or
51# want crossdev managing /etc/portage config files for the sdk
52HOST_PACKAGES = (
53 'dev-lang/go',
Yunlian Jiang2cb91dc2018-03-08 10:56:27 -080054 'dev-libs/elfutils',
Mike Frysinger66bfde52017-09-12 16:42:57 -040055 'sys-devel/binutils',
56 'sys-devel/clang',
57 'sys-devel/gcc',
Yunlian Jiangf5721f32017-10-31 11:43:11 -070058 'sys-devel/lld',
Mike Frysinger66bfde52017-09-12 16:42:57 -040059 'sys-devel/llvm',
60 'sys-kernel/linux-headers',
61 'sys-libs/glibc',
62 'sys-libs/libcxx',
63 'sys-libs/libcxxabi',
64)
65
Mike Frysinger785b0c32017-09-13 01:35:59 -040066# These packages are also installed into the host SDK. However, they require
67# the cross-compilers to be installed first (because they need them to actually
68# build), so we have to delay their installation.
69HOST_POST_CROSS_PACKAGES = (
Manoj Gupta65f88442018-04-12 22:42:19 -070070 'dev-lang/rust',
71 'dev-util/cargo',
Mike Frysinger61a24392017-10-17 17:14:27 -040072 'virtual/target-sdk-post-cross',
Mike Frysinger785b0c32017-09-13 01:35:59 -040073)
74
75# New packages that we're in the process of adding to the SDK. Since the SDK
76# bot hasn't had a chance to run yet, there are no binary packages available,
77# so we have to list them here and wait. Once it completes, entries here can
78# be removed so they'll end up on bots & dev's systems.
79NEW_PACKAGES = (
Mike Frysinger785b0c32017-09-13 01:35:59 -040080)
81
Rahul Chaudhry4b803052015-05-13 15:25:56 -070082# Enable the Go compiler for these targets.
83TARGET_GO_ENABLED = (
84 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070085 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -070086 'armv7a-cros-linux-gnueabihf',
Rahul Chaudhry4d416582017-10-25 12:31:58 -070087 'aarch64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070088)
89CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
90
Manoj Gupta1b5642e2017-03-08 16:44:12 -080091# Enable llvm's compiler-rt for these targets.
92TARGET_COMPILER_RT_ENABLED = (
93 'armv7a-cros-linux-gnueabi',
Yunlian Jiang1b77ee42017-10-06 13:44:29 -070094 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -070095 'aarch64-cros-linux-gnu',
Manoj Gupta21f3a082018-03-06 21:25:39 -080096 'armv7m-cros-eabi',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080097)
98CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
99
Manoj Gupta946abb42017-04-12 14:27:19 -0700100TARGET_LLVM_PKGS_ENABLED = (
101 'armv7a-cros-linux-gnueabi',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700102 'armv7a-cros-linux-gnueabihf',
Manoj Gupta946abb42017-04-12 14:27:19 -0700103 'aarch64-cros-linux-gnu',
104 'x86_64-cros-linux-gnu',
105)
106
107LLVM_PKGS_TABLE = {
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -0700108 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
109 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700110 'ex_llvm-libunwind' : ['--ex-pkg', 'sys-libs/llvm-libunwind'],
Manoj Gupta946abb42017-04-12 14:27:19 -0700111}
112
Zdenek Behan508dcce2011-12-05 15:39:32 +0100113# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
114CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500115 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -0400116 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -0800117 'armv7a-cros-linux-gnueabi': '-gold',
Yunlian Jiang16c1a422017-10-04 10:33:22 -0700118 'armv7a-cros-linux-gnueabihf': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500119 'i686-pc-linux-gnu' : '-gold',
120 'x86_64-cros-linux-gnu' : '-gold',
121 },
Zdenek Behan508dcce2011-12-05 15:39:32 +0100122}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100123
124
David James66a09c42012-11-05 13:31:38 -0800125class Crossdev(object):
126 """Class for interacting with crossdev and caching its output."""
127
128 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
129 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800130 # Packages that needs separate handling, in addition to what we have from
131 # crossdev.
132 MANUAL_PKGS = {
Manoj Guptaf0a602e2017-08-02 10:25:45 -0700133 'clang': 'sys-devel',
Yunlian Jiang18ae9982017-11-03 09:15:31 -0700134 'lld': 'sys-devel',
Han Shene23782f2016-02-18 12:20:00 -0800135 'llvm': 'sys-devel',
Manoj Gupta20cfc6c2017-07-19 15:49:55 -0700136 'libcxxabi': 'sys-libs',
137 'libcxx': 'sys-libs',
Yunlian Jiangda3ce5f2018-04-25 14:10:01 -0700138 'elfutils': 'dev-libs',
Chirantan Ekbotee694cad2018-07-12 15:07:24 -0700139 'llvm-libunwind': 'sys-libs',
Han Shene23782f2016-02-18 12:20:00 -0800140 }
David James66a09c42012-11-05 13:31:38 -0800141
142 @classmethod
143 def Load(cls, reconfig):
Mike Frysinger3ed47722017-08-08 14:59:08 -0400144 """Load crossdev cache from disk.
145
146 We invalidate the cache when crossdev updates or this script changes.
147 """
David James90239b92012-11-05 15:31:34 -0800148 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
Mike Frysinger3ed47722017-08-08 14:59:08 -0400149 # If we run the compiled/cached .pyc file, we'll read/hash that when we
150 # really always want to track the source .py file.
151 script = os.path.abspath(__file__)
152 if script.endswith('.pyc'):
153 script = script[:-1]
154 setup_toolchains_hash = hashlib.md5(osutils.ReadFile(script)).hexdigest()
155
156 cls._CACHE = {
157 'crossdev_version': crossdev_version,
158 'setup_toolchains_hash': setup_toolchains_hash,
159 }
160
161 logging.debug('cache: checking file: %s', cls._CACHE_FILE)
162 if reconfig:
163 logging.debug('cache: forcing regen due to reconfig')
164 return
165
166 try:
167 file_data = osutils.ReadFile(cls._CACHE_FILE)
168 except IOError as e:
169 if e.errno != errno.ENOENT:
170 logging.warning('cache: reading failed: %s', e)
171 osutils.SafeUnlink(cls._CACHE_FILE)
172 return
173
174 try:
175 data = json.loads(file_data)
176 except ValueError as e:
177 logging.warning('cache: ignoring invalid content: %s', e)
178 return
179
180 if crossdev_version != data.get('crossdev_version'):
181 logging.debug('cache: rebuilding after crossdev upgrade')
182 elif setup_toolchains_hash != data.get('setup_toolchains_hash'):
183 logging.debug('cache: rebuilding after cros_setup_toolchains change')
184 else:
185 logging.debug('cache: content is up-to-date!')
186 cls._CACHE = data
David James66a09c42012-11-05 13:31:38 -0800187
188 @classmethod
189 def Save(cls):
190 """Store crossdev cache on disk."""
191 # Save the cache from the successful run.
192 with open(cls._CACHE_FILE, 'w') as f:
193 json.dump(cls._CACHE, f)
194
195 @classmethod
196 def GetConfig(cls, target):
197 """Returns a map of crossdev provided variables about a tuple."""
198 CACHE_ATTR = '_target_tuple_map'
199
200 val = cls._CACHE.setdefault(CACHE_ATTR, {})
201 if not target in val:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400202 if target.startswith('host'):
Mike Frysinger66bfde52017-09-12 16:42:57 -0400203 conf = {
204 'crosspkgs': [],
205 'target': toolchain.GetHostTuple(),
206 }
Mike Frysinger785b0c32017-09-13 01:35:59 -0400207 if target == 'host':
208 packages_list = HOST_PACKAGES
209 else:
210 packages_list = HOST_POST_CROSS_PACKAGES
Mike Frysinger66bfde52017-09-12 16:42:57 -0400211 manual_pkgs = dict((pkg, cat) for cat, pkg in
Mike Frysinger785b0c32017-09-13 01:35:59 -0400212 [x.split('/') for x in packages_list])
Mike Frysinger66bfde52017-09-12 16:42:57 -0400213 else:
214 # Build the crossdev command.
215 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
216 if target in TARGET_COMPILER_RT_ENABLED:
217 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
218 if target in TARGET_GO_ENABLED:
219 cmd.extend(CROSSDEV_GO_ARGS)
220 if target in TARGET_LLVM_PKGS_ENABLED:
221 for pkg in LLVM_PKGS_TABLE:
222 cmd.extend(LLVM_PKGS_TABLE[pkg])
223 cmd.extend(['-t', target])
224 # Catch output of crossdev.
225 out = cros_build_lib.RunCommand(
226 cmd, print_cmd=False, redirect_stdout=True).output.splitlines()
227 # List of tuples split at the first '=', converted into dict.
228 conf = dict((k, cros_build_lib.ShellUnquote(v))
229 for k, v in (x.split('=', 1) for x in out))
230 conf['crosspkgs'] = conf['crosspkgs'].split()
Han Shene23782f2016-02-18 12:20:00 -0800231
Mike Frysinger66bfde52017-09-12 16:42:57 -0400232 manual_pkgs = cls.MANUAL_PKGS
233
234 for pkg, cat in manual_pkgs.items():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400235 conf[pkg + '_pn'] = pkg
236 conf[pkg + '_category'] = cat
237 if pkg not in conf['crosspkgs']:
238 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800239
240 val[target] = conf
241
David James66a09c42012-11-05 13:31:38 -0800242 return val[target]
243
244 @classmethod
245 def UpdateTargets(cls, targets, usepkg, config_only=False):
246 """Calls crossdev to initialize a cross target.
247
248 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700249 targets: The list of targets to initialize using crossdev.
250 usepkg: Copies the commandline opts.
251 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800252 """
253 configured_targets = cls._CACHE.setdefault('configured_targets', [])
254
255 cmdbase = ['crossdev', '--show-fail-log']
256 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
257 # Pick stable by default, and override as necessary.
258 cmdbase.extend(['-P', '--oneshot'])
259 if usepkg:
260 cmdbase.extend(['-P', '--getbinpkg',
261 '-P', '--usepkgonly',
262 '--without-headers'])
263
Christopher Wileyb22c0712015-06-02 10:37:03 -0700264 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800265 cmdbase.extend(['--overlays', overlays])
266 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
267
Yunlian Jiang4ff84172018-05-12 13:03:01 -0700268 # Build target by the reversed alphabetical order to make sure
269 # armv7a-cros-linux-gnueabihf builds before armv7a-cros-linux-gnueabi
Yunlian Jiang85c606a2017-10-10 20:58:53 -0700270 # because some dependency issue. This can be reverted once we
271 # migrated to armv7a-cros-linux-gnueabihf. crbug.com/711369
Yunlian Jiang4ff84172018-05-12 13:03:01 -0700272 for target in sorted(targets, reverse=True):
David James66a09c42012-11-05 13:31:38 -0800273 if config_only and target in configured_targets:
274 continue
275
276 cmd = cmdbase + ['-t', target]
277
278 for pkg in GetTargetPackages(target):
279 if pkg == 'gdb':
280 # Gdb does not have selectable versions.
281 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700282 elif pkg == 'ex_compiler-rt':
283 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700284 elif pkg == 'ex_go':
285 # Go does not have selectable versions.
286 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700287 elif pkg in LLVM_PKGS_TABLE:
288 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800289 elif pkg in cls.MANUAL_PKGS:
290 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700291 else:
292 # The first of the desired versions is the "primary" one.
293 version = GetDesiredPackageVersions(target, pkg)[0]
294 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800295
296 cmd.extend(targets[target]['crossdev'].split())
297 if config_only:
298 # In this case we want to just quietly reinit
299 cmd.append('--init-target')
300 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
301 else:
302 cros_build_lib.RunCommand(cmd)
303
304 configured_targets.append(target)
305
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100306
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100307def GetTargetPackages(target):
308 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800309 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100310 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800311 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100312
313
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100314# Portage helper functions:
315def GetPortagePackage(target, package):
316 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800317 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100318 # Portage category:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400319 if target.startswith('host') or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100320 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100322 category = conf['category']
323 # Portage package:
324 pn = conf[package + '_pn']
325 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500326 assert category
327 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100328 return '%s/%s' % (category, pn)
329
330
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700331def PortageTrees(root):
332 """Return the portage trees for a given root."""
333 if root == '/':
334 return portage.db['/']
335 # The portage logic requires the path always end in a slash.
336 root = root.rstrip('/') + '/'
337 return portage.create_trees(target_root=root, config_root=root)[root]
338
339
340def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100341 """Extracts the list of current versions of a target, package pair.
342
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500343 Args:
344 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700345 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100346
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500347 Returns:
348 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100349 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100350 versions = []
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700351 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100352 version = portage.versions.cpv_getversion(pkg)
353 versions.append(version)
354 return versions
355
356
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700357def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100358 """Extracts the current stable version for a given package.
359
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500360 Args:
361 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
362 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700363 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100364
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500365 Returns:
366 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367 """
David James90239b92012-11-05 15:31:34 -0800368 pkgtype = 'vartree' if installed else 'porttree'
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700369 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800370 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100371
372
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700373def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100374 """Resolves keywords in a given version list for a particular package.
375
376 Resolving means replacing PACKAGE_STABLE with the actual number.
377
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500378 Args:
379 target: The target to operate on (e.g. i686-pc-linux-gnu)
380 package: The target/package to operate on (e.g. gcc)
381 versions: List of versions to resolve
382 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700383 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500385 Returns:
386 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100387 """
388 resolved = []
David James90239b92012-11-05 15:31:34 -0800389 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700390 if not installed:
391 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 for version in versions:
393 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700394 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400395 else:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100396 resolved.append(version)
397 return resolved
398
399
400def GetDesiredPackageVersions(target, package):
401 """Produces the list of desired versions for each target, package pair.
402
403 The first version in the list is implicitly treated as primary, ie.
404 the version that will be initialized by crossdev and selected.
405
406 If the version is PACKAGE_STABLE, it really means the current version which
407 is emerged by using the package atom with no particular version key.
408 Since crossdev unmasks all packages by default, this will actually
409 mean 'unstable' in most cases.
410
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500411 Args:
412 target: The target to operate on (e.g. i686-pc-linux-gnu)
413 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100414
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500415 Returns:
416 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100417 """
Mike Frysingerd23be272017-09-12 17:18:44 -0400418 if package in GetTargetPackages(target):
419 return [PACKAGE_STABLE]
420 else:
421 return []
Zdenek Behan508dcce2011-12-05 15:39:32 +0100422
423
424def TargetIsInitialized(target):
425 """Verifies if the given list of targets has been correctly initialized.
426
427 This determines whether we have to call crossdev while emerging
428 toolchain packages or can do it using emerge. Emerge is naturally
429 preferred, because all packages can be updated in a single pass.
430
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500431 Args:
432 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100433
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500434 Returns:
435 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100436 """
437 # Check if packages for the given target all have a proper version.
438 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100439 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800440 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100441 # Do we even want this package && is it initialized?
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400442 if not (GetStablePackageVersion(atom, True) and
443 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100444 return False
445 return True
446 except cros_build_lib.RunCommandError:
447 # Fails - The target has likely never been initialized before.
448 return False
449
450
451def RemovePackageMask(target):
452 """Removes a package.mask file for the given platform.
453
454 The pre-existing package.mask files can mess with the keywords.
455
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500456 Args:
457 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100458 """
459 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700460 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100461
462
Zdenek Behan508dcce2011-12-05 15:39:32 +0100463# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700464def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500465 """Rebuild libtool as needed
466
467 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
468 gcc, libtool will break. We can't use binary packages either as those will
469 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700470
471 Args:
472 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500473 """
474 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700475 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500476 for line in f:
477 # Look for a line like:
478 # sys_lib_search_path_spec="..."
479 # It'll be a list of paths and gcc will be one of them.
480 if line.startswith('sys_lib_search_path_spec='):
481 line = line.rstrip()
482 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400483 root_path = os.path.join(root, path.lstrip(os.path.sep))
484 logging.debug('Libtool: checking %s', root_path)
485 if not os.path.exists(root_path):
486 logging.info('Rebuilding libtool after gcc upgrade')
487 logging.info(' %s', line)
488 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500489 needs_update = True
490 break
491
492 if needs_update:
493 break
494
495 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700496 cmd = [EMERGE_CMD, '--oneshot']
497 if root != '/':
498 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
499 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500500 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400501 else:
502 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500503
504
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700505def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100506 """Determines which packages need update/unmerge and defers to portage.
507
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500508 Args:
509 targets: The list of targets to update
510 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700511 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100512 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100513 # For each target, we do two things. Figure out the list of updates,
514 # and figure out the appropriate keywords/masks. Crossdev will initialize
515 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400516 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800517 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100518 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400519 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100520 # Record the highest needed version for each target, for masking purposes.
521 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100522 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100523 # Portage name for the package
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400524 logging.debug(' Checking package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100525 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700526 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100527 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200528 desired_num = VersionListToNumeric(target, package, desired, False)
Mike Frysinger785b0c32017-09-13 01:35:59 -0400529 if pkg in NEW_PACKAGES and usepkg:
530 # Skip this binary package (for now).
531 continue
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100532 mergemap[pkg] = set(desired_num).difference(current)
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400533 logging.debug(' %s -> %s', current, desired_num)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100534
Mike Frysinger7f0e1982017-09-12 17:08:50 -0400535 packages = [pkg for pkg, vers in mergemap.items() if vers]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400537 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800538 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100539
Mike Frysinger3bba5032016-09-20 14:15:04 -0400540 logging.info('Updating packages:')
541 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100543 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100544 if usepkg:
545 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700546 if root != '/':
547 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548
549 cmd.extend(packages)
550 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800551 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100552
553
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700554def CleanTargets(targets, root='/'):
555 """Unmerges old packages that are assumed unnecessary.
556
557 Args:
558 targets: The list of targets to clean up.
559 root: The install root in which we want packages cleaned up.
560 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561 unmergemap = {}
562 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400563 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100564 for package in GetTargetPackages(target):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400565 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100566 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700567 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100568 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700569 # NOTE: This refers to installed packages (vartree) rather than the
570 # Portage version (porttree and/or bintree) when determining the current
571 # version. While this isn't the most accurate thing to do, it is probably
572 # a good simple compromise, which should have the desired result of
573 # uninstalling everything but the latest installed version. In
574 # particular, using the bintree (--usebinpkg) requires a non-trivial
575 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200576 desired_num = VersionListToNumeric(target, package, desired, True)
577 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400578 logging.warning('Error detecting stable version for %s, '
579 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200580 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100581 unmergemap[pkg] = set(current).difference(desired_num)
582
583 # Cleaning doesn't care about consistency and rebuilding package.* files.
584 packages = []
585 for pkg, vers in unmergemap.iteritems():
586 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
587
588 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400589 logging.info('Cleaning packages:')
590 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100591 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700592 if root != '/':
593 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100594 cmd.extend(packages)
595 cros_build_lib.RunCommand(cmd)
596 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400597 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100598
599
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700600def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100601 """Runs gcc-config and binutils-config to select the desired.
602
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500603 Args:
604 targets: The targets to select
605 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700606 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100607 """
608 for package in ['gcc', 'binutils']:
609 for target in targets:
Mike Frysinger785b0c32017-09-13 01:35:59 -0400610 # See if this package is part of this target.
611 if package not in GetTargetPackages(target):
612 logging.debug('%s: %s is not used', target, package)
613 continue
614
Zdenek Behan508dcce2011-12-05 15:39:32 +0100615 # Pick the first version in the numbered list as the selected one.
616 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700617 desired_num = VersionListToNumeric(target, package, desired, True,
618 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100619 desired = desired_num[0]
620 # *-config does not play revisions, strip them, keep just PV.
621 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
622
Mike Frysinger785b0c32017-09-13 01:35:59 -0400623 if target.startswith('host'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100624 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800625 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100626
627 # And finally, attach target to it.
628 desired = '%s-%s' % (target, desired)
629
630 # Target specific hacks
631 if package in suffixes:
632 if target in suffixes[package]:
633 desired += suffixes[package][target]
634
David James7ec5efc2012-11-06 09:39:49 -0800635 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700636 if root != '/':
637 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800638 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500639 result = cros_build_lib.RunCommand(
640 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
641 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700642
643 # Do not reconfig when the current is live or nothing needs to be done.
644 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100645 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500646 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700647 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100648
649
Mike Frysinger35247af2012-11-16 18:58:06 -0500650def ExpandTargets(targets_wanted):
651 """Expand any possible toolchain aliases into full targets
652
653 This will expand 'all' and 'sdk' into the respective toolchain tuples.
654
655 Args:
656 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500657
Mike Frysinger35247af2012-11-16 18:58:06 -0500658 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300659 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500660 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500661 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700662 if targets_wanted == set(['boards']):
663 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300664 return {}
665
666 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500667 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300668 return all_targets
669 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500670 # Filter out all the non-sdk toolchains as we don't want to mess
671 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300672 return toolchain.FilterToolchains(all_targets, 'sdk', True)
673
674 # Verify user input.
675 nonexistent = targets_wanted.difference(all_targets)
676 if nonexistent:
677 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
678 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500679
680
David Jamesf8c672f2012-11-06 13:38:11 -0800681def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700682 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100683 """Performs all steps to create a synchronized toolchain enviroment.
684
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500685 Args:
686 usepkg: Use prebuilt packages
687 deleteold: Unmerge deprecated packages
688 hostonly: Only setup the host toolchain
689 reconfig: Reload crossdev config and reselect toolchains
690 targets_wanted: All the targets to update
691 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700692 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100693 """
David Jamesf8c672f2012-11-06 13:38:11 -0800694 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100695 if not hostonly:
696 # For hostonly, we can skip most of the below logic, much of which won't
697 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500698 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400699
Don Garrettc0c74002015-10-09 12:58:19 -0700700 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300701 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400702 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800703 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100704
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100705 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400706 for target in targets:
707 if TargetIsInitialized(target):
708 reconfig_targets[target] = targets[target]
709 else:
710 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100711 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400712 logging.info('The following targets need to be re-initialized:')
713 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800714 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200715 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800716 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100717
Mike Frysinger66814c32017-10-09 18:11:46 -0400718 # If we're building a subset of toolchains for a board, we might not have
719 # all the tuples that the packages expect. We don't define the "full" set
720 # of tuples currently other than "whatever the full sdk has normally".
721 if usepkg or set(('all', 'sdk')) & targets_wanted:
722 # Since we have cross-compilers now, we can update these packages.
723 targets['host-post-cross'] = {}
Mike Frysinger785b0c32017-09-13 01:35:59 -0400724
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100725 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400726 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100727
728 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700729 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
730 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800731
732 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700733 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100734
Mike Frysingerc880a962013-11-08 13:59:06 -0500735 # Now that we've cleared out old versions, see if we need to rebuild
736 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700737 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500738
Zdenek Behan508dcce2011-12-05 15:39:32 +0100739
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700740def ShowConfig(name):
741 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500742
743 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700744 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500745 """
Don Garrettc0c74002015-10-09 12:58:19 -0700746 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500747 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400748 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400749 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800750 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400751 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500752
753
Mike Frysinger35247af2012-11-16 18:58:06 -0500754def GeneratePathWrapper(root, wrappath, path):
755 """Generate a shell script to execute another shell script
756
757 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
758 argv[0] won't be pointing to the correct path, generate a shell script that
759 just executes another program with its full path.
760
761 Args:
762 root: The root tree to generate scripts inside of
763 wrappath: The full path (inside |root|) to create the wrapper
764 path: The target program which this wrapper will execute
765 """
766 replacements = {
767 'path': path,
768 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
769 }
Takuto Ikuta58403972018-08-16 18:52:51 +0900770
771 # Do not use exec here, because exec invokes script with absolute path in
772 # argv0. Keeping relativeness allows us to remove abs path from compile result
773 # and leads directory independent build cache sharing in some distributed
774 # build system.
Mike Frysinger35247af2012-11-16 18:58:06 -0500775 wrapper = """#!/bin/sh
Takuto Ikuta58403972018-08-16 18:52:51 +0900776basedir=$(dirname "$0")
777"${basedir}/%(relroot)s%(path)s" "$@"
778exit "$?"
Mike Frysinger35247af2012-11-16 18:58:06 -0500779""" % replacements
780 root_wrapper = root + wrappath
781 if os.path.islink(root_wrapper):
782 os.unlink(root_wrapper)
783 else:
784 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
785 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400786 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500787
788
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700789def FixClangXXWrapper(root, path):
790 """Fix wrapper shell scripts and symlinks for invoking clang++
791
792 In a typical installation, clang++ symlinks to clang, which symlinks to the
793 elf executable. The executable distinguishes between clang and clang++ based
794 on argv[0].
795
796 When invoked through the LdsoWrapper, argv[0] always contains the path to the
797 executable elf file, making clang/clang++ invocations indistinguishable.
798
799 This function detects if the elf executable being wrapped is clang-X.Y, and
800 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
801
802 The calling sequence now becomes:
803 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
804 the Ldsowrapper).
805 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
806 to the original clang-3.9 elf.
807 -) The difference this time is that inside the elf file execution, $0 is
808 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
809
Manoj Guptaae268142018-04-27 23:28:36 -0700810 Update: Starting since clang 7, the clang and clang++ are symlinks to
811 clang-7 binary, not clang-7.0. The pattern match is extended to handle
812 both clang-7 and clang-7.0 cases for now. (https://crbug.com/837889)
813
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700814 Args:
815 root: The root tree to generate scripts / symlinks inside of
816 path: The target elf for which LdsoWrapper was created
817 """
Manoj Guptaae268142018-04-27 23:28:36 -0700818 if re.match(r'/usr/bin/clang-\d+(\.\d+)*$', path):
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700819 logging.info('fixing clang++ invocation for %s', path)
820 clangdir = os.path.dirname(root + path)
821 clang = os.path.basename(path)
822 clangxx = clang.replace('clang', 'clang++')
823
824 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
825 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
826
827 # Create a hardlink clang++-X.Y pointing to clang-X.Y
828 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
829
830 # Adjust the clang++ symlink to point to clang++-X.Y
831 os.unlink(os.path.join(clangdir, 'clang++'))
832 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
833
834
Mike Frysinger35247af2012-11-16 18:58:06 -0500835def FileIsCrosSdkElf(elf):
836 """Determine if |elf| is an ELF that we execute in the cros_sdk
837
838 We don't need this to be perfect, just quick. It makes sure the ELF
839 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
840
841 Args:
842 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500843
Mike Frysinger35247af2012-11-16 18:58:06 -0500844 Returns:
845 True if we think |elf| is a native ELF
846 """
847 with open(elf) as f:
848 data = f.read(20)
849 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
850 return (data[0:4] == '\x7fELF' and
851 data[4] == '\x02' and
852 data[5] == '\x01' and
853 data[18] == '\x3e')
854
855
856def IsPathPackagable(ptype, path):
857 """Should the specified file be included in a toolchain package?
858
859 We only need to handle files as we'll create dirs as we need them.
860
861 Further, trim files that won't be useful:
862 - non-english translations (.mo) since it'd require env vars
863 - debug files since these are for the host compiler itself
864 - info/man pages as they're big, and docs are online, and the
865 native docs should work fine for the most part (`man gcc`)
866
867 Args:
868 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
869 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500870
Mike Frysinger35247af2012-11-16 18:58:06 -0500871 Returns:
872 True if we want to include this path in the package
873 """
874 return not (ptype in ('dir',) or
875 path.startswith('/usr/lib/debug/') or
876 os.path.splitext(path)[1] == '.mo' or
877 ('/man/' in path or '/info/' in path))
878
879
880def ReadlinkRoot(path, root):
881 """Like os.readlink(), but relative to a |root|
882
883 Args:
884 path: The symlink to read
885 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500886
Mike Frysinger35247af2012-11-16 18:58:06 -0500887 Returns:
888 A fully resolved symlink path
889 """
890 while os.path.islink(root + path):
891 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
892 return path
893
894
895def _GetFilesForTarget(target, root='/'):
896 """Locate all the files to package for |target|
897
898 This does not cover ELF dependencies.
899
900 Args:
901 target: The toolchain target name
902 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500903
Mike Frysinger35247af2012-11-16 18:58:06 -0500904 Returns:
905 A tuple of a set of all packable paths, and a set of all paths which
906 are also native ELFs
907 """
908 paths = set()
909 elfs = set()
910
911 # Find all the files owned by the packages for this target.
912 for pkg in GetTargetPackages(target):
Mike Frysinger35247af2012-11-16 18:58:06 -0500913
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700914 # Skip Go compiler from redistributable packages.
915 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
916 # into it. Due to this, the toolchain cannot be unpacked anywhere
917 # else and be readily useful. To enable packaging Go, we need to:
918 # -) Tweak the wrappers/environment to override GOROOT
919 # automatically based on the unpack location.
920 # -) Make sure the ELF dependency checking and wrapping logic
921 # below skips the Go toolchain executables and libraries.
922 # -) Make sure the packaging process maintains the relative
923 # timestamps of precompiled standard library packages.
924 # (see dev-lang/go ebuild for details).
925 if pkg == 'ex_go':
926 continue
927
Yunlian Jiang36f35242018-04-27 10:18:40 -0700928 # Use armv7a-cros-linux-gnueabi/compiler-rt for
929 # armv7a-cros-linux-gnueabihf/compiler-rt.
930 # Currently the armv7a-cros-linux-gnueabi is actually
931 # the same as armv7a-cros-linux-gnueabihf with different names.
932 # Because of that, for compiler-rt, it generates the same binary in
933 # the same location. To avoid the installation conflict, we do not
934 # install anything for 'armv7a-cros-linux-gnueabihf'. This would cause
935 # problem if other people try to use standalone armv7a-cros-linux-gnueabihf
936 # toolchain.
937 if 'compiler-rt' in pkg and 'armv7a-cros-linux-gnueabi' in target:
938 atom = GetPortagePackage(target, pkg)
939 cat, pn = atom.split('/')
940 ver = GetInstalledPackageVersions(atom, root=root)[0]
Yunlian Jiang36f35242018-04-27 10:18:40 -0700941 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
942 settings=portage.settings)
943 contents = dblink.getcontents()
944 if not contents:
945 if 'hf' in target:
946 new_target = 'armv7a-cros-linux-gnueabi'
947 else:
948 new_target = 'armv7a-cros-linux-gnueabihf'
949 atom = GetPortagePackage(new_target, pkg)
950 else:
951 atom = GetPortagePackage(target, pkg)
952
Mike Frysinger35247af2012-11-16 18:58:06 -0500953 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700954 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700955 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500956
Mike Frysinger35247af2012-11-16 18:58:06 -0500957 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
958 settings=portage.settings)
959 contents = dblink.getcontents()
960 for obj in contents:
961 ptype = contents[obj][0]
962 if not IsPathPackagable(ptype, obj):
963 continue
964
965 if ptype == 'obj':
966 # For native ELFs, we need to pull in their dependencies too.
967 if FileIsCrosSdkElf(obj):
968 elfs.add(obj)
969 paths.add(obj)
970
971 return paths, elfs
972
973
974def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500975 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500976 """Link in all packable files and their runtime dependencies
977
978 This also wraps up executable ELFs with helper scripts.
979
980 Args:
981 output_dir: The output directory to store files
982 paths: All the files to include
983 elfs: All the files which are ELFs (a subset of |paths|)
984 ldpaths: A dict of static ldpath information
985 path_rewrite_func: User callback to rewrite paths in output_dir
986 root: The root path to pull all packages/files from
987 """
988 # Link in all the files.
Mike Frysinger221bd822017-09-29 02:51:47 -0400989 sym_paths = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500990 for path in paths:
991 new_path = path_rewrite_func(path)
992 dst = output_dir + new_path
993 osutils.SafeMakedirs(os.path.dirname(dst))
994
995 # Is this a symlink which we have to rewrite or wrap?
996 # Delay wrap check until after we have created all paths.
997 src = root + path
998 if os.path.islink(src):
999 tgt = os.readlink(src)
1000 if os.path.sep in tgt:
Mike Frysinger221bd822017-09-29 02:51:47 -04001001 sym_paths[lddtree.normpath(ReadlinkRoot(src, root))] = new_path
Mike Frysinger35247af2012-11-16 18:58:06 -05001002
1003 # Rewrite absolute links to relative and then generate the symlink
1004 # ourselves. All other symlinks can be hardlinked below.
1005 if tgt[0] == '/':
1006 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
1007 os.symlink(tgt, dst)
1008 continue
1009
1010 os.link(src, dst)
1011
Mike Frysinger35247af2012-11-16 18:58:06 -05001012 # Locate all the dependencies for all the ELFs. Stick them all in the
1013 # top level "lib" dir to make the wrapper simpler. This exact path does
1014 # not matter since we execute ldso directly, and we tell the ldso the
1015 # exact path to search for its libraries.
1016 libdir = os.path.join(output_dir, 'lib')
1017 osutils.SafeMakedirs(libdir)
1018 donelibs = set()
Mike Frysinger4331fc62017-09-28 14:03:25 -04001019 glibc_re = re.compile(r'/lib(c|pthread)-[0-9.]+\.so$')
Mike Frysinger35247af2012-11-16 18:58:06 -05001020 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -04001021 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -05001022 interp = e['interp']
Yunlian Jiang196e8f42017-09-20 12:29:47 -07001023 # Do not create wrapper for libc. crbug.com/766827
1024 if interp and not glibc_re.search(elf):
Mike Frysinger35247af2012-11-16 18:58:06 -05001025 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -04001026 interp = os.path.join('/lib', os.path.basename(interp))
1027 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
1028 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -07001029 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -05001030
Mike Frysinger221bd822017-09-29 02:51:47 -04001031 # Wrap any symlinks to the wrapper.
1032 if elf in sym_paths:
1033 link = sym_paths[elf]
1034 GeneratePathWrapper(output_dir, link, elf)
1035
Mike Frysinger35247af2012-11-16 18:58:06 -05001036 for lib, lib_data in e['libs'].iteritems():
1037 if lib in donelibs:
1038 continue
1039
1040 src = path = lib_data['path']
1041 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -07001042 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -05001043 continue
1044 donelibs.add(lib)
1045
1046 # Needed libs are the SONAME, but that is usually a symlink, not a
1047 # real file. So link in the target rather than the symlink itself.
1048 # We have to walk all the possible symlinks (SONAME could point to a
1049 # symlink which points to a symlink), and we have to handle absolute
1050 # ourselves (since we have a "root" argument).
1051 dst = os.path.join(libdir, os.path.basename(path))
1052 src = ReadlinkRoot(src, root)
1053
1054 os.link(root + src, dst)
1055
1056
1057def _EnvdGetVar(envd, var):
1058 """Given a Gentoo env.d file, extract a var from it
1059
1060 Args:
1061 envd: The env.d file to load (may be a glob path)
1062 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -05001063
Mike Frysinger35247af2012-11-16 18:58:06 -05001064 Returns:
1065 The value of |var|
1066 """
1067 envds = glob.glob(envd)
1068 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1069 envd = envds[0]
1070 return cros_build_lib.LoadKeyValueFile(envd)[var]
1071
1072
1073def _ProcessBinutilsConfig(target, output_dir):
1074 """Do what binutils-config would have done"""
1075 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001076
1077 # Locate the bin dir holding the gold linker.
1078 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1079 target, 'binutils-bin')
1080 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001081 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001082 if not srcpath:
1083 # Maybe this target doesn't support gold.
1084 globpath = os.path.join(binutils_bin_path, '*')
1085 srcpath = glob.glob(globpath)
1086 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1087 % globpath)
1088 srcpath = srcpath[0]
1089 ld_path = os.path.join(srcpath, 'ld')
1090 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1091 ld_path = os.path.join(srcpath, 'ld.bfd')
1092 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1093 ld_path = os.path.join(srcpath, 'ld.gold')
1094 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1095 % ld_path)
1096
1097 # Nope, no gold support to be found.
1098 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001099 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001100 else:
1101 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001102 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001103
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001104 # Package the binutils-bin directory without the '-gold' suffix
1105 # if gold is not enabled as the default linker for this target.
1106 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1107 if not gold_supported:
1108 srcpath = srcpath[:-len('-gold')]
1109 ld_path = os.path.join(srcpath, 'ld')
1110 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1111
Mike Frysinger78b7a812014-11-26 19:45:23 -05001112 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001113 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1114 for prog in os.listdir(output_dir + srcpath):
1115 # Skip binaries already wrapped.
1116 if not prog.endswith('.real'):
1117 GeneratePathWrapper(output_dir, binpath + prog,
1118 os.path.join(srcpath, prog))
1119 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1120 os.path.join(srcpath, prog))
1121
David James27ac4ae2012-12-03 23:16:15 -08001122 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001123 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1124 if gold_supported:
1125 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001126 else:
1127 # If gold is not enabled as the default linker and 2 env.d
1128 # files exist, pick the one without the '-gold' suffix.
1129 envds = sorted(glob.glob(envd))
1130 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1131 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001132 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1133 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1134 output_dir + libpath)
1135
1136
1137def _ProcessGccConfig(target, output_dir):
1138 """Do what gcc-config would have done"""
1139 binpath = '/bin'
1140 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1141 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1142 for prog in os.listdir(output_dir + srcpath):
1143 # Skip binaries already wrapped.
1144 if (not prog.endswith('.real') and
1145 not prog.endswith('.elf') and
1146 prog.startswith(target)):
1147 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1148 os.path.join(srcpath, prog))
1149 return srcpath
1150
1151
Frank Henigman179ec7c2015-02-06 03:01:09 -05001152def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1153 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001154 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001155 for sysroot_wrapper in glob.glob(os.path.join(
1156 output_dir + srcpath, 'sysroot_wrapper*')):
1157 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
Douglas Andersoncc828a52017-10-13 13:07:25 -07001158
1159 # In order to optimize startup time in the chroot we run python a little
1160 # differently there. Put it back to the more portable way here.
Mike Frysingerdcad4e02018-08-03 16:20:02 -04001161 # See https://crbug.com/773138 for some details.
Douglas Andersoncc828a52017-10-13 13:07:25 -07001162 if contents[0] == '#!/usr/bin/python2 -S':
1163 contents[0] = '#!/usr/bin/env python2'
1164
Frank Henigman179ec7c2015-02-06 03:01:09 -05001165 for num in xrange(len(contents)):
1166 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001167 assert 'True' in contents[num]
1168 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001169 break
1170 # Can't update the wrapper in place since it's a hardlink to a file in /.
1171 os.unlink(sysroot_wrapper)
1172 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1173 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001174
1175
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001176def _CreateMainLibDir(target, output_dir):
1177 """Create some lib dirs so that compiler can get the right Gcc paths"""
1178 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'lib'))
1179 osutils.SafeMakedirs(os.path.join(output_dir, 'usr', target, 'usr/lib'))
1180
1181
Mike Frysinger35247af2012-11-16 18:58:06 -05001182def _ProcessDistroCleanups(target, output_dir):
1183 """Clean up the tree and remove all distro-specific requirements
1184
1185 Args:
1186 target: The toolchain target name
1187 output_dir: The output directory to clean up
1188 """
1189 _ProcessBinutilsConfig(target, output_dir)
1190 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001191 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Yunlian Jiang5ad6b512017-09-20 09:27:45 -07001192 _CreateMainLibDir(target, output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001193
1194 osutils.RmDir(os.path.join(output_dir, 'etc'))
1195
1196
1197def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1198 """Setup a tree from the packages for the specified target
1199
1200 This populates a path with all the files from toolchain packages so that
1201 a tarball can easily be generated from the result.
1202
1203 Args:
1204 target: The target to create a packagable root from
1205 output_dir: The output directory to place all the files
1206 ldpaths: A dict of static ldpath information
1207 root: The root path to pull all packages/files from
1208 """
1209 # Find all the files owned by the packages for this target.
1210 paths, elfs = _GetFilesForTarget(target, root=root)
1211
1212 # Link in all the package's files, any ELF dependencies, and wrap any
1213 # executable ELFs with helper scripts.
1214 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001215 """Move /usr/bin to /bin so people can just use that toplevel dir
1216
1217 Note we do not apply this to clang - there is correlation between clang's
1218 search path for libraries / inclusion and its installation path.
1219 """
1220 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1221 return path[4:]
1222 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001223 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1224 path_rewrite_func=MoveUsrBinToBin, root=root)
1225
1226 # The packages, when part of the normal distro, have helper scripts
1227 # that setup paths and such. Since we are making this standalone, we
1228 # need to preprocess all that ourselves.
1229 _ProcessDistroCleanups(target, output_dir)
1230
1231
1232def CreatePackages(targets_wanted, output_dir, root='/'):
1233 """Create redistributable cross-compiler packages for the specified targets
1234
1235 This creates toolchain packages that should be usable in conjunction with
1236 a downloaded sysroot (created elsewhere).
1237
1238 Tarballs (one per target) will be created in $PWD.
1239
1240 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001241 targets_wanted: The targets to package up.
1242 output_dir: The directory to put the packages in.
1243 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001244 """
Ralph Nathan03047282015-03-23 11:09:32 -07001245 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001246 osutils.SafeMakedirs(output_dir)
1247 ldpaths = lddtree.LoadLdpaths(root)
1248 targets = ExpandTargets(targets_wanted)
1249
Mike Frysinger221bd822017-09-29 02:51:47 -04001250 with osutils.TempDir(prefix='create-packages') as tempdir:
1251 logging.debug('Using tempdir: %s', tempdir)
1252
Mike Frysinger35247af2012-11-16 18:58:06 -05001253 # We have to split the root generation from the compression stages. This is
1254 # because we hardlink in all the files (to avoid overhead of reading/writing
1255 # the copies multiple times). But tar gets angry if a file's hardlink count
1256 # changes from when it starts reading a file to when it finishes.
1257 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1258 for target in targets:
1259 output_target_dir = os.path.join(tempdir, target)
1260 queue.put([target, output_target_dir, ldpaths, root])
1261
1262 # Build the tarball.
1263 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1264 for target in targets:
1265 tar_file = os.path.join(output_dir, target + '.tar.xz')
1266 queue.put([tar_file, os.path.join(tempdir, target)])
1267
1268
Mike Frysinger07534cf2017-09-12 17:40:21 -04001269def GetParser():
1270 """Return a command line parser."""
Mike Frysinger0c808452014-11-06 17:30:23 -05001271 parser = commandline.ArgumentParser(description=__doc__)
1272 parser.add_argument('-u', '--nousepkg',
1273 action='store_false', dest='usepkg', default=True,
1274 help='Use prebuilt packages if possible')
1275 parser.add_argument('-d', '--deleteold',
1276 action='store_true', dest='deleteold', default=False,
1277 help='Unmerge deprecated packages')
1278 parser.add_argument('-t', '--targets',
1279 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001280 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001281 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001282 "allowed. Defaults to 'sdk'.")
1283 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1284 help='Comma separated list of boards whose toolchains we '
1285 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001286 parser.add_argument('--hostonly',
1287 dest='hostonly', default=False, action='store_true',
1288 help='Only setup the host toolchain. '
1289 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001290 parser.add_argument('--show-board-cfg', '--show-cfg',
1291 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001292 help='Board to list toolchains tuples for')
Mike Frysinger91f52882017-09-13 00:16:58 -04001293 parser.add_argument('--show-packages', default=None,
1294 help='List all packages the specified target uses')
Mike Frysinger0c808452014-11-06 17:30:23 -05001295 parser.add_argument('--create-packages',
1296 action='store_true', default=False,
1297 help='Build redistributable packages')
1298 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1299 help='Output directory')
1300 parser.add_argument('--reconfig', default=False, action='store_true',
1301 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001302 parser.add_argument('--sysroot', type='path',
1303 help='The sysroot in which to install the toolchains')
Mike Frysinger07534cf2017-09-12 17:40:21 -04001304 return parser
Zdenek Behan508dcce2011-12-05 15:39:32 +01001305
Mike Frysinger07534cf2017-09-12 17:40:21 -04001306
1307def main(argv):
1308 parser = GetParser()
Mike Frysinger0c808452014-11-06 17:30:23 -05001309 options = parser.parse_args(argv)
1310 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001311
Mike Frysinger35247af2012-11-16 18:58:06 -05001312 # Figure out what we're supposed to do and reject conflicting options.
Mike Frysinger91f52882017-09-13 00:16:58 -04001313 conflicting_options = (
1314 options.cfg_name,
1315 options.show_packages,
1316 options.create_packages,
1317 )
1318 if sum(bool(x) for x in conflicting_options) > 1:
1319 parser.error('conflicting options: create-packages & show-packages & '
1320 'show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001321
Gilad Arnold8195b532015-04-07 10:56:30 +03001322 targets_wanted = set(options.targets.split(','))
1323 boards_wanted = (set(options.include_boards.split(','))
1324 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001325
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001326 if options.cfg_name:
1327 ShowConfig(options.cfg_name)
Mike Frysinger91f52882017-09-13 00:16:58 -04001328 elif options.show_packages is not None:
1329 cros_build_lib.AssertInsideChroot()
1330 target = options.show_packages
1331 Crossdev.Load(False)
1332 for package in GetTargetPackages(target):
1333 print(GetPortagePackage(target, package))
Mike Frysinger35247af2012-11-16 18:58:06 -05001334 elif options.create_packages:
1335 cros_build_lib.AssertInsideChroot()
1336 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001337 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001338 else:
1339 cros_build_lib.AssertInsideChroot()
1340 # This has to be always run as root.
1341 if os.geteuid() != 0:
1342 cros_build_lib.Die('this script must be run as root')
1343
1344 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001345 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001346 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001347 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001348 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001349 Crossdev.Save()
1350
1351 return 0