blob: 76b1bf84740fef3fe3b64e0b087f95c4f56c61d5 [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001# 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
Mike Frysinger750c5f52014-09-16 16:16:57 -04005"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01006
Mike Frysinger383367e2014-09-16 15:06:17 -04007from __future__ import print_function
8
Zdenek Behan508dcce2011-12-05 15:39:32 +01009import copy
Mike Frysinger35247af2012-11-16 18:58:06 -050010import glob
Mike Frysinger7ccee992012-06-01 21:27:59 -040011import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010012import os
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -070013import re
Zdenek Behan508dcce2011-12-05 15:39:32 +010014
Aviv Keshetb7519e12016-10-04 00:50:00 -070015from chromite.lib import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050016from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080017from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070018from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070019from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050020from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080021from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050022
23# Needs to be after chromite imports.
24import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010025
Mike Frysinger31596002012-12-03 23:54:24 -050026if cros_build_lib.IsInsideChroot():
27 # Only import portage after we've checked that we're inside the chroot.
28 # Outside may not have portage, in which case the above may not happen.
29 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070030 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050031 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010032
33
Matt Tennantf1e30972012-03-02 16:30:07 -080034EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010035PACKAGE_STABLE = '[stable]'
36PACKAGE_NONE = '[none]'
37SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
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
45# TODO: The versions are stored here very much like in setup_board.
46# The goal for future is to differentiate these using a config file.
47# This is done essentially by messing with GetDesiredPackageVersions()
48DEFAULT_VERSION = PACKAGE_STABLE
49DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010050}
51TARGET_VERSION_MAP = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050052 'host' : {
53 'gdb' : PACKAGE_NONE,
Rahul Chaudhry4b803052015-05-13 15:25:56 -070054 'ex_go' : PACKAGE_NONE,
Manoj Gupta1b5642e2017-03-08 16:44:12 -080055 'ex_compiler-rt': PACKAGE_NONE,
Manoj Gupta946abb42017-04-12 14:27:19 -070056 'ex_llvm-libunwind': PACKAGE_NONE,
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070057 'ex_libcxxabi': PACKAGE_NONE,
58 'ex_libcxx': PACKAGE_NONE,
Mike Frysingerd6e2df02014-11-26 02:55:04 -050059 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010060}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070061
62# Enable the Go compiler for these targets.
63TARGET_GO_ENABLED = (
64 'x86_64-cros-linux-gnu',
Rahul Chaudhry4b803052015-05-13 15:25:56 -070065 'armv7a-cros-linux-gnueabi',
66)
67CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
68
Manoj Gupta1b5642e2017-03-08 16:44:12 -080069# Enable llvm's compiler-rt for these targets.
70TARGET_COMPILER_RT_ENABLED = (
71 'armv7a-cros-linux-gnueabi',
Manoj Gupta946abb42017-04-12 14:27:19 -070072 'aarch64-cros-linux-gnu',
Manoj Gupta1b5642e2017-03-08 16:44:12 -080073)
74CROSSDEV_COMPILER_RT_ARGS = ['--ex-pkg', 'sys-libs/compiler-rt']
75
Manoj Gupta946abb42017-04-12 14:27:19 -070076TARGET_LLVM_PKGS_ENABLED = (
77 'armv7a-cros-linux-gnueabi',
78 'aarch64-cros-linux-gnu',
79 'x86_64-cros-linux-gnu',
80)
81
82LLVM_PKGS_TABLE = {
83 'ex_llvm-libunwind' : ['--ex-pkg', 'sys-libs/llvm-libunwind'],
Yunlian Jiangbb2a3d32017-04-26 14:44:09 -070084 'ex_libcxxabi' : ['--ex-pkg', 'sys-libs/libcxxabi'],
85 'ex_libcxx' : ['--ex-pkg', 'sys-libs/libcxx'],
Manoj Gupta946abb42017-04-12 14:27:19 -070086}
87
Zdenek Behan508dcce2011-12-05 15:39:32 +010088# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
89CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050090 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040091 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080092 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050093 'i686-pc-linux-gnu' : '-gold',
94 'x86_64-cros-linux-gnu' : '-gold',
95 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010096}
Zdenek Behan508dcce2011-12-05 15:39:32 +010097# Global per-run cache that will be filled ondemand in by GetPackageMap()
98# function as needed.
99target_version_map = {
100}
101
102
David James66a09c42012-11-05 13:31:38 -0800103class Crossdev(object):
104 """Class for interacting with crossdev and caching its output."""
105
106 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
107 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -0800108 # Packages that needs separate handling, in addition to what we have from
109 # crossdev.
110 MANUAL_PKGS = {
111 'llvm': 'sys-devel',
112 }
David James66a09c42012-11-05 13:31:38 -0800113
114 @classmethod
115 def Load(cls, reconfig):
116 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -0800117 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
118 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -0800119 if os.path.exists(cls._CACHE_FILE) and not reconfig:
120 with open(cls._CACHE_FILE) as f:
121 data = json.load(f)
David James90239b92012-11-05 15:31:34 -0800122 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800123 cls._CACHE = data
124
125 @classmethod
126 def Save(cls):
127 """Store crossdev cache on disk."""
128 # Save the cache from the successful run.
129 with open(cls._CACHE_FILE, 'w') as f:
130 json.dump(cls._CACHE, f)
131
132 @classmethod
133 def GetConfig(cls, target):
134 """Returns a map of crossdev provided variables about a tuple."""
135 CACHE_ATTR = '_target_tuple_map'
136
137 val = cls._CACHE.setdefault(CACHE_ATTR, {})
138 if not target in val:
139 # Find out the crossdev tuple.
140 target_tuple = target
141 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800142 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700143 # Build the crossdev command.
144 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
Manoj Gupta1b5642e2017-03-08 16:44:12 -0800145 if target in TARGET_COMPILER_RT_ENABLED:
146 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Manoj Guptab8181562017-05-21 10:18:59 -0700147 if target in TARGET_GO_ENABLED:
148 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700149 if target in TARGET_LLVM_PKGS_ENABLED:
150 for pkg in LLVM_PKGS_TABLE:
151 cmd.extend(LLVM_PKGS_TABLE[pkg])
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700152 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800153 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700154 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
155 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800156 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800157 conf = dict((k, cros_build_lib.ShellUnquote(v))
158 for k, v in (x.split('=', 1) for x in out))
159 conf['crosspkgs'] = conf['crosspkgs'].split()
160
161 for pkg, cat in cls.MANUAL_PKGS.iteritems():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400162 conf[pkg + '_pn'] = pkg
163 conf[pkg + '_category'] = cat
164 if pkg not in conf['crosspkgs']:
165 conf['crosspkgs'].append(pkg)
Han Shene23782f2016-02-18 12:20:00 -0800166
167 val[target] = conf
168
David James66a09c42012-11-05 13:31:38 -0800169 return val[target]
170
171 @classmethod
172 def UpdateTargets(cls, targets, usepkg, config_only=False):
173 """Calls crossdev to initialize a cross target.
174
175 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700176 targets: The list of targets to initialize using crossdev.
177 usepkg: Copies the commandline opts.
178 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800179 """
180 configured_targets = cls._CACHE.setdefault('configured_targets', [])
181
182 cmdbase = ['crossdev', '--show-fail-log']
183 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
184 # Pick stable by default, and override as necessary.
185 cmdbase.extend(['-P', '--oneshot'])
186 if usepkg:
187 cmdbase.extend(['-P', '--getbinpkg',
188 '-P', '--usepkgonly',
189 '--without-headers'])
190
Christopher Wileyb22c0712015-06-02 10:37:03 -0700191 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800192 cmdbase.extend(['--overlays', overlays])
193 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
194
195 for target in targets:
196 if config_only and target in configured_targets:
197 continue
198
199 cmd = cmdbase + ['-t', target]
200
201 for pkg in GetTargetPackages(target):
202 if pkg == 'gdb':
203 # Gdb does not have selectable versions.
204 cmd.append('--ex-gdb')
Manoj Guptab8181562017-05-21 10:18:59 -0700205 elif pkg == 'ex_compiler-rt':
206 cmd.extend(CROSSDEV_COMPILER_RT_ARGS)
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700207 elif pkg == 'ex_go':
208 # Go does not have selectable versions.
209 cmd.extend(CROSSDEV_GO_ARGS)
Manoj Gupta946abb42017-04-12 14:27:19 -0700210 elif pkg in LLVM_PKGS_TABLE:
211 cmd.extend(LLVM_PKGS_TABLE[pkg])
Han Shene23782f2016-02-18 12:20:00 -0800212 elif pkg in cls.MANUAL_PKGS:
213 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700214 else:
215 # The first of the desired versions is the "primary" one.
216 version = GetDesiredPackageVersions(target, pkg)[0]
217 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800218
219 cmd.extend(targets[target]['crossdev'].split())
220 if config_only:
221 # In this case we want to just quietly reinit
222 cmd.append('--init-target')
223 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
224 else:
225 cros_build_lib.RunCommand(cmd)
226
227 configured_targets.append(target)
228
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100229
Zdenek Behan508dcce2011-12-05 15:39:32 +0100230def GetPackageMap(target):
231 """Compiles a package map for the given target from the constants.
232
233 Uses a cache in target_version_map, that is dynamically filled in as needed,
234 since here everything is static data and the structuring is for ease of
235 configurability only.
236
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500237 Args:
238 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100239
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500240 Returns:
241 A map between packages and desired versions in internal format
242 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243 """
244 if target in target_version_map:
245 return target_version_map[target]
246
247 # Start from copy of the global defaults.
248 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
249
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100250 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100251 # prefer any specific overrides
252 if pkg in TARGET_VERSION_MAP.get(target, {}):
253 result[pkg] = TARGET_VERSION_MAP[target][pkg]
254 else:
255 # finally, if not already set, set a sane default
256 result.setdefault(pkg, DEFAULT_VERSION)
257 target_version_map[target] = result
258 return result
259
260
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100261def GetTargetPackages(target):
262 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800263 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100264 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800265 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100266
267
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100268# Portage helper functions:
269def GetPortagePackage(target, package):
270 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800271 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100272 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800273 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100274 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100275 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100276 category = conf['category']
277 # Portage package:
278 pn = conf[package + '_pn']
279 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500280 assert category
281 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100282 return '%s/%s' % (category, pn)
283
284
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100285def IsPackageDisabled(target, package):
286 """Returns if the given package is not used for the target."""
287 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
288
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100289
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700290def PortageTrees(root):
291 """Return the portage trees for a given root."""
292 if root == '/':
293 return portage.db['/']
294 # The portage logic requires the path always end in a slash.
295 root = root.rstrip('/') + '/'
296 return portage.create_trees(target_root=root, config_root=root)[root]
297
298
299def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100300 """Extracts the list of current versions of a target, package pair.
301
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500302 Args:
303 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700304 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100305
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500306 Returns:
307 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100308 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100309 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500310 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700311 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100312 version = portage.versions.cpv_getversion(pkg)
313 versions.append(version)
314 return versions
315
316
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700317def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100318 """Extracts the current stable version for a given package.
319
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500320 Args:
321 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
322 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700323 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500325 Returns:
326 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100327 """
David James90239b92012-11-05 15:31:34 -0800328 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500329 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700330 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800331 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100332
333
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700334def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100335 """Resolves keywords in a given version list for a particular package.
336
337 Resolving means replacing PACKAGE_STABLE with the actual number.
338
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500339 Args:
340 target: The target to operate on (e.g. i686-pc-linux-gnu)
341 package: The target/package to operate on (e.g. gcc)
342 versions: List of versions to resolve
343 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700344 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100345
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500346 Returns:
347 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100348 """
349 resolved = []
David James90239b92012-11-05 15:31:34 -0800350 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700351 if not installed:
352 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100353 for version in versions:
354 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700355 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100356 elif version != PACKAGE_NONE:
357 resolved.append(version)
358 return resolved
359
360
361def GetDesiredPackageVersions(target, package):
362 """Produces the list of desired versions for each target, package pair.
363
364 The first version in the list is implicitly treated as primary, ie.
365 the version that will be initialized by crossdev and selected.
366
367 If the version is PACKAGE_STABLE, it really means the current version which
368 is emerged by using the package atom with no particular version key.
369 Since crossdev unmasks all packages by default, this will actually
370 mean 'unstable' in most cases.
371
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500372 Args:
373 target: The target to operate on (e.g. i686-pc-linux-gnu)
374 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500376 Returns:
377 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100378 """
379 packagemap = GetPackageMap(target)
380
381 versions = []
382 if package in packagemap:
383 versions.append(packagemap[package])
384
385 return versions
386
387
388def TargetIsInitialized(target):
389 """Verifies if the given list of targets has been correctly initialized.
390
391 This determines whether we have to call crossdev while emerging
392 toolchain packages or can do it using emerge. Emerge is naturally
393 preferred, because all packages can be updated in a single pass.
394
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500395 Args:
396 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500398 Returns:
399 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100400 """
401 # Check if packages for the given target all have a proper version.
402 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100403 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800404 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100405 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800406 if not IsPackageDisabled(target, package) and not (
407 GetStablePackageVersion(atom, True) and
408 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100409 return False
410 return True
411 except cros_build_lib.RunCommandError:
412 # Fails - The target has likely never been initialized before.
413 return False
414
415
416def RemovePackageMask(target):
417 """Removes a package.mask file for the given platform.
418
419 The pre-existing package.mask files can mess with the keywords.
420
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500421 Args:
422 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100423 """
424 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700425 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100426
427
Zdenek Behan508dcce2011-12-05 15:39:32 +0100428# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700429def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500430 """Rebuild libtool as needed
431
432 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
433 gcc, libtool will break. We can't use binary packages either as those will
434 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700435
436 Args:
437 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500438 """
439 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700440 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500441 for line in f:
442 # Look for a line like:
443 # sys_lib_search_path_spec="..."
444 # It'll be a list of paths and gcc will be one of them.
445 if line.startswith('sys_lib_search_path_spec='):
446 line = line.rstrip()
447 for path in line.split('=', 1)[1].strip('"').split():
Mike Frysinger3bba5032016-09-20 14:15:04 -0400448 root_path = os.path.join(root, path.lstrip(os.path.sep))
449 logging.debug('Libtool: checking %s', root_path)
450 if not os.path.exists(root_path):
451 logging.info('Rebuilding libtool after gcc upgrade')
452 logging.info(' %s', line)
453 logging.info(' missing path: %s', path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500454 needs_update = True
455 break
456
457 if needs_update:
458 break
459
460 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700461 cmd = [EMERGE_CMD, '--oneshot']
462 if root != '/':
463 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
464 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500465 cros_build_lib.RunCommand(cmd)
Mike Frysinger3bba5032016-09-20 14:15:04 -0400466 else:
467 logging.debug('Libtool is up-to-date; no need to rebuild')
Mike Frysingerc880a962013-11-08 13:59:06 -0500468
469
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700470def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471 """Determines which packages need update/unmerge and defers to portage.
472
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500473 Args:
474 targets: The list of targets to update
475 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700476 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477 """
David James90239b92012-11-05 15:31:34 -0800478 # Remove keyword files created by old versions of cros_setup_toolchains.
479 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480
481 # For each target, we do two things. Figure out the list of updates,
482 # and figure out the appropriate keywords/masks. Crossdev will initialize
483 # these, but they need to be regenerated on every update.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400484 logging.info('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800485 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100486 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400487 logging.debug('Updating target %s', target)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100488 # Record the highest needed version for each target, for masking purposes.
489 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100490 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100491 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100492 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400493 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100494 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400495 logging.debug(' Updating package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100496 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700497 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100498 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200499 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100500 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502 packages = []
503 for pkg in mergemap:
504 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200505 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800506 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100507
508 if not packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400509 logging.info('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800510 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100511
Mike Frysinger3bba5032016-09-20 14:15:04 -0400512 logging.info('Updating packages:')
513 logging.info('%s', packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100514
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100515 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100516 if usepkg:
517 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700518 if root != '/':
519 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100520
521 cmd.extend(packages)
522 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800523 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100524
525
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700526def CleanTargets(targets, root='/'):
527 """Unmerges old packages that are assumed unnecessary.
528
529 Args:
530 targets: The list of targets to clean up.
531 root: The install root in which we want packages cleaned up.
532 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 unmergemap = {}
534 for target in targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400535 logging.debug('Cleaning target %s', target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100536 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100537 if IsPackageDisabled(target, package):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400538 logging.debug(' Skipping disabled package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100539 continue
Mike Frysinger3bba5032016-09-20 14:15:04 -0400540 logging.debug(' Cleaning package %s', package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100541 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700542 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100543 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700544 # NOTE: This refers to installed packages (vartree) rather than the
545 # Portage version (porttree and/or bintree) when determining the current
546 # version. While this isn't the most accurate thing to do, it is probably
547 # a good simple compromise, which should have the desired result of
548 # uninstalling everything but the latest installed version. In
549 # particular, using the bintree (--usebinpkg) requires a non-trivial
550 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200551 desired_num = VersionListToNumeric(target, package, desired, True)
552 if not set(desired_num).issubset(current):
Mike Frysinger3bba5032016-09-20 14:15:04 -0400553 logging.warning('Error detecting stable version for %s, '
554 'skipping clean!', pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200555 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556 unmergemap[pkg] = set(current).difference(desired_num)
557
558 # Cleaning doesn't care about consistency and rebuilding package.* files.
559 packages = []
560 for pkg, vers in unmergemap.iteritems():
561 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
562
563 if packages:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400564 logging.info('Cleaning packages:')
565 logging.info('%s', packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100566 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700567 if root != '/':
568 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100569 cmd.extend(packages)
570 cros_build_lib.RunCommand(cmd)
571 else:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400572 logging.info('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100573
574
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700575def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100576 """Runs gcc-config and binutils-config to select the desired.
577
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500578 Args:
579 targets: The targets to select
580 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700581 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100582 """
583 for package in ['gcc', 'binutils']:
584 for target in targets:
585 # Pick the first version in the numbered list as the selected one.
586 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700587 desired_num = VersionListToNumeric(target, package, desired, True,
588 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100589 desired = desired_num[0]
590 # *-config does not play revisions, strip them, keep just PV.
591 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
592
593 if target == 'host':
594 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800595 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100596
597 # And finally, attach target to it.
598 desired = '%s-%s' % (target, desired)
599
600 # Target specific hacks
601 if package in suffixes:
602 if target in suffixes[package]:
603 desired += suffixes[package][target]
604
David James7ec5efc2012-11-06 09:39:49 -0800605 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700606 if root != '/':
607 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800608 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500609 result = cros_build_lib.RunCommand(
610 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
611 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700612
613 # Do not reconfig when the current is live or nothing needs to be done.
614 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100615 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500616 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700617 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100618
619
Mike Frysinger35247af2012-11-16 18:58:06 -0500620def ExpandTargets(targets_wanted):
621 """Expand any possible toolchain aliases into full targets
622
623 This will expand 'all' and 'sdk' into the respective toolchain tuples.
624
625 Args:
626 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500627
Mike Frysinger35247af2012-11-16 18:58:06 -0500628 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300629 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500630 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500631 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700632 if targets_wanted == set(['boards']):
633 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300634 return {}
635
636 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500637 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300638 return all_targets
639 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500640 # Filter out all the non-sdk toolchains as we don't want to mess
641 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300642 return toolchain.FilterToolchains(all_targets, 'sdk', True)
643
644 # Verify user input.
645 nonexistent = targets_wanted.difference(all_targets)
646 if nonexistent:
647 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
648 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500649
650
David Jamesf8c672f2012-11-06 13:38:11 -0800651def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700652 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100653 """Performs all steps to create a synchronized toolchain enviroment.
654
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500655 Args:
656 usepkg: Use prebuilt packages
657 deleteold: Unmerge deprecated packages
658 hostonly: Only setup the host toolchain
659 reconfig: Reload crossdev config and reselect toolchains
660 targets_wanted: All the targets to update
661 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700662 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100663 """
David Jamesf8c672f2012-11-06 13:38:11 -0800664 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100665 if not hostonly:
666 # For hostonly, we can skip most of the below logic, much of which won't
667 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500668 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400669
Don Garrettc0c74002015-10-09 12:58:19 -0700670 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300671 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400672 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800673 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100674
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100675 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400676 for target in targets:
677 if TargetIsInitialized(target):
678 reconfig_targets[target] = targets[target]
679 else:
680 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100681 if crossdev_targets:
Mike Frysinger3bba5032016-09-20 14:15:04 -0400682 logging.info('The following targets need to be re-initialized:')
683 logging.info('%s', crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800684 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200685 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800686 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100687
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100688 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400689 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100690
691 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700692 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
693 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800694
695 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700696 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100697
Mike Frysingerc880a962013-11-08 13:59:06 -0500698 # Now that we've cleared out old versions, see if we need to rebuild
699 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700700 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500701
Zdenek Behan508dcce2011-12-05 15:39:32 +0100702
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700703def ShowConfig(name):
704 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500705
706 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700707 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500708 """
Don Garrettc0c74002015-10-09 12:58:19 -0700709 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500710 # Make sure we display the default toolchain first.
Mike Frysinger3bba5032016-09-20 14:15:04 -0400711 # Note: Do not use logging here as this is meant to be used by other tools.
Mike Frysinger383367e2014-09-16 15:06:17 -0400712 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800713 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400714 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500715
716
Mike Frysinger35247af2012-11-16 18:58:06 -0500717def GeneratePathWrapper(root, wrappath, path):
718 """Generate a shell script to execute another shell script
719
720 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
721 argv[0] won't be pointing to the correct path, generate a shell script that
722 just executes another program with its full path.
723
724 Args:
725 root: The root tree to generate scripts inside of
726 wrappath: The full path (inside |root|) to create the wrapper
727 path: The target program which this wrapper will execute
728 """
729 replacements = {
730 'path': path,
731 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
732 }
733 wrapper = """#!/bin/sh
734base=$(realpath "$0")
735basedir=${base%%/*}
736exec "${basedir}/%(relroot)s%(path)s" "$@"
737""" % replacements
738 root_wrapper = root + wrappath
739 if os.path.islink(root_wrapper):
740 os.unlink(root_wrapper)
741 else:
742 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
743 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400744 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500745
746
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700747def FixClangXXWrapper(root, path):
748 """Fix wrapper shell scripts and symlinks for invoking clang++
749
750 In a typical installation, clang++ symlinks to clang, which symlinks to the
751 elf executable. The executable distinguishes between clang and clang++ based
752 on argv[0].
753
754 When invoked through the LdsoWrapper, argv[0] always contains the path to the
755 executable elf file, making clang/clang++ invocations indistinguishable.
756
757 This function detects if the elf executable being wrapped is clang-X.Y, and
758 fixes wrappers/symlinks as necessary so that clang++ will work correctly.
759
760 The calling sequence now becomes:
761 -) clang++ invocation turns into clang++-3.9 (which is a copy of clang-3.9,
762 the Ldsowrapper).
763 -) clang++-3.9 uses the Ldso to invoke clang++-3.9.elf, which is a symlink
764 to the original clang-3.9 elf.
765 -) The difference this time is that inside the elf file execution, $0 is
766 set as .../usr/bin/clang++-3.9.elf, which contains 'clang++' in the name.
767
768 Args:
769 root: The root tree to generate scripts / symlinks inside of
770 path: The target elf for which LdsoWrapper was created
771 """
772 if re.match(r'/usr/bin/clang-\d+\.\d+$', path):
773 logging.info('fixing clang++ invocation for %s', path)
774 clangdir = os.path.dirname(root + path)
775 clang = os.path.basename(path)
776 clangxx = clang.replace('clang', 'clang++')
777
778 # Create a symlink clang++-X.Y.elf to point to clang-X.Y.elf
779 os.symlink(clang + '.elf', os.path.join(clangdir, clangxx + '.elf'))
780
781 # Create a hardlink clang++-X.Y pointing to clang-X.Y
782 os.link(os.path.join(clangdir, clang), os.path.join(clangdir, clangxx))
783
784 # Adjust the clang++ symlink to point to clang++-X.Y
785 os.unlink(os.path.join(clangdir, 'clang++'))
786 os.symlink(clangxx, os.path.join(clangdir, 'clang++'))
787
788
Mike Frysinger35247af2012-11-16 18:58:06 -0500789def FileIsCrosSdkElf(elf):
790 """Determine if |elf| is an ELF that we execute in the cros_sdk
791
792 We don't need this to be perfect, just quick. It makes sure the ELF
793 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
794
795 Args:
796 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500797
Mike Frysinger35247af2012-11-16 18:58:06 -0500798 Returns:
799 True if we think |elf| is a native ELF
800 """
801 with open(elf) as f:
802 data = f.read(20)
803 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
804 return (data[0:4] == '\x7fELF' and
805 data[4] == '\x02' and
806 data[5] == '\x01' and
807 data[18] == '\x3e')
808
809
810def IsPathPackagable(ptype, path):
811 """Should the specified file be included in a toolchain package?
812
813 We only need to handle files as we'll create dirs as we need them.
814
815 Further, trim files that won't be useful:
816 - non-english translations (.mo) since it'd require env vars
817 - debug files since these are for the host compiler itself
818 - info/man pages as they're big, and docs are online, and the
819 native docs should work fine for the most part (`man gcc`)
820
821 Args:
822 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
823 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500824
Mike Frysinger35247af2012-11-16 18:58:06 -0500825 Returns:
826 True if we want to include this path in the package
827 """
828 return not (ptype in ('dir',) or
829 path.startswith('/usr/lib/debug/') or
830 os.path.splitext(path)[1] == '.mo' or
831 ('/man/' in path or '/info/' in path))
832
833
834def ReadlinkRoot(path, root):
835 """Like os.readlink(), but relative to a |root|
836
837 Args:
838 path: The symlink to read
839 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500840
Mike Frysinger35247af2012-11-16 18:58:06 -0500841 Returns:
842 A fully resolved symlink path
843 """
844 while os.path.islink(root + path):
845 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
846 return path
847
848
849def _GetFilesForTarget(target, root='/'):
850 """Locate all the files to package for |target|
851
852 This does not cover ELF dependencies.
853
854 Args:
855 target: The toolchain target name
856 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500857
Mike Frysinger35247af2012-11-16 18:58:06 -0500858 Returns:
859 A tuple of a set of all packable paths, and a set of all paths which
860 are also native ELFs
861 """
862 paths = set()
863 elfs = set()
864
865 # Find all the files owned by the packages for this target.
866 for pkg in GetTargetPackages(target):
867 # Ignore packages that are part of the target sysroot.
868 if pkg in ('kernel', 'libc'):
869 continue
870
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700871 # Skip Go compiler from redistributable packages.
872 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
873 # into it. Due to this, the toolchain cannot be unpacked anywhere
874 # else and be readily useful. To enable packaging Go, we need to:
875 # -) Tweak the wrappers/environment to override GOROOT
876 # automatically based on the unpack location.
877 # -) Make sure the ELF dependency checking and wrapping logic
878 # below skips the Go toolchain executables and libraries.
879 # -) Make sure the packaging process maintains the relative
880 # timestamps of precompiled standard library packages.
881 # (see dev-lang/go ebuild for details).
882 if pkg == 'ex_go':
883 continue
884
Mike Frysinger35247af2012-11-16 18:58:06 -0500885 atom = GetPortagePackage(target, pkg)
886 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700887 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700888 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500889
890 # pylint: disable=E1101
891 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
892 settings=portage.settings)
893 contents = dblink.getcontents()
894 for obj in contents:
895 ptype = contents[obj][0]
896 if not IsPathPackagable(ptype, obj):
897 continue
898
899 if ptype == 'obj':
900 # For native ELFs, we need to pull in their dependencies too.
901 if FileIsCrosSdkElf(obj):
902 elfs.add(obj)
903 paths.add(obj)
904
905 return paths, elfs
906
907
908def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500909 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500910 """Link in all packable files and their runtime dependencies
911
912 This also wraps up executable ELFs with helper scripts.
913
914 Args:
915 output_dir: The output directory to store files
916 paths: All the files to include
917 elfs: All the files which are ELFs (a subset of |paths|)
918 ldpaths: A dict of static ldpath information
919 path_rewrite_func: User callback to rewrite paths in output_dir
920 root: The root path to pull all packages/files from
921 """
922 # Link in all the files.
923 sym_paths = []
924 for path in paths:
925 new_path = path_rewrite_func(path)
926 dst = output_dir + new_path
927 osutils.SafeMakedirs(os.path.dirname(dst))
928
929 # Is this a symlink which we have to rewrite or wrap?
930 # Delay wrap check until after we have created all paths.
931 src = root + path
932 if os.path.islink(src):
933 tgt = os.readlink(src)
934 if os.path.sep in tgt:
935 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
936
937 # Rewrite absolute links to relative and then generate the symlink
938 # ourselves. All other symlinks can be hardlinked below.
939 if tgt[0] == '/':
940 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
941 os.symlink(tgt, dst)
942 continue
943
944 os.link(src, dst)
945
946 # Now see if any of the symlinks need to be wrapped.
947 for sym, tgt in sym_paths:
948 if tgt in elfs:
949 GeneratePathWrapper(output_dir, sym, tgt)
950
951 # Locate all the dependencies for all the ELFs. Stick them all in the
952 # top level "lib" dir to make the wrapper simpler. This exact path does
953 # not matter since we execute ldso directly, and we tell the ldso the
954 # exact path to search for its libraries.
955 libdir = os.path.join(output_dir, 'lib')
956 osutils.SafeMakedirs(libdir)
957 donelibs = set()
958 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400959 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500960 interp = e['interp']
961 if interp:
962 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400963 interp = os.path.join('/lib', os.path.basename(interp))
964 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
965 libpaths=e['rpath'] + e['runpath'])
Rahul Chaudhrya8127bb2016-07-22 15:53:17 -0700966 FixClangXXWrapper(output_dir, path_rewrite_func(elf))
Mike Frysinger35247af2012-11-16 18:58:06 -0500967
968 for lib, lib_data in e['libs'].iteritems():
969 if lib in donelibs:
970 continue
971
972 src = path = lib_data['path']
973 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700974 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500975 continue
976 donelibs.add(lib)
977
978 # Needed libs are the SONAME, but that is usually a symlink, not a
979 # real file. So link in the target rather than the symlink itself.
980 # We have to walk all the possible symlinks (SONAME could point to a
981 # symlink which points to a symlink), and we have to handle absolute
982 # ourselves (since we have a "root" argument).
983 dst = os.path.join(libdir, os.path.basename(path))
984 src = ReadlinkRoot(src, root)
985
986 os.link(root + src, dst)
987
988
989def _EnvdGetVar(envd, var):
990 """Given a Gentoo env.d file, extract a var from it
991
992 Args:
993 envd: The env.d file to load (may be a glob path)
994 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500995
Mike Frysinger35247af2012-11-16 18:58:06 -0500996 Returns:
997 The value of |var|
998 """
999 envds = glob.glob(envd)
1000 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
1001 envd = envds[0]
1002 return cros_build_lib.LoadKeyValueFile(envd)[var]
1003
1004
1005def _ProcessBinutilsConfig(target, output_dir):
1006 """Do what binutils-config would have done"""
1007 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001008
1009 # Locate the bin dir holding the gold linker.
1010 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
1011 target, 'binutils-bin')
1012 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -05001013 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001014 if not srcpath:
1015 # Maybe this target doesn't support gold.
1016 globpath = os.path.join(binutils_bin_path, '*')
1017 srcpath = glob.glob(globpath)
1018 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
1019 % globpath)
1020 srcpath = srcpath[0]
1021 ld_path = os.path.join(srcpath, 'ld')
1022 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1023 ld_path = os.path.join(srcpath, 'ld.bfd')
1024 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1025 ld_path = os.path.join(srcpath, 'ld.gold')
1026 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
1027 % ld_path)
1028
1029 # Nope, no gold support to be found.
1030 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -07001031 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001032 else:
1033 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
Mike Frysinger78b7a812014-11-26 19:45:23 -05001034 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001035
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001036 # Package the binutils-bin directory without the '-gold' suffix
1037 # if gold is not enabled as the default linker for this target.
1038 gold_supported = CONFIG_TARGET_SUFFIXES['binutils'].get(target) == '-gold'
1039 if not gold_supported:
1040 srcpath = srcpath[:-len('-gold')]
1041 ld_path = os.path.join(srcpath, 'ld')
1042 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
1043
Mike Frysinger78b7a812014-11-26 19:45:23 -05001044 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -05001045 gccpath = os.path.join('/usr', 'libexec', 'gcc')
1046 for prog in os.listdir(output_dir + srcpath):
1047 # Skip binaries already wrapped.
1048 if not prog.endswith('.real'):
1049 GeneratePathWrapper(output_dir, binpath + prog,
1050 os.path.join(srcpath, prog))
1051 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
1052 os.path.join(srcpath, prog))
1053
David James27ac4ae2012-12-03 23:16:15 -08001054 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -05001055 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
1056 if gold_supported:
1057 envd += '-gold'
Rahul Chaudhry4891b4d2017-03-08 10:31:27 -08001058 else:
1059 # If gold is not enabled as the default linker and 2 env.d
1060 # files exist, pick the one without the '-gold' suffix.
1061 envds = sorted(glob.glob(envd))
1062 if len(envds) == 2 and envds[1] == envds[0] + '-gold':
1063 envd = envds[0]
Mike Frysinger35247af2012-11-16 18:58:06 -05001064 srcpath = _EnvdGetVar(envd, 'LIBPATH')
1065 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
1066 output_dir + libpath)
1067
1068
1069def _ProcessGccConfig(target, output_dir):
1070 """Do what gcc-config would have done"""
1071 binpath = '/bin'
1072 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
1073 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
1074 for prog in os.listdir(output_dir + srcpath):
1075 # Skip binaries already wrapped.
1076 if (not prog.endswith('.real') and
1077 not prog.endswith('.elf') and
1078 prog.startswith(target)):
1079 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
1080 os.path.join(srcpath, prog))
1081 return srcpath
1082
1083
Frank Henigman179ec7c2015-02-06 03:01:09 -05001084def _ProcessSysrootWrappers(_target, output_dir, srcpath):
1085 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -05001086 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -05001087 for sysroot_wrapper in glob.glob(os.path.join(
1088 output_dir + srcpath, 'sysroot_wrapper*')):
1089 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
1090 for num in xrange(len(contents)):
1091 if '@CCACHE_DEFAULT@' in contents[num]:
Caroline Ticece9e9232017-06-02 09:38:42 -07001092 assert 'True' in contents[num]
1093 contents[num] = contents[num].replace('True', 'False')
Frank Henigman179ec7c2015-02-06 03:01:09 -05001094 break
1095 # Can't update the wrapper in place since it's a hardlink to a file in /.
1096 os.unlink(sysroot_wrapper)
1097 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
1098 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -05001099
1100
1101def _ProcessDistroCleanups(target, output_dir):
1102 """Clean up the tree and remove all distro-specific requirements
1103
1104 Args:
1105 target: The toolchain target name
1106 output_dir: The output directory to clean up
1107 """
1108 _ProcessBinutilsConfig(target, output_dir)
1109 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001110 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001111
1112 osutils.RmDir(os.path.join(output_dir, 'etc'))
1113
1114
1115def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1116 """Setup a tree from the packages for the specified target
1117
1118 This populates a path with all the files from toolchain packages so that
1119 a tarball can easily be generated from the result.
1120
1121 Args:
1122 target: The target to create a packagable root from
1123 output_dir: The output directory to place all the files
1124 ldpaths: A dict of static ldpath information
1125 root: The root path to pull all packages/files from
1126 """
1127 # Find all the files owned by the packages for this target.
1128 paths, elfs = _GetFilesForTarget(target, root=root)
1129
1130 # Link in all the package's files, any ELF dependencies, and wrap any
1131 # executable ELFs with helper scripts.
1132 def MoveUsrBinToBin(path):
Han Shen699ea192016-03-02 10:42:47 -08001133 """Move /usr/bin to /bin so people can just use that toplevel dir
1134
1135 Note we do not apply this to clang - there is correlation between clang's
1136 search path for libraries / inclusion and its installation path.
1137 """
1138 if path.startswith('/usr/bin/') and path.find('clang') == -1:
1139 return path[4:]
1140 return path
Mike Frysinger35247af2012-11-16 18:58:06 -05001141 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1142 path_rewrite_func=MoveUsrBinToBin, root=root)
1143
1144 # The packages, when part of the normal distro, have helper scripts
1145 # that setup paths and such. Since we are making this standalone, we
1146 # need to preprocess all that ourselves.
1147 _ProcessDistroCleanups(target, output_dir)
1148
1149
1150def CreatePackages(targets_wanted, output_dir, root='/'):
1151 """Create redistributable cross-compiler packages for the specified targets
1152
1153 This creates toolchain packages that should be usable in conjunction with
1154 a downloaded sysroot (created elsewhere).
1155
1156 Tarballs (one per target) will be created in $PWD.
1157
1158 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001159 targets_wanted: The targets to package up.
1160 output_dir: The directory to put the packages in.
1161 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001162 """
Ralph Nathan03047282015-03-23 11:09:32 -07001163 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001164 osutils.SafeMakedirs(output_dir)
1165 ldpaths = lddtree.LoadLdpaths(root)
1166 targets = ExpandTargets(targets_wanted)
1167
David James4bc13702013-03-26 08:08:04 -07001168 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001169 # We have to split the root generation from the compression stages. This is
1170 # because we hardlink in all the files (to avoid overhead of reading/writing
1171 # the copies multiple times). But tar gets angry if a file's hardlink count
1172 # changes from when it starts reading a file to when it finishes.
1173 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1174 for target in targets:
1175 output_target_dir = os.path.join(tempdir, target)
1176 queue.put([target, output_target_dir, ldpaths, root])
1177
1178 # Build the tarball.
1179 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1180 for target in targets:
1181 tar_file = os.path.join(output_dir, target + '.tar.xz')
1182 queue.put([tar_file, os.path.join(tempdir, target)])
1183
1184
Brian Harring30675052012-02-29 12:18:22 -08001185def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001186 parser = commandline.ArgumentParser(description=__doc__)
1187 parser.add_argument('-u', '--nousepkg',
1188 action='store_false', dest='usepkg', default=True,
1189 help='Use prebuilt packages if possible')
1190 parser.add_argument('-d', '--deleteold',
1191 action='store_true', dest='deleteold', default=False,
1192 help='Unmerge deprecated packages')
1193 parser.add_argument('-t', '--targets',
1194 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001195 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001196 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001197 "allowed. Defaults to 'sdk'.")
1198 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1199 help='Comma separated list of boards whose toolchains we '
1200 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001201 parser.add_argument('--hostonly',
1202 dest='hostonly', default=False, action='store_true',
1203 help='Only setup the host toolchain. '
1204 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001205 parser.add_argument('--show-board-cfg', '--show-cfg',
1206 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001207 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001208 parser.add_argument('--create-packages',
1209 action='store_true', default=False,
1210 help='Build redistributable packages')
1211 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1212 help='Output directory')
1213 parser.add_argument('--reconfig', default=False, action='store_true',
1214 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001215 parser.add_argument('--sysroot', type='path',
1216 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001217
Mike Frysinger0c808452014-11-06 17:30:23 -05001218 options = parser.parse_args(argv)
1219 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001220
Mike Frysinger35247af2012-11-16 18:58:06 -05001221 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001222 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001223 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001224
Gilad Arnold8195b532015-04-07 10:56:30 +03001225 targets_wanted = set(options.targets.split(','))
1226 boards_wanted = (set(options.include_boards.split(','))
1227 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001228
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001229 if options.cfg_name:
1230 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001231 elif options.create_packages:
1232 cros_build_lib.AssertInsideChroot()
1233 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001234 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001235 else:
1236 cros_build_lib.AssertInsideChroot()
1237 # This has to be always run as root.
1238 if os.geteuid() != 0:
1239 cros_build_lib.Die('this script must be run as root')
1240
1241 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001242 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001243 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001244 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001245 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001246 Crossdev.Save()
1247
1248 return 0