Source code for waftools.ccross

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# Michel Mooij,

Setup and configure multiple C/C++ build environments and configure
common C/C++ tools used when cross-compiling. When using this module
the following tools will be loaded and configured autmatically as well:

- cmake
- codeblocks
- cppcheck
- doxygen
- eclipse
- gnucc
- indent
- makefile
- msdev
- bdist
- tree

.. warning::
	This module has been marked as deprecated and will be removed in 
	release version 0.5.0; use the *ccenv* module instead.

The code snippet below provides an example of how a complete build environment
can be created allowing you to build, not only for the host system, but also 
for one or more target platforms using a C/C++ cross compiler::

	#!/usr/bin/env python
	# -*- encoding: utf-8 -*-

	import os, waftools
	from waftools import ccross

	top = '.'
	out = 'build'
	prefix = 'output'

	VERSION = '0.0.1'
	APPNAME = 'cross-test'

	def options(opt):
		opt.add_option('--prefix', dest='prefix', default=prefix, 
						help='installation prefix [default: %r]' % prefix)
		opt.load('ccross', tooldir=waftools.location)

	def configure(conf):

	def build(bld):, trees=['components'])

	for var in ccross.variants():
		for ctx in ccross.contexts():
			name = ctx.__name__.replace('Context','').lower()
			class _t(ctx):
				__doc__ = "%ss '%s'" % (name, var)
				cmd = name + '_' + var
				variant = var

When loading and configuring the *ccross* tool, as shown in the example above, all 
required C/C++ tools for each build environment variant (i.e. native or cross-
compile) will be loaded and configured as well; e.g. compilers, makefile-, cmake-, 
eclipse-, codeblocks- and msdev exporters, cppcheck source code checking, doxygen 
documentation creation will be available for each build variant. Cross compile 
build environments can be specified in a seperate .INI file (named ccross.ini 
in the example above) using following syntax::

	c = gcc
	cxx = g++
	prefix = arm-linux-gnueabihf

The section name, *arm* in the example above, specifies the name of the cross-compile
build environment variant. The prefix combined with compiler type (c,cxx) will be 
used in order to create the concrete names of the cross compile toolchain 

	AR	= arm-linux-gnueabihf-ar
	CC	= arm-linux-gnueabihf-gcc
	CXX	= arm-linux-gnueabihf-g++

Concrete build scripts (i.e. wscript files) for components can be placed somewhere 
within the *components* sub-directory. Any top level wscript file of a tree (being 
*components* in this example) will be detected and incorporated within the build 
environment. Any wscript files below those top level script files will have to be 
included using the *bld.recurse('../somepath')* command from the top level script 
of that tree.

import os
import sys
	import ConfigParser as configparser
	import configparser

from waflib import Scripting, Errors, Logs, Utils
from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext
from waflib.Tools.compiler_c import c_compiler
from waflib.Tools.compiler_cxx import cxx_compiler

import waftools
from waftools.codeblocks import CodeblocksContext
from waftools.makefile import MakeFileContext
from waftools.eclipse import EclipseContext


[docs]def options(opt): opt.add_option('--all', dest='all', default=False, action='store_true', help='execute command for cross-compile environments as well') opt.add_option('--cchost', dest='cchost', default=False, action='store_true', help='use the default C/C++ compiler for this platform') opt.add_option(CCROSS_ARG, dest=CCROSS_OPT, default=CCROSS_INI, action='store', help='cross compile configuration') opt.load('compiler_c') opt.load('compiler_cxx') opt.load('cmake', tooldir=waftools.location) opt.load('codeblocks', tooldir=waftools.location) opt.load('cppcheck', tooldir=waftools.location) opt.load('doxygen', tooldir=waftools.location) opt.load('eclipse', tooldir=waftools.location) opt.load('gnucc', tooldir=waftools.location) opt.load('makefile', tooldir=waftools.location) opt.load('msdev', tooldir=waftools.location) opt.load('bdist', tooldir=waftools.location) opt.load('tree', tooldir=waftools.location) opt.load('indent', tooldir=waftools.location)
[docs]def configure(conf): conf.check_waf_version(mini='1.7.6', maxi='1.9.0') conf.env.PREFIX = str(conf.env.PREFIX).replace('\\', '/') conf.env.CCROSSINI = getattr(conf.options, CCROSS_OPT) conf.env.CCROSS = get_ccross(conf.env.CCROSSINI) c = c_compiler.copy() cxx = cxx_compiler.copy() host = Utils.unversioned_sys_platform() if host not in c_compiler: host = 'default' configure_cross(conf, host) configure_host(conf, host, c, cxx)
[docs]def configure_host(conf, host, c, cxx): conf.setenv('') conf.msg('Configure environment', '%s (host)' % host, color='PINK') if conf.options.cchost: c_compiler[host] = c[host] cxx_compiler[host] = cxx[host] else: c_compiler[host] = ['gcc'] cxx_compiler[host] = ['g++'] configure_base(conf) conf.load('cmake') conf.load('doxygen') conf.load('bdist') conf.load('indent')
[docs]def configure_cross(conf, host): '''create and configure cross compile environments uses the the configuration data as specified in the *.ini* file using configparser.ExtendedInterpolation syntax. ''' prefix = conf.env.PREFIX ccross = conf.env.CCROSS for name, ini in ccross.items(): # setup cross compile environment(s) conf.setenv(name) conf.msg('Configure environment', '%s (cross)' % name, color='PINK') conf.env.CCROSS = ccross conf.env.PREFIX = '%s/opt/%s' % (prefix, name) conf.env.BINDIR = '%s/opt/%s/bin' % (prefix, name) conf.env.LIBDIR = '%s/opt/%s/lib' % (prefix, name) for (var, action, value) in ini['env']: if action == 'set': conf.env[var] = value else: conf.env.append_unique(var, value) c_compiler[host] = ini['c'] cxx_compiler[host] = ini['cxx'] head = ini['prefix'] for tail in ini['c']: if tail != 'msvc': try: cc = '%s-%s' % (head, tail) if head else tail conf.find_program(cc, var='CC') except Errors.ConfigurationError: Logs.debug("program '%s' not found" % (cc)) else: break for tail in ini['cxx']: if tail != 'msvc': try: cxx = '%s-%s' % (head, tail) if head else tail conf.find_program(cxx, var='CXX') except Errors.ConfigurationError: Logs.debug("program '%s' not found" % (cxx)) else: break if ini['c'][0] != 'msvc': ar = '%s-ar' % (head) if head else 'ar' conf.find_program(ar, var='AR') configure_base(conf)
[docs]def configure_base(conf): try: conf.load('compiler_c unity') conf.load('compiler_cxx unity') conf.load('batched_cc') except Errors.ConfigurationError: # retry without unity,batched_cc conf.load('compiler_c') conf.load('compiler_cxx') conf.load('cppcheck') conf.load('codeblocks') conf.load('eclipse') conf.load('gnucc') conf.load('makefile') conf.load('msdev') conf.load('tree')
[docs]def build(bld, trees=[]): if bld.variant: libs = bld.env.CCROSS[bld.variant]['shlib'] for lib in libs: bld.read_shlib(lib, paths=bld.env.LIBPATH) if bld.options.all and not bld.variant: if bld.cmd in ('build', 'clean', 'install', 'uninstall', 'codeblocks', 'makefile', 'eclipse'): for variant in bld.env.CCROSS.keys(): Scripting.run_command('%s_%s' % (bld.cmd, variant)) for tree in trees: for script in waftools.get_scripts(tree, 'wscript'): bld.recurse(script)
[docs]def get_ccross(fname): '''Returns dictionary of cross-compile build environments. Dictionary key name depict the environment name (i.e. variant name). :param fname: Complete path to the config.ini file :type fname: str ''' if not os.path.exists(fname): Logs.warn("CCROSS: ini file '%s' not found!" % fname) cross = {} c = configparser.ConfigParser() for s in c.sections(): cross[s] = {'prefix' : None, 'shlib' : [], 'env' : [], 'c': ['gcc'], 'cxx': ['g++']} if c.has_option(s, 'c'): cross[s]['c'] = c.get(s,'c').split(',') if c.has_option(s, 'cxx'): cross[s]['cxx'] = c.get(s,'cxx').split(',') if c.has_option(s, 'prefix'): cross[s]['prefix'] = c.get(s,'prefix') if c.has_option(s, 'shlib'): cross[s]['shlib'] = [l for l in str(c.get(s,'shlib')).split(',') if len(l)] if c.has_option(s, 'env'): cross[s]['env'] = [l.split('\t') for l in c.get(s,'env').splitlines() if len(l)] return cross
[docs]def variants(fname=None): '''Returns a list of variant names; i.e. a list of names for build environments that have been defined in the 'ccross.ini' configuration file. :param fname: Complete path to the config.ini file :type fname: str ''' if not fname: fname = CCROSS_INI opt = '%s=' % CCROSS_ARG for a in sys.argv: if a.startswith(opt): fname = a.replace(opt, '') cross = get_ccross(fname) return list(cross.keys())
[docs]def contexts(): '''Returns a list of cross-compile build contexts. :param name: Complete path to the config.ini file :type name: list of waflib.Build.BuildContext ''' return [ BuildContext, CleanContext, InstallContext, UninstallContext, CodeblocksContext, MakeFileContext, EclipseContext ]