blob: d426b7d1351411a3b19b32425546bd9150cb07d9 [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
7import copy
Mike Frysinger35247af2012-11-16 18:58:06 -05008import glob
Mike Frysinger7ccee992012-06-01 21:27:59 -04009import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010010import os
Zdenek Behan508dcce2011-12-05 15:39:32 +010011
Don Garrett88b8d782014-05-13 17:30:55 -070012from chromite.cbuildbot import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050013from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080014from chromite.lib import cros_build_lib
Brian Harringaf019fb2012-05-10 15:06:13 -070015from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050016from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080017from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050018
19# Needs to be after chromite imports.
20import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010021
Mike Frysinger31596002012-12-03 23:54:24 -050022if cros_build_lib.IsInsideChroot():
23 # Only import portage after we've checked that we're inside the chroot.
24 # Outside may not have portage, in which case the above may not happen.
25 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070026 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050027 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010028
29
Matt Tennantf1e30972012-03-02 16:30:07 -080030EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
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' : {
Zdenek Behan508dcce2011-12-05 15:39:32 +010048 '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
David James66a09c42012-11-05 13:31:38 -080064class Crossdev(object):
65 """Class for interacting with crossdev and caching its output."""
66
67 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
68 _CACHE = {}
69
70 @classmethod
71 def Load(cls, reconfig):
72 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080073 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
74 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080075 if os.path.exists(cls._CACHE_FILE) and not reconfig:
76 with open(cls._CACHE_FILE) as f:
77 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080078 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080079 cls._CACHE = data
80
81 @classmethod
82 def Save(cls):
83 """Store crossdev cache on disk."""
84 # Save the cache from the successful run.
85 with open(cls._CACHE_FILE, 'w') as f:
86 json.dump(cls._CACHE, f)
87
88 @classmethod
89 def GetConfig(cls, target):
90 """Returns a map of crossdev provided variables about a tuple."""
91 CACHE_ATTR = '_target_tuple_map'
92
93 val = cls._CACHE.setdefault(CACHE_ATTR, {})
94 if not target in val:
95 # Find out the crossdev tuple.
96 target_tuple = target
97 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -080098 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -080099 # Catch output of crossdev.
100 out = cros_build_lib.RunCommand(['crossdev', '--show-target-cfg',
101 '--ex-gdb', target_tuple],
102 print_cmd=False, redirect_stdout=True).output.splitlines()
103 # List of tuples split at the first '=', converted into dict.
104 val[target] = dict([x.split('=', 1) for x in out])
105 return val[target]
106
107 @classmethod
108 def UpdateTargets(cls, targets, usepkg, config_only=False):
109 """Calls crossdev to initialize a cross target.
110
111 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700112 targets: The list of targets to initialize using crossdev.
113 usepkg: Copies the commandline opts.
114 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800115 """
116 configured_targets = cls._CACHE.setdefault('configured_targets', [])
117
118 cmdbase = ['crossdev', '--show-fail-log']
119 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
120 # Pick stable by default, and override as necessary.
121 cmdbase.extend(['-P', '--oneshot'])
122 if usepkg:
123 cmdbase.extend(['-P', '--getbinpkg',
124 '-P', '--usepkgonly',
125 '--without-headers'])
126
127 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
128 cmdbase.extend(['--overlays', overlays])
129 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
130
131 for target in targets:
132 if config_only and target in configured_targets:
133 continue
134
135 cmd = cmdbase + ['-t', target]
136
137 for pkg in GetTargetPackages(target):
138 if pkg == 'gdb':
139 # Gdb does not have selectable versions.
140 cmd.append('--ex-gdb')
141 continue
142 # The first of the desired versions is the "primary" one.
143 version = GetDesiredPackageVersions(target, pkg)[0]
144 cmd.extend(['--%s' % pkg, version])
145
146 cmd.extend(targets[target]['crossdev'].split())
147 if config_only:
148 # In this case we want to just quietly reinit
149 cmd.append('--init-target')
150 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
151 else:
152 cros_build_lib.RunCommand(cmd)
153
154 configured_targets.append(target)
155
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100156
Zdenek Behan508dcce2011-12-05 15:39:32 +0100157def GetPackageMap(target):
158 """Compiles a package map for the given target from the constants.
159
160 Uses a cache in target_version_map, that is dynamically filled in as needed,
161 since here everything is static data and the structuring is for ease of
162 configurability only.
163
164 args:
165 target - the target for which to return a version map
166
167 returns a map between packages and desired versions in internal format
168 (using the PACKAGE_* constants)
169 """
170 if target in target_version_map:
171 return target_version_map[target]
172
173 # Start from copy of the global defaults.
174 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
175
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100176 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100177 # prefer any specific overrides
178 if pkg in TARGET_VERSION_MAP.get(target, {}):
179 result[pkg] = TARGET_VERSION_MAP[target][pkg]
180 else:
181 # finally, if not already set, set a sane default
182 result.setdefault(pkg, DEFAULT_VERSION)
183 target_version_map[target] = result
184 return result
185
186
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100187def GetTargetPackages(target):
188 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800189 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100190 # Undesired packages are denoted by empty ${pkg}_pn variable.
191 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
192
193
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100194# Portage helper functions:
195def GetPortagePackage(target, package):
196 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800197 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100198 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100199 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100200 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100201 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100202 category = conf['category']
203 # Portage package:
204 pn = conf[package + '_pn']
205 # Final package name:
206 assert(category)
207 assert(pn)
208 return '%s/%s' % (category, pn)
209
210
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100211def IsPackageDisabled(target, package):
212 """Returns if the given package is not used for the target."""
213 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
214
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100215
David James66a09c42012-11-05 13:31:38 -0800216def GetInstalledPackageVersions(atom):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100217 """Extracts the list of current versions of a target, package pair.
218
219 args:
David James66a09c42012-11-05 13:31:38 -0800220 atom - the atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100221
222 returns the list of versions of the package currently installed.
223 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100224 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500225 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800226 for pkg in portage.db['/']['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100227 version = portage.versions.cpv_getversion(pkg)
228 versions.append(version)
229 return versions
230
231
David James90239b92012-11-05 15:31:34 -0800232def GetStablePackageVersion(atom, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100233 """Extracts the current stable version for a given package.
234
235 args:
236 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
Zdenek Behan699ddd32012-04-13 07:14:08 +0200237 installed - Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100238
239 returns a string containing the latest version.
240 """
David James90239b92012-11-05 15:31:34 -0800241 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500242 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800243 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
244 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100245
246
Zdenek Behan699ddd32012-04-13 07:14:08 +0200247def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100248 """Resolves keywords in a given version list for a particular package.
249
250 Resolving means replacing PACKAGE_STABLE with the actual number.
251
252 args:
253 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
254 versions - list of versions to resolve
255
256 returns list of purely numeric versions equivalent to argument
257 """
258 resolved = []
David James90239b92012-11-05 15:31:34 -0800259 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100260 for version in versions:
261 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800262 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100263 elif version != PACKAGE_NONE:
264 resolved.append(version)
265 return resolved
266
267
268def GetDesiredPackageVersions(target, package):
269 """Produces the list of desired versions for each target, package pair.
270
271 The first version in the list is implicitly treated as primary, ie.
272 the version that will be initialized by crossdev and selected.
273
274 If the version is PACKAGE_STABLE, it really means the current version which
275 is emerged by using the package atom with no particular version key.
276 Since crossdev unmasks all packages by default, this will actually
277 mean 'unstable' in most cases.
278
279 args:
280 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
281
282 returns a list composed of either a version string, PACKAGE_STABLE
283 """
284 packagemap = GetPackageMap(target)
285
286 versions = []
287 if package in packagemap:
288 versions.append(packagemap[package])
289
290 return versions
291
292
293def TargetIsInitialized(target):
294 """Verifies if the given list of targets has been correctly initialized.
295
296 This determines whether we have to call crossdev while emerging
297 toolchain packages or can do it using emerge. Emerge is naturally
298 preferred, because all packages can be updated in a single pass.
299
300 args:
301 targets - list of individual cross targets which are checked
302
303 returns True if target is completely initialized
304 returns False otherwise
305 """
306 # Check if packages for the given target all have a proper version.
307 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100308 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800309 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100310 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800311 if not IsPackageDisabled(target, package) and not (
312 GetStablePackageVersion(atom, True) and
313 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314 return False
315 return True
316 except cros_build_lib.RunCommandError:
317 # Fails - The target has likely never been initialized before.
318 return False
319
320
321def RemovePackageMask(target):
322 """Removes a package.mask file for the given platform.
323
324 The pre-existing package.mask files can mess with the keywords.
325
326 args:
327 target - the target for which to remove the file
328 """
329 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700330 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100331
332
Zdenek Behan508dcce2011-12-05 15:39:32 +0100333# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500334def RebuildLibtool():
335 """Rebuild libtool as needed
336
337 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
338 gcc, libtool will break. We can't use binary packages either as those will
339 most likely be compiled against the previous version of gcc.
340 """
341 needs_update = False
342 with open('/usr/bin/libtool') as f:
343 for line in f:
344 # Look for a line like:
345 # sys_lib_search_path_spec="..."
346 # It'll be a list of paths and gcc will be one of them.
347 if line.startswith('sys_lib_search_path_spec='):
348 line = line.rstrip()
349 for path in line.split('=', 1)[1].strip('"').split():
350 if not os.path.exists(path):
351 print 'Rebuilding libtool after gcc upgrade'
352 print ' %s' % line
353 print ' missing path: %s' % path
354 needs_update = True
355 break
356
357 if needs_update:
358 break
359
360 if needs_update:
361 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
362 cros_build_lib.RunCommand(cmd)
363
364
Zdenek Behan508dcce2011-12-05 15:39:32 +0100365def UpdateTargets(targets, usepkg):
366 """Determines which packages need update/unmerge and defers to portage.
367
368 args:
369 targets - the list of targets to update
370 usepkg - copies the commandline option
371 """
David James90239b92012-11-05 15:31:34 -0800372 # Remove keyword files created by old versions of cros_setup_toolchains.
373 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100374
375 # For each target, we do two things. Figure out the list of updates,
376 # and figure out the appropriate keywords/masks. Crossdev will initialize
377 # these, but they need to be regenerated on every update.
378 print 'Determining required toolchain updates...'
David James90239b92012-11-05 15:31:34 -0800379 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100380 for target in targets:
381 # Record the highest needed version for each target, for masking purposes.
382 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100383 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100384 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100385 if IsPackageDisabled(target, package):
386 continue
387 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800388 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100389 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200390 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100391 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392
Zdenek Behan508dcce2011-12-05 15:39:32 +0100393 packages = []
394 for pkg in mergemap:
395 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200396 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800397 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100398
399 if not packages:
400 print 'Nothing to update!'
David Jamesf8c672f2012-11-06 13:38:11 -0800401 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100402
403 print 'Updating packages:'
404 print packages
405
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100406 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407 if usepkg:
408 cmd.extend(['--getbinpkg', '--usepkgonly'])
409
410 cmd.extend(packages)
411 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800412 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100413
414
415def CleanTargets(targets):
416 """Unmerges old packages that are assumed unnecessary."""
417 unmergemap = {}
418 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100419 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100420 if IsPackageDisabled(target, package):
421 continue
422 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800423 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200425 desired_num = VersionListToNumeric(target, package, desired, True)
426 if not set(desired_num).issubset(current):
427 print 'Some packages have been held back, skipping clean!'
428 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100429 unmergemap[pkg] = set(current).difference(desired_num)
430
431 # Cleaning doesn't care about consistency and rebuilding package.* files.
432 packages = []
433 for pkg, vers in unmergemap.iteritems():
434 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
435
436 if packages:
437 print 'Cleaning packages:'
438 print packages
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100439 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100440 cmd.extend(packages)
441 cros_build_lib.RunCommand(cmd)
442 else:
443 print 'Nothing to clean!'
444
445
446def SelectActiveToolchains(targets, suffixes):
447 """Runs gcc-config and binutils-config to select the desired.
448
449 args:
450 targets - the targets to select
451 """
452 for package in ['gcc', 'binutils']:
453 for target in targets:
454 # Pick the first version in the numbered list as the selected one.
455 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200456 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100457 desired = desired_num[0]
458 # *-config does not play revisions, strip them, keep just PV.
459 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
460
461 if target == 'host':
462 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800463 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100464
465 # And finally, attach target to it.
466 desired = '%s-%s' % (target, desired)
467
468 # Target specific hacks
469 if package in suffixes:
470 if target in suffixes[package]:
471 desired += suffixes[package][target]
472
David James7ec5efc2012-11-06 09:39:49 -0800473 extra_env = {'CHOST': target}
474 cmd = ['%s-config' % package, '-c', target]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100475 current = cros_build_lib.RunCommand(cmd, print_cmd=False,
David James7ec5efc2012-11-06 09:39:49 -0800476 redirect_stdout=True, extra_env=extra_env).output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477 # Do not gcc-config when the current is live or nothing needs to be done.
478 if current != desired and current != '9999':
479 cmd = [ package + '-config', desired ]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100480 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100481
482
Mike Frysinger35247af2012-11-16 18:58:06 -0500483def ExpandTargets(targets_wanted):
484 """Expand any possible toolchain aliases into full targets
485
486 This will expand 'all' and 'sdk' into the respective toolchain tuples.
487
488 Args:
489 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500490
Mike Frysinger35247af2012-11-16 18:58:06 -0500491 Returns:
492 Full list of tuples with pseudo targets removed.
493 """
David James27ac4ae2012-12-03 23:16:15 -0800494 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500495 targets_wanted = set(targets_wanted)
496 if targets_wanted == set(['all']):
497 targets = alltargets
498 elif targets_wanted == set(['sdk']):
499 # Filter out all the non-sdk toolchains as we don't want to mess
500 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800501 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysinger35247af2012-11-16 18:58:06 -0500502 else:
503 # Verify user input.
504 nonexistent = targets_wanted.difference(alltargets)
505 if nonexistent:
506 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
507 targets = dict((t, alltargets[t]) for t in targets_wanted)
508 return targets
509
510
David Jamesf8c672f2012-11-06 13:38:11 -0800511def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
512 targets_wanted, boards_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100513 """Performs all steps to create a synchronized toolchain enviroment.
514
515 args:
516 arguments correspond to the given commandline flags
517 """
David Jamesf8c672f2012-11-06 13:38:11 -0800518 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100519 if not hostonly:
520 # For hostonly, we can skip most of the below logic, much of which won't
521 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500522 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400523
Mike Frysinger7ccee992012-06-01 21:27:59 -0400524 # Now re-add any targets that might be from this board. This is
525 # to allow unofficial boards to declare their own toolchains.
526 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800527 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100528
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100529 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400530 for target in targets:
531 if TargetIsInitialized(target):
532 reconfig_targets[target] = targets[target]
533 else:
534 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100535 if crossdev_targets:
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200536 print 'The following targets need to be re-initialized:'
537 print crossdev_targets
David James66a09c42012-11-05 13:31:38 -0800538 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200539 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800540 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100541
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100542 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400543 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100544
545 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800546 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
547 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800548
549 if deleteold:
550 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100551
Mike Frysingerc880a962013-11-08 13:59:06 -0500552 # Now that we've cleared out old versions, see if we need to rebuild
553 # anything. Can't do this earlier as it might not be broken.
554 RebuildLibtool()
555
Zdenek Behan508dcce2011-12-05 15:39:32 +0100556
Mike Frysinger35247af2012-11-16 18:58:06 -0500557def ShowBoardConfig(board):
558 """Show the toolchain tuples used by |board|
559
560 Args:
561 board: The board to query.
562 """
David James27ac4ae2012-12-03 23:16:15 -0800563 toolchains = toolchain.GetToolchainsForBoard(board)
Mike Frysinger35247af2012-11-16 18:58:06 -0500564 # Make sure we display the default toolchain first.
David James27ac4ae2012-12-03 23:16:15 -0800565 print ','.join(
566 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
567 toolchain.FilterToolchains(toolchains, 'default', False).keys())
Mike Frysinger35247af2012-11-16 18:58:06 -0500568
569
Mike Frysinger35247af2012-11-16 18:58:06 -0500570def GeneratePathWrapper(root, wrappath, path):
571 """Generate a shell script to execute another shell script
572
573 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
574 argv[0] won't be pointing to the correct path, generate a shell script that
575 just executes another program with its full path.
576
577 Args:
578 root: The root tree to generate scripts inside of
579 wrappath: The full path (inside |root|) to create the wrapper
580 path: The target program which this wrapper will execute
581 """
582 replacements = {
583 'path': path,
584 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
585 }
586 wrapper = """#!/bin/sh
587base=$(realpath "$0")
588basedir=${base%%/*}
589exec "${basedir}/%(relroot)s%(path)s" "$@"
590""" % replacements
591 root_wrapper = root + wrappath
592 if os.path.islink(root_wrapper):
593 os.unlink(root_wrapper)
594 else:
595 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
596 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400597 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500598
599
600def FileIsCrosSdkElf(elf):
601 """Determine if |elf| is an ELF that we execute in the cros_sdk
602
603 We don't need this to be perfect, just quick. It makes sure the ELF
604 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
605
606 Args:
607 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500608
Mike Frysinger35247af2012-11-16 18:58:06 -0500609 Returns:
610 True if we think |elf| is a native ELF
611 """
612 with open(elf) as f:
613 data = f.read(20)
614 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
615 return (data[0:4] == '\x7fELF' and
616 data[4] == '\x02' and
617 data[5] == '\x01' and
618 data[18] == '\x3e')
619
620
621def IsPathPackagable(ptype, path):
622 """Should the specified file be included in a toolchain package?
623
624 We only need to handle files as we'll create dirs as we need them.
625
626 Further, trim files that won't be useful:
627 - non-english translations (.mo) since it'd require env vars
628 - debug files since these are for the host compiler itself
629 - info/man pages as they're big, and docs are online, and the
630 native docs should work fine for the most part (`man gcc`)
631
632 Args:
633 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
634 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500635
Mike Frysinger35247af2012-11-16 18:58:06 -0500636 Returns:
637 True if we want to include this path in the package
638 """
639 return not (ptype in ('dir',) or
640 path.startswith('/usr/lib/debug/') or
641 os.path.splitext(path)[1] == '.mo' or
642 ('/man/' in path or '/info/' in path))
643
644
645def ReadlinkRoot(path, root):
646 """Like os.readlink(), but relative to a |root|
647
648 Args:
649 path: The symlink to read
650 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500651
Mike Frysinger35247af2012-11-16 18:58:06 -0500652 Returns:
653 A fully resolved symlink path
654 """
655 while os.path.islink(root + path):
656 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
657 return path
658
659
660def _GetFilesForTarget(target, root='/'):
661 """Locate all the files to package for |target|
662
663 This does not cover ELF dependencies.
664
665 Args:
666 target: The toolchain target name
667 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500668
Mike Frysinger35247af2012-11-16 18:58:06 -0500669 Returns:
670 A tuple of a set of all packable paths, and a set of all paths which
671 are also native ELFs
672 """
673 paths = set()
674 elfs = set()
675
676 # Find all the files owned by the packages for this target.
677 for pkg in GetTargetPackages(target):
678 # Ignore packages that are part of the target sysroot.
679 if pkg in ('kernel', 'libc'):
680 continue
681
682 atom = GetPortagePackage(target, pkg)
683 cat, pn = atom.split('/')
684 ver = GetInstalledPackageVersions(atom)[0]
685 cros_build_lib.Info('packaging %s-%s', atom, ver)
686
687 # pylint: disable=E1101
688 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
689 settings=portage.settings)
690 contents = dblink.getcontents()
691 for obj in contents:
692 ptype = contents[obj][0]
693 if not IsPathPackagable(ptype, obj):
694 continue
695
696 if ptype == 'obj':
697 # For native ELFs, we need to pull in their dependencies too.
698 if FileIsCrosSdkElf(obj):
699 elfs.add(obj)
700 paths.add(obj)
701
702 return paths, elfs
703
704
705def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
706 path_rewrite_func=lambda x:x, root='/'):
707 """Link in all packable files and their runtime dependencies
708
709 This also wraps up executable ELFs with helper scripts.
710
711 Args:
712 output_dir: The output directory to store files
713 paths: All the files to include
714 elfs: All the files which are ELFs (a subset of |paths|)
715 ldpaths: A dict of static ldpath information
716 path_rewrite_func: User callback to rewrite paths in output_dir
717 root: The root path to pull all packages/files from
718 """
719 # Link in all the files.
720 sym_paths = []
721 for path in paths:
722 new_path = path_rewrite_func(path)
723 dst = output_dir + new_path
724 osutils.SafeMakedirs(os.path.dirname(dst))
725
726 # Is this a symlink which we have to rewrite or wrap?
727 # Delay wrap check until after we have created all paths.
728 src = root + path
729 if os.path.islink(src):
730 tgt = os.readlink(src)
731 if os.path.sep in tgt:
732 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
733
734 # Rewrite absolute links to relative and then generate the symlink
735 # ourselves. All other symlinks can be hardlinked below.
736 if tgt[0] == '/':
737 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
738 os.symlink(tgt, dst)
739 continue
740
741 os.link(src, dst)
742
743 # Now see if any of the symlinks need to be wrapped.
744 for sym, tgt in sym_paths:
745 if tgt in elfs:
746 GeneratePathWrapper(output_dir, sym, tgt)
747
748 # Locate all the dependencies for all the ELFs. Stick them all in the
749 # top level "lib" dir to make the wrapper simpler. This exact path does
750 # not matter since we execute ldso directly, and we tell the ldso the
751 # exact path to search for its libraries.
752 libdir = os.path.join(output_dir, 'lib')
753 osutils.SafeMakedirs(libdir)
754 donelibs = set()
755 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400756 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500757 interp = e['interp']
758 if interp:
759 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400760 interp = os.path.join('/lib', os.path.basename(interp))
761 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
762 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500763
764 for lib, lib_data in e['libs'].iteritems():
765 if lib in donelibs:
766 continue
767
768 src = path = lib_data['path']
769 if path is None:
770 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
771 continue
772 donelibs.add(lib)
773
774 # Needed libs are the SONAME, but that is usually a symlink, not a
775 # real file. So link in the target rather than the symlink itself.
776 # We have to walk all the possible symlinks (SONAME could point to a
777 # symlink which points to a symlink), and we have to handle absolute
778 # ourselves (since we have a "root" argument).
779 dst = os.path.join(libdir, os.path.basename(path))
780 src = ReadlinkRoot(src, root)
781
782 os.link(root + src, dst)
783
784
785def _EnvdGetVar(envd, var):
786 """Given a Gentoo env.d file, extract a var from it
787
788 Args:
789 envd: The env.d file to load (may be a glob path)
790 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500791
Mike Frysinger35247af2012-11-16 18:58:06 -0500792 Returns:
793 The value of |var|
794 """
795 envds = glob.glob(envd)
796 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
797 envd = envds[0]
798 return cros_build_lib.LoadKeyValueFile(envd)[var]
799
800
801def _ProcessBinutilsConfig(target, output_dir):
802 """Do what binutils-config would have done"""
803 binpath = os.path.join('/bin', target + '-')
David James27ac4ae2012-12-03 23:16:15 -0800804 globpath = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(), target,
Mike Frysinger35247af2012-11-16 18:58:06 -0500805 'binutils-bin', '*-gold')
806 srcpath = glob.glob(globpath)
807 assert len(srcpath) == 1, '%s: did not match 1 path' % globpath
808 srcpath = srcpath[0][len(output_dir):]
809 gccpath = os.path.join('/usr', 'libexec', 'gcc')
810 for prog in os.listdir(output_dir + srcpath):
811 # Skip binaries already wrapped.
812 if not prog.endswith('.real'):
813 GeneratePathWrapper(output_dir, binpath + prog,
814 os.path.join(srcpath, prog))
815 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
816 os.path.join(srcpath, prog))
817
David James27ac4ae2012-12-03 23:16:15 -0800818 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysinger35247af2012-11-16 18:58:06 -0500819 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*-gold')
820 srcpath = _EnvdGetVar(envd, 'LIBPATH')
821 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
822 output_dir + libpath)
823
824
825def _ProcessGccConfig(target, output_dir):
826 """Do what gcc-config would have done"""
827 binpath = '/bin'
828 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
829 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
830 for prog in os.listdir(output_dir + srcpath):
831 # Skip binaries already wrapped.
832 if (not prog.endswith('.real') and
833 not prog.endswith('.elf') and
834 prog.startswith(target)):
835 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
836 os.path.join(srcpath, prog))
837 return srcpath
838
839
840def _ProcessSysrootWrapper(_target, output_dir, srcpath):
841 """Remove chroot-specific things from our sysroot wrapper"""
842 # Disable ccache since we know it won't work outside of chroot.
843 sysroot_wrapper = glob.glob(os.path.join(
844 output_dir + srcpath, 'sysroot_wrapper*'))[0]
845 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
846 for num in xrange(len(contents)):
847 if '@CCACHE_DEFAULT@' in contents[num]:
848 contents[num] = 'use_ccache = False'
849 break
850 # Can't update the wrapper in place since it's a hardlink to a file in /.
851 os.unlink(sysroot_wrapper)
852 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
Mike Frysinger60ec1012013-10-21 00:11:10 -0400853 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500854
855
856def _ProcessDistroCleanups(target, output_dir):
857 """Clean up the tree and remove all distro-specific requirements
858
859 Args:
860 target: The toolchain target name
861 output_dir: The output directory to clean up
862 """
863 _ProcessBinutilsConfig(target, output_dir)
864 gcc_path = _ProcessGccConfig(target, output_dir)
865 _ProcessSysrootWrapper(target, output_dir, gcc_path)
866
867 osutils.RmDir(os.path.join(output_dir, 'etc'))
868
869
870def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
871 """Setup a tree from the packages for the specified target
872
873 This populates a path with all the files from toolchain packages so that
874 a tarball can easily be generated from the result.
875
876 Args:
877 target: The target to create a packagable root from
878 output_dir: The output directory to place all the files
879 ldpaths: A dict of static ldpath information
880 root: The root path to pull all packages/files from
881 """
882 # Find all the files owned by the packages for this target.
883 paths, elfs = _GetFilesForTarget(target, root=root)
884
885 # Link in all the package's files, any ELF dependencies, and wrap any
886 # executable ELFs with helper scripts.
887 def MoveUsrBinToBin(path):
888 """Move /usr/bin to /bin so people can just use that toplevel dir"""
889 return path[4:] if path.startswith('/usr/bin/') else path
890 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
891 path_rewrite_func=MoveUsrBinToBin, root=root)
892
893 # The packages, when part of the normal distro, have helper scripts
894 # that setup paths and such. Since we are making this standalone, we
895 # need to preprocess all that ourselves.
896 _ProcessDistroCleanups(target, output_dir)
897
898
899def CreatePackages(targets_wanted, output_dir, root='/'):
900 """Create redistributable cross-compiler packages for the specified targets
901
902 This creates toolchain packages that should be usable in conjunction with
903 a downloaded sysroot (created elsewhere).
904
905 Tarballs (one per target) will be created in $PWD.
906
907 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700908 targets_wanted: The targets to package up.
909 output_dir: The directory to put the packages in.
910 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500911 """
912 osutils.SafeMakedirs(output_dir)
913 ldpaths = lddtree.LoadLdpaths(root)
914 targets = ExpandTargets(targets_wanted)
915
David James4bc13702013-03-26 08:08:04 -0700916 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500917 # We have to split the root generation from the compression stages. This is
918 # because we hardlink in all the files (to avoid overhead of reading/writing
919 # the copies multiple times). But tar gets angry if a file's hardlink count
920 # changes from when it starts reading a file to when it finishes.
921 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
922 for target in targets:
923 output_target_dir = os.path.join(tempdir, target)
924 queue.put([target, output_target_dir, ldpaths, root])
925
926 # Build the tarball.
927 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
928 for target in targets:
929 tar_file = os.path.join(output_dir, target + '.tar.xz')
930 queue.put([tar_file, os.path.join(tempdir, target)])
931
932
Brian Harring30675052012-02-29 12:18:22 -0800933def main(argv):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100934 usage = """usage: %prog [options]
935
Mike Frysinger506e75f2012-12-17 14:21:13 -0500936 The script installs and updates the toolchains in your chroot."""
937 parser = commandline.OptionParser(usage)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100938 parser.add_option('-u', '--nousepkg',
939 action='store_false', dest='usepkg', default=True,
Mike Frysinger506e75f2012-12-17 14:21:13 -0500940 help='Use prebuilt packages if possible')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100941 parser.add_option('-d', '--deleteold',
942 action='store_true', dest='deleteold', default=False,
Mike Frysinger506e75f2012-12-17 14:21:13 -0500943 help='Unmerge deprecated packages')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100944 parser.add_option('-t', '--targets',
Mike Frysingereaebb582012-06-19 13:04:53 -0400945 dest='targets', default='sdk',
Mike Frysinger506e75f2012-12-17 14:21:13 -0500946 help='Comma separated list of tuples. '
947 'Special keyword \'host\' is allowed. Default: sdk')
Mike Frysinger7ccee992012-06-01 21:27:59 -0400948 parser.add_option('--include-boards',
949 dest='include_boards', default='',
Mike Frysinger506e75f2012-12-17 14:21:13 -0500950 help='Comma separated list of boards whose toolchains we'
951 ' will always include. Default: none')
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100952 parser.add_option('--hostonly',
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100953 dest='hostonly', default=False, action='store_true',
Mike Frysinger506e75f2012-12-17 14:21:13 -0500954 help='Only setup the host toolchain. '
955 'Useful for bootstrapping chroot')
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100956 parser.add_option('--show-board-cfg',
957 dest='board_cfg', default=None,
Mike Frysinger506e75f2012-12-17 14:21:13 -0500958 help='Board to list toolchain tuples for')
Mike Frysinger35247af2012-11-16 18:58:06 -0500959 parser.add_option('--create-packages',
960 action='store_true', default=False,
961 help='Build redistributable packages')
962 parser.add_option('--output-dir', default=os.getcwd(), type='path',
963 help='Output directory')
David James66a09c42012-11-05 13:31:38 -0800964 parser.add_option('--reconfig', default=False, action='store_true',
Mike Frysinger506e75f2012-12-17 14:21:13 -0500965 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100966
Mike Frysinger35247af2012-11-16 18:58:06 -0500967 (options, remaining_arguments) = parser.parse_args(argv)
968 if len(remaining_arguments):
969 parser.error('script does not take arguments: %s' % remaining_arguments)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100970
Mike Frysinger35247af2012-11-16 18:58:06 -0500971 # Figure out what we're supposed to do and reject conflicting options.
972 if options.board_cfg and options.create_packages:
973 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -0400974
Zdenek Behan508dcce2011-12-05 15:39:32 +0100975 targets = set(options.targets.split(','))
Mike Frysinger7ccee992012-06-01 21:27:59 -0400976 boards = set(options.include_boards.split(',')) if options.include_boards \
977 else set()
Mike Frysinger35247af2012-11-16 18:58:06 -0500978
979 if options.board_cfg:
980 ShowBoardConfig(options.board_cfg)
981 elif options.create_packages:
982 cros_build_lib.AssertInsideChroot()
983 Crossdev.Load(False)
984 CreatePackages(targets, options.output_dir)
985 else:
986 cros_build_lib.AssertInsideChroot()
987 # This has to be always run as root.
988 if os.geteuid() != 0:
989 cros_build_lib.Die('this script must be run as root')
990
991 Crossdev.Load(options.reconfig)
992 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
993 options.reconfig, targets, boards)
994 Crossdev.Save()
995
996 return 0