blob: 15c58fc627f488ad88542f9f65d5e05aa407ff32 [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
Zdenek Behan508dcce2011-12-05 15:39:32 +010013
Don Garrett88b8d782014-05-13 17:30:55 -070014from chromite.cbuildbot import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050015from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080016from chromite.lib import cros_build_lib
Ralph Nathan03047282015-03-23 11:09:32 -070017from chromite.lib import cros_logging as logging
Brian Harringaf019fb2012-05-10 15:06:13 -070018from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050019from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080020from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050021
22# Needs to be after chromite imports.
23import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010024
Mike Frysinger31596002012-12-03 23:54:24 -050025if cros_build_lib.IsInsideChroot():
26 # Only import portage after we've checked that we're inside the chroot.
27 # Outside may not have portage, in which case the above may not happen.
28 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070029 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050030 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010031
32
Matt Tennantf1e30972012-03-02 16:30:07 -080033EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010034PACKAGE_STABLE = '[stable]'
35PACKAGE_NONE = '[none]'
36SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010037
38CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
Christopher Wileyb22c0712015-06-02 10:37:03 -070039ECLASS_OVERLAY = '/usr/local/portage/eclass-overlay'
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010040STABLE_OVERLAY = '/usr/local/portage/stable'
41CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010042
43
44# TODO: The versions are stored here very much like in setup_board.
45# The goal for future is to differentiate these using a config file.
46# This is done essentially by messing with GetDesiredPackageVersions()
47DEFAULT_VERSION = PACKAGE_STABLE
48DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010049}
50TARGET_VERSION_MAP = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050051 'host' : {
52 'gdb' : PACKAGE_NONE,
Rahul Chaudhry4b803052015-05-13 15:25:56 -070053 'ex_go' : PACKAGE_NONE,
Mike Frysingerd6e2df02014-11-26 02:55:04 -050054 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010055}
Rahul Chaudhry4b803052015-05-13 15:25:56 -070056
57# Enable the Go compiler for these targets.
58TARGET_GO_ENABLED = (
59 'x86_64-cros-linux-gnu',
60 'i686-pc-linux-gnu',
61 'armv7a-cros-linux-gnueabi',
62)
63CROSSDEV_GO_ARGS = ['--ex-pkg', 'dev-lang/go']
64
Zdenek Behan508dcce2011-12-05 15:39:32 +010065# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
66CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050067 'binutils' : {
Mike Frysinger8a83c622015-05-28 00:35:05 -040068 'armv6j-cros-linux-gnueabi': '-gold',
Han Shen43b84422015-02-19 11:38:13 -080069 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050070 'i686-pc-linux-gnu' : '-gold',
71 'x86_64-cros-linux-gnu' : '-gold',
72 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010073}
Zdenek Behan508dcce2011-12-05 15:39:32 +010074# Global per-run cache that will be filled ondemand in by GetPackageMap()
75# function as needed.
76target_version_map = {
77}
78
79
David James66a09c42012-11-05 13:31:38 -080080class Crossdev(object):
81 """Class for interacting with crossdev and caching its output."""
82
83 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
84 _CACHE = {}
Han Shene23782f2016-02-18 12:20:00 -080085 # Packages that needs separate handling, in addition to what we have from
86 # crossdev.
87 MANUAL_PKGS = {
88 'llvm': 'sys-devel',
89 }
David James66a09c42012-11-05 13:31:38 -080090
91 @classmethod
92 def Load(cls, reconfig):
93 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080094 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
95 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080096 if os.path.exists(cls._CACHE_FILE) and not reconfig:
97 with open(cls._CACHE_FILE) as f:
98 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080099 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -0800100 cls._CACHE = data
101
102 @classmethod
103 def Save(cls):
104 """Store crossdev cache on disk."""
105 # Save the cache from the successful run.
106 with open(cls._CACHE_FILE, 'w') as f:
107 json.dump(cls._CACHE, f)
108
109 @classmethod
110 def GetConfig(cls, target):
111 """Returns a map of crossdev provided variables about a tuple."""
112 CACHE_ATTR = '_target_tuple_map'
113
114 val = cls._CACHE.setdefault(CACHE_ATTR, {})
115 if not target in val:
116 # Find out the crossdev tuple.
117 target_tuple = target
118 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800119 target_tuple = toolchain.GetHostTuple()
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700120 # Build the crossdev command.
121 cmd = ['crossdev', '--show-target-cfg', '--ex-gdb']
122 if target in TARGET_GO_ENABLED:
123 cmd.extend(CROSSDEV_GO_ARGS)
124 cmd.extend(['-t', target_tuple])
David James66a09c42012-11-05 13:31:38 -0800125 # Catch output of crossdev.
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700126 out = cros_build_lib.RunCommand(cmd, print_cmd=False,
127 redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800128 # List of tuples split at the first '=', converted into dict.
Han Shene23782f2016-02-18 12:20:00 -0800129 conf = dict((k, cros_build_lib.ShellUnquote(v))
130 for k, v in (x.split('=', 1) for x in out))
131 conf['crosspkgs'] = conf['crosspkgs'].split()
132
133 for pkg, cat in cls.MANUAL_PKGS.iteritems():
134 conf[pkg + '_pn'] = pkg
135 conf[pkg + '_category'] = cat
136 if pkg not in conf['crosspkgs']:
137 conf['crosspkgs'].append(pkg)
138
139 val[target] = conf
140
David James66a09c42012-11-05 13:31:38 -0800141 return val[target]
142
143 @classmethod
144 def UpdateTargets(cls, targets, usepkg, config_only=False):
145 """Calls crossdev to initialize a cross target.
146
147 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700148 targets: The list of targets to initialize using crossdev.
149 usepkg: Copies the commandline opts.
150 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800151 """
152 configured_targets = cls._CACHE.setdefault('configured_targets', [])
153
154 cmdbase = ['crossdev', '--show-fail-log']
155 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
156 # Pick stable by default, and override as necessary.
157 cmdbase.extend(['-P', '--oneshot'])
158 if usepkg:
159 cmdbase.extend(['-P', '--getbinpkg',
160 '-P', '--usepkgonly',
161 '--without-headers'])
162
Christopher Wileyb22c0712015-06-02 10:37:03 -0700163 overlays = ' '.join((CHROMIUMOS_OVERLAY, ECLASS_OVERLAY, STABLE_OVERLAY))
David James66a09c42012-11-05 13:31:38 -0800164 cmdbase.extend(['--overlays', overlays])
165 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
166
167 for target in targets:
168 if config_only and target in configured_targets:
169 continue
170
171 cmd = cmdbase + ['-t', target]
172
173 for pkg in GetTargetPackages(target):
174 if pkg == 'gdb':
175 # Gdb does not have selectable versions.
176 cmd.append('--ex-gdb')
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700177 elif pkg == 'ex_go':
178 # Go does not have selectable versions.
179 cmd.extend(CROSSDEV_GO_ARGS)
Han Shene23782f2016-02-18 12:20:00 -0800180 elif pkg in cls.MANUAL_PKGS:
181 pass
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700182 else:
183 # The first of the desired versions is the "primary" one.
184 version = GetDesiredPackageVersions(target, pkg)[0]
185 cmd.extend(['--%s' % pkg, version])
David James66a09c42012-11-05 13:31:38 -0800186
187 cmd.extend(targets[target]['crossdev'].split())
188 if config_only:
189 # In this case we want to just quietly reinit
190 cmd.append('--init-target')
191 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
192 else:
193 cros_build_lib.RunCommand(cmd)
194
195 configured_targets.append(target)
196
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100197
Zdenek Behan508dcce2011-12-05 15:39:32 +0100198def GetPackageMap(target):
199 """Compiles a package map for the given target from the constants.
200
201 Uses a cache in target_version_map, that is dynamically filled in as needed,
202 since here everything is static data and the structuring is for ease of
203 configurability only.
204
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500205 Args:
206 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100207
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500208 Returns:
209 A map between packages and desired versions in internal format
210 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100211 """
212 if target in target_version_map:
213 return target_version_map[target]
214
215 # Start from copy of the global defaults.
216 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
217
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100218 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100219 # prefer any specific overrides
220 if pkg in TARGET_VERSION_MAP.get(target, {}):
221 result[pkg] = TARGET_VERSION_MAP[target][pkg]
222 else:
223 # finally, if not already set, set a sane default
224 result.setdefault(pkg, DEFAULT_VERSION)
225 target_version_map[target] = result
226 return result
227
228
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100229def GetTargetPackages(target):
230 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800231 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100232 # Undesired packages are denoted by empty ${pkg}_pn variable.
Han Shene23782f2016-02-18 12:20:00 -0800233 return [x for x in conf['crosspkgs'] if conf.get(x+'_pn')]
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100234
235
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100236# Portage helper functions:
237def GetPortagePackage(target, package):
238 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800239 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100240 # Portage category:
Han Shene23782f2016-02-18 12:20:00 -0800241 if target == 'host' or package in Crossdev.MANUAL_PKGS:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100242 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100244 category = conf['category']
245 # Portage package:
246 pn = conf[package + '_pn']
247 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500248 assert category
249 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100250 return '%s/%s' % (category, pn)
251
252
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100253def IsPackageDisabled(target, package):
254 """Returns if the given package is not used for the target."""
255 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
256
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100257
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700258def PortageTrees(root):
259 """Return the portage trees for a given root."""
260 if root == '/':
261 return portage.db['/']
262 # The portage logic requires the path always end in a slash.
263 root = root.rstrip('/') + '/'
264 return portage.create_trees(target_root=root, config_root=root)[root]
265
266
267def GetInstalledPackageVersions(atom, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100268 """Extracts the list of current versions of a target, package pair.
269
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500270 Args:
271 atom: The atom to operate on (e.g. sys-devel/gcc)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700272 root: The root to check for installed packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100273
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500274 Returns:
275 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100276 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100277 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500278 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700279 for pkg in PortageTrees(root)['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100280 version = portage.versions.cpv_getversion(pkg)
281 versions.append(version)
282 return versions
283
284
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700285def GetStablePackageVersion(atom, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100286 """Extracts the current stable version for a given package.
287
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500288 Args:
289 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
290 installed: Whether we want installed packages or ebuilds
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700291 root: The root to use when querying packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100292
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500293 Returns:
294 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100295 """
David James90239b92012-11-05 15:31:34 -0800296 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500297 # pylint: disable=E1101
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700298 cpv = portage.best(PortageTrees(root)[pkgtype].dbapi.match(atom, use_cache=0))
David James90239b92012-11-05 15:31:34 -0800299 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100300
301
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700302def VersionListToNumeric(target, package, versions, installed, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100303 """Resolves keywords in a given version list for a particular package.
304
305 Resolving means replacing PACKAGE_STABLE with the actual number.
306
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500307 Args:
308 target: The target to operate on (e.g. i686-pc-linux-gnu)
309 package: The target/package to operate on (e.g. gcc)
310 versions: List of versions to resolve
311 installed: Query installed packages
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700312 root: The install root to use; ignored if |installed| is False.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100313
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500314 Returns:
315 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100316 """
317 resolved = []
David James90239b92012-11-05 15:31:34 -0800318 atom = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700319 if not installed:
320 root = '/'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100321 for version in versions:
322 if version == PACKAGE_STABLE:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700323 resolved.append(GetStablePackageVersion(atom, installed, root=root))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100324 elif version != PACKAGE_NONE:
325 resolved.append(version)
326 return resolved
327
328
329def GetDesiredPackageVersions(target, package):
330 """Produces the list of desired versions for each target, package pair.
331
332 The first version in the list is implicitly treated as primary, ie.
333 the version that will be initialized by crossdev and selected.
334
335 If the version is PACKAGE_STABLE, it really means the current version which
336 is emerged by using the package atom with no particular version key.
337 Since crossdev unmasks all packages by default, this will actually
338 mean 'unstable' in most cases.
339
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500340 Args:
341 target: The target to operate on (e.g. i686-pc-linux-gnu)
342 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500344 Returns:
345 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100346 """
347 packagemap = GetPackageMap(target)
348
349 versions = []
350 if package in packagemap:
351 versions.append(packagemap[package])
352
353 return versions
354
355
356def TargetIsInitialized(target):
357 """Verifies if the given list of targets has been correctly initialized.
358
359 This determines whether we have to call crossdev while emerging
360 toolchain packages or can do it using emerge. Emerge is naturally
361 preferred, because all packages can be updated in a single pass.
362
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500363 Args:
364 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100365
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500366 Returns:
367 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100368 """
369 # Check if packages for the given target all have a proper version.
370 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100371 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800372 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100373 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800374 if not IsPackageDisabled(target, package) and not (
375 GetStablePackageVersion(atom, True) and
376 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100377 return False
378 return True
379 except cros_build_lib.RunCommandError:
380 # Fails - The target has likely never been initialized before.
381 return False
382
383
384def RemovePackageMask(target):
385 """Removes a package.mask file for the given platform.
386
387 The pre-existing package.mask files can mess with the keywords.
388
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500389 Args:
390 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100391 """
392 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700393 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
395
Zdenek Behan508dcce2011-12-05 15:39:32 +0100396# Main functions performing the actual update steps.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700397def RebuildLibtool(root='/'):
Mike Frysingerc880a962013-11-08 13:59:06 -0500398 """Rebuild libtool as needed
399
400 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
401 gcc, libtool will break. We can't use binary packages either as those will
402 most likely be compiled against the previous version of gcc.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700403
404 Args:
405 root: The install root where we want libtool rebuilt.
Mike Frysingerc880a962013-11-08 13:59:06 -0500406 """
407 needs_update = False
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700408 with open(os.path.join(root, 'usr/bin/libtool')) as f:
Mike Frysingerc880a962013-11-08 13:59:06 -0500409 for line in f:
410 # Look for a line like:
411 # sys_lib_search_path_spec="..."
412 # It'll be a list of paths and gcc will be one of them.
413 if line.startswith('sys_lib_search_path_spec='):
414 line = line.rstrip()
415 for path in line.split('=', 1)[1].strip('"').split():
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700416 if not os.path.exists(os.path.join(root, path.lstrip(os.path.sep))):
Mike Frysinger383367e2014-09-16 15:06:17 -0400417 print('Rebuilding libtool after gcc upgrade')
418 print(' %s' % line)
419 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500420 needs_update = True
421 break
422
423 if needs_update:
424 break
425
426 if needs_update:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700427 cmd = [EMERGE_CMD, '--oneshot']
428 if root != '/':
429 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
430 cmd.append('sys-devel/libtool')
Mike Frysingerc880a962013-11-08 13:59:06 -0500431 cros_build_lib.RunCommand(cmd)
432
433
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700434def UpdateTargets(targets, usepkg, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100435 """Determines which packages need update/unmerge and defers to portage.
436
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500437 Args:
438 targets: The list of targets to update
439 usepkg: Copies the commandline option
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700440 root: The install root in which we want packages updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100441 """
David James90239b92012-11-05 15:31:34 -0800442 # Remove keyword files created by old versions of cros_setup_toolchains.
443 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100444
445 # For each target, we do two things. Figure out the list of updates,
446 # and figure out the appropriate keywords/masks. Crossdev will initialize
447 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400448 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800449 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100450 for target in targets:
451 # Record the highest needed version for each target, for masking purposes.
452 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100453 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100454 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100455 if IsPackageDisabled(target, package):
456 continue
457 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700458 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200460 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100461 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100462
Zdenek Behan508dcce2011-12-05 15:39:32 +0100463 packages = []
464 for pkg in mergemap:
465 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200466 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800467 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100468
469 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400470 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800471 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100472
Mike Frysinger383367e2014-09-16 15:06:17 -0400473 print('Updating packages:')
474 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100475
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100476 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477 if usepkg:
478 cmd.extend(['--getbinpkg', '--usepkgonly'])
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700479 if root != '/':
480 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100481
482 cmd.extend(packages)
483 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800484 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485
486
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700487def CleanTargets(targets, root='/'):
488 """Unmerges old packages that are assumed unnecessary.
489
490 Args:
491 targets: The list of targets to clean up.
492 root: The install root in which we want packages cleaned up.
493 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100494 unmergemap = {}
495 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100496 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100497 if IsPackageDisabled(target, package):
498 continue
499 pkg = GetPortagePackage(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700500 current = GetInstalledPackageVersions(pkg, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100501 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700502 # NOTE: This refers to installed packages (vartree) rather than the
503 # Portage version (porttree and/or bintree) when determining the current
504 # version. While this isn't the most accurate thing to do, it is probably
505 # a good simple compromise, which should have the desired result of
506 # uninstalling everything but the latest installed version. In
507 # particular, using the bintree (--usebinpkg) requires a non-trivial
508 # binhost sync and is probably more complex than useful.
Zdenek Behan699ddd32012-04-13 07:14:08 +0200509 desired_num = VersionListToNumeric(target, package, desired, True)
510 if not set(desired_num).issubset(current):
Gilad Arnold2fcb0aa2015-05-21 14:51:41 -0700511 print('Error detecting stable version for %s, skipping clean!' % pkg)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200512 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100513 unmergemap[pkg] = set(current).difference(desired_num)
514
515 # Cleaning doesn't care about consistency and rebuilding package.* files.
516 packages = []
517 for pkg, vers in unmergemap.iteritems():
518 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
519
520 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400521 print('Cleaning packages:')
522 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100523 cmd = [EMERGE_CMD, '--unmerge']
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700524 if root != '/':
525 cmd.extend(['--sysroot=%s' % root, '--root=%s' % root])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100526 cmd.extend(packages)
527 cros_build_lib.RunCommand(cmd)
528 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400529 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530
531
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700532def SelectActiveToolchains(targets, suffixes, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100533 """Runs gcc-config and binutils-config to select the desired.
534
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500535 Args:
536 targets: The targets to select
537 suffixes: Optional target-specific hacks
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700538 root: The root where we want to select toolchain versions.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100539 """
540 for package in ['gcc', 'binutils']:
541 for target in targets:
542 # Pick the first version in the numbered list as the selected one.
543 desired = GetDesiredPackageVersions(target, package)
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700544 desired_num = VersionListToNumeric(target, package, desired, True,
545 root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100546 desired = desired_num[0]
547 # *-config does not play revisions, strip them, keep just PV.
548 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
549
550 if target == 'host':
551 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800552 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100553
554 # And finally, attach target to it.
555 desired = '%s-%s' % (target, desired)
556
557 # Target specific hacks
558 if package in suffixes:
559 if target in suffixes[package]:
560 desired += suffixes[package][target]
561
David James7ec5efc2012-11-06 09:39:49 -0800562 extra_env = {'CHOST': target}
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700563 if root != '/':
564 extra_env['ROOT'] = root
David James7ec5efc2012-11-06 09:39:49 -0800565 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500566 result = cros_build_lib.RunCommand(
567 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
568 current = result.output.splitlines()[0]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700569
570 # Do not reconfig when the current is live or nothing needs to be done.
571 extra_env = {'ROOT': root} if root != '/' else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100572 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500573 cmd = [package + '-config', desired]
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700574 cros_build_lib.RunCommand(cmd, print_cmd=False, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100575
576
Mike Frysinger35247af2012-11-16 18:58:06 -0500577def ExpandTargets(targets_wanted):
578 """Expand any possible toolchain aliases into full targets
579
580 This will expand 'all' and 'sdk' into the respective toolchain tuples.
581
582 Args:
583 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500584
Mike Frysinger35247af2012-11-16 18:58:06 -0500585 Returns:
Gilad Arnold8195b532015-04-07 10:56:30 +0300586 Dictionary of concrete targets and their toolchain tuples.
Mike Frysinger35247af2012-11-16 18:58:06 -0500587 """
Mike Frysinger35247af2012-11-16 18:58:06 -0500588 targets_wanted = set(targets_wanted)
Don Garrettc0c74002015-10-09 12:58:19 -0700589 if targets_wanted == set(['boards']):
590 # Only pull targets from the included boards.
Gilad Arnold8195b532015-04-07 10:56:30 +0300591 return {}
592
593 all_targets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500594 if targets_wanted == set(['all']):
Gilad Arnold8195b532015-04-07 10:56:30 +0300595 return all_targets
596 if targets_wanted == set(['sdk']):
Mike Frysinger35247af2012-11-16 18:58:06 -0500597 # Filter out all the non-sdk toolchains as we don't want to mess
598 # with those in all of our builds.
Gilad Arnold8195b532015-04-07 10:56:30 +0300599 return toolchain.FilterToolchains(all_targets, 'sdk', True)
600
601 # Verify user input.
602 nonexistent = targets_wanted.difference(all_targets)
603 if nonexistent:
604 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
605 return {t: all_targets[t] for t in targets_wanted}
Mike Frysinger35247af2012-11-16 18:58:06 -0500606
607
David Jamesf8c672f2012-11-06 13:38:11 -0800608def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
Don Garrettc0c74002015-10-09 12:58:19 -0700609 targets_wanted, boards_wanted, root='/'):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100610 """Performs all steps to create a synchronized toolchain enviroment.
611
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500612 Args:
613 usepkg: Use prebuilt packages
614 deleteold: Unmerge deprecated packages
615 hostonly: Only setup the host toolchain
616 reconfig: Reload crossdev config and reselect toolchains
617 targets_wanted: All the targets to update
618 boards_wanted: Load targets from these boards
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700619 root: The root in which to install the toolchains.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100620 """
David Jamesf8c672f2012-11-06 13:38:11 -0800621 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100622 if not hostonly:
623 # For hostonly, we can skip most of the below logic, much of which won't
624 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500625 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400626
Don Garrettc0c74002015-10-09 12:58:19 -0700627 # Now re-add any targets that might be from this board. This is to
Gilad Arnold8195b532015-04-07 10:56:30 +0300628 # allow unofficial boards to declare their own toolchains.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400629 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800630 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100631
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100632 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400633 for target in targets:
634 if TargetIsInitialized(target):
635 reconfig_targets[target] = targets[target]
636 else:
637 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100638 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400639 print('The following targets need to be re-initialized:')
640 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800641 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200642 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800643 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100644
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100645 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400646 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100647
648 # Now update all packages.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700649 if UpdateTargets(targets, usepkg, root=root) or crossdev_targets or reconfig:
650 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES, root=root)
David James7ec5efc2012-11-06 09:39:49 -0800651
652 if deleteold:
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700653 CleanTargets(targets, root=root)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100654
Mike Frysingerc880a962013-11-08 13:59:06 -0500655 # Now that we've cleared out old versions, see if we need to rebuild
656 # anything. Can't do this earlier as it might not be broken.
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700657 RebuildLibtool(root=root)
Mike Frysingerc880a962013-11-08 13:59:06 -0500658
Zdenek Behan508dcce2011-12-05 15:39:32 +0100659
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700660def ShowConfig(name):
661 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500662
663 Args:
Don Garrettc0c74002015-10-09 12:58:19 -0700664 name: The board name to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500665 """
Don Garrettc0c74002015-10-09 12:58:19 -0700666 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500667 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400668 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800669 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400670 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500671
672
Mike Frysinger35247af2012-11-16 18:58:06 -0500673def GeneratePathWrapper(root, wrappath, path):
674 """Generate a shell script to execute another shell script
675
676 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
677 argv[0] won't be pointing to the correct path, generate a shell script that
678 just executes another program with its full path.
679
680 Args:
681 root: The root tree to generate scripts inside of
682 wrappath: The full path (inside |root|) to create the wrapper
683 path: The target program which this wrapper will execute
684 """
685 replacements = {
686 'path': path,
687 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
688 }
689 wrapper = """#!/bin/sh
690base=$(realpath "$0")
691basedir=${base%%/*}
692exec "${basedir}/%(relroot)s%(path)s" "$@"
693""" % replacements
694 root_wrapper = root + wrappath
695 if os.path.islink(root_wrapper):
696 os.unlink(root_wrapper)
697 else:
698 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
699 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400700 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500701
702
703def FileIsCrosSdkElf(elf):
704 """Determine if |elf| is an ELF that we execute in the cros_sdk
705
706 We don't need this to be perfect, just quick. It makes sure the ELF
707 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
708
709 Args:
710 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500711
Mike Frysinger35247af2012-11-16 18:58:06 -0500712 Returns:
713 True if we think |elf| is a native ELF
714 """
715 with open(elf) as f:
716 data = f.read(20)
717 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
718 return (data[0:4] == '\x7fELF' and
719 data[4] == '\x02' and
720 data[5] == '\x01' and
721 data[18] == '\x3e')
722
723
724def IsPathPackagable(ptype, path):
725 """Should the specified file be included in a toolchain package?
726
727 We only need to handle files as we'll create dirs as we need them.
728
729 Further, trim files that won't be useful:
730 - non-english translations (.mo) since it'd require env vars
731 - debug files since these are for the host compiler itself
732 - info/man pages as they're big, and docs are online, and the
733 native docs should work fine for the most part (`man gcc`)
734
735 Args:
736 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
737 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500738
Mike Frysinger35247af2012-11-16 18:58:06 -0500739 Returns:
740 True if we want to include this path in the package
741 """
742 return not (ptype in ('dir',) or
743 path.startswith('/usr/lib/debug/') or
744 os.path.splitext(path)[1] == '.mo' or
745 ('/man/' in path or '/info/' in path))
746
747
748def ReadlinkRoot(path, root):
749 """Like os.readlink(), but relative to a |root|
750
751 Args:
752 path: The symlink to read
753 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500754
Mike Frysinger35247af2012-11-16 18:58:06 -0500755 Returns:
756 A fully resolved symlink path
757 """
758 while os.path.islink(root + path):
759 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
760 return path
761
762
763def _GetFilesForTarget(target, root='/'):
764 """Locate all the files to package for |target|
765
766 This does not cover ELF dependencies.
767
768 Args:
769 target: The toolchain target name
770 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500771
Mike Frysinger35247af2012-11-16 18:58:06 -0500772 Returns:
773 A tuple of a set of all packable paths, and a set of all paths which
774 are also native ELFs
775 """
776 paths = set()
777 elfs = set()
778
779 # Find all the files owned by the packages for this target.
780 for pkg in GetTargetPackages(target):
781 # Ignore packages that are part of the target sysroot.
782 if pkg in ('kernel', 'libc'):
783 continue
784
Rahul Chaudhry4b803052015-05-13 15:25:56 -0700785 # Skip Go compiler from redistributable packages.
786 # The "go" executable has GOROOT=/usr/lib/go/${CTARGET} hardcoded
787 # into it. Due to this, the toolchain cannot be unpacked anywhere
788 # else and be readily useful. To enable packaging Go, we need to:
789 # -) Tweak the wrappers/environment to override GOROOT
790 # automatically based on the unpack location.
791 # -) Make sure the ELF dependency checking and wrapping logic
792 # below skips the Go toolchain executables and libraries.
793 # -) Make sure the packaging process maintains the relative
794 # timestamps of precompiled standard library packages.
795 # (see dev-lang/go ebuild for details).
796 if pkg == 'ex_go':
797 continue
798
Mike Frysinger35247af2012-11-16 18:58:06 -0500799 atom = GetPortagePackage(target, pkg)
800 cat, pn = atom.split('/')
Gilad Arnold2dab78c2015-05-21 14:43:33 -0700801 ver = GetInstalledPackageVersions(atom, root=root)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700802 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500803
804 # pylint: disable=E1101
805 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
806 settings=portage.settings)
807 contents = dblink.getcontents()
808 for obj in contents:
809 ptype = contents[obj][0]
810 if not IsPathPackagable(ptype, obj):
811 continue
812
813 if ptype == 'obj':
814 # For native ELFs, we need to pull in their dependencies too.
815 if FileIsCrosSdkElf(obj):
816 elfs.add(obj)
817 paths.add(obj)
818
819 return paths, elfs
820
821
822def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500823 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500824 """Link in all packable files and their runtime dependencies
825
826 This also wraps up executable ELFs with helper scripts.
827
828 Args:
829 output_dir: The output directory to store files
830 paths: All the files to include
831 elfs: All the files which are ELFs (a subset of |paths|)
832 ldpaths: A dict of static ldpath information
833 path_rewrite_func: User callback to rewrite paths in output_dir
834 root: The root path to pull all packages/files from
835 """
836 # Link in all the files.
837 sym_paths = []
838 for path in paths:
839 new_path = path_rewrite_func(path)
840 dst = output_dir + new_path
841 osutils.SafeMakedirs(os.path.dirname(dst))
842
843 # Is this a symlink which we have to rewrite or wrap?
844 # Delay wrap check until after we have created all paths.
845 src = root + path
846 if os.path.islink(src):
847 tgt = os.readlink(src)
848 if os.path.sep in tgt:
849 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
850
851 # Rewrite absolute links to relative and then generate the symlink
852 # ourselves. All other symlinks can be hardlinked below.
853 if tgt[0] == '/':
854 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
855 os.symlink(tgt, dst)
856 continue
857
858 os.link(src, dst)
859
860 # Now see if any of the symlinks need to be wrapped.
861 for sym, tgt in sym_paths:
862 if tgt in elfs:
863 GeneratePathWrapper(output_dir, sym, tgt)
864
865 # Locate all the dependencies for all the ELFs. Stick them all in the
866 # top level "lib" dir to make the wrapper simpler. This exact path does
867 # not matter since we execute ldso directly, and we tell the ldso the
868 # exact path to search for its libraries.
869 libdir = os.path.join(output_dir, 'lib')
870 osutils.SafeMakedirs(libdir)
871 donelibs = set()
872 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400873 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500874 interp = e['interp']
875 if interp:
876 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400877 interp = os.path.join('/lib', os.path.basename(interp))
878 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
879 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500880
881 for lib, lib_data in e['libs'].iteritems():
882 if lib in donelibs:
883 continue
884
885 src = path = lib_data['path']
886 if path is None:
Ralph Nathan446aee92015-03-23 14:44:56 -0700887 logging.warning('%s: could not locate %s', elf, lib)
Mike Frysinger35247af2012-11-16 18:58:06 -0500888 continue
889 donelibs.add(lib)
890
891 # Needed libs are the SONAME, but that is usually a symlink, not a
892 # real file. So link in the target rather than the symlink itself.
893 # We have to walk all the possible symlinks (SONAME could point to a
894 # symlink which points to a symlink), and we have to handle absolute
895 # ourselves (since we have a "root" argument).
896 dst = os.path.join(libdir, os.path.basename(path))
897 src = ReadlinkRoot(src, root)
898
899 os.link(root + src, dst)
900
901
902def _EnvdGetVar(envd, var):
903 """Given a Gentoo env.d file, extract a var from it
904
905 Args:
906 envd: The env.d file to load (may be a glob path)
907 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500908
Mike Frysinger35247af2012-11-16 18:58:06 -0500909 Returns:
910 The value of |var|
911 """
912 envds = glob.glob(envd)
913 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
914 envd = envds[0]
915 return cros_build_lib.LoadKeyValueFile(envd)[var]
916
917
918def _ProcessBinutilsConfig(target, output_dir):
919 """Do what binutils-config would have done"""
920 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500921
922 # Locate the bin dir holding the gold linker.
923 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
924 target, 'binutils-bin')
925 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500926 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500927 if not srcpath:
928 # Maybe this target doesn't support gold.
929 globpath = os.path.join(binutils_bin_path, '*')
930 srcpath = glob.glob(globpath)
931 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
932 % globpath)
933 srcpath = srcpath[0]
934 ld_path = os.path.join(srcpath, 'ld')
935 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
936 ld_path = os.path.join(srcpath, 'ld.bfd')
937 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
938 ld_path = os.path.join(srcpath, 'ld.gold')
939 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
940 % ld_path)
941
942 # Nope, no gold support to be found.
943 gold_supported = False
Ralph Nathan446aee92015-03-23 14:44:56 -0700944 logging.warning('%s: binutils lacks support for the gold linker', target)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500945 else:
946 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
947 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -0500948 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500949
Mike Frysinger78b7a812014-11-26 19:45:23 -0500950 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -0500951 gccpath = os.path.join('/usr', 'libexec', 'gcc')
952 for prog in os.listdir(output_dir + srcpath):
953 # Skip binaries already wrapped.
954 if not prog.endswith('.real'):
955 GeneratePathWrapper(output_dir, binpath + prog,
956 os.path.join(srcpath, prog))
957 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
958 os.path.join(srcpath, prog))
959
David James27ac4ae2012-12-03 23:16:15 -0800960 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500961 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
962 if gold_supported:
963 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500964 srcpath = _EnvdGetVar(envd, 'LIBPATH')
965 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
966 output_dir + libpath)
967
968
969def _ProcessGccConfig(target, output_dir):
970 """Do what gcc-config would have done"""
971 binpath = '/bin'
972 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
973 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
974 for prog in os.listdir(output_dir + srcpath):
975 # Skip binaries already wrapped.
976 if (not prog.endswith('.real') and
977 not prog.endswith('.elf') and
978 prog.startswith(target)):
979 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
980 os.path.join(srcpath, prog))
981 return srcpath
982
983
Frank Henigman179ec7c2015-02-06 03:01:09 -0500984def _ProcessSysrootWrappers(_target, output_dir, srcpath):
985 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -0500986 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -0500987 for sysroot_wrapper in glob.glob(os.path.join(
988 output_dir + srcpath, 'sysroot_wrapper*')):
989 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
990 for num in xrange(len(contents)):
991 if '@CCACHE_DEFAULT@' in contents[num]:
992 contents[num] = 'use_ccache = False'
993 break
994 # Can't update the wrapper in place since it's a hardlink to a file in /.
995 os.unlink(sysroot_wrapper)
996 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
997 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500998
999
1000def _ProcessDistroCleanups(target, output_dir):
1001 """Clean up the tree and remove all distro-specific requirements
1002
1003 Args:
1004 target: The toolchain target name
1005 output_dir: The output directory to clean up
1006 """
1007 _ProcessBinutilsConfig(target, output_dir)
1008 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -05001009 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -05001010
1011 osutils.RmDir(os.path.join(output_dir, 'etc'))
1012
1013
1014def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
1015 """Setup a tree from the packages for the specified target
1016
1017 This populates a path with all the files from toolchain packages so that
1018 a tarball can easily be generated from the result.
1019
1020 Args:
1021 target: The target to create a packagable root from
1022 output_dir: The output directory to place all the files
1023 ldpaths: A dict of static ldpath information
1024 root: The root path to pull all packages/files from
1025 """
1026 # Find all the files owned by the packages for this target.
1027 paths, elfs = _GetFilesForTarget(target, root=root)
1028
1029 # Link in all the package's files, any ELF dependencies, and wrap any
1030 # executable ELFs with helper scripts.
1031 def MoveUsrBinToBin(path):
1032 """Move /usr/bin to /bin so people can just use that toplevel dir"""
1033 return path[4:] if path.startswith('/usr/bin/') else path
1034 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
1035 path_rewrite_func=MoveUsrBinToBin, root=root)
1036
1037 # The packages, when part of the normal distro, have helper scripts
1038 # that setup paths and such. Since we are making this standalone, we
1039 # need to preprocess all that ourselves.
1040 _ProcessDistroCleanups(target, output_dir)
1041
1042
1043def CreatePackages(targets_wanted, output_dir, root='/'):
1044 """Create redistributable cross-compiler packages for the specified targets
1045
1046 This creates toolchain packages that should be usable in conjunction with
1047 a downloaded sysroot (created elsewhere).
1048
1049 Tarballs (one per target) will be created in $PWD.
1050
1051 Args:
Don Garrett25f309a2014-03-19 14:02:12 -07001052 targets_wanted: The targets to package up.
1053 output_dir: The directory to put the packages in.
1054 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -05001055 """
Ralph Nathan03047282015-03-23 11:09:32 -07001056 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001057 osutils.SafeMakedirs(output_dir)
1058 ldpaths = lddtree.LoadLdpaths(root)
1059 targets = ExpandTargets(targets_wanted)
1060
David James4bc13702013-03-26 08:08:04 -07001061 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -05001062 # We have to split the root generation from the compression stages. This is
1063 # because we hardlink in all the files (to avoid overhead of reading/writing
1064 # the copies multiple times). But tar gets angry if a file's hardlink count
1065 # changes from when it starts reading a file to when it finishes.
1066 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
1067 for target in targets:
1068 output_target_dir = os.path.join(tempdir, target)
1069 queue.put([target, output_target_dir, ldpaths, root])
1070
1071 # Build the tarball.
1072 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
1073 for target in targets:
1074 tar_file = os.path.join(output_dir, target + '.tar.xz')
1075 queue.put([tar_file, os.path.join(tempdir, target)])
1076
1077
Brian Harring30675052012-02-29 12:18:22 -08001078def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -05001079 parser = commandline.ArgumentParser(description=__doc__)
1080 parser.add_argument('-u', '--nousepkg',
1081 action='store_false', dest='usepkg', default=True,
1082 help='Use prebuilt packages if possible')
1083 parser.add_argument('-d', '--deleteold',
1084 action='store_true', dest='deleteold', default=False,
1085 help='Unmerge deprecated packages')
1086 parser.add_argument('-t', '--targets',
1087 dest='targets', default='sdk',
Gilad Arnold8195b532015-04-07 10:56:30 +03001088 help="Comma separated list of tuples. Special keywords "
Don Garrettc0c74002015-10-09 12:58:19 -07001089 "'host', 'sdk', 'boards', and 'all' are "
Gilad Arnold8195b532015-04-07 10:56:30 +03001090 "allowed. Defaults to 'sdk'.")
1091 parser.add_argument('--include-boards', default='', metavar='BOARDS',
1092 help='Comma separated list of boards whose toolchains we '
1093 'will always include. Default: none')
Mike Frysinger0c808452014-11-06 17:30:23 -05001094 parser.add_argument('--hostonly',
1095 dest='hostonly', default=False, action='store_true',
1096 help='Only setup the host toolchain. '
1097 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001098 parser.add_argument('--show-board-cfg', '--show-cfg',
1099 dest='cfg_name', default=None,
Don Garrettc0c74002015-10-09 12:58:19 -07001100 help='Board to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001101 parser.add_argument('--create-packages',
1102 action='store_true', default=False,
1103 help='Build redistributable packages')
1104 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1105 help='Output directory')
1106 parser.add_argument('--reconfig', default=False, action='store_true',
1107 help='Reload crossdev config and reselect toolchains')
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001108 parser.add_argument('--sysroot', type='path',
1109 help='The sysroot in which to install the toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001110
Mike Frysinger0c808452014-11-06 17:30:23 -05001111 options = parser.parse_args(argv)
1112 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001113
Mike Frysinger35247af2012-11-16 18:58:06 -05001114 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001115 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001116 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001117
Gilad Arnold8195b532015-04-07 10:56:30 +03001118 targets_wanted = set(options.targets.split(','))
1119 boards_wanted = (set(options.include_boards.split(','))
1120 if options.include_boards else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001121
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001122 if options.cfg_name:
1123 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001124 elif options.create_packages:
1125 cros_build_lib.AssertInsideChroot()
1126 Crossdev.Load(False)
Gilad Arnold8195b532015-04-07 10:56:30 +03001127 CreatePackages(targets_wanted, options.output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -05001128 else:
1129 cros_build_lib.AssertInsideChroot()
1130 # This has to be always run as root.
1131 if os.geteuid() != 0:
1132 cros_build_lib.Die('this script must be run as root')
1133
1134 Crossdev.Load(options.reconfig)
Gilad Arnold2dab78c2015-05-21 14:43:33 -07001135 root = options.sysroot or '/'
Mike Frysinger35247af2012-11-16 18:58:06 -05001136 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
Gilad Arnold8195b532015-04-07 10:56:30 +03001137 options.reconfig, targets_wanted, boards_wanted,
Don Garrettc0c74002015-10-09 12:58:19 -07001138 root=root)
Mike Frysinger35247af2012-11-16 18:58:06 -05001139 Crossdev.Save()
1140
1141 return 0