blob: 6fcb35d93d793ef1ce05009ad9d369b09cd90767 [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 Behan4eb6fd22012-03-12 17:00:56 +010027EMERGE_CMD = os.path.join(os.path.dirname(__file__),
28 '../bin', 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010029PACKAGE_STABLE = '[stable]'
30PACKAGE_NONE = '[none]'
31SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010032
33CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
34STABLE_OVERLAY = '/usr/local/portage/stable'
35CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010036
37
38# TODO: The versions are stored here very much like in setup_board.
39# The goal for future is to differentiate these using a config file.
40# This is done essentially by messing with GetDesiredPackageVersions()
41DEFAULT_VERSION = PACKAGE_STABLE
42DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010043 'binutils' : '2.21-r4',
44}
45TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010046 'host' : {
47 'binutils' : '2.21.1',
48 'gdb' : PACKAGE_NONE,
49 },
50}
51# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
52CONFIG_TARGET_SUFFIXES = {
53 'binutils' : {
54 'i686-pc-linux-gnu' : '-gold',
55 'x86_64-cros-linux-gnu' : '-gold',
56 },
57}
Zdenek Behan508dcce2011-12-05 15:39:32 +010058# Global per-run cache that will be filled ondemand in by GetPackageMap()
59# function as needed.
60target_version_map = {
61}
62
63
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010064# Global variable cache. It has to be a descendant of 'object', rather than
65# instance thereof, because attributes cannot be set on 'object' instances.
66class VariableCache(object):
67 pass
68VAR_CACHE = VariableCache()
69
70
Zdenek Behan508dcce2011-12-05 15:39:32 +010071def GetPackageMap(target):
72 """Compiles a package map for the given target from the constants.
73
74 Uses a cache in target_version_map, that is dynamically filled in as needed,
75 since here everything is static data and the structuring is for ease of
76 configurability only.
77
78 args:
79 target - the target for which to return a version map
80
81 returns a map between packages and desired versions in internal format
82 (using the PACKAGE_* constants)
83 """
84 if target in target_version_map:
85 return target_version_map[target]
86
87 # Start from copy of the global defaults.
88 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
89
Zdenek Behanf4d18a02012-03-22 15:45:05 +010090 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +010091 # prefer any specific overrides
92 if pkg in TARGET_VERSION_MAP.get(target, {}):
93 result[pkg] = TARGET_VERSION_MAP[target][pkg]
94 else:
95 # finally, if not already set, set a sane default
96 result.setdefault(pkg, DEFAULT_VERSION)
97 target_version_map[target] = result
98 return result
99
100
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100101def GetHostTuple():
102 """Returns compiler tuple for the host system.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100103
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100104 Caches the result, because the command can be fairly expensive, and never
105 changes throughout a single run.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100106 """
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100107 CACHE_ATTR = '_host_tuple'
Zdenek Behan508dcce2011-12-05 15:39:32 +0100108
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100109 val = getattr(VAR_CACHE, CACHE_ATTR, None)
110 if val is None:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100111 val = portage.settings['CHOST']
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100112 setattr(VAR_CACHE, CACHE_ATTR, val)
113 return val
114
115
116def GetCrossdevConf(target):
117 """Returns a map of crossdev provided variables about a tuple."""
118 CACHE_ATTR = '_target_tuple_map'
119
120 val = getattr(VAR_CACHE, CACHE_ATTR, {})
121 if not target in val:
122 # Find out the crossdev tuple.
123 target_tuple = target
124 if target == 'host':
125 target_tuple = GetHostTuple()
126 # Catch output of crossdev.
127 out = cros_build_lib.RunCommand(['crossdev', '--show-target-cfg',
128 '--ex-gdb', target_tuple],
129 print_cmd=False, redirect_stdout=True).output.splitlines()
130 # List of tuples split at the first '=', converted into dict.
131 val[target] = dict([x.split('=', 1) for x in out])
132 setattr(VAR_CACHE, CACHE_ATTR, {})
133 return val[target]
134
135
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100136def GetTargetPackages(target):
137 """Returns a list of packages for a given target."""
138 conf = GetCrossdevConf(target)
139 # Undesired packages are denoted by empty ${pkg}_pn variable.
140 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
141
142
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100143# Portage helper functions:
144def GetPortagePackage(target, package):
145 """Returns a package name for the given target."""
146 conf = GetCrossdevConf(target)
147 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100148 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100149 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100150 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100151 category = conf['category']
152 # Portage package:
153 pn = conf[package + '_pn']
154 # Final package name:
155 assert(category)
156 assert(pn)
157 return '%s/%s' % (category, pn)
158
159
160def GetPortageKeyword(target):
161 """Returns a portage friendly keyword for a given target."""
162 return GetCrossdevConf(target)['arch']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100163
164
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100165def IsPackageDisabled(target, package):
166 """Returns if the given package is not used for the target."""
167 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
168
Zdenek Behan508dcce2011-12-05 15:39:32 +0100169# Tree interface functions. They help with retrieving data about the current
170# state of the tree:
171def GetAllTargets():
172 """Get the complete list of targets.
173
174 returns the list of cross targets for the current tree
175 """
176 cmd = ['cros_overlay_list', '--all_boards']
177 overlays = cros_build_lib.RunCommand(cmd, print_cmd=False,
178 redirect_stdout=True).output.splitlines()
179 targets = set()
180 for overlay in overlays:
181 config = os.path.join(overlay, 'toolchain.conf')
182 if os.path.exists(config):
183 with open(config) as config_file:
184 lines = config_file.read().splitlines()
185 for line in lines:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100186 line = line.split('#', 1)[0]
187 targets.update(line.split())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100188
189 # Remove the host target as that is not a cross-target. Replace with 'host'.
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100190 targets.discard(GetHostTuple())
Zdenek Behan508dcce2011-12-05 15:39:32 +0100191 return targets
192
193
194def GetInstalledPackageVersions(target, package):
195 """Extracts the list of current versions of a target, package pair.
196
197 args:
198 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
199
200 returns the list of versions of the package currently installed.
201 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100202 versions = []
203 # This is the package name in terms of portage.
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100204 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100205 for pkg in portage.db['/']['vartree'].dbapi.match(atom):
206 version = portage.versions.cpv_getversion(pkg)
207 versions.append(version)
208 return versions
209
210
Zdenek Behan508dcce2011-12-05 15:39:32 +0100211def GetStablePackageVersion(target, package):
212 """Extracts the current stable version for a given package.
213
214 args:
215 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
216
217 returns a string containing the latest version.
218 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100219 keyword = GetPortageKeyword(target)
220 extra_env = {'ACCEPT_KEYWORDS' : '-* ' + keyword}
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100221 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100222 cpv = cros_build_lib.RunCommand(['portageq', 'best_visible', '/', atom],
223 print_cmd=False, redirect_stdout=True,
224 extra_env=extra_env).output.splitlines()[0]
225 return portage.versions.cpv_getversion(cpv)
226
227
228def VersionListToNumeric(target, package, versions):
229 """Resolves keywords in a given version list for a particular package.
230
231 Resolving means replacing PACKAGE_STABLE with the actual number.
232
233 args:
234 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
235 versions - list of versions to resolve
236
237 returns list of purely numeric versions equivalent to argument
238 """
239 resolved = []
240 for version in versions:
241 if version == PACKAGE_STABLE:
242 resolved.append(GetStablePackageVersion(target, package))
243 elif version != PACKAGE_NONE:
244 resolved.append(version)
245 return resolved
246
247
248def GetDesiredPackageVersions(target, package):
249 """Produces the list of desired versions for each target, package pair.
250
251 The first version in the list is implicitly treated as primary, ie.
252 the version that will be initialized by crossdev and selected.
253
254 If the version is PACKAGE_STABLE, it really means the current version which
255 is emerged by using the package atom with no particular version key.
256 Since crossdev unmasks all packages by default, this will actually
257 mean 'unstable' in most cases.
258
259 args:
260 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
261
262 returns a list composed of either a version string, PACKAGE_STABLE
263 """
264 packagemap = GetPackageMap(target)
265
266 versions = []
267 if package in packagemap:
268 versions.append(packagemap[package])
269
270 return versions
271
272
273def TargetIsInitialized(target):
274 """Verifies if the given list of targets has been correctly initialized.
275
276 This determines whether we have to call crossdev while emerging
277 toolchain packages or can do it using emerge. Emerge is naturally
278 preferred, because all packages can be updated in a single pass.
279
280 args:
281 targets - list of individual cross targets which are checked
282
283 returns True if target is completely initialized
284 returns False otherwise
285 """
286 # Check if packages for the given target all have a proper version.
287 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100288 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100289 # Do we even want this package && is it initialized?
290 if not IsPackageDisabled(target, package) and \
291 not GetInstalledPackageVersions(target, package):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100292 return False
293 return True
294 except cros_build_lib.RunCommandError:
295 # Fails - The target has likely never been initialized before.
296 return False
297
298
299def RemovePackageMask(target):
300 """Removes a package.mask file for the given platform.
301
302 The pre-existing package.mask files can mess with the keywords.
303
304 args:
305 target - the target for which to remove the file
306 """
307 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100308 try:
309 os.unlink(maskfile)
310 except EnvironmentError as e:
311 if e.errno != errno.ENOENT:
312 raise
Zdenek Behan508dcce2011-12-05 15:39:32 +0100313
314
315def CreatePackageMask(target, masks):
316 """[Re]creates a package.mask file for the given platform.
317
318 args:
319 target - the given target on which to operate
320 masks - a map of package : version,
321 where version is the highest permissible version (mask >)
322 """
323 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
324 assert not os.path.exists(maskfile)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100325 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100326
327 with open(maskfile, 'w') as f:
328 for pkg, m in masks.items():
329 f.write('>%s-%s\n' % (pkg, m))
330
331
332def CreatePackageKeywords(target):
333 """[Re]create a package.keywords file for the platform.
334
335 This sets all package.keywords files to unmask all stable/testing packages.
336 TODO: Note that this approach should be deprecated and is only done for
337 compatibility reasons. In the future, we'd like to stop using keywords
338 altogether, and keep just stable unmasked.
339
340 args:
341 target - target for which to recreate package.keywords
342 """
343 maskfile = os.path.join('/etc/portage/package.keywords', 'cross-' + target)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100344 try:
345 os.unlink(maskfile)
346 except EnvironmentError as e:
347 if e.errno != errno.ENOENT:
348 raise
349 cros_build_lib.SafeMakedirs(os.path.dirname(maskfile))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100350
351 keyword = GetPortageKeyword(target)
352
353 with open(maskfile, 'w') as f:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100354 for pkg in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100355 if IsPackageDisabled(target, pkg):
356 continue
357 f.write('%s %s ~%s\n' %
358 (GetPortagePackage(target, pkg), keyword, keyword))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100359
360
361# Main functions performing the actual update steps.
362def InitializeCrossdevTargets(targets, usepkg):
363 """Calls crossdev to initialize a cross target.
364 args:
365 targets - the list of targets to initialize using crossdev
366 usepkg - copies the commandline opts
367 """
368 print 'The following targets need to be re-initialized:'
369 print targets
Zdenek Behan508dcce2011-12-05 15:39:32 +0100370
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100371 extra_env = { 'FEATURES' : 'splitdebug' }
Zdenek Behan508dcce2011-12-05 15:39:32 +0100372 for target in targets:
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100373 cmd = ['crossdev', '--show-fail-log',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100374 '-t', target]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100375 # Pick stable by default, and override as necessary.
376 cmd.extend(['-P', '--oneshot'])
377 if usepkg:
378 cmd.extend(['-P', '--getbinpkg',
379 '-P', '--usepkgonly',
380 '--without-headers'])
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100381
382 cmd.extend(['--overlays', '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)])
383 cmd.extend(['--ov-output', CROSSDEV_OVERLAY])
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100385 for pkg in GetTargetPackages(target):
386 if pkg == 'gdb':
387 # Gdb does not have selectable versions.
388 cmd.append('--ex-gdb')
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100389 continue
Zdenek Behan508dcce2011-12-05 15:39:32 +0100390 # The first of the desired versions is the "primary" one.
391 version = GetDesiredPackageVersions(target, pkg)[0]
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100392 cmd.extend(['--%s' % pkg, version])
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100393 cros_build_lib.RunCommand(cmd, extra_env=extra_env)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
395
396def UpdateTargets(targets, usepkg):
397 """Determines which packages need update/unmerge and defers to portage.
398
399 args:
400 targets - the list of targets to update
401 usepkg - copies the commandline option
402 """
403 # TODO(zbehan): This process is rather complex due to package.* handling.
404 # With some semantic changes over the original setup_board functionality,
405 # it can be considerably cleaned up.
406 mergemap = {}
407
408 # For each target, we do two things. Figure out the list of updates,
409 # and figure out the appropriate keywords/masks. Crossdev will initialize
410 # these, but they need to be regenerated on every update.
411 print 'Determining required toolchain updates...'
412 for target in targets:
413 # Record the highest needed version for each target, for masking purposes.
414 RemovePackageMask(target)
415 CreatePackageKeywords(target)
416 packagemasks = {}
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100417 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100418 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100419 if IsPackageDisabled(target, package):
420 continue
421 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100422 current = GetInstalledPackageVersions(target, package)
423 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100424 desired_num = VersionListToNumeric(target, package, desired)
425 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100426
427 # Pick the highest version for mask.
428 packagemasks[pkg] = portage.versions.best(desired_num)
429
430 CreatePackageMask(target, packagemasks)
431
432 packages = []
433 for pkg in mergemap:
434 for ver in mergemap[pkg]:
435 if ver == PACKAGE_STABLE:
436 packages.append(pkg)
437 elif ver != PACKAGE_NONE:
438 packages.append('=%s-%s' % (pkg, ver))
439
440 if not packages:
441 print 'Nothing to update!'
442 return
443
444 print 'Updating packages:'
445 print packages
446
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100447 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100448 if usepkg:
449 cmd.extend(['--getbinpkg', '--usepkgonly'])
450
451 cmd.extend(packages)
452 cros_build_lib.RunCommand(cmd)
453
454
455def CleanTargets(targets):
456 """Unmerges old packages that are assumed unnecessary."""
457 unmergemap = {}
458 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100459 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100460 if IsPackageDisabled(target, package):
461 continue
462 pkg = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100463 current = GetInstalledPackageVersions(target, package)
464 desired = GetDesiredPackageVersions(target, package)
465 desired_num = VersionListToNumeric(target, package, desired)
466 assert set(desired).issubset(set(desired))
467 unmergemap[pkg] = set(current).difference(desired_num)
468
469 # Cleaning doesn't care about consistency and rebuilding package.* files.
470 packages = []
471 for pkg, vers in unmergemap.iteritems():
472 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
473
474 if packages:
475 print 'Cleaning packages:'
476 print packages
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100477 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100478 cmd.extend(packages)
479 cros_build_lib.RunCommand(cmd)
480 else:
481 print 'Nothing to clean!'
482
483
484def SelectActiveToolchains(targets, suffixes):
485 """Runs gcc-config and binutils-config to select the desired.
486
487 args:
488 targets - the targets to select
489 """
490 for package in ['gcc', 'binutils']:
491 for target in targets:
492 # Pick the first version in the numbered list as the selected one.
493 desired = GetDesiredPackageVersions(target, package)
494 desired_num = VersionListToNumeric(target, package, desired)
495 desired = desired_num[0]
496 # *-config does not play revisions, strip them, keep just PV.
497 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
498
499 if target == 'host':
500 # *-config is the only tool treating host identically (by tuple).
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100501 target = GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100502
503 # And finally, attach target to it.
504 desired = '%s-%s' % (target, desired)
505
506 # Target specific hacks
507 if package in suffixes:
508 if target in suffixes[package]:
509 desired += suffixes[package][target]
510
511 cmd = [ package + '-config', '-c', target ]
512 current = cros_build_lib.RunCommand(cmd, print_cmd=False,
513 redirect_stdout=True).output.splitlines()[0]
514 # Do not gcc-config when the current is live or nothing needs to be done.
515 if current != desired and current != '9999':
516 cmd = [ package + '-config', desired ]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100517 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100518
519
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100520def UpdateToolchains(usepkg, deleteold, hostonly, targets_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100521 """Performs all steps to create a synchronized toolchain enviroment.
522
523 args:
524 arguments correspond to the given commandline flags
525 """
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100526 targets = set()
527 if not hostonly:
528 # For hostonly, we can skip most of the below logic, much of which won't
529 # work on bare systems where this is useful.
530 alltargets = GetAllTargets()
531 nonexistant = []
532 if targets_wanted == set(['all']):
533 targets = set(alltargets)
534 else:
535 targets = set(targets_wanted)
536 # Verify user input.
537 for target in targets_wanted:
538 if target not in alltargets:
539 nonexistant.append(target)
540 if nonexistant:
541 raise Exception("Invalid targets: " + ','.join(nonexistant))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100542
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100543 # First check and initialize all cross targets that need to be.
544 crossdev_targets = \
545 [t for t in targets if not TargetIsInitialized(t)]
546 if crossdev_targets:
547 InitializeCrossdevTargets(crossdev_targets, usepkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100548
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100549 # We want host updated.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550 targets.add('host')
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100551
552 # Now update all packages.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100553 UpdateTargets(targets, usepkg)
554 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
555
556 if deleteold:
557 CleanTargets(targets)
558
559
Brian Harring30675052012-02-29 12:18:22 -0800560def main(argv):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100561 usage = """usage: %prog [options]
562
563 The script installs and updates the toolchains in your chroot.
564 """
565 parser = optparse.OptionParser(usage)
566 parser.add_option('-u', '--nousepkg',
567 action='store_false', dest='usepkg', default=True,
568 help=('Use prebuilt packages if possible.'))
569 parser.add_option('-d', '--deleteold',
570 action='store_true', dest='deleteold', default=False,
571 help=('Unmerge deprecated packages.'))
572 parser.add_option('-t', '--targets',
573 dest='targets', default='all',
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100574 help=('Comma separated list of tuples. '
575 'Special keyword \'host\' is allowed. Default: all.'))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100576 parser.add_option('', '--hostonly',
577 dest='hostonly', default=False, action='store_true',
578 help=('Only setup the host toolchain. '
579 'Useful for bootstrapping chroot.'))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100580
Brian Harring30675052012-02-29 12:18:22 -0800581 (options, _remaining_arguments) = parser.parse_args(argv)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100582
Mike Frysingerb9a28fe2012-03-21 11:35:42 -0400583 # This has to be always ran as root.
584 if not os.getuid() == 0:
585 print "%s: This script must be run as root!" % sys.argv[0]
586 sys.exit(1)
587
Zdenek Behan508dcce2011-12-05 15:39:32 +0100588 targets = set(options.targets.split(','))
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100589 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly, targets)