blob: e595069f39018eb4cf7141df50f3d6849fe68c3a [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6"""This script manages the installed toolchains in the chroot.
7"""
8
9import copy
Zdenek Behan7e33b4e2012-03-12 17:00:56 +010010import errno
Zdenek Behan508dcce2011-12-05 15:39:32 +010011import optparse
12import os
13import sys
14
Brian Harring503f3ab2012-03-09 21:39:41 -080015from chromite.buildbot import constants
16from chromite.lib import cros_build_lib
Zdenek Behan508dcce2011-12-05 15:39:32 +010017
18# Some sanity checks first.
19if not cros_build_lib.IsInsideChroot():
20 print '%s: This needs to be run inside the chroot' % sys.argv[0]
21 sys.exit(1)
22# Only import portage after we've checked that we're inside the chroot.
23# Outside may not have portage, in which case the above may not happen.
24import portage
25
26
Zdenek Behan331f9822012-04-13 05:02:36 +020027EMERGE_CMD = os.path.join(
28 constants.SOURCE_ROOT, 'chromite/bin/parallel_emerge')
29CROS_OVERLAY_LIST_CMD = os.path.join(
30 constants.SOURCE_ROOT, 'src/platform/dev/host/cros_overlay_list')
Zdenek Behan508dcce2011-12-05 15:39:32 +010031PACKAGE_STABLE = '[stable]'
32PACKAGE_NONE = '[none]'
33SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010034
35CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
36STABLE_OVERLAY = '/usr/local/portage/stable'
37CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010038
39
40# TODO: The versions are stored here very much like in setup_board.
41# The goal for future is to differentiate these using a config file.
42# This is done essentially by messing with GetDesiredPackageVersions()
43DEFAULT_VERSION = PACKAGE_STABLE
44DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010045}
46TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010047 'host' : {
48 'binutils' : '2.21.1',
49 'gdb' : PACKAGE_NONE,
50 },
51}
52# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
53CONFIG_TARGET_SUFFIXES = {
54 'binutils' : {
55 'i686-pc-linux-gnu' : '-gold',
56 'x86_64-cros-linux-gnu' : '-gold',
57 },
58}
Zdenek Behan508dcce2011-12-05 15:39:32 +010059# Global per-run cache that will be filled ondemand in by GetPackageMap()
60# function as needed.
61target_version_map = {
62}
63
64
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010065# Global variable cache. It has to be a descendant of 'object', rather than
66# instance thereof, because attributes cannot be set on 'object' instances.
67class VariableCache(object):
68 pass
69VAR_CACHE = VariableCache()
70
71
Zdenek Behan508dcce2011-12-05 15:39:32 +010072def GetPackageMap(target):
73 """Compiles a package map for the given target from the constants.
74
75 Uses a cache in target_version_map, that is dynamically filled in as needed,
76 since here everything is static data and the structuring is for ease of
77 configurability only.
78
79 args:
80 target - the target for which to return a version map
81
82 returns a map between packages and desired versions in internal format
83 (using the PACKAGE_* constants)
84 """
85 if target in target_version_map:
86 return target_version_map[target]
87
88 # Start from copy of the global defaults.
89 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
90
Zdenek Behanf4d18a02012-03-22 15:45:05 +010091 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +010092 # prefer any specific overrides
93 if pkg in TARGET_VERSION_MAP.get(target, {}):
94 result[pkg] = TARGET_VERSION_MAP[target][pkg]
95 else:
96 # finally, if not already set, set a sane default
97 result.setdefault(pkg, DEFAULT_VERSION)
98 target_version_map[target] = result
99 return result
100
101
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100102def GetHostTuple():
103 """Returns compiler tuple for the host system.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100104
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100105 Caches the result, because the command can be fairly expensive, and never
106 changes throughout a single run.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100107 """
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100108 CACHE_ATTR = '_host_tuple'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100109
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100110 val = getattr(VAR_CACHE, CACHE_ATTR, None)
111 if val is None:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100112 val = portage.settings['CHOST']
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100113 setattr(VAR_CACHE, CACHE_ATTR, val)
114 return val
115
116
117def GetCrossdevConf(target):
118 """Returns a map of crossdev provided variables about a tuple."""
119 CACHE_ATTR = '_target_tuple_map'
120
121 val = getattr(VAR_CACHE, CACHE_ATTR, {})
122 if not target in val:
123 # Find out the crossdev tuple.
124 target_tuple = target
125 if target == 'host':
126 target_tuple = GetHostTuple()
127 # Catch output of crossdev.
128 out = cros_build_lib.RunCommand(['crossdev', '--show-target-cfg',
129 '--ex-gdb', target_tuple],
130 print_cmd=False, redirect_stdout=True).output.splitlines()
131 # List of tuples split at the first '=', converted into dict.
132 val[target] = dict([x.split('=', 1) for x in out])
133 setattr(VAR_CACHE, CACHE_ATTR, {})
134 return val[target]
135
136
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100137def GetTargetPackages(target):
138 """Returns a list of packages for a given target."""
139 conf = GetCrossdevConf(target)
140 # Undesired packages are denoted by empty ${pkg}_pn variable.
141 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
142
143
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100144# Portage helper functions:
145def GetPortagePackage(target, package):
146 """Returns a package name for the given target."""
147 conf = GetCrossdevConf(target)
148 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100149 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100150 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100151 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100152 category = conf['category']
153 # Portage package:
154 pn = conf[package + '_pn']
155 # Final package name:
156 assert(category)
157 assert(pn)
158 return '%s/%s' % (category, pn)
159
160
161def GetPortageKeyword(target):
162 """Returns a portage friendly keyword for a given target."""
163 return GetCrossdevConf(target)['arch']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100164
165
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100166def IsPackageDisabled(target, package):
167 """Returns if the given package is not used for the target."""
168 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
169
Zdenek Behan508dcce2011-12-05 15:39:32 +0100170# Tree interface functions. They help with retrieving data about the current
171# state of the tree:
172def GetAllTargets():
173 """Get the complete list of targets.
174
175 returns the list of cross targets for the current tree
176 """
Zdenek Behan331f9822012-04-13 05:02:36 +0200177 cmd = [CROS_OVERLAY_LIST_CMD, '--all_boards']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100178 overlays = cros_build_lib.RunCommand(cmd, print_cmd=False,
179 redirect_stdout=True).output.splitlines()
180 targets = set()
181 for overlay in overlays:
182 config = os.path.join(overlay, 'toolchain.conf')
183 if os.path.exists(config):
184 with open(config) as config_file:
185 lines = config_file.read().splitlines()
186 for line in lines:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100187 line = line.split('#', 1)[0]
188 targets.update(line.split())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100189
190 # Remove the host target as that is not a cross-target. Replace with 'host'.
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100191 targets.discard(GetHostTuple())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100192 return targets
193
194
195def GetInstalledPackageVersions(target, package):
196 """Extracts the list of current versions of a target, package pair.
197
198 args:
199 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
200
201 returns the list of versions of the package currently installed.
202 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100203 versions = []
204 # This is the package name in terms of portage.
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100205 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100206 for pkg in portage.db['/']['vartree'].dbapi.match(atom):
207 version = portage.versions.cpv_getversion(pkg)
208 versions.append(version)
209 return versions
210
211
Zdenek Behan699ddd32012-04-13 07:14:08 +0200212def GetStablePackageVersion(target, package, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100213 """Extracts the current stable version for a given package.
214
215 args:
216 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
Zdenek Behan699ddd32012-04-13 07:14:08 +0200217 installed - Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100218
219 returns a string containing the latest version.
220 """
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200221 def mass_portageq_splitline(entry):
222 """Splits the output of mass_best_visible into package:version tuple."""
223 # mass_best_visible returns lines of the format "package:cpv"
224 split_string = entry.split(':', 1)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200225 if split_string[1]:
226 split_string[1] = portage.versions.cpv_getversion(split_string[1])
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200227 return split_string
228
229 CACHE_ATTR = '_target_stable_map'
230
Zdenek Behan699ddd32012-04-13 07:14:08 +0200231 pkgtype = "installed" if installed else "ebuild"
232
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200233 val = getattr(VAR_CACHE, CACHE_ATTR, {})
234 if not target in val:
Zdenek Behan699ddd32012-04-13 07:14:08 +0200235 val[target] = {}
236 if not pkgtype in val[target]:
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200237 keyword = GetPortageKeyword(target)
238 extra_env = {'ACCEPT_KEYWORDS' : '-* ' + keyword}
239 # Evaluate all packages for a target in one swoop, because it's much faster.
240 pkgs = [GetPortagePackage(target, p) for p in GetTargetPackages(target)]
Zdenek Behan699ddd32012-04-13 07:14:08 +0200241 cmd = ['portageq', 'mass_best_visible', '/', pkgtype] + pkgs
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200242 cpvs = cros_build_lib.RunCommand(cmd,
243 print_cmd=False, redirect_stdout=True,
244 extra_env=extra_env).output.splitlines()
Zdenek Behan699ddd32012-04-13 07:14:08 +0200245 val[target][pkgtype] = dict(map(mass_portageq_splitline, cpvs))
Zdenek Behan20d6ea22012-04-05 05:15:39 +0200246 setattr(VAR_CACHE, CACHE_ATTR, val)
247
Zdenek Behan699ddd32012-04-13 07:14:08 +0200248 return val[target][pkgtype][GetPortagePackage(target, package)]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100249
250
Zdenek Behan699ddd32012-04-13 07:14:08 +0200251def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100252 """Resolves keywords in a given version list for a particular package.
253
254 Resolving means replacing PACKAGE_STABLE with the actual number.
255
256 args:
257 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
258 versions - list of versions to resolve
259
260 returns list of purely numeric versions equivalent to argument
261 """
262 resolved = []
263 for version in versions:
264 if version == PACKAGE_STABLE:
Zdenek Behan699ddd32012-04-13 07:14:08 +0200265 resolved.append(GetStablePackageVersion(target, package, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100266 elif version != PACKAGE_NONE:
267 resolved.append(version)
268 return resolved
269
270
271def GetDesiredPackageVersions(target, package):
272 """Produces the list of desired versions for each target, package pair.
273
274 The first version in the list is implicitly treated as primary, ie.
275 the version that will be initialized by crossdev and selected.
276
277 If the version is PACKAGE_STABLE, it really means the current version which
278 is emerged by using the package atom with no particular version key.
279 Since crossdev unmasks all packages by default, this will actually
280 mean 'unstable' in most cases.
281
282 args:
283 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
284
285 returns a list composed of either a version string, PACKAGE_STABLE
286 """
287 packagemap = GetPackageMap(target)
288
289 versions = []
290 if package in packagemap:
291 versions.append(packagemap[package])
292
293 return versions
294
295
296def TargetIsInitialized(target):
297 """Verifies if the given list of targets has been correctly initialized.
298
299 This determines whether we have to call crossdev while emerging
300 toolchain packages or can do it using emerge. Emerge is naturally
301 preferred, because all packages can be updated in a single pass.
302
303 args:
304 targets - list of individual cross targets which are checked
305
306 returns True if target is completely initialized
307 returns False otherwise
308 """
309 # Check if packages for the given target all have a proper version.
310 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100311 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100312 # Do we even want this package && is it initialized?
313 if not IsPackageDisabled(target, package) and \
314 not GetInstalledPackageVersions(target, package):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100315 return False
316 return True
317 except cros_build_lib.RunCommandError:
318 # Fails - The target has likely never been initialized before.
319 return False
320
321
322def RemovePackageMask(target):
323 """Removes a package.mask file for the given platform.
324
325 The pre-existing package.mask files can mess with the keywords.
326
327 args:
328 target - the target for which to remove the file
329 """
330 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100331 try:
332 os.unlink(maskfile)
333 except EnvironmentError as e:
334 if e.errno != errno.ENOENT:
335 raise
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336
337
338def CreatePackageMask(target, masks):
339 """[Re]creates a package.mask file for the given platform.
340
341 args:
342 target - the given target on which to operate
343 masks - a map of package : version,
344 where version is the highest permissible version (mask >)
345 """
346 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
347 assert not os.path.exists(maskfile)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100348 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100349
350 with open(maskfile, 'w') as f:
351 for pkg, m in masks.items():
352 f.write('>%s-%s\n' % (pkg, m))
353
354
355def CreatePackageKeywords(target):
356 """[Re]create a package.keywords file for the platform.
357
358 This sets all package.keywords files to unmask all stable/testing packages.
359 TODO: Note that this approach should be deprecated and is only done for
360 compatibility reasons. In the future, we'd like to stop using keywords
361 altogether, and keep just stable unmasked.
362
363 args:
364 target - target for which to recreate package.keywords
365 """
366 maskfile = os.path.join('/etc/portage/package.keywords', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100367 try:
368 os.unlink(maskfile)
369 except EnvironmentError as e:
370 if e.errno != errno.ENOENT:
371 raise
372 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100373
374 keyword = GetPortageKeyword(target)
375
376 with open(maskfile, 'w') as f:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100377 for pkg in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100378 if IsPackageDisabled(target, pkg):
379 continue
380 f.write('%s %s ~%s\n' %
381 (GetPortagePackage(target, pkg), keyword, keyword))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100382
383
384# Main functions performing the actual update steps.
385def InitializeCrossdevTargets(targets, usepkg):
386 """Calls crossdev to initialize a cross target.
387 args:
388 targets - the list of targets to initialize using crossdev
389 usepkg - copies the commandline opts
390 """
391 print 'The following targets need to be re-initialized:'
392 print targets
Zdenek Behan508dcce2011-12-05 15:39:32 +0100393
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100394 extra_env = { 'FEATURES' : 'splitdebug' }
Zdenek Behan508dcce2011-12-05 15:39:32 +0100395 for target in targets:
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100396 cmd = ['crossdev', '--show-fail-log',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100397 '-t', target]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100398 # Pick stable by default, and override as necessary.
399 cmd.extend(['-P', '--oneshot'])
400 if usepkg:
401 cmd.extend(['-P', '--getbinpkg',
402 '-P', '--usepkgonly',
403 '--without-headers'])
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100404
405 cmd.extend(['--overlays', '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)])
406 cmd.extend(['--ov-output', CROSSDEV_OVERLAY])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100408 for pkg in GetTargetPackages(target):
409 if pkg == 'gdb':
410 # Gdb does not have selectable versions.
411 cmd.append('--ex-gdb')
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100412 continue
Zdenek Behan508dcce2011-12-05 15:39:32 +0100413 # The first of the desired versions is the "primary" one.
414 version = GetDesiredPackageVersions(target, pkg)[0]
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100415 cmd.extend(['--%s' % pkg, version])
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100416 cros_build_lib.RunCommand(cmd, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100417
418
419def UpdateTargets(targets, usepkg):
420 """Determines which packages need update/unmerge and defers to portage.
421
422 args:
423 targets - the list of targets to update
424 usepkg - copies the commandline option
425 """
426 # TODO(zbehan): This process is rather complex due to package.* handling.
427 # With some semantic changes over the original setup_board functionality,
428 # it can be considerably cleaned up.
429 mergemap = {}
430
431 # For each target, we do two things. Figure out the list of updates,
432 # and figure out the appropriate keywords/masks. Crossdev will initialize
433 # these, but they need to be regenerated on every update.
434 print 'Determining required toolchain updates...'
435 for target in targets:
436 # Record the highest needed version for each target, for masking purposes.
437 RemovePackageMask(target)
438 CreatePackageKeywords(target)
439 packagemasks = {}
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100440 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100441 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100442 if IsPackageDisabled(target, package):
443 continue
444 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100445 current = GetInstalledPackageVersions(target, package)
446 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200447 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100448 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100449
450 # Pick the highest version for mask.
451 packagemasks[pkg] = portage.versions.best(desired_num)
452
453 CreatePackageMask(target, packagemasks)
454
455 packages = []
456 for pkg in mergemap:
457 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200458 if ver != PACKAGE_NONE:
459 # Be a little more permissive for usepkg, the binaries may not exist.
460 packages.append('%s%s-%s' % ('<=' if usepkg else '=', pkg, ver))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100461
462 if not packages:
463 print 'Nothing to update!'
464 return
465
466 print 'Updating packages:'
467 print packages
468
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100469 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100470 if usepkg:
471 cmd.extend(['--getbinpkg', '--usepkgonly'])
472
473 cmd.extend(packages)
474 cros_build_lib.RunCommand(cmd)
475
476
477def CleanTargets(targets):
478 """Unmerges old packages that are assumed unnecessary."""
479 unmergemap = {}
480 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100481 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100482 if IsPackageDisabled(target, package):
483 continue
484 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100485 current = GetInstalledPackageVersions(target, package)
486 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200487 desired_num = VersionListToNumeric(target, package, desired, True)
488 if not set(desired_num).issubset(current):
489 print 'Some packages have been held back, skipping clean!'
490 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100491 unmergemap[pkg] = set(current).difference(desired_num)
492
493 # Cleaning doesn't care about consistency and rebuilding package.* files.
494 packages = []
495 for pkg, vers in unmergemap.iteritems():
496 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
497
498 if packages:
499 print 'Cleaning packages:'
500 print packages
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100501 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502 cmd.extend(packages)
503 cros_build_lib.RunCommand(cmd)
504 else:
505 print 'Nothing to clean!'
506
507
508def SelectActiveToolchains(targets, suffixes):
509 """Runs gcc-config and binutils-config to select the desired.
510
511 args:
512 targets - the targets to select
513 """
514 for package in ['gcc', 'binutils']:
515 for target in targets:
516 # Pick the first version in the numbered list as the selected one.
517 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200518 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519 desired = desired_num[0]
520 # *-config does not play revisions, strip them, keep just PV.
521 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
522
523 if target == 'host':
524 # *-config is the only tool treating host identically (by tuple).
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100525 target = GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100526
527 # And finally, attach target to it.
528 desired = '%s-%s' % (target, desired)
529
530 # Target specific hacks
531 if package in suffixes:
532 if target in suffixes[package]:
533 desired += suffixes[package][target]
534
535 cmd = [ package + '-config', '-c', target ]
536 current = cros_build_lib.RunCommand(cmd, print_cmd=False,
Zdenek Behan699ddd32012-04-13 07:14:08 +0200537 redirect_stdout=True).output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 # Do not gcc-config when the current is live or nothing needs to be done.
539 if current != desired and current != '9999':
540 cmd = [ package + '-config', desired ]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100541 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542
543
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100544def UpdateToolchains(usepkg, deleteold, hostonly, targets_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100545 """Performs all steps to create a synchronized toolchain enviroment.
546
547 args:
548 arguments correspond to the given commandline flags
549 """
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100550 targets = set()
551 if not hostonly:
552 # For hostonly, we can skip most of the below logic, much of which won't
553 # work on bare systems where this is useful.
554 alltargets = GetAllTargets()
555 nonexistant = []
556 if targets_wanted == set(['all']):
557 targets = set(alltargets)
558 else:
559 targets = set(targets_wanted)
560 # Verify user input.
561 for target in targets_wanted:
562 if target not in alltargets:
563 nonexistant.append(target)
564 if nonexistant:
565 raise Exception("Invalid targets: " + ','.join(nonexistant))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100566
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100567 # First check and initialize all cross targets that need to be.
568 crossdev_targets = \
569 [t for t in targets if not TargetIsInitialized(t)]
570 if crossdev_targets:
571 InitializeCrossdevTargets(crossdev_targets, usepkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100572
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100573 # We want host updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100574 targets.add('host')
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100575
576 # Now update all packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100577 UpdateTargets(targets, usepkg)
578 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
579
580 if deleteold:
581 CleanTargets(targets)
582
583
Brian Harring30675052012-02-29 12:18:22 -0800584def main(argv):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100585 usage = """usage: %prog [options]
586
587 The script installs and updates the toolchains in your chroot.
588 """
589 parser = optparse.OptionParser(usage)
590 parser.add_option('-u', '--nousepkg',
591 action='store_false', dest='usepkg', default=True,
592 help=('Use prebuilt packages if possible.'))
593 parser.add_option('-d', '--deleteold',
594 action='store_true', dest='deleteold', default=False,
595 help=('Unmerge deprecated packages.'))
596 parser.add_option('-t', '--targets',
597 dest='targets', default='all',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100598 help=('Comma separated list of tuples. '
599 'Special keyword \'host\' is allowed. Default: all.'))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100600 parser.add_option('', '--hostonly',
601 dest='hostonly', default=False, action='store_true',
602 help=('Only setup the host toolchain. '
603 'Useful for bootstrapping chroot.'))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100604
Brian Harring30675052012-02-29 12:18:22 -0800605 (options, _remaining_arguments) = parser.parse_args(argv)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100606
Mike Frysingerb9a28fe2012-03-21 11:35:42 -0400607 # This has to be always ran as root.
608 if not os.getuid() == 0:
609 print "%s: This script must be run as root!" % sys.argv[0]
610 sys.exit(1)
611
Zdenek Behan508dcce2011-12-05 15:39:32 +0100612 targets = set(options.targets.split(','))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100613 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly, targets)