blob: 48b4650986f2cf8cc9fa90d6a3c10aca6856b2d3 [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
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -070015from chromite.lib import brick_lib
Mike Frysinger506e75f2012-12-17 14:21:13 -050016from chromite.lib import commandline
Brian Harring503f3ab2012-03-09 21:39:41 -080017from chromite.lib import cros_build_lib
Brian Harringaf019fb2012-05-10 15:06:13 -070018from chromite.lib import osutils
Mike Frysinger35247af2012-11-16 18:58:06 -050019from chromite.lib import parallel
David James27ac4ae2012-12-03 23:16:15 -080020from chromite.lib import toolchain
Mike Frysinger35247af2012-11-16 18:58:06 -050021
22# Needs to be after chromite imports.
23import lddtree
Zdenek Behan508dcce2011-12-05 15:39:32 +010024
Mike Frysinger31596002012-12-03 23:54:24 -050025if cros_build_lib.IsInsideChroot():
26 # Only import portage after we've checked that we're inside the chroot.
27 # Outside may not have portage, in which case the above may not happen.
28 # We'll check in main() if the operation needs portage.
Don Garrett25f309a2014-03-19 14:02:12 -070029 # pylint: disable=F0401
Mike Frysinger31596002012-12-03 23:54:24 -050030 import portage
Zdenek Behan508dcce2011-12-05 15:39:32 +010031
32
Matt Tennantf1e30972012-03-02 16:30:07 -080033EMERGE_CMD = os.path.join(constants.CHROMITE_BIN_DIR, 'parallel_emerge')
Zdenek Behan508dcce2011-12-05 15:39:32 +010034PACKAGE_STABLE = '[stable]'
35PACKAGE_NONE = '[none]'
36SRC_ROOT = os.path.realpath(constants.SOURCE_ROOT)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +010037
38CHROMIUMOS_OVERLAY = '/usr/local/portage/chromiumos'
39STABLE_OVERLAY = '/usr/local/portage/stable'
40CROSSDEV_OVERLAY = '/usr/local/portage/crossdev'
Zdenek Behan508dcce2011-12-05 15:39:32 +010041
42
43# TODO: The versions are stored here very much like in setup_board.
44# The goal for future is to differentiate these using a config file.
45# This is done essentially by messing with GetDesiredPackageVersions()
46DEFAULT_VERSION = PACKAGE_STABLE
47DEFAULT_TARGET_VERSION_MAP = {
Zdenek Behan508dcce2011-12-05 15:39:32 +010048}
49TARGET_VERSION_MAP = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050050 'host' : {
51 'gdb' : PACKAGE_NONE,
52 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010053}
54# Overrides for {gcc,binutils}-config, pick a package with particular suffix.
55CONFIG_TARGET_SUFFIXES = {
Mike Frysingerd6e2df02014-11-26 02:55:04 -050056 'binutils' : {
Han Shen43b84422015-02-19 11:38:13 -080057 'armv7a-cros-linux-gnueabi': '-gold',
Mike Frysingerd6e2df02014-11-26 02:55:04 -050058 'i686-pc-linux-gnu' : '-gold',
59 'x86_64-cros-linux-gnu' : '-gold',
60 },
Zdenek Behan508dcce2011-12-05 15:39:32 +010061}
Zdenek Behan508dcce2011-12-05 15:39:32 +010062# Global per-run cache that will be filled ondemand in by GetPackageMap()
63# function as needed.
64target_version_map = {
65}
66
67
David James66a09c42012-11-05 13:31:38 -080068class Crossdev(object):
69 """Class for interacting with crossdev and caching its output."""
70
71 _CACHE_FILE = os.path.join(CROSSDEV_OVERLAY, '.configured.json')
72 _CACHE = {}
73
74 @classmethod
75 def Load(cls, reconfig):
76 """Load crossdev cache from disk."""
David James90239b92012-11-05 15:31:34 -080077 crossdev_version = GetStablePackageVersion('sys-devel/crossdev', True)
78 cls._CACHE = {'crossdev_version': crossdev_version}
David James66a09c42012-11-05 13:31:38 -080079 if os.path.exists(cls._CACHE_FILE) and not reconfig:
80 with open(cls._CACHE_FILE) as f:
81 data = json.load(f)
David James90239b92012-11-05 15:31:34 -080082 if crossdev_version == data.get('crossdev_version'):
David James66a09c42012-11-05 13:31:38 -080083 cls._CACHE = data
84
85 @classmethod
86 def Save(cls):
87 """Store crossdev cache on disk."""
88 # Save the cache from the successful run.
89 with open(cls._CACHE_FILE, 'w') as f:
90 json.dump(cls._CACHE, f)
91
92 @classmethod
93 def GetConfig(cls, target):
94 """Returns a map of crossdev provided variables about a tuple."""
95 CACHE_ATTR = '_target_tuple_map'
96
97 val = cls._CACHE.setdefault(CACHE_ATTR, {})
98 if not target in val:
99 # Find out the crossdev tuple.
100 target_tuple = target
101 if target == 'host':
David James27ac4ae2012-12-03 23:16:15 -0800102 target_tuple = toolchain.GetHostTuple()
David James66a09c42012-11-05 13:31:38 -0800103 # Catch output of crossdev.
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500104 out = cros_build_lib.RunCommand(
105 ['crossdev', '--show-target-cfg', '--ex-gdb', target_tuple],
106 print_cmd=False, redirect_stdout=True).output.splitlines()
David James66a09c42012-11-05 13:31:38 -0800107 # List of tuples split at the first '=', converted into dict.
108 val[target] = dict([x.split('=', 1) for x in out])
109 return val[target]
110
111 @classmethod
112 def UpdateTargets(cls, targets, usepkg, config_only=False):
113 """Calls crossdev to initialize a cross target.
114
115 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700116 targets: The list of targets to initialize using crossdev.
117 usepkg: Copies the commandline opts.
118 config_only: Just update.
David James66a09c42012-11-05 13:31:38 -0800119 """
120 configured_targets = cls._CACHE.setdefault('configured_targets', [])
121
122 cmdbase = ['crossdev', '--show-fail-log']
123 cmdbase.extend(['--env', 'FEATURES=splitdebug'])
124 # Pick stable by default, and override as necessary.
125 cmdbase.extend(['-P', '--oneshot'])
126 if usepkg:
127 cmdbase.extend(['-P', '--getbinpkg',
128 '-P', '--usepkgonly',
129 '--without-headers'])
130
131 overlays = '%s %s' % (CHROMIUMOS_OVERLAY, STABLE_OVERLAY)
132 cmdbase.extend(['--overlays', overlays])
133 cmdbase.extend(['--ov-output', CROSSDEV_OVERLAY])
134
135 for target in targets:
136 if config_only and target in configured_targets:
137 continue
138
139 cmd = cmdbase + ['-t', target]
140
141 for pkg in GetTargetPackages(target):
142 if pkg == 'gdb':
143 # Gdb does not have selectable versions.
144 cmd.append('--ex-gdb')
145 continue
146 # The first of the desired versions is the "primary" one.
147 version = GetDesiredPackageVersions(target, pkg)[0]
148 cmd.extend(['--%s' % pkg, version])
149
150 cmd.extend(targets[target]['crossdev'].split())
151 if config_only:
152 # In this case we want to just quietly reinit
153 cmd.append('--init-target')
154 cros_build_lib.RunCommand(cmd, print_cmd=False, redirect_stdout=True)
155 else:
156 cros_build_lib.RunCommand(cmd)
157
158 configured_targets.append(target)
159
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100160
Zdenek Behan508dcce2011-12-05 15:39:32 +0100161def GetPackageMap(target):
162 """Compiles a package map for the given target from the constants.
163
164 Uses a cache in target_version_map, that is dynamically filled in as needed,
165 since here everything is static data and the structuring is for ease of
166 configurability only.
167
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500168 Args:
169 target: The target for which to return a version map
Zdenek Behan508dcce2011-12-05 15:39:32 +0100170
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500171 Returns:
172 A map between packages and desired versions in internal format
173 (using the PACKAGE_* constants)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100174 """
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
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500224 Args:
225 atom: The atom to operate on (e.g. sys-devel/gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100226
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500227 Returns:
228 The list of versions of the package currently installed.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100229 """
Zdenek Behan508dcce2011-12-05 15:39:32 +0100230 versions = []
Mike Frysinger506e75f2012-12-17 14:21:13 -0500231 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800232 for pkg in portage.db['/']['vartree'].dbapi.match(atom, use_cache=0):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100233 version = portage.versions.cpv_getversion(pkg)
234 versions.append(version)
235 return versions
236
237
David James90239b92012-11-05 15:31:34 -0800238def GetStablePackageVersion(atom, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100239 """Extracts the current stable version for a given package.
240
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500241 Args:
242 atom: The target/package to operate on eg. i686-pc-linux-gnu,gcc
243 installed: Whether we want installed packages or ebuilds
Zdenek Behan508dcce2011-12-05 15:39:32 +0100244
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500245 Returns:
246 A string containing the latest version.
Zdenek Behan508dcce2011-12-05 15:39:32 +0100247 """
David James90239b92012-11-05 15:31:34 -0800248 pkgtype = 'vartree' if installed else 'porttree'
Mike Frysinger506e75f2012-12-17 14:21:13 -0500249 # pylint: disable=E1101
David James90239b92012-11-05 15:31:34 -0800250 cpv = portage.best(portage.db['/'][pkgtype].dbapi.match(atom, use_cache=0))
251 return portage.versions.cpv_getversion(cpv) if cpv else None
Zdenek Behan508dcce2011-12-05 15:39:32 +0100252
253
Zdenek Behan699ddd32012-04-13 07:14:08 +0200254def VersionListToNumeric(target, package, versions, installed):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100255 """Resolves keywords in a given version list for a particular package.
256
257 Resolving means replacing PACKAGE_STABLE with the actual number.
258
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500259 Args:
260 target: The target to operate on (e.g. i686-pc-linux-gnu)
261 package: The target/package to operate on (e.g. gcc)
262 versions: List of versions to resolve
263 installed: Query installed packages
Zdenek Behan508dcce2011-12-05 15:39:32 +0100264
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500265 Returns:
266 List of purely numeric versions equivalent to argument
Zdenek Behan508dcce2011-12-05 15:39:32 +0100267 """
268 resolved = []
David James90239b92012-11-05 15:31:34 -0800269 atom = GetPortagePackage(target, package)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100270 for version in versions:
271 if version == PACKAGE_STABLE:
David James90239b92012-11-05 15:31:34 -0800272 resolved.append(GetStablePackageVersion(atom, installed))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100273 elif version != PACKAGE_NONE:
274 resolved.append(version)
275 return resolved
276
277
278def GetDesiredPackageVersions(target, package):
279 """Produces the list of desired versions for each target, package pair.
280
281 The first version in the list is implicitly treated as primary, ie.
282 the version that will be initialized by crossdev and selected.
283
284 If the version is PACKAGE_STABLE, it really means the current version which
285 is emerged by using the package atom with no particular version key.
286 Since crossdev unmasks all packages by default, this will actually
287 mean 'unstable' in most cases.
288
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500289 Args:
290 target: The target to operate on (e.g. i686-pc-linux-gnu)
291 package: The target/package to operate on (e.g. gcc)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100292
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500293 Returns:
294 A list composed of either a version string, PACKAGE_STABLE
Zdenek Behan508dcce2011-12-05 15:39:32 +0100295 """
296 packagemap = GetPackageMap(target)
297
298 versions = []
299 if package in packagemap:
300 versions.append(packagemap[package])
301
302 return versions
303
304
305def TargetIsInitialized(target):
306 """Verifies if the given list of targets has been correctly initialized.
307
308 This determines whether we have to call crossdev while emerging
309 toolchain packages or can do it using emerge. Emerge is naturally
310 preferred, because all packages can be updated in a single pass.
311
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500312 Args:
313 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100314
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500315 Returns:
316 True if |target| is completely initialized, else False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100317 """
318 # Check if packages for the given target all have a proper version.
319 try:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100320 for package in GetTargetPackages(target):
David James66a09c42012-11-05 13:31:38 -0800321 atom = GetPortagePackage(target, package)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100322 # Do we even want this package && is it initialized?
David James90239b92012-11-05 15:31:34 -0800323 if not IsPackageDisabled(target, package) and not (
324 GetStablePackageVersion(atom, True) and
325 GetStablePackageVersion(atom, False)):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100326 return False
327 return True
328 except cros_build_lib.RunCommandError:
329 # Fails - The target has likely never been initialized before.
330 return False
331
332
333def RemovePackageMask(target):
334 """Removes a package.mask file for the given platform.
335
336 The pre-existing package.mask files can mess with the keywords.
337
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500338 Args:
339 target: The target to operate on (e.g. i686-pc-linux-gnu)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100340 """
341 maskfile = os.path.join('/etc/portage/package.mask', 'cross-' + target)
Brian Harringaf019fb2012-05-10 15:06:13 -0700342 osutils.SafeUnlink(maskfile)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100343
344
Zdenek Behan508dcce2011-12-05 15:39:32 +0100345# Main functions performing the actual update steps.
Mike Frysingerc880a962013-11-08 13:59:06 -0500346def RebuildLibtool():
347 """Rebuild libtool as needed
348
349 Libtool hardcodes full paths to internal gcc files, so whenever we upgrade
350 gcc, libtool will break. We can't use binary packages either as those will
351 most likely be compiled against the previous version of gcc.
352 """
353 needs_update = False
354 with open('/usr/bin/libtool') as f:
355 for line in f:
356 # Look for a line like:
357 # sys_lib_search_path_spec="..."
358 # It'll be a list of paths and gcc will be one of them.
359 if line.startswith('sys_lib_search_path_spec='):
360 line = line.rstrip()
361 for path in line.split('=', 1)[1].strip('"').split():
362 if not os.path.exists(path):
Mike Frysinger383367e2014-09-16 15:06:17 -0400363 print('Rebuilding libtool after gcc upgrade')
364 print(' %s' % line)
365 print(' missing path: %s' % path)
Mike Frysingerc880a962013-11-08 13:59:06 -0500366 needs_update = True
367 break
368
369 if needs_update:
370 break
371
372 if needs_update:
373 cmd = [EMERGE_CMD, '--oneshot', 'sys-devel/libtool']
374 cros_build_lib.RunCommand(cmd)
375
376
Zdenek Behan508dcce2011-12-05 15:39:32 +0100377def UpdateTargets(targets, usepkg):
378 """Determines which packages need update/unmerge and defers to portage.
379
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500380 Args:
381 targets: The list of targets to update
382 usepkg: Copies the commandline option
Zdenek Behan508dcce2011-12-05 15:39:32 +0100383 """
David James90239b92012-11-05 15:31:34 -0800384 # Remove keyword files created by old versions of cros_setup_toolchains.
385 osutils.SafeUnlink('/etc/portage/package.keywords/cross-host')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100386
387 # For each target, we do two things. Figure out the list of updates,
388 # and figure out the appropriate keywords/masks. Crossdev will initialize
389 # these, but they need to be regenerated on every update.
Mike Frysinger383367e2014-09-16 15:06:17 -0400390 print('Determining required toolchain updates...')
David James90239b92012-11-05 15:31:34 -0800391 mergemap = {}
Zdenek Behan508dcce2011-12-05 15:39:32 +0100392 for target in targets:
393 # Record the highest needed version for each target, for masking purposes.
394 RemovePackageMask(target)
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100395 for package in GetTargetPackages(target):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100396 # Portage name for the package
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100397 if IsPackageDisabled(target, package):
398 continue
399 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800400 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100401 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200402 desired_num = VersionListToNumeric(target, package, desired, False)
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100403 mergemap[pkg] = set(desired_num).difference(current)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100404
Zdenek Behan508dcce2011-12-05 15:39:32 +0100405 packages = []
406 for pkg in mergemap:
407 for ver in mergemap[pkg]:
Zdenek Behan677b6d82012-04-11 05:31:47 +0200408 if ver != PACKAGE_NONE:
David James90239b92012-11-05 15:31:34 -0800409 packages.append(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100410
411 if not packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400412 print('Nothing to update!')
David Jamesf8c672f2012-11-06 13:38:11 -0800413 return False
Zdenek Behan508dcce2011-12-05 15:39:32 +0100414
Mike Frysinger383367e2014-09-16 15:06:17 -0400415 print('Updating packages:')
416 print(packages)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100417
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100418 cmd = [EMERGE_CMD, '--oneshot', '--update']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100419 if usepkg:
420 cmd.extend(['--getbinpkg', '--usepkgonly'])
421
422 cmd.extend(packages)
423 cros_build_lib.RunCommand(cmd)
David Jamesf8c672f2012-11-06 13:38:11 -0800424 return True
Zdenek Behan508dcce2011-12-05 15:39:32 +0100425
426
427def CleanTargets(targets):
428 """Unmerges old packages that are assumed unnecessary."""
429 unmergemap = {}
430 for target in targets:
Zdenek Behanf4d18a02012-03-22 15:45:05 +0100431 for package in GetTargetPackages(target):
Zdenek Behan4eb6fd22012-03-12 17:00:56 +0100432 if IsPackageDisabled(target, package):
433 continue
434 pkg = GetPortagePackage(target, package)
David James66a09c42012-11-05 13:31:38 -0800435 current = GetInstalledPackageVersions(pkg)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100436 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200437 desired_num = VersionListToNumeric(target, package, desired, True)
438 if not set(desired_num).issubset(current):
Mike Frysinger383367e2014-09-16 15:06:17 -0400439 print('Some packages have been held back, skipping clean!')
Zdenek Behan699ddd32012-04-13 07:14:08 +0200440 return
Zdenek Behan508dcce2011-12-05 15:39:32 +0100441 unmergemap[pkg] = set(current).difference(desired_num)
442
443 # Cleaning doesn't care about consistency and rebuilding package.* files.
444 packages = []
445 for pkg, vers in unmergemap.iteritems():
446 packages.extend('=%s-%s' % (pkg, ver) for ver in vers if ver != '9999')
447
448 if packages:
Mike Frysinger383367e2014-09-16 15:06:17 -0400449 print('Cleaning packages:')
450 print(packages)
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100451 cmd = [EMERGE_CMD, '--unmerge']
Zdenek Behan508dcce2011-12-05 15:39:32 +0100452 cmd.extend(packages)
453 cros_build_lib.RunCommand(cmd)
454 else:
Mike Frysinger383367e2014-09-16 15:06:17 -0400455 print('Nothing to clean!')
Zdenek Behan508dcce2011-12-05 15:39:32 +0100456
457
458def SelectActiveToolchains(targets, suffixes):
459 """Runs gcc-config and binutils-config to select the desired.
460
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500461 Args:
462 targets: The targets to select
463 suffixes: Optional target-specific hacks
Zdenek Behan508dcce2011-12-05 15:39:32 +0100464 """
465 for package in ['gcc', 'binutils']:
466 for target in targets:
467 # Pick the first version in the numbered list as the selected one.
468 desired = GetDesiredPackageVersions(target, package)
Zdenek Behan699ddd32012-04-13 07:14:08 +0200469 desired_num = VersionListToNumeric(target, package, desired, True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100470 desired = desired_num[0]
471 # *-config does not play revisions, strip them, keep just PV.
472 desired = portage.versions.pkgsplit('%s-%s' % (package, desired))[1]
473
474 if target == 'host':
475 # *-config is the only tool treating host identically (by tuple).
David James27ac4ae2012-12-03 23:16:15 -0800476 target = toolchain.GetHostTuple()
Zdenek Behan508dcce2011-12-05 15:39:32 +0100477
478 # And finally, attach target to it.
479 desired = '%s-%s' % (target, desired)
480
481 # Target specific hacks
482 if package in suffixes:
483 if target in suffixes[package]:
484 desired += suffixes[package][target]
485
David James7ec5efc2012-11-06 09:39:49 -0800486 extra_env = {'CHOST': target}
487 cmd = ['%s-config' % package, '-c', target]
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500488 result = cros_build_lib.RunCommand(
489 cmd, print_cmd=False, redirect_stdout=True, extra_env=extra_env)
490 current = result.output.splitlines()[0]
Zdenek Behan508dcce2011-12-05 15:39:32 +0100491 # Do not gcc-config when the current is live or nothing needs to be done.
492 if current != desired and current != '9999':
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500493 cmd = [package + '-config', desired]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100494 cros_build_lib.RunCommand(cmd, print_cmd=False)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100495
496
Mike Frysinger35247af2012-11-16 18:58:06 -0500497def ExpandTargets(targets_wanted):
498 """Expand any possible toolchain aliases into full targets
499
500 This will expand 'all' and 'sdk' into the respective toolchain tuples.
501
502 Args:
503 targets_wanted: The targets specified by the user.
Mike Frysinger1a736a82013-12-12 01:50:59 -0500504
Mike Frysinger35247af2012-11-16 18:58:06 -0500505 Returns:
506 Full list of tuples with pseudo targets removed.
507 """
David James27ac4ae2012-12-03 23:16:15 -0800508 alltargets = toolchain.GetAllTargets()
Mike Frysinger35247af2012-11-16 18:58:06 -0500509 targets_wanted = set(targets_wanted)
510 if targets_wanted == set(['all']):
511 targets = alltargets
512 elif targets_wanted == set(['sdk']):
513 # Filter out all the non-sdk toolchains as we don't want to mess
514 # with those in all of our builds.
David James27ac4ae2012-12-03 23:16:15 -0800515 targets = toolchain.FilterToolchains(alltargets, 'sdk', True)
Mike Frysingerda838af2014-11-05 12:36:48 -0500516 elif targets_wanted == set(['boards']):
517 # Only pull targets from the boards.
518 targets = {}
Mike Frysinger35247af2012-11-16 18:58:06 -0500519 else:
520 # Verify user input.
521 nonexistent = targets_wanted.difference(alltargets)
522 if nonexistent:
523 raise ValueError('Invalid targets: %s', ','.join(nonexistent))
524 targets = dict((t, alltargets[t]) for t in targets_wanted)
525 return targets
526
527
David Jamesf8c672f2012-11-06 13:38:11 -0800528def UpdateToolchains(usepkg, deleteold, hostonly, reconfig,
529 targets_wanted, boards_wanted):
Zdenek Behan508dcce2011-12-05 15:39:32 +0100530 """Performs all steps to create a synchronized toolchain enviroment.
531
Mike Frysingerdc649ae2014-11-26 19:29:24 -0500532 Args:
533 usepkg: Use prebuilt packages
534 deleteold: Unmerge deprecated packages
535 hostonly: Only setup the host toolchain
536 reconfig: Reload crossdev config and reselect toolchains
537 targets_wanted: All the targets to update
538 boards_wanted: Load targets from these boards
Zdenek Behan508dcce2011-12-05 15:39:32 +0100539 """
David Jamesf8c672f2012-11-06 13:38:11 -0800540 targets, crossdev_targets, reconfig_targets = {}, {}, {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100541 if not hostonly:
542 # For hostonly, we can skip most of the below logic, much of which won't
543 # work on bare systems where this is useful.
Mike Frysinger35247af2012-11-16 18:58:06 -0500544 targets = ExpandTargets(targets_wanted)
Mike Frysinger7ccee992012-06-01 21:27:59 -0400545
Mike Frysinger7ccee992012-06-01 21:27:59 -0400546 # Now re-add any targets that might be from this board. This is
547 # to allow unofficial boards to declare their own toolchains.
548 for board in boards_wanted:
David James27ac4ae2012-12-03 23:16:15 -0800549 targets.update(toolchain.GetToolchainsForBoard(board))
Zdenek Behan508dcce2011-12-05 15:39:32 +0100550
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100551 # First check and initialize all cross targets that need to be.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400552 for target in targets:
553 if TargetIsInitialized(target):
554 reconfig_targets[target] = targets[target]
555 else:
556 crossdev_targets[target] = targets[target]
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100557 if crossdev_targets:
Mike Frysinger383367e2014-09-16 15:06:17 -0400558 print('The following targets need to be re-initialized:')
559 print(crossdev_targets)
David James66a09c42012-11-05 13:31:38 -0800560 Crossdev.UpdateTargets(crossdev_targets, usepkg)
Zdenek Behan8be29ba2012-05-29 23:10:34 +0200561 # Those that were not initialized may need a config update.
David James66a09c42012-11-05 13:31:38 -0800562 Crossdev.UpdateTargets(reconfig_targets, usepkg, config_only=True)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100563
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100564 # We want host updated.
Mike Frysinger7ccee992012-06-01 21:27:59 -0400565 targets['host'] = {}
Zdenek Behan7e33b4e2012-03-12 17:00:56 +0100566
567 # Now update all packages.
David Jamesf8c672f2012-11-06 13:38:11 -0800568 if UpdateTargets(targets, usepkg) or crossdev_targets or reconfig:
569 SelectActiveToolchains(targets, CONFIG_TARGET_SUFFIXES)
David James7ec5efc2012-11-06 09:39:49 -0800570
571 if deleteold:
572 CleanTargets(targets)
Zdenek Behan508dcce2011-12-05 15:39:32 +0100573
Mike Frysingerc880a962013-11-08 13:59:06 -0500574 # Now that we've cleared out old versions, see if we need to rebuild
575 # anything. Can't do this earlier as it might not be broken.
576 RebuildLibtool()
577
Zdenek Behan508dcce2011-12-05 15:39:32 +0100578
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700579def ShowConfig(name):
580 """Show the toolchain tuples used by |name|
Mike Frysinger35247af2012-11-16 18:58:06 -0500581
582 Args:
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700583 name: The board name or brick locator to query.
Mike Frysinger35247af2012-11-16 18:58:06 -0500584 """
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -0700585 if brick_lib.IsLocator(name):
586 toolchains = toolchain.GetToolchainsForBrick(name)
587 else:
588 toolchains = toolchain.GetToolchainsForBoard(name)
Mike Frysinger35247af2012-11-16 18:58:06 -0500589 # Make sure we display the default toolchain first.
Mike Frysinger383367e2014-09-16 15:06:17 -0400590 print(','.join(
David James27ac4ae2012-12-03 23:16:15 -0800591 toolchain.FilterToolchains(toolchains, 'default', True).keys() +
Mike Frysinger383367e2014-09-16 15:06:17 -0400592 toolchain.FilterToolchains(toolchains, 'default', False).keys()))
Mike Frysinger35247af2012-11-16 18:58:06 -0500593
594
Mike Frysinger35247af2012-11-16 18:58:06 -0500595def GeneratePathWrapper(root, wrappath, path):
596 """Generate a shell script to execute another shell script
597
598 Since we can't symlink a wrapped ELF (see GenerateLdsoWrapper) because the
599 argv[0] won't be pointing to the correct path, generate a shell script that
600 just executes another program with its full path.
601
602 Args:
603 root: The root tree to generate scripts inside of
604 wrappath: The full path (inside |root|) to create the wrapper
605 path: The target program which this wrapper will execute
606 """
607 replacements = {
608 'path': path,
609 'relroot': os.path.relpath('/', os.path.dirname(wrappath)),
610 }
611 wrapper = """#!/bin/sh
612base=$(realpath "$0")
613basedir=${base%%/*}
614exec "${basedir}/%(relroot)s%(path)s" "$@"
615""" % replacements
616 root_wrapper = root + wrappath
617 if os.path.islink(root_wrapper):
618 os.unlink(root_wrapper)
619 else:
620 osutils.SafeMakedirs(os.path.dirname(root_wrapper))
621 osutils.WriteFile(root_wrapper, wrapper)
Mike Frysinger60ec1012013-10-21 00:11:10 -0400622 os.chmod(root_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500623
624
625def FileIsCrosSdkElf(elf):
626 """Determine if |elf| is an ELF that we execute in the cros_sdk
627
628 We don't need this to be perfect, just quick. It makes sure the ELF
629 is a 64bit LSB x86_64 ELF. That is the native type of cros_sdk.
630
631 Args:
632 elf: The file to check
Mike Frysinger1a736a82013-12-12 01:50:59 -0500633
Mike Frysinger35247af2012-11-16 18:58:06 -0500634 Returns:
635 True if we think |elf| is a native ELF
636 """
637 with open(elf) as f:
638 data = f.read(20)
639 # Check the magic number, EI_CLASS, EI_DATA, and e_machine.
640 return (data[0:4] == '\x7fELF' and
641 data[4] == '\x02' and
642 data[5] == '\x01' and
643 data[18] == '\x3e')
644
645
646def IsPathPackagable(ptype, path):
647 """Should the specified file be included in a toolchain package?
648
649 We only need to handle files as we'll create dirs as we need them.
650
651 Further, trim files that won't be useful:
652 - non-english translations (.mo) since it'd require env vars
653 - debug files since these are for the host compiler itself
654 - info/man pages as they're big, and docs are online, and the
655 native docs should work fine for the most part (`man gcc`)
656
657 Args:
658 ptype: A string describing the path type (i.e. 'file' or 'dir' or 'sym')
659 path: The full path to inspect
Mike Frysinger1a736a82013-12-12 01:50:59 -0500660
Mike Frysinger35247af2012-11-16 18:58:06 -0500661 Returns:
662 True if we want to include this path in the package
663 """
664 return not (ptype in ('dir',) or
665 path.startswith('/usr/lib/debug/') or
666 os.path.splitext(path)[1] == '.mo' or
667 ('/man/' in path or '/info/' in path))
668
669
670def ReadlinkRoot(path, root):
671 """Like os.readlink(), but relative to a |root|
672
673 Args:
674 path: The symlink to read
675 root: The path to use for resolving absolute symlinks
Mike Frysinger1a736a82013-12-12 01:50:59 -0500676
Mike Frysinger35247af2012-11-16 18:58:06 -0500677 Returns:
678 A fully resolved symlink path
679 """
680 while os.path.islink(root + path):
681 path = os.path.join(os.path.dirname(path), os.readlink(root + path))
682 return path
683
684
685def _GetFilesForTarget(target, root='/'):
686 """Locate all the files to package for |target|
687
688 This does not cover ELF dependencies.
689
690 Args:
691 target: The toolchain target name
692 root: The root path to pull all packages from
Mike Frysinger1a736a82013-12-12 01:50:59 -0500693
Mike Frysinger35247af2012-11-16 18:58:06 -0500694 Returns:
695 A tuple of a set of all packable paths, and a set of all paths which
696 are also native ELFs
697 """
698 paths = set()
699 elfs = set()
700
701 # Find all the files owned by the packages for this target.
702 for pkg in GetTargetPackages(target):
703 # Ignore packages that are part of the target sysroot.
704 if pkg in ('kernel', 'libc'):
705 continue
706
707 atom = GetPortagePackage(target, pkg)
708 cat, pn = atom.split('/')
709 ver = GetInstalledPackageVersions(atom)[0]
710 cros_build_lib.Info('packaging %s-%s', atom, ver)
711
712 # pylint: disable=E1101
713 dblink = portage.dblink(cat, pn + '-' + ver, myroot=root,
714 settings=portage.settings)
715 contents = dblink.getcontents()
716 for obj in contents:
717 ptype = contents[obj][0]
718 if not IsPathPackagable(ptype, obj):
719 continue
720
721 if ptype == 'obj':
722 # For native ELFs, we need to pull in their dependencies too.
723 if FileIsCrosSdkElf(obj):
724 elfs.add(obj)
725 paths.add(obj)
726
727 return paths, elfs
728
729
730def _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
Mike Frysingerd6e2df02014-11-26 02:55:04 -0500731 path_rewrite_func=lambda x: x, root='/'):
Mike Frysinger35247af2012-11-16 18:58:06 -0500732 """Link in all packable files and their runtime dependencies
733
734 This also wraps up executable ELFs with helper scripts.
735
736 Args:
737 output_dir: The output directory to store files
738 paths: All the files to include
739 elfs: All the files which are ELFs (a subset of |paths|)
740 ldpaths: A dict of static ldpath information
741 path_rewrite_func: User callback to rewrite paths in output_dir
742 root: The root path to pull all packages/files from
743 """
744 # Link in all the files.
745 sym_paths = []
746 for path in paths:
747 new_path = path_rewrite_func(path)
748 dst = output_dir + new_path
749 osutils.SafeMakedirs(os.path.dirname(dst))
750
751 # Is this a symlink which we have to rewrite or wrap?
752 # Delay wrap check until after we have created all paths.
753 src = root + path
754 if os.path.islink(src):
755 tgt = os.readlink(src)
756 if os.path.sep in tgt:
757 sym_paths.append((new_path, lddtree.normpath(ReadlinkRoot(src, root))))
758
759 # Rewrite absolute links to relative and then generate the symlink
760 # ourselves. All other symlinks can be hardlinked below.
761 if tgt[0] == '/':
762 tgt = os.path.relpath(tgt, os.path.dirname(new_path))
763 os.symlink(tgt, dst)
764 continue
765
766 os.link(src, dst)
767
768 # Now see if any of the symlinks need to be wrapped.
769 for sym, tgt in sym_paths:
770 if tgt in elfs:
771 GeneratePathWrapper(output_dir, sym, tgt)
772
773 # Locate all the dependencies for all the ELFs. Stick them all in the
774 # top level "lib" dir to make the wrapper simpler. This exact path does
775 # not matter since we execute ldso directly, and we tell the ldso the
776 # exact path to search for its libraries.
777 libdir = os.path.join(output_dir, 'lib')
778 osutils.SafeMakedirs(libdir)
779 donelibs = set()
780 for elf in elfs:
Mike Frysingerea7688e2014-07-31 22:40:33 -0400781 e = lddtree.ParseELF(elf, root=root, ldpaths=ldpaths)
Mike Frysinger35247af2012-11-16 18:58:06 -0500782 interp = e['interp']
783 if interp:
784 # Generate a wrapper if it is executable.
Mike Frysingerc2ec0902013-03-26 01:28:45 -0400785 interp = os.path.join('/lib', os.path.basename(interp))
786 lddtree.GenerateLdsoWrapper(output_dir, path_rewrite_func(elf), interp,
787 libpaths=e['rpath'] + e['runpath'])
Mike Frysinger35247af2012-11-16 18:58:06 -0500788
789 for lib, lib_data in e['libs'].iteritems():
790 if lib in donelibs:
791 continue
792
793 src = path = lib_data['path']
794 if path is None:
795 cros_build_lib.Warning('%s: could not locate %s', elf, lib)
796 continue
797 donelibs.add(lib)
798
799 # Needed libs are the SONAME, but that is usually a symlink, not a
800 # real file. So link in the target rather than the symlink itself.
801 # We have to walk all the possible symlinks (SONAME could point to a
802 # symlink which points to a symlink), and we have to handle absolute
803 # ourselves (since we have a "root" argument).
804 dst = os.path.join(libdir, os.path.basename(path))
805 src = ReadlinkRoot(src, root)
806
807 os.link(root + src, dst)
808
809
810def _EnvdGetVar(envd, var):
811 """Given a Gentoo env.d file, extract a var from it
812
813 Args:
814 envd: The env.d file to load (may be a glob path)
815 var: The var to extract
Mike Frysinger1a736a82013-12-12 01:50:59 -0500816
Mike Frysinger35247af2012-11-16 18:58:06 -0500817 Returns:
818 The value of |var|
819 """
820 envds = glob.glob(envd)
821 assert len(envds) == 1, '%s: should have exactly 1 env.d file' % envd
822 envd = envds[0]
823 return cros_build_lib.LoadKeyValueFile(envd)[var]
824
825
826def _ProcessBinutilsConfig(target, output_dir):
827 """Do what binutils-config would have done"""
828 binpath = os.path.join('/bin', target + '-')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500829
830 # Locate the bin dir holding the gold linker.
831 binutils_bin_path = os.path.join(output_dir, 'usr', toolchain.GetHostTuple(),
832 target, 'binutils-bin')
833 globpath = os.path.join(binutils_bin_path, '*-gold')
Mike Frysinger35247af2012-11-16 18:58:06 -0500834 srcpath = glob.glob(globpath)
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500835 if not srcpath:
836 # Maybe this target doesn't support gold.
837 globpath = os.path.join(binutils_bin_path, '*')
838 srcpath = glob.glob(globpath)
839 assert len(srcpath) == 1, ('%s: matched more than one path (but not *-gold)'
840 % globpath)
841 srcpath = srcpath[0]
842 ld_path = os.path.join(srcpath, 'ld')
843 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
844 ld_path = os.path.join(srcpath, 'ld.bfd')
845 assert os.path.exists(ld_path), '%s: linker is missing!' % ld_path
846 ld_path = os.path.join(srcpath, 'ld.gold')
847 assert not os.path.exists(ld_path), ('%s: exists, but gold dir does not!'
848 % ld_path)
849
850 # Nope, no gold support to be found.
851 gold_supported = False
852 cros_build_lib.Warning('%s: binutils lacks support for the gold linker',
853 target)
854 else:
855 assert len(srcpath) == 1, '%s: did not match exactly 1 path' % globpath
856 gold_supported = True
Mike Frysinger78b7a812014-11-26 19:45:23 -0500857 srcpath = srcpath[0]
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500858
Mike Frysinger78b7a812014-11-26 19:45:23 -0500859 srcpath = srcpath[len(output_dir):]
Mike Frysinger35247af2012-11-16 18:58:06 -0500860 gccpath = os.path.join('/usr', 'libexec', 'gcc')
861 for prog in os.listdir(output_dir + srcpath):
862 # Skip binaries already wrapped.
863 if not prog.endswith('.real'):
864 GeneratePathWrapper(output_dir, binpath + prog,
865 os.path.join(srcpath, prog))
866 GeneratePathWrapper(output_dir, os.path.join(gccpath, prog),
867 os.path.join(srcpath, prog))
868
David James27ac4ae2012-12-03 23:16:15 -0800869 libpath = os.path.join('/usr', toolchain.GetHostTuple(), target, 'lib')
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500870 envd = os.path.join(output_dir, 'etc', 'env.d', 'binutils', '*')
871 if gold_supported:
872 envd += '-gold'
Mike Frysinger35247af2012-11-16 18:58:06 -0500873 srcpath = _EnvdGetVar(envd, 'LIBPATH')
874 os.symlink(os.path.relpath(srcpath, os.path.dirname(libpath)),
875 output_dir + libpath)
876
877
878def _ProcessGccConfig(target, output_dir):
879 """Do what gcc-config would have done"""
880 binpath = '/bin'
881 envd = os.path.join(output_dir, 'etc', 'env.d', 'gcc', '*')
882 srcpath = _EnvdGetVar(envd, 'GCC_PATH')
883 for prog in os.listdir(output_dir + srcpath):
884 # Skip binaries already wrapped.
885 if (not prog.endswith('.real') and
886 not prog.endswith('.elf') and
887 prog.startswith(target)):
888 GeneratePathWrapper(output_dir, os.path.join(binpath, prog),
889 os.path.join(srcpath, prog))
890 return srcpath
891
892
Frank Henigman179ec7c2015-02-06 03:01:09 -0500893def _ProcessSysrootWrappers(_target, output_dir, srcpath):
894 """Remove chroot-specific things from our sysroot wrappers"""
Mike Frysinger35247af2012-11-16 18:58:06 -0500895 # Disable ccache since we know it won't work outside of chroot.
Frank Henigman179ec7c2015-02-06 03:01:09 -0500896 for sysroot_wrapper in glob.glob(os.path.join(
897 output_dir + srcpath, 'sysroot_wrapper*')):
898 contents = osutils.ReadFile(sysroot_wrapper).splitlines()
899 for num in xrange(len(contents)):
900 if '@CCACHE_DEFAULT@' in contents[num]:
901 contents[num] = 'use_ccache = False'
902 break
903 # Can't update the wrapper in place since it's a hardlink to a file in /.
904 os.unlink(sysroot_wrapper)
905 osutils.WriteFile(sysroot_wrapper, '\n'.join(contents))
906 os.chmod(sysroot_wrapper, 0o755)
Mike Frysinger35247af2012-11-16 18:58:06 -0500907
908
909def _ProcessDistroCleanups(target, output_dir):
910 """Clean up the tree and remove all distro-specific requirements
911
912 Args:
913 target: The toolchain target name
914 output_dir: The output directory to clean up
915 """
916 _ProcessBinutilsConfig(target, output_dir)
917 gcc_path = _ProcessGccConfig(target, output_dir)
Frank Henigman179ec7c2015-02-06 03:01:09 -0500918 _ProcessSysrootWrappers(target, output_dir, gcc_path)
Mike Frysinger35247af2012-11-16 18:58:06 -0500919
920 osutils.RmDir(os.path.join(output_dir, 'etc'))
921
922
923def CreatePackagableRoot(target, output_dir, ldpaths, root='/'):
924 """Setup a tree from the packages for the specified target
925
926 This populates a path with all the files from toolchain packages so that
927 a tarball can easily be generated from the result.
928
929 Args:
930 target: The target to create a packagable root from
931 output_dir: The output directory to place all the files
932 ldpaths: A dict of static ldpath information
933 root: The root path to pull all packages/files from
934 """
935 # Find all the files owned by the packages for this target.
936 paths, elfs = _GetFilesForTarget(target, root=root)
937
938 # Link in all the package's files, any ELF dependencies, and wrap any
939 # executable ELFs with helper scripts.
940 def MoveUsrBinToBin(path):
941 """Move /usr/bin to /bin so people can just use that toplevel dir"""
942 return path[4:] if path.startswith('/usr/bin/') else path
943 _BuildInitialPackageRoot(output_dir, paths, elfs, ldpaths,
944 path_rewrite_func=MoveUsrBinToBin, root=root)
945
946 # The packages, when part of the normal distro, have helper scripts
947 # that setup paths and such. Since we are making this standalone, we
948 # need to preprocess all that ourselves.
949 _ProcessDistroCleanups(target, output_dir)
950
951
952def CreatePackages(targets_wanted, output_dir, root='/'):
953 """Create redistributable cross-compiler packages for the specified targets
954
955 This creates toolchain packages that should be usable in conjunction with
956 a downloaded sysroot (created elsewhere).
957
958 Tarballs (one per target) will be created in $PWD.
959
960 Args:
Don Garrett25f309a2014-03-19 14:02:12 -0700961 targets_wanted: The targets to package up.
962 output_dir: The directory to put the packages in.
963 root: The root path to pull all packages/files from.
Mike Frysinger35247af2012-11-16 18:58:06 -0500964 """
Mike Frysingerd4d40fd2014-11-06 17:30:57 -0500965 cros_build_lib.Info('Writing tarballs to %s', output_dir)
Mike Frysinger35247af2012-11-16 18:58:06 -0500966 osutils.SafeMakedirs(output_dir)
967 ldpaths = lddtree.LoadLdpaths(root)
968 targets = ExpandTargets(targets_wanted)
969
David James4bc13702013-03-26 08:08:04 -0700970 with osutils.TempDir() as tempdir:
Mike Frysinger35247af2012-11-16 18:58:06 -0500971 # We have to split the root generation from the compression stages. This is
972 # because we hardlink in all the files (to avoid overhead of reading/writing
973 # the copies multiple times). But tar gets angry if a file's hardlink count
974 # changes from when it starts reading a file to when it finishes.
975 with parallel.BackgroundTaskRunner(CreatePackagableRoot) as queue:
976 for target in targets:
977 output_target_dir = os.path.join(tempdir, target)
978 queue.put([target, output_target_dir, ldpaths, root])
979
980 # Build the tarball.
981 with parallel.BackgroundTaskRunner(cros_build_lib.CreateTarball) as queue:
982 for target in targets:
983 tar_file = os.path.join(output_dir, target + '.tar.xz')
984 queue.put([tar_file, os.path.join(tempdir, target)])
985
986
Brian Harring30675052012-02-29 12:18:22 -0800987def main(argv):
Mike Frysinger0c808452014-11-06 17:30:23 -0500988 parser = commandline.ArgumentParser(description=__doc__)
989 parser.add_argument('-u', '--nousepkg',
990 action='store_false', dest='usepkg', default=True,
991 help='Use prebuilt packages if possible')
992 parser.add_argument('-d', '--deleteold',
993 action='store_true', dest='deleteold', default=False,
994 help='Unmerge deprecated packages')
995 parser.add_argument('-t', '--targets',
996 dest='targets', default='sdk',
997 help='Comma separated list of tuples. '
998 'Special keyword \'host\' is allowed. Default: sdk')
999 parser.add_argument('--include-boards',
1000 dest='include_boards', default='',
1001 help='Comma separated list of boards whose toolchains we'
1002 ' will always include. Default: none')
1003 parser.add_argument('--hostonly',
1004 dest='hostonly', default=False, action='store_true',
1005 help='Only setup the host toolchain. '
1006 'Useful for bootstrapping chroot')
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001007 parser.add_argument('--show-board-cfg', '--show-cfg',
1008 dest='cfg_name', default=None,
1009 help='Board or brick to list toolchains tuples for')
Mike Frysinger0c808452014-11-06 17:30:23 -05001010 parser.add_argument('--create-packages',
1011 action='store_true', default=False,
1012 help='Build redistributable packages')
1013 parser.add_argument('--output-dir', default=os.getcwd(), type='path',
1014 help='Output directory')
1015 parser.add_argument('--reconfig', default=False, action='store_true',
1016 help='Reload crossdev config and reselect toolchains')
Zdenek Behan508dcce2011-12-05 15:39:32 +01001017
Mike Frysinger0c808452014-11-06 17:30:23 -05001018 options = parser.parse_args(argv)
1019 options.Freeze()
Zdenek Behan508dcce2011-12-05 15:39:32 +01001020
Mike Frysinger35247af2012-11-16 18:58:06 -05001021 # Figure out what we're supposed to do and reject conflicting options.
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001022 if options.cfg_name and options.create_packages:
Mike Frysinger35247af2012-11-16 18:58:06 -05001023 parser.error('conflicting options: create-packages & show-board-cfg')
Mike Frysinger984d0622012-06-01 16:08:44 -04001024
Zdenek Behan508dcce2011-12-05 15:39:32 +01001025 targets = set(options.targets.split(','))
Mike Frysinger0c808452014-11-06 17:30:23 -05001026 boards = (set(options.include_boards.split(',')) if options.include_boards
1027 else set())
Mike Frysinger35247af2012-11-16 18:58:06 -05001028
Bertrand SIMONNETcae9d5f2015-03-09 15:58:01 -07001029 if options.cfg_name:
1030 ShowConfig(options.cfg_name)
Mike Frysinger35247af2012-11-16 18:58:06 -05001031 elif options.create_packages:
1032 cros_build_lib.AssertInsideChroot()
1033 Crossdev.Load(False)
1034 CreatePackages(targets, options.output_dir)
1035 else:
1036 cros_build_lib.AssertInsideChroot()
1037 # This has to be always run as root.
1038 if os.geteuid() != 0:
1039 cros_build_lib.Die('this script must be run as root')
1040
1041 Crossdev.Load(options.reconfig)
1042 UpdateToolchains(options.usepkg, options.deleteold, options.hostonly,
1043 options.reconfig, targets, boards)
1044 Crossdev.Save()
1045
1046 return 0