Buildroot Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [Buildroot] [RFC] external toolchain scanner
@ 2016-11-23  1:32 Hollis Blanchard
  2016-11-23  6:23 ` Baruch Siach
  2016-12-07 18:14 ` Hollis Blanchard
  0 siblings, 2 replies; 13+ messages in thread
From: Hollis Blanchard @ 2016-11-23  1:32 UTC (permalink / raw)
  To: buildroot

The attached python script inspects an external toolchain and spits out 
BR config settings, like so (with a Linaro toolchain):

    aurora:buildroot$ ./support/scripts/scan-ext-toolchain /foo/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux
    BR2_TOOLCHAIN_EXTERNAL=y
    BR2_TOOLCHAIN_EXTERNAL_GCC_4_9=y
    BR2_TOOLCHAIN_EXTERNAL_HEADERS_3_7=y
    BR2_TOOLCHAIN_EXTERNAL_CXX=y
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y
    BR2_TOOLCHAIN_EXTERNAL_GF=y
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX="aarch64-linux-gnu"
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC=y
    BR2_TOOLCHAIN_EXTERNAL_PATH="/foo/gcc-linaro-aarch64-linux-gnu-4.9-2014.09_linux"

It also works with multi-arch toolchains (this one from Mentor Graphics):

    aurora:buildroot$ ./support/scripts/scan-ext-toolchain /foo/codesourcery/codebench/
    Toolchain supports multiple targets. Please choose one of the following: ['aarch64-linux-gnu', 'arm-none-eabi', 'arm-none-linux-gnueabi']
    aurora:buildroot$ ./support/scripts/scan-ext-toolchain -t arm-none-linux-gnueabi /foo/codesourcery/codebench/
    BR2_TOOLCHAIN_EXTERNAL=y
    BR2_TOOLCHAIN_EXTERNAL_HEADERS_3_16=y
    BR2_TOOLCHAIN_EXTERNAL_GCC_4_9=y
    BR2_TOOLCHAIN_EXTERNAL_CXX=y
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=arm-none-linux-gnueabi
    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC=y
    BR2_TOOLCHAIN_EXTERNAL_PATH="/foo/codesourcery/codebench/"

It complains about bare-metal toolchains:

    aurora:buildroot$ ./support/scripts/scan-ext-toolchain -t arm-none-eabi /foo/codesourcery/codebench/
    Is this a Linux toolchain? Couldn't find the sysroot in:
             /foo/codesourcery/codebench/arm-none-eabi/libc
             /foo/codesourcery/codebench/arm-none-eabi/sysroot


Current limitations that I know of:

1. I haven't run through a full build with it yet, but it looks like 
it's doing the right thing.

2. It detects MUSL and UCLIBC toolchains, but it looks like further work 
is needed to detect SSP, RPC, etc, for those toolchain types.

3. There is no guarantee that BR2_arch matches 
BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX.

4. Users would run it something like this:

    ./support/scripts/scan-ext-toolchain > toolchain.defconfig
    cat board.defconfig toolchain.defconfig > defconfig
    make ... BR2_DEFCONFIG=defconfig

Creating and managing board.defconfig without toolchain configuration 
data is left as an (awkward?) exercise for the user.


Comments?

-- 
Hollis Blanchard <hollis_blanchard@mentor.com>
Mentor Graphics Emulation Division

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.busybox.net/pipermail/buildroot/attachments/20161122/9ddf9a99/attachment.html>
-------------- next part --------------
#!/usr/bin/env python

# Copyright 2016 Mentor Graphics Corporation
# All Rights Reserved
#
# THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY
# INFORMATION WHICH ARE THE PROPERTY OF MENTOR
# GRAPHICS CORPORATION OR ITS LICENSORS AND IS
# SUBJECT TO LICENSE TERMS.

import sys
import os
import subprocess
import re
from optparse import OptionParser

class ExtToolchainMetadata:
	def __init__(self, base_path):
		self.cfg = {}
		self.tools = {}
		self.base_path = base_path
		self.sysroot_path = None

	def get_buildroot_cfg(self):
		result = 'BR2_TOOLCHAIN_EXTERNAL=y\n'
		for k, v in self.cfg.items():
			result += 'BR2_TOOLCHAIN_EXTERNAL_%s=%s\n' % (k, v)
		return result

