blob: e068d950994af349d307bfe16c4e47f0855b5b77 [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
Bertrand SIMONNET3c77bc92015-03-20 14:28:54 -070021from chromite.lib import workspace_lib
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'
40STABLE_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,
53 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010054}
55# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
56CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050057 'binutils' : {
Han Shen43b84422015-02-19 11:38:13 -080058 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050059 'i686-pc-linux-gnu' : '-gold',
60 'x86_64-cros-linux-gnu' : '-gold',
61 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010062}
Zdenek Behan508dcce2011-12-05 15:39:32 +010063# Global per-run cache that will be filled ondemand in by GetPackageMap()
64# function as needed.
65target_version_map = {
66}
67
68
David James66a09c42012-11-05 13:31:38 -080069class Crossdev(object):
70 """Class for interacting with crossdev and caching its output."""
71
72 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
73 _CACHE = {}
74
75 @classmethod
76 def Load(cls, reconfig):
77 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080078 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
79 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080080 if os.path.exists(cls._CACHE_FILE) and not reconfig:
81 with open(cls._CACHE_FILE) as f:
82 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080083 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080084 cls._CACHE = data
85
86 @classmethod
87 def Save(cls):
88 """Store crossdev cache on disk."""
89 # Save the cache from the successful run.
90 with open(cls._CACHE_FILE, 'w') as f:
91 json.dump(cls._CACHE, f)
92
93 @classmethod
94 def GetConfig(cls, target):
95 """Returns a map of crossdev provided variables about a tuple."""
96 CACHE_ATTR = '_target_tuple_map'
97
98 val = cls._CACHE.setdefault(CACHE_ATTR, {})
99 if not target in val:
100 # Find out the crossdev tuple.
101 target_tuple = target
102 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800103 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -0800104 # Catch output of crossdev.
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500105 out = cros_build_lib.RunCommand(
106 ['crossdev', '--show-target-cfg', '--ex-gdb', target_tuple],
107 print_cmd=False, redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800108 # List of tuples split at the first '=', converted into dict.
109 val[target] = dict([x.split('=', 1) for x in out])
110 return val[target]
111
112 @classmethod
113 def UpdateTargets(cls, targets, usepkg, config_only=False):
114 """Calls crossdev to initialize a cross target.
115
116 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700117 targets: The list of targets to initialize using crossdev.
118 usepkg: Copies the commandline opts.
119 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800120 """
121 configured_targets = cls._CACHE.setdefault('configured_targets', [])
122
123 cmdbase = ['crossdev', '--show-fail-log']
124 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
125 # Pick stable by default, and override as necessary.
126 cmdbase.extend(['-P', '--oneshot'])
127 if usepkg:
128 cmdbase.extend(['-P', '--getbinpkg',
129 '-P', '--usepkgonly',
130 '--without-headers'])
131
132 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
133 cmdbase.extend(['--overlays', overlays])
134 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
135
136 for target in targets:
137 if config_only and target in configured_targets:
138 continue
139
140 cmd = cmdbase + ['-t', target]
141
142 for pkg in GetTargetPackages(target):
143 if pkg == 'gdb':
144 # Gdb does not have selectable versions.
145 cmd.append('--ex-gdb')
146 continue
147 # The first of the desired versions is the "primary" one.
148 version = GetDesiredPackageVersions(target, pkg)[0]
149 cmd.extend(['--%s' % pkg, version])
150
151 cmd.extend(targets[target]['crossdev'].split())
152 if config_only:
153 # In this case we want to just quietly reinit
154 cmd.append('--init-target')
155 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
156 else:
157 cros_build_lib.RunCommand(cmd)
158
159 configured_targets.append(target)
160
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100161
Zdenek Behan508dcce2011-12-05 15:39:32 +0100162def GetPackageMap(target):
163 """Compiles a package map for the given target from the constants.
164
165 Uses a cache in target_version_map, that is dynamically filled in as needed,
166 since here everything is static data and the structuring is for ease of
167 configurability only.
168
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500169 Args:
170 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100171
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500172 Returns:
173 A map between packages and desired versions in internal format
174 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100175 """
176 if target in target_version_map:
177 return target_version_map[target]
178
179 # Start from copy of the global defaults.
180 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
181
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100182 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100183 # prefer any specific overrides
184 if pkg in TARGET_VERSION_MAP.get(target, {}):
185 result[pkg] = TARGET_VERSION_MAP[target][pkg]
186 else:
187 # finally, if not already set, set a sane default
188 result.setdefault(pkg, DEFAULT_VERSION)
189 target_version_map[target] = result
190 return result
191
192
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100193def GetTargetPackages(target):
194 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800195 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100196 # Undesired packages are denoted by empty ${pkg}_pn variable.
197 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
198
199
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100200# Portage helper functions:
201def GetPortagePackage(target, package):
202 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800203 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100204 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100205 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100206 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100207 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100208 category = conf['category']
209 # Portage package:
210 pn = conf[package + '_pn']
211 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500212 assert category
213 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100214 return '%s/%s' % (category, pn)
215
216
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100217def IsPackageDisabled(target, package):
218 """Returns if the given package is not used for the target."""
219 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
220
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100221
David James66a09c42012-11-05 13:31:38 -0800222def GetInstalledPackageVersions(atom):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100223 """Extracts the list of current versions of a target, package pair.
224
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500225 Args:
226 atom: The atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100227
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500228 Returns:
229 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100230 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100231 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500232 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800233 for pkg in portage.db['/']['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100234 version = portage.versions.cpv_getversion(pkg)
235 versions.append(version)
236 return versions
237
238
David James90239b92012-11-05 15:31:34 -0800239def GetStablePackageVersion(atom, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100240 """Extracts the current stable version for a given package.
241
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500242 Args:
243 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
244 installed: Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100245
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500246 Returns:
247 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100248 """
David James90239b92012-11-05 15:31:34 -0800249 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500250 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800251 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
252 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100253
254
Zdenek Behan699ddd32012-04-13 07:14:08 +0200255def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100256 """Resolves keywords in a given version list for a particular package.
257
258 Resolving means replacing PACKAGE_STABLE with the actual number.
259
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500260 Args:
261 target: The target to operate on (e.g. i686-pc-linux-gnu)
262 package: The target/package to operate on (e.g. gcc)
263 versions: List of versions to resolve
264 installed: Query installed packages
Zdenek Behan508dcce2011-12-05 15:39:32 +0100265
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500266 Returns:
267 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100268 """
269 resolved = []
David James90239b92012-11-05 15:31:34 -0800270 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100271 for version in versions:
272 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800273 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100274 elif version != PACKAGE_NONE:
275 resolved.append(version)
276 return resolved
277
278
279def GetDesiredPackageVersions(target, package):
280 """Produces the list of desired versions for each target, package pair.
281
282 The first version in the list is implicitly treated as primary, ie.
283 the version that will be initialized by crossdev and selected.
284
285 If the version is PACKAGE_STABLE, it really means the current version which
286 is emerged by using the package atom with no particular version key.
287 Since crossdev unmasks all packages by default, this will actually
288 mean 'unstable' in most cases.
289
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500290 Args:
291 target: The target to operate on (e.g. i686-pc-linux-gnu)
292 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100293
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500294 Returns:
295 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100296 """
297 packagemap = GetPackageMap(target)
298
299 versions = []
300 if package in packagemap:
301 versions.append(packagemap[package])
302
303 return versions
304
305
306def TargetIsInitialized(target):
307 """Verifies if the given list of targets has been correctly initialized.
308
309 This determines whether we have to call crossdev while emerging
310 toolchain packages or can do it using emerge. Emerge is naturally
311 preferred, because all packages can be updated in a single pass.
312
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500313 Args:
314 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100315
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500316 Returns:
317 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100318 """
319 # Check if packages for the given target all have a proper version.
320 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100321 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800322 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100323 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800324 if not IsPackageDisabled(target, package) and not (
325 GetStablePackageVersion(atom, True) and
326 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100327 return False
328 return True
329 except cros_build_lib.RunCommandError:
330 # Fails - The target has likely never been initialized before.
331 return False
332
333
334def RemovePackageMask(target):
335 """Removes a package.mask file for the given platform.
336
337 The pre-existing package.mask files can mess with the keywords.
338
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500339 Args:
340 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100341 """
342 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700343 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344
345
Zdenek Behan508dcce2011-12-05 15:39:32 +0100346# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500347def RebuildLibtool():
348 """Rebuild libtool as needed
349
350 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
351 gcc, libtool will break. We can't use binary packages either as those will
352 most likely be compiled against the previous version of gcc.
353 """
354 needs_update = False
355 with open('/usr/bin/libtool') as f:
356 for line in f:
357 # Look for a line like:
358 # sys_lib_search_path_spec="..."
359 # It'll be a list of paths and gcc will be one of them.
360 if line.startswith('sys_lib_search_path_spec='):
361 line = line.rstrip()
362 for path in line.split('=', 1)[1].strip('"').split():
363 if not os.path.exists(path):
Mike Frysinger383367e2014-09-16 15:06:17 -0400364 print('Rebuilding libtool after gcc upgrade')
365 print(' %s' % line)
366 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500367 needs_update = True
368 break
369
370 if needs_update:
371 break
372
373 if needs_update:
374 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
375 cros_build_lib.RunCommand(cmd)
376
377
Zdenek Behan508dcce2011-12-05 15:39:32 +0100378def UpdateTargets(targets, usepkg):
379 """Determines which packages need update/unmerge and defers to portage.
380
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500381 Args:
382 targets: The list of targets to update
383 usepkg: Copies the commandline option
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 """
David James90239b92012-11-05 15:31:34 -0800385 # Remove keyword files created by old versions of cros_setup_toolchains.
386 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100387
388 # For each target, we do two things. Figure out the list of updates,
389 # and figure out the appropriate keywords/masks. Crossdev will initialize
390 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400391 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800392 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100393 for target in targets:
394 # Record the highest needed version for each target, for masking purposes.
395 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100396 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100398 if IsPackageDisabled(target, package):
399 continue
400 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800401 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200403 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100404 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100405
Zdenek Behan508dcce2011-12-05 15:39:32 +0100406 packages = []
407 for pkg in mergemap:
408 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200409 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800410 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100411
412 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400413 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800414 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100415
Mike Frysinger383367e2014-09-16 15:06:17 -0400416 print('Updating packages:')
417 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100418
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100419 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100420 if usepkg:
421 cmd.extend(['--getbinpkg', '--usepkgonly'])
422
423 cmd.extend(packages)
424 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800425 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100426
427
428def CleanTargets(targets):
429 """Unmerges old packages that are assumed unnecessary."""
430 unmergemap = {}
431 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100432 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100433 if IsPackageDisabled(target, package):
434 continue
435 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800436 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100437 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200438 desired_num = VersionListToNumeric(target, package, desired, True)
439 if not set(desired_num).issubset(current):
Mike Frysinger383367e2014-09-16 15:06:17 -0400440 print('Some packages have been held back, skipping clean!')
Zdenek Behan699ddd32012-04-13 07:14:08 +0200441 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100442 unmergemap[pkg] = set(current).difference(desired_num)
443
444 # Cleaning doesn't care about consistency and rebuilding package.* files.
445 packages = []
446 for pkg, vers in unmergemap.iteritems():
447 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
448
449 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400450 print('Cleaning packages:')
451 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100452 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100453 cmd.extend(packages)
454 cros_build_lib.RunCommand(cmd)
455 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400456 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457
458
459def SelectActiveToolchains(targets, suffixes):
460 """Runs gcc-config and binutils-config to select the desired.
461
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500462 Args:
463 targets: The targets to select
464 suffixes: Optional target-specific hacks
Zdenek Behan508dcce2011-12-05 15:39:32 +0100465 """
466 for package in ['gcc', 'binutils']:
467 for target in targets:
468 # Pick the first version in the numbered list as the selected one.
469 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200470 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100471 desired = desired_num[0]
472 # *-config does not play revisions, strip them, keep just PV.
473 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
474
475 if target == 'host':
476 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800477 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100478
479 # And finally, attach target to it.
480 desired = '%s-%s' % (target, desired)
481
482 # Target specific hacks
483 if package in suffixes:
484 if target in suffixes[package]:
485 desired += suffixes[package][target]
486
David James7ec5efc2012-11-06 09:39:49 -0800487 extra_env = {'CHOST': target}
488 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500489 result = cros_build_lib.RunCommand(
490 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
491 current = result.output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100492 # Do not gcc-config when the current is live or nothing needs to be done.
493 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500494 cmd = [package + '-config', desired]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100495 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100496
497
Mike Frysinger35247af2012-11-16 18:58:06 -0500498def ExpandTargets(targets_wanted):
499 """Expand any possible toolchain aliases into full targets
500
501 This will expand 'all' and 'sdk' into the respective toolchain tuples.
502
503 Args:
504 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500505
Mike Frysinger35247af2012-11-16 18:58:06 -0500506 Returns:
507 Full list of tuples with pseudo targets removed.
508 """
David James27ac4ae2012-12-03 23:16:15 -0800509 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500510 targets_wanted = set(targets_wanted)
511 if targets_wanted == set(['all']):
512 targets = alltargets
513 elif targets_wanted == set(['sdk']):
514 # Filter out all the non-sdk toolchains as we don't want to mess
515 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800516 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysingerda838af2014-11-05 12:36:48 -0500517 elif targets_wanted == set(['boards']):
518 # Only pull targets from the boards.
519 targets = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500520 else:
521 # Verify user input.
522 nonexistent = targets_wanted.difference(alltargets)
523 if nonexistent:
524 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
525 targets = dict((t, alltargets[t]) for t in targets_wanted)
526 return targets
527
528
David Jamesf8c672f2012-11-06 13:38:11 -0800529def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
530 targets_wanted, boards_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100531 """Performs all steps to create a synchronized toolchain enviroment.
532
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500533 Args:
534 usepkg: Use prebuilt packages
535 deleteold: Unmerge deprecated packages
536 hostonly: Only setup the host toolchain
537 reconfig: Reload crossdev config and reselect toolchains
538 targets_wanted: All the targets to update
539 boards_wanted: Load targets from these boards
Zdenek Behan508dcce2011-12-05 15:39:32 +0100540 """
David Jamesf8c672f2012-11-06 13:38:11 -0800541 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100542 if not hostonly:
543 # For hostonly, we can skip most of the below logic, much of which won't
544 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500545 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400546
Mike Frysinger7ccee992012-06-01 21:27:59 -0400547 # Now re-add any targets that might be from this board. This is
548 # to allow unofficial boards to declare their own toolchains.
549 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800550 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100552 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400553 for target in targets:
554 if TargetIsInitialized(target):
555 reconfig_targets[target] = targets[target]
556 else:
557 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100558 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400559 print('The following targets need to be re-initialized:')
560 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800561 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200562 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800563 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100565 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400566 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100567
568 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800569 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
570 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800571
572 if deleteold:
573 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100574
Mike Frysingerc880a962013-11-08 13:59:06 -0500575 # Now that we've cleared out old versions, see if we need to rebuild
576 # anything. Can't do this earlier as it might not be broken.
577 RebuildLibtool()
578
Zdenek Behan508dcce2011-12-05 15:39:32 +0100579
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700580def ShowConfig(name):
581 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500582
583 Args:
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700584 name: The board name or brick locator to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500585 """
Bertrand SIMONNET3c77bc92015-03-20 14:28:54 -0700586 if workspace_lib.IsLocator(name):
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700587 toolchains = toolchain.GetToolchainsForBrick(name)
588 else:
589 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500590 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400591 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800592 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400593 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500594
595
Mike Frysinger35247af2012-11-16 18:58:06 -0500596def GeneratePathWrapper(root, wrappath, path):
597 """Generate a shell script to execute another shell script
598
599 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
600 argv[0] won't be pointing to the correct path, generate a shell script that
601 just executes another program with its full path.
602
603 Args:
604 root: The root tree to generate scripts inside of
605 wrappath: The full path (inside |root|) to create the wrapper
606 path: The target program which this wrapper will execute
607 """
608 replacements = {
609 'path': path,
610 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
611 }
612 wrapper = """#!/bin/sh
613base=$(realpath "$0")
614basedir=${base%%/*}
615exec "${basedir}/%(relroot)s%(path)s" "$@"
616""" % replacements
617 root_wrapper = root + wrappath
618 if os.path.islink(root_wrapper):
619 os.unlink(root_wrapper)
620 else:
621 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
622 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400623 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500624
625
626def FileIsCrosSdkElf(elf):
627 """Determine if |elf| is an ELF that we execute in the cros_sdk
628
629 We don't need this to be perfect, just quick. It makes sure the ELF
630 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
631
632 Args:
633 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500634
Mike Frysinger35247af2012-11-16 18:58:06 -0500635 Returns:
636 True if we think |elf| is a native ELF
637 """
638 with open(elf) as f:
639 data = f.read(20)
640 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
641 return (data[0:4] == '\x7fELF' and
642 data[4] == '\x02' and
643 data[5] == '\x01' and
644 data[18] == '\x3e')
645
646
647def IsPathPackagable(ptype, path):
648 """Should the specified file be included in a toolchain package?
649
650 We only need to handle files as we'll create dirs as we need them.
651
652 Further, trim files that won't be useful:
653 - non-english translations (.mo) since it'd require env vars
654 - debug files since these are for the host compiler itself
655 - info/man pages as they're big, and docs are online, and the
656 native docs should work fine for the most part (`man gcc`)
657
658 Args:
659 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
660 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500661
Mike Frysinger35247af2012-11-16 18:58:06 -0500662 Returns:
663 True if we want to include this path in the package
664 """
665 return not (ptype in ('dir',) or
666 path.startswith('/usr/lib/debug/') or
667 os.path.splitext(path)[1] == '.mo' or
668 ('/man/' in path or '/info/' in path))
669
670
671def ReadlinkRoot(path, root):
672 """Like os.readlink(), but relative to a |root|
673
674 Args:
675 path: The symlink to read
676 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500677
Mike Frysinger35247af2012-11-16 18:58:06 -0500678 Returns:
679 A fully resolved symlink path
680 """
681 while os.path.islink(root + path):
682 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
683 return path
684
685
686def _GetFilesForTarget(target, root='/'):
687 """Locate all the files to package for |target|
688
689 This does not cover ELF dependencies.
690
691 Args:
692 target: The toolchain target name
693 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500694
Mike Frysinger35247af2012-11-16 18:58:06 -0500695 Returns:
696 A tuple of a set of all packable paths, and a set of all paths which
697 are also native ELFs
698 """
699 paths = set()
700 elfs = set()
701
702 # Find all the files owned by the packages for this target.
703 for pkg in GetTargetPackages(target):
704 # Ignore packages that are part of the target sysroot.
705 if pkg in ('kernel', 'libc'):
706 continue
707
708 atom = GetPortagePackage(target, pkg)
709 cat, pn = atom.split('/')
710 ver = GetInstalledPackageVersions(atom)[0]
Ralph Nathan03047282015-03-23 11:09:32 -0700711 logging.info('packaging %s-%s', atom, ver)
Mike Frysinger35247af2012-11-16 18:58:06 -0500712
713 # pylint: disable=E1101
714 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
715 settings=portage.settings)
716 contents = dblink.getcontents()
717 for obj in contents:
718 ptype = contents[obj][0]
719 if not IsPathPackagable(ptype, obj):
720 continue
721
722 if ptype == 'obj':
723 # For native ELFs, we need to pull in their dependencies too.
724 if FileIsCrosSdkElf(obj):
725 elfs.add(obj)
726 paths.add(obj)
727
728 return paths, elfs
729
730
731def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500732 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500733 """Link in all packable files and their runtime dependencies
734
735 This also wraps up executable ELFs with helper scripts.
736
737 Args:
738 output_dir: The output directory to store files
739 paths: All the files to include
740 elfs: All the files which are ELFs (a subset of |paths|)
741 ldpaths: A dict of static ldpath information
742 path_rewrite_func: User callback to rewrite paths in output_dir
743 root: The root path to pull all packages/files from
744 """
745 # Link in all the files.
746 sym_paths = []
747 for path in paths:
748 new_path = path_rewrite_func(path)
749 dst = output_dir + new_path
750 osutils.SafeMakedirs(os.path.dirname(dst))
751
752 # Is this a symlink which we have to rewrite or wrap?
753 # Delay wrap check until after we have created all paths.
754 src = root + path
755 if os.path.islink(src):
756 tgt = os.readlink(src)
757 if os.path.sep in tgt:
758 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
759
760 # Rewrite absolute links to relative and then generate the symlink
761 # ourselves. All other symlinks can be hardlinked below.
762 if tgt[0] == '/':
763 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
764 os.symlink(tgt, dst)
765 continue
766
767 os.link(src, dst)
768
769 # Now see if any of the symlinks need to be wrapped.
770 for sym, tgt in sym_paths:
771 if tgt in elfs:
772 GeneratePathWrapper(output_dir, sym, tgt)
773
774 # Locate all the dependencies for all the ELFs. Stick them all in the
775 # top level "lib" dir to make the wrapper simpler. This exact path does
776 # not matter since we execute ldso directly, and we tell the ldso the
777 # exact path to search for its libraries.
778 libdir = os.path.join(output_dir, 'lib')
779 osutils.SafeMakedirs(libdir)
780 donelibs = set()
781 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400782 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500783 interp = e['interp']
784 if interp:
785 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400786 interp = os.path.join('/lib', os.path.basename(interp))
787 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
788 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500789
790 for lib, lib_data in e['libs'].iteritems():
791 if lib in donelibs:
792 continue
793
794 src = path = lib_data['path']
795 if path is None:
796 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
797 continue
798 donelibs.add(lib)
799
800 # Needed libs are the SONAME, but that is usually a symlink, not a
801 # real file. So link in the target rather than the symlink itself.
802 # We have to walk all the possible symlinks (SONAME could point to a
803 # symlink which points to a symlink), and we have to handle absolute
804 # ourselves (since we have a "root" argument).
805 dst = os.path.join(libdir, os.path.basename(path))
806 src = ReadlinkRoot(src, root)
807
808 os.link(root + src, dst)
809
810
811def _EnvdGetVar(envd, var):
812 """Given a Gentoo env.d file, extract a var from it
813
814 Args:
815 envd: The env.d file to load (may be a glob path)
816 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500817
Mike Frysinger35247af2012-11-16 18:58:06 -0500818 Returns:
819 The value of |var|
820 """
821 envds = glob.glob(envd)
822 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
823 envd = envds[0]
824 return cros_build_lib.LoadKeyValueFile(envd)[var]
825
826
827def _ProcessBinutilsConfig(target, output_dir):
828 """Do what binutils-config would have done"""
829 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500830
831 # Locate the bin dir holding the gold linker.
832 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
833 target, 'binutils-bin')
834 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500835 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500836 if not srcpath:
837 # Maybe this target doesn't support gold.
838 globpath = os.path.join(binutils_bin_path, '*')
839 srcpath = glob.glob(globpath)
840 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
841 % globpath)
842 srcpath = srcpath[0]
843 ld_path = os.path.join(srcpath, 'ld')
844 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
845 ld_path = os.path.join(srcpath, 'ld.bfd')
846 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
847 ld_path = os.path.join(srcpath, 'ld.gold')
848 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
849 % ld_path)
850
851 # Nope, no gold support to be found.
852 gold_supported = False
853 cros_build_lib.Warning('%s: binutils lacks support for the gold linker',
854 target)
855 else:
856 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
857 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -0500858 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500859
Mike Frysinger78b7a812014-11-26 19:45:23 -0500860 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -0500861 gccpath = os.path.join('/usr', 'libexec', 'gcc')
862 for prog in os.listdir(output_dir + srcpath):
863 # Skip binaries already wrapped.
864 if not prog.endswith('.real'):
865 GeneratePathWrapper(output_dir, binpath + prog,
866 os.path.join(srcpath, prog))
867 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
868 os.path.join(srcpath, prog))
869
David James27ac4ae2012-12-03 23:16:15 -0800870 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500871 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
872 if gold_supported:
873 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500874 srcpath = _EnvdGetVar(envd, 'LIBPATH')
875 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
876 output_dir + libpath)
877
878
879def _ProcessGccConfig(target, output_dir):
880 """Do what gcc-config would have done"""
881 binpath = '/bin'
882 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
883 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
884 for prog in os.listdir(output_dir + srcpath):
885 # Skip binaries already wrapped.
886 if (not prog.endswith('.real') and
887 not prog.endswith('.elf') and
888 prog.startswith(target)):
889 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
890 os.path.join(srcpath, prog))
891 return srcpath
892
893
Frank Henigman179ec7c2015-02-06 03:01:09 -0500894def _ProcessSysrootWrappers(_target, output_dir, srcpath):
895 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -0500896 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -0500897 for sysroot_wrapper in glob.glob(os.path.join(
898 output_dir + srcpath, 'sysroot_wrapper*')):
899 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
900 for num in xrange(len(contents)):
901 if '@CCACHE_DEFAULT@' in contents[num]:
902 contents[num] = 'use_ccache = False'
903 break
904 # Can't update the wrapper in place since it's a hardlink to a file in /.
905 os.unlink(sysroot_wrapper)
906 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
907 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500908
909
910def _ProcessDistroCleanups(target, output_dir):
911 """Clean up the tree and remove all distro-specific requirements
912
913 Args:
914 target: The toolchain target name
915 output_dir: The output directory to clean up
916 """
917 _ProcessBinutilsConfig(target, output_dir)
918 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -0500919 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -0500920
921 osutils.RmDir(os.path.join(output_dir, 'etc'))
922
923
924def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
925 """Setup a tree from the packages for the specified target
926
927 This populates a path with all the files from toolchain packages so that
928 a tarball can easily be generated from the result.
929
930 Args:
931 target: The target to create a packagable root from
932 output_dir: The output directory to place all the files
933 ldpaths: A dict of static ldpath information
934 root: The root path to pull all packages/files from
935 """
936 # Find all the files owned by the packages for this target.
937 paths, elfs = _GetFilesForTarget(target, root=root)
938
939 # Link in all the package's files, any ELF dependencies, and wrap any
940 # executable ELFs with helper scripts.
941 def MoveUsrBinToBin(path):
942 """Move /usr/bin to /bin so people can just use that toplevel dir"""
943 return path[4:] if path.startswith('/usr/bin/') else path
944 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
945 path_rewrite_func=MoveUsrBinToBin, root=root)
946
947 # The packages, when part of the normal distro, have helper scripts
948 # that setup paths and such. Since we are making this standalone, we
949 # need to preprocess all that ourselves.
950 _ProcessDistroCleanups(target, output_dir)
951
952
953def CreatePackages(targets_wanted, output_dir, root='/'):
954 """Create redistributable cross-compiler packages for the specified targets
955
956 This creates toolchain packages that should be usable in conjunction with
957 a downloaded sysroot (created elsewhere).
958
959 Tarballs (one per target) will be created in $PWD.
960
961 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700962 targets_wanted: The targets to package up.
963 output_dir: The directory to put the packages in.
964 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500965 """
Ralph Nathan03047282015-03-23 11:09:32 -0700966 logging.info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -0500967 osutils.SafeMakedirs(output_dir)
968 ldpaths = lddtree.LoadLdpaths(root)
969 targets = ExpandTargets(targets_wanted)
970
David James4bc13702013-03-26 08:08:04 -0700971 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500972 # We have to split the root generation from the compression stages. This is
973 # because we hardlink in all the files (to avoid overhead of reading/writing
974 # the copies multiple times). But tar gets angry if a file's hardlink count
975 # changes from when it starts reading a file to when it finishes.
976 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
977 for target in targets:
978 output_target_dir = os.path.join(tempdir, target)
979 queue.put([target, output_target_dir, ldpaths, root])
980
981 # Build the tarball.
982 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
983 for target in targets:
984 tar_file = os.path.join(output_dir, target + '.tar.xz')
985 queue.put([tar_file, os.path.join(tempdir, target)])
986
987
Brian Harring30675052012-02-29 12:18:22 -0800988def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -0500989 parser = commandline.ArgumentParser(description=__doc__)
990 parser.add_argument('-u', '--nousepkg',
991 action='store_false', dest='usepkg', default=True,
992 help='Use prebuilt packages if possible')
993 parser.add_argument('-d', '--deleteold',
994 action='store_true', dest='deleteold', default=False,
995 help='Unmerge deprecated packages')
996 parser.add_argument('-t', '--targets',
997 dest='targets', default='sdk',
998 help='Comma separated list of tuples. '
999 'Special keyword \'host\' is allowed. Default: sdk')
1000 parser.add_argument('--include-boards',
1001 dest='include_boards', default='',
1002 help='Comma separated list of boards whose toolchains we'
1003 ' will always include. Default: none')
1004 parser.add_argument('--hostonly',
1005 dest='hostonly', default=False, action='store_true',
1006 help='Only setup the host toolchain. '
1007 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001008 parser.add_argument('--show-board-cfg', '--show-cfg',
1009 dest='cfg_name', default=None,
1010 help='Board or brick to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001011 parser.add_argument('--create-packages',
1012 action='store_true', default=False,
1013 help='Build redistributable packages')
1014 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1015 help='Output directory')
1016 parser.add_argument('--reconfig', default=False, action='store_true',
1017 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001018
Mike Frysinger0c808452014-11-06 17:30:23 -05001019 options = parser.parse_args(argv)
1020 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001021
Mike Frysinger35247af2012-11-16 18:58:06 -05001022 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001023 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001024 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001025
Zdenek Behan508dcce2011-12-05 15:39:32 +01001026 targets = set(options.targets.split(','))
Mike Frysinger0c808452014-11-06 17:30:23 -05001027 boards = (set(options.include_boards.split(',')) if options.include_boards
1028 else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001029
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001030 if options.cfg_name:
1031 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001032 elif options.create_packages:
1033 cros_build_lib.AssertInsideChroot()
1034 Crossdev.Load(False)
1035 CreatePackages(targets, options.output_dir)
1036 else:
1037 cros_build_lib.AssertInsideChroot()
1038 # This has to be always run as root.
1039 if os.geteuid() != 0:
1040 cros_build_lib.Die('this script must be run as root')
1041
1042 Crossdev.Load(options.reconfig)
1043 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
1044 options.reconfig, targets, boards)
1045 Crossdev.Save()
1046
1047 return 0