blob: a081df732f2e8f4477334c86671531bf4b0719f8 [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' : {
Han Shen43b84422015-02-19 11:38:13 -080056 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050057 'i686-pc-linux-gnu' : '-gold',
58 'x86_64-cros-linux-gnu' : '-gold',
59 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010060}
Zdenek Behan508dcce2011-12-05 15:39:32 +010061# Global per-run cache that will be filled ondemand in by GetPackageMap()
62# function as needed.
63target_version_map = {
64}
65
66
David James66a09c42012-11-05 13:31:38 -080067class Crossdev(object):
68 """Class for interacting with crossdev and caching its output."""
69
70 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
71 _CACHE = {}
72
73 @classmethod
74 def Load(cls, reconfig):
75 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080076 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
77 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080078 if os.path.exists(cls._CACHE_FILE) and not reconfig:
79 with open(cls._CACHE_FILE) as f:
80 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080081 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080082 cls._CACHE = data
83
84 @classmethod
85 def Save(cls):
86 """Store crossdev cache on disk."""
87 # Save the cache from the successful run.
88 with open(cls._CACHE_FILE, 'w') as f:
89 json.dump(cls._CACHE, f)
90
91 @classmethod
92 def GetConfig(cls, target):
93 """Returns a map of crossdev provided variables about a tuple."""
94 CACHE_ATTR = '_target_tuple_map'
95
96 val = cls._CACHE.setdefault(CACHE_ATTR, {})
97 if not target in val:
98 # Find out the crossdev tuple.
99 target_tuple = target
100 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800101 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -0800102 # Catch output of crossdev.
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500103 out = cros_build_lib.RunCommand(
104 ['crossdev', '--show-target-cfg', '--ex-gdb', target_tuple],
105 print_cmd=False, redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800106 # List of tuples split at the first '=', converted into dict.
107 val[target] = dict([x.split('=', 1) for x in out])
108 return val[target]
109
110 @classmethod
111 def UpdateTargets(cls, targets, usepkg, config_only=False):
112 """Calls crossdev to initialize a cross target.
113
114 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700115 targets: The list of targets to initialize using crossdev.
116 usepkg: Copies the commandline opts.
117 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800118 """
119 configured_targets = cls._CACHE.setdefault('configured_targets', [])
120
121 cmdbase = ['crossdev', '--show-fail-log']
122 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
123 # Pick stable by default, and override as necessary.
124 cmdbase.extend(['-P', '--oneshot'])
125 if usepkg:
126 cmdbase.extend(['-P', '--getbinpkg',
127 '-P', '--usepkgonly',
128 '--without-headers'])
129
130 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
131 cmdbase.extend(['--overlays', overlays])
132 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
133
134 for target in targets:
135 if config_only and target in configured_targets:
136 continue
137
138 cmd = cmdbase + ['-t', target]
139
140 for pkg in GetTargetPackages(target):
141 if pkg == 'gdb':
142 # Gdb does not have selectable versions.
143 cmd.append('--ex-gdb')
144 continue
145 # The first of the desired versions is the "primary" one.
146 version = GetDesiredPackageVersions(target, pkg)[0]
147 cmd.extend(['--%s' % pkg, version])
148
149 cmd.extend(targets[target]['crossdev'].split())
150 if config_only:
151 # In this case we want to just quietly reinit
152 cmd.append('--init-target')
153 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
154 else:
155 cros_build_lib.RunCommand(cmd)
156
157 configured_targets.append(target)
158
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100159
Zdenek Behan508dcce2011-12-05 15:39:32 +0100160def GetPackageMap(target):
161 """Compiles a package map for the given target from the constants.
162
163 Uses a cache in target_version_map, that is dynamically filled in as needed,
164 since here everything is static data and the structuring is for ease of
165 configurability only.
166
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500167 Args:
168 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100169
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500170 Returns:
171 A map between packages and desired versions in internal format
172 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100173 """
174 if target in target_version_map:
175 return target_version_map[target]
176
177 # Start from copy of the global defaults.
178 result = copy.copy(DEFAULT_TARGET_VERSION_MAP)
179
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100180 for pkg in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100181 # prefer any specific overrides
182 if pkg in TARGET_VERSION_MAP.get(target, {}):
183 result[pkg] = TARGET_VERSION_MAP[target][pkg]
184 else:
185 # finally, if not already set, set a sane default
186 result.setdefault(pkg, DEFAULT_VERSION)
187 target_version_map[target] = result
188 return result
189
190
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100191def GetTargetPackages(target):
192 """Returns a list of packages for a given target."""
David James66a09c42012-11-05 13:31:38 -0800193 conf = Crossdev.GetConfig(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100194 # Undesired packages are denoted by empty ${pkg}_pn variable.
195 return [x for x in conf['crosspkgs'].strip("'").split() if conf[x+'_pn']]
196
197
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100198# Portage helper functions:
199def GetPortagePackage(target, package):
200 """Returns a package name for the given target."""
David James66a09c42012-11-05 13:31:38 -0800201 conf = Crossdev.GetConfig(target)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100202 # Portage category:
Zdenek Behan508dcce2011-12-05 15:39:32 +0100203 if target == 'host':
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100204 category = conf[package + '_category']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100205 else:
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100206 category = conf['category']
207 # Portage package:
208 pn = conf[package + '_pn']
209 # Final package name:
Mike Frysinger422faf42014-11-12 23:16:48 -0500210 assert category
211 assert pn
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100212 return '%s/%s' % (category, pn)
213
214
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100215def IsPackageDisabled(target, package):
216 """Returns if the given package is not used for the target."""
217 return GetDesiredPackageVersions(target, package) == [PACKAGE_NONE]
218
Liam McLoughlinf54a0782012-05-17 23:36:52 +0100219
David James66a09c42012-11-05 13:31:38 -0800220def GetInstalledPackageVersions(atom):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100221 """Extracts the list of current versions of a target, package pair.
222
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500223 Args:
224 atom: The atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100225
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500226 Returns:
227 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100228 """
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
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500240 Args:
241 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
242 installed: Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100243
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500244 Returns:
245 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100246 """
David James90239b92012-11-05 15:31:34 -0800247 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500248 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800249 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
250 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100251
252
Zdenek Behan699ddd32012-04-13 07:14:08 +0200253def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100254 """Resolves keywords in a given version list for a particular package.
255
256 Resolving means replacing PACKAGE_STABLE with the actual number.
257
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500258 Args:
259 target: The target to operate on (e.g. i686-pc-linux-gnu)
260 package: The target/package to operate on (e.g. gcc)
261 versions: List of versions to resolve
262 installed: Query installed packages
Zdenek Behan508dcce2011-12-05 15:39:32 +0100263
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500264 Returns:
265 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100266 """
267 resolved = []
David James90239b92012-11-05 15:31:34 -0800268 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100269 for version in versions:
270 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800271 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100272 elif version != PACKAGE_NONE:
273 resolved.append(version)
274 return resolved
275
276
277def GetDesiredPackageVersions(target, package):
278 """Produces the list of desired versions for each target, package pair.
279
280 The first version in the list is implicitly treated as primary, ie.
281 the version that will be initialized by crossdev and selected.
282
283 If the version is PACKAGE_STABLE, it really means the current version which
284 is emerged by using the package atom with no particular version key.
285 Since crossdev unmasks all packages by default, this will actually
286 mean 'unstable' in most cases.
287
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500288 Args:
289 target: The target to operate on (e.g. i686-pc-linux-gnu)
290 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100291
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500292 Returns:
293 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100294 """
295 packagemap = GetPackageMap(target)
296
297 versions = []
298 if package in packagemap:
299 versions.append(packagemap[package])
300
301 return versions
302
303
304def TargetIsInitialized(target):
305 """Verifies if the given list of targets has been correctly initialized.
306
307 This determines whether we have to call crossdev while emerging
308 toolchain packages or can do it using emerge. Emerge is naturally
309 preferred, because all packages can be updated in a single pass.
310
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500311 Args:
312 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100313
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500314 Returns:
315 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100316 """
317 # Check if packages for the given target all have a proper version.
318 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100319 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800320 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100321 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800322 if not IsPackageDisabled(target, package) and not (
323 GetStablePackageVersion(atom, True) and
324 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100325 return False
326 return True
327 except cros_build_lib.RunCommandError:
328 # Fails - The target has likely never been initialized before.
329 return False
330
331
332def RemovePackageMask(target):
333 """Removes a package.mask file for the given platform.
334
335 The pre-existing package.mask files can mess with the keywords.
336
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500337 Args:
338 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100339 """
340 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700341 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100342
343
Zdenek Behan508dcce2011-12-05 15:39:32 +0100344# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500345def RebuildLibtool():
346 """Rebuild libtool as needed
347
348 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
349 gcc, libtool will break. We can't use binary packages either as those will
350 most likely be compiled against the previous version of gcc.
351 """
352 needs_update = False
353 with open('/usr/bin/libtool') as f:
354 for line in f:
355 # Look for a line like:
356 # sys_lib_search_path_spec="..."
357 # It'll be a list of paths and gcc will be one of them.
358 if line.startswith('sys_lib_search_path_spec='):
359 line = line.rstrip()
360 for path in line.split('=', 1)[1].strip('"').split():
361 if not os.path.exists(path):
Mike Frysinger383367e2014-09-16 15:06:17 -0400362 print('Rebuilding libtool after gcc upgrade')
363 print(' %s' % line)
364 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500365 needs_update = True
366 break
367
368 if needs_update:
369 break
370
371 if needs_update:
372 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
373 cros_build_lib.RunCommand(cmd)
374
375
Zdenek Behan508dcce2011-12-05 15:39:32 +0100376def UpdateTargets(targets, usepkg):
377 """Determines which packages need update/unmerge and defers to portage.
378
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500379 Args:
380 targets: The list of targets to update
381 usepkg: Copies the commandline option
Zdenek Behan508dcce2011-12-05 15:39:32 +0100382 """
David James90239b92012-11-05 15:31:34 -0800383 # Remove keyword files created by old versions of cros_setup_toolchains.
384 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100385
386 # For each target, we do two things. Figure out the list of updates,
387 # and figure out the appropriate keywords/masks. Crossdev will initialize
388 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400389 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800390 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100391 for target in targets:
392 # Record the highest needed version for each target, for masking purposes.
393 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100394 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100395 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100396 if IsPackageDisabled(target, package):
397 continue
398 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800399 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100400 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200401 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100402 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100403
Zdenek Behan508dcce2011-12-05 15:39:32 +0100404 packages = []
405 for pkg in mergemap:
406 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200407 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800408 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100409
410 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400411 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800412 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100413
Mike Frysinger383367e2014-09-16 15:06:17 -0400414 print('Updating packages:')
415 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100416
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100417 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100418 if usepkg:
419 cmd.extend(['--getbinpkg', '--usepkgonly'])
420
421 cmd.extend(packages)
422 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800423 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100424
425
426def CleanTargets(targets):
427 """Unmerges old packages that are assumed unnecessary."""
428 unmergemap = {}
429 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100430 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100431 if IsPackageDisabled(target, package):
432 continue
433 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800434 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100435 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200436 desired_num = VersionListToNumeric(target, package, desired, True)
437 if not set(desired_num).issubset(current):
Mike Frysinger383367e2014-09-16 15:06:17 -0400438 print('Some packages have been held back, skipping clean!')
Zdenek Behan699ddd32012-04-13 07:14:08 +0200439 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100440 unmergemap[pkg] = set(current).difference(desired_num)
441
442 # Cleaning doesn't care about consistency and rebuilding package.* files.
443 packages = []
444 for pkg, vers in unmergemap.iteritems():
445 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
446
447 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400448 print('Cleaning packages:')
449 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100450 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100451 cmd.extend(packages)
452 cros_build_lib.RunCommand(cmd)
453 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400454 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100455
456
457def SelectActiveToolchains(targets, suffixes):
458 """Runs gcc-config and binutils-config to select the desired.
459
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500460 Args:
461 targets: The targets to select
462 suffixes: Optional target-specific hacks
Zdenek Behan508dcce2011-12-05 15:39:32 +0100463 """
464 for package in ['gcc', 'binutils']:
465 for target in targets:
466 # Pick the first version in the numbered list as the selected one.
467 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200468 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100469 desired = desired_num[0]
470 # *-config does not play revisions, strip them, keep just PV.
471 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
472
473 if target == 'host':
474 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800475 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100476
477 # And finally, attach target to it.
478 desired = '%s-%s' % (target, desired)
479
480 # Target specific hacks
481 if package in suffixes:
482 if target in suffixes[package]:
483 desired += suffixes[package][target]
484
David James7ec5efc2012-11-06 09:39:49 -0800485 extra_env = {'CHOST': target}
486 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500487 result = cros_build_lib.RunCommand(
488 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
489 current = result.output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100490 # Do not gcc-config when the current is live or nothing needs to be done.
491 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500492 cmd = [package + '-config', desired]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100493 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100494
495
Mike Frysinger35247af2012-11-16 18:58:06 -0500496def ExpandTargets(targets_wanted):
497 """Expand any possible toolchain aliases into full targets
498
499 This will expand 'all' and 'sdk' into the respective toolchain tuples.
500
501 Args:
502 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500503
Mike Frysinger35247af2012-11-16 18:58:06 -0500504 Returns:
505 Full list of tuples with pseudo targets removed.
506 """
David James27ac4ae2012-12-03 23:16:15 -0800507 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500508 targets_wanted = set(targets_wanted)
509 if targets_wanted == set(['all']):
510 targets = alltargets
511 elif targets_wanted == set(['sdk']):
512 # Filter out all the non-sdk toolchains as we don't want to mess
513 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800514 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysingerda838af2014-11-05 12:36:48 -0500515 elif targets_wanted == set(['boards']):
516 # Only pull targets from the boards.
517 targets = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500518 else:
519 # Verify user input.
520 nonexistent = targets_wanted.difference(alltargets)
521 if nonexistent:
522 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
523 targets = dict((t, alltargets[t]) for t in targets_wanted)
524 return targets
525
526
David Jamesf8c672f2012-11-06 13:38:11 -0800527def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
528 targets_wanted, boards_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100529 """Performs all steps to create a synchronized toolchain enviroment.
530
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500531 Args:
532 usepkg: Use prebuilt packages
533 deleteold: Unmerge deprecated packages
534 hostonly: Only setup the host toolchain
535 reconfig: Reload crossdev config and reselect toolchains
536 targets_wanted: All the targets to update
537 boards_wanted: Load targets from these boards
Zdenek Behan508dcce2011-12-05 15:39:32 +0100538 """
David Jamesf8c672f2012-11-06 13:38:11 -0800539 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100540 if not hostonly:
541 # For hostonly, we can skip most of the below logic, much of which won't
542 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500543 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400544
Mike Frysinger7ccee992012-06-01 21:27:59 -0400545 # Now re-add any targets that might be from this board. This is
546 # to allow unofficial boards to declare their own toolchains.
547 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800548 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100549
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100550 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400551 for target in targets:
552 if TargetIsInitialized(target):
553 reconfig_targets[target] = targets[target]
554 else:
555 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100556 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400557 print('The following targets need to be re-initialized:')
558 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800559 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200560 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800561 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100562
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100563 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400564 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100565
566 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800567 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
568 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800569
570 if deleteold:
571 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100572
Mike Frysingerc880a962013-11-08 13:59:06 -0500573 # Now that we've cleared out old versions, see if we need to rebuild
574 # anything. Can't do this earlier as it might not be broken.
575 RebuildLibtool()
576
Zdenek Behan508dcce2011-12-05 15:39:32 +0100577
Mike Frysinger35247af2012-11-16 18:58:06 -0500578def ShowBoardConfig(board):
579 """Show the toolchain tuples used by |board|
580
581 Args:
582 board: The board to query.
583 """
David James27ac4ae2012-12-03 23:16:15 -0800584 toolchains = toolchain.GetToolchainsForBoard(board)
Mike Frysinger35247af2012-11-16 18:58:06 -0500585 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400586 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800587 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400588 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500589
590
Mike Frysinger35247af2012-11-16 18:58:06 -0500591def GeneratePathWrapper(root, wrappath, path):
592 """Generate a shell script to execute another shell script
593
594 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
595 argv[0] won't be pointing to the correct path, generate a shell script that
596 just executes another program with its full path.
597
598 Args:
599 root: The root tree to generate scripts inside of
600 wrappath: The full path (inside |root|) to create the wrapper
601 path: The target program which this wrapper will execute
602 """
603 replacements = {
604 'path': path,
605 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
606 }
607 wrapper = """#!/bin/sh
608base=$(realpath "$0")
609basedir=${base%%/*}
610exec "${basedir}/%(relroot)s%(path)s" "$@"
611""" % replacements
612 root_wrapper = root + wrappath
613 if os.path.islink(root_wrapper):
614 os.unlink(root_wrapper)
615 else:
616 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
617 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400618 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500619
620
621def FileIsCrosSdkElf(elf):
622 """Determine if |elf| is an ELF that we execute in the cros_sdk
623
624 We don't need this to be perfect, just quick. It makes sure the ELF
625 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
626
627 Args:
628 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500629
Mike Frysinger35247af2012-11-16 18:58:06 -0500630 Returns:
631 True if we think |elf| is a native ELF
632 """
633 with open(elf) as f:
634 data = f.read(20)
635 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
636 return (data[0:4] == '\x7fELF' and
637 data[4] == '\x02' and
638 data[5] == '\x01' and
639 data[18] == '\x3e')
640
641
642def IsPathPackagable(ptype, path):
643 """Should the specified file be included in a toolchain package?
644
645 We only need to handle files as we'll create dirs as we need them.
646
647 Further, trim files that won't be useful:
648 - non-english translations (.mo) since it'd require env vars
649 - debug files since these are for the host compiler itself
650 - info/man pages as they're big, and docs are online, and the
651 native docs should work fine for the most part (`man gcc`)
652
653 Args:
654 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
655 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500656
Mike Frysinger35247af2012-11-16 18:58:06 -0500657 Returns:
658 True if we want to include this path in the package
659 """
660 return not (ptype in ('dir',) or
661 path.startswith('/usr/lib/debug/') or
662 os.path.splitext(path)[1] == '.mo' or
663 ('/man/' in path or '/info/' in path))
664
665
666def ReadlinkRoot(path, root):
667 """Like os.readlink(), but relative to a |root|
668
669 Args:
670 path: The symlink to read
671 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500672
Mike Frysinger35247af2012-11-16 18:58:06 -0500673 Returns:
674 A fully resolved symlink path
675 """
676 while os.path.islink(root + path):
677 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
678 return path
679
680
681def _GetFilesForTarget(target, root='/'):
682 """Locate all the files to package for |target|
683
684 This does not cover ELF dependencies.
685
686 Args:
687 target: The toolchain target name
688 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500689
Mike Frysinger35247af2012-11-16 18:58:06 -0500690 Returns:
691 A tuple of a set of all packable paths, and a set of all paths which
692 are also native ELFs
693 """
694 paths = set()
695 elfs = set()
696
697 # Find all the files owned by the packages for this target.
698 for pkg in GetTargetPackages(target):
699 # Ignore packages that are part of the target sysroot.
700 if pkg in ('kernel', 'libc'):
701 continue
702
703 atom = GetPortagePackage(target, pkg)
704 cat, pn = atom.split('/')
705 ver = GetInstalledPackageVersions(atom)[0]
706 cros_build_lib.Info('packaging %s-%s', atom, ver)
707
708 # pylint: disable=E1101
709 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
710 settings=portage.settings)
711 contents = dblink.getcontents()
712 for obj in contents:
713 ptype = contents[obj][0]
714 if not IsPathPackagable(ptype, obj):
715 continue
716
717 if ptype == 'obj':
718 # For native ELFs, we need to pull in their dependencies too.
719 if FileIsCrosSdkElf(obj):
720 elfs.add(obj)
721 paths.add(obj)
722
723 return paths, elfs
724
725
726def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500727 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500728 """Link in all packable files and their runtime dependencies
729
730 This also wraps up executable ELFs with helper scripts.
731
732 Args:
733 output_dir: The output directory to store files
734 paths: All the files to include
735 elfs: All the files which are ELFs (a subset of |paths|)
736 ldpaths: A dict of static ldpath information
737 path_rewrite_func: User callback to rewrite paths in output_dir
738 root: The root path to pull all packages/files from
739 """
740 # Link in all the files.
741 sym_paths = []
742 for path in paths:
743 new_path = path_rewrite_func(path)
744 dst = output_dir + new_path
745 osutils.SafeMakedirs(os.path.dirname(dst))
746
747 # Is this a symlink which we have to rewrite or wrap?
748 # Delay wrap check until after we have created all paths.
749 src = root + path
750 if os.path.islink(src):
751 tgt = os.readlink(src)
752 if os.path.sep in tgt:
753 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
754
755 # Rewrite absolute links to relative and then generate the symlink
756 # ourselves. All other symlinks can be hardlinked below.
757 if tgt[0] == '/':
758 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
759 os.symlink(tgt, dst)
760 continue
761
762 os.link(src, dst)
763
764 # Now see if any of the symlinks need to be wrapped.
765 for sym, tgt in sym_paths:
766 if tgt in elfs:
767 GeneratePathWrapper(output_dir, sym, tgt)
768
769 # Locate all the dependencies for all the ELFs. Stick them all in the
770 # top level "lib" dir to make the wrapper simpler. This exact path does
771 # not matter since we execute ldso directly, and we tell the ldso the
772 # exact path to search for its libraries.
773 libdir = os.path.join(output_dir, 'lib')
774 osutils.SafeMakedirs(libdir)
775 donelibs = set()
776 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400777 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500778 interp = e['interp']
779 if interp:
780 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400781 interp = os.path.join('/lib', os.path.basename(interp))
782 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
783 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500784
785 for lib, lib_data in e['libs'].iteritems():
786 if lib in donelibs:
787 continue
788
789 src = path = lib_data['path']
790 if path is None:
791 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
792 continue
793 donelibs.add(lib)
794
795 # Needed libs are the SONAME, but that is usually a symlink, not a
796 # real file. So link in the target rather than the symlink itself.
797 # We have to walk all the possible symlinks (SONAME could point to a
798 # symlink which points to a symlink), and we have to handle absolute
799 # ourselves (since we have a "root" argument).
800 dst = os.path.join(libdir, os.path.basename(path))
801 src = ReadlinkRoot(src, root)
802
803 os.link(root + src, dst)
804
805
806def _EnvdGetVar(envd, var):
807 """Given a Gentoo env.d file, extract a var from it
808
809 Args:
810 envd: The env.d file to load (may be a glob path)
811 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500812
Mike Frysinger35247af2012-11-16 18:58:06 -0500813 Returns:
814 The value of |var|
815 """
816 envds = glob.glob(envd)
817 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
818 envd = envds[0]
819 return cros_build_lib.LoadKeyValueFile(envd)[var]
820
821
822def _ProcessBinutilsConfig(target, output_dir):
823 """Do what binutils-config would have done"""
824 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500825
826 # Locate the bin dir holding the gold linker.
827 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
828 target, 'binutils-bin')
829 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500830 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500831 if not srcpath:
832 # Maybe this target doesn't support gold.
833 globpath = os.path.join(binutils_bin_path, '*')
834 srcpath = glob.glob(globpath)
835 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
836 % globpath)
837 srcpath = srcpath[0]
838 ld_path = os.path.join(srcpath, 'ld')
839 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
840 ld_path = os.path.join(srcpath, 'ld.bfd')
841 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
842 ld_path = os.path.join(srcpath, 'ld.gold')
843 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
844 % ld_path)
845
846 # Nope, no gold support to be found.
847 gold_supported = False
848 cros_build_lib.Warning('%s: binutils lacks support for the gold linker',
849 target)
850 else:
851 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
852 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -0500853 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500854
Mike Frysinger78b7a812014-11-26 19:45:23 -0500855 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -0500856 gccpath = os.path.join('/usr', 'libexec', 'gcc')
857 for prog in os.listdir(output_dir + srcpath):
858 # Skip binaries already wrapped.
859 if not prog.endswith('.real'):
860 GeneratePathWrapper(output_dir, binpath + prog,
861 os.path.join(srcpath, prog))
862 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
863 os.path.join(srcpath, prog))
864
David James27ac4ae2012-12-03 23:16:15 -0800865 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500866 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
867 if gold_supported:
868 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500869 srcpath = _EnvdGetVar(envd, 'LIBPATH')
870 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
871 output_dir + libpath)
872
873
874def _ProcessGccConfig(target, output_dir):
875 """Do what gcc-config would have done"""
876 binpath = '/bin'
877 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
878 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
879 for prog in os.listdir(output_dir + srcpath):
880 # Skip binaries already wrapped.
881 if (not prog.endswith('.real') and
882 not prog.endswith('.elf') and
883 prog.startswith(target)):
884 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
885 os.path.join(srcpath, prog))
886 return srcpath
887
888
Frank Henigman179ec7c2015-02-06 03:01:09 -0500889def _ProcessSysrootWrappers(_target, output_dir, srcpath):
890 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -0500891 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -0500892 for sysroot_wrapper in glob.glob(os.path.join(
893 output_dir + srcpath, 'sysroot_wrapper*')):
894 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
895 for num in xrange(len(contents)):
896 if '@CCACHE_DEFAULT@' in contents[num]:
897 contents[num] = 'use_ccache = False'
898 break
899 # Can't update the wrapper in place since it's a hardlink to a file in /.
900 os.unlink(sysroot_wrapper)
901 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
902 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500903
904
905def _ProcessDistroCleanups(target, output_dir):
906 """Clean up the tree and remove all distro-specific requirements
907
908 Args:
909 target: The toolchain target name
910 output_dir: The output directory to clean up
911 """
912 _ProcessBinutilsConfig(target, output_dir)
913 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -0500914 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -0500915
916 osutils.RmDir(os.path.join(output_dir, 'etc'))
917
918
919def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
920 """Setup a tree from the packages for the specified target
921
922 This populates a path with all the files from toolchain packages so that
923 a tarball can easily be generated from the result.
924
925 Args:
926 target: The target to create a packagable root from
927 output_dir: The output directory to place all the files
928 ldpaths: A dict of static ldpath information
929 root: The root path to pull all packages/files from
930 """
931 # Find all the files owned by the packages for this target.
932 paths, elfs = _GetFilesForTarget(target, root=root)
933
934 # Link in all the package's files, any ELF dependencies, and wrap any
935 # executable ELFs with helper scripts.
936 def MoveUsrBinToBin(path):
937 """Move /usr/bin to /bin so people can just use that toplevel dir"""
938 return path[4:] if path.startswith('/usr/bin/') else path
939 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
940 path_rewrite_func=MoveUsrBinToBin, root=root)
941
942 # The packages, when part of the normal distro, have helper scripts
943 # that setup paths and such. Since we are making this standalone, we
944 # need to preprocess all that ourselves.
945 _ProcessDistroCleanups(target, output_dir)
946
947
948def CreatePackages(targets_wanted, output_dir, root='/'):
949 """Create redistributable cross-compiler packages for the specified targets
950
951 This creates toolchain packages that should be usable in conjunction with
952 a downloaded sysroot (created elsewhere).
953
954 Tarballs (one per target) will be created in $PWD.
955
956 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700957 targets_wanted: The targets to package up.
958 output_dir: The directory to put the packages in.
959 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500960 """
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500961 cros_build_lib.Info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -0500962 osutils.SafeMakedirs(output_dir)
963 ldpaths = lddtree.LoadLdpaths(root)
964 targets = ExpandTargets(targets_wanted)
965
David James4bc13702013-03-26 08:08:04 -0700966 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500967 # We have to split the root generation from the compression stages. This is
968 # because we hardlink in all the files (to avoid overhead of reading/writing
969 # the copies multiple times). But tar gets angry if a file's hardlink count
970 # changes from when it starts reading a file to when it finishes.
971 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
972 for target in targets:
973 output_target_dir = os.path.join(tempdir, target)
974 queue.put([target, output_target_dir, ldpaths, root])
975
976 # Build the tarball.
977 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
978 for target in targets:
979 tar_file = os.path.join(output_dir, target + '.tar.xz')
980 queue.put([tar_file, os.path.join(tempdir, target)])
981
982
Brian Harring30675052012-02-29 12:18:22 -0800983def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -0500984 parser = commandline.ArgumentParser(description=__doc__)
985 parser.add_argument('-u', '--nousepkg',
986 action='store_false', dest='usepkg', default=True,
987 help='Use prebuilt packages if possible')
988 parser.add_argument('-d', '--deleteold',
989 action='store_true', dest='deleteold', default=False,
990 help='Unmerge deprecated packages')
991 parser.add_argument('-t', '--targets',
992 dest='targets', default='sdk',
993 help='Comma separated list of tuples. '
994 'Special keyword \'host\' is allowed. Default: sdk')
995 parser.add_argument('--include-boards',
996 dest='include_boards', default='',
997 help='Comma separated list of boards whose toolchains we'
998 ' will always include. Default: none')
999 parser.add_argument('--hostonly',
1000 dest='hostonly', default=False, action='store_true',
1001 help='Only setup the host toolchain. '
1002 'Useful for bootstrapping chroot')
1003 parser.add_argument('--show-board-cfg',
1004 dest='board_cfg', default=None,
1005 help='Board to list toolchain tuples for')
1006 parser.add_argument('--create-packages',
1007 action='store_true', default=False,
1008 help='Build redistributable packages')
1009 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1010 help='Output directory')
1011 parser.add_argument('--reconfig', default=False, action='store_true',
1012 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001013
Mike Frysinger0c808452014-11-06 17:30:23 -05001014 options = parser.parse_args(argv)
1015 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001016
Mike Frysinger35247af2012-11-16 18:58:06 -05001017 # Figure out what we're supposed to do and reject conflicting options.
1018 if options.board_cfg and options.create_packages:
1019 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001020
Zdenek Behan508dcce2011-12-05 15:39:32 +01001021 targets = set(options.targets.split(','))
Mike Frysinger0c808452014-11-06 17:30:23 -05001022 boards = (set(options.include_boards.split(',')) if options.include_boards
1023 else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001024
1025 if options.board_cfg:
1026 ShowBoardConfig(options.board_cfg)
1027 elif options.create_packages:
1028 cros_build_lib.AssertInsideChroot()
1029 Crossdev.Load(False)
1030 CreatePackages(targets, options.output_dir)
1031 else:
1032 cros_build_lib.AssertInsideChroot()
1033 # This has to be always run as root.
1034 if os.geteuid() != 0:
1035 cros_build_lib.Die('this script must be run as root')
1036
1037 Crossdev.Load(options.reconfig)
1038 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
1039 options.reconfig, targets, boards)
1040 Crossdev.Save()
1041
1042 return 0