blob: 9b8b1267d243786251f1155868a10102a11b5646 [file] [log] [blame]
Zdenek Behan508dcce2011-12-05 15:39:32 +01001# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Mike Frysinger750c5f52014-09-16 16:16:57 -04005"""This script manages the installed toolchains in the chroot."""
Zdenek Behan508dcce2011-12-05 15:39:32 +01006
Mike Frysinger383367e2014-09-16 15:06:17 -04007from __future__ import print_function
8
Zdenek Behan508dcce2011-12-05 15:39:32 +01009import copy
Mike Frysinger35247af2012-11-16 18:58:06 -050010import glob
Mike Frysinger7ccee992012-06-01 21:27:59 -040011import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010012import os
Zdenek Behan508dcce2011-12-05 15:39:32 +010013
Don Garrett88b8d782014-05-13 17:30:55 -070014from chromite.cbuildbot import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050015from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080016from chromite.lib import cros_build_lib
Brian Harringaf019fb2012-05-10 15:06:13 -070017from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050018from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080019from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050020
21# Needs to be after chromite imports.
22import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010023
Mike Frysinger31596002012-12-03 23:54:24 -050024if cros_build_lib.IsInsideChroot():
25 # Only import portage after we've checked that we're inside the chroot.
26 # Outside may not have portage, in which case the above may not happen.
27 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070028 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050029 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010030
31
Matt Tennantf1e30972012-03-02 16:30:07 -080032EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010033PACKAGE_STABLE = '[stable]'
34PACKAGE_NONE = '[none]'
35SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010036
37CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
38STABLE_OVERLAY = '/usr/local/portage/stable'
39CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010040
41
42# TODO: The versions are stored here very much like in setup_board.
43# The goal for future is to differentiate these using a config file.
44# This is done essentially by messing with GetDesiredPackageVersions()
45DEFAULT_VERSION = PACKAGE_STABLE
46DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010047}
48TARGET_VERSION_MAP = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050049 'host' : {
50 'gdb' : PACKAGE_NONE,
51 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010052}
53# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
54CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050055 'binutils' : {
56 'i686-pc-linux-gnu' : '-gold',
57 'x86_64-cros-linux-gnu' : '-gold',
58 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010059}
Zdenek Behan508dcce2011-12-05 15:39:32 +010060# Global per-run cache that will be filled ondemand in by GetPackageMap()
61# function as needed.
62target_version_map = {
63}
64
65
David James66a09c42012-11-05 13:31:38 -080066class Crossdev(object):
67 """Class for interacting with crossdev and caching its output."""
68
69 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
70 _CACHE = {}
71
72 @classmethod
73 def Load(cls, reconfig):
74 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080075 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
76 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080077 if os.path.exists(cls._CACHE_FILE) and not reconfig:
78 with open(cls._CACHE_FILE) as f:
79 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080080 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080081 cls._CACHE = data
82
83 @classmethod
84 def Save(cls):
85 """Store crossdev cache on disk."""
86 # Save the cache from the successful run.
87 with open(cls._CACHE_FILE, 'w') as f:
88 json.dump(cls._CACHE, f)
89
90 @classmethod
91 def GetConfig(cls, target):
92 """Returns a map of crossdev provided variables about a tuple."""
93 CACHE_ATTR = '_target_tuple_map'
94
95 val = cls._CACHE.setdefault(CACHE_ATTR, {})
96 if not target in val:
97 # Find out the crossdev tuple.
98 target_tuple = target
99 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800100 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -0800101 # Catch output of crossdev.
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500102 out = cros_build_lib.RunCommand(
103 ['crossdev', '--show-target-cfg', '--ex-gdb', target_tuple],
104 print_cmd=False, redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800105 # List of tuples split at the first '=', converted into dict.
106 val[target] = dict([x.split('=', 1) for x in out])
107 return val[target]
108
109 @classmethod
110 def UpdateTargets(cls, targets, usepkg, config_only=False):
111 """Calls crossdev to initialize a cross target.
112
113 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700114 targets: The list of targets to initialize using crossdev.
115 usepkg: Copies the commandline opts.
116 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800117 """
118 configured_targets = cls._CACHE.setdefault('configured_targets', [])
119
120 cmdbase = ['crossdev', '--show-fail-log']
121 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
122 # Pick stable by default, and override as necessary.
123 cmdbase.extend(['-P', '--oneshot'])
124 if usepkg:
125 cmdbase.extend(['-P', '--getbinpkg',
126 '-P', '--usepkgonly',
127 '--without-headers'])
128
129 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
130 cmdbase.extend(['--overlays', overlays])
131 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
132
133 for target in targets:
134 if config_only and target in configured_targets:
135 continue
136
137 cmd = cmdbase + ['-t', target]
138
139 for pkg in GetTargetPackages(target):
140 if pkg == 'gdb':
141 # Gdb does not have selectable versions.
142 cmd.append('--ex-gdb')
143 continue
144 # The first of the desired versions is the "primary" one.
145 version = GetDesiredPackageVersions(target, pkg)[0]
146 cmd.extend(['--%s' % pkg, version])
147
148 cmd.extend(targets[target]['crossdev'].split())
149 if config_only:
150 # In this case we want to just quietly reinit
151 cmd.append('--init-target')
152 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
153 else:
154 cros_build_lib.RunCommand(cmd)
155
156 configured_targets.append(target)
157
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100158
Zdenek Behan508dcce2011-12-05 15:39:32 +0100159def GetPackageMap(target):
160 """Compiles a package map for the given target from the constants.
161
162 Uses a cache in target_version_map, that is dynamically filled in as needed,
163 since here everything is static data and the structuring is for ease of
164 configurability only.
165
166 args:
167 target - the target for which to return a version map
168
169 returns a map between packages and desired versions in internal format
170 (using the PACKAGE_* constants)
171 """
172 if target in target_version_map:
173 return target_version_map[target]
174
175 # Start from copy of the global defaults.
176 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
177
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100178 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100179 # prefer any specific overrides
180 if pkg in TARGET_VERSION_MAP.get(target, {}):
181 result[pkg] = TARGET_VERSION_MAP[target][pkg]
182 else:
183 # finally, if not already set, set a sane default
184 result.setdefault(pkg, DEFAULT_VERSION)
185 target_version_map[target] = result
186 return result
187
188
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100189def GetTargetPackages(target):
190 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800191 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100192 # Undesired packages are denoted by empty ${pkg}_pn variable.
193 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
194
195
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100196# Portage helper functions:
197def GetPortagePackage(target, package):
198 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800199 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100200 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100201 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100202 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100203 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100204 category = conf['category']
205 # Portage package:
206 pn = conf[package + '_pn']
207 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500208 assert category
209 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100210 return '%s/%s' % (category, pn)
211
212
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100213def IsPackageDisabled(target, package):
214 """Returns if the given package is not used for the target."""
215 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
216
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100217
David James66a09c42012-11-05 13:31:38 -0800218def GetInstalledPackageVersions(atom):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100219 """Extracts the list of current versions of a target, package pair.
220
221 args:
David James66a09c42012-11-05 13:31:38 -0800222 atom - the atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100223
224 returns the list of versions of the package currently installed.
225 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100226 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500227 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800228 for pkg in portage.db['/']['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100229 version = portage.versions.cpv_getversion(pkg)
230 versions.append(version)
231 return versions
232
233
David James90239b92012-11-05 15:31:34 -0800234def GetStablePackageVersion(atom, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100235 """Extracts the current stable version for a given package.
236
237 args:
238 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
Zdenek Behan699ddd32012-04-13 07:14:08 +0200239 installed - Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100240
241 returns a string containing the latest version.
242 """
David James90239b92012-11-05 15:31:34 -0800243 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500244 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800245 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
246 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100247
248
Zdenek Behan699ddd32012-04-13 07:14:08 +0200249def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100250 """Resolves keywords in a given version list for a particular package.
251
252 Resolving means replacing PACKAGE_STABLE with the actual number.
253
254 args:
255 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
256 versions - list of versions to resolve
257
258 returns list of purely numeric versions equivalent to argument
259 """
260 resolved = []
David James90239b92012-11-05 15:31:34 -0800261 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100262 for version in versions:
263 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800264 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100265 elif version != PACKAGE_NONE:
266 resolved.append(version)
267 return resolved
268
269
270def GetDesiredPackageVersions(target, package):
271 """Produces the list of desired versions for each target, package pair.
272
273 The first version in the list is implicitly treated as primary, ie.
274 the version that will be initialized by crossdev and selected.
275
276 If the version is PACKAGE_STABLE, it really means the current version which
277 is emerged by using the package atom with no particular version key.
278 Since crossdev unmasks all packages by default, this will actually
279 mean 'unstable' in most cases.
280
281 args:
282 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
283
284 returns a list composed of either a version string, PACKAGE_STABLE
285 """
286 packagemap = GetPackageMap(target)
287
288 versions = []
289 if package in packagemap:
290 versions.append(packagemap[package])
291
292 return versions
293
294
295def TargetIsInitialized(target):
296 """Verifies if the given list of targets has been correctly initialized.
297
298 This determines whether we have to call crossdev while emerging
299 toolchain packages or can do it using emerge. Emerge is naturally
300 preferred, because all packages can be updated in a single pass.
301
302 args:
303 targets - list of individual cross targets which are checked
304
305 returns True if target is completely initialized
306 returns False otherwise
307 """
308 # Check if packages for the given target all have a proper version.
309 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100310 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800311 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100312 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800313 if not IsPackageDisabled(target, package) and not (
314 GetStablePackageVersion(atom, True) and
315 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100316 return False
317 return True
318 except cros_build_lib.RunCommandError:
319 # Fails - The target has likely never been initialized before.
320 return False
321
322
323def RemovePackageMask(target):
324 """Removes a package.mask file for the given platform.
325
326 The pre-existing package.mask files can mess with the keywords.
327
328 args:
329 target - the target for which to remove the file
330 """
331 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700332 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100333
334
Zdenek Behan508dcce2011-12-05 15:39:32 +0100335# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500336def RebuildLibtool():
337 """Rebuild libtool as needed
338
339 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
340 gcc, libtool will break. We can't use binary packages either as those will
341 most likely be compiled against the previous version of gcc.
342 """
343 needs_update = False
344 with open('/usr/bin/libtool') as f:
345 for line in f:
346 # Look for a line like:
347 # sys_lib_search_path_spec="..."
348 # It'll be a list of paths and gcc will be one of them.
349 if line.startswith('sys_lib_search_path_spec='):
350 line = line.rstrip()
351 for path in line.split('=', 1)[1].strip('"').split():
352 if not os.path.exists(path):
Mike Frysinger383367e2014-09-16 15:06:17 -0400353 print('Rebuilding libtool after gcc upgrade')
354 print(' %s' % line)
355 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500356 needs_update = True
357 break
358
359 if needs_update:
360 break
361
362 if needs_update:
363 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
364 cros_build_lib.RunCommand(cmd)
365
366
Zdenek Behan508dcce2011-12-05 15:39:32 +0100367def UpdateTargets(targets, usepkg):
368 """Determines which packages need update/unmerge and defers to portage.
369
370 args:
371 targets - the list of targets to update
372 usepkg - copies the commandline option
373 """
David James90239b92012-11-05 15:31:34 -0800374 # Remove keyword files created by old versions of cros_setup_toolchains.
375 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376
377 # For each target, we do two things. Figure out the list of updates,
378 # and figure out the appropriate keywords/masks. Crossdev will initialize
379 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400380 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800381 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100382 for target in targets:
383 # Record the highest needed version for each target, for masking purposes.
384 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100385 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100386 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100387 if IsPackageDisabled(target, package):
388 continue
389 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800390 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100391 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200392 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100393 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394
Zdenek Behan508dcce2011-12-05 15:39:32 +0100395 packages = []
396 for pkg in mergemap:
397 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200398 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800399 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100400
401 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400402 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800403 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100404
Mike Frysinger383367e2014-09-16 15:06:17 -0400405 print('Updating packages:')
406 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100408 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100409 if usepkg:
410 cmd.extend(['--getbinpkg', '--usepkgonly'])
411
412 cmd.extend(packages)
413 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800414 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100415
416
417def CleanTargets(targets):
418 """Unmerges old packages that are assumed unnecessary."""
419 unmergemap = {}
420 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100421 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100422 if IsPackageDisabled(target, package):
423 continue
424 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800425 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100426 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200427 desired_num = VersionListToNumeric(target, package, desired, True)
428 if not set(desired_num).issubset(current):
Mike Frysinger383367e2014-09-16 15:06:17 -0400429 print('Some packages have been held back, skipping clean!')
Zdenek Behan699ddd32012-04-13 07:14:08 +0200430 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100431 unmergemap[pkg] = set(current).difference(desired_num)
432
433 # Cleaning doesn't care about consistency and rebuilding package.* files.
434 packages = []
435 for pkg, vers in unmergemap.iteritems():
436 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
437
438 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400439 print('Cleaning packages:')
440 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100441 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100442 cmd.extend(packages)
443 cros_build_lib.RunCommand(cmd)
444 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400445 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100446
447
448def SelectActiveToolchains(targets, suffixes):
449 """Runs gcc-config and binutils-config to select the desired.
450
451 args:
452 targets - the targets to select
453 """
454 for package in ['gcc', 'binutils']:
455 for target in targets:
456 # Pick the first version in the numbered list as the selected one.
457 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200458 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100459 desired = desired_num[0]
460 # *-config does not play revisions, strip them, keep just PV.
461 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
462
463 if target == 'host':
464 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800465 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100466
467 # And finally, attach target to it.
468 desired = '%s-%s' % (target, desired)
469
470 # Target specific hacks
471 if package in suffixes:
472 if target in suffixes[package]:
473 desired += suffixes[package][target]
474
David James7ec5efc2012-11-06 09:39:49 -0800475 extra_env = {'CHOST': target}
476 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500477 result = cros_build_lib.RunCommand(
478 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
479 current = result.output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480 # Do not gcc-config when the current is live or nothing needs to be done.
481 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500482 cmd = [package + '-config', desired]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100483 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100484
485
Mike Frysinger35247af2012-11-16 18:58:06 -0500486def ExpandTargets(targets_wanted):
487 """Expand any possible toolchain aliases into full targets
488
489 This will expand 'all' and 'sdk' into the respective toolchain tuples.
490
491 Args:
492 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500493
Mike Frysinger35247af2012-11-16 18:58:06 -0500494 Returns:
495 Full list of tuples with pseudo targets removed.
496 """
David James27ac4ae2012-12-03 23:16:15 -0800497 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500498 targets_wanted = set(targets_wanted)
499 if targets_wanted == set(['all']):
500 targets = alltargets
501 elif targets_wanted == set(['sdk']):
502 # Filter out all the non-sdk toolchains as we don't want to mess
503 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800504 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysingerda838af2014-11-05 12:36:48 -0500505 elif targets_wanted == set(['boards']):
506 # Only pull targets from the boards.
507 targets = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500508 else:
509 # Verify user input.
510 nonexistent = targets_wanted.difference(alltargets)
511 if nonexistent:
512 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
513 targets = dict((t, alltargets[t]) for t in targets_wanted)
514 return targets
515
516
David Jamesf8c672f2012-11-06 13:38:11 -0800517def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
518 targets_wanted, boards_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100519 """Performs all steps to create a synchronized toolchain enviroment.
520
521 args:
522 arguments correspond to the given commandline flags
523 """
David Jamesf8c672f2012-11-06 13:38:11 -0800524 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100525 if not hostonly:
526 # For hostonly, we can skip most of the below logic, much of which won't
527 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500528 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400529
Mike Frysinger7ccee992012-06-01 21:27:59 -0400530 # Now re-add any targets that might be from this board. This is
531 # to allow unofficial boards to declare their own toolchains.
532 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800533 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100534
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100535 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400536 for target in targets:
537 if TargetIsInitialized(target):
538 reconfig_targets[target] = targets[target]
539 else:
540 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100541 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400542 print('The following targets need to be re-initialized:')
543 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800544 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200545 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800546 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100547
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100548 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400549 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100550
551 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800552 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
553 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800554
555 if deleteold:
556 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100557
Mike Frysingerc880a962013-11-08 13:59:06 -0500558 # Now that we've cleared out old versions, see if we need to rebuild
559 # anything. Can't do this earlier as it might not be broken.
560 RebuildLibtool()
561
Zdenek Behan508dcce2011-12-05 15:39:32 +0100562
Mike Frysinger35247af2012-11-16 18:58:06 -0500563def ShowBoardConfig(board):
564 """Show the toolchain tuples used by |board|
565
566 Args:
567 board: The board to query.
568 """
David James27ac4ae2012-12-03 23:16:15 -0800569 toolchains = toolchain.GetToolchainsForBoard(board)
Mike Frysinger35247af2012-11-16 18:58:06 -0500570 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400571 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800572 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400573 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500574
575
Mike Frysinger35247af2012-11-16 18:58:06 -0500576def GeneratePathWrapper(root, wrappath, path):
577 """Generate a shell script to execute another shell script
578
579 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
580 argv[0] won't be pointing to the correct path, generate a shell script that
581 just executes another program with its full path.
582
583 Args:
584 root: The root tree to generate scripts inside of
585 wrappath: The full path (inside |root|) to create the wrapper
586 path: The target program which this wrapper will execute
587 """
588 replacements = {
589 'path': path,
590 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
591 }
592 wrapper = """#!/bin/sh
593base=$(realpath "$0")
594basedir=${base%%/*}
595exec "${basedir}/%(relroot)s%(path)s" "$@"
596""" % replacements
597 root_wrapper = root + wrappath
598 if os.path.islink(root_wrapper):
599 os.unlink(root_wrapper)
600 else:
601 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
602 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400603 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500604
605
606def FileIsCrosSdkElf(elf):
607 """Determine if |elf| is an ELF that we execute in the cros_sdk
608
609 We don't need this to be perfect, just quick. It makes sure the ELF
610 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
611
612 Args:
613 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500614
Mike Frysinger35247af2012-11-16 18:58:06 -0500615 Returns:
616 True if we think |elf| is a native ELF
617 """
618 with open(elf) as f:
619 data = f.read(20)
620 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
621 return (data[0:4] == '\x7fELF' and
622 data[4] == '\x02' and
623 data[5] == '\x01' and
624 data[18] == '\x3e')
625
626
627def IsPathPackagable(ptype, path):
628 """Should the specified file be included in a toolchain package?
629
630 We only need to handle files as we'll create dirs as we need them.
631
632 Further, trim files that won't be useful:
633 - non-english translations (.mo) since it'd require env vars
634 - debug files since these are for the host compiler itself
635 - info/man pages as they're big, and docs are online, and the
636 native docs should work fine for the most part (`man gcc`)
637
638 Args:
639 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
640 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500641
Mike Frysinger35247af2012-11-16 18:58:06 -0500642 Returns:
643 True if we want to include this path in the package
644 """
645 return not (ptype in ('dir',) or
646 path.startswith('/usr/lib/debug/') or
647 os.path.splitext(path)[1] == '.mo' or
648 ('/man/' in path or '/info/' in path))
649
650
651def ReadlinkRoot(path, root):
652 """Like os.readlink(), but relative to a |root|
653
654 Args:
655 path: The symlink to read
656 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500657
Mike Frysinger35247af2012-11-16 18:58:06 -0500658 Returns:
659 A fully resolved symlink path
660 """
661 while os.path.islink(root + path):
662 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
663 return path
664
665
666def _GetFilesForTarget(target, root='/'):
667 """Locate all the files to package for |target|
668
669 This does not cover ELF dependencies.
670
671 Args:
672 target: The toolchain target name
673 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500674
Mike Frysinger35247af2012-11-16 18:58:06 -0500675 Returns:
676 A tuple of a set of all packable paths, and a set of all paths which
677 are also native ELFs
678 """
679 paths = set()
680 elfs = set()
681
682 # Find all the files owned by the packages for this target.
683 for pkg in GetTargetPackages(target):
684 # Ignore packages that are part of the target sysroot.
685 if pkg in ('kernel', 'libc'):
686 continue
687
688 atom = GetPortagePackage(target, pkg)
689 cat, pn = atom.split('/')
690 ver = GetInstalledPackageVersions(atom)[0]
691 cros_build_lib.Info('packaging %s-%s', atom, ver)
692
693 # pylint: disable=E1101
694 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
695 settings=portage.settings)
696 contents = dblink.getcontents()
697 for obj in contents:
698 ptype = contents[obj][0]
699 if not IsPathPackagable(ptype, obj):
700 continue
701
702 if ptype == 'obj':
703 # For native ELFs, we need to pull in their dependencies too.
704 if FileIsCrosSdkElf(obj):
705 elfs.add(obj)
706 paths.add(obj)
707
708 return paths, elfs
709
710
711def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500712 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500713 """Link in all packable files and their runtime dependencies
714
715 This also wraps up executable ELFs with helper scripts.
716
717 Args:
718 output_dir: The output directory to store files
719 paths: All the files to include
720 elfs: All the files which are ELFs (a subset of |paths|)
721 ldpaths: A dict of static ldpath information
722 path_rewrite_func: User callback to rewrite paths in output_dir
723 root: The root path to pull all packages/files from
724 """
725 # Link in all the files.
726 sym_paths = []
727 for path in paths:
728 new_path = path_rewrite_func(path)
729 dst = output_dir + new_path
730 osutils.SafeMakedirs(os.path.dirname(dst))
731
732 # Is this a symlink which we have to rewrite or wrap?
733 # Delay wrap check until after we have created all paths.
734 src = root + path
735 if os.path.islink(src):
736 tgt = os.readlink(src)
737 if os.path.sep in tgt:
738 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
739
740 # Rewrite absolute links to relative and then generate the symlink
741 # ourselves. All other symlinks can be hardlinked below.
742 if tgt[0] == '/':
743 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
744 os.symlink(tgt, dst)
745 continue
746
747 os.link(src, dst)
748
749 # Now see if any of the symlinks need to be wrapped.
750 for sym, tgt in sym_paths:
751 if tgt in elfs:
752 GeneratePathWrapper(output_dir, sym, tgt)
753
754 # Locate all the dependencies for all the ELFs. Stick them all in the
755 # top level "lib" dir to make the wrapper simpler. This exact path does
756 # not matter since we execute ldso directly, and we tell the ldso the
757 # exact path to search for its libraries.
758 libdir = os.path.join(output_dir, 'lib')
759 osutils.SafeMakedirs(libdir)
760 donelibs = set()
761 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400762 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500763 interp = e['interp']
764 if interp:
765 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400766 interp = os.path.join('/lib', os.path.basename(interp))
767 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
768 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500769
770 for lib, lib_data in e['libs'].iteritems():
771 if lib in donelibs:
772 continue
773
774 src = path = lib_data['path']
775 if path is None:
776 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
777 continue
778 donelibs.add(lib)
779
780 # Needed libs are the SONAME, but that is usually a symlink, not a
781 # real file. So link in the target rather than the symlink itself.
782 # We have to walk all the possible symlinks (SONAME could point to a
783 # symlink which points to a symlink), and we have to handle absolute
784 # ourselves (since we have a "root" argument).
785 dst = os.path.join(libdir, os.path.basename(path))
786 src = ReadlinkRoot(src, root)
787
788 os.link(root + src, dst)
789
790
791def _EnvdGetVar(envd, var):
792 """Given a Gentoo env.d file, extract a var from it
793
794 Args:
795 envd: The env.d file to load (may be a glob path)
796 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500797
Mike Frysinger35247af2012-11-16 18:58:06 -0500798 Returns:
799 The value of |var|
800 """
801 envds = glob.glob(envd)
802 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
803 envd = envds[0]
804 return cros_build_lib.LoadKeyValueFile(envd)[var]
805
806
807def _ProcessBinutilsConfig(target, output_dir):
808 """Do what binutils-config would have done"""
809 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500810
811 # Locate the bin dir holding the gold linker.
812 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
813 target, 'binutils-bin')
814 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500815 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500816 if not srcpath:
817 # Maybe this target doesn't support gold.
818 globpath = os.path.join(binutils_bin_path, '*')
819 srcpath = glob.glob(globpath)
820 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
821 % globpath)
822 srcpath = srcpath[0]
823 ld_path = os.path.join(srcpath, 'ld')
824 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
825 ld_path = os.path.join(srcpath, 'ld.bfd')
826 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
827 ld_path = os.path.join(srcpath, 'ld.gold')
828 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
829 % ld_path)
830
831 # Nope, no gold support to be found.
832 gold_supported = False
833 cros_build_lib.Warning('%s: binutils lacks support for the gold linker',
834 target)
835 else:
836 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
837 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -0500838 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500839
Mike Frysinger78b7a812014-11-26 19:45:23 -0500840 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -0500841 gccpath = os.path.join('/usr', 'libexec', 'gcc')
842 for prog in os.listdir(output_dir + srcpath):
843 # Skip binaries already wrapped.
844 if not prog.endswith('.real'):
845 GeneratePathWrapper(output_dir, binpath + prog,
846 os.path.join(srcpath, prog))
847 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
848 os.path.join(srcpath, prog))
849
David James27ac4ae2012-12-03 23:16:15 -0800850 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500851 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
852 if gold_supported:
853 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500854 srcpath = _EnvdGetVar(envd, 'LIBPATH')
855 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
856 output_dir + libpath)
857
858
859def _ProcessGccConfig(target, output_dir):
860 """Do what gcc-config would have done"""
861 binpath = '/bin'
862 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
863 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
864 for prog in os.listdir(output_dir + srcpath):
865 # Skip binaries already wrapped.
866 if (not prog.endswith('.real') and
867 not prog.endswith('.elf') and
868 prog.startswith(target)):
869 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
870 os.path.join(srcpath, prog))
871 return srcpath
872
873
874def _ProcessSysrootWrapper(_target, output_dir, srcpath):
875 """Remove chroot-specific things from our sysroot wrapper"""
876 # Disable ccache since we know it won't work outside of chroot.
877 sysroot_wrapper = glob.glob(os.path.join(
878 output_dir + srcpath, 'sysroot_wrapper*'))[0]
879 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
880 for num in xrange(len(contents)):
881 if '@CCACHE_DEFAULT@' in contents[num]:
882 contents[num] = 'use_ccache = False'
883 break
884 # Can't update the wrapper in place since it's a hardlink to a file in /.
885 os.unlink(sysroot_wrapper)
886 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
Mike Frysinger60ec1012013-10-21 00:11:10 -0400887 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500888
889
890def _ProcessDistroCleanups(target, output_dir):
891 """Clean up the tree and remove all distro-specific requirements
892
893 Args:
894 target: The toolchain target name
895 output_dir: The output directory to clean up
896 """
897 _ProcessBinutilsConfig(target, output_dir)
898 gcc_path = _ProcessGccConfig(target, output_dir)
899 _ProcessSysrootWrapper(target, output_dir, gcc_path)
900
901 osutils.RmDir(os.path.join(output_dir, 'etc'))
902
903
904def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
905 """Setup a tree from the packages for the specified target
906
907 This populates a path with all the files from toolchain packages so that
908 a tarball can easily be generated from the result.
909
910 Args:
911 target: The target to create a packagable root from
912 output_dir: The output directory to place all the files
913 ldpaths: A dict of static ldpath information
914 root: The root path to pull all packages/files from
915 """
916 # Find all the files owned by the packages for this target.
917 paths, elfs = _GetFilesForTarget(target, root=root)
918
919 # Link in all the package's files, any ELF dependencies, and wrap any
920 # executable ELFs with helper scripts.
921 def MoveUsrBinToBin(path):
922 """Move /usr/bin to /bin so people can just use that toplevel dir"""
923 return path[4:] if path.startswith('/usr/bin/') else path
924 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
925 path_rewrite_func=MoveUsrBinToBin, root=root)
926
927 # The packages, when part of the normal distro, have helper scripts
928 # that setup paths and such. Since we are making this standalone, we
929 # need to preprocess all that ourselves.
930 _ProcessDistroCleanups(target, output_dir)
931
932
933def CreatePackages(targets_wanted, output_dir, root='/'):
934 """Create redistributable cross-compiler packages for the specified targets
935
936 This creates toolchain packages that should be usable in conjunction with
937 a downloaded sysroot (created elsewhere).
938
939 Tarballs (one per target) will be created in $PWD.
940
941 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700942 targets_wanted: The targets to package up.
943 output_dir: The directory to put the packages in.
944 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500945 """
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500946 cros_build_lib.Info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -0500947 osutils.SafeMakedirs(output_dir)
948 ldpaths = lddtree.LoadLdpaths(root)
949 targets = ExpandTargets(targets_wanted)
950
David James4bc13702013-03-26 08:08:04 -0700951 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500952 # We have to split the root generation from the compression stages. This is
953 # because we hardlink in all the files (to avoid overhead of reading/writing
954 # the copies multiple times). But tar gets angry if a file's hardlink count
955 # changes from when it starts reading a file to when it finishes.
956 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
957 for target in targets:
958 output_target_dir = os.path.join(tempdir, target)
959 queue.put([target, output_target_dir, ldpaths, root])
960
961 # Build the tarball.
962 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
963 for target in targets:
964 tar_file = os.path.join(output_dir, target + '.tar.xz')
965 queue.put([tar_file, os.path.join(tempdir, target)])
966
967
Brian Harring30675052012-02-29 12:18:22 -0800968def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -0500969 parser = commandline.ArgumentParser(description=__doc__)
970 parser.add_argument('-u', '--nousepkg',
971 action='store_false', dest='usepkg', default=True,
972 help='Use prebuilt packages if possible')
973 parser.add_argument('-d', '--deleteold',
974 action='store_true', dest='deleteold', default=False,
975 help='Unmerge deprecated packages')
976 parser.add_argument('-t', '--targets',
977 dest='targets', default='sdk',
978 help='Comma separated list of tuples. '
979 'Special keyword \'host\' is allowed. Default: sdk')
980 parser.add_argument('--include-boards',
981 dest='include_boards', default='',
982 help='Comma separated list of boards whose toolchains we'
983 ' will always include. Default: none')
984 parser.add_argument('--hostonly',
985 dest='hostonly', default=False, action='store_true',
986 help='Only setup the host toolchain. '
987 'Useful for bootstrapping chroot')
988 parser.add_argument('--show-board-cfg',
989 dest='board_cfg', default=None,
990 help='Board to list toolchain tuples for')
991 parser.add_argument('--create-packages',
992 action='store_true', default=False,
993 help='Build redistributable packages')
994 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
995 help='Output directory')
996 parser.add_argument('--reconfig', default=False, action='store_true',
997 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100998
Mike Frysinger0c808452014-11-06 17:30:23 -0500999 options = parser.parse_args(argv)
1000 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001001
Mike Frysinger35247af2012-11-16 18:58:06 -05001002 # Figure out what we're supposed to do and reject conflicting options.
1003 if options.board_cfg and options.create_packages:
1004 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001005
Zdenek Behan508dcce2011-12-05 15:39:32 +01001006 targets = set(options.targets.split(','))
Mike Frysinger0c808452014-11-06 17:30:23 -05001007 boards = (set(options.include_boards.split(',')) if options.include_boards
1008 else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001009
1010 if options.board_cfg:
1011 ShowBoardConfig(options.board_cfg)
1012 elif options.create_packages:
1013 cros_build_lib.AssertInsideChroot()
1014 Crossdev.Load(False)
1015 CreatePackages(targets, options.output_dir)
1016 else:
1017 cros_build_lib.AssertInsideChroot()
1018 # This has to be always run as root.
1019 if os.geteuid() != 0:
1020 cros_build_lib.Die('this script must be run as root')
1021
1022 Crossdev.Load(options.reconfig)
1023 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
1024 options.reconfig, targets, boards)
1025 Crossdev.Save()
1026
1027 return 0