def probe_prefix(path, target, metadata):
	libexec_path = os.path.join(path, 'libexec', 'gcc') 

	if not os.path.isdir(libexec_path):
		raise RuntimeError("Couldn't examine directory %s" % libexec_path)

	targets = os.listdir(libexec_path)
	if len(targets) == 0:
		raise RuntimeError("Couldn't find any targets in %s" % libexec_path)

	if not target:
		if len(targets) > 1:
			raise RuntimeError('Toolchain supports multiple targets. '
					'Please choose one of the following: %s' % (targets))
		target = targets[0]
	else:
		if target not in targets:
			raise RuntimeError('Toolchain does not support target %s.' % target)
		target = target

	# XXX use ARCH instead?
	# cpu, vendor_os = target.split('-', 1)
	# metadata.cfg['CUSTOM_PREFIX'] = '"$(ARCH)-%s"' % vendor_os
	metadata.cfg['CUSTOM_PREFIX'] = '"%s"' % target

def probe_tools(path, metadata):
	class Tool:
		def __init__(self, executable, cfgname=None):
			self.executable = executable
			self.cfgname = cfgname

	tools = (
		Tool('gcc'),
		Tool('readelf'),
		Tool('g++', 'CXX'),
		Tool('gfortran', 'GF'),
	)

	prefix = metadata.cfg['CUSTOM_PREFIX'].strip('"')

	for tool in tools:
		full_name = '%s-%s' % (prefix, tool.executable)
		full_path = os.path.join(path, 'bin', full_name)

		if os.path.exists(full_path):
			metadata.tools[tool.executable] = full_path
			if tool.cfgname:
				metadata.cfg[tool.cfgname] = 'y'

def probe_gcc_version(metadata):
	argv = [
		metadata.tools['gcc'],
		'--version',
	]

	proc = subprocess.Popen(argv, stdout=subprocess.PIPE)
	output = proc.communicate()[0]
	line1 = output.splitlines()[0]

	m = re.match('^[^)]+\) ([^ ]+)', line1)
	if not m:
		raise RuntimeError("%s\n\tdidn't report a recognizable version:\n%s" %
				(metadata.tools['gcc'], line1))

	version = m.group(1) # E.g. 4.9.2
	major, minor = [ int(i) for i in version.split('.', 2)[:2] ]
	metadata.cfg['GCC_%d_%d' % (major, minor)] = 'y'

def probe_gcc_sysroot(metadata):
	# Sysroot directories could have a couple names:
	subdirs = ('libc', 'sysroot')

	# Construct a list of full paths so that in case of failure we can tell the
	# user exactly where we searched.
	base = metadata.base_path
	prefix = metadata.cfg['CUSTOM_PREFIX'].strip('"')
	sysroot_paths = [ os.path.join(base, prefix, d) for d in subdirs ]

	sysroot_path = None
	for path in sysroot_paths:
		if os.path.exists(path):
			sysroot_path = path
			break

	if not sysroot_path:
		msg = "Is this a Linux toolchain? Couldn't find the sysroot in:\n\t%s"
		raise RuntimeError(msg % '\n\t'.join(sysroot_paths))

	metadata.sysroot_path = sysroot_path

def probe_gcc_headers(metadata):
	version_path = os.path.join(metadata.sysroot_path,
		'usr',
		'include',
		'linux',
		'version.h'
	)
	version_re = '#define LINUX_VERSION_CODE ([0-9]+)'

	with open(version_path) as version_file:
		linux_version_code = version_file.readline()

	m = re.match(version_re, linux_version_code)
	if not m:
		msg = "Didn't recognize LINUX_VERSION_CODE in %s"
		raise RuntimeError(msg % version_path)

	version = int(m.group(1))
	major = (version >> 16) & 0xff
	minor = (version >> 8) & 0xff
	metadata.cfg['HEADERS_%d_%d' % (major, minor)] = 'y'

def probe_libc(metadata):
	libc_re = '  -m(glibc|musl|eglibc)\s+\[enabled\]'
	argv = [
		metadata.tools['gcc'],
		'-Q',
		'--help=target',
	]

	proc = subprocess.Popen(argv, stdout=subprocess.PIPE)
	output = proc.communicate()[0].splitlines()
	for line in output:
		m = re.match(libc_re, line)
		if m:
			libc = m.group(1)
			metadata.cfg['CUSTOM_%s' % libc.upper()] = 'y'
			break

def probe_rpc(metadata):
	rpc_path = os.path.join(metadata.sysroot_path,
		'usr',
		'include',
		'rpc',
		'rpc.h')
	if os.path.exists(rpc_path):
		metadata.cfg['HAS_RPC'] = 'y'

