blob: a12d5c2a762986c5d02b2be9c74fe503013c0b37 [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 Frysinger1d4752b2014-11-08 04:00:18 -05007# pylint: disable=bad-continuation
8# pylint: disable=bad-whitespace
9
Mike Frysinger383367e2014-09-16 15:06:17 -040010from __future__ import print_function
11
Zdenek Behan508dcce2011-12-05 15:39:32 +010012import copy
Mike Frysinger35247af2012-11-16 18:58:06 -050013import glob
Mike Frysinger7ccee992012-06-01 21:27:59 -040014import json
Zdenek Behan508dcce2011-12-05 15:39:32 +010015import os
Zdenek Behan508dcce2011-12-05 15:39:32 +010016
Don Garrett88b8d782014-05-13 17:30:55 -070017from chromite.cbuildbot import constants
Mike Frysinger506e75f2012-12-17 14:21:13 -050018from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080019from chromite.lib import cros_build_lib
Brian Harringaf019fb2012-05-10 15:06:13 -070020from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050021from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080022from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050023
24# Needs to be after chromite imports.
25import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010026
Mike Frysinger31596002012-12-03 23:54:24 -050027if cros_build_lib.IsInsideChroot():
28 # Only import portage after we've checked that we're inside the chroot.
29 # Outside may not have portage, in which case the above may not happen.
30 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070031 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050032 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010033
34
Matt Tennantf1e30972012-03-02 16:30:07 -080035EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010036PACKAGE_STABLE = '[stable]'
37PACKAGE_NONE = '[none]'
38SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010039
40CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
41STABLE_OVERLAY = '/usr/local/portage/stable'
42CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010043
44
45# TODO: The versions are stored here very much like in setup_board.
46# The goal for future is to differentiate these using a config file.
47# This is done essentially by messing with GetDesiredPackageVersions()
48DEFAULT_VERSION = PACKAGE_STABLE
49DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010050}
51TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010052 'host' : {
Zdenek Behan508dcce2011-12-05 15:39:32 +010053 'gdb' : PACKAGE_NONE,
54 },
55}
56# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
57CONFIG_TARGET_SUFFIXES = {
58 'binutils' : {
59 'i686-pc-linux-gnu' : '-gold',
60 'x86_64-cros-linux-gnu' : '-gold',
61 },
62}
Zdenek Behan508dcce2011-12-05 15:39:32 +010063# Global per-run cache that will be filled ondemand in by GetPackageMap()
64# function as needed.
65target_version_map = {
66}
67
68
David James66a09c42012-11-05 13:31:38 -080069class Crossdev(object):
70 """Class for interacting with crossdev and caching its output."""
71
72 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
73 _CACHE = {}
74
75 @classmethod
76 def Load(cls, reconfig):
77 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080078 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
79 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080080 if os.path.exists(cls._CACHE_FILE) and not reconfig:
81 with open(cls._CACHE_FILE) as f:
82 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080083 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080084 cls._CACHE = data
85
86 @classmethod
87 def Save(cls):
88 """Store crossdev cache on disk."""
89 # Save the cache from the successful run.
90 with open(cls._CACHE_FILE, 'w') as f:
91 json.dump(cls._CACHE, f)
92
93 @classmethod
94 def GetConfig(cls, target):
95 """Returns a map of crossdev provided variables about a tuple."""
96 CACHE_ATTR = '_target_tuple_map'
97
98 val = cls._CACHE.setdefault(CACHE_ATTR, {})
99 if not target in val:
100 # Find out the crossdev tuple.
101 target_tuple = target
102 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800103 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -0800104 # Catch output of crossdev.
105 out = cros_build_lib.RunCommand(['crossdev', '--show-target-cfg',
106 '--ex-gdb', target_tuple],
107 print_cmd=False, redirect_stdout=True).output.splitlines()
108 # List of tuples split at the first '=', converted into dict.
109 val[target] = dict([x.split('=', 1) for x in out])
110 return val[target]
111
112 @classmethod
113 def UpdateTargets(cls, targets, usepkg, config_only=False):
114 """Calls crossdev to initialize a cross target.
115
116 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700117 targets: The list of targets to initialize using crossdev.
118 usepkg: Copies the commandline opts.
119 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800120 """
121 configured_targets = cls._CACHE.setdefault('configured_targets', [])
122
123 cmdbase = ['crossdev', '--show-fail-log']
124 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
125 # Pick stable by default, and override as necessary.
126 cmdbase.extend(['-P', '--oneshot'])
127 if usepkg:
128 cmdbase.extend(['-P', '--getbinpkg',
129 '-P', '--usepkgonly',
130 '--without-headers'])
131
132 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
133 cmdbase.extend(['--overlays', overlays])
134 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
135
136 for target in targets:
137 if config_only and target in configured_targets:
138 continue
139
140 cmd = cmdbase + ['-t', target]
141
142 for pkg in GetTargetPackages(target):
143 if pkg == 'gdb':
144 # Gdb does not have selectable versions.
145 cmd.append('--ex-gdb')
146 continue
147 # The first of the desired versions is the "primary" one.
148 version = GetDesiredPackageVersions(target, pkg)[0]
149 cmd.extend(['--%s' % pkg, version])
150
151 cmd.extend(targets[target]['crossdev'].split())
152 if config_only:
153 # In this case we want to just quietly reinit
154 cmd.append('--init-target')
155 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
156 else:
157 cros_build_lib.RunCommand(cmd)
158
159 configured_targets.append(target)
160
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100161
Zdenek Behan508dcce2011-12-05 15:39:32 +0100162def GetPackageMap(target):
163 """Compiles a package map for the given target from the constants.
164
165 Uses a cache in target_version_map, that is dynamically filled in as needed,
166 since here everything is static data and the structuring is for ease of
167 configurability only.
168
169 args:
170 target - the target for which to return a version map
171
172 returns a map between packages and desired versions in internal format
173 (using the PACKAGE_* constants)
174 """
175 if target in target_version_map:
176 return target_version_map[target]
177
178 # Start from copy of the global defaults.
179 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
180
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100181 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100182 # prefer any specific overrides
183 if pkg in TARGET_VERSION_MAP.get(target, {}):
184 result[pkg] = TARGET_VERSION_MAP[target][pkg]
185 else:
186 # finally, if not already set, set a sane default
187 result.setdefault(pkg, DEFAULT_VERSION)
188 target_version_map[target] = result
189 return result
190
191
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100192def GetTargetPackages(target):
193 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800194 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100195 # Undesired packages are denoted by empty ${pkg}_pn variable.
196 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
197
198
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100199# Portage helper functions:
200def GetPortagePackage(target, package):
201 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800202 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100203 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100204 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100205 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100206 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100207 category = conf['category']
208 # Portage package:
209 pn = conf[package + '_pn']
210 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500211 assert category
212 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100213 return '%s/%s' % (category, pn)
214
215
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100216def IsPackageDisabled(target, package):
217 """Returns if the given package is not used for the target."""
218 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
219
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100220
David James66a09c42012-11-05 13:31:38 -0800221def GetInstalledPackageVersions(atom):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100222 """Extracts the list of current versions of a target, package pair.
223
224 args:
David James66a09c42012-11-05 13:31:38 -0800225 atom - the atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100226
227 returns the list of versions of the package currently installed.
228 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100229 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500230 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800231 for pkg in portage.db['/']['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100232 version = portage.versions.cpv_getversion(pkg)
233 versions.append(version)
234 return versions
235
236
David James90239b92012-11-05 15:31:34 -0800237def GetStablePackageVersion(atom, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100238 """Extracts the current stable version for a given package.
239
240 args:
241 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
Zdenek Behan699ddd32012-04-13 07:14:08 +0200242 installed - Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243
244 returns a string containing the latest version.
245 """
David James90239b92012-11-05 15:31:34 -0800246 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500247 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800248 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
249 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100250
251
Zdenek Behan699ddd32012-04-13 07:14:08 +0200252def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100253 """Resolves keywords in a given version list for a particular package.
254
255 Resolving means replacing PACKAGE_STABLE with the actual number.
256
257 args:
258 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
259 versions - list of versions to resolve
260
261 returns list of purely numeric versions equivalent to argument
262 """
263 resolved = []
David James90239b92012-11-05 15:31:34 -0800264 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100265 for version in versions:
266 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800267 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100268 elif version != PACKAGE_NONE:
269 resolved.append(version)
270 return resolved
271
272
273def GetDesiredPackageVersions(target, package):
274 """Produces the list of desired versions for each target, package pair.
275
276 The first version in the list is implicitly treated as primary, ie.
277 the version that will be initialized by crossdev and selected.
278
279 If the version is PACKAGE_STABLE, it really means the current version which
280 is emerged by using the package atom with no particular version key.
281 Since crossdev unmasks all packages by default, this will actually
282 mean 'unstable' in most cases.
283
284 args:
285 target, package - the target/package to operate on eg. i686-pc-linux-gnu,gcc
286
287 returns a list composed of either a version string, PACKAGE_STABLE
288 """
289 packagemap = GetPackageMap(target)
290
291 versions = []
292 if package in packagemap:
293 versions.append(packagemap[package])
294
295 return versions
296
297
298def TargetIsInitialized(target):
299 """Verifies if the given list of targets has been correctly initialized.
300
301 This determines whether we have to call crossdev while emerging
302 toolchain packages or can do it using emerge. Emerge is naturally
303 preferred, because all packages can be updated in a single pass.
304
305 args:
306 targets - list of individual cross targets which are checked
307
308 returns True if target is completely initialized
309 returns False otherwise
310 """
311 # Check if packages for the given target all have a proper version.
312 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100313 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800314 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100315 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800316 if not IsPackageDisabled(target, package) and not (
317 GetStablePackageVersion(atom, True) and
318 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100319 return False
320 return True
321 except cros_build_lib.RunCommandError:
322 # Fails - The target has likely never been initialized before.
323 return False
324
325
326def RemovePackageMask(target):
327 """Removes a package.mask file for the given platform.
328
329 The pre-existing package.mask files can mess with the keywords.
330
331 args:
332 target - the target for which to remove the file
333 """
334 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700335 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100336
337
Zdenek Behan508dcce2011-12-05 15:39:32 +0100338# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500339def RebuildLibtool():
340 """Rebuild libtool as needed
341
342 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
343 gcc, libtool will break. We can't use binary packages either as those will
344 most likely be compiled against the previous version of gcc.
345 """
346 needs_update = False
347 with open('/usr/bin/libtool') as f:
348 for line in f:
349 # Look for a line like:
350 # sys_lib_search_path_spec="..."
351 # It'll be a list of paths and gcc will be one of them.
352 if line.startswith('sys_lib_search_path_spec='):
353 line = line.rstrip()
354 for path in line.split('=', 1)[1].strip('"').split():
355 if not os.path.exists(path):
Mike Frysinger383367e2014-09-16 15:06:17 -0400356 print('Rebuilding libtool after gcc upgrade')
357 print(' %s' % line)
358 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500359 needs_update = True
360 break
361
362 if needs_update:
363 break
364
365 if needs_update:
366 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
367 cros_build_lib.RunCommand(cmd)
368
369
Zdenek Behan508dcce2011-12-05 15:39:32 +0100370def UpdateTargets(targets, usepkg):
371 """Determines which packages need update/unmerge and defers to portage.
372
373 args:
374 targets - the list of targets to update
375 usepkg - copies the commandline option
376 """
David James90239b92012-11-05 15:31:34 -0800377 # Remove keyword files created by old versions of cros_setup_toolchains.
378 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100379
380 # For each target, we do two things. Figure out the list of updates,
381 # and figure out the appropriate keywords/masks. Crossdev will initialize
382 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400383 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800384 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100385 for target in targets:
386 # Record the highest needed version for each target, for masking purposes.
387 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100388 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100389 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100390 if IsPackageDisabled(target, package):
391 continue
392 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800393 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100394 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200395 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100396 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100397
Zdenek Behan508dcce2011-12-05 15:39:32 +0100398 packages = []
399 for pkg in mergemap:
400 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200401 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800402 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100403
404 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400405 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800406 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100407
Mike Frysinger383367e2014-09-16 15:06:17 -0400408 print('Updating packages:')
409 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100411 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100412 if usepkg:
413 cmd.extend(['--getbinpkg', '--usepkgonly'])
414
415 cmd.extend(packages)
416 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800417 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100418
419
420def CleanTargets(targets):
421 """Unmerges old packages that are assumed unnecessary."""
422 unmergemap = {}
423 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100424 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100425 if IsPackageDisabled(target, package):
426 continue
427 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800428 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100429 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200430 desired_num = VersionListToNumeric(target, package, desired, True)
431 if not set(desired_num).issubset(current):
Mike Frysinger383367e2014-09-16 15:06:17 -0400432 print('Some packages have been held back, skipping clean!')
Zdenek Behan699ddd32012-04-13 07:14:08 +0200433 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100434 unmergemap[pkg] = set(current).difference(desired_num)
435
436 # Cleaning doesn't care about consistency and rebuilding package.* files.
437 packages = []
438 for pkg, vers in unmergemap.iteritems():
439 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
440
441 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400442 print('Cleaning packages:')
443 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100444 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100445 cmd.extend(packages)
446 cros_build_lib.RunCommand(cmd)
447 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400448 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100449
450
451def SelectActiveToolchains(targets, suffixes):
452 """Runs gcc-config and binutils-config to select the desired.
453
454 args:
455 targets - the targets to select
456 """
457 for package in ['gcc', 'binutils']:
458 for target in targets:
459 # Pick the first version in the numbered list as the selected one.
460 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200461 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100462 desired = desired_num[0]
463 # *-config does not play revisions, strip them, keep just PV.
464 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
465
466 if target == 'host':
467 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800468 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100469
470 # And finally, attach target to it.
471 desired = '%s-%s' % (target, desired)
472
473 # Target specific hacks
474 if package in suffixes:
475 if target in suffixes[package]:
476 desired += suffixes[package][target]
477
David James7ec5efc2012-11-06 09:39:49 -0800478 extra_env = {'CHOST': target}
479 cmd = ['%s-config' % package, '-c', target]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100480 current = cros_build_lib.RunCommand(cmd, print_cmd=False,
David James7ec5efc2012-11-06 09:39:49 -0800481 redirect_stdout=True, extra_env=extra_env).output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100482 # Do not gcc-config when the current is live or nothing needs to be done.
483 if current != desired and current != '9999':
484 cmd = [ package + '-config', desired ]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100485 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100486
487
Mike Frysinger35247af2012-11-16 18:58:06 -0500488def ExpandTargets(targets_wanted):
489 """Expand any possible toolchain aliases into full targets
490
491 This will expand 'all' and 'sdk' into the respective toolchain tuples.
492
493 Args:
494 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500495
Mike Frysinger35247af2012-11-16 18:58:06 -0500496 Returns:
497 Full list of tuples with pseudo targets removed.
498 """
David James27ac4ae2012-12-03 23:16:15 -0800499 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500500 targets_wanted = set(targets_wanted)
501 if targets_wanted == set(['all']):
502 targets = alltargets
503 elif targets_wanted == set(['sdk']):
504 # Filter out all the non-sdk toolchains as we don't want to mess
505 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800506 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysingerda838af2014-11-05 12:36:48 -0500507 elif targets_wanted == set(['boards']):
508 # Only pull targets from the boards.
509 targets = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500510 else:
511 # Verify user input.
512 nonexistent = targets_wanted.difference(alltargets)
513 if nonexistent:
514 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
515 targets = dict((t, alltargets[t]) for t in targets_wanted)
516 return targets
517
518
David Jamesf8c672f2012-11-06 13:38:11 -0800519def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
520 targets_wanted, boards_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 """
David Jamesf8c672f2012-11-06 13:38:11 -0800526 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100527 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.
Mike Frysinger35247af2012-11-16 18:58:06 -0500530 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400531
Mike Frysinger7ccee992012-06-01 21:27:59 -0400532 # Now re-add any targets that might be from this board. This is
533 # to allow unofficial boards to declare their own toolchains.
534 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800535 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100536
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100537 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400538 for target in targets:
539 if TargetIsInitialized(target):
540 reconfig_targets[target] = targets[target]
541 else:
542 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100543 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400544 print('The following targets need to be re-initialized:')
545 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800546 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200547 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800548 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100549
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100550 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400551 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100552
553 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800554 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
555 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800556
557 if deleteold:
558 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100559
Mike Frysingerc880a962013-11-08 13:59:06 -0500560 # Now that we've cleared out old versions, see if we need to rebuild
561 # anything. Can't do this earlier as it might not be broken.
562 RebuildLibtool()
563
Zdenek Behan508dcce2011-12-05 15:39:32 +0100564
Mike Frysinger35247af2012-11-16 18:58:06 -0500565def ShowBoardConfig(board):
566 """Show the toolchain tuples used by |board|
567
568 Args:
569 board: The board to query.
570 """
David James27ac4ae2012-12-03 23:16:15 -0800571 toolchains = toolchain.GetToolchainsForBoard(board)
Mike Frysinger35247af2012-11-16 18:58:06 -0500572 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400573 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800574 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400575 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500576
577
Mike Frysinger35247af2012-11-16 18:58:06 -0500578def GeneratePathWrapper(root, wrappath, path):
579 """Generate a shell script to execute another shell script
580
581 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
582 argv[0] won't be pointing to the correct path, generate a shell script that
583 just executes another program with its full path.
584
585 Args:
586 root: The root tree to generate scripts inside of
587 wrappath: The full path (inside |root|) to create the wrapper
588 path: The target program which this wrapper will execute
589 """
590 replacements = {
591 'path': path,
592 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
593 }
594 wrapper = """#!/bin/sh
595base=$(realpath "$0")
596basedir=${base%%/*}
597exec "${basedir}/%(relroot)s%(path)s" "$@"
598""" % replacements
599 root_wrapper = root + wrappath
600 if os.path.islink(root_wrapper):
601 os.unlink(root_wrapper)
602 else:
603 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
604 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400605 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500606
607
608def FileIsCrosSdkElf(elf):
609 """Determine if |elf| is an ELF that we execute in the cros_sdk
610
611 We don't need this to be perfect, just quick. It makes sure the ELF
612 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
613
614 Args:
615 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500616
Mike Frysinger35247af2012-11-16 18:58:06 -0500617 Returns:
618 True if we think |elf| is a native ELF
619 """
620 with open(elf) as f:
621 data = f.read(20)
622 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
623 return (data[0:4] == '\x7fELF' and
624 data[4] == '\x02' and
625 data[5] == '\x01' and
626 data[18] == '\x3e')
627
628
629def IsPathPackagable(ptype, path):
630 """Should the specified file be included in a toolchain package?
631
632 We only need to handle files as we'll create dirs as we need them.
633
634 Further, trim files that won't be useful:
635 - non-english translations (.mo) since it'd require env vars
636 - debug files since these are for the host compiler itself
637 - info/man pages as they're big, and docs are online, and the
638 native docs should work fine for the most part (`man gcc`)
639
640 Args:
641 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
642 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500643
Mike Frysinger35247af2012-11-16 18:58:06 -0500644 Returns:
645 True if we want to include this path in the package
646 """
647 return not (ptype in ('dir',) or
648 path.startswith('/usr/lib/debug/') or
649 os.path.splitext(path)[1] == '.mo' or
650 ('/man/' in path or '/info/' in path))
651
652
653def ReadlinkRoot(path, root):
654 """Like os.readlink(), but relative to a |root|
655
656 Args:
657 path: The symlink to read
658 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500659
Mike Frysinger35247af2012-11-16 18:58:06 -0500660 Returns:
661 A fully resolved symlink path
662 """
663 while os.path.islink(root + path):
664 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
665 return path
666
667
668def _GetFilesForTarget(target, root='/'):
669 """Locate all the files to package for |target|
670
671 This does not cover ELF dependencies.
672
673 Args:
674 target: The toolchain target name
675 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500676
Mike Frysinger35247af2012-11-16 18:58:06 -0500677 Returns:
678 A tuple of a set of all packable paths, and a set of all paths which
679 are also native ELFs
680 """
681 paths = set()
682 elfs = set()
683
684 # Find all the files owned by the packages for this target.
685 for pkg in GetTargetPackages(target):
686 # Ignore packages that are part of the target sysroot.
687 if pkg in ('kernel', 'libc'):
688 continue
689
690 atom = GetPortagePackage(target, pkg)
691 cat, pn = atom.split('/')
692 ver = GetInstalledPackageVersions(atom)[0]
693 cros_build_lib.Info('packaging %s-%s', atom, ver)
694
695 # pylint: disable=E1101
696 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
697 settings=portage.settings)
698 contents = dblink.getcontents()
699 for obj in contents:
700 ptype = contents[obj][0]
701 if not IsPathPackagable(ptype, obj):
702 continue
703
704 if ptype == 'obj':
705 # For native ELFs, we need to pull in their dependencies too.
706 if FileIsCrosSdkElf(obj):
707 elfs.add(obj)
708 paths.add(obj)
709
710 return paths, elfs
711
712
713def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
714 path_rewrite_func=lambda x:x, root='/'):
715 """Link in all packable files and their runtime dependencies
716
717 This also wraps up executable ELFs with helper scripts.
718
719 Args:
720 output_dir: The output directory to store files
721 paths: All the files to include
722 elfs: All the files which are ELFs (a subset of |paths|)
723 ldpaths: A dict of static ldpath information
724 path_rewrite_func: User callback to rewrite paths in output_dir
725 root: The root path to pull all packages/files from
726 """
727 # Link in all the files.
728 sym_paths = []
729 for path in paths:
730 new_path = path_rewrite_func(path)
731 dst = output_dir + new_path
732 osutils.SafeMakedirs(os.path.dirname(dst))
733
734 # Is this a symlink which we have to rewrite or wrap?
735 # Delay wrap check until after we have created all paths.
736 src = root + path
737 if os.path.islink(src):
738 tgt = os.readlink(src)
739 if os.path.sep in tgt:
740 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
741
742 # Rewrite absolute links to relative and then generate the symlink
743 # ourselves. All other symlinks can be hardlinked below.
744 if tgt[0] == '/':
745 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
746 os.symlink(tgt, dst)
747 continue
748
749 os.link(src, dst)
750
751 # Now see if any of the symlinks need to be wrapped.
752 for sym, tgt in sym_paths:
753 if tgt in elfs:
754 GeneratePathWrapper(output_dir, sym, tgt)
755
756 # Locate all the dependencies for all the ELFs. Stick them all in the
757 # top level "lib" dir to make the wrapper simpler. This exact path does
758 # not matter since we execute ldso directly, and we tell the ldso the
759 # exact path to search for its libraries.
760 libdir = os.path.join(output_dir, 'lib')
761 osutils.SafeMakedirs(libdir)
762 donelibs = set()
763 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400764 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500765 interp = e['interp']
766 if interp:
767 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400768 interp = os.path.join('/lib', os.path.basename(interp))
769 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
770 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500771
772 for lib, lib_data in e['libs'].iteritems():
773 if lib in donelibs:
774 continue
775
776 src = path = lib_data['path']
777 if path is None:
778 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
779 continue
780 donelibs.add(lib)
781
782 # Needed libs are the SONAME, but that is usually a symlink, not a
783 # real file. So link in the target rather than the symlink itself.
784 # We have to walk all the possible symlinks (SONAME could point to a
785 # symlink which points to a symlink), and we have to handle absolute
786 # ourselves (since we have a "root" argument).
787 dst = os.path.join(libdir, os.path.basename(path))
788 src = ReadlinkRoot(src, root)
789
790 os.link(root + src, dst)
791
792
793def _EnvdGetVar(envd, var):
794 """Given a Gentoo env.d file, extract a var from it
795
796 Args:
797 envd: The env.d file to load (may be a glob path)
798 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500799
Mike Frysinger35247af2012-11-16 18:58:06 -0500800 Returns:
801 The value of |var|
802 """
803 envds = glob.glob(envd)
804 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
805 envd = envds[0]
806 return cros_build_lib.LoadKeyValueFile(envd)[var]
807
808
809def _ProcessBinutilsConfig(target, output_dir):
810 """Do what binutils-config would have done"""
811 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500812
813 # Locate the bin dir holding the gold linker.
814 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
815 target, 'binutils-bin')
816 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500817 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500818 if not srcpath:
819 # Maybe this target doesn't support gold.
820 globpath = os.path.join(binutils_bin_path, '*')
821 srcpath = glob.glob(globpath)
822 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
823 % globpath)
824 srcpath = srcpath[0]
825 ld_path = os.path.join(srcpath, 'ld')
826 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
827 ld_path = os.path.join(srcpath, 'ld.bfd')
828 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
829 ld_path = os.path.join(srcpath, 'ld.gold')
830 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
831 % ld_path)
832
833 # Nope, no gold support to be found.
834 gold_supported = False
835 cros_build_lib.Warning('%s: binutils lacks support for the gold linker',
836 target)
837 else:
838 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
839 gold_supported = True
840
Mike Frysinger35247af2012-11-16 18:58:06 -0500841 srcpath = srcpath[0][len(output_dir):]
842 gccpath = os.path.join('/usr', 'libexec', 'gcc')
843 for prog in os.listdir(output_dir + srcpath):
844 # Skip binaries already wrapped.
845 if not prog.endswith('.real'):
846 GeneratePathWrapper(output_dir, binpath + prog,
847 os.path.join(srcpath, prog))
848 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
849 os.path.join(srcpath, prog))
850
David James27ac4ae2012-12-03 23:16:15 -0800851 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500852 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
853 if gold_supported:
854 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500855 srcpath = _EnvdGetVar(envd, 'LIBPATH')
856 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
857 output_dir + libpath)
858
859
860def _ProcessGccConfig(target, output_dir):
861 """Do what gcc-config would have done"""
862 binpath = '/bin'
863 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
864 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
865 for prog in os.listdir(output_dir + srcpath):
866 # Skip binaries already wrapped.
867 if (not prog.endswith('.real') and
868 not prog.endswith('.elf') and
869 prog.startswith(target)):
870 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
871 os.path.join(srcpath, prog))
872 return srcpath
873
874
875def _ProcessSysrootWrapper(_target, output_dir, srcpath):
876 """Remove chroot-specific things from our sysroot wrapper"""
877 # Disable ccache since we know it won't work outside of chroot.
878 sysroot_wrapper = glob.glob(os.path.join(
879 output_dir + srcpath, 'sysroot_wrapper*'))[0]
880 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
881 for num in xrange(len(contents)):
882 if '@CCACHE_DEFAULT@' in contents[num]:
883 contents[num] = 'use_ccache = False'
884 break
885 # Can't update the wrapper in place since it's a hardlink to a file in /.
886 os.unlink(sysroot_wrapper)
887 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
Mike Frysinger60ec1012013-10-21 00:11:10 -0400888 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500889
890
891def _ProcessDistroCleanups(target, output_dir):
892 """Clean up the tree and remove all distro-specific requirements
893
894 Args:
895 target: The toolchain target name
896 output_dir: The output directory to clean up
897 """
898 _ProcessBinutilsConfig(target, output_dir)
899 gcc_path = _ProcessGccConfig(target, output_dir)
900 _ProcessSysrootWrapper(target, output_dir, gcc_path)
901
902 osutils.RmDir(os.path.join(output_dir, 'etc'))
903
904
905def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
906 """Setup a tree from the packages for the specified target
907
908 This populates a path with all the files from toolchain packages so that
909 a tarball can easily be generated from the result.
910
911 Args:
912 target: The target to create a packagable root from
913 output_dir: The output directory to place all the files
914 ldpaths: A dict of static ldpath information
915 root: The root path to pull all packages/files from
916 """
917 # Find all the files owned by the packages for this target.
918 paths, elfs = _GetFilesForTarget(target, root=root)
919
920 # Link in all the package's files, any ELF dependencies, and wrap any
921 # executable ELFs with helper scripts.
922 def MoveUsrBinToBin(path):
923 """Move /usr/bin to /bin so people can just use that toplevel dir"""
924 return path[4:] if path.startswith('/usr/bin/') else path
925 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
926 path_rewrite_func=MoveUsrBinToBin, root=root)
927
928 # The packages, when part of the normal distro, have helper scripts
929 # that setup paths and such. Since we are making this standalone, we
930 # need to preprocess all that ourselves.
931 _ProcessDistroCleanups(target, output_dir)
932
933
934def CreatePackages(targets_wanted, output_dir, root='/'):
935 """Create redistributable cross-compiler packages for the specified targets
936
937 This creates toolchain packages that should be usable in conjunction with
938 a downloaded sysroot (created elsewhere).
939
940 Tarballs (one per target) will be created in $PWD.
941
942 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700943 targets_wanted: The targets to package up.
944 output_dir: The directory to put the packages in.
945 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500946 """
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500947 cros_build_lib.Info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -0500948 osutils.SafeMakedirs(output_dir)
949 ldpaths = lddtree.LoadLdpaths(root)
950 targets = ExpandTargets(targets_wanted)
951
David James4bc13702013-03-26 08:08:04 -0700952 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500953 # We have to split the root generation from the compression stages. This is
954 # because we hardlink in all the files (to avoid overhead of reading/writing
955 # the copies multiple times). But tar gets angry if a file's hardlink count
956 # changes from when it starts reading a file to when it finishes.
957 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
958 for target in targets:
959 output_target_dir = os.path.join(tempdir, target)
960 queue.put([target, output_target_dir, ldpaths, root])
961
962 # Build the tarball.
963 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
964 for target in targets:
965 tar_file = os.path.join(output_dir, target + '.tar.xz')
966 queue.put([tar_file, os.path.join(tempdir, target)])
967
968
Brian Harring30675052012-02-29 12:18:22 -0800969def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -0500970 parser = commandline.ArgumentParser(description=__doc__)
971 parser.add_argument('-u', '--nousepkg',
972 action='store_false', dest='usepkg', default=True,
973 help='Use prebuilt packages if possible')
974 parser.add_argument('-d', '--deleteold',
975 action='store_true', dest='deleteold', default=False,
976 help='Unmerge deprecated packages')
977 parser.add_argument('-t', '--targets',
978 dest='targets', default='sdk',
979 help='Comma separated list of tuples. '
980 'Special keyword \'host\' is allowed. Default: sdk')
981 parser.add_argument('--include-boards',
982 dest='include_boards', default='',
983 help='Comma separated list of boards whose toolchains we'
984 ' will always include. Default: none')
985 parser.add_argument('--hostonly',
986 dest='hostonly', default=False, action='store_true',
987 help='Only setup the host toolchain. '
988 'Useful for bootstrapping chroot')
989 parser.add_argument('--show-board-cfg',
990 dest='board_cfg', default=None,
991 help='Board to list toolchain tuples for')
992 parser.add_argument('--create-packages',
993 action='store_true', default=False,
994 help='Build redistributable packages')
995 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
996 help='Output directory')
997 parser.add_argument('--reconfig', default=False, action='store_true',
998 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100999
Mike Frysinger0c808452014-11-06 17:30:23 -05001000 options = parser.parse_args(argv)
1001 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001002
Mike Frysinger35247af2012-11-16 18:58:06 -05001003 # Figure out what we're supposed to do and reject conflicting options.
1004 if options.board_cfg and options.create_packages:
1005 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001006
Zdenek Behan508dcce2011-12-05 15:39:32 +01001007 targets = set(options.targets.split(','))
Mike Frysinger0c808452014-11-06 17:30:23 -05001008 boards = (set(options.include_boards.split(',')) if options.include_boards
1009 else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001010
1011 if options.board_cfg:
1012 ShowBoardConfig(options.board_cfg)
1013 elif options.create_packages:
1014 cros_build_lib.AssertInsideChroot()
1015 Crossdev.Load(False)
1016 CreatePackages(targets, options.output_dir)
1017 else:
1018 cros_build_lib.AssertInsideChroot()
1019 # This has to be always run as root.
1020 if os.geteuid() != 0:
1021 cros_build_lib.Die('this script must be run as root')
1022
1023 Crossdev.Load(options.reconfig)
1024 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
1025 options.reconfig, targets, boards)
1026 Crossdev.Save()
1027
1028 return 0