Files
meta-external-toolchain/classes/external-toolchain.bbclass
Christopher Larson 0beb66b376 Split up external-sourcery-toolchain into separate recipes
common-license.bbclass will set LIC_FILES_CHKSUM to a common license file
based on LICENSE, which is appropriate for a case where we have no sources to
refer to.
external-toolchain.bbclass, among other things, handles extraction of files in
the external toolchain sysroot, based on patterns in the FILES variables,
checking alternate locations to better support any arbitrary toolchain, and
has basic mirror handling for checking multiple paths within the sysroots.

Under normal circumstances, I'd want this to use highly granular commits, but
this branch has been extremely long lived (>1yr) and is such an invasive
refactoring that attempting to break it down now would be of limited
usefulness.

Signed-off-by: Christopher Larson <chris_larson@mentor.com>
2014-12-19 10:35:25 -07:00

233 lines
8.5 KiB
Plaintext

# This class provides everything necessary for a recipe to pull bits from an
# external toolchain:
# - Automatically sets LIC_FILES_CHKSUM based on LICENSE if appropriate
# - Searches the external toolchain sysroot and alternate locations for the
# patterns specified in the FILES variables, with support for checking
# alternate locations within the sysroot as well
# - Automatically PROVIDES/RPROVIDES the non-external-suffixed names
# - Usual bits to handle packaging of existing binaries
# - Automatically skips the recipe if its files aren't available in the
# external toolchain
# - Automatically grabs all the .debug files for everything included
# Since these are prebuilt binaries, there are no source files to checksum for
# LIC_FILES_CHKSUM, so use the license from common-licenses
inherit common-license
# Prebuilt binaries, no need for any default dependencies
INHIBIT_DEFAULT_DEPS = "1"
EXTERNAL_PN ?= "${@PN.replace('-external', '')}"
PROVIDES += "${EXTERNAL_PN}"
LICENSE = "CLOSED"
LIC_FILES_CHKSUM = "${COMMON_LIC_CHKSUM}"
EXTERNAL_TOOLCHAIN_SYSROOT ?= "${@external_run(d, 'gcc', *(TARGET_CC_ARCH.split() + ['-print-sysroot'])).rstrip()}"
EXTERNAL_INSTALL_SOURCE_PATHS = "\
${EXTERNAL_TOOLCHAIN_SYSROOT} \
${EXTERNAL_TOOLCHAIN}/${EXTERNAL_TARGET_SYS} \
${EXTERNAL_TOOLCHAIN_SYSROOT}/.. \
${EXTERNAL_TOOLCHAIN} \
${D} \
"
# Potential locations within the external toolchain sysroot
FILES_MIRRORS = "\
${bindir}/|/usr/${baselib}/bin/\n \
${base_libdir}/|/usr/${baselib}/\n \
${libexecdir}/|/usr/libexec/\n \
${libexecdir}/|/usr/${baselib}/${PN}\n \
${mandir}/|/usr/share/man/\n \
${mandir}/|/usr/man/\n \
${mandir}/|/man/\n \
${mandir}/|/share/doc/*-${EXTERNAL_TARGET_SYS}/man/\n \
${prefix}/|${base_prefix}/\n \
"
do_configure[noexec] = "1"
do_compile[noexec] = "1"
EXTERNAL_PV_PREFIX ?= ""
EXTERNAL_PV_SUFFIX ?= ""
PV_prepend = "${@'${EXTERNAL_PV_PREFIX}' if '${EXTERNAL_PV_PREFIX}' else ''}"
PV_append = "${@'${EXTERNAL_PV_SUFFIX}' if '${EXTERNAL_PV_SUFFIX}' else ''}"
EXTERNAL_EXTRA_FILES ?= ""
# Skip this recipe if we don't have files in the external toolchain
EXTERNAL_AUTO_PROVIDE ?= "0"
EXTERNAL_AUTO_PROVIDE[type] = "boolean"
EXTERNAL_AUTO_PROVIDE_class-target ?= "1"
python () {
# Skipping only matters up front
if d.getVar('BB_WORKERCONTEXT', True) == '1':
return
# We're not an available provider if there's no external toolchain
if not d.getVar("EXTERNAL_TOOLCHAIN"):
raise bb.parse.SkipPackage("External toolchain not configured (EXTERNAL_TOOLCHAIN not set).")
if not oe.data.typed_value('EXTERNAL_AUTO_PROVIDE', d):
return
sysroots, mirrors = get_file_search_metadata(d)
pattern = d.getVar('EXTERNAL_PROVIDE_PATTERN', True)
if pattern is None:
files = gather_pkg_files(d)
expanded = expand_paths(files, mirrors)
paths = search_sysroots(expanded, sysroots)
if not any(f for p, f in paths):
raise bb.parse.SkipPackage('No files found in external toolchain sysroot')
elif not pattern:
return
else:
expanded = oe.external_toolchain.expand_paths([pattern], mirrors)
paths = oe.external_toolchain.search_sysroots(expanded, sysroots)
if not any(f for p, f in paths):
raise bb.parse.SkipPackage('No files found in external toolchain sysroot for `{}`'.format(pattern))
}
python do_install () {
bb.build.exec_func('external_toolchain_do_install', d)
if 'do_install_extra' in d:
bb.build.exec_func('do_install_extra', d)
}
python external_toolchain_do_install () {
installdest = d.getVar('D', True)
sysroots, mirrors = get_file_search_metadata(d)
files = gather_pkg_files(d)
copy_from_sysroots(files, sysroots, mirrors, installdest)
}
external_toolchain_do_install[vardeps] += "${@' '.join('FILES_%s' % pkg for pkg in '${PACKAGES}'.split())}"
def get_file_search_metadata(d):
'''Given the metadata, return the mirrors and sysroots to operate against.'''
from collections import defaultdict
mirrors = []
for entry in d.getVar('FILES_MIRRORS', True).replace('\\n', '\n').split('\n'):
entry = entry.strip()
if not entry:
continue
pattern, subst = entry.strip().split('|', 1)
mirrors.append(('^' + pattern, subst))
source_paths = [os.path.realpath(p)
for p in d.getVar('EXTERNAL_INSTALL_SOURCE_PATHS', True).split()]
return source_paths, mirrors
def gather_pkg_files(d):
'''Given the metadata, return all the files we want to copy to ${D} for
this recipe.'''
import itertools
files = []
for pkg in d.getVar('PACKAGES', True).split():
files = itertools.chain(files, (d.getVar('FILES_{}'.format(pkg), True) or '').split())
files = itertools.chain(files, d.getVar('EXTERNAL_EXTRA_FILES', True).split())
return files
def copy_from_sysroots(pathnames, sysroots, mirrors, installdest):
'''Copy the specified files from the specified sysroots, also checking the
specified mirror patterns as alternate paths, to the specified destination.'''
import subprocess
expanded_pathnames = expand_paths(pathnames, mirrors)
searched_paths = search_sysroots(expanded_pathnames, sysroots)
for path, files in searched_paths:
if not files:
bb.debug(1, 'Failed to find `{}`'.format(path))
else:
destdir = oe.path.join(installdest, os.path.dirname(path))
bb.utils.mkdirhier(destdir)
subprocess.check_call(['cp', '-pPR'] + list(files) + [destdir + '/'])
bb.note('Copied `{}` to `{}/`'.format(', '.join(files), destdir))
def expand_paths(pathnames, mirrors):
'''Apply search/replace to paths to get alternate search paths.
Returns a generator with tuples of (pathname, expanded_paths).'''
import re
for pathname in pathnames:
expanded_paths = [pathname]
for search, replace in mirrors:
new_pathname = re.sub(search, replace, pathname, count=1)
if new_pathname != pathname:
expanded_paths.append(new_pathname)
yield pathname, expanded_paths
def search_sysroots(path_entries, sysroots):
'''Search the supplied sysroots for the supplied paths, checking supplied
alternate paths. Expects entries in the format (pathname, all_paths).
Returns a generator with tuples of (pathname, found_paths).'''
import glob
import itertools
for path, pathnames in path_entries:
for sysroot, pathname in ((s, p) for s in sysroots
for p in itertools.chain([path], pathnames)):
check_path = sysroot + os.sep + pathname
found_paths = glob.glob(check_path)
if found_paths:
yield path, found_paths
break
else:
yield path, None
# Change do_install's CWD to EXTERNAL_TOOLCHAIN for convenience
do_install[dirs] = "${D} ${EXTERNAL_TOOLCHAIN}"
# Debug files are likely already split out
INHIBIT_PACKAGE_STRIP = "1"
# Toolchain shipped binaries weren't necessarily built ideally
WARN_QA_remove = "ldflags textrel"
ERROR_QA_remove = "ldflags textrel"
RPROVIDES_${PN} += "${EXTERNAL_PN}"
RPROVIDES_${PN}-dev += "${EXTERNAL_PN}-dev"
RPROVIDES_${PN}-staticdev += "${EXTERNAL_PN}-staticdev"
RPROVIDES_${PN}-dbg += "${EXTERNAL_PN}-dbg"
RPROVIDES_${PN}-doc += "${EXTERNAL_PN}-doc"
RPROVIDES_${PN}-locale += "${EXTERNAL_PN}-locale"
LOCALEBASEPN = "${EXTERNAL_PN}"
FILES_${PN} = ""
FILES_${PN}-dev = ""
FILES_${PN}-staticdev = ""
FILES_${PN}-doc = ""
FILES_${PN}-locale = ""
def debug_paths(d):
l = d.createCopy()
l.finalize()
paths = []
exclude = [
l.getVar('datadir', True),
l.getVar('includedir', True),
]
for p in l.getVar('PACKAGES', True).split():
if p.endswith('-dbg'):
continue
for f in (l.getVar('FILES_%s' % p, True) or '').split():
if any((f == x or f.startswith(x + '/')) for x in exclude):
continue
d = os.path.dirname(f)
b = os.path.basename(f)
paths.append('/usr/lib/debug{0}/{1}.debug'.format(d, b))
paths.append('{0}/.debug/{1}'.format(d, b))
paths.append('{0}/.debug/{1}.debug'.format(d, b))
return set(paths)
FILES_${PN}-dbg = "${@' '.join(debug_paths(d))}"
# do_package[depends] += "virtual/${MLPREFIX}libc:do_packagedata"
# do_package_write_ipk[depends] += "virtual/${MLPREFIX}libc:do_packagedata"
# do_package_write_deb[depends] += "virtual/${MLPREFIX}libc:do_packagedata"
# do_package_write_rpm[depends] += "virtual/${MLPREFIX}libc:do_packagedata"