def probe(path, options, metadata):
	metadata.cfg['CUSTOM'] = 'y'
	metadata.cfg['PATH'] = '"%s"' % path

	probe_prefix(path, options.target, metadata)
	probe_tools(path, metadata)
	probe_gcc_version(metadata)
	probe_gcc_sysroot(metadata)
	probe_gcc_headers(metadata)
	probe_libc(metadata)
	probe_rpc(metadata)

def output_cfg(metadata):
	for k, v in metadata.items():
		sys.stdout.write('BR2_TOOLCHAIN_%s=%s\n' % (k, v))

def main():
	parser = OptionParser()
	parser.add_option('-t', '--target', dest='target')

	(options, arguments) = parser.parse_args()

	if len(arguments) < 1:
		print "Missing path to toolchain base directory"
		sys.exit(1)
	toolchain_dir = arguments[0]
	if not os.path.isdir(toolchain_dir):
		print "Not a directory: %s" % toolchain_dir
		sys.exit(2)

	metadata = ExtToolchainMetadata(toolchain_dir)
	probe(toolchain_dir, options, metadata)
	print metadata.get_buildroot_cfg().strip()

if __name__ == '__main__':
	try:
		main()
	except RuntimeError, e:
		print e

^ permalink raw reply	[flat|nested] 13+ messages in thread
* [Buildroot] [RFC] external toolchain scanner
@ 2016-11-23  6:34 Blanchard, Hollis
  0 siblings, 0 replies; 13+ messages in thread
From: Blanchard, Hollis @ 2016-11-23  6:34 UTC (permalink / raw)
  To: buildroot

On Nov 22, 2016 10:24 PM, Baruch Siach <baruch@tkos.co.il> wrote:
>
> Hi Hollis,
>
> On Tue, Nov 22, 2016 at 05:32:51PM -0800, Hollis Blanchard wrote:
> > It also works with multi-arch toolchains (this one from Mentor Graphics):
> >
> >    aurora:buildroot$ ./support/scripts/scan-ext-toolchain /foo/codesourcery/codebench/
> >    Toolchain supports multiple targets. Please choose one of the following: ['aarch64-linux-gnu', 'arm-none-eabi', 'arm-none-linux-gnueabi']
> >    aurora:buildroot$ ./support/scripts/scan-ext-toolchain -t arm-none-linux-gnueabi /foo/codesourcery/codebench/
> >    BR2_TOOLCHAIN_EXTERNAL=y
> >    BR2_TOOLCHAIN_EXTERNAL_HEADERS_3_16=y
> >    BR2_TOOLCHAIN_EXTERNAL_GCC_4_9=y
> >    BR2_TOOLCHAIN_EXTERNAL_CXX=y
> >    BR2_TOOLCHAIN_EXTERNAL_CUSTOM=y
> >    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_PREFIX=arm-none-linux-gnueabi
> >    BR2_TOOLCHAIN_EXTERNAL_CUSTOM_GLIBC=y
> >    BR2_TOOLCHAIN_EXTERNAL_PATH="/foo/codesourcery/codebench/"
>
> Just curious, is this a publicly available toolchain? The latest Sourcery
> CodeBench ARM toolchain that Buildroot knows about is 2014.05, which is based
> on gcc 4.8.3.

Do you mean public, or free? I believe this toolchain is the former but not the latter.

> [...]
>
> > #!/usr/bin/env python
> >
> > # Copyright 2016 Mentor Graphics Corporation
> > # All Rights Reserved
> > #
> > # THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY
> > # INFORMATION WHICH ARE THE PROPERTY OF MENTOR
> > # GRAPHICS CORPORATION OR ITS LICENSORS AND IS
> > # SUBJECT TO LICENSE TERMS.
>
> Are you sure about that?

Yes. The GPL is a license...

-Hollis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.busybox.net/pipermail/buildroot/attachments/20161123/d3065e55/attachment.html>

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2017-01-16 18:36 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-11-23  1:32 [Buildroot] [RFC] external toolchain scanner Hollis Blanchard
2016-11-23  6:23 ` Baruch Siach
2016-12-07 18:14 ` Hollis Blanchard
2016-12-08 21:02   ` Yann E. MORIN
2016-12-19 20:07     ` Hollis Blanchard
2017-01-09 23:07       ` Hollis Blanchard
2017-01-12 17:32         ` Yann E. MORIN
2017-01-12 22:12           ` Hollis Blanchard
2017-01-12 23:43             ` Arnout Vandecappelle
2017-01-15 21:48               ` Thomas Petazzoni
2017-01-16 14:54                 ` Peter Korsgaard
2017-01-16 18:36                   ` Hollis Blanchard
  -- strict thread matches above, loose matches on Subject: below --
2016-11-23  6:34 Blanchard, Hollis

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox